1 : /******************************************************************************
2 : * $Id: gxfdataset.cpp 22401 2011-05-18 22:20:45Z warmerdam $
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 22401 2011-05-18 22:20:45Z warmerdam $");
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 7 : {
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 7 : GXFRasterBand::GXFRasterBand( GXFDataset *poDS, int nBand )
95 :
96 : {
97 7 : this->poDS = poDS;
98 7 : this->nBand = nBand;
99 :
100 7 : eDataType = poDS->eDataType;
101 :
102 7 : nBlockXSize = poDS->GetRasterXSize();
103 7 : nBlockYSize = 1;
104 7 : }
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 1530 : CPLErr GXFRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
127 : void * pImage )
128 :
129 : {
130 1530 : GXFDataset *poGXF_DS = (GXFDataset *) poDS;
131 : double *padfBuffer;
132 1530 : float *pafBuffer = (float *) pImage;
133 : int i;
134 : CPLErr eErr;
135 :
136 1530 : CPLAssert( nBlockXOff == 0 );
137 :
138 1530 : if (eDataType == GDT_Float32)
139 : {
140 1530 : padfBuffer = (double *) CPLMalloc(sizeof(double) * nBlockXSize);
141 1530 : eErr = GXFGetScanline( poGXF_DS->hGXF, nBlockYOff, padfBuffer );
142 :
143 613917 : for( i = 0; i < nBlockXSize; i++ )
144 612387 : pafBuffer[i] = (float) padfBuffer[i];
145 :
146 1530 : CPLFree( padfBuffer );
147 : }
148 0 : else if (eDataType == GDT_Float64)
149 0 : eErr = GXFGetScanline( poGXF_DS->hGXF, nBlockYOff, (double*)pImage );
150 : else
151 0 : eErr = CE_Failure;
152 :
153 1530 : return eErr;
154 : }
155 :
156 : /************************************************************************/
157 : /* ==================================================================== */
158 : /* GXFDataset */
159 : /* ==================================================================== */
160 : /************************************************************************/
161 :
162 : /************************************************************************/
163 : /* GXFDataset() */
164 : /************************************************************************/
165 :
166 7 : GXFDataset::GXFDataset()
167 :
168 : {
169 7 : pszProjection = NULL;
170 7 : hGXF = NULL;
171 7 : dfNoDataValue = 0;
172 7 : eDataType = GDT_Float32;
173 7 : }
174 :
175 : /************************************************************************/
176 : /* ~GXFDataset() */
177 : /************************************************************************/
178 :
179 7 : GXFDataset::~GXFDataset()
180 :
181 : {
182 7 : FlushCache();
183 7 : if( hGXF != NULL )
184 7 : GXFClose( hGXF );
185 7 : CPLFree( pszProjection );
186 7 : }
187 :
188 :
189 : /************************************************************************/
190 : /* GetGeoTransform() */
191 : /************************************************************************/
192 :
193 0 : CPLErr GXFDataset::GetGeoTransform( double * padfTransform )
194 :
195 : {
196 : CPLErr eErr;
197 : double dfXOrigin, dfYOrigin, dfXSize, dfYSize, dfRotation;
198 :
199 : eErr = GXFGetPosition( hGXF, &dfXOrigin, &dfYOrigin,
200 0 : &dfXSize, &dfYSize, &dfRotation );
201 :
202 0 : if( eErr != CE_None )
203 0 : return eErr;
204 :
205 : // Transform to radians.
206 0 : dfRotation = (dfRotation / 360.0) * 2 * PI;
207 :
208 0 : padfTransform[1] = dfXSize * cos(dfRotation);
209 0 : padfTransform[2] = dfYSize * sin(dfRotation);
210 0 : padfTransform[4] = dfXSize * sin(dfRotation);
211 0 : padfTransform[5] = -1 * dfYSize * cos(dfRotation);
212 :
213 : // take into account that GXF is point or center of pixel oriented.
214 0 : padfTransform[0] = dfXOrigin - 0.5*padfTransform[1] - 0.5*padfTransform[2];
215 0 : padfTransform[3] = dfYOrigin - 0.5*padfTransform[4] - 0.5*padfTransform[5];
216 :
217 0 : return CE_None;
218 : }
219 :
220 : /************************************************************************/
221 : /* GetProjectionRef() */
222 : /************************************************************************/
223 :
224 0 : const char *GXFDataset::GetProjectionRef()
225 :
226 : {
227 0 : return( pszProjection );
228 : }
229 :
230 : /************************************************************************/
231 : /* Open() */
232 : /************************************************************************/
233 :
234 10729 : GDALDataset *GXFDataset::Open( GDALOpenInfo * poOpenInfo )
235 :
236 : {
237 : GXFHandle hGXF;
238 : int i, bFoundKeyword, bFoundIllegal;
239 :
240 : /* -------------------------------------------------------------------- */
241 : /* Before trying GXFOpen() we first verify that there is at */
242 : /* least one "\n#keyword" type signature in the first chunk of */
243 : /* the file. */
244 : /* -------------------------------------------------------------------- */
245 10729 : if( poOpenInfo->fp == NULL || poOpenInfo->nHeaderBytes < 50 )
246 10420 : return NULL;
247 :
248 309 : bFoundKeyword = FALSE;
249 309 : bFoundIllegal = FALSE;
250 78555 : for( i = 0; i < poOpenInfo->nHeaderBytes-1; i++ )
251 : {
252 157119 : if( (poOpenInfo->pabyHeader[i] == 10
253 77533 : || poOpenInfo->pabyHeader[i] == 13)
254 1126 : && poOpenInfo->pabyHeader[i+1] == '#' )
255 : {
256 44 : bFoundKeyword = TRUE;
257 : }
258 78460 : if( poOpenInfo->pabyHeader[i] == 0 )
259 : {
260 214 : bFoundIllegal = TRUE;
261 214 : break;
262 : }
263 : }
264 :
265 309 : if( !bFoundKeyword || bFoundIllegal )
266 302 : return NULL;
267 :
268 :
269 : /* -------------------------------------------------------------------- */
270 : /* At this point it is plausible that this is a GXF file, but */
271 : /* we also now verify that there is a #GRID keyword before */
272 : /* passing it off to GXFOpen(). We check in the first 50K. */
273 : /* -------------------------------------------------------------------- */
274 7 : int nBytesRead, bGotGrid = FALSE;
275 : char szBigBuf[50000];
276 : FILE *fp;
277 :
278 7 : fp = VSIFOpen( poOpenInfo->pszFilename, "rb" );
279 7 : if( fp == NULL )
280 0 : return NULL;
281 :
282 7 : nBytesRead = VSIFRead( szBigBuf, 1, sizeof(szBigBuf), fp );
283 7 : VSIFClose( fp );
284 :
285 14659 : for( i = 0; i < nBytesRead - 5 && !bGotGrid; i++ )
286 : {
287 14652 : if( szBigBuf[i] == '#' && EQUALN(szBigBuf+i+1,"GRID",4) )
288 7 : bGotGrid = TRUE;
289 : }
290 :
291 7 : if( !bGotGrid )
292 0 : return NULL;
293 :
294 : /* -------------------------------------------------------------------- */
295 : /* Try opening the dataset. */
296 : /* -------------------------------------------------------------------- */
297 :
298 7 : hGXF = GXFOpen( poOpenInfo->pszFilename );
299 :
300 7 : if( hGXF == NULL )
301 0 : return( NULL );
302 :
303 : /* -------------------------------------------------------------------- */
304 : /* Confirm the requested access is supported. */
305 : /* -------------------------------------------------------------------- */
306 7 : if( poOpenInfo->eAccess == GA_Update )
307 : {
308 0 : GXFClose(hGXF);
309 : CPLError( CE_Failure, CPLE_NotSupported,
310 : "The GXF driver does not support update access to existing"
311 0 : " datasets.\n" );
312 0 : return NULL;
313 : }
314 :
315 : /* -------------------------------------------------------------------- */
316 : /* Create a corresponding GDALDataset. */
317 : /* -------------------------------------------------------------------- */
318 : GXFDataset *poDS;
319 :
320 7 : poDS = new GXFDataset();
321 :
322 7 : const char* pszGXFDataType = CPLGetConfigOption("GXF_DATATYPE", "Float32");
323 7 : GDALDataType eDT = GDALGetDataTypeByName(pszGXFDataType);
324 7 : if (!(eDT == GDT_Float32 || eDT == GDT_Float64))
325 : {
326 : CPLError(CE_Warning, CPLE_NotSupported,
327 0 : "Unsupported value for GXF_DATATYPE : %s", pszGXFDataType);
328 0 : eDT = GDT_Float32;
329 : }
330 :
331 7 : poDS->hGXF = hGXF;
332 7 : poDS->eDataType = eDT;
333 :
334 : /* -------------------------------------------------------------------- */
335 : /* Establish the projection. */
336 : /* -------------------------------------------------------------------- */
337 7 : poDS->pszProjection = GXFGetMapProjectionAsOGCWKT( hGXF );
338 :
339 : /* -------------------------------------------------------------------- */
340 : /* Capture some information from the file that is of interest. */
341 : /* -------------------------------------------------------------------- */
342 : GXFGetRawInfo( hGXF, &(poDS->nRasterXSize), &(poDS->nRasterYSize), NULL,
343 7 : NULL, NULL, &(poDS->dfNoDataValue) );
344 :
345 7 : if (poDS->nRasterXSize <= 0 || poDS->nRasterYSize <= 0)
346 : {
347 : CPLError( CE_Failure, CPLE_AppDefined,
348 : "Invalid dimensions : %d x %d",
349 0 : poDS->nRasterXSize, poDS->nRasterYSize);
350 0 : delete poDS;
351 0 : return NULL;
352 : }
353 :
354 : /* -------------------------------------------------------------------- */
355 : /* Create band information objects. */
356 : /* -------------------------------------------------------------------- */
357 7 : poDS->nBands = 1;
358 7 : poDS->SetBand( 1, new GXFRasterBand( poDS, 1 ));
359 :
360 : /* -------------------------------------------------------------------- */
361 : /* Initialize any PAM information. */
362 : /* -------------------------------------------------------------------- */
363 7 : poDS->SetDescription( poOpenInfo->pszFilename );
364 7 : poDS->TryLoadXML();
365 :
366 : /* -------------------------------------------------------------------- */
367 : /* Check for external overviews. */
368 : /* -------------------------------------------------------------------- */
369 7 : poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename, poOpenInfo->papszSiblingFiles );
370 :
371 7 : return( poDS );
372 : }
373 :
374 : /************************************************************************/
375 : /* GDALRegister_GXF() */
376 : /************************************************************************/
377 :
378 558 : void GDALRegister_GXF()
379 :
380 : {
381 : GDALDriver *poDriver;
382 :
383 558 : if( GDALGetDriverByName( "GXF" ) == NULL )
384 : {
385 537 : poDriver = new GDALDriver();
386 :
387 537 : poDriver->SetDescription( "GXF" );
388 : poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
389 537 : "GeoSoft Grid Exchange Format" );
390 : poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
391 537 : "frmt_various.html#GXF" );
392 537 : poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "gxf" );
393 :
394 537 : poDriver->pfnOpen = GXFDataset::Open;
395 :
396 537 : GetGDALDriverManager()->RegisterDriver( poDriver );
397 : }
398 558 : }
|