LCOV - code coverage report
Current view: top level - gcore - gdaloverviewdataset.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 231 253 91.3 %
Date: 2024-05-03 15:49:35 Functions: 25 25 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL Core
       4             :  * Purpose:  Implementation of a dataset overview warping class
       5             :  * Author:   Even Rouault, <even dot rouault at spatialys dot com>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2014, Even Rouault, <even dot rouault at spatialys dot com>
       9             :  *
      10             :  * Permission is hereby granted, free of charge, to any person obtaining a
      11             :  * copy of this software and associated documentation files (the "Software"),
      12             :  * to deal in the Software without restriction, including without limitation
      13             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      14             :  * and/or sell copies of the Software, and to permit persons to whom the
      15             :  * Software is furnished to do so, subject to the following conditions:
      16             :  *
      17             :  * The above copyright notice and this permission notice shall be included
      18             :  * in all copies or substantial portions of the Software.
      19             :  *
      20             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      21             :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      22             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      23             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      24             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      25             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      26             :  * DEALINGS IN THE SOFTWARE.
      27             :  ****************************************************************************/
      28             : 
      29             : #include "cpl_port.h"
      30             : #include "gdal_priv.h"
      31             : 
      32             : #include <cstring>
      33             : 
      34             : #include "cpl_conv.h"
      35             : #include "cpl_error.h"
      36             : #include "cpl_progress.h"
      37             : #include "cpl_string.h"
      38             : #include "gdal.h"
      39             : #include "gdal_mdreader.h"
      40             : #include "gdal_proxy.h"
      41             : 
      42             : /** In GDAL, GDALRasterBand::GetOverview() returns a stand-alone band, that may
      43             :     have no parent dataset. This can be inconvenient in certain contexts, where
      44             :     cross-band processing must be done, or when API expect a fully fledged
      45             :     dataset.  Furthermore even if overview band has a container dataset, that
      46             :     one often fails to declare its projection, geotransform, etc... which make
      47             :     it somehow useless. GDALOverviewDataset remedies to those deficiencies.
      48             : */
      49             : 
      50             : class GDALOverviewBand;
      51             : 
      52             : /* ******************************************************************** */
      53             : /*                          GDALOverviewDataset                         */
      54             : /* ******************************************************************** */
      55             : 
      56             : class GDALOverviewDataset final : public GDALDataset
      57             : {
      58             :   private:
      59             :     friend class GDALOverviewBand;
      60             : 
      61             :     GDALDataset *poMainDS = nullptr;
      62             : 
      63             :     GDALDataset *poOvrDS = nullptr;  // Will be often NULL.
      64             :     int nOvrLevel = 0;
      65             :     bool bThisLevelOnly = false;
      66             : 
      67             :     int nGCPCount = 0;
      68             :     GDAL_GCP *pasGCPList = nullptr;
      69             :     char **papszMD_RPC = nullptr;
      70             :     char **papszMD_GEOLOCATION = nullptr;
      71             :     GDALOverviewBand *m_poMaskBand = nullptr;
      72             : 
      73             :     static void Rescale(char **&papszMD, const char *pszItem, double dfRatio,
      74             :                         double dfDefaultVal);
      75             : 
      76             :   protected:
      77             :     CPLErr IRasterIO(GDALRWFlag, int, int, int, int, void *, int, int,
      78             :                      GDALDataType, int, int *, GSpacing, GSpacing, GSpacing,
      79             :                      GDALRasterIOExtraArg *psExtraArg) override;
      80             : 
      81             :   public:
      82             :     GDALOverviewDataset(GDALDataset *poMainDS, int nOvrLevel,
      83             :                         bool bThisLevelOnly);
      84             :     ~GDALOverviewDataset() override;
      85             : 
      86             :     const OGRSpatialReference *GetSpatialRef() const override;
      87             :     CPLErr GetGeoTransform(double *) override;
      88             : 
      89             :     int GetGCPCount() override;
      90             :     const OGRSpatialReference *GetGCPSpatialRef() const override;
      91             :     const GDAL_GCP *GetGCPs() override;
      92             : 
      93             :     char **GetMetadata(const char *pszDomain = "") override;
      94             :     const char *GetMetadataItem(const char *pszName,
      95             :                                 const char *pszDomain = "") override;
      96             : 
      97             :     int CloseDependentDatasets() override;
      98             : 
      99             :   private:
     100             :     CPL_DISALLOW_COPY_ASSIGN(GDALOverviewDataset)
     101             : };
     102             : 
     103             : /* ******************************************************************** */
     104             : /*                           GDALOverviewBand                           */
     105             : /* ******************************************************************** */
     106             : 
     107             : class GDALOverviewBand final : public GDALProxyRasterBand
     108             : {
     109             :   protected:
     110             :     friend class GDALOverviewDataset;
     111             : 
     112             :     GDALRasterBand *poUnderlyingBand = nullptr;
     113             :     GDALRasterBand *RefUnderlyingRasterBand(bool bForceOpen) const override;
     114             : 
     115             :     CPLErr IRasterIO(GDALRWFlag, int, int, int, int, void *, int, int,
     116             :                      GDALDataType, GSpacing, GSpacing,
     117             :                      GDALRasterIOExtraArg *psExtraArg) override;
     118             : 
     119             :   public:
     120             :     GDALOverviewBand(GDALOverviewDataset *poDS, int nBand);
     121             :     ~GDALOverviewBand() override;
     122             : 
     123             :     CPLErr FlushCache(bool bAtClosing) override;
     124             : 
     125             :     int GetOverviewCount() override;
     126             :     GDALRasterBand *GetOverview(int) override;
     127             : 
     128             :     int GetMaskFlags() override;
     129             :     GDALRasterBand *GetMaskBand() override;
     130             : 
     131             :   private:
     132             :     CPL_DISALLOW_COPY_ASSIGN(GDALOverviewBand)
     133             : };
     134             : 
     135             : /************************************************************************/
     136             : /*                           GetOverviewEx()                            */
     137             : /************************************************************************/
     138             : 
     139        1079 : static GDALRasterBand *GetOverviewEx(GDALRasterBand *poBand, int nLevel)
     140             : {
     141        1079 :     if (nLevel == -1)
     142          59 :         return poBand;
     143        1020 :     return poBand->GetOverview(nLevel);
     144             : }
     145             : 
     146             : /************************************************************************/
     147             : /*                       GDALCreateOverviewDataset()                    */
     148             : /************************************************************************/
     149             : 
     150             : // Takes a reference on poMainDS in case of success.
     151             : // nOvrLevel=-1 means the full resolution dataset (only useful if
     152             : // bThisLevelOnly = false to expose a dataset without its overviews)
     153         160 : GDALDataset *GDALCreateOverviewDataset(GDALDataset *poMainDS, int nOvrLevel,
     154             :                                        bool bThisLevelOnly)
     155             : {
     156             :     // Sanity checks.
     157         160 :     const int nBands = poMainDS->GetRasterCount();
     158         160 :     if (nBands == 0)
     159           0 :         return nullptr;
     160             : 
     161         160 :     auto poFirstBand = GetOverviewEx(poMainDS->GetRasterBand(1), nOvrLevel);
     162         409 :     for (int i = 1; i <= nBands; ++i)
     163             :     {
     164         254 :         auto poBand = GetOverviewEx(poMainDS->GetRasterBand(i), nOvrLevel);
     165         254 :         if (poBand == nullptr)
     166             :         {
     167           5 :             return nullptr;
     168             :         }
     169         498 :         if (poBand->GetXSize() != poFirstBand->GetXSize() ||
     170         249 :             poBand->GetYSize() != poFirstBand->GetYSize())
     171             :         {
     172           0 :             return nullptr;
     173             :         }
     174             :     }
     175             : 
     176         155 :     return new GDALOverviewDataset(poMainDS, nOvrLevel, bThisLevelOnly);
     177             : }
     178             : 
     179             : /************************************************************************/
     180             : /*                        GDALOverviewDataset()                         */
     181             : /************************************************************************/
     182             : 
     183         155 : GDALOverviewDataset::GDALOverviewDataset(GDALDataset *poMainDSIn,
     184         155 :                                          int nOvrLevelIn, bool bThisLevelOnlyIn)
     185             :     : poMainDS(poMainDSIn), nOvrLevel(nOvrLevelIn),
     186         155 :       bThisLevelOnly(bThisLevelOnlyIn)
     187             : {
     188         155 :     poMainDSIn->Reference();
     189         155 :     eAccess = poMainDS->GetAccess();
     190         155 :     auto poFirstBand = GetOverviewEx(poMainDS->GetRasterBand(1), nOvrLevel);
     191         155 :     nRasterXSize = poFirstBand->GetXSize();
     192         155 :     nRasterYSize = poFirstBand->GetYSize();
     193         155 :     poOvrDS = poFirstBand->GetDataset();
     194         155 :     if (nOvrLevel != -1 && poOvrDS != nullptr && poOvrDS == poMainDS)
     195             :     {
     196           0 :         CPLDebug("GDAL", "Dataset of overview is the same as the main band. "
     197             :                          "This is not expected");
     198           0 :         poOvrDS = nullptr;
     199             :     }
     200         155 :     nBands = poMainDS->GetRasterCount();
     201         404 :     for (int i = 0; i < nBands; ++i)
     202             :     {
     203         249 :         if (poOvrDS)
     204             :         {
     205             :             // Check that all overview bands belong to the same dataset
     206             :             auto poOvrBand =
     207         249 :                 GetOverviewEx(poMainDS->GetRasterBand(i + 1), nOvrLevel);
     208         249 :             if (poOvrBand->GetDataset() != poOvrDS)
     209           0 :                 poOvrDS = nullptr;
     210             :         }
     211         249 :         SetBand(i + 1, new GDALOverviewBand(this, i + 1));
     212             :     }
     213             : 
     214         155 :     if (poFirstBand->GetMaskFlags() == GMF_PER_DATASET)
     215             :     {
     216          12 :         auto poOvrMaskBand = poFirstBand->GetMaskBand();
     217          24 :         if (poOvrMaskBand && poOvrMaskBand->GetXSize() == nRasterXSize &&
     218          12 :             poOvrMaskBand->GetYSize() == nRasterYSize)
     219             :         {
     220          12 :             m_poMaskBand = new GDALOverviewBand(this, 0);
     221             :         }
     222             :     }
     223             : 
     224             :     // We create a fake driver that has the same name as the original
     225             :     // one, but we cannot use the real driver object, so that code
     226             :     // doesn't try to cast the GDALOverviewDataset* as a native dataset
     227             :     // object.
     228         155 :     if (poMainDS->GetDriver() != nullptr)
     229             :     {
     230         155 :         poDriver = new GDALDriver();
     231         155 :         poDriver->SetDescription(poMainDS->GetDriver()->GetDescription());
     232         155 :         poDriver->SetMetadata(poMainDS->GetDriver()->GetMetadata());
     233             :     }
     234             : 
     235         155 :     SetDescription(poMainDS->GetDescription());
     236             : 
     237         155 :     CPLDebug("GDAL", "GDALOverviewDataset(%s, this=%p) creation.",
     238         155 :              poMainDS->GetDescription(), this);
     239             : 
     240         155 :     papszOpenOptions = CSLDuplicate(poMainDS->GetOpenOptions());
     241             :     // Add OVERVIEW_LEVEL if not called from GDALOpenEx(), but directly.
     242         155 :     papszOpenOptions = CSLSetNameValue(
     243             :         papszOpenOptions, "OVERVIEW_LEVEL",
     244         155 :         nOvrLevel == -1
     245             :             ? "NONE"
     246         148 :             : CPLSPrintf("%d%s", nOvrLevel, bThisLevelOnly ? " only" : ""));
     247         155 : }
     248             : 
     249             : /************************************************************************/
     250             : /*                       ~GDALOverviewDataset()                         */
     251             : /************************************************************************/
     252             : 
     253         310 : GDALOverviewDataset::~GDALOverviewDataset()
     254             : {
     255         155 :     GDALOverviewDataset::FlushCache(true);
     256             : 
     257         155 :     GDALOverviewDataset::CloseDependentDatasets();
     258             : 
     259         155 :     if (nGCPCount > 0)
     260             :     {
     261           1 :         GDALDeinitGCPs(nGCPCount, pasGCPList);
     262           1 :         CPLFree(pasGCPList);
     263             :     }
     264         155 :     CSLDestroy(papszMD_RPC);
     265             : 
     266         155 :     CSLDestroy(papszMD_GEOLOCATION);
     267             : 
     268         155 :     delete poDriver;
     269         310 : }
     270             : 
     271             : /************************************************************************/
     272             : /*                      CloseDependentDatasets()                        */
     273             : /************************************************************************/
     274             : 
     275         155 : int GDALOverviewDataset::CloseDependentDatasets()
     276             : {
     277         155 :     bool bRet = false;
     278             : 
     279         155 :     if (poMainDS)
     280             :     {
     281         404 :         for (int i = 0; i < nBands; ++i)
     282             :         {
     283             :             GDALOverviewBand *const band =
     284         249 :                 cpl::down_cast<GDALOverviewBand *>(papoBands[i]);
     285         249 :             band->poUnderlyingBand = nullptr;
     286             :         }
     287         155 :         if (poMainDS->ReleaseRef())
     288          27 :             bRet = true;
     289         155 :         poMainDS = nullptr;
     290             :     }
     291             : 
     292         155 :     if (m_poMaskBand)
     293             :     {
     294          12 :         m_poMaskBand->poUnderlyingBand = nullptr;
     295          12 :         delete m_poMaskBand;
     296          12 :         m_poMaskBand = nullptr;
     297             :     }
     298             : 
     299         155 :     return bRet;
     300             : }
     301             : 
     302             : /************************************************************************/
     303             : /*                             IRasterIO()                              */
     304             : /*                                                                      */
     305             : /*      The default implementation of IRasterIO() is to pass the        */
     306             : /*      request off to each band objects rasterio methods with          */
     307             : /*      appropriate arguments.                                          */
     308             : /************************************************************************/
     309             : 
     310        3654 : CPLErr GDALOverviewDataset::IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
     311             :                                       int nXSize, int nYSize, void *pData,
     312             :                                       int nBufXSize, int nBufYSize,
     313             :                                       GDALDataType eBufType, int nBandCount,
     314             :                                       int *panBandMap, GSpacing nPixelSpace,
     315             :                                       GSpacing nLineSpace, GSpacing nBandSpace,
     316             :                                       GDALRasterIOExtraArg *psExtraArg)
     317             : 
     318             : {
     319             :     // Try to pass the request to the most appropriate overview dataset.
     320        3654 :     if (nBufXSize < nXSize && nBufYSize < nYSize)
     321             :     {
     322          11 :         int bTried = FALSE;
     323          11 :         const CPLErr eErr = TryOverviewRasterIO(
     324             :             eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
     325             :             eBufType, nBandCount, panBandMap, nPixelSpace, nLineSpace,
     326             :             nBandSpace, psExtraArg, &bTried);
     327          11 :         if (bTried)
     328           2 :             return eErr;
     329             :     }
     330             : 
     331             :     // In case the overview bands are really linked to a dataset, then issue
     332             :     // the request to that dataset.
     333        3652 :     if (poOvrDS != nullptr)
     334             :     {
     335        3652 :         const bool bEnabledOverviews = poOvrDS->AreOverviewsEnabled();
     336        3652 :         poOvrDS->SetEnableOverviews(false);
     337        3652 :         CPLErr eErr = poOvrDS->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
     338             :                                         pData, nBufXSize, nBufYSize, eBufType,
     339             :                                         nBandCount, panBandMap, nPixelSpace,
     340             :                                         nLineSpace, nBandSpace, psExtraArg);
     341        3652 :         poOvrDS->SetEnableOverviews(bEnabledOverviews);
     342        3652 :         return eErr;
     343             :     }
     344             : 
     345           0 :     GDALProgressFunc pfnProgressGlobal = psExtraArg->pfnProgress;
     346           0 :     void *pProgressDataGlobal = psExtraArg->pProgressData;
     347           0 :     CPLErr eErr = CE_None;
     348             : 
     349           0 :     for (int iBandIndex = 0; iBandIndex < nBandCount && eErr == CE_None;
     350             :          ++iBandIndex)
     351             :     {
     352           0 :         GDALOverviewBand *poBand = cpl::down_cast<GDALOverviewBand *>(
     353           0 :             GetRasterBand(panBandMap[iBandIndex]));
     354           0 :         GByte *pabyBandData =
     355           0 :             static_cast<GByte *>(pData) + iBandIndex * nBandSpace;
     356             : 
     357           0 :         psExtraArg->pfnProgress = GDALScaledProgress;
     358           0 :         psExtraArg->pProgressData = GDALCreateScaledProgress(
     359           0 :             1.0 * iBandIndex / nBandCount, 1.0 * (iBandIndex + 1) / nBandCount,
     360             :             pfnProgressGlobal, pProgressDataGlobal);
     361             : 
     362           0 :         eErr = poBand->IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
     363             :                                  pabyBandData, nBufXSize, nBufYSize, eBufType,
     364             :                                  nPixelSpace, nLineSpace, psExtraArg);
     365             : 
     366           0 :         GDALDestroyScaledProgress(psExtraArg->pProgressData);
     367             :     }
     368             : 
     369           0 :     psExtraArg->pfnProgress = pfnProgressGlobal;
     370           0 :     psExtraArg->pProgressData = pProgressDataGlobal;
     371             : 
     372           0 :     return eErr;
     373             : }
     374             : 
     375             : /************************************************************************/
     376             : /*                           GetSpatialRef()                            */
     377             : /************************************************************************/
     378             : 
     379          56 : const OGRSpatialReference *GDALOverviewDataset::GetSpatialRef() const
     380             : 
     381             : {
     382          56 :     return poMainDS->GetSpatialRef();
     383             : }
     384             : 
     385             : /************************************************************************/
     386             : /*                          GetGeoTransform()                           */
     387             : /************************************************************************/
     388             : 
     389          32 : CPLErr GDALOverviewDataset::GetGeoTransform(double *padfTransform)
     390             : 
     391             : {
     392          32 :     double adfGeoTransform[6] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
     393          32 :     if (poMainDS->GetGeoTransform(adfGeoTransform) != CE_None)
     394           1 :         return CE_Failure;
     395             : 
     396          31 :     adfGeoTransform[1] *=
     397          31 :         static_cast<double>(poMainDS->GetRasterXSize()) / nRasterXSize;
     398          31 :     adfGeoTransform[2] *=
     399          31 :         static_cast<double>(poMainDS->GetRasterYSize()) / nRasterYSize;
     400          31 :     adfGeoTransform[4] *=
     401          31 :         static_cast<double>(poMainDS->GetRasterXSize()) / nRasterXSize;
     402          31 :     adfGeoTransform[5] *=
     403          31 :         static_cast<double>(poMainDS->GetRasterYSize()) / nRasterYSize;
     404             : 
     405          31 :     memcpy(padfTransform, adfGeoTransform, sizeof(double) * 6);
     406             : 
     407          31 :     return CE_None;
     408             : }
     409             : 
     410             : /************************************************************************/
     411             : /*                            GetGCPCount()                             */
     412             : /************************************************************************/
     413             : 
     414          12 : int GDALOverviewDataset::GetGCPCount()
     415             : 
     416             : {
     417          12 :     return poMainDS->GetGCPCount();
     418             : }
     419             : 
     420             : /************************************************************************/
     421             : /*                          GetGCPSpatialRef()                          */
     422             : /************************************************************************/
     423             : 
     424           3 : const OGRSpatialReference *GDALOverviewDataset::GetGCPSpatialRef() const
     425             : 
     426             : {
     427           3 :     return poMainDS->GetGCPSpatialRef();
     428             : }
     429             : 
     430             : /************************************************************************/
     431             : /*                               GetGCPs()                              */
     432             : /************************************************************************/
     433             : 
     434           4 : const GDAL_GCP *GDALOverviewDataset::GetGCPs()
     435             : 
     436             : {
     437           4 :     if (pasGCPList != nullptr)
     438           1 :         return pasGCPList;
     439             : 
     440           3 :     const GDAL_GCP *pasGCPsMain = poMainDS->GetGCPs();
     441           3 :     if (pasGCPsMain == nullptr)
     442           2 :         return nullptr;
     443           1 :     nGCPCount = poMainDS->GetGCPCount();
     444             : 
     445           1 :     pasGCPList = GDALDuplicateGCPs(nGCPCount, pasGCPsMain);
     446           4 :     for (int i = 0; i < nGCPCount; ++i)
     447             :     {
     448           3 :         pasGCPList[i].dfGCPPixel *=
     449           3 :             static_cast<double>(nRasterXSize) / poMainDS->GetRasterXSize();
     450           3 :         pasGCPList[i].dfGCPLine *=
     451           3 :             static_cast<double>(nRasterYSize) / poMainDS->GetRasterYSize();
     452             :     }
     453           1 :     return pasGCPList;
     454             : }
     455             : 
     456             : /************************************************************************/
     457             : /*                             Rescale()                                */
     458             : /************************************************************************/
     459             : 
     460          12 : void GDALOverviewDataset::Rescale(char **&papszMD, const char *pszItem,
     461             :                                   double dfRatio, double dfDefaultVal)
     462             : {
     463          12 :     double dfVal = CPLAtofM(CSLFetchNameValueDef(
     464             :         papszMD, pszItem, CPLSPrintf("%.18g", dfDefaultVal)));
     465          12 :     dfVal *= dfRatio;
     466          12 :     papszMD = CSLSetNameValue(papszMD, pszItem, CPLSPrintf("%.18g", dfVal));
     467          12 : }
     468             : 
     469             : /************************************************************************/
     470             : /*                            GetMetadata()                             */
     471             : /************************************************************************/
     472             : 
     473         121 : char **GDALOverviewDataset::GetMetadata(const char *pszDomain)
     474             : {
     475         121 :     if (poOvrDS != nullptr)
     476             :     {
     477         121 :         char **papszMD = poOvrDS->GetMetadata(pszDomain);
     478         121 :         if (papszMD != nullptr)
     479           1 :             return papszMD;
     480             :     }
     481             : 
     482         120 :     char **papszMD = poMainDS->GetMetadata(pszDomain);
     483             : 
     484             :     // We may need to rescale some values from the RPC metadata domain.
     485         120 :     if (pszDomain != nullptr && EQUAL(pszDomain, MD_DOMAIN_RPC) &&
     486             :         papszMD != nullptr)
     487             :     {
     488          19 :         if (papszMD_RPC)
     489          17 :             return papszMD_RPC;
     490           2 :         papszMD_RPC = CSLDuplicate(papszMD);
     491             : 
     492           2 :         Rescale(papszMD_RPC, RPC_LINE_OFF,
     493           2 :                 static_cast<double>(nRasterYSize) / poMainDS->GetRasterYSize(),
     494             :                 0.0);
     495           2 :         Rescale(papszMD_RPC, RPC_LINE_SCALE,
     496           2 :                 static_cast<double>(nRasterYSize) / poMainDS->GetRasterYSize(),
     497             :                 1.0);
     498           2 :         Rescale(papszMD_RPC, RPC_SAMP_OFF,
     499           2 :                 static_cast<double>(nRasterXSize) / poMainDS->GetRasterXSize(),
     500             :                 0.0);
     501           2 :         Rescale(papszMD_RPC, RPC_SAMP_SCALE,
     502           2 :                 static_cast<double>(nRasterXSize) / poMainDS->GetRasterXSize(),
     503             :                 1.0);
     504             : 
     505           2 :         papszMD = papszMD_RPC;
     506             :     }
     507             : 
     508             :     // We may need to rescale some values from the GEOLOCATION metadata domain.
     509         103 :     if (pszDomain != nullptr && EQUAL(pszDomain, "GEOLOCATION") &&
     510             :         papszMD != nullptr)
     511             :     {
     512          13 :         if (papszMD_GEOLOCATION)
     513          12 :             return papszMD_GEOLOCATION;
     514           1 :         papszMD_GEOLOCATION = CSLDuplicate(papszMD);
     515             : 
     516           1 :         Rescale(papszMD_GEOLOCATION, "PIXEL_OFFSET",
     517           1 :                 static_cast<double>(poMainDS->GetRasterXSize()) / nRasterXSize,
     518             :                 0.0);
     519           1 :         Rescale(papszMD_GEOLOCATION, "LINE_OFFSET",
     520           1 :                 static_cast<double>(poMainDS->GetRasterYSize()) / nRasterYSize,
     521             :                 0.0);
     522             : 
     523           1 :         Rescale(papszMD_GEOLOCATION, "PIXEL_STEP",
     524           1 :                 static_cast<double>(nRasterXSize) / poMainDS->GetRasterXSize(),
     525             :                 1.0);
     526           1 :         Rescale(papszMD_GEOLOCATION, "LINE_STEP",
     527           1 :                 static_cast<double>(nRasterYSize) / poMainDS->GetRasterYSize(),
     528             :                 1.0);
     529             : 
     530           1 :         papszMD = papszMD_GEOLOCATION;
     531             :     }
     532             : 
     533          91 :     return papszMD;
     534             : }
     535             : 
     536             : /************************************************************************/
     537             : /*                          GetMetadataItem()                           */
     538             : /************************************************************************/
     539             : 
     540          80 : const char *GDALOverviewDataset::GetMetadataItem(const char *pszName,
     541             :                                                  const char *pszDomain)
     542             : {
     543          80 :     if (poOvrDS != nullptr)
     544             :     {
     545          80 :         const char *pszValue = poOvrDS->GetMetadataItem(pszName, pszDomain);
     546          80 :         if (pszValue != nullptr)
     547          19 :             return pszValue;
     548             :     }
     549             : 
     550          61 :     if (pszDomain != nullptr &&
     551          61 :         (EQUAL(pszDomain, "RPC") || EQUAL(pszDomain, "GEOLOCATION")))
     552             :     {
     553          27 :         char **papszMD = GetMetadata(pszDomain);
     554          27 :         return CSLFetchNameValue(papszMD, pszName);
     555             :     }
     556             : 
     557          34 :     return poMainDS->GetMetadataItem(pszName, pszDomain);
     558             : }
     559             : 
     560             : /************************************************************************/
     561             : /*                          GDALOverviewBand()                          */
     562             : /************************************************************************/
     563             : 
     564         261 : GDALOverviewBand::GDALOverviewBand(GDALOverviewDataset *poDSIn, int nBandIn)
     565             : {
     566         261 :     poDS = poDSIn;
     567         261 :     nBand = nBandIn;
     568         261 :     nRasterXSize = poDSIn->nRasterXSize;
     569         261 :     nRasterYSize = poDSIn->nRasterYSize;
     570         261 :     if (nBandIn == 0)
     571             :     {
     572          12 :         poUnderlyingBand =
     573          12 :             GetOverviewEx(poDSIn->poMainDS->GetRasterBand(1), poDSIn->nOvrLevel)
     574          12 :                 ->GetMaskBand();
     575             :     }
     576             :     else
     577             :     {
     578         249 :         poUnderlyingBand = GetOverviewEx(
     579         249 :             poDSIn->poMainDS->GetRasterBand(nBandIn), poDSIn->nOvrLevel);
     580             :     }
     581         261 :     eDataType = poUnderlyingBand->GetRasterDataType();
     582         261 :     poUnderlyingBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
     583         261 : }
     584             : 
     585             : /************************************************************************/
     586             : /*                         ~GDALOverviewBand()                          */
     587             : /************************************************************************/
     588             : 
     589         522 : GDALOverviewBand::~GDALOverviewBand()
     590             : {
     591         261 :     GDALOverviewBand::FlushCache(true);
     592         522 : }
     593             : 
     594             : /************************************************************************/
     595             : /*                              FlushCache()                            */
     596             : /************************************************************************/
     597             : 
     598         529 : CPLErr GDALOverviewBand::FlushCache(bool bAtClosing)
     599             : {
     600         529 :     if (poUnderlyingBand)
     601         268 :         return poUnderlyingBand->FlushCache(bAtClosing);
     602         261 :     return CE_None;
     603             : }
     604             : 
     605             : /************************************************************************/
     606             : /*                        RefUnderlyingRasterBand()                     */
     607             : /************************************************************************/
     608             : 
     609             : GDALRasterBand *
     610         694 : GDALOverviewBand::RefUnderlyingRasterBand(bool /*bForceOpen */) const
     611             : {
     612         694 :     return poUnderlyingBand;
     613             : }
     614             : 
     615             : /************************************************************************/
     616             : /*                         GetOverviewCount()                           */
     617             : /************************************************************************/
     618             : 
     619          69 : int GDALOverviewBand::GetOverviewCount()
     620             : {
     621             :     GDALOverviewDataset *const poOvrDS =
     622          69 :         cpl::down_cast<GDALOverviewDataset *>(poDS);
     623          69 :     if (poOvrDS->bThisLevelOnly)
     624          13 :         return 0;
     625          56 :     GDALDataset *const poMainDS = poOvrDS->poMainDS;
     626          56 :     GDALRasterBand *poMainBand = (nBand == 0)
     627          56 :                                      ? poMainDS->GetRasterBand(1)->GetMaskBand()
     628          54 :                                      : poMainDS->GetRasterBand(nBand);
     629          56 :     return poMainBand->GetOverviewCount() - poOvrDS->nOvrLevel - 1;
     630             :     ;
     631             : }
     632             : 
     633             : /************************************************************************/
     634             : /*                           GetOverview()                              */
     635             : /************************************************************************/
     636             : 
     637          40 : GDALRasterBand *GDALOverviewBand::GetOverview(int iOvr)
     638             : {
     639          40 :     if (iOvr < 0 || iOvr >= GetOverviewCount())
     640           0 :         return nullptr;
     641             :     GDALOverviewDataset *const poOvrDS =
     642          40 :         cpl::down_cast<GDALOverviewDataset *>(poDS);
     643          40 :     GDALDataset *const poMainDS = poOvrDS->poMainDS;
     644          40 :     GDALRasterBand *poMainBand = (nBand == 0)
     645          40 :                                      ? poMainDS->GetRasterBand(1)->GetMaskBand()
     646          39 :                                      : poMainDS->GetRasterBand(nBand);
     647          40 :     return poMainBand->GetOverview(iOvr + poOvrDS->nOvrLevel + 1);
     648             : }
     649             : 
     650             : /************************************************************************/
     651             : /*                           GetMaskFlags()                             */
     652             : /************************************************************************/
     653             : 
     654          96 : int GDALOverviewBand::GetMaskFlags()
     655             : {
     656             :     GDALOverviewDataset *const poOvrDS =
     657          96 :         cpl::down_cast<GDALOverviewDataset *>(poDS);
     658          96 :     if (nBand != 0 && poOvrDS->m_poMaskBand)
     659           1 :         return GMF_PER_DATASET;
     660          95 :     return GDALProxyRasterBand::GetMaskFlags();
     661             : }
     662             : 
     663             : /************************************************************************/
     664             : /*                           GetMaskBand()                              */
     665             : /************************************************************************/
     666             : 
     667           4 : GDALRasterBand *GDALOverviewBand::GetMaskBand()
     668             : {
     669             :     GDALOverviewDataset *const poOvrDS =
     670           4 :         cpl::down_cast<GDALOverviewDataset *>(poDS);
     671           4 :     if (nBand != 0 && poOvrDS->m_poMaskBand)
     672           1 :         return poOvrDS->m_poMaskBand;
     673           3 :     return GDALProxyRasterBand::GetMaskBand();
     674             : }
     675             : 
     676             : /************************************************************************/
     677             : /*                            IRasterIO()                               */
     678             : /************************************************************************/
     679             : 
     680          51 : CPLErr GDALOverviewBand::IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
     681             :                                    int nXSize, int nYSize, void *pData,
     682             :                                    int nBufXSize, int nBufYSize,
     683             :                                    GDALDataType eBufType, GSpacing nPixelSpace,
     684             :                                    GSpacing nLineSpace,
     685             :                                    GDALRasterIOExtraArg *psExtraArg)
     686             : {
     687             :     GDALOverviewDataset *const poOvrDS =
     688          51 :         cpl::down_cast<GDALOverviewDataset *>(poDS);
     689          51 :     if (poOvrDS->bThisLevelOnly && poOvrDS->poOvrDS)
     690             :     {
     691          15 :         const bool bEnabledOverviews = poOvrDS->poOvrDS->AreOverviewsEnabled();
     692          15 :         poOvrDS->poOvrDS->SetEnableOverviews(false);
     693          15 :         CPLErr eErr = GDALProxyRasterBand::IRasterIO(
     694             :             eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
     695             :             eBufType, nPixelSpace, nLineSpace, psExtraArg);
     696          15 :         poOvrDS->poOvrDS->SetEnableOverviews(bEnabledOverviews);
     697          15 :         return eErr;
     698             :     }
     699             : 
     700             :     // Try to pass the request to the most appropriate overview.
     701          36 :     if (nBufXSize < nXSize && nBufYSize < nYSize)
     702             :     {
     703           2 :         int bTried = FALSE;
     704           2 :         const CPLErr eErr = TryOverviewRasterIO(
     705             :             eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
     706             :             eBufType, nPixelSpace, nLineSpace, psExtraArg, &bTried);
     707           2 :         if (bTried)
     708           2 :             return eErr;
     709             :     }
     710             : 
     711          34 :     return GDALProxyRasterBand::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
     712             :                                           pData, nBufXSize, nBufYSize, eBufType,
     713          34 :                                           nPixelSpace, nLineSpace, psExtraArg);
     714             : }

Generated by: LCOV version 1.14