1 : /****************************************************************************
2 : * $Id: gs7bgdataset.cpp 24584 2012-06-16 10:24:03Z rouault $
3 : *
4 : * Project: GDAL
5 : * Purpose: Implements the Golden Software Surfer 7 Binary Grid Format.
6 : * Author: Adam Guernsey, adam@ctech.com
7 : * (Based almost entirely on gsbgdataset.cpp by Kevin Locke)
8 : * Create functions added by Russell Jurgensen.
9 : *
10 : ****************************************************************************
11 : * Copyright (c) 2007, Adam Guernsey <adam@ctech.com>
12 : *
13 : * Permission is hereby granted, free of charge, to any person obtaining a
14 : * copy of this software and associated documentation files (the "Software"),
15 : * to deal in the Software without restriction, including without limitation
16 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
17 : * and/or sell copies of the Software, and to permit persons to whom the
18 : * Software is furnished to do so, subject to the following conditions:
19 : *
20 : * The above copyright notice and this permission notice shall be included
21 : * in all copies or substantial portions of the Software.
22 : *
23 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29 : * DEALINGS IN THE SOFTWARE.
30 : ****************************************************************************/
31 :
32 : #include <float.h>
33 : #include <limits.h>
34 : #include <math.h>
35 : #include <assert.h>
36 :
37 : #include "gdal_pam.h"
38 :
39 : #ifndef DBL_MAX
40 : # ifdef __DBL_MAX__
41 : # define DBL_MAX __DBL_MAX__
42 : # else
43 : # define DBL_MAX 1.7976931348623157E+308
44 : # endif /* __DBL_MAX__ */
45 : #endif /* DBL_MAX */
46 :
47 : #ifndef FLT_MAX
48 : # ifdef __FLT_MAX__
49 : # define FLT_MAX __FLT_MAX__
50 : # else
51 : # define FLT_MAX 3.40282347E+38F
52 : # endif /* __FLT_MAX__ */
53 : #endif /* FLT_MAX */
54 :
55 : #ifndef INT_MAX
56 : # define INT_MAX 2147483647
57 : #endif /* INT_MAX */
58 :
59 : #ifndef SHRT_MAX
60 : # define SHRT_MAX 32767
61 : #endif /* SHRT_MAX */
62 :
63 : CPL_CVSID("$Id: gs7bgdataset.cpp 24584 2012-06-16 10:24:03Z rouault $");
64 :
65 : CPL_C_START
66 : void GDALRegister_GS7BG(void);
67 : CPL_C_END
68 :
69 : /************************************************************************/
70 : /* ==================================================================== */
71 : /* GS7BGDataset */
72 : /* ==================================================================== */
73 : /************************************************************************/
74 :
75 : class GS7BGRasterBand;
76 :
77 : class GS7BGDataset : public GDALPamDataset
78 32 : {
79 : friend class GS7BGRasterBand;
80 :
81 : static double dfNoData_Value;
82 : static const size_t nHEADER_SIZE;
83 : static size_t nData_Position;
84 :
85 : static CPLErr WriteHeader( VSILFILE *fp, GInt32 nXSize, GInt32 nYSize,
86 : double dfMinX, double dfMaxX,
87 : double dfMinY, double dfMaxY,
88 : double dfMinZ, double dfMaxZ );
89 :
90 : VSILFILE *fp;
91 :
92 : public:
93 : ~GS7BGDataset();
94 :
95 : static int Identify( GDALOpenInfo * );
96 : static GDALDataset *Open( GDALOpenInfo * );
97 : static GDALDataset *Create( const char * pszFilename,
98 : int nXSize, int nYSize, int nBands,
99 : GDALDataType eType,
100 : char **papszParmList );
101 : static GDALDataset *CreateCopy( const char *pszFilename,
102 : GDALDataset *poSrcDS,
103 : int bStrict, char **papszOptions,
104 : GDALProgressFunc pfnProgress,
105 : void *pProgressData );
106 :
107 : CPLErr GetGeoTransform( double *padfGeoTransform );
108 : CPLErr SetGeoTransform( double *padfGeoTransform );
109 : };
110 :
111 : /* NOTE: This is not mentioned in the spec, but Surfer 8 uses this value */
112 : /* 0x7effffee (Little Endian: eeffff7e) */
113 : double GS7BGDataset::dfNoData_Value = 1.701410009187828e+38f;
114 :
115 : const size_t GS7BGDataset::nHEADER_SIZE = 100;
116 :
117 : size_t GS7BGDataset::nData_Position = 0;
118 :
119 : const long nHEADER_TAG = 0x42525344;
120 : const long nGRID_TAG = 0x44495247;
121 : const long nDATA_TAG = 0x41544144;
122 : const long nFAULT_TAG = 0x49544c46;
123 :
124 : /************************************************************************/
125 : /* ==================================================================== */
126 : /* GS7BGRasterBand */
127 : /* ==================================================================== */
128 : /************************************************************************/
129 :
130 : class GS7BGRasterBand : public GDALPamRasterBand
131 : {
132 : friend class GS7BGDataset;
133 :
134 : double dfMinX;
135 : double dfMaxX;
136 : double dfMinY;
137 : double dfMaxY;
138 : double dfMinZ;
139 : double dfMaxZ;
140 :
141 : double *pafRowMinZ;
142 : double *pafRowMaxZ;
143 : int nMinZRow;
144 : int nMaxZRow;
145 :
146 : CPLErr ScanForMinMaxZ();
147 :
148 : public:
149 :
150 : GS7BGRasterBand( GS7BGDataset *, int );
151 : ~GS7BGRasterBand();
152 :
153 : CPLErr IReadBlock( int, int, void * );
154 : CPLErr IWriteBlock( int, int, void * );
155 : double GetMinimum( int *pbSuccess = NULL );
156 : double GetMaximum( int *pbSuccess = NULL );
157 :
158 : double GetNoDataValue( int *pbSuccess = NULL );
159 : };
160 :
161 : /************************************************************************/
162 : /* GS7BGRasterBand() */
163 : /************************************************************************/
164 :
165 32 : GS7BGRasterBand::GS7BGRasterBand( GS7BGDataset *poDS, int nBand ) :
166 : pafRowMinZ(NULL),
167 : pafRowMaxZ(NULL),
168 : nMinZRow(-1),
169 32 : nMaxZRow(-1)
170 :
171 : {
172 32 : this->poDS = poDS;
173 32 : this->nBand = nBand;
174 :
175 32 : eDataType = GDT_Float64;
176 :
177 32 : nBlockXSize = poDS->GetRasterXSize();
178 32 : nBlockYSize = 1;
179 32 : }
180 :
181 : /************************************************************************/
182 : /* ~GSBGRasterBand() */
183 : /************************************************************************/
184 :
185 32 : GS7BGRasterBand::~GS7BGRasterBand( )
186 :
187 : {
188 32 : if( pafRowMinZ != NULL )
189 1 : CPLFree( pafRowMinZ );
190 32 : if( pafRowMaxZ != NULL )
191 1 : CPLFree( pafRowMaxZ );
192 32 : }
193 :
194 : /************************************************************************/
195 : /* ScanForMinMaxZ() */
196 : /************************************************************************/
197 :
198 1 : CPLErr GS7BGRasterBand::ScanForMinMaxZ()
199 :
200 : {
201 1 : double *pafRowVals = (double *)VSIMalloc2( nRasterXSize, sizeof(double));
202 :
203 1 : if( pafRowVals == NULL )
204 : {
205 : CPLError( CE_Failure, CPLE_OutOfMemory,
206 0 : "Unable to allocate row buffer to scan grid file.\n" );
207 0 : return CE_Failure;
208 : }
209 :
210 1 : double dfNewMinZ = DBL_MAX;
211 1 : double dfNewMaxZ = -DBL_MAX;
212 1 : int nNewMinZRow = 0;
213 1 : int nNewMaxZRow = 0;
214 :
215 : /* Since we have to scan, lets calc. statistics too */
216 1 : double dfSum = 0.0;
217 1 : double dfSum2 = 0.0;
218 1 : unsigned long nValuesRead = 0;
219 21 : for( int iRow=0; iRow<nRasterYSize; iRow++ )
220 : {
221 20 : CPLErr eErr = IReadBlock( 0, iRow, pafRowVals );
222 20 : if( eErr != CE_None )
223 : {
224 0 : VSIFree( pafRowVals );
225 0 : return CE_Failure;
226 : }
227 :
228 20 : pafRowMinZ[iRow] = FLT_MAX;
229 20 : pafRowMaxZ[iRow] = -FLT_MAX;
230 420 : for( int iCol=0; iCol<nRasterXSize; iCol++ )
231 : {
232 400 : if( pafRowVals[iCol] == GS7BGDataset::dfNoData_Value )
233 400 : continue;
234 :
235 0 : if( pafRowVals[iCol] < pafRowMinZ[iRow] )
236 0 : pafRowMinZ[iRow] = pafRowVals[iCol];
237 :
238 0 : if( pafRowVals[iCol] > pafRowMinZ[iRow] )
239 0 : pafRowMaxZ[iRow] = pafRowVals[iCol];
240 :
241 0 : dfSum += pafRowVals[iCol];
242 0 : dfSum2 += pafRowVals[iCol] * pafRowVals[iCol];
243 0 : nValuesRead++;
244 : }
245 :
246 20 : if( pafRowMinZ[iRow] < dfNewMinZ )
247 : {
248 1 : dfNewMinZ = pafRowMinZ[iRow];
249 1 : nNewMinZRow = iRow;
250 : }
251 :
252 20 : if( pafRowMaxZ[iRow] > dfNewMaxZ )
253 : {
254 1 : dfNewMaxZ = pafRowMaxZ[iRow];
255 1 : nNewMaxZRow = iRow;
256 : }
257 : }
258 :
259 1 : VSIFree( pafRowVals );
260 :
261 1 : if( nValuesRead == 0 )
262 : {
263 1 : dfMinZ = 0.0;
264 1 : dfMaxZ = 0.0;
265 1 : nMinZRow = 0;
266 1 : nMaxZRow = 0;
267 1 : return CE_None;
268 : }
269 :
270 0 : dfMinZ = dfNewMinZ;
271 0 : dfMaxZ = dfNewMaxZ;
272 0 : nMinZRow = nNewMinZRow;
273 0 : nMaxZRow = nNewMaxZRow;
274 :
275 0 : double dfMean = dfSum / nValuesRead;
276 0 : double dfStdDev = sqrt((dfSum2 / nValuesRead) - (dfMean * dfMean));
277 0 : SetStatistics( dfMinZ, dfMaxZ, dfMean, dfStdDev );
278 :
279 0 : return CE_None;
280 : }
281 :
282 : /************************************************************************/
283 : /* IReadBlock() */
284 : /************************************************************************/
285 :
286 140 : CPLErr GS7BGRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
287 : void * pImage )
288 :
289 : {
290 140 : if( nBlockYOff < 0 || nBlockYOff > nRasterYSize - 1 || nBlockXOff != 0 )
291 0 : return CE_Failure;
292 :
293 140 : GS7BGDataset *poGDS = (GS7BGDataset *) ( poDS );
294 :
295 140 : if( VSIFSeekL( poGDS->fp,
296 : ( GS7BGDataset::nData_Position +
297 : sizeof(double) * nRasterXSize * (nRasterYSize - nBlockYOff - 1) ),
298 : SEEK_SET ) != 0 )
299 : {
300 : CPLError( CE_Failure, CPLE_FileIO,
301 0 : "Unable to seek to beginning of grid row.\n" );
302 0 : return CE_Failure;
303 : }
304 :
305 140 : if( VSIFReadL( pImage, sizeof(double), nBlockXSize,
306 : poGDS->fp ) != static_cast<unsigned>(nBlockXSize) )
307 : {
308 : CPLError( CE_Failure, CPLE_FileIO,
309 0 : "Unable to read block from grid file.\n" );
310 0 : return CE_Failure;
311 : }
312 :
313 : double *pfImage;
314 140 : pfImage = (double *)pImage;
315 140 : for( int iPixel=0; iPixel<nBlockXSize; iPixel++ )
316 : CPL_LSBPTR64( pfImage + iPixel );
317 :
318 140 : return CE_None;
319 : }
320 :
321 : /************************************************************************/
322 : /* IWriteBlock() */
323 : /************************************************************************/
324 :
325 20 : CPLErr GS7BGRasterBand::IWriteBlock( int nBlockXOff, int nBlockYOff,
326 : void *pImage )
327 :
328 : {
329 20 : if( eAccess == GA_ReadOnly )
330 : {
331 : CPLError( CE_Failure, CPLE_NoWriteAccess,
332 0 : "Unable to write block, dataset opened read only.\n" );
333 0 : return CE_Failure;
334 : }
335 :
336 20 : if( nBlockYOff < 0 || nBlockYOff > nRasterYSize - 1 || nBlockXOff != 0 )
337 0 : return CE_Failure;
338 :
339 20 : GS7BGDataset *poGDS = (GS7BGDataset *) ( poDS );
340 :
341 20 : if( pafRowMinZ == NULL || pafRowMaxZ == NULL
342 : || nMinZRow < 0 || nMaxZRow < 0 )
343 : {
344 1 : pafRowMinZ = (double *)VSIMalloc2( nRasterYSize,sizeof(double) );
345 1 : if( pafRowMinZ == NULL )
346 : {
347 : CPLError( CE_Failure, CPLE_OutOfMemory,
348 0 : "Unable to allocate space for row minimums array.\n" );
349 0 : return CE_Failure;
350 : }
351 :
352 1 : pafRowMaxZ = (double *)VSIMalloc2( nRasterYSize,sizeof(double) );
353 1 : if( pafRowMaxZ == NULL )
354 : {
355 0 : VSIFree( pafRowMinZ );
356 0 : pafRowMinZ = NULL;
357 : CPLError( CE_Failure, CPLE_OutOfMemory,
358 0 : "Unable to allocate space for row maximums array.\n" );
359 0 : return CE_Failure;
360 : }
361 :
362 1 : CPLErr eErr = ScanForMinMaxZ();
363 1 : if( eErr != CE_None )
364 0 : return eErr;
365 : }
366 :
367 20 : if( VSIFSeekL( poGDS->fp,
368 : GS7BGDataset::nHEADER_SIZE +
369 : sizeof(double) * nRasterXSize * (nRasterYSize - nBlockYOff - 1),
370 : SEEK_SET ) != 0 )
371 : {
372 : CPLError( CE_Failure, CPLE_FileIO,
373 0 : "Unable to seek to beginning of grid row.\n" );
374 0 : return CE_Failure;
375 : }
376 :
377 20 : double *pdfImage = (double *)pImage;
378 20 : pafRowMinZ[nBlockYOff] = DBL_MAX;
379 20 : pafRowMaxZ[nBlockYOff] = -DBL_MAX;
380 420 : for( int iPixel=0; iPixel<nBlockXSize; iPixel++ )
381 : {
382 400 : if( pdfImage[iPixel] != GS7BGDataset::dfNoData_Value )
383 : {
384 400 : if( pdfImage[iPixel] < pafRowMinZ[nBlockYOff] )
385 78 : pafRowMinZ[nBlockYOff] = pdfImage[iPixel];
386 :
387 400 : if( pdfImage[iPixel] > pafRowMaxZ[nBlockYOff] )
388 43 : pafRowMaxZ[nBlockYOff] = pdfImage[iPixel];
389 : }
390 :
391 : CPL_LSBPTR64( pdfImage+iPixel );
392 : }
393 :
394 20 : if( VSIFWriteL( pImage, sizeof(double), nBlockXSize,
395 : poGDS->fp ) != static_cast<unsigned>(nBlockXSize) )
396 : {
397 : CPLError( CE_Failure, CPLE_FileIO,
398 0 : "Unable to write block to grid file.\n" );
399 0 : return CE_Failure;
400 : }
401 :
402 : /* Update min/max Z values as appropriate */
403 20 : bool bHeaderNeedsUpdate = false;
404 20 : if( nMinZRow == nBlockYOff && pafRowMinZ[nBlockYOff] > dfMinZ )
405 : {
406 1 : double dfNewMinZ = DBL_MAX;
407 21 : for( int iRow=0; iRow<nRasterYSize; iRow++ )
408 : {
409 20 : if( pafRowMinZ[iRow] < dfNewMinZ )
410 : {
411 1 : dfNewMinZ = pafRowMinZ[iRow];
412 1 : nMinZRow = iRow;
413 : }
414 : }
415 :
416 1 : if( dfNewMinZ != dfMinZ )
417 : {
418 1 : dfMinZ = dfNewMinZ;
419 1 : bHeaderNeedsUpdate = true;
420 : }
421 : }
422 :
423 20 : if( nMaxZRow == nBlockYOff && pafRowMaxZ[nBlockYOff] < dfMaxZ )
424 : {
425 0 : double dfNewMaxZ = -DBL_MAX;
426 0 : for( int iRow=0; iRow<nRasterYSize; iRow++ )
427 : {
428 0 : if( pafRowMaxZ[iRow] > dfNewMaxZ )
429 : {
430 0 : dfNewMaxZ = pafRowMaxZ[iRow];
431 0 : nMaxZRow = iRow;
432 : }
433 : }
434 :
435 0 : if( dfNewMaxZ != dfMaxZ )
436 : {
437 0 : dfMaxZ = dfNewMaxZ;
438 0 : bHeaderNeedsUpdate = true;
439 : }
440 : }
441 :
442 20 : if( pafRowMinZ[nBlockYOff] < dfMinZ || pafRowMaxZ[nBlockYOff] > dfMaxZ )
443 : {
444 6 : if( pafRowMinZ[nBlockYOff] < dfMinZ )
445 : {
446 3 : dfMinZ = pafRowMinZ[nBlockYOff];
447 3 : nMinZRow = nBlockYOff;
448 : }
449 :
450 6 : if( pafRowMaxZ[nBlockYOff] > dfMaxZ )
451 : {
452 4 : dfMaxZ = pafRowMaxZ[nBlockYOff];
453 4 : nMaxZRow = nBlockYOff;
454 : }
455 :
456 6 : bHeaderNeedsUpdate = true;
457 : }
458 :
459 20 : if( bHeaderNeedsUpdate && dfMaxZ > dfMinZ )
460 : {
461 : CPLErr eErr = poGDS->WriteHeader( poGDS->fp,
462 : nRasterXSize, nRasterYSize,
463 : dfMinX, dfMaxX,
464 : dfMinY, dfMaxY,
465 6 : dfMinZ, dfMaxZ );
466 6 : return eErr;
467 : }
468 :
469 14 : return CE_None;
470 : }
471 :
472 : /************************************************************************/
473 : /* GetNoDataValue() */
474 : /************************************************************************/
475 :
476 11 : double GS7BGRasterBand::GetNoDataValue( int * pbSuccess )
477 : {
478 11 : if( pbSuccess )
479 10 : *pbSuccess = TRUE;
480 :
481 11 : return GS7BGDataset::dfNoData_Value;
482 : }
483 :
484 : /************************************************************************/
485 : /* GetMinimum() */
486 : /************************************************************************/
487 :
488 0 : double GS7BGRasterBand::GetMinimum( int *pbSuccess )
489 : {
490 0 : if( pbSuccess )
491 0 : *pbSuccess = TRUE;
492 :
493 0 : return dfMinZ;
494 : }
495 :
496 : /************************************************************************/
497 : /* GetMaximum() */
498 : /************************************************************************/
499 :
500 0 : double GS7BGRasterBand::GetMaximum( int *pbSuccess )
501 : {
502 0 : if( pbSuccess )
503 0 : *pbSuccess = TRUE;
504 :
505 0 : return dfMaxZ;
506 : }
507 :
508 : /************************************************************************/
509 : /* ==================================================================== */
510 : /* GS7BGDataset */
511 : /* ==================================================================== */
512 : /************************************************************************/
513 :
514 32 : GS7BGDataset::~GS7BGDataset()
515 :
516 : {
517 32 : FlushCache();
518 32 : if( fp != NULL )
519 32 : VSIFCloseL( fp );
520 32 : }
521 :
522 : /************************************************************************/
523 : /* Identify() */
524 : /************************************************************************/
525 :
526 12430 : int GS7BGDataset::Identify( GDALOpenInfo * poOpenInfo )
527 :
528 : {
529 : /* Check for signature - for GS7BG the signature is the */
530 : /* nHEADER_TAG with reverse byte order. */
531 12430 : if( poOpenInfo->nHeaderBytes < 4
532 : || !EQUALN((const char *) poOpenInfo->pabyHeader,"DSRB",4) )
533 : {
534 12398 : return FALSE;
535 : }
536 :
537 32 : return TRUE;
538 : }
539 :
540 : /************************************************************************/
541 : /* Open() */
542 : /************************************************************************/
543 :
544 2337 : GDALDataset *GS7BGDataset::Open( GDALOpenInfo * poOpenInfo )
545 :
546 : {
547 2337 : if( !Identify(poOpenInfo) )
548 : {
549 2305 : return NULL;
550 : }
551 :
552 : /* ------------------------------------------------------------------- */
553 : /* Create a corresponding GDALDataset. */
554 : /* ------------------------------------------------------------------- */
555 32 : GS7BGDataset *poDS = new GS7BGDataset();
556 :
557 : /* ------------------------------------------------------------------- */
558 : /* Open file with large file API. */
559 : /* ------------------------------------------------------------------- */
560 32 : poDS->eAccess = poOpenInfo->eAccess;
561 32 : if( poOpenInfo->eAccess == GA_ReadOnly )
562 13 : poDS->fp = VSIFOpenL( poOpenInfo->pszFilename, "rb" );
563 : else
564 19 : poDS->fp = VSIFOpenL( poOpenInfo->pszFilename, "r+b" );
565 :
566 32 : if( poDS->fp == NULL )
567 : {
568 0 : delete poDS;
569 : CPLError( CE_Failure, CPLE_OpenFailed,
570 : "VSIFOpenL(%s) failed unexpectedly.",
571 0 : poOpenInfo->pszFilename );
572 0 : return NULL;
573 : }
574 :
575 : /* ------------------------------------------------------------------- */
576 : /* Read the header. The Header section must be the first section */
577 : /* in the file. */
578 : /* ------------------------------------------------------------------- */
579 32 : if( VSIFSeekL( poDS->fp, 0, SEEK_SET ) != 0 )
580 : {
581 0 : delete poDS;
582 : CPLError( CE_Failure, CPLE_FileIO,
583 0 : "Unable to seek to start of grid file header.\n" );
584 0 : return NULL;
585 : }
586 :
587 : GInt32 nTag;
588 : GInt32 nSize;
589 : GInt32 nVersion;
590 :
591 32 : if( VSIFReadL( (void *)&nTag, sizeof(GInt32), 1, poDS->fp ) != 1 )
592 : {
593 0 : delete poDS;
594 0 : CPLError( CE_Failure, CPLE_FileIO, "Unable to read Tag.\n" );
595 0 : return NULL;
596 : }
597 :
598 : CPL_LSBPTR32( &nTag );
599 :
600 32 : if(nTag != nHEADER_TAG)
601 : {
602 0 : delete poDS;
603 0 : CPLError( CE_Failure, CPLE_FileIO, "Header tag not found.\n" );
604 0 : return NULL;
605 : }
606 :
607 32 : if( VSIFReadL( (void *)&nSize, sizeof(GInt32), 1, poDS->fp ) != 1 )
608 : {
609 0 : delete poDS;
610 : CPLError( CE_Failure, CPLE_FileIO,
611 0 : "Unable to read file section size.\n" );
612 0 : return NULL;
613 : }
614 :
615 : CPL_LSBPTR32( &nSize );
616 :
617 32 : if( VSIFReadL( (void *)&nVersion, sizeof(GInt32), 1, poDS->fp ) != 1 )
618 : {
619 0 : delete poDS;
620 : CPLError( CE_Failure, CPLE_FileIO,
621 0 : "Unable to read file version.\n" );
622 0 : return NULL;
623 : }
624 :
625 : CPL_LSBPTR32( &nVersion );
626 :
627 32 : if(nVersion != 1 && nVersion != 2)
628 : {
629 0 : delete poDS;
630 : CPLError( CE_Failure, CPLE_FileIO,
631 0 : "Incorrect file version (%d).", nVersion );
632 0 : return NULL;
633 : }
634 :
635 : // advance until the grid tag is found
636 96 : while(nTag != nGRID_TAG)
637 : {
638 32 : if( VSIFReadL( (void *)&nTag, sizeof(GInt32), 1, poDS->fp ) != 1 )
639 : {
640 0 : delete poDS;
641 0 : CPLError( CE_Failure, CPLE_FileIO, "Unable to read Tag.\n" );
642 0 : return NULL;
643 : }
644 :
645 : CPL_LSBPTR32( &nTag );
646 :
647 32 : if( VSIFReadL( (void *)&nSize, sizeof(GInt32), 1, poDS->fp ) != 1 )
648 : {
649 0 : delete poDS;
650 : CPLError( CE_Failure, CPLE_FileIO,
651 0 : "Unable to read file section size.\n" );
652 0 : return NULL;
653 : }
654 :
655 : CPL_LSBPTR32( &nSize );
656 :
657 32 : if(nTag != nGRID_TAG)
658 : {
659 0 : if( VSIFSeekL( poDS->fp, nSize, SEEK_SET ) != 0 )
660 : {
661 0 : delete poDS;
662 : CPLError( CE_Failure, CPLE_FileIO,
663 0 : "Unable to seek to end of file section.\n" );
664 0 : return NULL;
665 : }
666 : }
667 : }
668 :
669 : /* --------------------------------------------------------------------*/
670 : /* Read the grid. */
671 : /* --------------------------------------------------------------------*/
672 : /* Parse number of Y axis grid rows */
673 : GInt32 nRows;
674 32 : if( VSIFReadL( (void *)&nRows, sizeof(GInt32), 1, poDS->fp ) != 1 )
675 : {
676 0 : delete poDS;
677 : CPLError( CE_Failure, CPLE_FileIO,
678 0 : "Unable to read raster Y size.\n" );
679 0 : return NULL;
680 : }
681 : CPL_LSBPTR32( &nRows );
682 32 : poDS->nRasterYSize = nRows;
683 :
684 : /* Parse number of X axis grid columns */
685 : GInt32 nCols;
686 32 : if( VSIFReadL( (void *)&nCols, sizeof(GInt32), 1, poDS->fp ) != 1 )
687 : {
688 0 : delete poDS;
689 : CPLError( CE_Failure, CPLE_FileIO,
690 0 : "Unable to read raster X size.\n" );
691 0 : return NULL;
692 : }
693 : CPL_LSBPTR32( &nCols );
694 32 : poDS->nRasterXSize = nCols;
695 :
696 32 : if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize))
697 : {
698 0 : delete poDS;
699 0 : return NULL;
700 : }
701 :
702 : /* --------------------------------------------------------------------*/
703 : /* Create band information objects. */
704 : /* --------------------------------------------------------------------*/
705 32 : GS7BGRasterBand *poBand = new GS7BGRasterBand( poDS, 1 );
706 :
707 : // find the min X Value of the grid
708 : double dfTemp;
709 32 : if( VSIFReadL( (void *)&dfTemp, sizeof(double), 1, poDS->fp ) != 1 )
710 : {
711 0 : delete poDS;
712 : CPLError( CE_Failure, CPLE_FileIO,
713 0 : "Unable to read minimum X value.\n" );
714 0 : return NULL;
715 : }
716 : CPL_LSBPTR64( &dfTemp );
717 32 : poBand->dfMinX = dfTemp;
718 :
719 : // find the min Y value of the grid
720 32 : if( VSIFReadL( (void *)&dfTemp, sizeof(double), 1, poDS->fp ) != 1 )
721 : {
722 0 : delete poDS;
723 : CPLError( CE_Failure, CPLE_FileIO,
724 0 : "Unable to read minimum X value.\n" );
725 0 : return NULL;
726 : }
727 : CPL_LSBPTR64( &dfTemp );
728 32 : poBand->dfMinY = dfTemp;
729 :
730 : // find the spacing between adjacent nodes in the X direction
731 : // (between columns)
732 32 : if( VSIFReadL( (void *)&dfTemp, sizeof(double), 1, poDS->fp ) != 1 )
733 : {
734 0 : delete poDS;
735 : CPLError( CE_Failure, CPLE_FileIO,
736 0 : "Unable to read spacing in X value.\n" );
737 0 : return NULL;
738 : }
739 : CPL_LSBPTR64( &dfTemp );
740 32 : poBand->dfMaxX = poBand->dfMinX + (dfTemp * (nCols - 1));
741 :
742 : // find the spacing between adjacent nodes in the Y direction
743 : // (between rows)
744 32 : if( VSIFReadL( (void *)&dfTemp, sizeof(double), 1, poDS->fp ) != 1 )
745 : {
746 0 : delete poDS;
747 : CPLError( CE_Failure, CPLE_FileIO,
748 0 : "Unable to read spacing in Y value.\n" );
749 0 : return NULL;
750 : }
751 : CPL_LSBPTR64( &dfTemp );
752 32 : poBand->dfMaxY = poBand->dfMinY + (dfTemp * (nRows - 1));
753 :
754 : // set the z min
755 32 : if( VSIFReadL( (void *)&dfTemp, sizeof(double), 1, poDS->fp ) != 1 )
756 : {
757 0 : delete poDS;
758 : CPLError( CE_Failure, CPLE_FileIO,
759 0 : "Unable to read Z min value.\n" );
760 0 : return NULL;
761 : }
762 : CPL_LSBPTR64( &dfTemp );
763 32 : poBand->dfMinZ = dfTemp;
764 :
765 : // set the z max
766 32 : if( VSIFReadL( (void *)&dfTemp, sizeof(double), 1, poDS->fp ) != 1 )
767 : {
768 0 : delete poDS;
769 : CPLError( CE_Failure, CPLE_FileIO,
770 0 : "Unable to read Z max value.\n" );
771 0 : return NULL;
772 : }
773 : CPL_LSBPTR64( &dfTemp );
774 32 : poBand->dfMaxZ = dfTemp;
775 32 : poDS->SetBand( 1, poBand );
776 :
777 : // read and ignore the rotation value
778 : //(This is not used in the current version).
779 32 : if( VSIFReadL( (void *)&dfTemp, sizeof(double), 1, poDS->fp ) != 1 )
780 : {
781 0 : delete poDS;
782 : CPLError( CE_Failure, CPLE_FileIO,
783 0 : "Unable to read rotation value.\n" );
784 0 : return NULL;
785 : }
786 :
787 : // read and set the cell blank value
788 32 : if( VSIFReadL( (void *)&dfTemp, sizeof(double), 1, poDS->fp ) != 1 )
789 : {
790 0 : delete poDS;
791 : CPLError( CE_Failure, CPLE_FileIO,
792 0 : "Unable to Blank value.\n" );
793 0 : return NULL;
794 : }
795 : CPL_LSBPTR64( &dfTemp );
796 32 : poDS->dfNoData_Value = dfTemp;
797 :
798 : /* --------------------------------------------------------------------*/
799 : /* Set the current offset of the grid data. */
800 : /* --------------------------------------------------------------------*/
801 32 : if( VSIFReadL( (void *)&nTag, sizeof(GInt32), 1, poDS->fp ) != 1 )
802 : {
803 0 : delete poDS;
804 0 : CPLError( CE_Failure, CPLE_FileIO, "Unable to read Tag.\n" );
805 0 : return NULL;
806 : }
807 :
808 : CPL_LSBPTR32( &nTag );
809 32 : if(nTag != nDATA_TAG)
810 : {
811 0 : delete poDS;
812 0 : CPLError( CE_Failure, CPLE_FileIO, "Data tag not found.\n" );
813 0 : return NULL;
814 : }
815 :
816 32 : if( VSIFReadL( (void *)&nSize, sizeof(GInt32), 1, poDS->fp ) != 1 )
817 : {
818 0 : delete poDS;
819 : CPLError( CE_Failure, CPLE_FileIO,
820 0 : "Unable to data section size.\n" );
821 0 : return NULL;
822 : }
823 :
824 32 : poDS->nData_Position = (size_t) VSIFTellL(poDS->fp);
825 :
826 : /* --------------------------------------------------------------------*/
827 : /* Initialize any PAM information. */
828 : /* --------------------------------------------------------------------*/
829 32 : poDS->SetDescription( poOpenInfo->pszFilename );
830 32 : poDS->TryLoadXML();
831 :
832 : /* -------------------------------------------------------------------- */
833 : /* Check for external overviews. */
834 : /* -------------------------------------------------------------------- */
835 32 : poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename, poOpenInfo->papszSiblingFiles );
836 :
837 32 : return poDS;
838 : }
839 :
840 : /************************************************************************/
841 : /* GetGeoTransform() */
842 : /************************************************************************/
843 :
844 23 : CPLErr GS7BGDataset::GetGeoTransform( double *padfGeoTransform )
845 : {
846 23 : if( padfGeoTransform == NULL )
847 0 : return CE_Failure;
848 :
849 23 : GS7BGRasterBand *poGRB = (GS7BGRasterBand *)GetRasterBand( 1 );
850 :
851 23 : if( poGRB == NULL )
852 : {
853 0 : padfGeoTransform[0] = 0;
854 0 : padfGeoTransform[1] = 1;
855 0 : padfGeoTransform[2] = 0;
856 0 : padfGeoTransform[3] = 0;
857 0 : padfGeoTransform[4] = 0;
858 0 : padfGeoTransform[5] = 1;
859 0 : return CE_Failure;
860 : }
861 :
862 : /* check if we have a PAM GeoTransform stored */
863 23 : CPLPushErrorHandler( CPLQuietErrorHandler );
864 23 : CPLErr eErr = GDALPamDataset::GetGeoTransform( padfGeoTransform );
865 23 : CPLPopErrorHandler();
866 :
867 23 : if( eErr == CE_None )
868 0 : return CE_None;
869 :
870 : /* calculate pixel size first */
871 23 : padfGeoTransform[1] = (poGRB->dfMaxX - poGRB->dfMinX)/(nRasterXSize - 1);
872 23 : padfGeoTransform[5] = (poGRB->dfMinY - poGRB->dfMaxY)/(nRasterYSize - 1);
873 :
874 : /* then calculate image origin */
875 23 : padfGeoTransform[0] = poGRB->dfMinX - padfGeoTransform[1] / 2;
876 23 : padfGeoTransform[3] = poGRB->dfMaxY - padfGeoTransform[5] / 2;
877 :
878 : /* tilt/rotation does not supported by the GS grids */
879 23 : padfGeoTransform[4] = 0.0;
880 23 : padfGeoTransform[2] = 0.0;
881 :
882 23 : return CE_None;
883 : }
884 :
885 : /************************************************************************/
886 : /* SetGeoTransform() */
887 : /************************************************************************/
888 :
889 6 : CPLErr GS7BGDataset::SetGeoTransform( double *padfGeoTransform )
890 : {
891 6 : if( eAccess == GA_ReadOnly )
892 : {
893 : CPLError( CE_Failure, CPLE_NoWriteAccess,
894 0 : "Unable to set GeoTransform, dataset opened read only.\n" );
895 0 : return CE_Failure;
896 : }
897 :
898 6 : GS7BGRasterBand *poGRB = dynamic_cast<GS7BGRasterBand *>(GetRasterBand( 1 ));
899 :
900 6 : if( poGRB == NULL || padfGeoTransform == NULL)
901 0 : return CE_Failure;
902 :
903 : /* non-zero transform 2 or 4 or negative 1 or 5 not supported natively */
904 6 : CPLErr eErr = CE_None;
905 : /*if( padfGeoTransform[2] != 0.0 || padfGeoTransform[4] != 0.0
906 : || padfGeoTransform[1] < 0.0 || padfGeoTransform[5] < 0.0 )
907 : eErr = GDALPamDataset::SetGeoTransform( padfGeoTransform );
908 :
909 : if( eErr != CE_None )
910 : return eErr;*/
911 :
912 6 : double dfMinX = padfGeoTransform[0] + padfGeoTransform[1] / 2;
913 6 : double dfMaxX = padfGeoTransform[1] * (nRasterXSize - 0.5) + padfGeoTransform[0];
914 6 : double dfMinY = padfGeoTransform[5] * (nRasterYSize - 0.5) + padfGeoTransform[3];
915 6 : double dfMaxY = padfGeoTransform[3] + padfGeoTransform[5] / 2;
916 :
917 : eErr = WriteHeader( fp, poGRB->nRasterXSize, poGRB->nRasterYSize,
918 : dfMinX, dfMaxX, dfMinY, dfMaxY,
919 6 : poGRB->dfMinZ, poGRB->dfMaxZ );
920 :
921 6 : if( eErr == CE_None )
922 : {
923 6 : poGRB->dfMinX = dfMinX;
924 6 : poGRB->dfMaxX = dfMaxX;
925 6 : poGRB->dfMinY = dfMinY;
926 6 : poGRB->dfMaxY = dfMaxY;
927 : }
928 :
929 6 : return eErr;
930 : }
931 :
932 : /************************************************************************/
933 : /* WriteHeader() */
934 : /************************************************************************/
935 :
936 43 : CPLErr GS7BGDataset::WriteHeader( VSILFILE *fp, GInt32 nXSize, GInt32 nYSize,
937 : double dfMinX, double dfMaxX,
938 : double dfMinY, double dfMaxY,
939 : double dfMinZ, double dfMaxZ )
940 :
941 : {
942 43 : if( VSIFSeekL( fp, 0, SEEK_SET ) != 0 )
943 : {
944 : CPLError( CE_Failure, CPLE_FileIO,
945 0 : "Unable to seek to start of grid file.\n" );
946 0 : return CE_Failure;
947 : }
948 :
949 43 : GInt32 nTemp = CPL_LSBWORD32(nHEADER_TAG);
950 43 : if( VSIFWriteL( (void *)&nTemp, sizeof(GInt32), 1, fp ) != 1 )
951 : {
952 : CPLError( CE_Failure, CPLE_FileIO,
953 0 : "Unable to write header tag to grid file.\n" );
954 0 : return CE_Failure;
955 : }
956 :
957 43 : nTemp = CPL_LSBWORD32(sizeof(GInt32)); // Size of version section.
958 43 : if( VSIFWriteL( (void *)&nTemp, sizeof(GInt32), 1, fp ) != 1 )
959 : {
960 : CPLError( CE_Failure, CPLE_FileIO,
961 0 : "Unable to write size to grid file.\n" );
962 0 : return CE_Failure;
963 : }
964 :
965 43 : nTemp = CPL_LSBWORD32(1); // Version
966 43 : if( VSIFWriteL( (void *)&nTemp, sizeof(GInt32), 1, fp ) != 1 )
967 : {
968 : CPLError( CE_Failure, CPLE_FileIO,
969 0 : "Unable to write size to grid file.\n" );
970 0 : return CE_Failure;
971 : }
972 :
973 43 : nTemp = CPL_LSBWORD32(nGRID_TAG); // Mark start of grid
974 43 : if( VSIFWriteL( (void *)&nTemp, sizeof(GInt32), 1, fp ) != 1 )
975 : {
976 : CPLError( CE_Failure, CPLE_FileIO,
977 0 : "Unable to write size to grid file.\n" );
978 0 : return CE_Failure;
979 : }
980 :
981 43 : nTemp = CPL_LSBWORD32(72); // Grid info size (the remainder of the header)
982 43 : if( VSIFWriteL( (void *)&nTemp, sizeof(GInt32), 1, fp ) != 1 )
983 : {
984 : CPLError( CE_Failure, CPLE_FileIO,
985 0 : "Unable to write size to grid file.\n" );
986 0 : return CE_Failure;
987 : }
988 :
989 43 : nTemp = CPL_LSBWORD32(nYSize);
990 43 : if( VSIFWriteL( (void *)&nTemp, sizeof(GInt32), 1, fp ) != 1 )
991 : {
992 : CPLError( CE_Failure, CPLE_FileIO,
993 0 : "Unable to write Y size to grid file.\n" );
994 0 : return CE_Failure;
995 : }
996 :
997 43 : nTemp = CPL_LSBWORD32(nXSize);
998 43 : if( VSIFWriteL( (void *)&nTemp, sizeof(GInt32), 1, fp ) != 1 )
999 : {
1000 : CPLError( CE_Failure, CPLE_FileIO,
1001 0 : "Unable to write X size to grid file.\n" );
1002 0 : return CE_Failure;
1003 : }
1004 :
1005 43 : double dfTemp = dfMinX;
1006 : CPL_LSBPTR64(&dfTemp);
1007 43 : if( VSIFWriteL( (void *)&dfTemp, sizeof(double), 1, fp ) != 1 )
1008 : {
1009 : CPLError( CE_Failure, CPLE_FileIO,
1010 0 : "Unable to write minimum X value to grid file.\n" );
1011 0 : return CE_Failure;
1012 : }
1013 :
1014 43 : dfTemp = dfMinY;
1015 : CPL_LSBPTR64( &dfTemp );
1016 43 : if( VSIFWriteL( (void *)&dfTemp, sizeof(double), 1, fp ) != 1 )
1017 : {
1018 : CPLError( CE_Failure, CPLE_FileIO,
1019 0 : "Unable to write minimum Y value to grid file.\n" );
1020 0 : return CE_Failure;
1021 : }
1022 :
1023 : // Write node spacing in x direction
1024 43 : dfTemp = (dfMaxX - dfMinX) / (nXSize - 1);
1025 : CPL_LSBPTR64(&dfTemp);
1026 43 : if( VSIFWriteL( (void *)&dfTemp, sizeof(double), 1, fp ) != 1 )
1027 : {
1028 : CPLError( CE_Failure, CPLE_FileIO,
1029 0 : "Unable to write spacing in X value.\n" );
1030 0 : return CE_Failure;
1031 : }
1032 :
1033 : // Write node spacing in y direction
1034 43 : dfTemp = (dfMaxY - dfMinY) / (nYSize -1);
1035 : CPL_LSBPTR64( &dfTemp );
1036 43 : if( VSIFWriteL( (void *)&dfTemp, sizeof(double), 1, fp ) != 1 )
1037 : {
1038 : CPLError( CE_Failure, CPLE_FileIO,
1039 0 : "Unable to write spacing in Y value.\n" );
1040 0 : return CE_Failure;
1041 : }
1042 :
1043 43 : dfTemp = dfMinZ;
1044 : CPL_LSBPTR64( &dfTemp );
1045 43 : if( VSIFWriteL( (void *)&dfTemp, sizeof(double), 1, fp ) != 1 )
1046 : {
1047 : CPLError( CE_Failure, CPLE_FileIO,
1048 0 : "Unable to write minimum Z value to grid file.\n" );
1049 0 : return CE_Failure;
1050 : }
1051 :
1052 43 : dfTemp = dfMaxZ;
1053 : CPL_LSBPTR64( &dfTemp );
1054 43 : if( VSIFWriteL( (void *)&dfTemp, sizeof(double), 1, fp ) != 1 )
1055 : {
1056 : CPLError( CE_Failure, CPLE_FileIO,
1057 0 : "Unable to write maximum Z value to grid file.\n" );
1058 0 : return CE_Failure;
1059 : }
1060 :
1061 43 : dfTemp = 0; // Rotation value is zero
1062 : CPL_LSBPTR64( &dfTemp );
1063 43 : if( VSIFWriteL( (void *)&dfTemp, sizeof(double), 1, fp ) != 1 )
1064 : {
1065 : CPLError( CE_Failure, CPLE_FileIO,
1066 0 : "Unable to write rotation value to grid file.\n" );
1067 0 : return CE_Failure;
1068 : }
1069 :
1070 43 : dfTemp = dfNoData_Value;
1071 : CPL_LSBPTR64( &dfTemp );
1072 43 : if( VSIFWriteL( (void *)&dfTemp, sizeof(double), 1, fp ) != 1 )
1073 : {
1074 : CPLError( CE_Failure, CPLE_FileIO,
1075 0 : "Unable to write cell blank value to grid file.\n" );
1076 0 : return CE_Failure;
1077 : }
1078 :
1079 : // Only supports 1 band so go ahead and write band info here
1080 43 : nTemp = CPL_LSBWORD32(nDATA_TAG); // Mark start of data
1081 43 : if( VSIFWriteL( (void *)&nTemp, sizeof(GInt32), 1, fp ) != 1 )
1082 : {
1083 : CPLError( CE_Failure, CPLE_FileIO,
1084 0 : "Unable to data tag to grid file.\n" );
1085 0 : return CE_Failure;
1086 : }
1087 :
1088 43 : int nSize = nXSize * nYSize * sizeof(double);
1089 43 : nTemp = CPL_LSBWORD32(nSize); // Mark size of data
1090 43 : if( VSIFWriteL( (void *)&nTemp, sizeof(GInt32), 1, fp ) != 1 )
1091 : {
1092 : CPLError( CE_Failure, CPLE_FileIO,
1093 0 : "Unable to write data size to grid file.\n" );
1094 0 : return CE_Failure;
1095 : }
1096 :
1097 :
1098 43 : return CE_None;
1099 : }
1100 :
1101 : /************************************************************************/
1102 : /* Create() */
1103 : /************************************************************************/
1104 :
1105 27 : GDALDataset *GS7BGDataset::Create( const char * pszFilename,
1106 : int nXSize, int nYSize, int nBands,
1107 : GDALDataType eType,
1108 : char **papszParmList )
1109 :
1110 : {
1111 27 : if( nXSize <= 0 || nYSize <= 0 )
1112 : {
1113 : CPLError( CE_Failure, CPLE_IllegalArg,
1114 : "Unable to create grid, both X and Y size must be "
1115 0 : "non-negative.\n" );
1116 :
1117 0 : return NULL;
1118 : }
1119 :
1120 27 : if( eType != GDT_Byte && eType != GDT_Float32 && eType != GDT_UInt16
1121 : && eType != GDT_Int16 && eType != GDT_Float64)
1122 : {
1123 : CPLError( CE_Failure, CPLE_AppDefined,
1124 : "GS7BG Grid only supports Byte, Int16, "
1125 : "Uint16, Float32, and Float64 datatypes. Unable to create with "
1126 12 : "type %s.\n", GDALGetDataTypeName( eType ) );
1127 :
1128 12 : return NULL;
1129 : }
1130 :
1131 15 : if (nBands > 1)
1132 : {
1133 : CPLError( CE_Failure, CPLE_NotSupported,
1134 : "Unable to create copy, "
1135 8 : "format only supports one raster band.\n" );
1136 8 : return NULL;
1137 : }
1138 :
1139 7 : VSILFILE *fp = VSIFOpenL( pszFilename, "w+b" );
1140 :
1141 7 : if( fp == NULL )
1142 : {
1143 : CPLError( CE_Failure, CPLE_OpenFailed,
1144 : "Attempt to create file '%s' failed.\n",
1145 0 : pszFilename );
1146 0 : return NULL;
1147 : }
1148 :
1149 : CPLErr eErr = WriteHeader( fp, nXSize, nYSize,
1150 7 : 0.0, nXSize, 0.0, nYSize, 0.0, 0.0 );
1151 7 : if( eErr != CE_None )
1152 : {
1153 0 : VSIFCloseL( fp );
1154 0 : return NULL;
1155 : }
1156 :
1157 7 : double dfVal = dfNoData_Value;
1158 : CPL_LSBPTR64( &dfVal );
1159 627 : for( int iRow = 0; iRow < nYSize; iRow++ )
1160 : {
1161 61020 : for( int iCol=0; iCol<nXSize; iCol++ )
1162 : {
1163 60400 : if( VSIFWriteL( (void *)&dfVal, sizeof(double), 1, fp ) != 1 )
1164 : {
1165 0 : VSIFCloseL( fp );
1166 : CPLError( CE_Failure, CPLE_FileIO,
1167 0 : "Unable to write grid cell. Disk full?\n" );
1168 0 : return NULL;
1169 : }
1170 : }
1171 : }
1172 :
1173 7 : VSIFCloseL( fp );
1174 :
1175 7 : return (GDALDataset *)GDALOpen( pszFilename, GA_Update );
1176 : }
1177 :
1178 : /************************************************************************/
1179 : /* CreateCopy() */
1180 : /************************************************************************/
1181 :
1182 30 : GDALDataset *GS7BGDataset::CreateCopy( const char *pszFilename,
1183 : GDALDataset *poSrcDS,
1184 : int bStrict, char **papszOptions,
1185 : GDALProgressFunc pfnProgress,
1186 : void *pProgressData )
1187 : {
1188 30 : if( pfnProgress == NULL )
1189 0 : pfnProgress = GDALDummyProgress;
1190 :
1191 30 : int nBands = poSrcDS->GetRasterCount();
1192 30 : if (nBands == 0)
1193 : {
1194 : CPLError( CE_Failure, CPLE_NotSupported,
1195 1 : "Driver does not support source dataset with zero band.\n");
1196 1 : return NULL;
1197 : }
1198 29 : else if (nBands > 1)
1199 : {
1200 4 : if( bStrict )
1201 : {
1202 : CPLError( CE_Failure, CPLE_NotSupported,
1203 : "Unable to create copy, "
1204 4 : "format only supports one raster band.\n" );
1205 4 : return NULL;
1206 : }
1207 : else
1208 : CPLError( CE_Warning, CPLE_NotSupported,
1209 : "Format only supports one "
1210 0 : "raster band, first band will be copied.\n" );
1211 : }
1212 :
1213 25 : GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand( 1 );
1214 :
1215 25 : if( !pfnProgress( 0.0, NULL, pProgressData ) )
1216 : {
1217 0 : CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated\n" );
1218 0 : return NULL;
1219 : }
1220 :
1221 25 : VSILFILE *fp = VSIFOpenL( pszFilename, "w+b" );
1222 :
1223 25 : if( fp == NULL )
1224 : {
1225 : CPLError( CE_Failure, CPLE_OpenFailed,
1226 : "Attempt to create file '%s' failed.\n",
1227 13 : pszFilename );
1228 13 : return NULL;
1229 : }
1230 :
1231 12 : GInt32 nXSize = poSrcBand->GetXSize();
1232 12 : GInt32 nYSize = poSrcBand->GetYSize();
1233 : double adfGeoTransform[6];
1234 :
1235 12 : poSrcDS->GetGeoTransform( adfGeoTransform );
1236 :
1237 12 : double dfMinX = adfGeoTransform[0] + adfGeoTransform[1] / 2;
1238 12 : double dfMaxX = adfGeoTransform[1] * (nXSize - 0.5) + adfGeoTransform[0];
1239 12 : double dfMinY = adfGeoTransform[5] * (nYSize - 0.5) + adfGeoTransform[3];
1240 12 : double dfMaxY = adfGeoTransform[3] + adfGeoTransform[5] / 2;
1241 : CPLErr eErr = WriteHeader( fp, nXSize, nYSize,
1242 12 : dfMinX, dfMaxX, dfMinY, dfMaxY, 0.0, 0.0 );
1243 :
1244 12 : if( eErr != CE_None )
1245 : {
1246 0 : VSIFCloseL( fp );
1247 0 : return NULL;
1248 : }
1249 :
1250 : /* -------------------------------------------------------------------- */
1251 : /* Copy band data. */
1252 : /* -------------------------------------------------------------------- */
1253 12 : double *pfData = (double *)VSIMalloc2( nXSize, sizeof( double ) );
1254 12 : if( pfData == NULL )
1255 : {
1256 0 : VSIFCloseL( fp );
1257 : CPLError( CE_Failure, CPLE_OutOfMemory,
1258 0 : "Unable to create copy, unable to allocate line buffer.\n" );
1259 0 : return NULL;
1260 : }
1261 :
1262 : int bSrcHasNDValue;
1263 12 : double dfSrcNoDataValue = poSrcBand->GetNoDataValue( &bSrcHasNDValue );
1264 12 : double dfMinZ = DBL_MAX;
1265 12 : double dfMaxZ = -DBL_MAX;
1266 142 : for( GInt32 iRow = nYSize - 1; iRow >= 0; iRow-- )
1267 : {
1268 : eErr = poSrcBand->RasterIO( GF_Read, 0, iRow,
1269 : nXSize, 1, pfData,
1270 130 : nXSize, 1, GDT_Float64, 0, 0 );
1271 :
1272 130 : if( eErr != CE_None )
1273 : {
1274 0 : VSIFCloseL( fp );
1275 0 : VSIFree( pfData );
1276 0 : return NULL;
1277 : }
1278 :
1279 1630 : for( int iCol=0; iCol<nXSize; iCol++ )
1280 : {
1281 1500 : if( bSrcHasNDValue && pfData[iCol] == dfSrcNoDataValue )
1282 : {
1283 0 : pfData[iCol] = dfNoData_Value;
1284 : }
1285 : else
1286 : {
1287 1500 : if( pfData[iCol] > dfMaxZ )
1288 14 : dfMaxZ = pfData[iCol];
1289 :
1290 1500 : if( pfData[iCol] < dfMinZ )
1291 19 : dfMinZ = pfData[iCol];
1292 : }
1293 :
1294 : CPL_LSBPTR32( pfData+iCol );
1295 : }
1296 :
1297 130 : if( VSIFWriteL( (void *)pfData, sizeof( double ), nXSize,
1298 : fp ) != static_cast<unsigned>(nXSize) )
1299 : {
1300 0 : VSIFCloseL( fp );
1301 0 : VSIFree( pfData );
1302 : CPLError( CE_Failure, CPLE_FileIO,
1303 0 : "Unable to write grid row. Disk full?\n" );
1304 0 : return NULL;
1305 : }
1306 :
1307 130 : if( !pfnProgress( static_cast<double>(nYSize - iRow)/nYSize,
1308 : NULL, pProgressData ) )
1309 : {
1310 0 : VSIFCloseL( fp );
1311 0 : VSIFree( pfData );
1312 0 : CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
1313 0 : return NULL;
1314 : }
1315 : }
1316 :
1317 12 : VSIFree( pfData );
1318 :
1319 : /* write out the min and max values */
1320 : eErr = WriteHeader( fp, nXSize, nYSize,
1321 12 : dfMinX, dfMaxX, dfMinY, dfMaxY, dfMinZ, dfMaxZ );
1322 :
1323 12 : if( eErr != CE_None )
1324 : {
1325 0 : VSIFCloseL( fp );
1326 0 : return NULL;
1327 : }
1328 :
1329 12 : VSIFCloseL( fp );
1330 :
1331 : GDALPamDataset *poDS = (GDALPamDataset *)GDALOpen( pszFilename,
1332 12 : GA_Update );
1333 12 : if (poDS)
1334 : {
1335 12 : poDS->CloneInfo( poSrcDS, GCIF_PAM_DEFAULT );
1336 : }
1337 :
1338 12 : return poDS;
1339 : }
1340 :
1341 : /************************************************************************/
1342 : /* GDALRegister_GS7BG() */
1343 : /************************************************************************/
1344 582 : void GDALRegister_GS7BG()
1345 :
1346 : {
1347 : GDALDriver *poDriver;
1348 :
1349 582 : if( GDALGetDriverByName( "GS7BG" ) == NULL )
1350 : {
1351 561 : poDriver = new GDALDriver();
1352 :
1353 561 : poDriver->SetDescription( "GS7BG" );
1354 : poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
1355 561 : "Golden Software 7 Binary Grid (.grd)" );
1356 : poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
1357 561 : "frmt_various.html#GS7BG" );
1358 561 : poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "grd" );
1359 : poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES,
1360 561 : "Byte Int16 UInt16 Float32 Float64" );
1361 561 : poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
1362 :
1363 561 : poDriver->pfnIdentify = GS7BGDataset::Identify;
1364 561 : poDriver->pfnOpen = GS7BGDataset::Open;
1365 561 : poDriver->pfnCreate = GS7BGDataset::Create;
1366 561 : poDriver->pfnCreateCopy = GS7BGDataset::CreateCopy;
1367 :
1368 561 : GetGDALDriverManager()->RegisterDriver( poDriver );
1369 : }
1370 582 : }
1371 :
|