1
/******************************************************************************
2
* $Id: snodasdataset.cpp 21984 2011-03-19 17:22:58Z rouault $
4
* Project: SNODAS driver
5
* Purpose: Implementation of SNODASDataset
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 "rawdataset.h"
31
#include "ogr_srs_api.h"
32
#include "cpl_string.h"
34
CPL_CVSID("$Id: snodasdataset.cpp 21984 2011-03-19 17:22:58Z rouault $");
36
// g++ -g -Wall -fPIC frmts/raw/snodasdataset.cpp -shared -o gdal_SNODAS.so -Iport -Igcore -Ifrmts/raw -Iogr -L. -lgdal
39
void GDALRegister_SNODAS(void);
42
/************************************************************************/
43
/* ==================================================================== */
45
/* ==================================================================== */
46
/************************************************************************/
48
class SNODASRasterBand;
50
class SNODASDataset : public RawDataset
52
CPLString osDataFilename;
54
double adfGeoTransform[6];
62
friend class SNODASRasterBand;
68
virtual CPLErr GetGeoTransform( double * padfTransform );
69
virtual const char *GetProjectionRef(void);
71
virtual char **GetFileList();
73
static GDALDataset *Open( GDALOpenInfo * );
74
static int Identify( GDALOpenInfo * );
78
/************************************************************************/
79
/* ==================================================================== */
80
/* SNODASRasterBand */
81
/* ==================================================================== */
82
/************************************************************************/
84
class SNODASRasterBand : public RawRasterBand
87
SNODASRasterBand(VSILFILE* fpRaw, int nXSize, int nYSize);
89
virtual double GetNoDataValue( int *pbSuccess = NULL );
90
virtual double GetMinimum( int *pbSuccess = NULL );
91
virtual double GetMaximum(int *pbSuccess = NULL );
95
/************************************************************************/
96
/* SNODASRasterBand() */
97
/************************************************************************/
99
SNODASRasterBand::SNODASRasterBand(VSILFILE* fpRaw,
100
int nXSize, int nYSize) :
101
RawRasterBand( fpRaw, 0, 2,
102
nXSize * 2, GDT_Int16,
103
!CPL_IS_LSB, nXSize, nYSize, TRUE, TRUE)
107
/************************************************************************/
108
/* GetNoDataValue() */
109
/************************************************************************/
111
double SNODASRasterBand::GetNoDataValue( int *pbSuccess )
113
SNODASDataset* poGDS = (SNODASDataset*) poDS;
115
*pbSuccess = poGDS->bHasNoData;
116
if (poGDS->bHasNoData)
117
return poGDS->dfNoData;
119
return RawRasterBand::GetNoDataValue(pbSuccess);
122
/************************************************************************/
124
/************************************************************************/
126
double SNODASRasterBand::GetMinimum( int *pbSuccess )
128
SNODASDataset* poGDS = (SNODASDataset*) poDS;
130
*pbSuccess = poGDS->bHasMin;
134
return RawRasterBand::GetMinimum(pbSuccess);
137
/************************************************************************/
139
/************************************************************************/
141
double SNODASRasterBand::GetMaximum( int *pbSuccess )
143
SNODASDataset* poGDS = (SNODASDataset*) poDS;
145
*pbSuccess = poGDS->bHasMax;
149
return RawRasterBand::GetMaximum(pbSuccess);
152
/************************************************************************/
153
/* ==================================================================== */
155
/* ==================================================================== */
156
/************************************************************************/
158
/************************************************************************/
159
/* SNODASDataset() */
160
/************************************************************************/
162
SNODASDataset::SNODASDataset()
164
bGotTransform = FALSE;
165
adfGeoTransform[0] = 0.0;
166
adfGeoTransform[1] = 1.0;
167
adfGeoTransform[2] = 0.0;
168
adfGeoTransform[3] = 0.0;
169
adfGeoTransform[4] = 0.0;
170
adfGeoTransform[5] = 1.0;
179
/************************************************************************/
180
/* ~SNODASDataset() */
181
/************************************************************************/
183
SNODASDataset::~SNODASDataset()
189
/************************************************************************/
190
/* GetProjectionRef() */
191
/************************************************************************/
193
const char *SNODASDataset::GetProjectionRef()
196
return SRS_WKT_WGS84;
199
/************************************************************************/
200
/* GetGeoTransform() */
201
/************************************************************************/
203
CPLErr SNODASDataset::GetGeoTransform( double * padfTransform )
208
memcpy( padfTransform, adfGeoTransform, sizeof(double) * 6 );
213
return GDALPamDataset::GetGeoTransform( padfTransform );
218
/************************************************************************/
220
/************************************************************************/
222
char **SNODASDataset::GetFileList()
225
char **papszFileList = GDALPamDataset::GetFileList();
227
papszFileList = CSLAddString(papszFileList, osDataFilename);
229
return papszFileList;
232
/************************************************************************/
234
/************************************************************************/
236
int SNODASDataset::Identify( GDALOpenInfo * poOpenInfo )
238
if (poOpenInfo->nHeaderBytes == 0)
241
return EQUALN((const char*)poOpenInfo->pabyHeader,
242
"Format version: NOHRSC GIS/RS raster file v1.1",
243
strlen("Format version: NOHRSC GIS/RS raster file v1.1"));
246
/************************************************************************/
248
/************************************************************************/
250
GDALDataset *SNODASDataset::Open( GDALOpenInfo * poOpenInfo )
253
if( !Identify(poOpenInfo) )
258
fp = VSIFOpenL( poOpenInfo->pszFilename, "r" );
265
const char * pszLine;
266
int nRows = -1, nCols = -1;
267
CPLString osDataFilename;
268
int bIsInteger = FALSE, bIs2Bytes = FALSE;
270
int bHasNoData = FALSE;
275
double dfMinX = 0.0, dfMinY = 0.0, dfMaxX = 0.0, dfMaxY = 0.0;
276
int bHasMinX = FALSE, bHasMinY = FALSE, bHasMaxX = FALSE, bHasMaxY = FALSE;
277
int bNotProjected = FALSE, bIsWGS84 = FALSE;
278
CPLString osDescription, osDataUnits;
279
int nStartYear = -1, nStartMonth = -1, nStartDay = -1,
280
nStartHour = -1, nStartMinute = -1, nStartSecond = -1;
281
int nStopYear = -1, nStopMonth = -1, nStopDay = -1,
282
nStopHour = -1, nStopMinute = -1, nStopSecond = -1;
284
while( (pszLine = CPLReadLine2L( fp, 256, NULL )) != NULL )
286
char** papszTokens = CSLTokenizeStringComplex( pszLine, ":", TRUE, FALSE );
287
if( CSLCount( papszTokens ) != 2 )
289
CSLDestroy( papszTokens );
292
if( papszTokens[1][0] == ' ' )
293
memmove(papszTokens[1], papszTokens[1] + 1, strlen(papszTokens[1] + 1) + 1);
295
if( EQUAL(papszTokens[0],"Data file pathname") )
297
osDataFilename = papszTokens[1];
299
else if( EQUAL(papszTokens[0],"Description") )
301
osDescription = papszTokens[1];
303
else if( EQUAL(papszTokens[0],"Data units") )
305
osDataUnits= papszTokens[1];
308
else if( EQUAL(papszTokens[0],"Start year") )
309
nStartYear = atoi(papszTokens[1]);
310
else if( EQUAL(papszTokens[0],"Start month") )
311
nStartMonth = atoi(papszTokens[1]);
312
else if( EQUAL(papszTokens[0],"Start day") )
313
nStartDay = atoi(papszTokens[1]);
314
else if( EQUAL(papszTokens[0],"Start hour") )
315
nStartHour = atoi(papszTokens[1]);
316
else if( EQUAL(papszTokens[0],"Start minute") )
317
nStartMinute = atoi(papszTokens[1]);
318
else if( EQUAL(papszTokens[0],"Start second") )
319
nStartSecond = atoi(papszTokens[1]);
321
else if( EQUAL(papszTokens[0],"Stop year") )
322
nStopYear = atoi(papszTokens[1]);
323
else if( EQUAL(papszTokens[0],"Stop month") )
324
nStopMonth = atoi(papszTokens[1]);
325
else if( EQUAL(papszTokens[0],"Stop day") )
326
nStopDay = atoi(papszTokens[1]);
327
else if( EQUAL(papszTokens[0],"Stop hour") )
328
nStopHour = atoi(papszTokens[1]);
329
else if( EQUAL(papszTokens[0],"Stop minute") )
330
nStopMinute = atoi(papszTokens[1]);
331
else if( EQUAL(papszTokens[0],"Stop second") )
332
nStopSecond = atoi(papszTokens[1]);
334
else if( EQUAL(papszTokens[0],"Number of columns") )
336
nCols = atoi(papszTokens[1]);
338
else if( EQUAL(papszTokens[0],"Number of rows") )
340
nRows = atoi(papszTokens[1]);
342
else if( EQUAL(papszTokens[0],"Data type"))
344
bIsInteger = EQUAL(papszTokens[1],"integer");
346
else if( EQUAL(papszTokens[0],"Data bytes per pixel"))
348
bIs2Bytes = EQUAL(papszTokens[1],"2");
350
else if( EQUAL(papszTokens[0],"Projected"))
352
bNotProjected = EQUAL(papszTokens[1],"no");
354
else if( EQUAL(papszTokens[0],"Horizontal datum"))
356
bIsWGS84 = EQUAL(papszTokens[1],"WGS84");
358
else if( EQUAL(papszTokens[0],"No data value"))
361
dfNoData = CPLAtofM(papszTokens[1]);
363
else if( EQUAL(papszTokens[0],"Minimum data value"))
366
dfMin = CPLAtofM(papszTokens[1]);
368
else if( EQUAL(papszTokens[0],"Maximum data value"))
371
dfMax = CPLAtofM(papszTokens[1]);
373
else if( EQUAL(papszTokens[0],"Minimum x-axis coordinate") )
376
dfMinX = CPLAtofM(papszTokens[1]);
378
else if( EQUAL(papszTokens[0],"Minimum y-axis coordinate") )
381
dfMinY = CPLAtofM(papszTokens[1]);
383
else if( EQUAL(papszTokens[0],"Maximum x-axis coordinate") )
386
dfMaxX = CPLAtofM(papszTokens[1]);
388
else if( EQUAL(papszTokens[0],"Maximum y-axis coordinate") )
391
dfMaxY = CPLAtofM(papszTokens[1]);
394
CSLDestroy( papszTokens );
399
/* -------------------------------------------------------------------- */
400
/* Did we get the required keywords? If not we return with */
401
/* this never having been considered to be a match. This isn't */
403
/* -------------------------------------------------------------------- */
404
if( nRows == -1 || nCols == -1 || !bIsInteger || !bIs2Bytes )
407
if( !bNotProjected || !bIsWGS84 )
410
if( osDataFilename.size() == 0 )
413
if (!GDALCheckDatasetDimensions(nCols, nRows))
416
/* -------------------------------------------------------------------- */
417
/* Open target binary file. */
418
/* -------------------------------------------------------------------- */
419
const char* pszPath = CPLGetPath(poOpenInfo->pszFilename);
420
osDataFilename = CPLFormFilename(pszPath, osDataFilename, NULL);
422
VSILFILE* fpRaw = VSIFOpenL( osDataFilename, "rb" );
427
/* -------------------------------------------------------------------- */
428
/* Create a corresponding GDALDataset. */
429
/* -------------------------------------------------------------------- */
432
poDS = new SNODASDataset();
434
poDS->nRasterXSize = nCols;
435
poDS->nRasterYSize = nRows;
436
poDS->osDataFilename = osDataFilename;
437
poDS->bHasNoData = bHasNoData;
438
poDS->dfNoData = dfNoData;
439
poDS->bHasMin = bHasMin;
441
poDS->bHasMax = bHasMax;
443
if (bHasMinX && bHasMinY && bHasMaxX && bHasMaxY)
445
poDS->bGotTransform = TRUE;
446
poDS->adfGeoTransform[0] = dfMinX;
447
poDS->adfGeoTransform[1] = (dfMaxX - dfMinX) / nCols;
448
poDS->adfGeoTransform[2] = 0.0;
449
poDS->adfGeoTransform[3] = dfMaxY;
450
poDS->adfGeoTransform[4] = 0.0;
451
poDS->adfGeoTransform[5] = - (dfMaxY - dfMinY) / nRows;
454
if (osDescription.size())
455
poDS->SetMetadataItem("Description", osDescription);
456
if (osDataUnits.size())
457
poDS->SetMetadataItem("Data_Units", osDataUnits);
458
if (nStartYear != -1 && nStartMonth != -1 && nStartDay != -1 &&
459
nStartHour != -1 && nStartMinute != -1 && nStartSecond != -1)
460
poDS->SetMetadataItem("Start_Date",
461
CPLSPrintf("%04d/%02d/%02d %02d:%02d:%02d",
462
nStartYear, nStartMonth, nStartDay,
463
nStartHour, nStartMinute, nStartSecond));
464
if (nStopYear != -1 && nStopMonth != -1 && nStopDay != -1 &&
465
nStopHour != -1 && nStopMinute != -1 && nStopSecond != -1)
466
poDS->SetMetadataItem("Stop_Date",
467
CPLSPrintf("%04d/%02d/%02d %02d:%02d:%02d",
468
nStopYear, nStopMonth, nStopDay,
469
nStopHour, nStopMinute, nStopSecond));
471
/* -------------------------------------------------------------------- */
472
/* Create band information objects. */
473
/* -------------------------------------------------------------------- */
474
poDS->SetBand( 1, new SNODASRasterBand( fpRaw, nCols, nRows) );
476
/* -------------------------------------------------------------------- */
477
/* Initialize any PAM information. */
478
/* -------------------------------------------------------------------- */
479
poDS->SetDescription( poOpenInfo->pszFilename );
482
/* -------------------------------------------------------------------- */
483
/* Check for overviews. */
484
/* -------------------------------------------------------------------- */
485
poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
490
/************************************************************************/
491
/* GDALRegister_SNODAS() */
492
/************************************************************************/
494
void GDALRegister_SNODAS()
497
GDALDriver *poDriver;
499
if( GDALGetDriverByName( "SNODAS" ) == NULL )
501
poDriver = new GDALDriver();
503
poDriver->SetDescription( "SNODAS" );
504
poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
505
"Snow Data Assimilation System" );
506
poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
507
"frmt_various.html#SNODAS" );
508
poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "hdr" );
510
poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
511
poDriver->pfnOpen = SNODASDataset::Open;
512
poDriver->pfnIdentify = SNODASDataset::Identify;
514
GetGDALDriverManager()->RegisterDriver( poDriver );