1 : /******************************************************************************
2 : * $Id: gxfopen.c 16865 2009-04-27 12:49:49Z chaitanya $
3 : *
4 : * Project: GXF Reader
5 : * Purpose: Majority of Geosoft GXF reading code.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 1998, Global Geomatics
10 : * Copyright (c) 1998, Frank Warmerdam
11 : *
12 : * Permission is hereby granted, free of charge, to any person obtaining a
13 : * copy of this software and associated documentation files (the "Software"),
14 : * to deal in the Software without restriction, including without limitation
15 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 : * and/or sell copies of the Software, and to permit persons to whom the
17 : * Software is furnished to do so, subject to the following conditions:
18 : *
19 : * The above copyright notice and this permission notice shall be included
20 : * in all copies or substantial portions of the Software.
21 : *
22 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 : * DEALINGS IN THE SOFTWARE.
29 : ****************************************************************************/
30 :
31 : #include <ctype.h>
32 : #include "gxfopen.h"
33 :
34 : CPL_CVSID("$Id: gxfopen.c 16865 2009-04-27 12:49:49Z chaitanya $");
35 :
36 :
37 : /* this is also defined in gdal.h which we avoid in this separable component */
38 : #define CPLE_WrongFormat 200
39 :
40 : /************************************************************************/
41 : /* GXFReadHeaderValue() */
42 : /* */
43 : /* Read one entry from the file header, and return it and it's */
44 : /* value in clean form. */
45 : /************************************************************************/
46 :
47 96 : static char **GXFReadHeaderValue( FILE * fp, char * pszHTitle )
48 :
49 : {
50 : const char *pszLine;
51 96 : char **papszReturn = NULL;
52 : int i;
53 :
54 : /* -------------------------------------------------------------------- */
55 : /* Try to read a line. If we fail or if this isn't a proper */
56 : /* header value then return the failure. */
57 : /* -------------------------------------------------------------------- */
58 96 : pszLine = CPLReadLine( fp );
59 96 : if( pszLine == NULL )
60 : {
61 0 : strcpy( pszHTitle, "#EOF" );
62 0 : return( NULL );
63 : }
64 :
65 : /* -------------------------------------------------------------------- */
66 : /* Extract the title. It should be terminated by some sort of */
67 : /* white space. */
68 : /* -------------------------------------------------------------------- */
69 96 : for( i = 0; !isspace((unsigned char)pszLine[i]) && pszLine[i] != '\0' && i < 70; i++ ) {}
70 :
71 96 : strncpy( pszHTitle, pszLine, i );
72 96 : pszHTitle[i] = '\0';
73 :
74 : /* -------------------------------------------------------------------- */
75 : /* If this is #GRID, then return ... we are at the end of the */
76 : /* header. */
77 : /* -------------------------------------------------------------------- */
78 96 : if( EQUAL(pszHTitle,"#GRID") )
79 7 : return NULL;
80 :
81 : /* -------------------------------------------------------------------- */
82 : /* Skip white space. */
83 : /* -------------------------------------------------------------------- */
84 5433 : while( isspace((unsigned char)pszLine[i]) )
85 5255 : i++;
86 :
87 : /* -------------------------------------------------------------------- */
88 : /* If we have reached the end of the line, try to read another line. */
89 : /* -------------------------------------------------------------------- */
90 89 : if( pszLine[i] == '\0' )
91 : {
92 89 : pszLine = CPLReadLine( fp );
93 89 : if( pszLine == NULL )
94 : {
95 0 : strcpy( pszHTitle, "#EOF" );
96 0 : return( NULL );
97 : }
98 89 : i = 0;
99 : }
100 :
101 : /* -------------------------------------------------------------------- */
102 : /* Keeping adding the value stuff as new lines till we reach a */
103 : /* `#' mark at the beginning of a new line. */
104 : /* -------------------------------------------------------------------- */
105 : do {
106 : int nNextChar;
107 : char *pszTrimmedLine;
108 :
109 117 : pszTrimmedLine = CPLStrdup( pszLine );
110 :
111 7364 : for( i = strlen(pszLine)-1; i >= 0 && pszLine[i] == ' '; i-- )
112 7247 : pszTrimmedLine[i] = '\0';
113 :
114 117 : papszReturn = CSLAddString( papszReturn, pszTrimmedLine );
115 117 : CPLFree( pszTrimmedLine );
116 :
117 117 : nNextChar = VSIFGetc( fp );
118 117 : VSIUngetc( nNextChar, fp );
119 :
120 117 : if( nNextChar == '#' )
121 89 : pszLine = NULL;
122 : else
123 28 : pszLine = CPLReadLine( fp );
124 117 : } while( pszLine != NULL );
125 :
126 89 : return( papszReturn );
127 : }
128 :
129 : /************************************************************************/
130 : /* GXFOpen() */
131 : /************************************************************************/
132 :
133 : /**
134 : * Open a GXF file, and collect contents of the header.
135 : *
136 : * @param pszFilename the name of the file to open.
137 : *
138 : * @return a handle for use with other GXF functions to access the file. This
139 : * will be NULL if the access fails.
140 : */
141 :
142 7 : GXFHandle GXFOpen( const char * pszFilename )
143 :
144 : {
145 : FILE *fp;
146 : GXFInfo_t *psGXF;
147 : char szTitle[71];
148 : char **papszList;
149 :
150 : /* -------------------------------------------------------------------- */
151 : /* We open in binary to ensure that we can efficiently seek() */
152 : /* to any location when reading scanlines randomly. If we */
153 : /* opened as text we might still be able to seek(), but I */
154 : /* believe that on Windows, the C library has to read through */
155 : /* all the data to find the right spot taking into account DOS */
156 : /* CRs. */
157 : /* -------------------------------------------------------------------- */
158 7 : fp = VSIFOpen( pszFilename, "rb" );
159 :
160 7 : if( fp == NULL )
161 : {
162 : /* how to effectively communicate this error out? */
163 0 : CPLError( CE_Failure, CPLE_OpenFailed,
164 : "Unable to open file: %s\n", pszFilename );
165 0 : return NULL;
166 : }
167 :
168 : /* -------------------------------------------------------------------- */
169 : /* Create the GXF Information object. */
170 : /* -------------------------------------------------------------------- */
171 7 : psGXF = (GXFInfo_t *) VSICalloc( sizeof(GXFInfo_t), 1 );
172 7 : psGXF->fp = fp;
173 7 : psGXF->dfTransformScale = 1.0;
174 7 : psGXF->nSense = GXFS_LL_RIGHT;
175 7 : psGXF->dfXPixelSize = 1.0;
176 7 : psGXF->dfYPixelSize = 1.0;
177 7 : psGXF->dfSetDummyTo = -1e12;
178 :
179 7 : psGXF->dfUnitToMeter = 1.0;
180 7 : psGXF->pszTitle = VSIStrdup("");
181 :
182 : /* -------------------------------------------------------------------- */
183 : /* Read the header, one line at a time. */
184 : /* -------------------------------------------------------------------- */
185 103 : while( (papszList = GXFReadHeaderValue( fp, szTitle)) != NULL )
186 : {
187 89 : if( EQUALN(szTitle,"#TITL",5) )
188 : {
189 6 : CPLFree( psGXF->pszTitle );
190 6 : psGXF->pszTitle = CPLStrdup( papszList[0] );
191 : }
192 83 : else if( EQUALN(szTitle,"#POIN",5) )
193 : {
194 7 : psGXF->nRawXSize = atoi(papszList[0]);
195 : }
196 76 : else if( EQUALN(szTitle,"#ROWS",5) )
197 : {
198 7 : psGXF->nRawYSize = atoi(papszList[0]);
199 : }
200 69 : else if( EQUALN(szTitle,"#PTSE",5) )
201 : {
202 6 : psGXF->dfXPixelSize = atof(papszList[0]);
203 : }
204 63 : else if( EQUALN(szTitle,"#RWSE",5) )
205 : {
206 6 : psGXF->dfYPixelSize = atof(papszList[0]);
207 : }
208 57 : else if( EQUALN(szTitle,"#DUMM",5) )
209 : {
210 2 : memset( psGXF->szDummy, 0, sizeof(psGXF->szDummy));
211 2 : strncpy( psGXF->szDummy, papszList[0], sizeof(psGXF->szDummy) - 1);
212 2 : psGXF->dfSetDummyTo = atof(papszList[0]);
213 : }
214 55 : else if( EQUALN(szTitle,"#XORI",5) )
215 : {
216 6 : psGXF->dfXOrigin = atof(papszList[0]);
217 : }
218 49 : else if( EQUALN(szTitle,"#YORI",5) )
219 : {
220 6 : psGXF->dfYOrigin = atof(papszList[0]);
221 : }
222 43 : else if( EQUALN(szTitle,"#ZMIN",5) )
223 : {
224 6 : psGXF->dfZMinimum = atof(papszList[0]);
225 : }
226 37 : else if( EQUALN(szTitle,"#ZMAX",5) )
227 : {
228 6 : psGXF->dfZMaximum = atof(papszList[0]);
229 : }
230 31 : else if( EQUALN(szTitle,"#SENS",5) )
231 : {
232 6 : psGXF->nSense = atoi(papszList[0]);
233 : }
234 25 : else if( EQUALN(szTitle,"#MAP_PROJECTION",8) )
235 : {
236 5 : psGXF->papszMapProjection = papszList;
237 5 : papszList = NULL;
238 : }
239 20 : else if( EQUALN(szTitle,"#MAP_D",5) )
240 : {
241 0 : psGXF->papszMapDatumTransform = papszList;
242 0 : papszList = NULL;
243 : }
244 20 : else if( EQUALN(szTitle,"#UNIT",5) )
245 : {
246 : char **papszFields;
247 :
248 5 : papszFields = CSLTokenizeStringComplex( papszList[0], ", ",
249 : TRUE, TRUE );
250 :
251 5 : if( CSLCount(papszFields) > 1 )
252 : {
253 5 : psGXF->pszUnitName = VSIStrdup( papszFields[0] );
254 5 : psGXF->dfUnitToMeter = atof( papszFields[1] );
255 5 : if( psGXF->dfUnitToMeter == 0.0 )
256 0 : psGXF->dfUnitToMeter = 1.0;
257 : }
258 :
259 5 : CSLDestroy( papszFields );
260 : }
261 15 : else if( EQUALN(szTitle,"#TRAN",5) )
262 : {
263 : char **papszFields;
264 :
265 5 : papszFields = CSLTokenizeStringComplex( papszList[0], ", ",
266 : TRUE, TRUE );
267 :
268 5 : if( CSLCount(papszFields) > 1 )
269 : {
270 5 : psGXF->dfTransformScale = atof(papszFields[0]);
271 5 : psGXF->dfTransformOffset = atof(papszFields[1]);
272 : }
273 :
274 5 : if( CSLCount(papszFields) > 2 )
275 0 : psGXF->pszTransformName = CPLStrdup( papszFields[2] );
276 :
277 5 : CSLDestroy( papszFields );
278 : }
279 10 : else if( EQUALN(szTitle,"#GTYPE",5) )
280 : {
281 4 : psGXF->nGType = atoi(papszList[0]);
282 : }
283 :
284 89 : CSLDestroy( papszList );
285 : }
286 :
287 : /* -------------------------------------------------------------------- */
288 : /* Did we find the #GRID? */
289 : /* -------------------------------------------------------------------- */
290 7 : if( !EQUALN(szTitle,"#GRID",5) )
291 : {
292 0 : GXFClose( psGXF );
293 0 : CPLError( CE_Failure, CPLE_WrongFormat,
294 : "Didn't parse through to #GRID successfully in.\n"
295 : "file `%s'.\n",
296 : pszFilename );
297 :
298 0 : return NULL;
299 : }
300 :
301 : /* -------------------------------------------------------------------- */
302 : /* Allocate, and initialize the raw scanline offset array. */
303 : /* -------------------------------------------------------------------- */
304 7 : psGXF->panRawLineOffset = (long *)
305 7 : CPLCalloc( sizeof(long), psGXF->nRawYSize+1 );
306 :
307 7 : psGXF->panRawLineOffset[0] = VSIFTell( psGXF->fp );
308 :
309 : /* -------------------------------------------------------------------- */
310 : /* Update the zmin/zmax values to take into account #TRANSFORM */
311 : /* information. */
312 : /* -------------------------------------------------------------------- */
313 7 : if( psGXF->dfZMinimum != 0.0 || psGXF->dfZMaximum != 0.0 )
314 : {
315 6 : psGXF->dfZMinimum = (psGXF->dfZMinimum * psGXF->dfTransformScale)
316 : + psGXF->dfTransformOffset;
317 6 : psGXF->dfZMaximum = (psGXF->dfZMaximum * psGXF->dfTransformScale)
318 : + psGXF->dfTransformOffset;
319 : }
320 :
321 7 : return( (GXFHandle) psGXF );
322 : }
323 :
324 : /************************************************************************/
325 : /* GXFClose() */
326 : /************************************************************************/
327 :
328 : /**
329 : * Close GXF file opened with GXFOpen().
330 : *
331 : * @param hGXF handle to GXF file.
332 : */
333 :
334 7 : void GXFClose( GXFHandle hGXF )
335 :
336 : {
337 7 : GXFInfo_t *psGXF = (GXFInfo_t *) hGXF;
338 :
339 7 : CPLFree( psGXF->panRawLineOffset );
340 7 : CPLFree( psGXF->pszUnitName );
341 7 : CSLDestroy( psGXF->papszMapDatumTransform );
342 7 : CSLDestroy( psGXF->papszMapProjection );
343 7 : CPLFree( psGXF->pszTitle );
344 :
345 7 : VSIFClose( psGXF->fp );
346 :
347 7 : CPLReadLine( NULL );
348 :
349 7 : CPLFree( psGXF );
350 7 : }
351 :
352 : /************************************************************************/
353 : /* GXFParseBase90() */
354 : /* */
355 : /* Parse a base 90 number ... exceptions (repeat, and dummy) */
356 : /* values have to be recognised outside this function. */
357 : /************************************************************************/
358 :
359 477843 : double GXFParseBase90( GXFInfo_t * psGXF, const char * pszText,
360 : int bScale )
361 :
362 : {
363 477843 : int i = 0, nValue = 0;
364 :
365 2867058 : while( i < psGXF->nGType )
366 : {
367 1911372 : nValue = nValue*90 + (pszText[i] - 37);
368 1911372 : i++;
369 : }
370 :
371 477843 : if( bScale )
372 476828 : return( (nValue * psGXF->dfTransformScale) + psGXF->dfTransformOffset);
373 : else
374 1015 : return( nValue );
375 : }
376 :
377 :
378 : /************************************************************************/
379 : /* GXFReadRawScanlineFrom() */
380 : /************************************************************************/
381 :
382 1530 : static int GXFReadRawScanlineFrom( GXFInfo_t * psGXF, long iOffset,
383 : long * pnNewOffset, double * padfLineBuf )
384 :
385 : {
386 : const char *pszLine;
387 1530 : int nValuesRead = 0, nValuesSought = psGXF->nRawXSize;
388 :
389 1530 : VSIFSeek( psGXF->fp, iOffset, SEEK_SET );
390 :
391 41554 : while( nValuesRead < nValuesSought )
392 : {
393 38494 : pszLine = CPLReadLine( psGXF->fp );
394 38494 : if( pszLine == NULL )
395 0 : break;
396 :
397 : /* -------------------------------------------------------------------- */
398 : /* Uncompressed case. */
399 : /* -------------------------------------------------------------------- */
400 38494 : if( psGXF->nGType == 0 )
401 : {
402 : /* we could just tokenize the line, but that's pretty expensive.
403 : Instead I will parse on white space ``by hand''. */
404 138216 : while( *pszLine != '\0' && nValuesRead < nValuesSought )
405 : {
406 : int i;
407 :
408 : /* skip leading white space */
409 110130 : for( ; isspace((unsigned char)*pszLine); pszLine++ ) {}
410 :
411 : /* Skip the data value (non white space) */
412 110130 : for( i = 0; pszLine[i] != '\0' && !isspace((unsigned char)pszLine[i]); i++) {}
413 :
414 110130 : if( strncmp(pszLine,psGXF->szDummy,i) == 0 )
415 : {
416 17731 : padfLineBuf[nValuesRead++] = psGXF->dfSetDummyTo;
417 : }
418 : else
419 : {
420 92399 : padfLineBuf[nValuesRead++] = atof(pszLine);
421 : }
422 :
423 : /* skip further whitespace */
424 110130 : for( pszLine += i; isspace((unsigned char)*pszLine); pszLine++ ) {}
425 : }
426 : }
427 :
428 : /* -------------------------------------------------------------------- */
429 : /* Compressed case. */
430 : /* -------------------------------------------------------------------- */
431 : else
432 : {
433 527977 : while( *pszLine != '\0' && nValuesRead < nValuesSought )
434 : {
435 479075 : if( pszLine[0] == '!' )
436 : {
437 1887 : padfLineBuf[nValuesRead++] = psGXF->dfSetDummyTo;
438 : }
439 477188 : else if( pszLine[0] == '"' )
440 : {
441 : int nCount, i;
442 : double dfValue;
443 :
444 1015 : pszLine += psGXF->nGType;
445 1015 : if( (int) strlen(pszLine) < psGXF->nGType )
446 22 : pszLine = CPLReadLine( psGXF->fp );
447 :
448 1015 : nCount = (int) GXFParseBase90( psGXF, pszLine, FALSE);
449 1015 : pszLine += psGXF->nGType;
450 :
451 1015 : if( (int) strlen(pszLine) < psGXF->nGType )
452 34 : pszLine = CPLReadLine( psGXF->fp );
453 :
454 1015 : if( *pszLine == '!' )
455 360 : dfValue = psGXF->dfSetDummyTo;
456 : else
457 655 : dfValue = GXFParseBase90( psGXF, pszLine, TRUE );
458 :
459 1015 : if( nValuesRead + nCount > nValuesSought )
460 : {
461 0 : CPLError(CE_Failure, CPLE_AppDefined, "Wrong count value");
462 0 : return CE_Failure;
463 : }
464 :
465 25212 : for( i=0; i < nCount && nValuesRead < nValuesSought; i++ )
466 24197 : padfLineBuf[nValuesRead++] = dfValue;
467 : }
468 : else
469 : {
470 952346 : padfLineBuf[nValuesRead++] =
471 476173 : GXFParseBase90( psGXF, pszLine, TRUE );
472 : }
473 :
474 479075 : pszLine += psGXF->nGType;
475 : }
476 : }
477 : }
478 :
479 : /* -------------------------------------------------------------------- */
480 : /* Return the new offset, if requested. */
481 : /* -------------------------------------------------------------------- */
482 1530 : if( pnNewOffset != NULL )
483 : {
484 1530 : *pnNewOffset = VSIFTell( psGXF->fp );
485 : }
486 :
487 1530 : return CE_None;
488 : }
489 :
490 : /************************************************************************/
491 : /* GXFGetScanline() */
492 : /************************************************************************/
493 :
494 : /**
495 : * Read a scanline of raster data from GXF file.
496 : *
497 : * This function operates similarly to GXFGetRawScanline(), but it
498 : * attempts to mirror data horizontally or vertically based on the #SENSE
499 : * flag to return data in a top to bottom, and left to right organization.
500 : * If the file is organized in columns (#SENSE is GXFS_UR_DOWN, GXFS_UL_DOWN,
501 : * GXFS_LR_UP, or GXFS_LL_UP) then this function will fail, returning
502 : * CE_Failure, and reporting a sense error.
503 : *
504 : * See GXFGetRawScanline() for other notes.
505 : *
506 : * @param hGXF the GXF file handle, as returned from GXFOpen().
507 : * @param iScanline the scanline to read, zero is the top scanline.
508 : * @param padfLineBuf a buffer of doubles into which the scanline pixel
509 : * values are read. This must be at least as long as a scanline.
510 : *
511 : * @return CE_None if access succeeds or CE_Failure if something goes wrong.
512 : */
513 :
514 0 : CPLErr GXFGetScanline( GXFHandle hGXF, int iScanline, double * padfLineBuf )
515 :
516 : {
517 0 : GXFInfo_t *psGXF = (GXFInfo_t *) hGXF;
518 : CPLErr nErr;
519 : int iRawScanline;
520 :
521 0 : if( psGXF->nSense == GXFS_LL_RIGHT
522 0 : || psGXF->nSense == GXFS_LR_LEFT )
523 : {
524 0 : iRawScanline = psGXF->nRawYSize - iScanline - 1;
525 : }
526 :
527 0 : else if( psGXF->nSense == GXFS_UL_RIGHT
528 0 : || psGXF->nSense == GXFS_UR_LEFT )
529 : {
530 0 : iRawScanline = iScanline;
531 : }
532 : else
533 : {
534 0 : CPLError( CE_Failure, CPLE_AppDefined,
535 : "Unable to support vertically oriented images." );
536 0 : return( CE_Failure );
537 : }
538 :
539 0 : nErr = GXFGetRawScanline( hGXF, iRawScanline, padfLineBuf );
540 :
541 0 : if( nErr == CE_None
542 0 : && (psGXF->nSense == GXFS_LR_LEFT || psGXF->nSense == GXFS_UR_LEFT) )
543 : {
544 : int i;
545 : double dfTemp;
546 :
547 0 : for( i = psGXF->nRawXSize / 2 - 1; i >= 0; i-- )
548 : {
549 0 : dfTemp = padfLineBuf[i];
550 0 : padfLineBuf[i] = padfLineBuf[psGXF->nRawXSize-i-1];
551 0 : padfLineBuf[psGXF->nRawXSize-i-1] = dfTemp;
552 : }
553 : }
554 :
555 0 : return( nErr );
556 : }
557 :
558 : /************************************************************************/
559 : /* GXFGetRawScanline() */
560 : /************************************************************************/
561 :
562 : /**
563 : * Read a scanline of raster data from GXF file.
564 : *
565 : * This function will read a row of data from the GXF file. It is "Raw"
566 : * in the sense that it doesn't attempt to account for the #SENSE flag as
567 : * the GXFGetScanline() function does. Unlike GXFGetScanline(), this function
568 : * supports column organized files.
569 : *
570 : * Any dummy pixels are assigned the dummy value indicated by GXFGetRawInfo().
571 : *
572 : * @param hGXF the GXF file handle, as returned from GXFOpen().
573 : * @param iScanline the scanline to read, zero is the first scanline in the
574 : * file.
575 : * @param padfLineBuf a buffer of doubles into which the scanline pixel
576 : * values are read. This must be at least as long as a scanline.
577 : *
578 : * @return CE_None if access succeeds or CE_Failure if something goes wrong.
579 : */
580 :
581 1530 : CPLErr GXFGetRawScanline( GXFHandle hGXF, int iScanline, double * padfLineBuf )
582 :
583 : {
584 1530 : GXFInfo_t *psGXF = (GXFInfo_t *) hGXF;
585 : CPLErr nErr;
586 :
587 : /* -------------------------------------------------------------------- */
588 : /* Validate scanline. */
589 : /* -------------------------------------------------------------------- */
590 1530 : if( iScanline < 0 || iScanline >= psGXF->nRawYSize )
591 : {
592 0 : CPLError( CE_Failure, CPLE_IllegalArg,
593 : "GXFGetRawScanline(): Scanline `%d' does not exist.\n",
594 : iScanline );
595 0 : return CE_Failure;
596 : }
597 :
598 : /* -------------------------------------------------------------------- */
599 : /* If we don't have the requested scanline, fetch preceeding */
600 : /* scanlines to find the pointer to this scanline. */
601 : /* -------------------------------------------------------------------- */
602 1530 : if( psGXF->panRawLineOffset[iScanline] == 0 )
603 : {
604 : int i;
605 :
606 : CPLAssert( iScanline > 0 );
607 :
608 0 : for( i = 0; i < iScanline; i++ )
609 : {
610 0 : if( psGXF->panRawLineOffset[i+1] == 0 )
611 : {
612 0 : nErr = GXFGetRawScanline( hGXF, i, padfLineBuf );
613 0 : if( nErr != CE_None )
614 0 : return( nErr );
615 : }
616 : }
617 : }
618 :
619 : /* -------------------------------------------------------------------- */
620 : /* Get this scanline, and update the offset for the next line. */
621 : /* -------------------------------------------------------------------- */
622 3060 : nErr = (CPLErr)
623 1530 : GXFReadRawScanlineFrom( psGXF, psGXF->panRawLineOffset[iScanline],
624 : psGXF->panRawLineOffset+iScanline+1,
625 : padfLineBuf );
626 :
627 1530 : return nErr;
628 : }
629 :
630 : /************************************************************************/
631 : /* GXFScanForZMinMax() */
632 : /* */
633 : /* The header doesn't contain the ZMin/ZMax values, but the */
634 : /* application has requested it ... scan the entire image for */
635 : /* it. */
636 : /************************************************************************/
637 :
638 0 : static void GXFScanForZMinMax( GXFHandle hGXF )
639 :
640 : {
641 0 : GXFInfo_t *psGXF = (GXFInfo_t *) hGXF;
642 : int iLine, iPixel;
643 : double *padfScanline;
644 :
645 :
646 0 : padfScanline = (double *) VSICalloc(sizeof(double),psGXF->nRawXSize);
647 0 : if( padfScanline == NULL )
648 0 : return;
649 :
650 0 : psGXF->dfZMinimum = 1e50;
651 0 : psGXF->dfZMaximum = -1e50;
652 :
653 0 : for( iLine = 0; iLine < psGXF->nRawYSize; iLine++ )
654 : {
655 0 : if( GXFGetRawScanline( hGXF, iLine, padfScanline ) != CE_None )
656 0 : break;
657 :
658 0 : for( iPixel = 0; iPixel < psGXF->nRawXSize; iPixel++ )
659 : {
660 0 : if( padfScanline[iPixel] != psGXF->dfSetDummyTo )
661 : {
662 0 : psGXF->dfZMinimum =
663 0 : MIN(psGXF->dfZMinimum,padfScanline[iPixel]);
664 0 : psGXF->dfZMaximum =
665 0 : MAX(psGXF->dfZMaximum,padfScanline[iPixel]);
666 : }
667 : }
668 : }
669 :
670 0 : VSIFree( padfScanline );
671 :
672 : /* -------------------------------------------------------------------- */
673 : /* Did we get any real data points? */
674 : /* -------------------------------------------------------------------- */
675 0 : if( psGXF->dfZMinimum > psGXF->dfZMaximum )
676 : {
677 0 : psGXF->dfZMinimum = 0.0;
678 0 : psGXF->dfZMaximum = 0.0;
679 : }
680 : }
681 :
682 : /************************************************************************/
683 : /* GXFGetRawInfo() */
684 : /************************************************************************/
685 :
686 : /**
687 : * Fetch header information about a GXF file.
688 : *
689 : * Note that the X and Y sizes are of the raw raster and don't take into
690 : * account the #SENSE flag. If the file is column oriented (rows in the
691 : * files are actually columns in the raster) these values would need to be
692 : * transposed for the actual raster.
693 : *
694 : * The legal pnSense values are:
695 : * <ul>
696 : * <li> GXFS_LL_UP(-1): lower left origin, scanning up.
697 : * <li> GXFS_LL_RIGHT(1): lower left origin, scanning right.
698 : * <li> GXFS_UL_RIGHT(-2): upper left origin, scanning right.
699 : * <li> GXFS_UL_DOWN(2): upper left origin, scanning down.
700 : * <li> GXFS_UR_DOWN(-3): upper right origin, scanning down.
701 : * <li> GXFS_UR_LEFT(3): upper right origin, scanning left.
702 : * <li> GXFS_LR_LEFT(-4): lower right origin, scanning left.
703 : * <li> GXFS_LR_UP(4): lower right origin, scanning up.
704 : * </ul>
705 : *
706 : * Note that the GXFGetScanline() function attempts to provide a GXFS_UL_RIGHT
707 : * view onto files, but doesn't handle the *_DOWN and *_UP oriented files.
708 : *
709 : * The Z min and max values may not occur in the GXF header. If they are
710 : * requested, and aren't available in the header the entire file is scanned
711 : * in order to establish them. This can be expensive.
712 : *
713 : * If no #DUMMY value was specified in the file, a default of -1e12 is used.
714 : *
715 : * @param hGXF handle to GXF file returned by GXFOpen().
716 : * @param pnXSize int to be set with the width of the raw raster. May be NULL.
717 : * @param pnYSize int to be set with the height of the raw raster. May be NULL.
718 : * @param pnSense int to set with #SENSE flag, may be NULL.
719 : * @param pdfZMin double to set with minimum raster value, may be NULL.
720 : * @param pdfZMax double to set with minimum raster value, may be NULL.
721 : * @param pdfDummy double to set with dummy (nodata / invalid data) pixel
722 : * value.
723 : */
724 :
725 7 : CPLErr GXFGetRawInfo( GXFHandle hGXF, int *pnXSize, int *pnYSize,
726 : int * pnSense, double * pdfZMin, double * pdfZMax,
727 : double * pdfDummy )
728 :
729 : {
730 7 : GXFInfo_t *psGXF = (GXFInfo_t *) hGXF;
731 :
732 7 : if( pnXSize != NULL )
733 7 : *pnXSize = psGXF->nRawXSize;
734 :
735 7 : if( pnYSize != NULL )
736 7 : *pnYSize = psGXF->nRawYSize;
737 :
738 7 : if( pnSense != NULL )
739 0 : *pnSense = psGXF->nSense;
740 :
741 7 : if( (pdfZMin != NULL || pdfZMax != NULL)
742 0 : && psGXF->dfZMinimum == 0.0 && psGXF->dfZMaximum == 0.0 )
743 : {
744 0 : GXFScanForZMinMax( hGXF );
745 : }
746 :
747 7 : if( pdfZMin != NULL )
748 0 : *pdfZMin = psGXF->dfZMinimum;
749 :
750 7 : if( pdfZMax != NULL )
751 0 : *pdfZMax = psGXF->dfZMaximum;
752 :
753 7 : if( pdfDummy != NULL )
754 7 : *pdfDummy = psGXF->dfSetDummyTo;
755 :
756 7 : return( CE_None );
757 : }
758 :
759 : /************************************************************************/
760 : /* GXFGetMapProjection() */
761 : /************************************************************************/
762 :
763 : /**
764 : * Return the lines related to the map projection. It is up to
765 : * the caller to parse them and interprete. The return result
766 : * will be NULL if no #MAP_PROJECTION line was found in the header.
767 : *
768 : * @param hGXF the GXF file handle.
769 : *
770 : * @return a NULL terminated array of string pointers containing the
771 : * projection, or NULL. The strings remained owned by the GXF API, and
772 : * should not be modified or freed by the caller.
773 : */
774 :
775 0 : char **GXFGetMapProjection( GXFHandle hGXF )
776 :
777 : {
778 0 : return( ((GXFInfo_t *) hGXF)->papszMapProjection );
779 : }
780 :
781 : /************************************************************************/
782 : /* GXFGetMapDatumTransform() */
783 : /************************************************************************/
784 :
785 : /**
786 : * Return the lines related to the datum transformation. It is up to
787 : * the caller to parse them and interpret. The return result
788 : * will be NULL if no #MAP_DATUM_TRANSFORM line was found in the header.
789 : *
790 : * @param hGXF the GXF file handle.
791 : *
792 : * @return a NULL terminated array of string pointers containing the
793 : * datum, or NULL. The strings remained owned by the GXF API, and
794 : * should not be modified or freed by the caller.
795 : */
796 :
797 0 : char **GXFGetMapDatumTransform( GXFHandle hGXF )
798 :
799 : {
800 0 : return( ((GXFInfo_t *) hGXF)->papszMapDatumTransform );
801 : }
802 :
803 : /************************************************************************/
804 : /* GXFGetRawPosition() */
805 : /************************************************************************/
806 :
807 : /**
808 : * Get the raw grid positioning information.
809 : *
810 : * Note that these coordinates refer to the raw grid, and are in the units
811 : * specified by the #UNITS field. See GXFGetPosition() for a similar
812 : * function that takes into account the #SENSE values similarly to
813 : * GXFGetScanline().
814 : *
815 : * Note that the pixel values are considered to be point values in GXF,
816 : * and thus the origin is for the first point. If you consider the pixels
817 : * to be areas, then the origin is for the center of the origin pixel, not
818 : * the outer corner.
819 : *
820 : * @param hGXF the GXF file handle.
821 : * @param pdfXOrigin X position of the origin in the base coordinate system.
822 : * @param pdfYOrigin Y position of the origin in the base coordinate system.
823 : * @param pdfXPixelSize X pixel size in base coordinates.
824 : * @param pdfYPixelSize Y pixel size in base coordinates.
825 : * @param pdfRotation rotation in degrees counter-clockwise from the
826 : * base coordinate system.
827 : *
828 : * @return Returns CE_None if successful, or CE_Failure if no posiitioning
829 : * information was found in the file.
830 : */
831 :
832 :
833 0 : CPLErr GXFGetRawPosition( GXFHandle hGXF,
834 : double * pdfXOrigin, double * pdfYOrigin,
835 : double * pdfXPixelSize, double * pdfYPixelSize,
836 : double * pdfRotation )
837 :
838 : {
839 0 : GXFInfo_t *psGXF = (GXFInfo_t *) hGXF;
840 :
841 0 : if( pdfXOrigin != NULL )
842 0 : *pdfXOrigin = psGXF->dfXOrigin;
843 0 : if( pdfYOrigin != NULL )
844 0 : *pdfYOrigin = psGXF->dfYOrigin;
845 0 : if( pdfXPixelSize != NULL )
846 0 : *pdfXPixelSize = psGXF->dfXPixelSize;
847 0 : if( pdfYPixelSize != NULL )
848 0 : *pdfYPixelSize = psGXF->dfYPixelSize;
849 0 : if( pdfRotation != NULL )
850 0 : *pdfRotation = psGXF->dfRotation;
851 :
852 0 : if( psGXF->dfXOrigin == 0.0 && psGXF->dfYOrigin == 0.0
853 0 : && psGXF->dfXPixelSize == 0.0 && psGXF->dfYPixelSize == 0.0 )
854 0 : return( CE_Failure );
855 : else
856 0 : return( CE_None );
857 : }
858 :
859 :
860 : /************************************************************************/
861 : /* GXFGetPosition() */
862 : /************************************************************************/
863 :
864 : /**
865 : * Get the grid positioning information.
866 : *
867 : * Note that these coordinates refer to the grid positioning after taking
868 : * into account the #SENSE flag (as is done by the GXFGetScanline()) function.
869 : *
870 : * Note that the pixel values are considered to be point values in GXF,
871 : * and thus the origin is for the first point. If you consider the pixels
872 : * to be areas, then the origin is for the center of the origin pixel, not
873 : * the outer corner.
874 : *
875 : * This function does not support vertically oriented images, nor does it
876 : * properly transform rotation for images with a SENSE other than
877 : * GXFS_UL_RIGHT.
878 : *
879 : * @param hGXF the GXF file handle.
880 : * @param pdfXOrigin X position of the origin in the base coordinate system.
881 : * @param pdfYOrigin Y position of the origin in the base coordinate system.
882 : * @param pdfXPixelSize X pixel size in base coordinates.
883 : * @param pdfYPixelSize Y pixel size in base coordinates.
884 : * @param pdfRotation rotation in degrees counter-clockwise from the
885 : * base coordinate system.
886 : *
887 : * @return Returns CE_None if successful, or CE_Failure if no posiitioning
888 : * information was found in the file.
889 : */
890 :
891 :
892 0 : CPLErr GXFGetPosition( GXFHandle hGXF,
893 : double * pdfXOrigin, double * pdfYOrigin,
894 : double * pdfXPixelSize, double * pdfYPixelSize,
895 : double * pdfRotation )
896 :
897 : {
898 0 : GXFInfo_t *psGXF = (GXFInfo_t *) hGXF;
899 : double dfCXOrigin, dfCYOrigin, dfCXPixelSize, dfCYPixelSize;
900 :
901 0 : switch( psGXF->nSense )
902 : {
903 : case GXFS_UL_RIGHT:
904 0 : dfCXOrigin = psGXF->dfXOrigin;
905 0 : dfCYOrigin = psGXF->dfYOrigin;
906 0 : dfCXPixelSize = psGXF->dfXPixelSize;
907 0 : dfCYPixelSize = psGXF->dfYPixelSize;
908 0 : break;
909 :
910 : case GXFS_UR_LEFT:
911 0 : dfCXOrigin = psGXF->dfXOrigin
912 0 : - (psGXF->nRawXSize-1) * psGXF->dfXPixelSize;
913 0 : dfCYOrigin = psGXF->dfYOrigin;
914 0 : dfCXPixelSize = psGXF->dfXPixelSize;
915 0 : dfCYPixelSize = psGXF->dfYPixelSize;
916 0 : break;
917 :
918 : case GXFS_LL_RIGHT:
919 0 : dfCXOrigin = psGXF->dfXOrigin;
920 0 : dfCYOrigin = psGXF->dfYOrigin
921 0 : + (psGXF->nRawYSize-1) * psGXF->dfYPixelSize;
922 0 : dfCXPixelSize = psGXF->dfXPixelSize;
923 0 : dfCYPixelSize = psGXF->dfYPixelSize;
924 0 : break;
925 :
926 : case GXFS_LR_LEFT:
927 0 : dfCXOrigin = psGXF->dfXOrigin
928 0 : - (psGXF->nRawXSize-1) * psGXF->dfXPixelSize;
929 0 : dfCYOrigin = psGXF->dfYOrigin
930 0 : + (psGXF->nRawYSize-1) * psGXF->dfYPixelSize;
931 0 : dfCXPixelSize = psGXF->dfXPixelSize;
932 0 : dfCYPixelSize = psGXF->dfYPixelSize;
933 0 : break;
934 :
935 : default:
936 0 : CPLError( CE_Failure, CPLE_AppDefined,
937 : "GXFGetPosition() doesn't support vertically organized images." );
938 0 : return CE_Failure;
939 : }
940 :
941 0 : if( pdfXOrigin != NULL )
942 0 : *pdfXOrigin = dfCXOrigin;
943 0 : if( pdfYOrigin != NULL )
944 0 : *pdfYOrigin = dfCYOrigin;
945 0 : if( pdfXPixelSize != NULL )
946 0 : *pdfXPixelSize = dfCXPixelSize;
947 0 : if( pdfYPixelSize != NULL )
948 0 : *pdfYPixelSize = dfCYPixelSize;
949 0 : if( pdfRotation != NULL )
950 0 : *pdfRotation = psGXF->dfRotation;
951 :
952 0 : if( psGXF->dfXOrigin == 0.0 && psGXF->dfYOrigin == 0.0
953 0 : && psGXF->dfXPixelSize == 0.0 && psGXF->dfYPixelSize == 0.0 )
954 0 : return( CE_Failure );
955 : else
956 0 : return( CE_None );
957 : }
958 :
959 :
|