709 строки
26 KiB
C++
709 строки
26 KiB
C++
/******************************************************************************
|
|
*
|
|
* 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 "cpl_port.h"
|
|
#include "gdal_priv.h"
|
|
|
|
#include <cstring>
|
|
|
|
#include "cpl_conv.h"
|
|
#include "cpl_error.h"
|
|
#include "cpl_progress.h"
|
|
#include "cpl_string.h"
|
|
#include "gdal.h"
|
|
#include "gdal_mdreader.h"
|
|
#include "gdal_proxy.h"
|
|
|
|
/** 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 fledged
|
|
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 final : public GDALDataset
|
|
{
|
|
private:
|
|
friend class GDALOverviewBand;
|
|
|
|
GDALDataset *poMainDS = nullptr;
|
|
|
|
GDALDataset *poOvrDS = nullptr; // Will be often NULL.
|
|
int nOvrLevel = 0;
|
|
bool bThisLevelOnly = false;
|
|
|
|
int nGCPCount = 0;
|
|
GDAL_GCP *pasGCPList = nullptr;
|
|
char **papszMD_RPC = nullptr;
|
|
char **papszMD_GEOLOCATION = nullptr;
|
|
GDALOverviewBand *m_poMaskBand = nullptr;
|
|
|
|
static void Rescale(char **&papszMD, const char *pszItem, double dfRatio,
|
|
double dfDefaultVal);
|
|
|
|
protected:
|
|
CPLErr IRasterIO(GDALRWFlag, int, int, int, int, void *, int, int,
|
|
GDALDataType, int, int *, GSpacing, GSpacing, GSpacing,
|
|
GDALRasterIOExtraArg *psExtraArg) override;
|
|
|
|
public:
|
|
GDALOverviewDataset(GDALDataset *poMainDS, int nOvrLevel,
|
|
bool bThisLevelOnly);
|
|
~GDALOverviewDataset() override;
|
|
|
|
const OGRSpatialReference *GetSpatialRef() const override;
|
|
CPLErr GetGeoTransform(double *) override;
|
|
|
|
int GetGCPCount() override;
|
|
const OGRSpatialReference *GetGCPSpatialRef() const override;
|
|
const GDAL_GCP *GetGCPs() override;
|
|
|
|
char **GetMetadata(const char *pszDomain = "") override;
|
|
const char *GetMetadataItem(const char *pszName,
|
|
const char *pszDomain = "") override;
|
|
|
|
int CloseDependentDatasets() override;
|
|
|
|
private:
|
|
CPL_DISALLOW_COPY_ASSIGN(GDALOverviewDataset)
|
|
};
|
|
|
|
/* ******************************************************************** */
|
|
/* GDALOverviewBand */
|
|
/* ******************************************************************** */
|
|
|
|
class GDALOverviewBand final : public GDALProxyRasterBand
|
|
{
|
|
protected:
|
|
friend class GDALOverviewDataset;
|
|
|
|
GDALRasterBand *poUnderlyingBand = nullptr;
|
|
GDALRasterBand *RefUnderlyingRasterBand(bool bForceOpen) const override;
|
|
|
|
CPLErr IRasterIO(GDALRWFlag, int, int, int, int, void *, int, int,
|
|
GDALDataType, GSpacing, GSpacing,
|
|
GDALRasterIOExtraArg *psExtraArg) override;
|
|
|
|
public:
|
|
GDALOverviewBand(GDALOverviewDataset *poDS, int nBand);
|
|
~GDALOverviewBand() override;
|
|
|
|
CPLErr FlushCache(bool bAtClosing) override;
|
|
|
|
int GetOverviewCount() override;
|
|
GDALRasterBand *GetOverview(int) override;
|
|
|
|
int GetMaskFlags() override;
|
|
GDALRasterBand *GetMaskBand() override;
|
|
|
|
private:
|
|
CPL_DISALLOW_COPY_ASSIGN(GDALOverviewBand)
|
|
};
|
|
|
|
/************************************************************************/
|
|
/* GetOverviewEx() */
|
|
/************************************************************************/
|
|
|
|
static GDALRasterBand *GetOverviewEx(GDALRasterBand *poBand, int nLevel)
|
|
{
|
|
if (nLevel == -1)
|
|
return poBand;
|
|
return poBand->GetOverview(nLevel);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GDALCreateOverviewDataset() */
|
|
/************************************************************************/
|
|
|
|
// Takes a reference on poMainDS in case of success.
|
|
// nOvrLevel=-1 means the full resolution dataset (only useful if
|
|
// bThisLevelOnly = false to expose a dataset without its overviews)
|
|
GDALDataset *GDALCreateOverviewDataset(GDALDataset *poMainDS, int nOvrLevel,
|
|
bool bThisLevelOnly)
|
|
{
|
|
// Sanity checks.
|
|
const int nBands = poMainDS->GetRasterCount();
|
|
if (nBands == 0)
|
|
return nullptr;
|
|
|
|
auto poFirstBand = GetOverviewEx(poMainDS->GetRasterBand(1), nOvrLevel);
|
|
for (int i = 1; i <= nBands; ++i)
|
|
{
|
|
auto poBand = GetOverviewEx(poMainDS->GetRasterBand(i), nOvrLevel);
|
|
if (poBand == nullptr)
|
|
{
|
|
return nullptr;
|
|
}
|
|
if (poBand->GetXSize() != poFirstBand->GetXSize() ||
|
|
poBand->GetYSize() != poFirstBand->GetYSize())
|
|
{
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
return new GDALOverviewDataset(poMainDS, nOvrLevel, bThisLevelOnly);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GDALOverviewDataset() */
|
|
/************************************************************************/
|
|
|
|
GDALOverviewDataset::GDALOverviewDataset(GDALDataset *poMainDSIn,
|
|
int nOvrLevelIn, bool bThisLevelOnlyIn)
|
|
: poMainDS(poMainDSIn), nOvrLevel(nOvrLevelIn),
|
|
bThisLevelOnly(bThisLevelOnlyIn)
|
|
{
|
|
poMainDSIn->Reference();
|
|
eAccess = poMainDS->GetAccess();
|
|
auto poFirstBand = GetOverviewEx(poMainDS->GetRasterBand(1), nOvrLevel);
|
|
nRasterXSize = poFirstBand->GetXSize();
|
|
nRasterYSize = poFirstBand->GetYSize();
|
|
poOvrDS = poFirstBand->GetDataset();
|
|
if (nOvrLevel != -1 && poOvrDS != nullptr && poOvrDS == poMainDS)
|
|
{
|
|
CPLDebug("GDAL", "Dataset of overview is the same as the main band. "
|
|
"This is not expected");
|
|
poOvrDS = nullptr;
|
|
}
|
|
nBands = poMainDS->GetRasterCount();
|
|
for (int i = 0; i < nBands; ++i)
|
|
{
|
|
SetBand(i + 1, new GDALOverviewBand(this, i + 1));
|
|
}
|
|
|
|
if (poFirstBand->GetMaskFlags() == GMF_PER_DATASET)
|
|
{
|
|
auto poOvrMaskBand = poFirstBand->GetMaskBand();
|
|
if (poOvrMaskBand && poOvrMaskBand->GetXSize() == nRasterXSize &&
|
|
poOvrMaskBand->GetYSize() == nRasterYSize)
|
|
{
|
|
m_poMaskBand = new GDALOverviewBand(this, 0);
|
|
}
|
|
}
|
|
|
|
// 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() != nullptr)
|
|
{
|
|
poDriver = new GDALDriver();
|
|
poDriver->SetDescription(poMainDS->GetDriver()->GetDescription());
|
|
poDriver->SetMetadata(poMainDS->GetDriver()->GetMetadata());
|
|
}
|
|
|
|
if (poOvrDS)
|
|
poOvrDS->SetEnableOverviews(false);
|
|
|
|
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",
|
|
nOvrLevel == -1
|
|
? "NONE"
|
|
: CPLSPrintf("%d%s", nOvrLevel, bThisLevelOnly ? " only" : ""));
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* ~GDALOverviewDataset() */
|
|
/************************************************************************/
|
|
|
|
GDALOverviewDataset::~GDALOverviewDataset()
|
|
{
|
|
GDALOverviewDataset::FlushCache(true);
|
|
|
|
GDALOverviewDataset::CloseDependentDatasets();
|
|
|
|
if (nGCPCount > 0)
|
|
{
|
|
GDALDeinitGCPs(nGCPCount, pasGCPList);
|
|
CPLFree(pasGCPList);
|
|
}
|
|
CSLDestroy(papszMD_RPC);
|
|
|
|
CSLDestroy(papszMD_GEOLOCATION);
|
|
|
|
delete poDriver;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* CloseDependentDatasets() */
|
|
/************************************************************************/
|
|
|
|
int GDALOverviewDataset::CloseDependentDatasets()
|
|
{
|
|
bool bRet = false;
|
|
|
|
if (poOvrDS)
|
|
poOvrDS->SetEnableOverviews(true);
|
|
|
|
if (poMainDS)
|
|
{
|
|
for (int i = 0; i < nBands; ++i)
|
|
{
|
|
GDALOverviewBand *const band =
|
|
cpl::down_cast<GDALOverviewBand *>(papoBands[i]);
|
|
band->poUnderlyingBand = nullptr;
|
|
}
|
|
if (poMainDS->ReleaseRef())
|
|
bRet = true;
|
|
poMainDS = nullptr;
|
|
}
|
|
|
|
if (m_poMaskBand)
|
|
{
|
|
m_poMaskBand->poUnderlyingBand = nullptr;
|
|
delete m_poMaskBand;
|
|
m_poMaskBand = nullptr;
|
|
}
|
|
|
|
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)
|
|
|
|
{
|
|
// Try to pass the request to the most appropriate overview dataset.
|
|
if (nBufXSize < nXSize && nBufYSize < nYSize)
|
|
{
|
|
int bTried = FALSE;
|
|
const CPLErr eErr = TryOverviewRasterIO(
|
|
eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
|
|
eBufType, nBandCount, panBandMap, nPixelSpace, nLineSpace,
|
|
nBandSpace, psExtraArg, &bTried);
|
|
if (bTried)
|
|
return eErr;
|
|
}
|
|
|
|
// In case the overview bands are really linked to a dataset, then issue
|
|
// the request to that dataset.
|
|
if (nOvrLevel != -1 && poOvrDS != nullptr)
|
|
{
|
|
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;
|
|
CPLErr eErr = CE_None;
|
|
|
|
for (int iBandIndex = 0; iBandIndex < nBandCount && eErr == CE_None;
|
|
++iBandIndex)
|
|
{
|
|
GDALOverviewBand *poBand = cpl::down_cast<GDALOverviewBand *>(
|
|
GetRasterBand(panBandMap[iBandIndex]));
|
|
GByte *pabyBandData =
|
|
static_cast<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,
|
|
pabyBandData, nBufXSize, nBufYSize, eBufType,
|
|
nPixelSpace, nLineSpace, psExtraArg);
|
|
|
|
GDALDestroyScaledProgress(psExtraArg->pProgressData);
|
|
}
|
|
|
|
psExtraArg->pfnProgress = pfnProgressGlobal;
|
|
psExtraArg->pProgressData = pProgressDataGlobal;
|
|
|
|
return eErr;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetSpatialRef() */
|
|
/************************************************************************/
|
|
|
|
const OGRSpatialReference *GDALOverviewDataset::GetSpatialRef() const
|
|
|
|
{
|
|
return poMainDS->GetSpatialRef();
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetGeoTransform() */
|
|
/************************************************************************/
|
|
|
|
CPLErr GDALOverviewDataset::GetGeoTransform(double *padfTransform)
|
|
|
|
{
|
|
double adfGeoTransform[6] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
|
|
if (poMainDS->GetGeoTransform(adfGeoTransform) != CE_None)
|
|
return CE_Failure;
|
|
|
|
adfGeoTransform[1] *=
|
|
static_cast<double>(poMainDS->GetRasterXSize()) / nRasterXSize;
|
|
adfGeoTransform[2] *=
|
|
static_cast<double>(poMainDS->GetRasterYSize()) / nRasterYSize;
|
|
adfGeoTransform[4] *=
|
|
static_cast<double>(poMainDS->GetRasterXSize()) / nRasterXSize;
|
|
adfGeoTransform[5] *=
|
|
static_cast<double>(poMainDS->GetRasterYSize()) / nRasterYSize;
|
|
|
|
memcpy(padfTransform, adfGeoTransform, sizeof(double) * 6);
|
|
|
|
return CE_None;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetGCPCount() */
|
|
/************************************************************************/
|
|
|
|
int GDALOverviewDataset::GetGCPCount()
|
|
|
|
{
|
|
return poMainDS->GetGCPCount();
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetGCPSpatialRef() */
|
|
/************************************************************************/
|
|
|
|
const OGRSpatialReference *GDALOverviewDataset::GetGCPSpatialRef() const
|
|
|
|
{
|
|
return poMainDS->GetGCPSpatialRef();
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetGCPs() */
|
|
/************************************************************************/
|
|
|
|
const GDAL_GCP *GDALOverviewDataset::GetGCPs()
|
|
|
|
{
|
|
if (pasGCPList != nullptr)
|
|
return pasGCPList;
|
|
|
|
const GDAL_GCP *pasGCPsMain = poMainDS->GetGCPs();
|
|
if (pasGCPsMain == nullptr)
|
|
return nullptr;
|
|
nGCPCount = poMainDS->GetGCPCount();
|
|
|
|
pasGCPList = GDALDuplicateGCPs(nGCPCount, pasGCPsMain);
|
|
for (int i = 0; i < nGCPCount; ++i)
|
|
{
|
|
pasGCPList[i].dfGCPPixel *=
|
|
static_cast<double>(nRasterXSize) / poMainDS->GetRasterXSize();
|
|
pasGCPList[i].dfGCPLine *=
|
|
static_cast<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)
|
|
{
|
|
if (poOvrDS != nullptr)
|
|
{
|
|
char **papszMD = poOvrDS->GetMetadata(pszDomain);
|
|
if (papszMD != nullptr)
|
|
return papszMD;
|
|
}
|
|
|
|
char **papszMD = poMainDS->GetMetadata(pszDomain);
|
|
|
|
// We may need to rescale some values from the RPC metadata domain.
|
|
if (pszDomain != nullptr && EQUAL(pszDomain, MD_DOMAIN_RPC) &&
|
|
papszMD != nullptr)
|
|
{
|
|
if (papszMD_RPC)
|
|
return papszMD_RPC;
|
|
papszMD_RPC = CSLDuplicate(papszMD);
|
|
|
|
Rescale(papszMD_RPC, RPC_LINE_OFF,
|
|
static_cast<double>(nRasterYSize) / poMainDS->GetRasterYSize(),
|
|
0.0);
|
|
Rescale(papszMD_RPC, RPC_LINE_SCALE,
|
|
static_cast<double>(nRasterYSize) / poMainDS->GetRasterYSize(),
|
|
1.0);
|
|
Rescale(papszMD_RPC, RPC_SAMP_OFF,
|
|
static_cast<double>(nRasterXSize) / poMainDS->GetRasterXSize(),
|
|
0.0);
|
|
Rescale(papszMD_RPC, RPC_SAMP_SCALE,
|
|
static_cast<double>(nRasterXSize) / poMainDS->GetRasterXSize(),
|
|
1.0);
|
|
|
|
papszMD = papszMD_RPC;
|
|
}
|
|
|
|
// We may need to rescale some values from the GEOLOCATION metadata domain.
|
|
if (pszDomain != nullptr && EQUAL(pszDomain, "GEOLOCATION") &&
|
|
papszMD != nullptr)
|
|
{
|
|
if (papszMD_GEOLOCATION)
|
|
return papszMD_GEOLOCATION;
|
|
papszMD_GEOLOCATION = CSLDuplicate(papszMD);
|
|
|
|
Rescale(papszMD_GEOLOCATION, "PIXEL_OFFSET",
|
|
static_cast<double>(poMainDS->GetRasterXSize()) / nRasterXSize,
|
|
0.0);
|
|
Rescale(papszMD_GEOLOCATION, "LINE_OFFSET",
|
|
static_cast<double>(poMainDS->GetRasterYSize()) / nRasterYSize,
|
|
0.0);
|
|
|
|
Rescale(papszMD_GEOLOCATION, "PIXEL_STEP",
|
|
static_cast<double>(nRasterXSize) / poMainDS->GetRasterXSize(),
|
|
1.0);
|
|
Rescale(papszMD_GEOLOCATION, "LINE_STEP",
|
|
static_cast<double>(nRasterYSize) / poMainDS->GetRasterYSize(),
|
|
1.0);
|
|
|
|
papszMD = papszMD_GEOLOCATION;
|
|
}
|
|
|
|
return papszMD;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetMetadataItem() */
|
|
/************************************************************************/
|
|
|
|
const char *GDALOverviewDataset::GetMetadataItem(const char *pszName,
|
|
const char *pszDomain)
|
|
{
|
|
if (poOvrDS != nullptr)
|
|
{
|
|
const char *pszValue = poOvrDS->GetMetadataItem(pszName, pszDomain);
|
|
if (pszValue != nullptr)
|
|
return pszValue;
|
|
}
|
|
|
|
if (pszDomain != nullptr &&
|
|
(EQUAL(pszDomain, "RPC") || EQUAL(pszDomain, "GEOLOCATION")))
|
|
{
|
|
char **papszMD = GetMetadata(pszDomain);
|
|
return CSLFetchNameValue(papszMD, pszName);
|
|
}
|
|
|
|
return poMainDS->GetMetadataItem(pszName, pszDomain);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GDALOverviewBand() */
|
|
/************************************************************************/
|
|
|
|
GDALOverviewBand::GDALOverviewBand(GDALOverviewDataset *poDSIn, int nBandIn)
|
|
{
|
|
poDS = poDSIn;
|
|
nBand = nBandIn;
|
|
nRasterXSize = poDSIn->nRasterXSize;
|
|
nRasterYSize = poDSIn->nRasterYSize;
|
|
if (nBandIn == 0)
|
|
{
|
|
poUnderlyingBand =
|
|
GetOverviewEx(poDSIn->poMainDS->GetRasterBand(1), poDSIn->nOvrLevel)
|
|
->GetMaskBand();
|
|
}
|
|
else
|
|
{
|
|
poUnderlyingBand = GetOverviewEx(
|
|
poDSIn->poMainDS->GetRasterBand(nBandIn), poDSIn->nOvrLevel);
|
|
}
|
|
eDataType = poUnderlyingBand->GetRasterDataType();
|
|
poUnderlyingBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* ~GDALOverviewBand() */
|
|
/************************************************************************/
|
|
|
|
GDALOverviewBand::~GDALOverviewBand()
|
|
{
|
|
GDALOverviewBand::FlushCache(true);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* FlushCache() */
|
|
/************************************************************************/
|
|
|
|
CPLErr GDALOverviewBand::FlushCache(bool bAtClosing)
|
|
{
|
|
if (poUnderlyingBand)
|
|
return poUnderlyingBand->FlushCache(bAtClosing);
|
|
return CE_None;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* RefUnderlyingRasterBand() */
|
|
/************************************************************************/
|
|
|
|
GDALRasterBand *
|
|
GDALOverviewBand::RefUnderlyingRasterBand(bool /*bForceOpen */) const
|
|
{
|
|
return poUnderlyingBand;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetOverviewCount() */
|
|
/************************************************************************/
|
|
|
|
int GDALOverviewBand::GetOverviewCount()
|
|
{
|
|
GDALOverviewDataset *const poOvrDS =
|
|
cpl::down_cast<GDALOverviewDataset *>(poDS);
|
|
if (poOvrDS->bThisLevelOnly)
|
|
return 0;
|
|
GDALDataset *const poMainDS = poOvrDS->poMainDS;
|
|
GDALRasterBand *poMainBand = (nBand == 0)
|
|
? poMainDS->GetRasterBand(1)->GetMaskBand()
|
|
: poMainDS->GetRasterBand(nBand);
|
|
auto poUnderlyingDS =
|
|
poUnderlyingBand ? poUnderlyingBand->GetDataset() : nullptr;
|
|
if (poUnderlyingDS)
|
|
poUnderlyingDS->SetEnableOverviews(true);
|
|
const int nRet = poMainBand->GetOverviewCount() - poOvrDS->nOvrLevel - 1;
|
|
if (poUnderlyingDS)
|
|
poUnderlyingDS->SetEnableOverviews(false);
|
|
return nRet;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetOverview() */
|
|
/************************************************************************/
|
|
|
|
GDALRasterBand *GDALOverviewBand::GetOverview(int iOvr)
|
|
{
|
|
if (iOvr < 0 || iOvr >= GetOverviewCount())
|
|
return nullptr;
|
|
GDALOverviewDataset *const poOvrDS =
|
|
cpl::down_cast<GDALOverviewDataset *>(poDS);
|
|
GDALDataset *const poMainDS = poOvrDS->poMainDS;
|
|
GDALRasterBand *poMainBand = (nBand == 0)
|
|
? poMainDS->GetRasterBand(1)->GetMaskBand()
|
|
: poMainDS->GetRasterBand(nBand);
|
|
auto poUnderlyingDS =
|
|
poUnderlyingBand ? poUnderlyingBand->GetDataset() : nullptr;
|
|
if (poUnderlyingDS)
|
|
poUnderlyingDS->SetEnableOverviews(true);
|
|
auto poRet = poMainBand->GetOverview(iOvr + poOvrDS->nOvrLevel + 1);
|
|
if (poUnderlyingDS)
|
|
poUnderlyingDS->SetEnableOverviews(false);
|
|
return poRet;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetMaskFlags() */
|
|
/************************************************************************/
|
|
|
|
int GDALOverviewBand::GetMaskFlags()
|
|
{
|
|
GDALOverviewDataset *const poOvrDS =
|
|
cpl::down_cast<GDALOverviewDataset *>(poDS);
|
|
if (nBand != 0 && poOvrDS->m_poMaskBand)
|
|
return GMF_PER_DATASET;
|
|
return GDALProxyRasterBand::GetMaskFlags();
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetMaskBand() */
|
|
/************************************************************************/
|
|
|
|
GDALRasterBand *GDALOverviewBand::GetMaskBand()
|
|
{
|
|
GDALOverviewDataset *const poOvrDS =
|
|
cpl::down_cast<GDALOverviewDataset *>(poDS);
|
|
if (nBand != 0 && poOvrDS->m_poMaskBand)
|
|
return poOvrDS->m_poMaskBand;
|
|
return GDALProxyRasterBand::GetMaskBand();
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* IRasterIO() */
|
|
/************************************************************************/
|
|
|
|
CPLErr GDALOverviewBand::IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
|
|
int nXSize, int nYSize, void *pData,
|
|
int nBufXSize, int nBufYSize,
|
|
GDALDataType eBufType, GSpacing nPixelSpace,
|
|
GSpacing nLineSpace,
|
|
GDALRasterIOExtraArg *psExtraArg)
|
|
{
|
|
// Try to pass the request to the most appropriate overview.
|
|
if (nBufXSize < nXSize && nBufYSize < nYSize)
|
|
{
|
|
int bTried = FALSE;
|
|
const CPLErr eErr = TryOverviewRasterIO(
|
|
eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
|
|
eBufType, nPixelSpace, nLineSpace, psExtraArg, &bTried);
|
|
if (bTried)
|
|
return eErr;
|
|
}
|
|
|
|
return GDALProxyRasterBand::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
|
|
pData, nBufXSize, nBufYSize, eBufType,
|
|
nPixelSpace, nLineSpace, psExtraArg);
|
|
}
|