ultimatepp/bazaar/plugin/gdal/frmts/zmap/zmapdataset.cpp
cxl 23ff1e7e82 .gdal moved to bazaar
git-svn-id: svn://ultimatepp.org/upp/trunk@9273 f0d560ea-af0d-0410-9eb7-867de7ffcac7
2015-12-07 13:36:24 +00:00

726 lines
23 KiB
C++

/******************************************************************************
* $Id: zmapdataset.cpp 28053 2014-12-04 09:31:07Z rouault $
*
* Project: ZMap driver
* Purpose: GDALDataset driver for ZMap dataset.
* Author: Even Rouault, <even dot rouault at mines dash paris dot org>
*
******************************************************************************
* Copyright (c) 2011-2012, Even Rouault <even dot rouault at mines-paris dot org>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
****************************************************************************/
#include "cpl_vsi_virtual.h"
#include "cpl_string.h"
#include "gdal_pam.h"
CPL_CVSID("$Id: zmapdataset.cpp 28053 2014-12-04 09:31:07Z rouault $");
CPL_C_START
void GDALRegister_ZMap(void);
CPL_C_END
/************************************************************************/
/* ==================================================================== */
/* ZMapDataset */
/* ==================================================================== */
/************************************************************************/
class ZMapRasterBand;
class ZMapDataset : public GDALPamDataset
{
friend class ZMapRasterBand;
VSILFILE *fp;
int nValuesPerLine;
int nFieldSize;
int nDecimalCount;
int nColNum;
double dfNoDataValue;
vsi_l_offset nDataStartOff;
double adfGeoTransform[6];
public:
ZMapDataset();
virtual ~ZMapDataset();
virtual CPLErr GetGeoTransform( double * );
static GDALDataset *Open( GDALOpenInfo * );
static int Identify( GDALOpenInfo * );
static GDALDataset *CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
int bStrict, char ** papszOptions,
GDALProgressFunc pfnProgress, void * pProgressData );
};
/************************************************************************/
/* ==================================================================== */
/* ZMapRasterBand */
/* ==================================================================== */
/************************************************************************/
class ZMapRasterBand : public GDALPamRasterBand
{
friend class ZMapDataset;
public:
ZMapRasterBand( ZMapDataset * );
virtual CPLErr IReadBlock( int, int, void * );
virtual double GetNoDataValue( int *pbSuccess = NULL );
};
/************************************************************************/
/* ZMapRasterBand() */
/************************************************************************/
ZMapRasterBand::ZMapRasterBand( ZMapDataset *poDS )
{
this->poDS = poDS;
this->nBand = nBand;
eDataType = GDT_Float64;
nBlockXSize = 1;
nBlockYSize = poDS->GetRasterYSize();
}
/************************************************************************/
/* IReadBlock() */
/************************************************************************/
CPLErr ZMapRasterBand::IReadBlock( int nBlockXOff,
CPL_UNUSED int nBlockYOff,
void * pImage )
{
int i;
ZMapDataset *poGDS = (ZMapDataset *) poDS;
if (poGDS->fp == NULL)
return CE_Failure;
if (nBlockXOff < poGDS->nColNum + 1)
{
VSIFSeekL(poGDS->fp, poGDS->nDataStartOff, SEEK_SET);
poGDS->nColNum = -1;
}
if (nBlockXOff > poGDS->nColNum + 1)
{
for(i=poGDS->nColNum + 1;i<nBlockXOff;i++)
{
if (IReadBlock(i,0,pImage) != CE_None)
return CE_Failure;
}
}
char* pszLine;
i = 0;
double dfExp = pow(10.0, poGDS->nDecimalCount);
while(i<nRasterYSize)
{
pszLine = (char*)CPLReadLineL(poGDS->fp);
if (pszLine == NULL)
return CE_Failure;
int nExpected = nRasterYSize - i;
if (nExpected > poGDS->nValuesPerLine)
nExpected = poGDS->nValuesPerLine;
if ((int)strlen(pszLine) != nExpected * poGDS->nFieldSize)
return CE_Failure;
for(int j=0;j<nExpected;j++)
{
char* pszValue = pszLine + j * poGDS->nFieldSize;
char chSaved = pszValue[poGDS->nFieldSize];
pszValue[poGDS->nFieldSize] = 0;
if (strchr(pszValue, '.') != NULL)
((double*)pImage)[i+j] = CPLAtofM(pszValue);
else
((double*)pImage)[i+j] = atoi(pszValue) * dfExp;
pszValue[poGDS->nFieldSize] = chSaved;
}
i += nExpected;
}
poGDS->nColNum ++;
return CE_None;
}
/************************************************************************/
/* GetNoDataValue() */
/************************************************************************/
double ZMapRasterBand::GetNoDataValue( int *pbSuccess )
{
ZMapDataset *poGDS = (ZMapDataset *) poDS;
if (pbSuccess)
*pbSuccess = TRUE;
return poGDS->dfNoDataValue;
}
/************************************************************************/
/* ~ZMapDataset() */
/************************************************************************/
ZMapDataset::ZMapDataset()
{
fp = NULL;
nDataStartOff = 0;
nColNum = -1;
nValuesPerLine = 0;
nFieldSize = 0;
nDecimalCount = 0;
dfNoDataValue = 0.0;
adfGeoTransform[0] = 0;
adfGeoTransform[1] = 1;
adfGeoTransform[2] = 0;
adfGeoTransform[3] = 0;
adfGeoTransform[4] = 0;
adfGeoTransform[5] = 1;
}
/************************************************************************/
/* ~ZMapDataset() */
/************************************************************************/
ZMapDataset::~ZMapDataset()
{
FlushCache();
if (fp)
VSIFCloseL(fp);
}
/************************************************************************/
/* Identify() */
/************************************************************************/
int ZMapDataset::Identify( GDALOpenInfo * poOpenInfo )
{
int i;
if (poOpenInfo->nHeaderBytes == 0)
return FALSE;
/* -------------------------------------------------------------------- */
/* Chech that it looks roughly as a ZMap dataset */
/* -------------------------------------------------------------------- */
const char* pszData = (const char*)poOpenInfo->pabyHeader;
/* Skip comments line at the beginning */
i=0;
if (pszData[i] == '!')
{
i++;
for(;i<poOpenInfo->nHeaderBytes;i++)
{
char ch = pszData[i];
if (ch == 13 || ch == 10)
{
i++;
if (ch == 13 && pszData[i] == 10)
i++;
if (pszData[i] != '!')
break;
}
}
}
if (pszData[i] != '@')
return FALSE;
i++;
char** papszTokens = CSLTokenizeString2( pszData+i, ",", 0 );
if (CSLCount(papszTokens) < 3)
{
CSLDestroy(papszTokens);
return FALSE;
}
const char* pszToken = papszTokens[1];
while (*pszToken == ' ')
pszToken ++;
if (strncmp(pszToken, "GRID", 4) != 0)
{
CSLDestroy(papszTokens);
return FALSE;
}
CSLDestroy(papszTokens);
return TRUE;
}
/************************************************************************/
/* Open() */
/************************************************************************/
GDALDataset *ZMapDataset::Open( GDALOpenInfo * poOpenInfo )
{
if (!Identify(poOpenInfo))
return NULL;
/* -------------------------------------------------------------------- */
/* Find dataset characteristics */
/* -------------------------------------------------------------------- */
VSILFILE* fp = VSIFOpenL(poOpenInfo->pszFilename, "rb");
if (fp == NULL)
return NULL;
const char* pszLine;
while((pszLine = CPLReadLine2L(fp, 100, NULL)) != NULL)
{
if (*pszLine == '!')
{
continue;
}
else
break;
}
if (pszLine == NULL)
{
VSIFCloseL(fp);
return NULL;
}
/* Parse first header line */
char** papszTokens = CSLTokenizeString2( pszLine, ",", 0 );
if (CSLCount(papszTokens) != 3)
{
CSLDestroy(papszTokens);
VSIFCloseL(fp);
return NULL;
}
int nValuesPerLine = atoi(papszTokens[2]);
if (nValuesPerLine <= 0)
{
CSLDestroy(papszTokens);
VSIFCloseL(fp);
return NULL;
}
CSLDestroy(papszTokens);
papszTokens = NULL;
/* Parse second header line */
pszLine = CPLReadLine2L(fp, 100, NULL);
if (pszLine == NULL)
{
VSIFCloseL(fp);
return NULL;
}
papszTokens = CSLTokenizeString2( pszLine, ",", 0 );
if (CSLCount(papszTokens) != 5)
{
CSLDestroy(papszTokens);
VSIFCloseL(fp);
return NULL;
}
int nFieldSize = atoi(papszTokens[0]);
double dfNoDataValue = CPLAtofM(papszTokens[1]);
int nDecimalCount = atoi(papszTokens[3]);
int nColumnNumber = atoi(papszTokens[4]);
CSLDestroy(papszTokens);
papszTokens = NULL;
if (nFieldSize <= 0 || nFieldSize >= 40 ||
nDecimalCount <= 0 || nDecimalCount >= nFieldSize ||
nColumnNumber != 1)
{
CPLDebug("ZMap", "nFieldSize=%d, nDecimalCount=%d, nColumnNumber=%d",
nFieldSize, nDecimalCount, nColumnNumber);
VSIFCloseL(fp);
return NULL;
}
/* Parse third header line */
pszLine = CPLReadLine2L(fp, 100, NULL);
if (pszLine == NULL)
{
VSIFCloseL(fp);
return NULL;
}
papszTokens = CSLTokenizeString2( pszLine, ",", 0 );
if (CSLCount(papszTokens) != 6)
{
CSLDestroy(papszTokens);
VSIFCloseL(fp);
return NULL;
}
int nRows = atoi(papszTokens[0]);
int nCols = atoi(papszTokens[1]);
double dfMinX = CPLAtofM(papszTokens[2]);
double dfMaxX = CPLAtofM(papszTokens[3]);
double dfMinY = CPLAtofM(papszTokens[4]);
double dfMaxY = CPLAtofM(papszTokens[5]);
CSLDestroy(papszTokens);
papszTokens = NULL;
if (!GDALCheckDatasetDimensions(nCols, nRows) ||
nCols == 1 || nRows == 1)
{
VSIFCloseL(fp);
return NULL;
}
/* Ignore fourth header line */
pszLine = CPLReadLine2L(fp, 100, NULL);
if (pszLine == NULL)
{
VSIFCloseL(fp);
return NULL;
}
/* Check fifth header line */
pszLine = CPLReadLine2L(fp, 100, NULL);
if (pszLine == NULL || pszLine[0] != '@')
{
VSIFCloseL(fp);
return NULL;
}
/* -------------------------------------------------------------------- */
/* Create a corresponding GDALDataset. */
/* -------------------------------------------------------------------- */
ZMapDataset *poDS;
poDS = new ZMapDataset();
poDS->fp = fp;
poDS->nDataStartOff = VSIFTellL(fp);
poDS->nValuesPerLine = nValuesPerLine;
poDS->nFieldSize = nFieldSize;
poDS->nDecimalCount = nDecimalCount;
poDS->nRasterXSize = nCols;
poDS->nRasterYSize = nRows;
poDS->dfNoDataValue = dfNoDataValue;
if (CSLTestBoolean(CPLGetConfigOption("ZMAP_PIXEL_IS_POINT", "FALSE")))
{
double dfStepX = (dfMaxX - dfMinX) / (nCols - 1);
double dfStepY = (dfMaxY - dfMinY) / (nRows - 1);
poDS->adfGeoTransform[0] = dfMinX - dfStepX / 2;
poDS->adfGeoTransform[1] = dfStepX;
poDS->adfGeoTransform[3] = dfMaxY + dfStepY / 2;
poDS->adfGeoTransform[5] = -dfStepY;
}
else
{
double dfStepX = (dfMaxX - dfMinX) / nCols ;
double dfStepY = (dfMaxY - dfMinY) / nRows;
poDS->adfGeoTransform[0] = dfMinX;
poDS->adfGeoTransform[1] = dfStepX;
poDS->adfGeoTransform[3] = dfMaxY;
poDS->adfGeoTransform[5] = -dfStepY;
}
/* -------------------------------------------------------------------- */
/* Create band information objects. */
/* -------------------------------------------------------------------- */
poDS->nBands = 1;
poDS->SetBand( 1, new ZMapRasterBand( poDS ) );
/* -------------------------------------------------------------------- */
/* Initialize any PAM information. */
/* -------------------------------------------------------------------- */
poDS->SetDescription( poOpenInfo->pszFilename );
poDS->TryLoadXML();
/* -------------------------------------------------------------------- */
/* Support overviews. */
/* -------------------------------------------------------------------- */
poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
return( poDS );
}
/************************************************************************/
/* WriteRightJustified() */
/************************************************************************/
static void WriteRightJustified(VSILFILE* fp, const char *pszValue, int nWidth)
{
int nLen = strlen(pszValue);
CPLAssert(nLen <= nWidth);
int i;
for(i=0;i<nWidth -nLen;i++)
VSIFWriteL(" ", 1, 1, fp);
VSIFWriteL(pszValue, 1, nLen, fp);
}
static void WriteRightJustified(VSILFILE* fp, int nValue, int nWidth)
{
CPLString osValue(CPLSPrintf("%d", nValue));
WriteRightJustified(fp, osValue.c_str(), nWidth);
}
static void WriteRightJustified(VSILFILE* fp, double dfValue, int nWidth,
int nDecimals = -1)
{
char szFormat[32];
if (nDecimals >= 0)
sprintf(szFormat, "%%.%df", nDecimals);
else
sprintf(szFormat, "%%g");
char* pszValue = (char*)CPLSPrintf(szFormat, dfValue);
char* pszE = strchr(pszValue, 'e');
if (pszE)
*pszE = 'E';
if ((int)strlen(pszValue) > nWidth)
{
sprintf(szFormat, "%%.%dg", nDecimals);
pszValue = (char*)CPLSPrintf(szFormat, dfValue);
pszE = strchr(pszValue, 'e');
if (pszE)
*pszE = 'E';
}
CPLString osValue(pszValue);
WriteRightJustified(fp, osValue.c_str(), nWidth);
}
/************************************************************************/
/* CreateCopy() */
/************************************************************************/
GDALDataset* ZMapDataset::CreateCopy( const char * pszFilename,
GDALDataset *poSrcDS,
int bStrict,
CPL_UNUSED char ** papszOptions,
GDALProgressFunc pfnProgress,
void * pProgressData )
{
/* -------------------------------------------------------------------- */
/* Some some rudimentary checks */
/* -------------------------------------------------------------------- */
int nBands = poSrcDS->GetRasterCount();
if (nBands == 0)
{
CPLError( CE_Failure, CPLE_NotSupported,
"ZMap driver does not support source dataset with zero band.\n");
return NULL;
}
if (nBands != 1)
{
CPLError( (bStrict) ? CE_Failure : CE_Warning, CPLE_NotSupported,
"ZMap driver only uses the first band of the dataset.\n");
if (bStrict)
return NULL;
}
if( pfnProgress && !pfnProgress( 0.0, NULL, pProgressData ) )
return NULL;
/* -------------------------------------------------------------------- */
/* Get source dataset info */
/* -------------------------------------------------------------------- */
int nXSize = poSrcDS->GetRasterXSize();
int nYSize = poSrcDS->GetRasterYSize();
if (nXSize == 1 || nYSize == 1)
{
return NULL;
}
double adfGeoTransform[6];
poSrcDS->GetGeoTransform(adfGeoTransform);
if (adfGeoTransform[2] != 0 || adfGeoTransform[4] != 0)
{
CPLError( CE_Failure, CPLE_NotSupported,
"ZMap driver does not support CreateCopy() from skewed or rotated dataset.\n");
return NULL;
}
/* -------------------------------------------------------------------- */
/* Create target file */
/* -------------------------------------------------------------------- */
VSILFILE* fp = VSIFOpenL(pszFilename, "wb");
if (fp == NULL)
{
CPLError( CE_Failure, CPLE_AppDefined,
"Cannot create %s", pszFilename );
return NULL;
}
int nFieldSize = 20;
int nValuesPerLine = 4;
int nDecimalCount = 7;
int bHasNoDataValue = FALSE;
double dfNoDataValue =
poSrcDS->GetRasterBand(1)->GetNoDataValue(&bHasNoDataValue);
if (!bHasNoDataValue)
dfNoDataValue = 1.e30;
VSIFPrintfL(fp, "!\n");
VSIFPrintfL(fp, "! Created by GDAL.\n");
VSIFPrintfL(fp, "!\n");
VSIFPrintfL(fp, "@GRID FILE, GRID, %d\n", nValuesPerLine);
WriteRightJustified(fp, nFieldSize, 10);
VSIFPrintfL(fp, ",");
WriteRightJustified(fp, dfNoDataValue, 10);
VSIFPrintfL(fp, ",");
WriteRightJustified(fp, "", 10);
VSIFPrintfL(fp, ",");
WriteRightJustified(fp, nDecimalCount, 10);
VSIFPrintfL(fp, ",");
WriteRightJustified(fp, 1, 10);
VSIFPrintfL(fp, "\n");
WriteRightJustified(fp, nYSize, 10);
VSIFPrintfL(fp, ",");
WriteRightJustified(fp, nXSize, 10);
VSIFPrintfL(fp, ",");
if (CSLTestBoolean(CPLGetConfigOption("ZMAP_PIXEL_IS_POINT", "FALSE")))
{
WriteRightJustified(fp, adfGeoTransform[0] + adfGeoTransform[1] / 2, 14, 7);
VSIFPrintfL(fp, ",");
WriteRightJustified(fp, adfGeoTransform[0] + adfGeoTransform[1] * nXSize -
adfGeoTransform[1] / 2, 14, 7);
VSIFPrintfL(fp, ",");
WriteRightJustified(fp, adfGeoTransform[3] + adfGeoTransform[5] * nYSize -
adfGeoTransform[5] / 2, 14, 7);
VSIFPrintfL(fp, ",");
WriteRightJustified(fp, adfGeoTransform[3] + adfGeoTransform[5] / 2, 14, 7);
}
else
{
WriteRightJustified(fp, adfGeoTransform[0], 14, 7);
VSIFPrintfL(fp, ",");
WriteRightJustified(fp, adfGeoTransform[0] + adfGeoTransform[1] * nXSize, 14, 7);
VSIFPrintfL(fp, ",");
WriteRightJustified(fp, adfGeoTransform[3] + adfGeoTransform[5] * nYSize, 14, 7);
VSIFPrintfL(fp, ",");
WriteRightJustified(fp, adfGeoTransform[3], 14, 7);
}
VSIFPrintfL(fp, "\n");
VSIFPrintfL(fp, "0.0, 0.0, 0.0\n");
VSIFPrintfL(fp, "@\n");
/* -------------------------------------------------------------------- */
/* Copy imagery */
/* -------------------------------------------------------------------- */
double* padfLineBuffer = (double*) CPLMalloc(nYSize * sizeof(double));
int i, j;
CPLErr eErr = CE_None;
for(i=0;i<nXSize && eErr == CE_None;i++)
{
eErr = poSrcDS->GetRasterBand(1)->RasterIO(
GF_Read, i, 0, 1, nYSize,
padfLineBuffer, 1, nYSize,
GDT_Float64, 0, 0, NULL);
if (eErr != CE_None)
break;
int bEOLPrinted = FALSE;
for(j=0;j<nYSize;j++)
{
WriteRightJustified(fp, padfLineBuffer[j], nFieldSize, nDecimalCount);
if (((j + 1) % nValuesPerLine) == 0)
{
bEOLPrinted = TRUE;
VSIFPrintfL(fp, "\n");
}
else
bEOLPrinted = FALSE;
}
if (!bEOLPrinted)
VSIFPrintfL(fp, "\n");
if (!pfnProgress( (j+1) * 1.0 / nYSize, NULL, pProgressData))
{
eErr = CE_Failure;
break;
}
}
CPLFree(padfLineBuffer);
VSIFCloseL(fp);
if (eErr != CE_None)
return NULL;
return (GDALDataset*) GDALOpen(pszFilename, GA_ReadOnly);
}
/************************************************************************/
/* GetGeoTransform() */
/************************************************************************/
CPLErr ZMapDataset::GetGeoTransform( double * padfTransform )
{
memcpy(padfTransform, adfGeoTransform, 6 * sizeof(double));
return( CE_None );
}
/************************************************************************/
/* GDALRegister_ZMap() */
/************************************************************************/
void GDALRegister_ZMap()
{
GDALDriver *poDriver;
if( GDALGetDriverByName( "ZMap" ) == NULL )
{
poDriver = new GDALDriver();
poDriver->SetDescription( "ZMap" );
poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
"ZMap Plus Grid" );
poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
"frmt_various.html#ZMap" );
poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "dat" );
poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
poDriver->pfnOpen = ZMapDataset::Open;
poDriver->pfnIdentify = ZMapDataset::Identify;
poDriver->pfnCreateCopy = ZMapDataset::CreateCopy;
GetGDALDriverManager()->RegisterDriver( poDriver );
}
}