1 : /******************************************************************************
2 : * $Id: gxfopen.c 19867 2010-06-14 20:45:06Z rouault $
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 19867 2010-06-14 20:45:06Z rouault $");
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 : static char **GXFReadHeaderValue( FILE * fp, char * pszHTitle )
48 :
49 96 : {
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 : GXFHandle GXFOpen( const char * pszFilename )
143 :
144 7 : {
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 : 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 : void GXFClose( GXFHandle hGXF )
335 :
336 7 : {
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 7 : CPLFree( psGXF->pszTransformName );
345 :
346 7 : VSIFClose( psGXF->fp );
347 :
348 7 : CPLReadLine( NULL );
349 :
350 7 : CPLFree( psGXF );
351 7 : }
352 :
353 : /************************************************************************/
354 : /* GXFParseBase90() */
355 : /* */
356 : /* Parse a base 90 number ... exceptions (repeat, and dummy) */
357 : /* values have to be recognised outside this function. */
358 : /************************************************************************/
359 :
360 : double GXFParseBase90( GXFInfo_t * psGXF, const char * pszText,
361 : int bScale )
362 :
363 477843 : {
364 477843 : int i = 0, nValue = 0;
365 :
366 2867058 : while( i < psGXF->nGType )
367 : {
368 1911372 : nValue = nValue*90 + (pszText[i] - 37);
369 1911372 : i++;
370 : }
371 :
372 477843 : if( bScale )
373 476828 : return( (nValue * psGXF->dfTransformScale) + psGXF->dfTransformOffset);
374 : else
375 1015 : return( nValue );
376 : }
377 :
378 :
379 : /************************************************************************/
380 : /* GXFReadRawScanlineFrom() */
381 : /************************************************************************/
382 :
383 : static int GXFReadRawScanlineFrom( GXFInfo_t * psGXF, long iOffset,
384 : long * pnNewOffset, double * padfLineBuf )
385 :
386 1530 : {
387 : const char *pszLine;
388 1530 : int nValuesRead = 0, nValuesSought = psGXF->nRawXSize;
389 :
390 1530 : VSIFSeek( psGXF->fp, iOffset, SEEK_SET );
391 :
392 41554 : while( nValuesRead < nValuesSought )
393 : {
394 38494 : pszLine = CPLReadLine( psGXF->fp );
395 38494 : if( pszLine == NULL )
396 0 : break;
397 :
398 : /* -------------------------------------------------------------------- */
399 : /* Uncompressed case. */
400 : /* -------------------------------------------------------------------- */
401 38494 : if( psGXF->nGType == 0 )
402 : {
403 : /* we could just tokenize the line, but that's pretty expensive.
404 : Instead I will parse on white space ``by hand''. */
405 138216 : while( *pszLine != '\0' && nValuesRead < nValuesSought )
406 : {
407 : int i;
408 :
409 : /* skip leading white space */
410 110130 : for( ; isspace((unsigned char)*pszLine); pszLine++ ) {}
411 :
412 : /* Skip the data value (non white space) */
413 110130 : for( i = 0; pszLine[i] != '\0' && !isspace((unsigned char)pszLine[i]); i++) {}
414 :
415 110130 : if( strncmp(pszLine,psGXF->szDummy,i) == 0 )
416 : {
417 17731 : padfLineBuf[nValuesRead++] = psGXF->dfSetDummyTo;
418 : }
419 : else
420 : {
421 92399 : padfLineBuf[nValuesRead++] = atof(pszLine);
422 : }
423 :
424 : /* skip further whitespace */
425 110130 : for( pszLine += i; isspace((unsigned char)*pszLine); pszLine++ ) {}
426 : }
427 : }
428 :
429 : /* -------------------------------------------------------------------- */
430 : /* Compressed case. */
431 : /* -------------------------------------------------------------------- */
432 : else
433 : {
434 527977 : while( *pszLine != '\0' && nValuesRead < nValuesSought )
435 : {
436 479075 : if( pszLine[0] == '!' )
437 : {
438 1887 : padfLineBuf[nValuesRead++] = psGXF->dfSetDummyTo;
439 : }
440 477188 : else if( pszLine[0] == '"' )
441 : {
442 : int nCount, i;
443 : double dfValue;
444 :
445 1015 : pszLine += psGXF->nGType;
446 1015 : if( (int) strlen(pszLine) < psGXF->nGType )
447 22 : pszLine = CPLReadLine( psGXF->fp );
448 :
449 1015 : nCount = (int) GXFParseBase90( psGXF, pszLine, FALSE);
450 1015 : pszLine += psGXF->nGType;
451 :
452 1015 : if( (int) strlen(pszLine) < psGXF->nGType )
453 34 : pszLine = CPLReadLine( psGXF->fp );
454 :
455 1015 : if( *pszLine == '!' )
456 360 : dfValue = psGXF->dfSetDummyTo;
457 : else
458 655 : dfValue = GXFParseBase90( psGXF, pszLine, TRUE );
459 :
460 1015 : if( nValuesRead + nCount > nValuesSought )
461 : {
462 0 : CPLError(CE_Failure, CPLE_AppDefined, "Wrong count value");
463 0 : return CE_Failure;
464 : }
465 :
466 25212 : for( i=0; i < nCount && nValuesRead < nValuesSought; i++ )
467 24197 : padfLineBuf[nValuesRead++] = dfValue;
468 : }
469 : else
470 : {
471 476173 : padfLineBuf[nValuesRead++] =
472 : GXFParseBase90( psGXF, pszLine, TRUE );
473 : }
474 :
475 479075 : pszLine += psGXF->nGType;
476 : }
477 : }
478 : }
479 :
480 : /* -------------------------------------------------------------------- */
481 : /* Return the new offset, if requested. */
482 : /* -------------------------------------------------------------------- */
483 1530 : if( pnNewOffset != NULL )
484 : {
485 1530 : *pnNewOffset = VSIFTell( psGXF->fp );
486 : }
487 :
488 1530 : return CE_None;
489 : }
490 :
491 : /************************************************************************/
492 : /* GXFGetScanline() */
493 : /************************************************************************/
494 :
495 : /**
496 : * Read a scanline of raster data from GXF file.
497 : *
498 : * This function operates similarly to GXFGetRawScanline(), but it
499 : * attempts to mirror data horizontally or vertically based on the #SENSE
500 : * flag to return data in a top to bottom, and left to right organization.
501 : * If the file is organized in columns (#SENSE is GXFS_UR_DOWN, GXFS_UL_DOWN,
502 : * GXFS_LR_UP, or GXFS_LL_UP) then this function will fail, returning
503 : * CE_Failure, and reporting a sense error.
504 : *
505 : * See GXFGetRawScanline() for other notes.
506 : *
507 : * @param hGXF the GXF file handle, as returned from GXFOpen().
508 : * @param iScanline the scanline to read, zero is the top scanline.
509 : * @param padfLineBuf a buffer of doubles into which the scanline pixel
510 : * values are read. This must be at least as long as a scanline.
511 : *
512 : * @return CE_None if access succeeds or CE_Failure if something goes wrong.
513 : */
514 :
515 : CPLErr GXFGetScanline( GXFHandle hGXF, int iScanline, double * padfLineBuf )
516 :
517 0 : {
518 0 : GXFInfo_t *psGXF = (GXFInfo_t *) hGXF;
519 : CPLErr nErr;
520 : int iRawScanline;
521 :
522 0 : if( psGXF->nSense == GXFS_LL_RIGHT
523 : || psGXF->nSense == GXFS_LR_LEFT )
524 : {
525 0 : iRawScanline = psGXF->nRawYSize - iScanline - 1;
526 : }
527 :
528 0 : else if( psGXF->nSense == GXFS_UL_RIGHT
529 : || psGXF->nSense == GXFS_UR_LEFT )
530 : {
531 0 : iRawScanline = iScanline;
532 : }
533 : else
534 : {
535 0 : CPLError( CE_Failure, CPLE_AppDefined,
536 : "Unable to support vertically oriented images." );
537 0 : return( CE_Failure );
538 : }
539 :
540 0 : nErr = GXFGetRawScanline( hGXF, iRawScanline, padfLineBuf );
541 :
542 0 : if( nErr == CE_None
543 : && (psGXF->nSense == GXFS_LR_LEFT || psGXF->nSense == GXFS_UR_LEFT) )
544 : {
545 : int i;
546 : double dfTemp;
547 :
548 0 : for( i = psGXF->nRawXSize / 2 - 1; i >= 0; i-- )
549 : {
550 0 : dfTemp = padfLineBuf[i];
551 0 : padfLineBuf[i] = padfLineBuf[psGXF->nRawXSize-i-1];
552 0 : padfLineBuf[psGXF->nRawXSize-i-1] = dfTemp;
553 : }
554 : }
555 :
556 0 : return( nErr );
557 : }
558 :
559 : /************************************************************************/
560 : /* GXFGetRawScanline() */
561 : /************************************************************************/
562 :
563 : /**
564 : * Read a scanline of raster data from GXF file.
565 : *
566 : * This function will read a row of data from the GXF file. It is "Raw"
567 : * in the sense that it doesn't attempt to account for the #SENSE flag as
568 : * the GXFGetScanline() function does. Unlike GXFGetScanline(), this function
569 : * supports column organized files.
570 : *
571 : * Any dummy pixels are assigned the dummy value indicated by GXFGetRawInfo().
572 : *
573 : * @param hGXF the GXF file handle, as returned from GXFOpen().
574 : * @param iScanline the scanline to read, zero is the first scanline in the
575 : * file.
576 : * @param padfLineBuf a buffer of doubles into which the scanline pixel
577 : * values are read. This must be at least as long as a scanline.
578 : *
579 : * @return CE_None if access succeeds or CE_Failure if something goes wrong.
580 : */
581 :
582 : CPLErr GXFGetRawScanline( GXFHandle hGXF, int iScanline, double * padfLineBuf )
583 :
584 1530 : {
585 1530 : GXFInfo_t *psGXF = (GXFInfo_t *) hGXF;
586 : CPLErr nErr;
587 :
588 : /* -------------------------------------------------------------------- */
589 : /* Validate scanline. */
590 : /* -------------------------------------------------------------------- */
591 1530 : if( iScanline < 0 || iScanline >= psGXF->nRawYSize )
592 : {
593 0 : CPLError( CE_Failure, CPLE_IllegalArg,
594 : "GXFGetRawScanline(): Scanline `%d' does not exist.\n",
595 : iScanline );
596 0 : return CE_Failure;
597 : }
598 :
599 : /* -------------------------------------------------------------------- */
600 : /* If we don't have the requested scanline, fetch preceeding */
601 : /* scanlines to find the pointer to this scanline. */
602 : /* -------------------------------------------------------------------- */
603 1530 : if( psGXF->panRawLineOffset[iScanline] == 0 )
604 : {
605 : int i;
606 :
607 0 : CPLAssert( iScanline > 0 );
608 :
609 0 : for( i = 0; i < iScanline; i++ )
610 : {
611 0 : if( psGXF->panRawLineOffset[i+1] == 0 )
612 : {
613 0 : nErr = GXFGetRawScanline( hGXF, i, padfLineBuf );
614 0 : if( nErr != CE_None )
615 0 : return( nErr );
616 : }
617 : }
618 : }
619 :
620 : /* -------------------------------------------------------------------- */
621 : /* Get this scanline, and update the offset for the next line. */
622 : /* -------------------------------------------------------------------- */
623 1530 : nErr = (CPLErr)
624 : GXFReadRawScanlineFrom( psGXF, psGXF->panRawLineOffset[iScanline],
625 : psGXF->panRawLineOffset+iScanline+1,
626 : padfLineBuf );
627 :
628 1530 : return nErr;
629 : }
630 :
631 : /************************************************************************/
632 : /* GXFScanForZMinMax() */
633 : /* */
634 : /* The header doesn't contain the ZMin/ZMax values, but the */
635 : /* application has requested it ... scan the entire image for */
636 : /* it. */
637 : /************************************************************************/
638 :
639 : static void GXFScanForZMinMax( GXFHandle hGXF )
640 :
641 0 : {
642 0 : GXFInfo_t *psGXF = (GXFInfo_t *) hGXF;
643 : int iLine, iPixel;
644 : double *padfScanline;
645 :
646 :
647 0 : padfScanline = (double *) VSICalloc(sizeof(double),psGXF->nRawXSize);
648 0 : if( padfScanline == NULL )
649 0 : return;
650 :
651 0 : psGXF->dfZMinimum = 1e50;
652 0 : psGXF->dfZMaximum = -1e50;
653 :
654 0 : for( iLine = 0; iLine < psGXF->nRawYSize; iLine++ )
655 : {
656 0 : if( GXFGetRawScanline( hGXF, iLine, padfScanline ) != CE_None )
657 0 : break;
658 :
659 0 : for( iPixel = 0; iPixel < psGXF->nRawXSize; iPixel++ )
660 : {
661 0 : if( padfScanline[iPixel] != psGXF->dfSetDummyTo )
662 : {
663 0 : psGXF->dfZMinimum =
664 : MIN(psGXF->dfZMinimum,padfScanline[iPixel]);
665 0 : psGXF->dfZMaximum =
666 : MAX(psGXF->dfZMaximum,padfScanline[iPixel]);
667 : }
668 : }
669 : }
670 :
671 0 : VSIFree( padfScanline );
672 :
673 : /* -------------------------------------------------------------------- */
674 : /* Did we get any real data points? */
675 : /* -------------------------------------------------------------------- */
676 0 : if( psGXF->dfZMinimum > psGXF->dfZMaximum )
677 : {
678 0 : psGXF->dfZMinimum = 0.0;
679 0 : psGXF->dfZMaximum = 0.0;
680 : }
681 : }
682 :
683 : /************************************************************************/
684 : /* GXFGetRawInfo() */
685 : /************************************************************************/
686 :
687 : /**
688 : * Fetch header information about a GXF file.
689 : *
690 : * Note that the X and Y sizes are of the raw raster and don't take into
691 : * account the #SENSE flag. If the file is column oriented (rows in the
692 : * files are actually columns in the raster) these values would need to be
693 : * transposed for the actual raster.
694 : *
695 : * The legal pnSense values are:
696 : * <ul>
697 : * <li> GXFS_LL_UP(-1): lower left origin, scanning up.
698 : * <li> GXFS_LL_RIGHT(1): lower left origin, scanning right.
699 : * <li> GXFS_UL_RIGHT(-2): upper left origin, scanning right.
700 : * <li> GXFS_UL_DOWN(2): upper left origin, scanning down.
701 : * <li> GXFS_UR_DOWN(-3): upper right origin, scanning down.
702 : * <li> GXFS_UR_LEFT(3): upper right origin, scanning left.
703 : * <li> GXFS_LR_LEFT(-4): lower right origin, scanning left.
704 : * <li> GXFS_LR_UP(4): lower right origin, scanning up.
705 : * </ul>
706 : *
707 : * Note that the GXFGetScanline() function attempts to provide a GXFS_UL_RIGHT
708 : * view onto files, but doesn't handle the *_DOWN and *_UP oriented files.
709 : *
710 : * The Z min and max values may not occur in the GXF header. If they are
711 : * requested, and aren't available in the header the entire file is scanned
712 : * in order to establish them. This can be expensive.
713 : *
714 : * If no #DUMMY value was specified in the file, a default of -1e12 is used.
715 : *
716 : * @param hGXF handle to GXF file returned by GXFOpen().
717 : * @param pnXSize int to be set with the width of the raw raster. May be NULL.
718 : * @param pnYSize int to be set with the height of the raw raster. May be NULL.
719 : * @param pnSense int to set with #SENSE flag, may be NULL.
720 : * @param pdfZMin double to set with minimum raster value, may be NULL.
721 : * @param pdfZMax double to set with minimum raster value, may be NULL.
722 : * @param pdfDummy double to set with dummy (nodata / invalid data) pixel
723 : * value.
724 : */
725 :
726 : CPLErr GXFGetRawInfo( GXFHandle hGXF, int *pnXSize, int *pnYSize,
727 : int * pnSense, double * pdfZMin, double * pdfZMax,
728 : double * pdfDummy )
729 :
730 7 : {
731 7 : GXFInfo_t *psGXF = (GXFInfo_t *) hGXF;
732 :
733 7 : if( pnXSize != NULL )
734 7 : *pnXSize = psGXF->nRawXSize;
735 :
736 7 : if( pnYSize != NULL )
737 7 : *pnYSize = psGXF->nRawYSize;
738 :
739 7 : if( pnSense != NULL )
740 0 : *pnSense = psGXF->nSense;
741 :
742 7 : if( (pdfZMin != NULL || pdfZMax != NULL)
743 : && psGXF->dfZMinimum == 0.0 && psGXF->dfZMaximum == 0.0 )
744 : {
745 0 : GXFScanForZMinMax( hGXF );
746 : }
747 :
748 7 : if( pdfZMin != NULL )
749 0 : *pdfZMin = psGXF->dfZMinimum;
750 :
751 7 : if( pdfZMax != NULL )
752 0 : *pdfZMax = psGXF->dfZMaximum;
753 :
754 7 : if( pdfDummy != NULL )
755 7 : *pdfDummy = psGXF->dfSetDummyTo;
756 :
757 7 : return( CE_None );
758 : }
759 :
760 : /************************************************************************/
761 : /* GXFGetMapProjection() */
762 : /************************************************************************/
763 :
764 : /**
765 : * Return the lines related to the map projection. It is up to
766 : * the caller to parse them and interprete. The return result
767 : * will be NULL if no #MAP_PROJECTION line was found in the header.
768 : *
769 : * @param hGXF the GXF file handle.
770 : *
771 : * @return a NULL terminated array of string pointers containing the
772 : * projection, or NULL. The strings remained owned by the GXF API, and
773 : * should not be modified or freed by the caller.
774 : */
775 :
776 : char **GXFGetMapProjection( GXFHandle hGXF )
777 :
778 0 : {
779 0 : return( ((GXFInfo_t *) hGXF)->papszMapProjection );
780 : }
781 :
782 : /************************************************************************/
783 : /* GXFGetMapDatumTransform() */
784 : /************************************************************************/
785 :
786 : /**
787 : * Return the lines related to the datum transformation. It is up to
788 : * the caller to parse them and interpret. The return result
789 : * will be NULL if no #MAP_DATUM_TRANSFORM line was found in the header.
790 : *
791 : * @param hGXF the GXF file handle.
792 : *
793 : * @return a NULL terminated array of string pointers containing the
794 : * datum, or NULL. The strings remained owned by the GXF API, and
795 : * should not be modified or freed by the caller.
796 : */
797 :
798 : char **GXFGetMapDatumTransform( GXFHandle hGXF )
799 :
800 0 : {
801 0 : return( ((GXFInfo_t *) hGXF)->papszMapDatumTransform );
802 : }
803 :
804 : /************************************************************************/
805 : /* GXFGetRawPosition() */
806 : /************************************************************************/
807 :
808 : /**
809 : * Get the raw grid positioning information.
810 : *
811 : * Note that these coordinates refer to the raw grid, and are in the units
812 : * specified by the #UNITS field. See GXFGetPosition() for a similar
813 : * function that takes into account the #SENSE values similarly to
814 : * GXFGetScanline().
815 : *
816 : * Note that the pixel values are considered to be point values in GXF,
817 : * and thus the origin is for the first point. If you consider the pixels
818 : * to be areas, then the origin is for the center of the origin pixel, not
819 : * the outer corner.
820 : *
821 : * @param hGXF the GXF file handle.
822 : * @param pdfXOrigin X position of the origin in the base coordinate system.
823 : * @param pdfYOrigin Y position of the origin in the base coordinate system.
824 : * @param pdfXPixelSize X pixel size in base coordinates.
825 : * @param pdfYPixelSize Y pixel size in base coordinates.
826 : * @param pdfRotation rotation in degrees counter-clockwise from the
827 : * base coordinate system.
828 : *
829 : * @return Returns CE_None if successful, or CE_Failure if no posiitioning
830 : * information was found in the file.
831 : */
832 :
833 :
834 : CPLErr GXFGetRawPosition( GXFHandle hGXF,
835 : double * pdfXOrigin, double * pdfYOrigin,
836 : double * pdfXPixelSize, double * pdfYPixelSize,
837 : double * pdfRotation )
838 :
839 0 : {
840 0 : GXFInfo_t *psGXF = (GXFInfo_t *) hGXF;
841 :
842 0 : if( pdfXOrigin != NULL )
843 0 : *pdfXOrigin = psGXF->dfXOrigin;
844 0 : if( pdfYOrigin != NULL )
845 0 : *pdfYOrigin = psGXF->dfYOrigin;
846 0 : if( pdfXPixelSize != NULL )
847 0 : *pdfXPixelSize = psGXF->dfXPixelSize;
848 0 : if( pdfYPixelSize != NULL )
849 0 : *pdfYPixelSize = psGXF->dfYPixelSize;
850 0 : if( pdfRotation != NULL )
851 0 : *pdfRotation = psGXF->dfRotation;
852 :
853 0 : if( psGXF->dfXOrigin == 0.0 && psGXF->dfYOrigin == 0.0
854 : && psGXF->dfXPixelSize == 0.0 && psGXF->dfYPixelSize == 0.0 )
855 0 : return( CE_Failure );
856 : else
857 0 : return( CE_None );
858 : }
859 :
860 :
861 : /************************************************************************/
862 : /* GXFGetPosition() */
863 : /************************************************************************/
864 :
865 : /**
866 : * Get the grid positioning information.
867 : *
868 : * Note that these coordinates refer to the grid positioning after taking
869 : * into account the #SENSE flag (as is done by the GXFGetScanline()) function.
870 : *
871 : * Note that the pixel values are considered to be point values in GXF,
872 : * and thus the origin is for the first point. If you consider the pixels
873 : * to be areas, then the origin is for the center of the origin pixel, not
874 : * the outer corner.
875 : *
876 : * This function does not support vertically oriented images, nor does it
877 : * properly transform rotation for images with a SENSE other than
878 : * GXFS_UL_RIGHT.
879 : *
880 : * @param hGXF the GXF file handle.
881 : * @param pdfXOrigin X position of the origin in the base coordinate system.
882 : * @param pdfYOrigin Y position of the origin in the base coordinate system.
883 : * @param pdfXPixelSize X pixel size in base coordinates.
884 : * @param pdfYPixelSize Y pixel size in base coordinates.
885 : * @param pdfRotation rotation in degrees counter-clockwise from the
886 : * base coordinate system.
887 : *
888 : * @return Returns CE_None if successful, or CE_Failure if no posiitioning
889 : * information was found in the file.
890 : */
891 :
892 :
893 : CPLErr GXFGetPosition( GXFHandle hGXF,
894 : double * pdfXOrigin, double * pdfYOrigin,
895 : double * pdfXPixelSize, double * pdfYPixelSize,
896 : double * pdfRotation )
897 :
898 0 : {
899 0 : GXFInfo_t *psGXF = (GXFInfo_t *) hGXF;
900 : double dfCXOrigin, dfCYOrigin, dfCXPixelSize, dfCYPixelSize;
901 :
902 0 : switch( psGXF->nSense )
903 : {
904 : case GXFS_UL_RIGHT:
905 0 : dfCXOrigin = psGXF->dfXOrigin;
906 0 : dfCYOrigin = psGXF->dfYOrigin;
907 0 : dfCXPixelSize = psGXF->dfXPixelSize;
908 0 : dfCYPixelSize = psGXF->dfYPixelSize;
909 0 : break;
910 :
911 : case GXFS_UR_LEFT:
912 0 : dfCXOrigin = psGXF->dfXOrigin
913 : - (psGXF->nRawXSize-1) * psGXF->dfXPixelSize;
914 0 : dfCYOrigin = psGXF->dfYOrigin;
915 0 : dfCXPixelSize = psGXF->dfXPixelSize;
916 0 : dfCYPixelSize = psGXF->dfYPixelSize;
917 0 : break;
918 :
919 : case GXFS_LL_RIGHT:
920 0 : dfCXOrigin = psGXF->dfXOrigin;
921 0 : dfCYOrigin = psGXF->dfYOrigin
922 : + (psGXF->nRawYSize-1) * psGXF->dfYPixelSize;
923 0 : dfCXPixelSize = psGXF->dfXPixelSize;
924 0 : dfCYPixelSize = psGXF->dfYPixelSize;
925 0 : break;
926 :
927 : case GXFS_LR_LEFT:
928 0 : dfCXOrigin = psGXF->dfXOrigin
929 : - (psGXF->nRawXSize-1) * psGXF->dfXPixelSize;
930 0 : dfCYOrigin = psGXF->dfYOrigin
931 : + (psGXF->nRawYSize-1) * psGXF->dfYPixelSize;
932 0 : dfCXPixelSize = psGXF->dfXPixelSize;
933 0 : dfCYPixelSize = psGXF->dfYPixelSize;
934 0 : break;
935 :
936 : default:
937 0 : CPLError( CE_Failure, CPLE_AppDefined,
938 : "GXFGetPosition() doesn't support vertically organized images." );
939 0 : return CE_Failure;
940 : }
941 :
942 0 : if( pdfXOrigin != NULL )
943 0 : *pdfXOrigin = dfCXOrigin;
944 0 : if( pdfYOrigin != NULL )
945 0 : *pdfYOrigin = dfCYOrigin;
946 0 : if( pdfXPixelSize != NULL )
947 0 : *pdfXPixelSize = dfCXPixelSize;
948 0 : if( pdfYPixelSize != NULL )
949 0 : *pdfYPixelSize = dfCYPixelSize;
950 0 : if( pdfRotation != NULL )
951 0 : *pdfRotation = psGXF->dfRotation;
952 :
953 0 : if( psGXF->dfXOrigin == 0.0 && psGXF->dfYOrigin == 0.0
954 : && psGXF->dfXPixelSize == 0.0 && psGXF->dfYPixelSize == 0.0 )
955 0 : return( CE_Failure );
956 : else
957 0 : return( CE_None );
958 : }
959 :
960 :
|