ultimatepp/bazaar/plugin/gdal/frmts/blx/blxdataset.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

453 lines
14 KiB
C++

/******************************************************************************
* $Id: blxdataset.cpp 28053 2014-12-04 09:31:07Z rouault $
*
* Project: BLX Driver
* Purpose: GDAL BLX support.
* Author: Henrik Johansson, henrik@johome.net
*
******************************************************************************
* Copyright (c) 2006, Henrik Johansson <henrik@johome.net>
* Copyright (c) 2008-2011, 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 "gdal_pam.h"
#include "cpl_string.h"
CPL_CVSID("$Id: blxdataset.cpp 28053 2014-12-04 09:31:07Z rouault $");
CPL_C_START
#include <blx.h>
CPL_C_END
CPL_C_START
void GDALRegister_BLX(void);
CPL_C_END
class BLXDataset : public GDALPamDataset
{
friend class BLXRasterBand;
CPLErr GetGeoTransform( double * padfTransform );
const char *GetProjectionRef();
blxcontext_t *blxcontext;
int nOverviewCount;
int bIsOverview;
BLXDataset *papoOverviewDS[BLX_OVERVIEWLEVELS];
public:
BLXDataset();
~BLXDataset();
static GDALDataset *Open( GDALOpenInfo * );
};
class BLXRasterBand : public GDALPamRasterBand
{
int overviewLevel;
public:
BLXRasterBand( BLXDataset *, int, int overviewLevel=0 );
virtual double GetNoDataValue( int *pbSuccess = NULL );
virtual GDALColorInterp GetColorInterpretation(void);
virtual int GetOverviewCount();
virtual GDALRasterBand *GetOverview( int );
virtual CPLErr IReadBlock( int, int, void * );
};
GDALDataset *BLXDataset::Open( GDALOpenInfo * poOpenInfo )
{
// --------------------------------------------------------------------
// First that the header looks like a BLX header
// --------------------------------------------------------------------
if( poOpenInfo->fpL == NULL || poOpenInfo->nHeaderBytes < 102 )
return NULL;
if(!blx_checkheader((char *)poOpenInfo->pabyHeader))
return NULL;
// --------------------------------------------------------------------
// Create a corresponding GDALDataset.
// --------------------------------------------------------------------
BLXDataset *poDS;
poDS = new BLXDataset();
// --------------------------------------------------------------------
// Open BLX file
// --------------------------------------------------------------------
poDS->blxcontext = blx_create_context();
if(poDS->blxcontext==NULL)
{
delete poDS;
return NULL;
}
if (blxopen(poDS->blxcontext, poOpenInfo->pszFilename, "rb") != 0)
{
delete poDS;
return NULL;
}
if ((poDS->blxcontext->cell_xsize % (1 << (1+BLX_OVERVIEWLEVELS))) != 0 ||
(poDS->blxcontext->cell_ysize % (1 << (1+BLX_OVERVIEWLEVELS))) != 0)
{
delete poDS;
return NULL;
}
// Update dataset header from BLX context
poDS->nRasterXSize = poDS->blxcontext->xsize;
poDS->nRasterYSize = poDS->blxcontext->ysize;
// --------------------------------------------------------------------
// Create band information objects.
// --------------------------------------------------------------------
poDS->nBands = 1;
poDS->SetBand( 1, new BLXRasterBand( poDS, 1 ));
// Create overview bands
poDS->nOverviewCount = BLX_OVERVIEWLEVELS;
for(int i=0; i < poDS->nOverviewCount; i++) {
poDS->papoOverviewDS[i] = new BLXDataset();
poDS->papoOverviewDS[i]->blxcontext = poDS->blxcontext;
poDS->papoOverviewDS[i]->bIsOverview = TRUE;
poDS->papoOverviewDS[i]->nRasterXSize = poDS->nRasterXSize >> (i+1);
poDS->papoOverviewDS[i]->nRasterYSize = poDS->nRasterYSize >> (i+1);
poDS->nBands = 1;
poDS->papoOverviewDS[i]->SetBand(1, new BLXRasterBand( poDS->papoOverviewDS[i], 1, i+1));
}
/* -------------------------------------------------------------------- */
/* Confirm the requested access is supported. */
/* -------------------------------------------------------------------- */
if( poOpenInfo->eAccess == GA_Update )
{
delete poDS;
CPLError( CE_Failure, CPLE_NotSupported,
"The BLX driver does not support update access to existing"
" datasets.\n" );
return NULL;
}
/* -------------------------------------------------------------------- */
/* Initialize any PAM information. */
/* -------------------------------------------------------------------- */
poDS->SetDescription( poOpenInfo->pszFilename );
poDS->TryLoadXML();
return( poDS );
}
BLXDataset::BLXDataset() {
blxcontext = NULL;
bIsOverview = FALSE;
nOverviewCount = 0;
for(int i=0; i < nOverviewCount; i++)
papoOverviewDS[i]=NULL;
}
BLXDataset::~BLXDataset() {
if(!bIsOverview) {
if(blxcontext) {
blxclose(blxcontext);
blx_free_context(blxcontext);
}
for(int i=0; i < nOverviewCount; i++)
if(papoOverviewDS[i])
delete papoOverviewDS[i];
}
}
CPLErr BLXDataset::GetGeoTransform( double * padfTransform )
{
padfTransform[0] = blxcontext->lon;
padfTransform[1] = blxcontext->pixelsize_lon;
padfTransform[2] = 0.0;
padfTransform[3] = blxcontext->lat;
padfTransform[4] = 0.0;
padfTransform[5] = blxcontext->pixelsize_lat;
return CE_None;
}
const char *BLXDataset::GetProjectionRef()
{
return( "GEOGCS[\"WGS 84\",DATUM[\"WGS_1984\",SPHEROID[\"WGS 84\",6378137,298.257223563]],PRIMEM[\"Greenwich\",0],UNIT[\"degree\",0.0174532925199433],AUTHORITY[\"EPSG\",\"4326\"]]" );
}
BLXRasterBand::BLXRasterBand( BLXDataset *poDS, int nBand, int overviewLevel )
{
BLXDataset *poGDS = (BLXDataset *) poDS;
this->poDS = poDS;
this->nBand = nBand;
this->overviewLevel = overviewLevel;
eDataType = GDT_Int16;
nBlockXSize = poGDS->blxcontext->cell_xsize >> overviewLevel;
nBlockYSize = poGDS->blxcontext->cell_ysize >> overviewLevel;
}
int BLXRasterBand::GetOverviewCount()
{
BLXDataset *poGDS = (BLXDataset *) poDS;
return poGDS->nOverviewCount;
}
GDALRasterBand *BLXRasterBand::GetOverview( int i )
{
BLXDataset *poGDS = (BLXDataset *) poDS;
if( i < 0 || i >= poGDS->nOverviewCount )
return NULL;
else
return poGDS->papoOverviewDS[i]->GetRasterBand(nBand);
}
CPLErr BLXRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
void * pImage )
{
BLXDataset *poGDS = (BLXDataset *) poDS;
if(blx_readcell(poGDS->blxcontext, nBlockYOff, nBlockXOff, (short *)pImage, nBlockXSize*nBlockYSize*2, overviewLevel) == NULL) {
CPLError(CE_Failure, CPLE_AppDefined,
"Failed to read BLX cell");
return CE_Failure;
}
return CE_None;
}
double BLXRasterBand::GetNoDataValue( int * pbSuccess )
{
if (pbSuccess)
*pbSuccess = TRUE;
return BLX_UNDEF;
}
GDALColorInterp BLXRasterBand::GetColorInterpretation(void) {
return GCI_GrayIndex;
}
/* TODO: check if georeference is the same as for BLX files, WGS84
*/
static GDALDataset *
BLXCreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
int bStrict, char ** papszOptions,
GDALProgressFunc pfnProgress, void * pProgressData )
{
int nBands = poSrcDS->GetRasterCount();
int nXSize = poSrcDS->GetRasterXSize();
int nYSize = poSrcDS->GetRasterYSize();
int zscale = 1;
int fillundef = 1, fillundefval = 0;
int endian = LITTLEENDIAN;
// --------------------------------------------------------------------
// Some rudimentary checks
// --------------------------------------------------------------------
if( nBands != 1 )
{
CPLError( CE_Failure, CPLE_NotSupported,
"BLX driver doesn't support %d bands. Must be 1 (grey) ",
nBands );
return NULL;
}
if( poSrcDS->GetRasterBand(1)->GetRasterDataType() != GDT_Int16 && bStrict )
{
CPLError( CE_Failure, CPLE_NotSupported,
"BLX driver doesn't support data type %s. "
"Only 16 bit byte bands supported.\n",
GDALGetDataTypeName(
poSrcDS->GetRasterBand(1)->GetRasterDataType()) );
return NULL;
}
if( (nXSize % 128 != 0) || (nYSize % 128 != 0) ) {
CPLError( CE_Failure, CPLE_NotSupported,
"BLX driver doesn't support dimensions that are not a multiple of 128.\n");
return NULL;
}
// --------------------------------------------------------------------
// What options has the user selected?
// --------------------------------------------------------------------
if( CSLFetchNameValue(papszOptions,"ZSCALE") != NULL ) {
zscale = atoi(CSLFetchNameValue(papszOptions,"ZSCALE"));
if( zscale < 1 ) {
CPLError( CE_Failure, CPLE_IllegalArg,
"ZSCALE=%s is not a legal value in the range >= 1.",
CSLFetchNameValue(papszOptions,"ZSCALE") );
return NULL;
}
}
if( CSLFetchNameValue(papszOptions,"FILLUNDEF") != NULL
&& EQUAL(CSLFetchNameValue(papszOptions,"FILLUNDEF"),"NO") )
fillundef = 0;
else
fillundef = 1;
if( CSLFetchNameValue(papszOptions,"FILLUNDEFVAL") != NULL ) {
fillundefval = atoi(CSLFetchNameValue(papszOptions,"FILLUNDEFVAL"));
if( (fillundefval < -32768) || (fillundefval > 32767) ) {
CPLError( CE_Failure, CPLE_IllegalArg,
"FILLUNDEFVAL=%s is not a legal value in the range -32768, 32767.",
CSLFetchNameValue(papszOptions,"FILLUNDEFVAL") );
return NULL;
}
}
if( CSLFetchNameValue(papszOptions,"BIGENDIAN") != NULL
&& !EQUAL(CSLFetchNameValue(papszOptions,"BIGENDIAN"),"NO") )
endian = BIGENDIAN;
// --------------------------------------------------------------------
// Create the dataset.
// --------------------------------------------------------------------
blxcontext_t *ctx;
// Create a BLX context
ctx = blx_create_context();
// Setup BLX parameters
ctx->cell_rows = nYSize / ctx->cell_ysize;
ctx->cell_cols = nXSize / ctx->cell_xsize;
ctx->zscale = zscale;
ctx->fillundef = fillundef;
ctx->fillundefval = fillundefval;
ctx->endian = endian;
if(blxopen(ctx, pszFilename, "wb")) {
CPLError( CE_Failure, CPLE_OpenFailed,
"Unable to create blx file %s.\n",
pszFilename );
blx_free_context(ctx);
return NULL;
}
// --------------------------------------------------------------------
// Loop over image, copying image data.
// --------------------------------------------------------------------
GInt16 *pabyTile;
CPLErr eErr=CE_None;
pabyTile = (GInt16 *) VSIMalloc( sizeof(GInt16)*ctx->cell_xsize*ctx->cell_ysize );
if (pabyTile == NULL)
{
CPLError( CE_Failure, CPLE_OutOfMemory, "Out of memory");
blxclose(ctx);
blx_free_context(ctx);
return NULL;
}
if( !pfnProgress( 0.0, NULL, pProgressData ) )
eErr = CE_Failure;
for(int i=0; (i < ctx->cell_rows) && (eErr == CE_None); i++)
for(int j=0; j < ctx->cell_cols; j++) {
blxdata *celldata;
GDALRasterBand * poBand = poSrcDS->GetRasterBand( 1 );
eErr = poBand->RasterIO( GF_Read, j*ctx->cell_xsize, i*ctx->cell_ysize,
ctx->cell_xsize, ctx->cell_ysize,
pabyTile, ctx->cell_xsize, ctx->cell_ysize, GDT_Int16,
0, 0, NULL );
if(eErr >= CE_Failure)
break;
celldata = pabyTile;
if (blx_writecell(ctx, celldata, i, j) != 0)
{
eErr = CE_Failure;
break;
}
if ( ! pfnProgress( 1.0 * (i * ctx->cell_cols + j) / (ctx->cell_rows * ctx->cell_cols), NULL, pProgressData ))
{
eErr = CE_Failure;
break;
}
}
pfnProgress( 1.0, NULL, pProgressData );
CPLFree( pabyTile );
double adfGeoTransform[6];
if( poSrcDS->GetGeoTransform( adfGeoTransform ) == CE_None )
{
ctx->lon = adfGeoTransform[0];
ctx->lat = adfGeoTransform[3];
ctx->pixelsize_lon = adfGeoTransform[1];
ctx->pixelsize_lat = adfGeoTransform[5];
}
blxclose(ctx);
blx_free_context(ctx);
if (eErr == CE_None)
return (GDALDataset *) GDALOpen( pszFilename, GA_ReadOnly );
else
return NULL;
}
void GDALRegister_BLX()
{
GDALDriver *poDriver;
if( GDALGetDriverByName( "BLX" ) == NULL )
{
poDriver = new GDALDriver();
poDriver->SetDescription( "BLX" );
poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
"Magellan topo (.blx)" );
poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
"frmt_various.html#BLX" );
poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "blx" );
poDriver->pfnOpen = BLXDataset::Open;
poDriver->pfnCreateCopy = BLXCreateCopy;
GetGDALDriverManager()->RegisterDriver( poDriver );
}
}