PageRenderTime 38ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/gdal-1.9.1-fedora/frmts/gxf/gxfopen.c

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