ultimatepp/bazaar/plugin/gdal/gcore/gdaloverviewdataset.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

570 lines
21 KiB
C++

/******************************************************************************
* $Id: gdaloverviewdataset.cpp 29128 2015-05-03 13:21:49Z rouault $
*
* Project: GDAL Core
* Purpose: Implementation of a dataset overview warping class
* Author: Even Rouault, <even dot rouault at spatialys dot com>
*
******************************************************************************
* Copyright (c) 2014, Even Rouault, <even dot rouault at spatialys dot com>
*
* 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_proxy.h"
#include "gdal_mdreader.h"
CPL_CVSID("$Id: gdaloverviewdataset.cpp 29128 2015-05-03 13:21:49Z rouault $");
/** In GDAL, GDALRasterBand::GetOverview() returns a stand-alone band, that
may have no parent dataset. This can be inconvenient in certain contexts, where
cross-band processing must be done, or when API expect a fully fledge dataset.
Furthermore even if overview band has a container dataset, that one often
fails to declare its projection, geotransform, etc... which make it somehow
useless. GDALOverviewDataset remedies to those deficiencies.
*/
class GDALOverviewBand;
/* ******************************************************************** */
/* GDALOverviewDataset */
/* ******************************************************************** */
class GDALOverviewDataset : public GDALDataset
{
private:
friend class GDALOverviewBand;
GDALDataset* poMainDS;
int bOwnDS;
GDALDataset* poOvrDS; /* will be often NULL */
int nOvrLevel;
int bThisLevelOnly;
int nGCPCount;
GDAL_GCP *pasGCPList;
char **papszMD_RPC;
char **papszMD_GEOLOCATION;
static void Rescale(char**& papszMD, const char* pszItem,
double dfRatio, double dfDefaultVal);
protected:
virtual CPLErr IRasterIO( GDALRWFlag, int, int, int, int,
void *, int, int, GDALDataType,
int, int *,
GSpacing, GSpacing, GSpacing,
GDALRasterIOExtraArg* psExtraArg );
public:
GDALOverviewDataset(GDALDataset* poMainDS, int nOvrLevel,
int bThisLevelOnly,
int bOwnDS);
virtual ~GDALOverviewDataset();
virtual const char *GetProjectionRef(void);
virtual CPLErr GetGeoTransform( double * );
virtual int GetGCPCount();
virtual const char *GetGCPProjection();
virtual const GDAL_GCP *GetGCPs();
virtual char **GetMetadata( const char * pszDomain = "" );
virtual const char *GetMetadataItem( const char * pszName,
const char * pszDomain = "" );
virtual int CloseDependentDatasets();
};
/* ******************************************************************** */
/* GDALOverviewBand */
/* ******************************************************************** */
class GDALOverviewBand : public GDALProxyRasterBand
{
protected:
friend class GDALOverviewDataset;
GDALRasterBand* poUnderlyingBand;
virtual GDALRasterBand* RefUnderlyingRasterBand();
public:
GDALOverviewBand(GDALOverviewDataset* poDS, int nBand);
virtual ~GDALOverviewBand();
virtual CPLErr FlushCache();
virtual int GetOverviewCount();
virtual GDALRasterBand *GetOverview(int);
};
/************************************************************************/
/* GDALCreateOverviewDataset() */
/************************************************************************/
GDALDataset* GDALCreateOverviewDataset(GDALDataset* poMainDS, int nOvrLevel,
int bThisLevelOnly, int bOwnDS)
{
/* Sanity checks */
int nBands = poMainDS->GetRasterCount();
if( nBands == 0 )
return NULL;
for(int i = 1; i<= nBands; i++ )
{
if( poMainDS->GetRasterBand(i)->GetOverview(nOvrLevel) == NULL )
{
return NULL;
}
if( poMainDS->GetRasterBand(i)->GetOverview(nOvrLevel)->GetXSize() !=
poMainDS->GetRasterBand(1)->GetOverview(nOvrLevel)->GetXSize() ||
poMainDS->GetRasterBand(i)->GetOverview(nOvrLevel)->GetYSize() !=
poMainDS->GetRasterBand(1)->GetOverview(nOvrLevel)->GetYSize() )
{
return NULL;
}
}
return new GDALOverviewDataset(poMainDS, nOvrLevel, bThisLevelOnly, bOwnDS);
}
/************************************************************************/
/* GDALOverviewDataset() */
/************************************************************************/
GDALOverviewDataset::GDALOverviewDataset(GDALDataset* poMainDS,
int nOvrLevel,
int bThisLevelOnly,
int bOwnDS)
{
this->poMainDS = poMainDS;
this->nOvrLevel = nOvrLevel;
this->bOwnDS = bOwnDS;
this->bThisLevelOnly = bThisLevelOnly;
eAccess = poMainDS->GetAccess();
nRasterXSize = poMainDS->GetRasterBand(1)->GetOverview(nOvrLevel)->GetXSize();
nRasterYSize = poMainDS->GetRasterBand(1)->GetOverview(nOvrLevel)->GetYSize();
poOvrDS = poMainDS->GetRasterBand(1)->GetOverview(nOvrLevel)->GetDataset();
if( poOvrDS != NULL && poOvrDS == poMainDS )
{
CPLDebug("GDAL", "Dataset of overview is the same as the main band. This is not expected");
poOvrDS = NULL;
}
nBands = poMainDS->GetRasterCount();
for(int i=0;i<nBands;i++)
{
SetBand(i+1, new GDALOverviewBand(this, i+1));
}
nGCPCount = 0;
pasGCPList = NULL;
papszMD_RPC = NULL;
papszMD_GEOLOCATION = NULL;
/* We create a fake driver that has the same name as the original */
/* one, but we cannot use the real driver object, so that code */
/* doesn't try to cast the GDALOverviewDataset* as a native dataset */
/* object */
if( poMainDS->GetDriver() != NULL )
{
poDriver = new GDALDriver();
poDriver->SetDescription(poMainDS->GetDriver()->GetDescription());
poDriver->SetMetadata(poMainDS->GetDriver()->GetMetadata());
}
SetDescription( poMainDS->GetDescription() );
CPLDebug( "GDAL", "GDALOverviewDataset(%s, this=%p) creation.",
poMainDS->GetDescription(), this );
papszOpenOptions = CSLDuplicate(poMainDS->GetOpenOptions());
/* Add OVERVIEW_LEVEL if not called from GDALOpenEx() but directly */
papszOpenOptions = CSLSetNameValue(papszOpenOptions, "OVERVIEW_LEVEL",
CPLSPrintf("%d", nOvrLevel));
}
/************************************************************************/
/* ~GDALOverviewDataset() */
/************************************************************************/
GDALOverviewDataset::~GDALOverviewDataset()
{
FlushCache();
CloseDependentDatasets();
if( nGCPCount > 0 )
{
GDALDeinitGCPs( nGCPCount, pasGCPList );
CPLFree( pasGCPList );
}
CSLDestroy(papszMD_RPC);
CSLDestroy(papszMD_GEOLOCATION);
delete poDriver;
}
/************************************************************************/
/* CloseDependentDatasets() */
/************************************************************************/
int GDALOverviewDataset::CloseDependentDatasets()
{
int bRet = FALSE;
if( bOwnDS )
{
for(int i=0;i<nBands;i++)
{
((GDALOverviewBand*)papoBands[i])->poUnderlyingBand = NULL;
}
GDALClose( poMainDS );
poMainDS = NULL;
bOwnDS = FALSE;
bRet = TRUE;
}
return bRet;
}
/************************************************************************/
/* IRasterIO() */
/* */
/* The default implementation of IRasterIO() is to pass the */
/* request off to each band objects rasterio methods with */
/* appropriate arguments. */
/************************************************************************/
CPLErr GDALOverviewDataset::IRasterIO( GDALRWFlag eRWFlag,
int nXOff, int nYOff, int nXSize, int nYSize,
void * pData, int nBufXSize, int nBufYSize,
GDALDataType eBufType,
int nBandCount, int *panBandMap,
GSpacing nPixelSpace, GSpacing nLineSpace,
GSpacing nBandSpace,
GDALRasterIOExtraArg* psExtraArg)
{
int iBandIndex;
CPLErr eErr = CE_None;
/* In case the overview bands are really linked to a dataset, then issue */
/* the request to that dataset */
if( poOvrDS != NULL )
{
return poOvrDS->RasterIO(
eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
eBufType, nBandCount, panBandMap, nPixelSpace, nLineSpace, nBandSpace,
psExtraArg);
}
GDALProgressFunc pfnProgressGlobal = psExtraArg->pfnProgress;
void *pProgressDataGlobal = psExtraArg->pProgressData;
for( iBandIndex = 0;
iBandIndex < nBandCount && eErr == CE_None;
iBandIndex++ )
{
GDALOverviewBand *poBand = (GDALOverviewBand*) GetRasterBand(panBandMap[iBandIndex]);
GByte *pabyBandData;
if (poBand == NULL)
{
eErr = CE_Failure;
break;
}
pabyBandData = ((GByte *) pData) + iBandIndex * nBandSpace;
psExtraArg->pfnProgress = GDALScaledProgress;
psExtraArg->pProgressData =
GDALCreateScaledProgress( 1.0 * iBandIndex / nBandCount,
1.0 * (iBandIndex + 1) / nBandCount,
pfnProgressGlobal,
pProgressDataGlobal );
eErr = poBand->IRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
(void *) pabyBandData, nBufXSize, nBufYSize,
eBufType, nPixelSpace, nLineSpace, psExtraArg );
GDALDestroyScaledProgress( psExtraArg->pProgressData );
}
psExtraArg->pfnProgress = pfnProgressGlobal;
psExtraArg->pProgressData = pProgressDataGlobal;
return eErr;
}
/************************************************************************/
/* GetProjectionRef() */
/************************************************************************/
const char *GDALOverviewDataset::GetProjectionRef()
{
return poMainDS->GetProjectionRef();
}
/************************************************************************/
/* GetGeoTransform() */
/************************************************************************/
CPLErr GDALOverviewDataset::GetGeoTransform( double * padfTransform )
{
double adfGeoTransform[6];
if( poMainDS->GetGeoTransform(adfGeoTransform) == CE_None )
{
if( adfGeoTransform[2] == 0.0 && adfGeoTransform[4] == 0.0 )
{
adfGeoTransform[1] *= (double)poMainDS->GetRasterXSize() / nRasterXSize;
adfGeoTransform[5] *= (double)poMainDS->GetRasterYSize() / nRasterYSize;
}
else
{
/* If the x and y ratios are not equal, then we cannot really */
/* compute a geotransform */
double dfRatio = (double)poMainDS->GetRasterXSize() / nRasterXSize;
adfGeoTransform[1] *= dfRatio;
adfGeoTransform[2] *= dfRatio;
adfGeoTransform[4] *= dfRatio;
adfGeoTransform[5] *= dfRatio;
}
memcpy( padfTransform, adfGeoTransform, sizeof(double)*6 );
return CE_None;
}
else
return CE_Failure;
}
/************************************************************************/
/* GetGCPCount() */
/************************************************************************/
int GDALOverviewDataset::GetGCPCount()
{
return poMainDS->GetGCPCount();
}
/************************************************************************/
/* GetGCPProjection() */
/************************************************************************/
const char *GDALOverviewDataset::GetGCPProjection()
{
return poMainDS->GetGCPProjection();
}
/************************************************************************/
/* GetGCPs() */
/************************************************************************/
const GDAL_GCP *GDALOverviewDataset::GetGCPs()
{
if( pasGCPList != NULL )
return pasGCPList;
const GDAL_GCP* pasGCPsMain = poMainDS->GetGCPs();
if( pasGCPsMain == NULL )
return NULL;
nGCPCount = poMainDS->GetGCPCount();
pasGCPList = GDALDuplicateGCPs( nGCPCount, pasGCPsMain );
for(int i = 0; i < nGCPCount; i++)
{
pasGCPList[i].dfGCPPixel *= (double)nRasterXSize / poMainDS->GetRasterXSize();
pasGCPList[i].dfGCPLine *= (double)nRasterYSize / poMainDS->GetRasterYSize();
}
return pasGCPList;
}
/************************************************************************/
/* Rescale() */
/************************************************************************/
void GDALOverviewDataset::Rescale(char**& papszMD, const char* pszItem,
double dfRatio, double dfDefaultVal)
{
double dfVal = CPLAtofM(CSLFetchNameValueDef(papszMD, pszItem,
CPLSPrintf("%.18g", dfDefaultVal)));
dfVal *= dfRatio;
papszMD = CSLSetNameValue(papszMD, pszItem, CPLSPrintf("%.18g", dfVal));
}
/************************************************************************/
/* GetMetadata() */
/************************************************************************/
char **GDALOverviewDataset::GetMetadata( const char * pszDomain )
{
char** papszMD;
if (poOvrDS != NULL)
{
papszMD = poOvrDS->GetMetadata(pszDomain);
if( papszMD != NULL )
return papszMD;
}
papszMD = poMainDS->GetMetadata(pszDomain);
/* We may need to rescale some values from the RPC metadata domain */
if( pszDomain != NULL && EQUAL(pszDomain, MD_DOMAIN_RPC) && papszMD != NULL )
{
if( papszMD_RPC )
return papszMD_RPC;
papszMD_RPC = CSLDuplicate(papszMD);
Rescale(papszMD_RPC, RPC_LINE_OFF,
(double)nRasterYSize / poMainDS->GetRasterYSize(), 0.0);
Rescale(papszMD_RPC, RPC_LINE_SCALE,
(double)nRasterYSize / poMainDS->GetRasterYSize(), 1.0);
Rescale(papszMD_RPC, RPC_SAMP_OFF,
(double)nRasterXSize / poMainDS->GetRasterXSize(), 0.0);
Rescale(papszMD_RPC, RPC_SAMP_SCALE,
(double)nRasterXSize / poMainDS->GetRasterXSize(), 1.0);
papszMD = papszMD_RPC;
}
/* We may need to rescale some values from the GEOLOCATION metadata domain */
if( pszDomain != NULL && EQUAL(pszDomain, "GEOLOCATION") && papszMD != NULL )
{
if( papszMD_GEOLOCATION )
return papszMD_GEOLOCATION;
papszMD_GEOLOCATION = CSLDuplicate(papszMD);
Rescale(papszMD_GEOLOCATION, "PIXEL_OFFSET",
(double)poMainDS->GetRasterXSize() / nRasterXSize, 0.0);
Rescale(papszMD_GEOLOCATION, "LINE_OFFSET",
(double)poMainDS->GetRasterYSize() / nRasterYSize, 0.0);
Rescale(papszMD_GEOLOCATION, "PIXEL_STEP",
(double)nRasterXSize / poMainDS->GetRasterXSize(), 1.0);
Rescale(papszMD_GEOLOCATION, "LINE_STEP",
(double)nRasterYSize / poMainDS->GetRasterYSize(), 1.0);
papszMD = papszMD_GEOLOCATION;
}
return papszMD;
}
/************************************************************************/
/* GetMetadataItem() */
/************************************************************************/
const char *GDALOverviewDataset::GetMetadataItem( const char * pszName,
const char * pszDomain )
{
if (poOvrDS != NULL)
{
const char* pszValue = poOvrDS->GetMetadataItem(pszName, pszDomain);
if( pszValue != NULL )
return pszValue;
}
if( pszDomain != NULL && (EQUAL(pszDomain, "RPC") ||
EQUAL(pszDomain, "GEOLOCATION")) )
{
char** papszMD = GetMetadata(pszDomain);
return CSLFetchNameValue(papszMD, pszName);
}
return poMainDS->GetMetadataItem(pszName, pszDomain);
}
/************************************************************************/
/* GDALOverviewBand() */
/************************************************************************/
GDALOverviewBand::GDALOverviewBand(GDALOverviewDataset* poDS, int nBand)
{
this->poDS = poDS;
this->nBand = nBand;
poUnderlyingBand = poDS->poMainDS->GetRasterBand(nBand)->GetOverview(poDS->nOvrLevel);
nRasterXSize = poDS->nRasterXSize;
nRasterYSize = poDS->nRasterYSize;
eDataType = poUnderlyingBand->GetRasterDataType();
poUnderlyingBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
}
/************************************************************************/
/* ~GDALOverviewBand() */
/************************************************************************/
GDALOverviewBand::~GDALOverviewBand()
{
FlushCache();
}
/************************************************************************/
/* FlushCache() */
/************************************************************************/
CPLErr GDALOverviewBand::FlushCache()
{
if( ((GDALOverviewDataset*)poDS)->poMainDS )
return poUnderlyingBand->FlushCache();
return CE_None;
}
/************************************************************************/
/* RefUnderlyingRasterBand() */
/************************************************************************/
GDALRasterBand* GDALOverviewBand::RefUnderlyingRasterBand()
{
if( ((GDALOverviewDataset*)poDS)->poMainDS )
return poUnderlyingBand;
else
return NULL;
}
/************************************************************************/
/* GetOverviewCount() */
/************************************************************************/
int GDALOverviewBand::GetOverviewCount()
{
GDALOverviewDataset* poOvrDS = (GDALOverviewDataset*)poDS;
if( poOvrDS->bThisLevelOnly )
return 0;
GDALDataset* poMainDS = poOvrDS->poMainDS;
return poMainDS->GetRasterBand(nBand)->GetOverviewCount() - poOvrDS->nOvrLevel - 1;
}
/************************************************************************/
/* GetOverview() */
/************************************************************************/
GDALRasterBand *GDALOverviewBand::GetOverview(int iOvr)
{
if( iOvr < 0 || iOvr >= GetOverviewCount() )
return NULL;
GDALOverviewDataset* poOvrDS = (GDALOverviewDataset*)poDS;
GDALDataset* poMainDS = poOvrDS->poMainDS;
return poMainDS->GetRasterBand(nBand)->GetOverview(iOvr + poOvrDS->nOvrLevel + 1);
}