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.
22 * (Log is kept at end of this file)
26 #include <math.h> /* rint() */
28 #include <stdlib.h> /* atoi() atof() */
29 #include <string.h> /* swab() */
31 #include <sys/types.h> /* open() */
34 #include <unistd.h> /* close() */
39 /* Read the DEM header to determine various key parameters for this
41 void rawReadDemHdr( fgRAWDEM *raw, char *hdr_file ) {
43 char line[256], key[256], value[256];
47 if ( (hdr = fopen(hdr_file, "r")) == NULL ) {
48 printf("Error opening DEM header file: %s\n", hdr_file);
52 /* process each line */
53 while ( (fgets(line, 256, hdr) != NULL) ) {
54 /* printf("%s", line); */
59 while ( (line[i] != ' ') && (i < len) ) {
65 /* skip middle space */
66 while ( (line[i] == ' ') && (i < len) ) {
72 while ( (line[i] != '\n') && (i < len) ) {
73 value[i-offset] = line[i];
76 value[i-offset] = '\0';
77 /* printf("key='%s' value='%s'\n", key, value); */
79 if ( strcmp(key, "NROWS") == 0 ) {
80 raw->nrows = atoi(value);
81 } else if ( strcmp(key, "NCOLS") == 0 ) {
82 raw->ncols = atoi(value);
83 } else if ( strcmp(key, "ULXMAP") == 0 ) {
85 raw->ulxmap = (int)rint(tmp * 3600.0); /* convert to arcsec */
86 } else if ( strcmp(key, "ULYMAP") == 0 ) {
88 raw->ulymap = (int)rint(tmp * 3600.0); /* convert to arcsec */
89 } else if ( strcmp(key, "XDIM") == 0 ) {
91 raw->xdim = (int)rint(tmp * 3600.0); /* convert to arcsec */
92 } else if ( strcmp(key, "YDIM") == 0 ) {
94 raw->ydim = (int)rint(tmp * 3600.0); /* convert to arcsec */
100 raw->rootx = raw->ulxmap - (raw->xdim / 2);
101 raw->rooty = raw->ulymap + (raw->ydim / 2);
103 printf("%d %d %d %d %d %d %d %d\n", raw->nrows, raw->ncols,
104 raw->ulxmap, raw->ulymap, raw->rootx, raw->rooty, raw->xdim,
109 /* Open a raw DEM file. */
110 void rawOpenDemFile( fgRAWDEM *raw, char *raw_dem_file ) {
111 printf("Opening Raw DEM file: %s\n", raw_dem_file);
112 if ( (raw->fd = open(raw_dem_file ,O_RDONLY)) == -1 ) {
113 printf("Error opening Raw DEM file: %s\n", raw_dem_file);
119 /* Close a raw DEM file. */
120 void rawCloseDemFile( fgRAWDEM *raw ) {
125 /* Advance file pointer position to correct latitude (row) */
126 void rawAdvancePosition( fgRAWDEM *raw, int arcsec ) {
129 offset = 2 * raw->ncols * ( arcsec / raw->ydim );
131 if ( (result = lseek(raw->fd, offset, SEEK_SET)) == -1 ) {
132 printf("Error lseek filed trying to offset by %ld\n", offset);
136 printf("Successful seek ahead of %ld bytes\n", result);
140 /* Read the next row of data */
141 void rawReadNextRow( fgRAWDEM *raw, int index ) {
142 char buf[MAX_COLS_X_2];
145 if ( raw->ncols > MAX_ROWS ) {
146 printf("Error, buf needs to be bigger in rawReadNextRow()\n");
150 /* printf("Attempting to read %d bytes\n", 2 * raw->ncols); */
151 result = read(raw->fd, buf, 2 * raw->ncols);
152 /* printf("Read %d bytes\n", result); */
154 /* reverse byte order */
155 /* it would be nice to test in advance some how if we need to do
157 /* swab(frombuf, tobuf, 2 * raw->ncols); */
159 for ( i = 0; i < raw->ncols; i++ ) {
160 /* printf("hi = %d lo = %d\n", buf[2*i], buf[2*i + 1]); */
161 raw->strip[index][i] = ( (buf[2*i] + 1) << 8 ) + buf[2*i + 1];
166 /* Convert from pixel centered values to pixel corner values. This is
167 accomplished by taking the average of the closes center nodes. In
168 the following diagram "x" marks the data point location:
177 void rawConvertCenter2Edge( fgRAWDEM *raw ) {
180 /* derive corner nodes */
181 raw->edge[0][0] = raw->center[0][0];
182 raw->edge[120][0] = raw->center[119][0];
183 raw->edge[120][120] = raw->center[119][119];
184 raw->edge[0][120] = raw->center[0][119];
186 /* derive edge nodes */
187 for ( i = 1; i < 120; i++ ) {
188 raw->edge[i][0] = (raw->center[i-1][0] + raw->center[i][0]) / 2.0;
189 raw->edge[i][120] = (raw->center[i-1][119] + raw->center[i][119]) / 2.0;
190 raw->edge[0][i] = (raw->center[0][i-1] + raw->center[0][i]) / 2.0;
191 raw->edge[120][i] = (raw->center[119][i-1] + raw->center[119][i]) / 2.0;
194 /* derive internal nodes */
195 for ( j = 1; j < 120; j++ ) {
196 for ( i = 1; i < 120; i++ ) {
197 raw->edge[i][j] = ( raw->center[i-1][j-1] +
198 raw->center[i] [j-1] +
200 raw->center[i-1][j] ) / 4;
206 /* Dump out the ascii format DEM file */
207 void rawDumpAsciiDEM( fgRAWDEM *raw, char *path, int ilon, int ilat ) {
211 char lon_sign, lat_sign;
215 /* Generate output file name */
233 sprintf(outfile, "%s/%c%03d%c%03d.dem", path, lon_sign, lon, lat_sign, lat);
235 printf("outfile = %s\n", outfile);
237 if ( (fd = fopen(outfile, "w")) == NULL ) {
238 printf("Error opening output file = %s\n", outfile);
242 /* Dump the "A" record */
244 /* print descriptive header (144 characters) */
245 sprintf(tmp, "%s - Generated from a 30 arcsec binary DEM", outfile);
246 fprintf(fd, "%-144s", tmp);
248 /* DEM level code, 3 reflects processing by DMA */
249 fprintf(fd, "%6d", 1);
251 /* Pattern code, 1 indicates a regular elevation pattern */
252 fprintf(fd, "%6d", 1);
254 /* Planimetric reference system code, 0 indicates geographic
255 * coordinate system. */
256 fprintf(fd, "%6d", 0);
259 fprintf(fd, "%6d", 0);
261 /* Map projection parameters (ignored) */
262 for ( i = 0; i < 15; i++ ) {
263 fprintf(fd, "%6.1f%18s", 0.0, "");
266 /* Units code, 3 represents arc-seconds as the unit of measure for
267 * ground planimetric coordinates throughout the file. */
268 fprintf(fd, "%6d", 3);
270 /* Units code; 2 represents meters as the unit of measure for
271 * elevation coordinates throughout the file. */
272 fprintf(fd, "%6d", 2);
274 /* Number (n) of sides in the polygon which defines the coverage of
275 * the DEM file (usually equal to 4). */
276 fprintf(fd, "%6d", 4);
278 /* Ground coordinates of bounding box in arc-seconds */
279 fprintf(fd, "%20.15fD+06", ilon * 3600.0 / 1000000.0);
280 fprintf(fd, "%20.15fD+06", ilat * 3600.0 / 1000000.0);
282 fprintf(fd, "%20.15fD+06", ilon * 3600.0 / 1000000.0);
283 fprintf(fd, "%20.15fD+06", (ilat+1) * 3600.0 / 1000000.0);
285 fprintf(fd, "%20.15fD+06", (ilon+1) * 3600.0 / 1000000.0);
286 fprintf(fd, "%20.15fD+06", (ilat+1) * 3600.0 / 1000000.0);
288 fprintf(fd, "%20.15fD+06", (ilon+1) * 3600.0 / 1000000.0);
289 fprintf(fd, "%20.15fD+06", (ilat) * 3600.0 / 1000000.0);
291 /* Minimum/maximum elevations in meters */
292 fprintf(fd, " %20.15E", (double)raw->tmp_min);
293 fprintf(fd, " %20.15E", (double)raw->tmp_max);
295 /* Counterclockwise angle from the primary axis of ground
296 * planimetric referenced to the primary axis of the DEM local
297 * reference system. */
298 fprintf(fd, "%6.1f", 0.0);
300 /* Accuracy code; 0 indicates that a record of accuracy does not
301 * exist and that no record type C will follow. */
302 fprintf(fd, "%24d", 0);
304 /* DEM spacial resolution. Usually (3,3) (3,6) or (3,9)
305 * depending on latitude */
306 fprintf(fd, "%12.6E", 30.0);
307 fprintf(fd, "%12.6E", 30.0);
310 fprintf(fd, "%12.6E", 1.0);
312 /* dimension of arrays to follow (1)*/
313 fprintf(fd, "%6d", 1);
315 /* number of profiles */
316 fprintf(fd, "%6d", 3600 / raw->ydim + 1);
319 fprintf(fd, "%160s", "");
322 /* Dump "B" records */
324 for ( j = 0; j <= 120; j++ ) {
325 /* row / column id of this profile */
326 fprintf(fd, "%6d%6d", 1, j + 1);
328 /* Number of rows and columns (elevation points) in this
330 fprintf(fd, "%6d%6d", 3600 / raw->xdim + 1, 1);
332 /* Ground planimetric coordinates (arc-seconds) of the first
333 * elevation in the profile */
334 fprintf(fd, "%20.15fD+06", ilon * 3600.0 / 1000000.0);
335 fprintf(fd, "%20.15fD+06", (ilat * 3600.0 + j * raw->ydim) / 1000000.0);
337 /* Elevation of local datum for the profile. Always zero for
338 * 1-degree DEM, the reference is mean sea level. */
339 fprintf(fd, "%6.1f", 0.0);
340 fprintf(fd, "%18s", "");
342 /* Minimum and maximum elevations for the profile. */
343 fprintf(fd, " %20.15E", 0.0);
344 fprintf(fd, " %20.15E", 0.0);
346 /* One (usually) dimensional array (1,prof_num_cols) of
348 for ( i = 0; i <= 120; i++ ) {
349 fprintf(fd, "%6.0f", raw->edge[j][i]);
359 /* Read a horizontal strip of (1 vertical degree) from the raw DEM
360 * file specified by the upper latitude of the stripe specified in
361 * degrees. The output the individual ASCII format DEM tiles. */
362 void rawProcessStrip( fgRAWDEM *raw, int lat_degrees, char *path ) {
364 int i, j, index, row, col;
366 int span, num_degrees, tile_width;
369 /* convert to arcsec */
370 lat = lat_degrees * 3600;
372 printf("Max Latitude = %d arcsec\n", lat);
374 /* validity check ... */
375 if ( (lat > raw->rooty) ||
376 (lat < (raw->rooty - raw->nrows * raw->ydim + 1)) ) {
377 printf("Latitude out of range for this DEM file\n");
381 printf ("Reading strip starting at %d (top and working down)\n", lat);
383 /* advance to the correct latitude */
384 rawAdvancePosition(raw, (raw->rooty - lat));
386 /* printf("short = %d\n", sizeof(short)); */
388 yrange = 3600 / raw->ydim;
390 for ( i = 0; i < yrange; i++ ) {
391 index = yrange - i - 1;
392 /* printf("About to read into row %d\n", index); */
393 rawReadNextRow(raw, index);
395 for ( j = 0; j < raw->ncols; j++ ) {
396 if ( raw->strip[index][j] == -9999 ) {
397 /* map ocean to 0 for now */
398 raw->strip[index][j] = 0;
403 /* extract individual tiles from the strip */
404 span = raw->ncols * raw->xdim;
405 num_degrees = span / 3600;
406 tile_width = raw->ncols / num_degrees;
407 printf("span = %d num_degrees = %d width = %d\n",
408 span, num_degrees, tile_width);
410 for ( i = 0; i < num_degrees; i++ ) {
411 xstart = i * tile_width;
414 min = 10000; max = -10000;
415 for ( row = 0; row < yrange; row++ ) {
416 for ( col = xstart; col < xend; col++ ) {
417 /* Copy from strip to pixel centered tile. Yep,
418 * row/col are reversed here. raw->strip is backwards
419 * for convenience. I am converting to [x,y] now. */
420 raw->center[col-xstart][row] = raw->strip[row][col];
422 if ( raw->strip[row][col] < min) {
423 min = raw->strip[row][col];
426 if ( raw->strip[row][col] > max) {
427 max = raw->strip[row][col];
435 /* Convert from pixel centered to pixel edge values */
436 rawConvertCenter2Edge(raw);
438 /* Dump out the ascii format DEM file */
439 rawDumpAsciiDEM(raw, path, (raw->rootx / 3600) + i, lat_degrees - 1);
445 /* Revision 1.5 1998/04/18 03:59:46 curt
446 /* Incorporated into gnu automake/autoconf system.
448 * Revision 1.4 1998/04/06 21:09:43 curt
449 * Additional win32 support.
450 * Fixed a bad bug in dem file parsing that was causing the output to be
451 * flipped about x = y.
453 * Revision 1.3 1998/03/03 13:10:29 curt
454 * Close to a working version.
456 * Revision 1.2 1998/03/03 02:04:01 curt
457 * Starting DEM Ascii format output routine.
459 * Revision 1.1 1998/03/02 23:31:01 curt