1
/******************************************************************************
2
* $Id: ngsgeoiddataset.cpp 23334 2011-11-05 22:40:46Z rouault $
4
* Project: NGSGEOID driver
5
* Purpose: GDALDataset driver for NGSGEOID dataset.
6
* Author: Even Rouault, <even dot rouault at mines dash paris dot org>
8
******************************************************************************
9
* Copyright (c) 2011, Even Rouault
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:
18
* The above copyright notice and this permission notice shall be included
19
* in all copies or substantial portions of the Software.
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
****************************************************************************/
30
#include "cpl_vsi_virtual.h"
31
#include "cpl_string.h"
33
#include "ogr_srs_api.h"
35
CPL_CVSID("$Id: ngsgeoiddataset.cpp 23334 2011-11-05 22:40:46Z rouault $");
38
void GDALRegister_NGSGEOID(void);
41
#define HEADER_SIZE (4 * 8 + 3 * 4)
43
/************************************************************************/
44
/* ==================================================================== */
46
/* ==================================================================== */
47
/************************************************************************/
49
class NGSGEOIDRasterBand;
51
class NGSGEOIDDataset : public GDALPamDataset
53
friend class NGSGEOIDRasterBand;
56
double adfGeoTransform[6];
59
static int GetHeaderInfo( const GByte* pBuffer,
60
double* padfGeoTransform,
63
int* pbIsLittleEndian );
67
virtual ~NGSGEOIDDataset();
69
virtual CPLErr GetGeoTransform( double * );
70
virtual const char* GetProjectionRef();
72
static GDALDataset *Open( GDALOpenInfo * );
73
static int Identify( GDALOpenInfo * );
76
/************************************************************************/
77
/* ==================================================================== */
78
/* NGSGEOIDRasterBand */
79
/* ==================================================================== */
80
/************************************************************************/
82
class NGSGEOIDRasterBand : public GDALPamRasterBand
84
friend class NGSGEOIDDataset;
88
NGSGEOIDRasterBand( NGSGEOIDDataset * );
90
virtual CPLErr IReadBlock( int, int, void * );
92
virtual const char* GetUnitType() { return "m"; }
96
/************************************************************************/
97
/* NGSGEOIDRasterBand() */
98
/************************************************************************/
100
NGSGEOIDRasterBand::NGSGEOIDRasterBand( NGSGEOIDDataset *poDS )
106
eDataType = GDT_Float32;
108
nBlockXSize = poDS->GetRasterXSize();
112
/************************************************************************/
114
/************************************************************************/
116
CPLErr NGSGEOIDRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
120
NGSGEOIDDataset *poGDS = (NGSGEOIDDataset *) poDS;
122
/* First values in the file corresponds to the south-most line of the imagery */
124
HEADER_SIZE + (nRasterYSize - 1 - nBlockYOff) * nRasterXSize * 4,
127
if ((int)VSIFReadL(pImage, 4, nRasterXSize, poGDS->fp) != nRasterXSize)
130
if (poGDS->bIsLittleEndian)
133
GDALSwapWords( pImage, 4, nRasterXSize, 4 );
139
GDALSwapWords( pImage, 4, nRasterXSize, 4 );
146
/************************************************************************/
147
/* ~NGSGEOIDDataset() */
148
/************************************************************************/
150
NGSGEOIDDataset::NGSGEOIDDataset()
153
adfGeoTransform[0] = 0;
154
adfGeoTransform[1] = 1;
155
adfGeoTransform[2] = 0;
156
adfGeoTransform[3] = 0;
157
adfGeoTransform[4] = 0;
158
adfGeoTransform[5] = 1;
159
bIsLittleEndian = TRUE;
162
/************************************************************************/
163
/* ~NGSGEOIDDataset() */
164
/************************************************************************/
166
NGSGEOIDDataset::~NGSGEOIDDataset()
174
/************************************************************************/
175
/* GetHeaderInfo() */
176
/************************************************************************/
178
int NGSGEOIDDataset::GetHeaderInfo( const GByte* pBuffer,
179
double* padfGeoTransform,
182
int* pbIsLittleEndian )
192
/* First check IKIND marker to determine if the file */
193
/* is in little or big-endian order, and if it is a valid */
194
/* NGSGEOID dataset */
195
memcpy(&nIKIND, pBuffer + HEADER_SIZE - 4, 4);
196
CPL_LSBPTR32(&nIKIND);
199
*pbIsLittleEndian = TRUE;
203
memcpy(&nIKIND, pBuffer + HEADER_SIZE - 4, 4);
204
CPL_MSBPTR32(&nIKIND);
207
*pbIsLittleEndian = FALSE;
215
memcpy(&dfSLAT, pBuffer, 8);
216
if (*pbIsLittleEndian)
218
CPL_LSBPTR64(&dfSLAT);
222
CPL_MSBPTR64(&dfSLAT);
225
memcpy(&dfWLON, pBuffer, 8);
226
if (*pbIsLittleEndian)
228
CPL_LSBPTR64(&dfWLON);
232
CPL_MSBPTR64(&dfWLON);
235
memcpy(&dfDLAT, pBuffer, 8);
236
if (*pbIsLittleEndian)
238
CPL_LSBPTR64(&dfDLAT);
242
CPL_MSBPTR64(&dfDLAT);
245
memcpy(&dfDLON, pBuffer, 8);
246
if (*pbIsLittleEndian)
248
CPL_LSBPTR64(&dfDLON);
252
CPL_MSBPTR64(&dfDLON);
255
memcpy(&nNLAT, pBuffer, 4);
256
if (*pbIsLittleEndian)
258
CPL_LSBPTR32(&nNLAT);
262
CPL_MSBPTR32(&nNLAT);
265
memcpy(&nNLON, pBuffer, 4);
266
if (*pbIsLittleEndian)
268
CPL_LSBPTR32(&nNLON);
272
CPL_MSBPTR32(&nNLON);
276
/*CPLDebug("NGSGEOID", "SLAT=%f, WLON=%f, DLAT=%f, DLON=%f, NLAT=%d, NLON=%d, IKIND=%d",
277
dfSLAT, dfWLON, dfDLAT, dfDLON, nNLAT, nNLON, nIKIND);*/
279
if (nNLAT <= 0 || nNLON <= 0 || dfDLAT <= 0.0 || dfDLON <= 0.0)
282
/* Grids go over +180 in longitude */
283
if (dfSLAT < -90.0 || dfSLAT + nNLAT * dfDLAT > 90.0 ||
284
dfWLON < -180.0 || dfWLON + nNLON * dfDLON > 360.0)
287
padfGeoTransform[0] = dfWLON - dfDLON / 2;
288
padfGeoTransform[1] = dfDLON;
289
padfGeoTransform[2] = 0.0;
290
padfGeoTransform[3] = dfSLAT + nNLAT * dfDLAT - dfDLAT / 2;
291
padfGeoTransform[4] = 0.0;
292
padfGeoTransform[5] = -dfDLAT;
300
/************************************************************************/
302
/************************************************************************/
304
int NGSGEOIDDataset::Identify( GDALOpenInfo * poOpenInfo )
306
if (poOpenInfo->nHeaderBytes < HEADER_SIZE)
309
double adfGeoTransform[6];
312
if ( !GetHeaderInfo( poOpenInfo->pabyHeader,
314
&nRows, &nCols, &bIsLittleEndian ) )
321
/************************************************************************/
323
/************************************************************************/
325
GDALDataset *NGSGEOIDDataset::Open( GDALOpenInfo * poOpenInfo )
328
if (!Identify(poOpenInfo))
331
if (poOpenInfo->eAccess == GA_Update)
333
CPLError( CE_Failure, CPLE_NotSupported,
334
"The NGSGEOID driver does not support update access to existing"
339
VSILFILE* fp = VSIFOpenL( poOpenInfo->pszFilename, "rb" );
343
/* -------------------------------------------------------------------- */
344
/* Create a corresponding GDALDataset. */
345
/* -------------------------------------------------------------------- */
346
NGSGEOIDDataset *poDS;
348
poDS = new NGSGEOIDDataset();
352
GetHeaderInfo( poOpenInfo->pabyHeader,
353
poDS->adfGeoTransform,
356
&poDS->bIsLittleEndian );
357
poDS->nRasterXSize = nCols;
358
poDS->nRasterYSize = nRows;
360
/* -------------------------------------------------------------------- */
361
/* Create band information objects. */
362
/* -------------------------------------------------------------------- */
364
poDS->SetBand( 1, new NGSGEOIDRasterBand( poDS ) );
366
/* -------------------------------------------------------------------- */
367
/* Initialize any PAM information. */
368
/* -------------------------------------------------------------------- */
369
poDS->SetDescription( poOpenInfo->pszFilename );
372
/* -------------------------------------------------------------------- */
373
/* Support overviews. */
374
/* -------------------------------------------------------------------- */
375
poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
379
/************************************************************************/
380
/* GetGeoTransform() */
381
/************************************************************************/
383
CPLErr NGSGEOIDDataset::GetGeoTransform( double * padfTransform )
386
memcpy(padfTransform, adfGeoTransform, 6 * sizeof(double));
391
/************************************************************************/
392
/* GetProjectionRef() */
393
/************************************************************************/
395
const char* NGSGEOIDDataset::GetProjectionRef()
397
return SRS_WKT_WGS84;
400
/************************************************************************/
401
/* GDALRegister_NGSGEOID() */
402
/************************************************************************/
404
void GDALRegister_NGSGEOID()
407
GDALDriver *poDriver;
409
if( GDALGetDriverByName( "NGSGEOID" ) == NULL )
411
poDriver = new GDALDriver();
413
poDriver->SetDescription( "NGSGEOID" );
414
poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
415
"NOAA NGS Geoid Height Grids" );
416
poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
417
"frmt_ngsgeoid.html" );
418
poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "bin" );
420
poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
422
poDriver->pfnOpen = NGSGEOIDDataset::Open;
423
poDriver->pfnIdentify = NGSGEOIDDataset::Identify;
425
GetGDALDriverManager()->RegisterDriver( poDriver );