LCOV - code coverage report
Current view: top level - apps - gdalalg_raster_overview_refresh.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 254 266 95.5 %
Date: 2025-05-15 13:16:46 Functions: 6 6 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL
       4             :  * Purpose:  gdal "raster overview refresh" subcommand
       5             :  * Author:   Even Rouault <even dot rouault at spatialys.com>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2025, Even Rouault <even dot rouault at spatialys.com>
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #include "gdalalg_raster_overview_refresh.h"
      14             : 
      15             : #include "cpl_string.h"
      16             : #include "gdal_priv.h"
      17             : #include "vrtdataset.h"
      18             : #include "vrt_priv.h"
      19             : 
      20             : #include <algorithm>
      21             : 
      22             : //! @cond Doxygen_Suppress
      23             : 
      24             : #ifndef _
      25             : #define _(x) (x)
      26             : #endif
      27             : 
      28             : /************************************************************************/
      29             : /*                 GDALRasterOverviewAlgorithmRefresh()                 */
      30             : /************************************************************************/
      31             : 
      32          20 : GDALRasterOverviewAlgorithmRefresh::GDALRasterOverviewAlgorithmRefresh()
      33          20 :     : GDALAlgorithm(NAME, DESCRIPTION, HELP_URL)
      34             : {
      35          20 :     AddProgressArg();
      36          20 :     AddOpenOptionsArg(&m_openOptions);
      37             :     AddArg("dataset", 0,
      38             :            _("Dataset (to be updated in-place, unless --external)"), &m_dataset,
      39          40 :            GDAL_OF_RASTER | GDAL_OF_UPDATE)
      40          20 :         .SetPositional()
      41          20 :         .SetRequired();
      42          40 :     AddArg("external", 0, _("Refresh external overviews"), &m_readOnly)
      43          40 :         .AddHiddenAlias("ro")
      44          20 :         .AddHiddenAlias(GDAL_ARG_NAME_READ_ONLY);
      45             : 
      46          40 :     AddArg("resampling", 'r', _("Resampling method"), &m_resampling)
      47             :         .SetChoices("nearest", "average", "cubic", "cubicspline", "lanczos",
      48          20 :                     "bilinear", "gauss", "average_magphase", "rms", "mode")
      49          20 :         .SetHiddenChoices("near", "none");
      50             : 
      51          40 :     AddArg("levels", 0, _("Levels / decimation factors"), &m_levels)
      52          20 :         .SetMinValueIncluded(2);
      53             : 
      54          20 :     AddBBOXArg(&m_refreshBbox, _("Bounding box to refresh"))
      55          20 :         .SetMutualExclusionGroup("refresh");
      56          40 :     AddArg("like", 0, _("Use extent of dataset(s)"), &m_like)
      57          20 :         .SetMutualExclusionGroup("refresh");
      58             :     AddArg("use-source-timestamp", 0,
      59             :            _("Use timestamp of VRT or GTI sources as refresh criterion"),
      60          40 :            &m_refreshFromSourceTimestamp)
      61          20 :         .SetMutualExclusionGroup("refresh");
      62          20 : }
      63             : 
      64             : /************************************************************************/
      65             : /*                              PartialRefresh()                        */
      66             : /************************************************************************/
      67             : 
      68           5 : static bool PartialRefresh(GDALDataset *poDS,
      69             :                            const std::vector<int> &anOvrIndices,
      70             :                            const char *pszResampling, int nXOff, int nYOff,
      71             :                            int nXSize, int nYSize, GDALProgressFunc pfnProgress,
      72             :                            void *pProgressArg)
      73             : {
      74           5 :     int nOvCount = 0;
      75           5 :     const int nBandCount = poDS->GetRasterCount();
      76          10 :     for (int i = 0; i < nBandCount; ++i)
      77             :     {
      78           5 :         auto poSrcBand = poDS->GetRasterBand(i + 1);
      79           5 :         if (i == 0)
      80           5 :             nOvCount = poSrcBand->GetOverviewCount();
      81           0 :         else if (nOvCount != poSrcBand->GetOverviewCount())
      82             :         {
      83           0 :             CPLError(CE_Failure, CPLE_AppDefined,
      84             :                      "Not same number of overviews on all bands");
      85           0 :             return false;
      86             :         }
      87             :     }
      88             : 
      89          10 :     std::vector<GDALRasterBand *> apoSrcBands;
      90          10 :     std::vector<std::vector<GDALRasterBand *>> aapoOverviewBands;
      91          10 :     for (int i = 0; i < nBandCount; ++i)
      92             :     {
      93           5 :         auto poSrcBand = poDS->GetRasterBand(i + 1);
      94           5 :         apoSrcBands.push_back(poSrcBand);
      95          10 :         std::vector<GDALRasterBand *> apoOverviewBands;
      96          13 :         for (int nOvrIdx : anOvrIndices)
      97             :         {
      98           8 :             apoOverviewBands.push_back(poSrcBand->GetOverview(nOvrIdx));
      99             :         }
     100           5 :         aapoOverviewBands.push_back(std::move(apoOverviewBands));
     101             :     }
     102             : 
     103           5 :     CPLStringList aosOptions;
     104           5 :     aosOptions.SetNameValue("XOFF", CPLSPrintf("%d", nXOff));
     105           5 :     aosOptions.SetNameValue("YOFF", CPLSPrintf("%d", nYOff));
     106           5 :     aosOptions.SetNameValue("XSIZE", CPLSPrintf("%d", nXSize));
     107           5 :     aosOptions.SetNameValue("YSIZE", CPLSPrintf("%d", nYSize));
     108           5 :     return GDALRegenerateOverviewsMultiBand(
     109             :                apoSrcBands, aapoOverviewBands, pszResampling, pfnProgress,
     110          10 :                pProgressArg, aosOptions.List()) == CE_None;
     111             : }
     112             : 
     113             : /************************************************************************/
     114             : /*                   PartialRefreshFromSourceTimestamp()                */
     115             : /************************************************************************/
     116             : 
     117             : static bool
     118           5 : PartialRefreshFromSourceTimestamp(GDALDataset *poDS, const char *pszResampling,
     119             :                                   const std::vector<int> &anOvrIndices,
     120             :                                   GDALProgressFunc pfnProgress,
     121             :                                   void *pProgressArg)
     122             : {
     123             :     VSIStatBufL sStatOvr;
     124          15 :     std::string osOvr(std::string(poDS->GetDescription()) + ".ovr");
     125           5 :     if (VSIStatL(osOvr.c_str(), &sStatOvr) != 0)
     126             :     {
     127           1 :         CPLError(CE_Failure, CPLE_AppDefined, "Cannot find %s", osOvr.c_str());
     128           1 :         return false;
     129             :     }
     130           4 :     if (sStatOvr.st_mtime == 0)
     131             :     {
     132           1 :         CPLError(CE_Failure, CPLE_AppDefined,
     133             :                  "Cannot get modification time of %s", osOvr.c_str());
     134           1 :         return false;
     135             :     }
     136             : 
     137           6 :     std::vector<GTISourceDesc> regions;
     138             : 
     139           3 :     double dfTotalPixels = 0;
     140             : 
     141           3 :     if (dynamic_cast<VRTDataset *>(poDS))
     142             :     {
     143             :         auto poVRTBand =
     144           1 :             dynamic_cast<VRTSourcedRasterBand *>(poDS->GetRasterBand(1));
     145           1 :         if (!poVRTBand)
     146             :         {
     147           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     148             :                      "Band is not a VRTSourcedRasterBand");
     149           0 :             return false;
     150             :         }
     151             : 
     152           3 :         for (int i = 0; i < poVRTBand->nSources; ++i)
     153             :         {
     154             :             auto poSource =
     155           2 :                 dynamic_cast<VRTSimpleSource *>(poVRTBand->papoSources[i]);
     156           2 :             if (poSource)
     157             :             {
     158             :                 VSIStatBufL sStatSource;
     159           2 :                 if (VSIStatL(poSource->GetSourceDatasetName().c_str(),
     160           2 :                              &sStatSource) == 0)
     161             :                 {
     162           2 :                     if (sStatSource.st_mtime > sStatOvr.st_mtime)
     163             :                     {
     164             :                         double dfXOff, dfYOff, dfXSize, dfYSize;
     165           1 :                         poSource->GetDstWindow(dfXOff, dfYOff, dfXSize,
     166             :                                                dfYSize);
     167           1 :                         constexpr double EPS = 1e-8;
     168           1 :                         int nXOff = static_cast<int>(dfXOff + EPS);
     169           1 :                         int nYOff = static_cast<int>(dfYOff + EPS);
     170           1 :                         int nXSize = static_cast<int>(dfXSize + 0.5);
     171           1 :                         int nYSize = static_cast<int>(dfYSize + 0.5);
     172           2 :                         if (!(nXOff > poDS->GetRasterXSize() ||
     173           1 :                               nYOff > poDS->GetRasterYSize() || nXSize <= 0 ||
     174             :                               nYSize <= 0))
     175             :                         {
     176           1 :                             if (nXOff < 0)
     177             :                             {
     178           0 :                                 nXSize += nXOff;
     179           0 :                                 nXOff = 0;
     180             :                             }
     181           1 :                             if (nXOff > poDS->GetRasterXSize() - nXSize)
     182             :                             {
     183           0 :                                 nXSize = poDS->GetRasterXSize() - nXOff;
     184             :                             }
     185           1 :                             if (nYOff < 0)
     186             :                             {
     187           0 :                                 nYSize += nYOff;
     188           0 :                                 nYOff = 0;
     189             :                             }
     190           1 :                             if (nYOff > poDS->GetRasterYSize() - nYSize)
     191             :                             {
     192           0 :                                 nYSize = poDS->GetRasterYSize() - nYOff;
     193             :                             }
     194             : 
     195           1 :                             dfTotalPixels +=
     196           1 :                                 static_cast<double>(nXSize) * nYSize;
     197           2 :                             GTISourceDesc region;
     198             :                             region.osFilename =
     199           1 :                                 poSource->GetSourceDatasetName();
     200           1 :                             region.nDstXOff = nXOff;
     201           1 :                             region.nDstYOff = nYOff;
     202           1 :                             region.nDstXSize = nXSize;
     203           1 :                             region.nDstYSize = nYSize;
     204           1 :                             regions.push_back(std::move(region));
     205             :                         }
     206             :                     }
     207             :                 }
     208             :             }
     209             :         }
     210             :     }
     211             : #ifdef GTI_DRIVER_DISABLED_OR_PLUGIN
     212             :     else if (poDS->GetDriver() &&
     213             :              EQUAL(poDS->GetDriver()->GetDescription(), "GTI"))
     214             :     {
     215             :         CPLError(CE_Failure, CPLE_NotSupported,
     216             :                  "--use-source-timestamp only works on a GTI "
     217             :                  "dataset if the GTI driver is not built as a plugin, "
     218             :                  "but in core library");
     219             :         return false;
     220             :     }
     221             : #else
     222           2 :     else if (auto poGTIDS = GDALDatasetCastToGTIDataset(poDS))
     223             :     {
     224           1 :         regions = GTIGetSourcesMoreRecentThan(poGTIDS, sStatOvr.st_mtime);
     225           2 :         for (const auto &region : regions)
     226             :         {
     227           1 :             dfTotalPixels +=
     228           1 :                 static_cast<double>(region.nDstXSize) * region.nDstYSize;
     229             :         }
     230             :     }
     231             : #endif
     232             :     else
     233             :     {
     234           1 :         CPLError(CE_Failure, CPLE_AppDefined,
     235             :                  "--use-source-timestamp only works on a VRT or GTI "
     236             :                  "dataset");
     237           1 :         return false;
     238             :     }
     239             : 
     240           2 :     bool bRet = true;
     241           2 :     if (!regions.empty())
     242             :     {
     243           2 :         double dfCurPixels = 0;
     244           4 :         for (const auto &region : regions)
     245             :         {
     246           2 :             if (bRet)
     247             :             {
     248           2 :                 CPLDebug("GDAL", "Refresh from source %s",
     249             :                          region.osFilename.c_str());
     250           2 :                 double dfNextCurPixels =
     251             :                     dfCurPixels +
     252           2 :                     static_cast<double>(region.nDstXSize) * region.nDstYSize;
     253           2 :                 void *pScaledProgress = GDALCreateScaledProgress(
     254             :                     dfCurPixels / dfTotalPixels,
     255             :                     dfNextCurPixels / dfTotalPixels, pfnProgress, pProgressArg);
     256           2 :                 bRet = PartialRefresh(
     257           2 :                     poDS, anOvrIndices, pszResampling, region.nDstXOff,
     258           2 :                     region.nDstYOff, region.nDstXSize, region.nDstYSize,
     259             :                     pScaledProgress ? GDALScaledProgress : nullptr,
     260             :                     pScaledProgress);
     261           2 :                 GDALDestroyScaledProgress(pScaledProgress);
     262           2 :                 dfCurPixels = dfNextCurPixels;
     263             :             }
     264             :         }
     265             :     }
     266             :     else
     267             :     {
     268           0 :         CPLDebug("GDAL", "No source is more recent than the overviews");
     269             :     }
     270             : 
     271           2 :     return bRet;
     272             : }
     273             : 
     274             : /************************************************************************/
     275             : /*                   PartialRefreshFromSourceExtent()                   */
     276             : /************************************************************************/
     277             : 
     278           6 : static bool PartialRefreshFromSourceExtent(
     279             :     GDALDataset *poDS, const std::vector<std::string> &sources,
     280             :     const char *pszResampling, const std::vector<int> &anOvrIndices,
     281             :     GDALProgressFunc pfnProgress, void *pProgressArg)
     282             : {
     283             :     double adfGeoTransform[6];
     284           6 :     if (poDS->GetGeoTransform(adfGeoTransform) != CE_None)
     285             :     {
     286           1 :         CPLError(CE_Failure, CPLE_AppDefined, "Dataset has no geotransform");
     287           1 :         return false;
     288             :     }
     289             :     double adfInvGT[6];
     290           5 :     if (!GDALInvGeoTransform(adfGeoTransform, adfInvGT))
     291             :     {
     292           1 :         CPLError(CE_Failure, CPLE_AppDefined, "Cannot invert geotransform");
     293           1 :         return false;
     294             :     }
     295             : 
     296             :     struct Region
     297             :     {
     298             :         std::string osFileName{};
     299             :         int nXOff = 0;
     300             :         int nYOff = 0;
     301             :         int nXSize = 0;
     302             :         int nYSize = 0;
     303             :     };
     304             : 
     305           8 :     std::vector<Region> regions;
     306             : 
     307           4 :     double dfTotalPixels = 0;
     308           6 :     for (const std::string &filename : sources)
     309             :     {
     310             :         auto poSrcDS = std::unique_ptr<GDALDataset>(GDALDataset::Open(
     311           4 :             filename.c_str(), GDAL_OF_RASTER | GDAL_OF_VERBOSE_ERROR));
     312           4 :         if (!poSrcDS)
     313           1 :             return false;
     314             : 
     315             :         double adfSrcGT[6];
     316           3 :         if (poSrcDS->GetGeoTransform(adfSrcGT) != CE_None)
     317             :         {
     318           1 :             CPLError(CE_Failure, CPLE_AppDefined,
     319             :                      "Source dataset has no geotransform");
     320           1 :             return false;
     321             :         }
     322             : 
     323           2 :         const double dfULX = adfSrcGT[0];
     324           2 :         const double dfULY = adfSrcGT[3];
     325           4 :         const double dfLRX = adfSrcGT[0] +
     326           2 :                              poSrcDS->GetRasterXSize() * adfSrcGT[1] +
     327           2 :                              poSrcDS->GetRasterYSize() * adfSrcGT[2];
     328           4 :         const double dfLRY = adfSrcGT[3] +
     329           2 :                              poSrcDS->GetRasterXSize() * adfSrcGT[4] +
     330           2 :                              poSrcDS->GetRasterYSize() * adfSrcGT[5];
     331           2 :         const double dfX1 =
     332           2 :             adfInvGT[0] + adfInvGT[1] * dfULX + adfInvGT[2] * dfULY;
     333           2 :         const double dfY1 =
     334           2 :             adfInvGT[3] + adfInvGT[4] * dfULX + adfInvGT[5] * dfULY;
     335           2 :         const double dfX2 =
     336           2 :             adfInvGT[0] + adfInvGT[1] * dfLRX + adfInvGT[2] * dfLRY;
     337           2 :         const double dfY2 =
     338           2 :             adfInvGT[3] + adfInvGT[4] * dfLRX + adfInvGT[5] * dfLRY;
     339           2 :         constexpr double EPS = 1e-8;
     340             :         const int nXOff =
     341           2 :             static_cast<int>(std::max(0.0, std::min(dfX1, dfX2)) + EPS);
     342             :         const int nYOff =
     343           2 :             static_cast<int>(std::max(0.0, std::min(dfY1, dfY2)) + EPS);
     344             :         const int nXSize =
     345           2 :             static_cast<int>(
     346           2 :                 std::ceil(std::min(static_cast<double>(poDS->GetRasterXSize()),
     347           4 :                                    std::max(dfX1, dfX2)) -
     348             :                           EPS)) -
     349           2 :             nXOff;
     350             :         const int nYSize =
     351           2 :             static_cast<int>(
     352           2 :                 std::ceil(std::min(static_cast<double>(poDS->GetRasterYSize()),
     353           4 :                                    std::max(dfY1, dfY2)) -
     354             :                           EPS)) -
     355           2 :             nYOff;
     356             : 
     357           2 :         dfTotalPixels += static_cast<double>(nXSize) * nYSize;
     358           4 :         Region region;
     359           2 :         region.osFileName = filename;
     360           2 :         region.nXOff = nXOff;
     361           2 :         region.nYOff = nYOff;
     362           2 :         region.nXSize = nXSize;
     363           2 :         region.nYSize = nYSize;
     364           2 :         regions.push_back(std::move(region));
     365             :     }
     366             : 
     367           2 :     bool bRet = true;
     368           2 :     double dfCurPixels = 0;
     369           4 :     for (const auto &region : regions)
     370             :     {
     371           2 :         if (bRet)
     372             :         {
     373           2 :             CPLDebug("GDAL", "Refresh from source %s",
     374             :                      region.osFileName.c_str());
     375           2 :             double dfNextCurPixels =
     376             :                 dfCurPixels +
     377           2 :                 static_cast<double>(region.nXSize) * region.nYSize;
     378             :             // coverity[divide_by_zero]
     379           2 :             void *pScaledProgress = GDALCreateScaledProgress(
     380             :                 dfCurPixels / dfTotalPixels, dfNextCurPixels / dfTotalPixels,
     381             :                 pfnProgress, pProgressArg);
     382             :             bRet =
     383           2 :                 PartialRefresh(poDS, anOvrIndices, pszResampling, region.nXOff,
     384           2 :                                region.nYOff, region.nXSize, region.nYSize,
     385             :                                pScaledProgress ? GDALScaledProgress : nullptr,
     386             :                                pScaledProgress);
     387           2 :             GDALDestroyScaledProgress(pScaledProgress);
     388           2 :             dfCurPixels = dfNextCurPixels;
     389             :         }
     390             :     }
     391             : 
     392           2 :     return bRet;
     393             : }
     394             : 
     395             : /************************************************************************/
     396             : /*                     PartialRefreshFromBBOX()                         */
     397             : /************************************************************************/
     398             : 
     399           3 : static bool PartialRefreshFromBBOX(GDALDataset *poDS,
     400             :                                    const std::vector<double> &bbox,
     401             :                                    const char *pszResampling,
     402             :                                    const std::vector<int> &anOvrIndices,
     403             :                                    GDALProgressFunc pfnProgress,
     404             :                                    void *pProgressArg)
     405             : {
     406           3 :     const double dfULX = bbox[0];
     407           3 :     const double dfLRY = bbox[1];
     408           3 :     const double dfLRX = bbox[2];
     409           3 :     const double dfULY = bbox[3];
     410             : 
     411             :     double adfGeoTransform[6];
     412           3 :     if (poDS->GetGeoTransform(adfGeoTransform) != CE_None)
     413             :     {
     414           1 :         CPLError(CE_Failure, CPLE_AppDefined, "Dataset has no geotransform");
     415           1 :         return false;
     416             :     }
     417             :     double adfInvGT[6];
     418           2 :     if (!GDALInvGeoTransform(adfGeoTransform, adfInvGT))
     419             :     {
     420           1 :         CPLError(CE_Failure, CPLE_AppDefined, "Cannot invert geotransform");
     421           1 :         return false;
     422             :     }
     423           1 :     const double dfX1 = adfInvGT[0] + adfInvGT[1] * dfULX + adfInvGT[2] * dfULY;
     424           1 :     const double dfY1 = adfInvGT[3] + adfInvGT[4] * dfULX + adfInvGT[5] * dfULY;
     425           1 :     const double dfX2 = adfInvGT[0] + adfInvGT[1] * dfLRX + adfInvGT[2] * dfLRY;
     426           1 :     const double dfY2 = adfInvGT[3] + adfInvGT[4] * dfLRX + adfInvGT[5] * dfLRY;
     427           1 :     constexpr double EPS = 1e-8;
     428             :     const int nXOff =
     429           1 :         static_cast<int>(std::max(0.0, std::min(dfX1, dfX2)) + EPS);
     430             :     const int nYOff =
     431           1 :         static_cast<int>(std::max(0.0, std::min(dfY1, dfY2)) + EPS);
     432           1 :     const int nXSize = static_cast<int>(std::ceil(
     433           1 :                            std::min(static_cast<double>(poDS->GetRasterXSize()),
     434           2 :                                     std::max(dfX1, dfX2)) -
     435             :                            EPS)) -
     436           1 :                        nXOff;
     437           1 :     const int nYSize = static_cast<int>(std::ceil(
     438           1 :                            std::min(static_cast<double>(poDS->GetRasterYSize()),
     439           2 :                                     std::max(dfY1, dfY2)) -
     440             :                            EPS)) -
     441           1 :                        nYOff;
     442           1 :     return PartialRefresh(poDS, anOvrIndices, pszResampling, nXOff, nYOff,
     443           1 :                           nXSize, nYSize, pfnProgress, pProgressArg);
     444             : }
     445             : 
     446             : /************************************************************************/
     447             : /*              GDALRasterOverviewAlgorithmRefresh::RunImpl()           */
     448             : /************************************************************************/
     449             : 
     450          18 : bool GDALRasterOverviewAlgorithmRefresh::RunImpl(GDALProgressFunc pfnProgress,
     451             :                                                  void *pProgressData)
     452             : {
     453          18 :     auto poDS = m_dataset.GetDatasetRef();
     454          18 :     CPLAssert(poDS);
     455          18 :     if (poDS->GetRasterCount() == 0)
     456             :     {
     457           1 :         ReportError(CE_Failure, CPLE_AppDefined, "Dataset has no raster band");
     458           1 :         return false;
     459             :     }
     460             : 
     461          17 :     auto poBand = poDS->GetRasterBand(1);
     462          17 :     const int nOvCount = poBand->GetOverviewCount();
     463             : 
     464          34 :     std::vector<int> levels = m_levels;
     465             : 
     466             :     // If no levels are specified, reuse the potentially existing ones.
     467          17 :     if (levels.empty())
     468             :     {
     469          34 :         for (int iOvr = 0; iOvr < nOvCount; ++iOvr)
     470             :         {
     471          18 :             auto poOverview = poBand->GetOverview(iOvr);
     472          18 :             if (poOverview)
     473             :             {
     474          18 :                 const int nOvFactor = GDALComputeOvFactor(
     475             :                     poOverview->GetXSize(), poBand->GetXSize(),
     476          18 :                     poOverview->GetYSize(), poBand->GetYSize());
     477          18 :                 levels.push_back(nOvFactor);
     478             :             }
     479             :         }
     480             :     }
     481          17 :     if (levels.empty())
     482             :     {
     483           1 :         ReportError(CE_Failure, CPLE_AppDefined, "No overviews to refresh");
     484           1 :         return false;
     485             :     }
     486             : 
     487          32 :     std::vector<int> anOvrIndices;
     488          34 :     for (int nLevel : levels)
     489             :     {
     490          19 :         int nIdx = -1;
     491          23 :         for (int iOvr = 0; iOvr < nOvCount; iOvr++)
     492             :         {
     493          22 :             auto poOverview = poBand->GetOverview(iOvr);
     494          22 :             if (poOverview)
     495             :             {
     496          22 :                 const int nOvFactor = GDALComputeOvFactor(
     497             :                     poOverview->GetXSize(), poBand->GetXSize(),
     498             :                     poOverview->GetYSize(), poBand->GetYSize());
     499          26 :                 if (nOvFactor == nLevel ||
     500           4 :                     nOvFactor == GDALOvLevelAdjust2(nLevel, poBand->GetXSize(),
     501             :                                                     poBand->GetYSize()))
     502             :                 {
     503          18 :                     nIdx = iOvr;
     504          18 :                     break;
     505             :                 }
     506             :             }
     507             :         }
     508          19 :         if (nIdx < 0)
     509             :         {
     510           1 :             CPLError(CE_Failure, CPLE_AppDefined,
     511             :                      "Cannot find overview level with subsampling factor of %d",
     512             :                      nLevel);
     513           1 :             return false;
     514             :         }
     515          18 :         CPLDebug("GDAL", "Refreshing overview idx %d", nIdx);
     516          18 :         anOvrIndices.push_back(nIdx);
     517             :     }
     518             : 
     519          30 :     std::string resampling = m_resampling;
     520          15 :     if (resampling.empty())
     521             :     {
     522             :         const char *pszResampling =
     523          10 :             poBand->GetOverview(0)->GetMetadataItem("RESAMPLING");
     524          10 :         if (pszResampling)
     525             :         {
     526           2 :             resampling = pszResampling;
     527           2 :             CPLDebug("GDAL",
     528             :                      "Reusing resampling method %s from existing "
     529             :                      "overview",
     530             :                      pszResampling);
     531             :         }
     532             :     }
     533          15 :     if (resampling.empty())
     534           8 :         resampling = "nearest";
     535             : 
     536          15 :     if (m_refreshFromSourceTimestamp)
     537             :     {
     538           5 :         return PartialRefreshFromSourceTimestamp(
     539           5 :             poDS, resampling.c_str(), anOvrIndices, pfnProgress, pProgressData);
     540             :     }
     541          10 :     else if (!m_refreshBbox.empty())
     542             :     {
     543           3 :         return PartialRefreshFromBBOX(poDS, m_refreshBbox, resampling.c_str(),
     544           3 :                                       anOvrIndices, pfnProgress, pProgressData);
     545             :     }
     546           7 :     else if (!m_like.empty())
     547             :     {
     548           6 :         return PartialRefreshFromSourceExtent(poDS, m_like, resampling.c_str(),
     549             :                                               anOvrIndices, pfnProgress,
     550           6 :                                               pProgressData);
     551             :     }
     552             :     else
     553             :     {
     554           1 :         return GDALBuildOverviews(
     555             :                    GDALDataset::ToHandle(poDS), resampling.c_str(),
     556           1 :                    static_cast<int>(levels.size()), levels.data(), 0, nullptr,
     557           1 :                    pfnProgress, pProgressData) == CE_None;
     558             :     }
     559             : }
     560             : 
     561             : //! @endcond

Generated by: LCOV version 1.14