1
/******************************************************************************
2
* $Id: hf2dataset.cpp 21680 2011-02-11 21:12:07Z warmerdam $
5
* Purpose: GDALDataset driver for HF2/HFZ dataset.
6
* Author: Even Rouault, <even dot rouault at mines dash paris dot org>
8
******************************************************************************
9
* Copyright (c) 2010, 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_string.h"
32
#include "ogr_spatialref.h"
34
CPL_CVSID("$Id: hf2dataset.cpp 21680 2011-02-11 21:12:07Z warmerdam $");
37
void GDALRegister_HF2(void);
40
/************************************************************************/
41
/* ==================================================================== */
43
/* ==================================================================== */
44
/************************************************************************/
48
class HF2Dataset : public GDALPamDataset
50
friend class HF2RasterBand;
53
double adfGeoTransform[6];
55
vsi_l_offset *panBlockOffset;
58
int bHasLoaderBlockMap;
63
virtual ~HF2Dataset();
65
virtual CPLErr GetGeoTransform( double * );
66
virtual const char* GetProjectionRef();
68
static GDALDataset *Open( GDALOpenInfo * );
69
static int Identify( GDALOpenInfo * );
70
static GDALDataset *CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
71
int bStrict, char ** papszOptions,
72
GDALProgressFunc pfnProgress, void * pProgressData );
75
/************************************************************************/
76
/* ==================================================================== */
78
/* ==================================================================== */
79
/************************************************************************/
81
class HF2RasterBand : public GDALPamRasterBand
83
friend class HF2Dataset;
90
HF2RasterBand( HF2Dataset *, int, GDALDataType );
93
virtual CPLErr IReadBlock( int, int, void * );
97
/************************************************************************/
99
/************************************************************************/
101
HF2RasterBand::HF2RasterBand( HF2Dataset *poDS, int nBand, GDALDataType eDT )
109
nBlockXSize = poDS->nTileSize;
116
/************************************************************************/
117
/* ~HF2RasterBand() */
118
/************************************************************************/
120
HF2RasterBand::~HF2RasterBand()
122
CPLFree(pafBlockData);
125
/************************************************************************/
127
/************************************************************************/
129
CPLErr HF2RasterBand::IReadBlock( int nBlockXOff, int nLineYOff,
133
HF2Dataset *poGDS = (HF2Dataset *) poDS;
135
int nXBlocks = (nRasterXSize + nBlockXSize - 1) / nBlockXSize;
136
int nYBlocks = (nRasterYSize + nBlockXSize - 1) / nBlockXSize;
138
if (!poGDS->LoadBlockMap())
141
if (pafBlockData == NULL)
143
pafBlockData = (float*)VSIMalloc3(nXBlocks * sizeof(float), poGDS->nTileSize, poGDS->nTileSize);
144
if (pafBlockData == NULL)
148
nLineYOff = nRasterYSize - 1 - nLineYOff;
150
int nBlockYOff = nLineYOff / nBlockXSize;
151
int nYOffInTile = nLineYOff % nBlockXSize;
153
if (nBlockYOff != nLastBlockYOff)
155
nLastBlockYOff = nBlockYOff;
157
memset(pafBlockData, 0, nXBlocks * sizeof(float) * nBlockXSize * nBlockXSize);
159
/* 4 * nBlockXSize is the upper bound */
160
void* pabyData = CPLMalloc( 4 * nBlockXSize );
163
for(nxoff = 0; nxoff < nXBlocks; nxoff++)
165
VSIFSeekL(poGDS->fp, poGDS->panBlockOffset[(nYBlocks - 1 - nBlockYOff) * nXBlocks + nxoff], SEEK_SET);
167
VSIFReadL(&fScale, 4, 1, poGDS->fp);
168
VSIFReadL(&fOff, 4, 1, poGDS->fp);
169
CPL_LSBPTR32(&fScale);
172
int nTileWidth = MIN(nBlockXSize, nRasterXSize - nxoff * nBlockXSize);
173
int nTileHeight = MIN(nBlockXSize, nRasterYSize - nBlockYOff * nBlockXSize);
176
for(j=0;j<nTileHeight;j++)
179
VSIFReadL(&nWordSize, 1, 1, poGDS->fp);
180
if (nWordSize != 1 && nWordSize != 2 && nWordSize != 4)
182
CPLError(CE_Failure, CPLE_AppDefined,
183
"Unexpected word size : %d", (int)nWordSize);
188
VSIFReadL(&nVal, 4, 1, poGDS->fp);
190
VSIFReadL(pabyData, nWordSize * (nTileWidth - 1), 1, poGDS->fp);
193
GDALSwapWords(pabyData, nWordSize, nTileWidth - 1, nWordSize);
196
pafBlockData[nxoff * nBlockXSize * nBlockXSize + j * nBlockXSize + 0] = nVal * fScale + fOff;
198
for(i=1;i<nTileWidth;i++)
201
nVal += ((char*)pabyData)[i-1];
202
else if (nWordSize == 2)
203
nVal += ((GInt16*)pabyData)[i-1];
205
nVal += ((GInt32*)pabyData)[i-1];
206
pafBlockData[nxoff * nBlockXSize * nBlockXSize + j * nBlockXSize + i] = nVal * fScale + fOff;
214
int nTileWidth = MIN(nBlockXSize, nRasterXSize - nBlockXOff * nBlockXSize);
215
memcpy(pImage, pafBlockData + nBlockXOff * nBlockXSize * nBlockXSize +
216
nYOffInTile * nBlockXSize,
217
nTileWidth * sizeof(float));
222
/************************************************************************/
224
/************************************************************************/
226
HF2Dataset::HF2Dataset()
230
panBlockOffset = NULL;
231
adfGeoTransform[0] = 0;
232
adfGeoTransform[1] = 1;
233
adfGeoTransform[2] = 0;
234
adfGeoTransform[3] = 0;
235
adfGeoTransform[4] = 0;
236
adfGeoTransform[5] = 1;
237
bHasLoaderBlockMap = FALSE;
241
/************************************************************************/
243
/************************************************************************/
245
HF2Dataset::~HF2Dataset()
250
CPLFree(panBlockOffset);
255
/************************************************************************/
257
/************************************************************************/
259
int HF2Dataset::LoadBlockMap()
261
if (bHasLoaderBlockMap)
262
return panBlockOffset != NULL;
264
bHasLoaderBlockMap = TRUE;
266
int nXBlocks = (nRasterXSize + nTileSize - 1) / nTileSize;
267
int nYBlocks = (nRasterYSize + nTileSize - 1) / nTileSize;
268
panBlockOffset = (vsi_l_offset*) VSIMalloc3(sizeof(vsi_l_offset), nXBlocks, nYBlocks);
269
if (panBlockOffset == NULL)
274
for(j = 0; j < nYBlocks; j++)
276
for(i = 0; i < nXBlocks; i++)
278
vsi_l_offset nOff = VSIFTellL(fp);
279
panBlockOffset[(nYBlocks - 1 - j) * nXBlocks + i] = nOff;
280
//VSIFSeekL(fp, 4 + 4, SEEK_CUR);
282
VSIFReadL(&fScale, 4, 1, fp);
283
VSIFReadL(&fOff, 4, 1, fp);
284
CPL_LSBPTR32(&fScale);
286
//printf("fScale = %f, fOff = %f\n", fScale, fOff);
288
int nCols = MIN(nTileSize, nRasterXSize - nTileSize *i);
289
int nLines = MIN(nTileSize, nRasterYSize - nTileSize *j);
290
for(k = 0; k < nLines; k++)
293
VSIFReadL(&nWordSize, 1, 1, fp);
294
//printf("nWordSize=%d\n", nWordSize);
295
if (nWordSize == 1 || nWordSize == 2 || nWordSize == 4)
296
VSIFSeekL(fp, 4 + nWordSize * (nCols - 1), SEEK_CUR);
299
CPLError(CE_Failure, CPLE_AppDefined,
300
"Got unexpected byte depth (%d) for block (%d, %d) line %d",
301
(int)nWordSize, i, j, k);
302
VSIFree(panBlockOffset);
303
panBlockOffset = NULL;
313
/************************************************************************/
314
/* GetProjectionRef() */
315
/************************************************************************/
317
const char* HF2Dataset::GetProjectionRef()
321
return GDALPamDataset::GetProjectionRef();
324
/************************************************************************/
326
/************************************************************************/
328
int HF2Dataset::Identify( GDALOpenInfo * poOpenInfo)
331
GDALOpenInfo* poOpenInfoToDelete = NULL;
332
/* GZipped .hf2 files are common, so automagically open them */
333
/* if the /vsigzip/ has not been explicitely passed */
334
CPLString osFilename(poOpenInfo->pszFilename);
335
if ((EQUAL(CPLGetExtension(poOpenInfo->pszFilename), "hfz") ||
336
(strlen(poOpenInfo->pszFilename) > 6 &&
337
EQUAL(poOpenInfo->pszFilename + strlen(poOpenInfo->pszFilename) - 6, "hf2.gz"))) &&
338
!EQUALN(poOpenInfo->pszFilename, "/vsigzip/", 9))
340
osFilename = "/vsigzip/";
341
osFilename += poOpenInfo->pszFilename;
342
poOpenInfo = poOpenInfoToDelete =
343
new GDALOpenInfo(osFilename.c_str(), GA_ReadOnly,
344
poOpenInfo->papszSiblingFiles);
347
if (poOpenInfo->nHeaderBytes < 28)
349
delete poOpenInfoToDelete;
353
if (memcmp(poOpenInfo->pabyHeader, "HF2\0\0\0\0", 6) != 0)
355
delete poOpenInfoToDelete;
359
delete poOpenInfoToDelete;
363
/************************************************************************/
365
/************************************************************************/
367
GDALDataset *HF2Dataset::Open( GDALOpenInfo * poOpenInfo )
370
CPLString osOriginalFilename(poOpenInfo->pszFilename);
372
if (!Identify(poOpenInfo))
375
GDALOpenInfo* poOpenInfoToDelete = NULL;
376
/* GZipped .hf2 files are common, so automagically open them */
377
/* if the /vsigzip/ has not been explicitely passed */
378
CPLString osFilename(poOpenInfo->pszFilename);
379
if ((EQUAL(CPLGetExtension(poOpenInfo->pszFilename), "hfz") ||
380
(strlen(poOpenInfo->pszFilename) > 6 &&
381
EQUAL(poOpenInfo->pszFilename + strlen(poOpenInfo->pszFilename) - 6, "hf2.gz"))) &&
382
!EQUALN(poOpenInfo->pszFilename, "/vsigzip/", 9))
384
osFilename = "/vsigzip/";
385
osFilename += poOpenInfo->pszFilename;
386
poOpenInfo = poOpenInfoToDelete =
387
new GDALOpenInfo(osFilename.c_str(), GA_ReadOnly,
388
poOpenInfo->papszSiblingFiles);
391
/* -------------------------------------------------------------------- */
393
/* -------------------------------------------------------------------- */
396
memcpy(&nXSize, poOpenInfo->pabyHeader + 6, 4);
397
CPL_LSBPTR32(&nXSize);
398
memcpy(&nYSize, poOpenInfo->pabyHeader + 10, 4);
399
CPL_LSBPTR32(&nYSize);
402
memcpy(&nTileSize, poOpenInfo->pabyHeader + 14, 2);
403
CPL_LSBPTR16(&nTileSize);
405
float fVertPres, fHorizScale;
406
memcpy(&fVertPres, poOpenInfo->pabyHeader + 16, 4);
407
CPL_LSBPTR32(&fVertPres);
408
memcpy(&fHorizScale, poOpenInfo->pabyHeader + 20, 4);
409
CPL_LSBPTR32(&fHorizScale);
411
GUInt32 nExtendedHeaderLen;
412
memcpy(&nExtendedHeaderLen, poOpenInfo->pabyHeader + 24, 4);
413
CPL_LSBPTR32(&nExtendedHeaderLen);
415
delete poOpenInfoToDelete;
416
poOpenInfoToDelete = NULL;
420
if (nXSize <= 0 || nXSize > INT_MAX - nTileSize ||
421
nYSize <= 0 || nYSize > INT_MAX - nTileSize)
423
/* To avoid later potential int overflows */
424
if (nExtendedHeaderLen > 1024 * 65536)
427
if (!GDALCheckDatasetDimensions(nXSize, nYSize))
432
/* -------------------------------------------------------------------- */
433
/* Parse extended blocks */
434
/* -------------------------------------------------------------------- */
436
VSILFILE* fp = VSIFOpenL(osFilename.c_str(), "rb");
440
VSIFSeekL(fp, 28, SEEK_SET);
442
int bHasExtent = FALSE;
443
double dfMinX = 0, dfMaxX = 0, dfMinY = 0, dfMaxY = 0;
444
int bHasUTMZone = FALSE;
446
int bHasEPSGDatumCode = FALSE;
447
GInt16 nEPSGDatumCode = 0;
448
int bHasEPSGCode = FALSE;
449
GInt16 nEPSGCode = 0;
450
int bHasRelativePrecision = FALSE;
451
float fRelativePrecision = 0;
452
char szApplicationName[256];
453
szApplicationName[0] = 0;
455
GUInt32 nExtendedHeaderOff = 0;
456
while(nExtendedHeaderOff < nExtendedHeaderLen)
458
char pabyBlockHeader[24];
459
VSIFReadL(pabyBlockHeader, 24, 1, fp);
461
char szBlockName[16 + 1];
462
memcpy(szBlockName, pabyBlockHeader + 4, 16);
465
memcpy(&nBlockSize, pabyBlockHeader + 20, 4);
466
CPL_LSBPTR32(&nBlockSize);
467
if (nBlockSize > 65536)
470
nExtendedHeaderOff += 24 + nBlockSize;
472
if (strcmp(szBlockName, "georef-extents") == 0 &&
475
char pabyBlockData[34];
476
VSIFReadL(pabyBlockData, 34, 1, fp);
478
memcpy(&dfMinX, pabyBlockData + 2, 8);
479
CPL_LSBPTR64(&dfMinX);
480
memcpy(&dfMaxX, pabyBlockData + 2 + 8, 8);
481
CPL_LSBPTR64(&dfMaxX);
482
memcpy(&dfMinY, pabyBlockData + 2 + 8 + 8, 8);
483
CPL_LSBPTR64(&dfMinY);
484
memcpy(&dfMaxY, pabyBlockData + 2 + 8 + 8 + 8, 8);
485
CPL_LSBPTR64(&dfMaxY);
489
else if (strcmp(szBlockName, "georef-utm") == 0 &&
492
VSIFReadL(&nUTMZone, 2, 1, fp);
493
CPL_LSBPTR16(&nUTMZone);
494
CPLDebug("HF2", "UTM Zone = %d", nUTMZone);
498
else if (strcmp(szBlockName, "georef-datum") == 0 &&
501
VSIFReadL(&nEPSGDatumCode, 2, 1, fp);
502
CPL_LSBPTR16(&nEPSGDatumCode);
503
CPLDebug("HF2", "EPSG Datum Code = %d", nEPSGDatumCode);
505
bHasEPSGDatumCode = TRUE;
507
else if (strcmp(szBlockName, "georef-epsg-prj") == 0 &&
510
VSIFReadL(&nEPSGCode, 2, 1, fp);
511
CPL_LSBPTR16(&nEPSGCode);
512
CPLDebug("HF2", "EPSG Code = %d", nEPSGCode);
516
else if (strcmp(szBlockName, "precis-rel") == 0 &&
519
VSIFReadL(&fRelativePrecision, 4, 1, fp);
520
CPL_LSBPTR32(&fRelativePrecision);
522
bHasRelativePrecision = TRUE;
524
else if (strcmp(szBlockName, "app-name") == 0 &&
527
VSIFReadL(szApplicationName, nBlockSize, 1, fp);
528
szApplicationName[nBlockSize] = 0;
532
CPLDebug("HF2", "Skipping block %s", szBlockName);
533
VSIFSeekL(fp, nBlockSize, SEEK_CUR);
537
/* -------------------------------------------------------------------- */
538
/* Create a corresponding GDALDataset. */
539
/* -------------------------------------------------------------------- */
542
poDS = new HF2Dataset();
544
poDS->nRasterXSize = nXSize;
545
poDS->nRasterYSize = nYSize;
546
poDS->nTileSize = nTileSize;
547
CPLDebug("HF2", "nXSize = %d, nYSize = %d, nTileSize = %d", nXSize, nYSize, nTileSize);
550
poDS->adfGeoTransform[0] = dfMinX;
551
poDS->adfGeoTransform[3] = dfMaxY;
552
poDS->adfGeoTransform[1] = (dfMaxX - dfMinX) / nXSize;
553
poDS->adfGeoTransform[5] = -(dfMaxY - dfMinY) / nYSize;
557
poDS->adfGeoTransform[1] = fHorizScale;
558
poDS->adfGeoTransform[5] = fHorizScale;
563
OGRSpatialReference oSRS;
564
if (oSRS.importFromEPSG(nEPSGCode) == OGRERR_NONE)
565
oSRS.exportToWkt(&poDS->pszWKT);
570
OGRSpatialReference oSRS;
571
oSRS.SetGeogCS("unknown", "unknown", "unknown", SRS_WGS84_SEMIMAJOR, SRS_WGS84_INVFLATTENING);
572
if (bHasEPSGDatumCode)
574
if (nEPSGDatumCode == 23 || nEPSGDatumCode == 6326)
577
oSRS.SetWellKnownGeogCS("WGS84");
579
else if (nEPSGDatumCode >= 6000)
582
sprintf( szName, "EPSG:%d", nEPSGDatumCode-2000 );
583
oSRS.SetWellKnownGeogCS( szName );
588
if (bHasUTMZone && ABS(nUTMZone) >= 1 && ABS(nUTMZone) <= 60)
591
oSRS.SetUTM(ABS(nUTMZone), nUTMZone > 0);
594
oSRS.exportToWkt(&poDS->pszWKT);
597
/* -------------------------------------------------------------------- */
598
/* Create band information objects. */
599
/* -------------------------------------------------------------------- */
602
for( i = 0; i < poDS->nBands; i++ )
604
poDS->SetBand( i+1, new HF2RasterBand( poDS, i+1, GDT_Float32 ) );
605
poDS->GetRasterBand(i+1)->SetUnitType("m");
608
if (szApplicationName[0] != '\0')
609
poDS->SetMetadataItem("APPLICATION_NAME", szApplicationName);
610
poDS->SetMetadataItem("VERTICAL_PRECISION", CPLString().Printf("%f", fVertPres));
611
if (bHasRelativePrecision)
612
poDS->SetMetadataItem("RELATIVE_VERTICAL_PRECISION", CPLString().Printf("%f", fRelativePrecision));
614
/* -------------------------------------------------------------------- */
615
/* Initialize any PAM information. */
616
/* -------------------------------------------------------------------- */
617
poDS->SetDescription( osOriginalFilename.c_str() );
620
/* -------------------------------------------------------------------- */
621
/* Support overviews. */
622
/* -------------------------------------------------------------------- */
623
poDS->oOvManager.Initialize( poDS, osOriginalFilename.c_str() );
627
/************************************************************************/
628
/* GetGeoTransform() */
629
/************************************************************************/
631
CPLErr HF2Dataset::GetGeoTransform( double * padfTransform )
634
memcpy(padfTransform, adfGeoTransform, 6 * sizeof(double));
640
static void WriteShort(VSILFILE* fp, GInt16 val)
643
VSIFWriteL(&val, 2, 1, fp);
646
static void WriteInt(VSILFILE* fp, GInt32 val)
649
VSIFWriteL(&val, 4, 1, fp);
652
static void WriteFloat(VSILFILE* fp, float val)
655
VSIFWriteL(&val, 4, 1, fp);
658
static void WriteDouble(VSILFILE* fp, double val)
661
VSIFWriteL(&val, 8, 1, fp);
664
/************************************************************************/
666
/************************************************************************/
668
GDALDataset* HF2Dataset::CreateCopy( const char * pszFilename,
669
GDALDataset *poSrcDS,
670
int bStrict, char ** papszOptions,
671
GDALProgressFunc pfnProgress,
672
void * pProgressData )
674
/* -------------------------------------------------------------------- */
675
/* Some some rudimentary checks */
676
/* -------------------------------------------------------------------- */
677
int nBands = poSrcDS->GetRasterCount();
680
CPLError( CE_Failure, CPLE_NotSupported,
681
"HF2 driver does not support source dataset with zero band.\n");
687
CPLError( (bStrict) ? CE_Failure : CE_Warning, CPLE_NotSupported,
688
"HF2 driver only uses the first band of the dataset.\n");
693
if( pfnProgress && !pfnProgress( 0.0, NULL, pProgressData ) )
696
/* -------------------------------------------------------------------- */
697
/* Get source dataset info */
698
/* -------------------------------------------------------------------- */
700
int nXSize = poSrcDS->GetRasterXSize();
701
int nYSize = poSrcDS->GetRasterYSize();
702
double adfGeoTransform[6];
703
poSrcDS->GetGeoTransform(adfGeoTransform);
704
int bHasGeoTransform = !(adfGeoTransform[0] == 0 &&
705
adfGeoTransform[1] == 1 &&
706
adfGeoTransform[2] == 0 &&
707
adfGeoTransform[3] == 0 &&
708
adfGeoTransform[4] == 0 &&
709
adfGeoTransform[5] == 1);
710
if (adfGeoTransform[2] != 0 || adfGeoTransform[4] != 0)
712
CPLError( CE_Failure, CPLE_NotSupported,
713
"HF2 driver does not support CreateCopy() from skewed or rotated dataset.\n");
717
GDALDataType eSrcDT = poSrcDS->GetRasterBand(1)->GetRasterDataType();
719
float fVertPres = (float) 0.01;
720
if (eSrcDT == GDT_Byte || eSrcDT == GDT_Int16)
726
eReqDT = GDT_Float32;
728
/* -------------------------------------------------------------------- */
729
/* Read creation options */
730
/* -------------------------------------------------------------------- */
731
const char* pszCompressed = CSLFetchNameValue(papszOptions, "COMPRESS");
732
int bCompress = FALSE;
734
bCompress = CSLTestBoolean(pszCompressed);
736
const char* pszVerticalPrecision = CSLFetchNameValue(papszOptions, "VERTICAL_PRECISION");
737
if (pszVerticalPrecision)
739
fVertPres = (float) CPLAtofM(pszVerticalPrecision);
742
CPLError(CE_Warning, CPLE_AppDefined,
743
"Unsupported value for VERTICAL_PRECISION. Defaulting to 0.01");
744
fVertPres = (float) 0.01;
746
if (eReqDT == GDT_Int16 && fVertPres > 1)
747
eReqDT = GDT_Float32;
750
const char* pszBlockSize = CSLFetchNameValue(papszOptions, "BLOCKSIZE");
754
nTileSize = atoi(pszBlockSize);
755
if (nTileSize < 8 || nTileSize > 4096)
757
CPLError(CE_Warning, CPLE_AppDefined,
758
"Unsupported value for BLOCKSIZE. Defaulting to 256");
763
/* -------------------------------------------------------------------- */
764
/* Parse source dataset georeferencing info */
765
/* -------------------------------------------------------------------- */
767
int nExtendedHeaderLen = 0;
768
if (bHasGeoTransform)
769
nExtendedHeaderLen += 58;
770
const char* pszProjectionRef = poSrcDS->GetProjectionRef();
775
int nExtentUnits = 1;
776
if (pszProjectionRef != NULL && pszProjectionRef[0] != '\0')
778
OGRSpatialReference oSRS;
779
char* pszTemp = (char*) pszProjectionRef;
780
if (oSRS.importFromWkt(&pszTemp) == OGRERR_NONE)
782
const char* pszValue = NULL;
783
if( oSRS.GetAuthorityName( "GEOGCS|DATUM" ) != NULL
784
&& EQUAL(oSRS.GetAuthorityName( "GEOGCS|DATUM" ),"EPSG") )
785
nDatumCode = atoi(oSRS.GetAuthorityCode( "GEOGCS|DATUM" ));
786
else if ((pszValue = oSRS.GetAttrValue("GEOGCS|DATUM")) != NULL)
788
if (strstr(pszValue, "WGS") && strstr(pszValue, "84"))
792
nUTMZone = oSRS.GetUTMZone(&bNorth);
794
if( oSRS.GetAuthorityName( "PROJCS" ) != NULL
795
&& EQUAL(oSRS.GetAuthorityName( "PROJCS" ),"EPSG") )
796
nEPSGCode = atoi(oSRS.GetAuthorityCode( "PROJCS" ));
798
if( oSRS.IsGeographic() )
804
double dfLinear = oSRS.GetLinearUnits();
806
if( ABS(dfLinear - 0.3048) < 0.0000001 )
808
else if( ABS(dfLinear - atof(SRS_UL_US_FOOT_CONV)) < 0.00000001 )
814
if (nDatumCode != -2)
815
nExtendedHeaderLen += 26;
817
nExtendedHeaderLen += 26;
819
nExtendedHeaderLen += 26;
821
/* -------------------------------------------------------------------- */
822
/* Create target file */
823
/* -------------------------------------------------------------------- */
825
CPLString osFilename;
828
osFilename = "/vsigzip/";
829
osFilename += pszFilename;
832
osFilename = pszFilename;
833
VSILFILE* fp = VSIFOpenL(osFilename.c_str(), "wb");
836
CPLError( CE_Failure, CPLE_AppDefined,
837
"Cannot create %s", pszFilename );
841
/* -------------------------------------------------------------------- */
843
/* -------------------------------------------------------------------- */
845
VSIFWriteL("HF2\0", 4, 1, fp);
847
WriteInt(fp, nXSize);
848
WriteInt(fp, nYSize);
849
WriteShort(fp, (GInt16) nTileSize);
850
WriteFloat(fp, fVertPres);
851
float fHorizScale = (float) ((fabs(adfGeoTransform[1]) + fabs(adfGeoTransform[5])) / 2);
852
WriteFloat(fp, fHorizScale);
853
WriteInt(fp, nExtendedHeaderLen);
855
/* -------------------------------------------------------------------- */
856
/* Write extended header */
857
/* -------------------------------------------------------------------- */
859
char szBlockName[16 + 1];
860
if (bHasGeoTransform)
862
VSIFWriteL("bin\0", 4, 1, fp);
863
memset(szBlockName, 0, 16 + 1);
864
strcpy(szBlockName, "georef-extents");
865
VSIFWriteL(szBlockName, 16, 1, fp);
867
WriteShort(fp, (GInt16) nExtentUnits);
868
WriteDouble(fp, adfGeoTransform[0]);
869
WriteDouble(fp, adfGeoTransform[0] + nXSize * adfGeoTransform[1]);
870
WriteDouble(fp, adfGeoTransform[3] + nYSize * adfGeoTransform[5]);
871
WriteDouble(fp, adfGeoTransform[3]);
875
VSIFWriteL("bin\0", 4, 1, fp);
876
memset(szBlockName, 0, 16 + 1);
877
strcpy(szBlockName, "georef-utm");
878
VSIFWriteL(szBlockName, 16, 1, fp);
880
WriteShort(fp, (GInt16) ((bNorth) ? nUTMZone : -nUTMZone));
882
if (nDatumCode != -2)
884
VSIFWriteL("bin\0", 4, 1, fp);
885
memset(szBlockName, 0, 16 + 1);
886
strcpy(szBlockName, "georef-datum");
887
VSIFWriteL(szBlockName, 16, 1, fp);
889
WriteShort(fp, (GInt16) nDatumCode);
893
VSIFWriteL("bin\0", 4, 1, fp);
894
memset(szBlockName, 0, 16 + 1);
895
strcpy(szBlockName, "georef-epsg-prj");
896
VSIFWriteL(szBlockName, 16, 1, fp);
898
WriteShort(fp, (GInt16) nEPSGCode);
901
/* -------------------------------------------------------------------- */
903
/* -------------------------------------------------------------------- */
904
int nXBlocks = (nXSize + nTileSize - 1) / nTileSize;
905
int nYBlocks = (nYSize + nTileSize - 1) / nTileSize;
907
void* pTileBuffer = (void*) VSIMalloc(nTileSize * nTileSize * (GDALGetDataTypeSize(eReqDT) / 8));
908
if (pTileBuffer == NULL)
910
CPLError( CE_Failure, CPLE_OutOfMemory, "Out of memory");
916
CPLErr eErr = CE_None;
917
for(j=0;j<nYBlocks && eErr == CE_None;j++)
919
for(i=0;i<nXBlocks && eErr == CE_None;i++)
921
int nReqXSize = MIN(nTileSize, nXSize - i * nTileSize);
922
int nReqYSize = MIN(nTileSize, nYSize - j * nTileSize);
923
eErr = poSrcDS->GetRasterBand(1)->RasterIO(GF_Read,
924
i * nTileSize, MAX(0, nYSize - (j + 1) * nTileSize),
925
nReqXSize, nReqYSize,
926
pTileBuffer, nReqXSize, nReqYSize,
931
if (eReqDT == GDT_Int16)
933
WriteFloat(fp, 1); /* scale */
934
WriteFloat(fp, 0); /* offset */
935
for(k=0;k<nReqYSize;k++)
937
int nLastVal = ((short*)pTileBuffer)[(nReqYSize - k - 1) * nReqXSize + 0];
939
for(l=1;l<nReqXSize;l++)
941
int nVal = ((short*)pTileBuffer)[(nReqYSize - k - 1) * nReqXSize + l];
942
int nDiff = nVal - nLastVal;
943
if (nDiff < -32768 || nDiff > 32767)
948
if (nDiff < -128 || nDiff > 127)
953
VSIFWriteL(&nWordSize, 1, 1, fp);
954
nLastVal = ((short*)pTileBuffer)[(nReqYSize - k - 1) * nReqXSize + 0];
955
WriteInt(fp, nLastVal);
956
for(l=1;l<nReqXSize;l++)
958
int nVal = ((short*)pTileBuffer)[(nReqYSize - k - 1) * nReqXSize + l];
959
int nDiff = nVal - nLastVal;
962
CPLAssert(nDiff >= -128 && nDiff <= 127);
963
char chDiff = (char)nDiff;
964
VSIFWriteL(&chDiff, 1, 1, fp);
966
else if (nWordSize == 2)
968
CPLAssert(nDiff >= -32768 && nDiff <= 32767);
969
WriteShort(fp, (short)nDiff);
981
float fMinVal = ((float*)pTileBuffer)[0];
982
float fMaxVal = fMinVal;
983
for(k=1;k<nReqYSize*nReqXSize;k++)
985
float fVal = ((float*)pTileBuffer)[k];
986
if (fVal < fMinVal) fMinVal = fVal;
987
if (fVal > fMaxVal) fMaxVal = fVal;
990
float fIntRange = (fMaxVal - fMinVal) / fVertPres;
991
float fScale = (fMinVal == fMaxVal) ? 1 : (fMaxVal - fMinVal) / fIntRange;
992
float fOffset = fMinVal;
993
WriteFloat(fp, fScale); /* scale */
994
WriteFloat(fp, fOffset); /* offset */
995
for(k=0;k<nReqYSize;k++)
997
float fLastVal = ((float*)pTileBuffer)[(nReqYSize - k - 1) * nReqXSize + 0];
998
float fIntLastVal = (fLastVal - fOffset) / fScale;
999
CPLAssert(fIntLastVal >= -2147483648.0f && fIntLastVal <= 2147483647.0f);
1000
int nLastVal = (int)fIntLastVal;
1001
GByte nWordSize = 1;
1002
for(l=1;l<nReqXSize;l++)
1004
float fVal = ((float*)pTileBuffer)[(nReqYSize - k - 1) * nReqXSize + l];
1005
float fIntVal = (fVal - fOffset) / fScale;
1006
CPLAssert(fIntVal >= -2147483648.0f && fIntVal <= 2147483647.0f);
1007
int nVal = (int)fIntVal;
1008
int nDiff = nVal - nLastVal;
1009
CPLAssert((int)((GIntBig)nVal - nLastVal) == nDiff);
1010
if (nDiff < -32768 || nDiff > 32767)
1015
if (nDiff < -128 || nDiff > 127)
1020
VSIFWriteL(&nWordSize, 1, 1, fp);
1021
fLastVal = ((float*)pTileBuffer)[(nReqYSize - k - 1) * nReqXSize + 0];
1022
fIntLastVal = (fLastVal - fOffset) / fScale;
1023
nLastVal = (int)fIntLastVal;
1024
WriteInt(fp, nLastVal);
1025
for(l=1;l<nReqXSize;l++)
1027
float fVal = ((float*)pTileBuffer)[(nReqYSize - k - 1) * nReqXSize + l];
1028
float fIntVal = (fVal - fOffset) / fScale;
1029
int nVal = (int)fIntVal;
1030
int nDiff = nVal - nLastVal;
1031
CPLAssert((int)((GIntBig)nVal - nLastVal) == nDiff);
1034
CPLAssert(nDiff >= -128 && nDiff <= 127);
1035
char chDiff = (char)nDiff;
1036
VSIFWriteL(&chDiff, 1, 1, fp);
1038
else if (nWordSize == 2)
1040
CPLAssert(nDiff >= -32768 && nDiff <= 32767);
1041
WriteShort(fp, (short)nDiff);
1045
WriteInt(fp, nDiff);
1052
if( pfnProgress && !pfnProgress( (j * nXBlocks + i + 1) * 1.0 / (nXBlocks * nYBlocks), NULL, pProgressData ) )
1060
CPLFree(pTileBuffer);
1064
return (GDALDataset*) GDALOpen(osFilename.c_str(), GA_ReadOnly);
1067
/************************************************************************/
1068
/* GDALRegister_HF2() */
1069
/************************************************************************/
1071
void GDALRegister_HF2()
1074
GDALDriver *poDriver;
1076
if( GDALGetDriverByName( "HF2" ) == NULL )
1078
poDriver = new GDALDriver();
1080
poDriver->SetDescription( "HF2" );
1081
poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
1082
"HF2/HFZ heightfield raster" );
1083
poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
1085
poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "hf2" );
1086
poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
1087
"<CreationOptionList>"
1088
" <Option name='VERTICAL_PRECISION' type='float' default='0.01' description='Vertical precision.'/>"
1089
" <Option name='COMPRESS' type='boolean' default='false' description='Set to true to produce a GZip compressed file.'/>"
1090
" <Option name='BLOCKSIZE' type='int' default='256' description='Tile size.'/>"
1091
"</CreationOptionList>");
1093
poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
1095
poDriver->pfnOpen = HF2Dataset::Open;
1096
poDriver->pfnIdentify = HF2Dataset::Identify;
1097
poDriver->pfnCreateCopy = HF2Dataset::CreateCopy;
1099
GetGDALDriverManager()->RegisterDriver( poDriver );