1 /* rawdem.c -- library of routines for processing raw dem files (30 arcsec)
3 * Written by Curtis Olson, started February 1998.
5 * Copyright (C) 1998 Curtis L. Olson - curt@me.umn.edu
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29 #include <math.h> /* rint() */
31 #include <stdlib.h> /* atoi() atof() */
32 #include <string.h> /* swab() */
34 #include <sys/types.h> /* open() */
37 #include <unistd.h> /* close() */
42 /* Read the DEM header to determine various key parameters for this
44 void rawReadDemHdr( fgRAWDEM *raw, char *hdr_file ) {
46 char line[256], key[256], value[256];
50 if ( (hdr = fopen(hdr_file, "r")) == NULL ) {
51 printf("Error opening DEM header file: %s\n", hdr_file);
55 /* process each line */
56 while ( (fgets(line, 256, hdr) != NULL) ) {
57 /* printf("%s", line); */
62 while ( (line[i] != ' ') && (i < len) ) {
68 /* skip middle space */
69 while ( (line[i] == ' ') && (i < len) ) {
75 while ( (line[i] != '\n') && (i < len) ) {
76 value[i-offset] = line[i];
79 value[i-offset] = '\0';
80 /* printf("key='%s' value='%s'\n", key, value); */
82 if ( strcmp(key, "NROWS") == 0 ) {
83 raw->nrows = atoi(value);
84 } else if ( strcmp(key, "NCOLS") == 0 ) {
85 raw->ncols = atoi(value);
86 } else if ( strcmp(key, "ULXMAP") == 0 ) {
89 raw->ulxmap = (int)rint(tmp * 3600.0); /* convert to arcsec */
91 # error Port me rint()
93 } else if ( strcmp(key, "ULYMAP") == 0 ) {
96 raw->ulymap = (int)rint(tmp * 3600.0); /* convert to arcsec */
98 # error Port me rint()
100 } else if ( strcmp(key, "XDIM") == 0 ) {
103 raw->xdim = (int)rint(tmp * 3600.0); /* convert to arcsec */
105 # error Port me rint()
107 } else if ( strcmp(key, "YDIM") == 0 ) {
110 raw->ydim = (int)rint(tmp * 3600.0); /* convert to arcsec */
112 # error Port me rint()
119 raw->rootx = raw->ulxmap - (raw->xdim / 2);
120 raw->rooty = raw->ulymap + (raw->ydim / 2);
122 printf("%d %d %d %d %d %d %d %d\n", raw->nrows, raw->ncols,
123 raw->ulxmap, raw->ulymap, raw->rootx, raw->rooty, raw->xdim,
128 /* Open a raw DEM file. */
129 void rawOpenDemFile( fgRAWDEM *raw, char *raw_dem_file ) {
130 printf("Opening Raw DEM file: %s\n", raw_dem_file);
131 if ( (raw->fd = open(raw_dem_file ,O_RDONLY)) == -1 ) {
132 printf("Error opening Raw DEM file: %s\n", raw_dem_file);
138 /* Close a raw DEM file. */
139 void rawCloseDemFile( fgRAWDEM *raw ) {
144 /* Advance file pointer position to correct latitude (row) */
145 void rawAdvancePosition( fgRAWDEM *raw, int arcsec ) {
148 offset = 2 * raw->ncols * ( arcsec / raw->ydim );
150 if ( (result = lseek(raw->fd, offset, SEEK_SET)) == -1 ) {
151 printf("Error lseek filed trying to offset by %ld\n", offset);
155 printf("Successful seek ahead of %ld bytes\n", result);
159 /* Read the next row of data */
160 void rawReadNextRow( fgRAWDEM *raw, int index ) {
161 char buf[MAX_COLS_X_2];
164 if ( raw->ncols > MAX_ROWS ) {
165 printf("Error, buf needs to be bigger in rawReadNextRow()\n");
169 /* printf("Attempting to read %d bytes\n", 2 * raw->ncols); */
170 result = read(raw->fd, buf, 2 * raw->ncols);
171 /* printf("Read %d bytes\n", result); */
173 /* reverse byte order */
174 /* it would be nice to test in advance some how if we need to do
176 /* swab(frombuf, tobuf, 2 * raw->ncols); */
178 for ( i = 0; i < raw->ncols; i++ ) {
179 /* printf("hi = %d lo = %d\n", buf[2*i], buf[2*i + 1]); */
180 raw->strip[index][i] = ( (buf[2*i] + 1) << 8 ) + buf[2*i + 1];
185 /* Convert from pixel centered values to pixel corner values. This is
186 accomplished by taking the average of the closes center nodes. In
187 the following diagram "x" marks the data point location:
196 void rawConvertCenter2Edge( fgRAWDEM *raw ) {
199 /* derive corner nodes */
200 raw->edge[0][0] = raw->center[0][0];
201 raw->edge[120][0] = raw->center[119][0];
202 raw->edge[120][120] = raw->center[119][119];
203 raw->edge[0][120] = raw->center[0][119];
205 /* derive edge nodes */
206 for ( i = 1; i < 120; i++ ) {
207 raw->edge[i][0] = (raw->center[i-1][0] + raw->center[i][0]) / 2.0;
208 raw->edge[i][120] = (raw->center[i-1][119] + raw->center[i][119]) / 2.0;
209 raw->edge[0][i] = (raw->center[0][i-1] + raw->center[0][i]) / 2.0;
210 raw->edge[120][i] = (raw->center[119][i-1] + raw->center[119][i]) / 2.0;
213 /* derive internal nodes */
214 for ( j = 1; j < 120; j++ ) {
215 for ( i = 1; i < 120; i++ ) {
216 raw->edge[i][j] = ( raw->center[i-1][j-1] +
217 raw->center[i] [j-1] +
219 raw->center[i-1][j] ) / 4;
225 /* Dump out the ascii format DEM file */
226 void rawDumpAsciiDEM( fgRAWDEM *raw, char *path, int ilon, int ilat ) {
230 char lon_sign, lat_sign;
234 /* Generate output file name */
252 sprintf(outfile, "%s/%c%03d%c%03d.dem", path, lon_sign, lon, lat_sign, lat);
254 printf("outfile = %s\n", outfile);
256 if ( (fd = fopen(outfile, "w")) == NULL ) {
257 printf("Error opening output file = %s\n", outfile);
261 /* Dump the "A" record */
263 /* print descriptive header (144 characters) */
264 sprintf(tmp, "%s - Generated from a 30 arcsec binary DEM", outfile);
265 fprintf(fd, "%-144s", tmp);
267 /* DEM level code, 3 reflects processing by DMA */
268 fprintf(fd, "%6d", 1);
270 /* Pattern code, 1 indicates a regular elevation pattern */
271 fprintf(fd, "%6d", 1);
273 /* Planimetric reference system code, 0 indicates geographic
274 * coordinate system. */
275 fprintf(fd, "%6d", 0);
278 fprintf(fd, "%6d", 0);
280 /* Map projection parameters (ignored) */
281 for ( i = 0; i < 15; i++ ) {
282 fprintf(fd, "%6.1f%18s", 0.0, "");
285 /* Units code, 3 represents arc-seconds as the unit of measure for
286 * ground planimetric coordinates throughout the file. */
287 fprintf(fd, "%6d", 3);
289 /* Units code; 2 represents meters as the unit of measure for
290 * elevation coordinates throughout the file. */
291 fprintf(fd, "%6d", 2);
293 /* Number (n) of sides in the polygon which defines the coverage of
294 * the DEM file (usually equal to 4). */
295 fprintf(fd, "%6d", 4);
297 /* Ground coordinates of bounding box in arc-seconds */
298 fprintf(fd, "%20.15fD+06", ilon * 3600.0 / 1000000.0);
299 fprintf(fd, "%20.15fD+06", ilat * 3600.0 / 1000000.0);
301 fprintf(fd, "%20.15fD+06", ilon * 3600.0 / 1000000.0);
302 fprintf(fd, "%20.15fD+06", (ilat+1) * 3600.0 / 1000000.0);
304 fprintf(fd, "%20.15fD+06", (ilon+1) * 3600.0 / 1000000.0);
305 fprintf(fd, "%20.15fD+06", (ilat+1) * 3600.0 / 1000000.0);
307 fprintf(fd, "%20.15fD+06", (ilon+1) * 3600.0 / 1000000.0);
308 fprintf(fd, "%20.15fD+06", (ilat) * 3600.0 / 1000000.0);
310 /* Minimum/maximum elevations in meters */
311 fprintf(fd, " %20.15E", (double)raw->tmp_min);
312 fprintf(fd, " %20.15E", (double)raw->tmp_max);
314 /* Counterclockwise angle from the primary axis of ground
315 * planimetric referenced to the primary axis of the DEM local
316 * reference system. */
317 fprintf(fd, "%6.1f", 0.0);
319 /* Accuracy code; 0 indicates that a record of accuracy does not
320 * exist and that no record type C will follow. */
321 fprintf(fd, "%24d", 0);
323 /* DEM spacial resolution. Usually (3,3) (3,6) or (3,9)
324 * depending on latitude */
325 fprintf(fd, "%12.6E", 30.0);
326 fprintf(fd, "%12.6E", 30.0);
329 fprintf(fd, "%12.6E", 1.0);
331 /* dimension of arrays to follow (1)*/
332 fprintf(fd, "%6d", 1);
334 /* number of profiles */
335 fprintf(fd, "%6d", 3600 / raw->ydim + 1);
338 fprintf(fd, "%160s", "");
341 /* Dump "B" records */
343 for ( j = 0; j <= 120; j++ ) {
344 /* row / column id of this profile */
345 fprintf(fd, "%6d%6d", 1, j + 1);
347 /* Number of rows and columns (elevation points) in this
349 fprintf(fd, "%6d%6d", 3600 / raw->xdim + 1, 1);
351 /* Ground planimetric coordinates (arc-seconds) of the first
352 * elevation in the profile */
353 fprintf(fd, "%20.15fD+06", ilon * 3600.0 / 1000000.0);
354 fprintf(fd, "%20.15fD+06", (ilat * 3600.0 + j * raw->ydim) / 1000000.0);
356 /* Elevation of local datum for the profile. Always zero for
357 * 1-degree DEM, the reference is mean sea level. */
358 fprintf(fd, "%6.1f", 0.0);
359 fprintf(fd, "%18s", "");
361 /* Minimum and maximum elevations for the profile. */
362 fprintf(fd, " %20.15E", 0.0);
363 fprintf(fd, " %20.15E", 0.0);
365 /* One (usually) dimensional array (1,prof_num_cols) of
367 for ( i = 0; i <= 120; i++ ) {
368 fprintf(fd, "%6.0f", raw->edge[j][i]);
378 /* Read a horizontal strip of (1 vertical degree) from the raw DEM
379 * file specified by the upper latitude of the stripe specified in
380 * degrees. The output the individual ASCII format DEM tiles. */
381 void rawProcessStrip( fgRAWDEM *raw, int lat_degrees, char *path ) {
383 int i, j, index, row, col;
385 int span, num_degrees, tile_width;
388 /* convert to arcsec */
389 lat = lat_degrees * 3600;
391 printf("Max Latitude = %d arcsec\n", lat);
393 /* validity check ... */
394 if ( (lat > raw->rooty) ||
395 (lat < (raw->rooty - raw->nrows * raw->ydim + 1)) ) {
396 printf("Latitude out of range for this DEM file\n");
400 printf ("Reading strip starting at %d (top and working down)\n", lat);
402 /* advance to the correct latitude */
403 rawAdvancePosition(raw, (raw->rooty - lat));
405 /* printf("short = %d\n", sizeof(short)); */
407 yrange = 3600 / raw->ydim;
409 for ( i = 0; i < yrange; i++ ) {
410 index = yrange - i - 1;
411 /* printf("About to read into row %d\n", index); */
412 rawReadNextRow(raw, index);
414 for ( j = 0; j < raw->ncols; j++ ) {
415 if ( raw->strip[index][j] == -9999 ) {
416 /* map ocean to 0 for now */
417 raw->strip[index][j] = 0;
422 /* extract individual tiles from the strip */
423 span = raw->ncols * raw->xdim;
424 num_degrees = span / 3600;
425 tile_width = raw->ncols / num_degrees;
426 printf("span = %d num_degrees = %d width = %d\n",
427 span, num_degrees, tile_width);
429 for ( i = 0; i < num_degrees; i++ ) {
430 xstart = i * tile_width;
433 min = 10000; max = -10000;
434 for ( row = 0; row < yrange; row++ ) {
435 for ( col = xstart; col < xend; col++ ) {
436 /* Copy from strip to pixel centered tile. Yep,
437 * row/col are reversed here. raw->strip is backwards
438 * for convenience. I am converting to [x,y] now. */
439 raw->center[col-xstart][row] = raw->strip[row][col];
441 if ( raw->strip[row][col] < min) {
442 min = raw->strip[row][col];
445 if ( raw->strip[row][col] > max) {
446 max = raw->strip[row][col];
454 /* Convert from pixel centered to pixel edge values */
455 rawConvertCenter2Edge(raw);
457 /* Dump out the ascii format DEM file */
458 rawDumpAsciiDEM(raw, path, (raw->rootx / 3600) + i, lat_degrees - 1);