1 : /******************************************************************************
2 : * $Id: gxfdataset.cpp 25164 2012-10-20 13:42:32Z rouault $
3 : *
4 : * Project: GXF Reader
5 : * Purpose: GDAL binding for GXF reader.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 1998, Frank Warmerdam
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #include "gxfopen.h"
31 : #include "gdal_pam.h"
32 :
33 : CPL_CVSID("$Id: gxfdataset.cpp 25164 2012-10-20 13:42:32Z rouault $");
34 :
35 : #ifndef PI
36 : # define PI 3.14159265358979323846
37 : #endif
38 :
39 : CPL_C_START
40 : void GDALRegister_GXF(void);
41 : CPL_C_END
42 :
43 : /************************************************************************/
44 : /* ==================================================================== */
45 : /* GXFDataset */
46 : /* ==================================================================== */
47 : /************************************************************************/
48 :
49 : class GXFRasterBand;
50 :
51 : class GXFDataset : public GDALPamDataset
52 : {
53 : friend class GXFRasterBand;
54 :
55 : GXFHandle hGXF;
56 :
57 : char *pszProjection;
58 : double dfNoDataValue;
59 : GDALDataType eDataType;
60 :
61 : public:
62 : GXFDataset();
63 : ~GXFDataset();
64 :
65 : static GDALDataset *Open( GDALOpenInfo * );
66 :
67 : CPLErr GetGeoTransform( double * padfTransform );
68 : const char *GetProjectionRef();
69 : };
70 :
71 : /************************************************************************/
72 : /* ==================================================================== */
73 : /* GXFRasterBand */
74 : /* ==================================================================== */
75 : /************************************************************************/
76 :
77 : class GXFRasterBand : public GDALPamRasterBand
78 8 : {
79 : friend class GXFDataset;
80 :
81 : public:
82 :
83 : GXFRasterBand( GXFDataset *, int );
84 : double GetNoDataValue(int* bGotNoDataValue);
85 :
86 : virtual CPLErr IReadBlock( int, int, void * );
87 : };
88 :
89 :
90 : /************************************************************************/
91 : /* GXFRasterBand() */
92 : /************************************************************************/
93 :
94 8 : GXFRasterBand::GXFRasterBand( GXFDataset *poDS, int nBand )
95 :
96 : {
97 8 : this->poDS = poDS;
98 8 : this->nBand = nBand;
99 :
100 8 : eDataType = poDS->eDataType;
101 :
102 8 : nBlockXSize = poDS->GetRasterXSize();
103 8 : nBlockYSize = 1;
104 8 : }
105 :
106 : /************************************************************************/
107 : /* GetNoDataValue() */
108 : /************************************************************************/
109 :
110 0 : double GXFRasterBand::GetNoDataValue(int* bGotNoDataValue)
111 :
112 : {
113 0 : GXFDataset *poGXF_DS = (GXFDataset *) poDS;
114 0 : if (bGotNoDataValue)
115 0 : *bGotNoDataValue = (fabs(poGXF_DS->dfNoDataValue - -1e12) > .1);
116 0 : if (eDataType == GDT_Float32)
117 0 : return (double)(float)poGXF_DS->dfNoDataValue;
118 : else
119 0 : return poGXF_DS->dfNoDataValue;
120 : }
121 :
122 : /************************************************************************/
123 : /* IReadBlock() */
124 : /************************************************************************/
125 :
126 1538 : CPLErr GXFRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
127 : void * pImage )
128 :
129 : {
130 1538 : GXFDataset *poGXF_DS = (GXFDataset *) poDS;
131 : double *padfBuffer;
132 1538 : float *pafBuffer = (float *) pImage;
133 : int i;
134 : CPLErr eErr;
135 :
136 1538 : CPLAssert( nBlockXOff == 0 );
137 :
138 1538 : if (eDataType == GDT_Float32)
139 : {
140 1538 : padfBuffer = (double *) VSIMalloc2(sizeof(double), nBlockXSize);
141 1538 : if( padfBuffer == NULL )
142 0 : return CE_Failure;
143 1538 : eErr = GXFGetScanline( poGXF_DS->hGXF, nBlockYOff, padfBuffer );
144 :
145 614005 : for( i = 0; i < nBlockXSize; i++ )
146 612467 : pafBuffer[i] = (float) padfBuffer[i];
147 :
148 1538 : CPLFree( padfBuffer );
149 : }
150 0 : else if (eDataType == GDT_Float64)
151 0 : eErr = GXFGetScanline( poGXF_DS->hGXF, nBlockYOff, (double*)pImage );
152 : else
153 0 : eErr = CE_Failure;
154 :
155 1538 : return eErr;
156 : }
157 :
158 : /************************************************************************/
159 : /* ==================================================================== */
160 : /* GXFDataset */
161 : /* ==================================================================== */
162 : /************************************************************************/
163 :
164 : /************************************************************************/
165 : /* GXFDataset() */
166 : /************************************************************************/
167 :
168 8 : GXFDataset::GXFDataset()
169 :
170 : {
171 8 : pszProjection = NULL;
172 8 : hGXF = NULL;
173 8 : dfNoDataValue = 0;
174 8 : eDataType = GDT_Float32;
175 8 : }
176 :
177 : /************************************************************************/
178 : /* ~GXFDataset() */
179 : /************************************************************************/
180 :
181 8 : GXFDataset::~GXFDataset()
182 :
183 : {
184 8 : FlushCache();
185 8 : if( hGXF != NULL )
186 8 : GXFClose( hGXF );
187 8 : CPLFree( pszProjection );
188 8 : }
189 :
190 :
191 : /************************************************************************/
192 : /* GetGeoTransform() */
193 : /************************************************************************/
194 :
195 0 : CPLErr GXFDataset::GetGeoTransform( double * padfTransform )
196 :
197 : {
198 : CPLErr eErr;
199 : double dfXOrigin, dfYOrigin, dfXSize, dfYSize, dfRotation;
200 :
201 : eErr = GXFGetPosition( hGXF, &dfXOrigin, &dfYOrigin,
202 0 : &dfXSize, &dfYSize, &dfRotation );
203 :
204 0 : if( eErr != CE_None )
205 0 : return eErr;
206 :
207 : // Transform to radians.
208 0 : dfRotation = (dfRotation / 360.0) * 2 * PI;
209 :
210 0 : padfTransform[1] = dfXSize * cos(dfRotation);
211 0 : padfTransform[2] = dfYSize * sin(dfRotation);
212 0 : padfTransform[4] = dfXSize * sin(dfRotation);
213 0 : padfTransform[5] = -1 * dfYSize * cos(dfRotation);
214 :
215 : // take into account that GXF is point or center of pixel oriented.
216 0 : padfTransform[0] = dfXOrigin - 0.5*padfTransform[1] - 0.5*padfTransform[2];
217 0 : padfTransform[3] = dfYOrigin - 0.5*padfTransform[4] - 0.5*padfTransform[5];
218 :
219 0 : return CE_None;
220 : }
221 :
222 : /************************************************************************/
223 : /* GetProjectionRef() */
224 : /************************************************************************/
225 :
226 1 : const char *GXFDataset::GetProjectionRef()
227 :
228 : {
229 1 : return( pszProjection );
230 : }
231 :
232 : /************************************************************************/
233 : /* Open() */
234 : /************************************************************************/
235 :
236 11836 : GDALDataset *GXFDataset::Open( GDALOpenInfo * poOpenInfo )
237 :
238 : {
239 : GXFHandle hGXF;
240 : int i, bFoundKeyword, bFoundIllegal;
241 :
242 : /* -------------------------------------------------------------------- */
243 : /* Before trying GXFOpen() we first verify that there is at */
244 : /* least one "\n#keyword" type signature in the first chunk of */
245 : /* the file. */
246 : /* -------------------------------------------------------------------- */
247 11836 : if( poOpenInfo->fp == NULL || poOpenInfo->nHeaderBytes < 50 )
248 11340 : return NULL;
249 :
250 496 : bFoundKeyword = FALSE;
251 496 : bFoundIllegal = FALSE;
252 218553 : for( i = 0; i < poOpenInfo->nHeaderBytes-1; i++ )
253 : {
254 436931 : if( (poOpenInfo->pabyHeader[i] == 10
255 215485 : || poOpenInfo->pabyHeader[i] == 13)
256 3098 : && poOpenInfo->pabyHeader[i+1] == '#' )
257 : {
258 56 : bFoundKeyword = TRUE;
259 : }
260 218348 : if( poOpenInfo->pabyHeader[i] == 0 )
261 : {
262 291 : bFoundIllegal = TRUE;
263 291 : break;
264 : }
265 : }
266 :
267 496 : if( !bFoundKeyword || bFoundIllegal )
268 488 : return NULL;
269 :
270 :
271 : /* -------------------------------------------------------------------- */
272 : /* At this point it is plausible that this is a GXF file, but */
273 : /* we also now verify that there is a #GRID keyword before */
274 : /* passing it off to GXFOpen(). We check in the first 50K. */
275 : /* -------------------------------------------------------------------- */
276 : #define BIGBUFSIZE 50000
277 8 : int nBytesRead, bGotGrid = FALSE;
278 : FILE *fp;
279 :
280 8 : fp = VSIFOpen( poOpenInfo->pszFilename, "rb" );
281 8 : if( fp == NULL )
282 0 : return NULL;
283 :
284 8 : char *pszBigBuf = (char *) CPLMalloc(BIGBUFSIZE);
285 8 : nBytesRead = VSIFRead( pszBigBuf, 1, BIGBUFSIZE, fp );
286 8 : VSIFClose( fp );
287 :
288 15053 : for( i = 0; i < nBytesRead - 5 && !bGotGrid; i++ )
289 : {
290 15045 : if( pszBigBuf[i] == '#' && EQUALN(pszBigBuf+i+1,"GRID",4) )
291 8 : bGotGrid = TRUE;
292 : }
293 :
294 8 : CPLFree( pszBigBuf );
295 :
296 8 : if( !bGotGrid )
297 0 : return NULL;
298 :
299 : /* -------------------------------------------------------------------- */
300 : /* Try opening the dataset. */
301 : /* -------------------------------------------------------------------- */
302 :
303 8 : hGXF = GXFOpen( poOpenInfo->pszFilename );
304 :
305 8 : if( hGXF == NULL )
306 0 : return( NULL );
307 :
308 : /* -------------------------------------------------------------------- */
309 : /* Confirm the requested access is supported. */
310 : /* -------------------------------------------------------------------- */
311 8 : if( poOpenInfo->eAccess == GA_Update )
312 : {
313 0 : GXFClose(hGXF);
314 : CPLError( CE_Failure, CPLE_NotSupported,
315 : "The GXF driver does not support update access to existing"
316 0 : " datasets.\n" );
317 0 : return NULL;
318 : }
319 :
320 : /* -------------------------------------------------------------------- */
321 : /* Create a corresponding GDALDataset. */
322 : /* -------------------------------------------------------------------- */
323 : GXFDataset *poDS;
324 :
325 8 : poDS = new GXFDataset();
326 :
327 8 : const char* pszGXFDataType = CPLGetConfigOption("GXF_DATATYPE", "Float32");
328 8 : GDALDataType eDT = GDALGetDataTypeByName(pszGXFDataType);
329 8 : if (!(eDT == GDT_Float32 || eDT == GDT_Float64))
330 : {
331 : CPLError(CE_Warning, CPLE_NotSupported,
332 0 : "Unsupported value for GXF_DATATYPE : %s", pszGXFDataType);
333 0 : eDT = GDT_Float32;
334 : }
335 :
336 8 : poDS->hGXF = hGXF;
337 8 : poDS->eDataType = eDT;
338 :
339 : /* -------------------------------------------------------------------- */
340 : /* Establish the projection. */
341 : /* -------------------------------------------------------------------- */
342 8 : poDS->pszProjection = GXFGetMapProjectionAsOGCWKT( hGXF );
343 :
344 : /* -------------------------------------------------------------------- */
345 : /* Capture some information from the file that is of interest. */
346 : /* -------------------------------------------------------------------- */
347 : GXFGetRawInfo( hGXF, &(poDS->nRasterXSize), &(poDS->nRasterYSize), NULL,
348 8 : NULL, NULL, &(poDS->dfNoDataValue) );
349 :
350 8 : if (poDS->nRasterXSize <= 0 || poDS->nRasterYSize <= 0)
351 : {
352 : CPLError( CE_Failure, CPLE_AppDefined,
353 : "Invalid dimensions : %d x %d",
354 0 : poDS->nRasterXSize, poDS->nRasterYSize);
355 0 : delete poDS;
356 0 : return NULL;
357 : }
358 :
359 : /* -------------------------------------------------------------------- */
360 : /* Create band information objects. */
361 : /* -------------------------------------------------------------------- */
362 8 : poDS->nBands = 1;
363 8 : poDS->SetBand( 1, new GXFRasterBand( poDS, 1 ));
364 :
365 : /* -------------------------------------------------------------------- */
366 : /* Initialize any PAM information. */
367 : /* -------------------------------------------------------------------- */
368 8 : poDS->SetDescription( poOpenInfo->pszFilename );
369 8 : poDS->TryLoadXML();
370 :
371 : /* -------------------------------------------------------------------- */
372 : /* Check for external overviews. */
373 : /* -------------------------------------------------------------------- */
374 8 : poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename, poOpenInfo->papszSiblingFiles );
375 :
376 8 : return( poDS );
377 : }
378 :
379 : /************************************************************************/
380 : /* GDALRegister_GXF() */
381 : /************************************************************************/
382 :
383 582 : void GDALRegister_GXF()
384 :
385 : {
386 : GDALDriver *poDriver;
387 :
388 582 : if( GDALGetDriverByName( "GXF" ) == NULL )
389 : {
390 561 : poDriver = new GDALDriver();
391 :
392 561 : poDriver->SetDescription( "GXF" );
393 : poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
394 561 : "GeoSoft Grid Exchange Format" );
395 : poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
396 561 : "frmt_various.html#GXF" );
397 561 : poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "gxf" );
398 :
399 561 : poDriver->pfnOpen = GXFDataset::Open;
400 :
401 561 : GetGDALDriverManager()->RegisterDriver( poDriver );
402 : }
403 582 : }
|