LCOV - code coverage report
Current view: top level - apps - gdaladdo.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 355 440 80.7 %
Date: 2024-11-21 22:18:42 Functions: 6 10 60.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL Utilities
       4             :  * Purpose:  Command line application to build overviews.
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2000, Frank Warmerdam
       9             :  * Copyright (c) 2008-2013, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include "cpl_string.h"
      15             : #include "gdal_version.h"
      16             : #include "gdal_priv.h"
      17             : #include "commonutils.h"
      18             : #include "vrtdataset.h"
      19             : #include "vrt_priv.h"
      20             : #include "gdalargumentparser.h"
      21             : 
      22             : #include <algorithm>
      23             : 
      24             : /************************************************************************/
      25             : /*                        GDALAddoErrorHandler()                        */
      26             : /************************************************************************/
      27             : 
      28             : class GDALError
      29             : {
      30             :   public:
      31             :     CPLErr m_eErr;
      32             :     CPLErrorNum m_errNum;
      33             :     CPLString m_osMsg;
      34             : 
      35           0 :     explicit GDALError(CPLErr eErr = CE_None, CPLErrorNum errNum = CPLE_None,
      36             :                        const char *pszMsg = "")
      37           0 :         : m_eErr(eErr), m_errNum(errNum), m_osMsg(pszMsg ? pszMsg : "")
      38             :     {
      39           0 :     }
      40             : };
      41             : 
      42             : std::vector<GDALError> aoErrors;
      43             : 
      44           0 : static void CPL_STDCALL GDALAddoErrorHandler(CPLErr eErr, CPLErrorNum errNum,
      45             :                                              const char *pszMsg)
      46             : {
      47           0 :     aoErrors.push_back(GDALError(eErr, errNum, pszMsg));
      48           0 : }
      49             : 
      50             : /************************************************************************/
      51             : /*                              PartialRefresh()                        */
      52             : /************************************************************************/
      53             : 
      54           4 : static bool PartialRefresh(GDALDataset *poDS,
      55             :                            const std::vector<int> &anOvrIndices, int nBandCount,
      56             :                            const int *panBandList, const char *pszResampling,
      57             :                            int nXOff, int nYOff, int nXSize, int nYSize,
      58             :                            GDALProgressFunc pfnProgress, void *pProgressArg)
      59             : {
      60           8 :     std::vector<int> anBandList;
      61           4 :     if (nBandCount == 0)
      62             :     {
      63           8 :         for (int i = 0; i < poDS->GetRasterCount(); ++i)
      64           4 :             anBandList.push_back(i + 1);
      65           4 :         nBandCount = poDS->GetRasterCount();
      66           4 :         panBandList = anBandList.data();
      67             :     }
      68             : 
      69           4 :     int nOvCount = 0;
      70           8 :     for (int i = 0; i < nBandCount; ++i)
      71             :     {
      72           4 :         auto poSrcBand = poDS->GetRasterBand(panBandList[i]);
      73           4 :         if (i == 0)
      74           4 :             nOvCount = poSrcBand->GetOverviewCount();
      75           0 :         else if (nOvCount != poSrcBand->GetOverviewCount())
      76             :         {
      77           0 :             CPLError(CE_Failure, CPLE_AppDefined,
      78             :                      "Not same number of overviews on all bands");
      79           0 :             return false;
      80             :         }
      81             :     }
      82             : 
      83           8 :     std::vector<GDALRasterBand *> apoSrcBands;
      84           8 :     std::vector<GDALRasterBand **> apapoOverviewBands;
      85           8 :     for (int i = 0; i < nBandCount; ++i)
      86             :     {
      87           4 :         auto poSrcBand = poDS->GetRasterBand(panBandList[i]);
      88           4 :         apoSrcBands.push_back(poSrcBand);
      89           0 :         apapoOverviewBands.push_back(static_cast<GDALRasterBand **>(
      90           4 :             CPLMalloc(sizeof(GDALRasterBand *) * anOvrIndices.size())));
      91           4 :         int j = 0;
      92           8 :         for (int nOvrIdx : anOvrIndices)
      93             :         {
      94           4 :             apapoOverviewBands[i][j] = poSrcBand->GetOverview(nOvrIdx);
      95           4 :             ++j;
      96             :         }
      97             :     }
      98             : 
      99           4 :     CPLStringList aosOptions;
     100           4 :     aosOptions.SetNameValue("XOFF", CPLSPrintf("%d", nXOff));
     101           4 :     aosOptions.SetNameValue("YOFF", CPLSPrintf("%d", nYOff));
     102           4 :     aosOptions.SetNameValue("XSIZE", CPLSPrintf("%d", nXSize));
     103           4 :     aosOptions.SetNameValue("YSIZE", CPLSPrintf("%d", nYSize));
     104           4 :     bool bOK = GDALRegenerateOverviewsMultiBand(
     105           4 :                    nBandCount, apoSrcBands.data(),
     106           4 :                    static_cast<int>(anOvrIndices.size()),
     107           4 :                    apapoOverviewBands.data(), pszResampling, pfnProgress,
     108           4 :                    pProgressArg, aosOptions.List()) == CE_None;
     109           8 :     for (auto papoOverviewBands : apapoOverviewBands)
     110           4 :         CPLFree(papoOverviewBands);
     111           4 :     return bOK;
     112             : }
     113             : 
     114             : /************************************************************************/
     115             : /*                           GetOvrIndices()                            */
     116             : /************************************************************************/
     117             : 
     118           4 : static bool GetOvrIndices(GDALDataset *poDS, int nLevelCount,
     119             :                           const int *panLevels, bool bMinSizeSpecified,
     120             :                           int nMinSize, std::vector<int> &anOvrIndices)
     121             : {
     122           4 :     auto poBand = poDS->GetRasterBand(1);
     123           4 :     if (!poBand)
     124             :     {
     125           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Dataset has no bands");
     126           0 :         return false;
     127             :     }
     128           4 :     const int nOvCount = poBand->GetOverviewCount();
     129           4 :     if (nOvCount == 0)
     130             :     {
     131           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Dataset has no overviews");
     132           0 :         return false;
     133             :     }
     134             : 
     135           4 :     if (nLevelCount == 0)
     136             :     {
     137           3 :         if (!bMinSizeSpecified)
     138             :         {
     139           6 :             for (int i = 0; i < nOvCount; ++i)
     140           3 :                 anOvrIndices.push_back(i);
     141             :         }
     142             :         else
     143             :         {
     144           0 :             for (int i = 0; i < nOvCount; i++)
     145             :             {
     146           0 :                 GDALRasterBand *poOverview = poBand->GetOverview(i);
     147           0 :                 if (poOverview == nullptr)
     148           0 :                     continue;
     149           0 :                 if (poOverview->GetXSize() >= nMinSize ||
     150           0 :                     poOverview->GetYSize() >= nMinSize)
     151             :                 {
     152           0 :                     anOvrIndices.push_back(i);
     153             :                 }
     154             :             }
     155             :         }
     156             :     }
     157             :     else
     158             :     {
     159           2 :         for (int i = 0; i < nLevelCount; ++i)
     160             :         {
     161           1 :             const int nLevel = panLevels[i];
     162           1 :             int nIdx = -1;
     163           1 :             for (int j = 0; j < nOvCount; j++)
     164             :             {
     165           1 :                 GDALRasterBand *poOverview = poBand->GetOverview(j);
     166           1 :                 if (poOverview == nullptr)
     167           0 :                     continue;
     168             : 
     169           1 :                 int nOvFactor = GDALComputeOvFactor(
     170             :                     poOverview->GetXSize(), poBand->GetXSize(),
     171             :                     poOverview->GetYSize(), poBand->GetYSize());
     172             : 
     173           1 :                 if (nOvFactor == nLevel ||
     174           0 :                     nOvFactor == GDALOvLevelAdjust2(nLevel, poBand->GetXSize(),
     175             :                                                     poBand->GetYSize()))
     176             :                 {
     177           1 :                     nIdx = j;
     178           1 :                     break;
     179             :                 }
     180             :             }
     181           1 :             if (nIdx < 0)
     182             :             {
     183           0 :                 CPLError(
     184             :                     CE_Failure, CPLE_AppDefined,
     185             :                     "Cannot find overview level with subsampling factor of %d",
     186             :                     nLevel);
     187           0 :                 return false;
     188             :             }
     189           1 :             anOvrIndices.push_back(nIdx);
     190             :         }
     191             :     }
     192           4 :     return true;
     193             : }
     194             : 
     195             : /************************************************************************/
     196             : /*                   PartialRefreshFromSourceTimestamp()                */
     197             : /************************************************************************/
     198             : 
     199           2 : static bool PartialRefreshFromSourceTimestamp(
     200             :     GDALDataset *poDS, const char *pszResampling, int nLevelCount,
     201             :     const int *panLevels, int nBandCount, const int *panBandList,
     202             :     bool bMinSizeSpecified, int nMinSize, GDALProgressFunc pfnProgress,
     203             :     void *pProgressArg)
     204             : {
     205           4 :     std::vector<int> anOvrIndices;
     206           2 :     if (!GetOvrIndices(poDS, nLevelCount, panLevels, bMinSizeSpecified,
     207             :                        nMinSize, anOvrIndices))
     208           0 :         return false;
     209             : 
     210             :     VSIStatBufL sStatVRTOvr;
     211           6 :     std::string osVRTOvr(std::string(poDS->GetDescription()) + ".ovr");
     212           2 :     if (VSIStatL(osVRTOvr.c_str(), &sStatVRTOvr) != 0)
     213             :     {
     214           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Cannot find %s\n",
     215             :                  osVRTOvr.c_str());
     216           0 :         return false;
     217             :     }
     218           2 :     if (sStatVRTOvr.st_mtime == 0)
     219             :     {
     220           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     221             :                  "Cannot get modification time of %s\n", osVRTOvr.c_str());
     222           0 :         return false;
     223             :     }
     224             : 
     225           4 :     std::vector<GTISourceDesc> regions;
     226             : 
     227           2 :     double dfTotalPixels = 0;
     228             : 
     229           2 :     if (dynamic_cast<VRTDataset *>(poDS))
     230             :     {
     231             :         auto poVRTBand =
     232           1 :             dynamic_cast<VRTSourcedRasterBand *>(poDS->GetRasterBand(1));
     233           1 :         if (!poVRTBand)
     234             :         {
     235           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     236             :                      "Band is not a VRTSourcedRasterBand");
     237           0 :             return false;
     238             :         }
     239             : 
     240           3 :         for (int i = 0; i < poVRTBand->nSources; ++i)
     241             :         {
     242             :             auto poSource =
     243           2 :                 dynamic_cast<VRTSimpleSource *>(poVRTBand->papoSources[i]);
     244           2 :             if (poSource)
     245             :             {
     246             :                 VSIStatBufL sStatSource;
     247           2 :                 if (VSIStatL(poSource->GetSourceDatasetName().c_str(),
     248           2 :                              &sStatSource) == 0)
     249             :                 {
     250           2 :                     if (sStatSource.st_mtime > sStatVRTOvr.st_mtime)
     251             :                     {
     252             :                         double dfXOff, dfYOff, dfXSize, dfYSize;
     253           1 :                         poSource->GetDstWindow(dfXOff, dfYOff, dfXSize,
     254             :                                                dfYSize);
     255           1 :                         constexpr double EPS = 1e-8;
     256           1 :                         int nXOff = static_cast<int>(dfXOff + EPS);
     257           1 :                         int nYOff = static_cast<int>(dfYOff + EPS);
     258           1 :                         int nXSize = static_cast<int>(dfXSize + 0.5);
     259           1 :                         int nYSize = static_cast<int>(dfYSize + 0.5);
     260           1 :                         if (nXOff > poDS->GetRasterXSize() ||
     261           1 :                             nYOff > poDS->GetRasterYSize() || nXSize <= 0 ||
     262             :                             nYSize <= 0)
     263             :                         {
     264           0 :                             continue;
     265             :                         }
     266           1 :                         if (nXOff < 0)
     267             :                         {
     268           0 :                             nXSize += nXOff;
     269           0 :                             nXOff = 0;
     270             :                         }
     271           1 :                         if (nXOff > poDS->GetRasterXSize() - nXSize)
     272             :                         {
     273           0 :                             nXSize = poDS->GetRasterXSize() - nXOff;
     274             :                         }
     275           1 :                         if (nYOff < 0)
     276             :                         {
     277           0 :                             nYSize += nYOff;
     278           0 :                             nYOff = 0;
     279             :                         }
     280           1 :                         if (nYOff > poDS->GetRasterYSize() - nYSize)
     281             :                         {
     282           0 :                             nYSize = poDS->GetRasterYSize() - nYOff;
     283             :                         }
     284             : 
     285           1 :                         dfTotalPixels += static_cast<double>(nXSize) * nYSize;
     286           2 :                         GTISourceDesc region;
     287           1 :                         region.osFilename = poSource->GetSourceDatasetName();
     288           1 :                         region.nDstXOff = nXOff;
     289           1 :                         region.nDstYOff = nYOff;
     290           1 :                         region.nDstXSize = nXSize;
     291           1 :                         region.nDstYSize = nYSize;
     292           1 :                         regions.push_back(std::move(region));
     293             :                     }
     294             :                 }
     295             :             }
     296             :         }
     297             :     }
     298             : #ifdef GTI_DRIVER_DISABLED_OR_PLUGIN
     299             :     else if (poDS->GetDriver() &&
     300             :              EQUAL(poDS->GetDriver()->GetDescription(), "GTI"))
     301             :     {
     302             :         CPLError(CE_Failure, CPLE_NotSupported,
     303             :                  "--partial-refresh-from-source-timestamp only works on a GTI "
     304             :                  "dataset if the GTI driver is not built as a plugin, "
     305             :                  "but in core library");
     306             :         return false;
     307             :     }
     308             : #else
     309           1 :     else if (auto poGTIDS = GDALDatasetCastToGTIDataset(poDS))
     310             :     {
     311           1 :         regions = GTIGetSourcesMoreRecentThan(poGTIDS, sStatVRTOvr.st_mtime);
     312           2 :         for (const auto &region : regions)
     313             :         {
     314           1 :             dfTotalPixels +=
     315           1 :                 static_cast<double>(region.nDstXSize) * region.nDstYSize;
     316             :         }
     317             :     }
     318             : #endif
     319             :     else
     320             :     {
     321           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     322             :                  "--partial-refresh-from-source-timestamp only works on a VRT "
     323             :                  "dataset");
     324           0 :         return false;
     325             :     }
     326             : 
     327           2 :     if (!regions.empty())
     328             :     {
     329           2 :         double dfCurPixels = 0;
     330           4 :         for (const auto &region : regions)
     331             :         {
     332           2 :             if (pfnProgress == GDALDummyProgress)
     333             :             {
     334           0 :                 CPLDebug("GDAL", "Refresh from source %s",
     335             :                          region.osFilename.c_str());
     336             :             }
     337             :             else
     338             :             {
     339           2 :                 printf("Refresh from source %s.\n", region.osFilename.c_str());
     340             :             }
     341           2 :             double dfNextCurPixels =
     342             :                 dfCurPixels +
     343           2 :                 static_cast<double>(region.nDstXSize) * region.nDstYSize;
     344           2 :             void *pScaledProgress = GDALCreateScaledProgress(
     345             :                 dfCurPixels / dfTotalPixels, dfNextCurPixels / dfTotalPixels,
     346             :                 pfnProgress, pProgressArg);
     347           4 :             bool bRet = PartialRefresh(
     348             :                 poDS, anOvrIndices, nBandCount, panBandList, pszResampling,
     349           2 :                 region.nDstXOff, region.nDstYOff, region.nDstXSize,
     350           2 :                 region.nDstYSize, GDALScaledProgress, pScaledProgress);
     351           2 :             GDALDestroyScaledProgress(pScaledProgress);
     352           2 :             if (!bRet)
     353           0 :                 return false;
     354           2 :             dfCurPixels = dfNextCurPixels;
     355             :         }
     356             :     }
     357             :     else
     358             :     {
     359           0 :         if (pfnProgress == GDALDummyProgress)
     360             :         {
     361           0 :             CPLDebug("GDAL", "No source is more recent than the overviews");
     362             :         }
     363             :         else
     364             :         {
     365           0 :             printf("No source is more recent than the overviews.\n");
     366             :         }
     367             :     }
     368             : 
     369           2 :     return true;
     370             : }
     371             : 
     372             : /************************************************************************/
     373             : /*                   PartialRefreshFromSourceExtent()                   */
     374             : /************************************************************************/
     375             : 
     376           1 : static bool PartialRefreshFromSourceExtent(
     377             :     GDALDataset *poDS, const CPLStringList &aosSources,
     378             :     const char *pszResampling, int nLevelCount, const int *panLevels,
     379             :     int nBandCount, const int *panBandList, bool bMinSizeSpecified,
     380             :     int nMinSize, GDALProgressFunc pfnProgress, void *pProgressArg)
     381             : {
     382           2 :     std::vector<int> anOvrIndices;
     383           1 :     if (!GetOvrIndices(poDS, nLevelCount, panLevels, bMinSizeSpecified,
     384             :                        nMinSize, anOvrIndices))
     385           0 :         return false;
     386             : 
     387             :     double adfGeoTransform[6];
     388           1 :     if (poDS->GetGeoTransform(adfGeoTransform) != CE_None)
     389             :     {
     390           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Dataset has no geotransform");
     391           0 :         return false;
     392             :     }
     393             :     double adfInvGT[6];
     394           1 :     if (!GDALInvGeoTransform(adfGeoTransform, adfInvGT))
     395             :     {
     396           0 :         return false;
     397             :     }
     398             : 
     399             :     struct Region
     400             :     {
     401             :         std::string osFileName;
     402             :         int nXOff;
     403             :         int nYOff;
     404             :         int nXSize;
     405             :         int nYSize;
     406             :     };
     407             : 
     408           2 :     std::vector<Region> regions;
     409             : 
     410           1 :     double dfTotalPixels = 0;
     411           2 :     for (int i = 0; i < aosSources.size(); ++i)
     412             :     {
     413             :         auto poSrcDS = std::unique_ptr<GDALDataset>(GDALDataset::Open(
     414           1 :             aosSources[i], GDAL_OF_RASTER | GDAL_OF_VERBOSE_ERROR));
     415           1 :         if (!poSrcDS)
     416           0 :             return false;
     417             : 
     418             :         double adfSrcGT[6];
     419           1 :         if (poSrcDS->GetGeoTransform(adfSrcGT) != CE_None)
     420             :         {
     421           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     422             :                      "Source dataset has no geotransform");
     423           0 :             return false;
     424             :         }
     425             : 
     426           1 :         const double dfULX = adfSrcGT[0];
     427           1 :         const double dfULY = adfSrcGT[3];
     428           2 :         const double dfLRX = adfSrcGT[0] +
     429           1 :                              poSrcDS->GetRasterXSize() * adfSrcGT[1] +
     430           1 :                              poSrcDS->GetRasterYSize() * adfSrcGT[2];
     431           2 :         const double dfLRY = adfSrcGT[3] +
     432           1 :                              poSrcDS->GetRasterXSize() * adfSrcGT[4] +
     433           1 :                              poSrcDS->GetRasterYSize() * adfSrcGT[5];
     434           1 :         const double dfX1 =
     435           1 :             adfInvGT[0] + adfInvGT[1] * dfULX + adfInvGT[2] * dfULY;
     436           1 :         const double dfY1 =
     437           1 :             adfInvGT[3] + adfInvGT[4] * dfULX + adfInvGT[5] * dfULY;
     438           1 :         const double dfX2 =
     439           1 :             adfInvGT[0] + adfInvGT[1] * dfLRX + adfInvGT[2] * dfLRY;
     440           1 :         const double dfY2 =
     441           1 :             adfInvGT[3] + adfInvGT[4] * dfLRX + adfInvGT[5] * dfLRY;
     442           1 :         constexpr double EPS = 1e-8;
     443             :         const int nXOff =
     444           1 :             static_cast<int>(std::max(0.0, std::min(dfX1, dfX2)) + EPS);
     445             :         const int nYOff =
     446           1 :             static_cast<int>(std::max(0.0, std::min(dfY1, dfY2)) + EPS);
     447             :         const int nXSize =
     448           1 :             static_cast<int>(
     449           1 :                 std::ceil(std::min(static_cast<double>(poDS->GetRasterXSize()),
     450           2 :                                    std::max(dfX1, dfX2)) -
     451             :                           EPS)) -
     452           1 :             nXOff;
     453             :         const int nYSize =
     454           1 :             static_cast<int>(
     455           1 :                 std::ceil(std::min(static_cast<double>(poDS->GetRasterYSize()),
     456           2 :                                    std::max(dfY1, dfY2)) -
     457             :                           EPS)) -
     458           1 :             nYOff;
     459             : 
     460           1 :         dfTotalPixels += static_cast<double>(nXSize) * nYSize;
     461           2 :         Region region;
     462           1 :         region.osFileName = aosSources[i];
     463           1 :         region.nXOff = nXOff;
     464           1 :         region.nYOff = nYOff;
     465           1 :         region.nXSize = nXSize;
     466           1 :         region.nYSize = nYSize;
     467           1 :         regions.push_back(std::move(region));
     468             :     }
     469             : 
     470           1 :     double dfCurPixels = 0;
     471           2 :     for (const auto &region : regions)
     472             :     {
     473           1 :         if (pfnProgress == GDALDummyProgress)
     474             :         {
     475           0 :             CPLDebug("GDAL", "Refresh from source %s",
     476             :                      region.osFileName.c_str());
     477             :         }
     478             :         else
     479             :         {
     480           1 :             printf("Refresh from source %s.\n", region.osFileName.c_str());
     481             :         }
     482           1 :         double dfNextCurPixels =
     483           1 :             dfCurPixels + static_cast<double>(region.nXSize) * region.nYSize;
     484           1 :         void *pScaledProgress = GDALCreateScaledProgress(
     485             :             dfCurPixels / dfTotalPixels, dfNextCurPixels / dfTotalPixels,
     486             :             pfnProgress, pProgressArg);
     487           2 :         bool bRet = PartialRefresh(poDS, anOvrIndices, nBandCount, panBandList,
     488           1 :                                    pszResampling, region.nXOff, region.nYOff,
     489           1 :                                    region.nXSize, region.nYSize,
     490             :                                    GDALScaledProgress, pScaledProgress);
     491           1 :         GDALDestroyScaledProgress(pScaledProgress);
     492           1 :         if (!bRet)
     493           0 :             return false;
     494           1 :         dfCurPixels = dfNextCurPixels;
     495             :     }
     496             : 
     497           1 :     return true;
     498             : }
     499             : 
     500             : /************************************************************************/
     501             : /*                     PartialRefreshFromProjWin()                      */
     502             : /************************************************************************/
     503             : 
     504           1 : static bool PartialRefreshFromProjWin(
     505             :     GDALDataset *poDS, double dfULX, double dfULY, double dfLRX, double dfLRY,
     506             :     const char *pszResampling, int nLevelCount, const int *panLevels,
     507             :     int nBandCount, const int *panBandList, bool bMinSizeSpecified,
     508             :     int nMinSize, GDALProgressFunc pfnProgress, void *pProgressArg)
     509             : {
     510           2 :     std::vector<int> anOvrIndices;
     511           1 :     if (!GetOvrIndices(poDS, nLevelCount, panLevels, bMinSizeSpecified,
     512             :                        nMinSize, anOvrIndices))
     513           0 :         return false;
     514             : 
     515             :     double adfGeoTransform[6];
     516           1 :     if (poDS->GetGeoTransform(adfGeoTransform) != CE_None)
     517             :     {
     518           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Dataset has no geotransform");
     519           0 :         return false;
     520             :     }
     521             :     double adfInvGT[6];
     522           1 :     if (!GDALInvGeoTransform(adfGeoTransform, adfInvGT))
     523             :     {
     524           0 :         return false;
     525             :     }
     526           1 :     const double dfX1 = adfInvGT[0] + adfInvGT[1] * dfULX + adfInvGT[2] * dfULY;
     527           1 :     const double dfY1 = adfInvGT[3] + adfInvGT[4] * dfULX + adfInvGT[5] * dfULY;
     528           1 :     const double dfX2 = adfInvGT[0] + adfInvGT[1] * dfLRX + adfInvGT[2] * dfLRY;
     529           1 :     const double dfY2 = adfInvGT[3] + adfInvGT[4] * dfLRX + adfInvGT[5] * dfLRY;
     530           1 :     constexpr double EPS = 1e-8;
     531             :     const int nXOff =
     532           1 :         static_cast<int>(std::max(0.0, std::min(dfX1, dfX2)) + EPS);
     533             :     const int nYOff =
     534           1 :         static_cast<int>(std::max(0.0, std::min(dfY1, dfY2)) + EPS);
     535           1 :     const int nXSize = static_cast<int>(std::ceil(
     536           1 :                            std::min(static_cast<double>(poDS->GetRasterXSize()),
     537           2 :                                     std::max(dfX1, dfX2)) -
     538             :                            EPS)) -
     539           1 :                        nXOff;
     540           1 :     const int nYSize = static_cast<int>(std::ceil(
     541           1 :                            std::min(static_cast<double>(poDS->GetRasterYSize()),
     542           2 :                                     std::max(dfY1, dfY2)) -
     543             :                            EPS)) -
     544           1 :                        nYOff;
     545           1 :     return PartialRefresh(poDS, anOvrIndices, nBandCount, panBandList,
     546             :                           pszResampling, nXOff, nYOff, nXSize, nYSize,
     547           1 :                           pfnProgress, pProgressArg);
     548             : }
     549             : 
     550             : /************************************************************************/
     551             : /*                                main()                                */
     552             : /************************************************************************/
     553             : 
     554          24 : MAIN_START(nArgc, papszArgv)
     555             : 
     556             : {
     557          24 :     EarlySetConfigOptions(nArgc, papszArgv);
     558          24 :     GDALAllRegister();
     559             : 
     560          24 :     nArgc = GDALGeneralCmdLineProcessor(nArgc, &papszArgv, 0);
     561          24 :     if (nArgc < 1)
     562           0 :         exit(-nArgc);
     563          46 :     CPLStringList aosArgv;
     564          24 :     aosArgv.Assign(papszArgv, /* bAssign = */ true);
     565             : 
     566          70 :     GDALArgumentParser argParser(aosArgv[0], /* bForBinary=*/true);
     567             : 
     568          24 :     argParser.add_description(_("Builds or rebuilds overview images."));
     569             : 
     570          24 :     const char *pszEpilog = _(
     571             :         "Useful configuration variables :\n"
     572             :         "  --config USE_RRD YES : Use Erdas Imagine format (.aux) as overview "
     573             :         "format.\n"
     574             :         "Below, only for external overviews in GeoTIFF format:\n"
     575             :         "  --config COMPRESS_OVERVIEW {JPEG,LZW,PACKBITS,DEFLATE} : TIFF "
     576             :         "compression\n"
     577             :         "  --config PHOTOMETRIC_OVERVIEW {RGB,YCBCR,...} : TIFF photometric "
     578             :         "interp.\n"
     579             :         "  --config INTERLEAVE_OVERVIEW {PIXEL|BAND} : TIFF interleaving "
     580             :         "method\n"
     581             :         "  --config BIGTIFF_OVERVIEW {IF_NEEDED|IF_SAFER|YES|NO} : is BigTIFF "
     582             :         "used\n"
     583             :         "\n"
     584             :         "Examples:\n"
     585             :         " %% gdaladdo -r average abc.tif\n"
     586             :         " %% gdaladdo --config COMPRESS_OVERVIEW JPEG\n"
     587             :         "            --config PHOTOMETRIC_OVERVIEW YCBCR\n"
     588             :         "            --config INTERLEAVE_OVERVIEW PIXEL -ro abc.tif\n"
     589             :         "\n"
     590             :         "For more details, consult https://gdal.org/programs/gdaladdo.html");
     591          24 :     argParser.add_epilog(pszEpilog);
     592             : 
     593          46 :     std::string osResampling;
     594          24 :     argParser.add_argument("-r")
     595          24 :         .store_into(osResampling)
     596             :         .metavar("nearest|average|rms|gauss|bilinear|cubic|cubicspline|lanczos|"
     597          48 :                  "average_magphase|mode")
     598          24 :         .help(_("Select a resampling algorithm."));
     599             : 
     600          24 :     bool bReadOnly = false;
     601          24 :     argParser.add_argument("-ro").store_into(bReadOnly).help(
     602             :         _("Open the dataset in read-only mode, in order to generate external "
     603          24 :           "overview."));
     604             : 
     605          24 :     bool bQuiet = false;
     606          24 :     argParser.add_quiet_argument(&bQuiet);
     607             : 
     608          46 :     std::vector<int> anBandList;
     609          24 :     argParser.add_argument("-b")
     610          24 :         .append()
     611          48 :         .metavar("<band>")
     612             :         .action(
     613           0 :             [&anBandList](const std::string &s)
     614             :             {
     615           0 :                 const int nBand = atoi(s.c_str());
     616           0 :                 if (nBand < 1)
     617             :                 {
     618             :                     throw std::invalid_argument(CPLSPrintf(
     619           0 :                         "Unrecognizable band number (%s).", s.c_str()));
     620             :                 }
     621           0 :                 anBandList.push_back(nBand);
     622          24 :             })
     623          24 :         .help(_("Select input band(s) for overview generation."));
     624             : 
     625          46 :     CPLStringList aosOpenOptions;
     626          24 :     argParser.add_argument("-oo")
     627          24 :         .append()
     628          48 :         .metavar("<NAME=VALUE>")
     629           0 :         .action([&aosOpenOptions](const std::string &s)
     630          24 :                 { aosOpenOptions.AddString(s.c_str()); })
     631          24 :         .help(_("Dataset open option (format-specific)."));
     632             : 
     633          24 :     int nMinSize = 256;
     634          24 :     argParser.add_argument("-minsize")
     635          24 :         .default_value(nMinSize)
     636          48 :         .metavar("<val>")
     637          24 :         .store_into(nMinSize)
     638          24 :         .help(_("Maximum width or height of the smallest overview level."));
     639             : 
     640          24 :     bool bClean = false;
     641          24 :     bool bPartialRefreshFromSourceTimestamp = false;
     642          46 :     std::string osPartialRefreshFromSourceExtent;
     643             : 
     644             :     {
     645          24 :         auto &group = argParser.add_mutually_exclusive_group();
     646          24 :         group.add_argument("-clean").store_into(bClean).help(
     647          24 :             _("Remove all overviews."));
     648             : 
     649          24 :         group.add_argument("--partial-refresh-from-source-timestamp")
     650          24 :             .store_into(bPartialRefreshFromSourceTimestamp)
     651             :             .help(_("Performs a partial refresh of existing overviews, when "
     652          24 :                     "<filename> is a VRT file with an external overview."));
     653             : 
     654          24 :         group.add_argument("--partial-refresh-from-projwin")
     655          48 :             .metavar("<ulx> <uly> <lrx> <lry>")
     656          24 :             .nargs(4)
     657          24 :             .scan<'g', double>()
     658             :             .help(
     659             :                 _("Performs a partial refresh of existing overviews, in the "
     660          24 :                   "region of interest specified by georeference coordinates."));
     661             : 
     662          24 :         group.add_argument("--partial-refresh-from-source-extent")
     663          48 :             .metavar("<filename1>[,<filenameN>]...")
     664          24 :             .store_into(osPartialRefreshFromSourceExtent)
     665             :             .help(
     666             :                 _("Performs a partial refresh of existing overviews, in the "
     667          24 :                   "region of interest specified by one or several filename."));
     668             :     }
     669             : 
     670          46 :     std::string osFilename;
     671          24 :     argParser.add_argument("filename")
     672          24 :         .store_into(osFilename)
     673             :         .help(_("The file to build overviews for (or whose overviews must be "
     674          24 :                 "removed)."));
     675             : 
     676          48 :     argParser.add_argument("level").remaining().metavar("<level>").help(
     677          24 :         _("A list of integral overview levels to build."));
     678             : 
     679             :     try
     680             :     {
     681          24 :         argParser.parse_args(aosArgv);
     682             :     }
     683           0 :     catch (const std::exception &err)
     684             :     {
     685           0 :         argParser.display_error_and_usage(err);
     686           0 :         std::exit(1);
     687             :     }
     688             : 
     689          44 :     std::vector<int> anLevels;
     690          44 :     auto levels = argParser.present<std::vector<std::string>>("level");
     691          22 :     if (levels)
     692             :     {
     693          26 :         for (const auto &level : *levels)
     694             :         {
     695          15 :             anLevels.push_back(atoi(level.c_str()));
     696          15 :             if (anLevels.back() == 1)
     697             :             {
     698           0 :                 printf(
     699             :                     "Warning: Overview with subsampling factor of 1 requested. "
     700             :                     "This will copy the full resolution dataset in the "
     701             :                     "overview!\n");
     702             :             }
     703             :         }
     704             :     }
     705             : 
     706          22 :     GDALProgressFunc pfnProgress =
     707          22 :         bQuiet ? GDALDummyProgress : GDALTermProgress;
     708          22 :     const bool bMinSizeSpecified = argParser.is_used("-minsize");
     709             : 
     710          22 :     CPLStringList aosSources;
     711          22 :     if (!osPartialRefreshFromSourceExtent.empty())
     712             :     {
     713             :         aosSources = CSLTokenizeString2(
     714           1 :             osPartialRefreshFromSourceExtent.c_str(), ",", 0);
     715             :     }
     716             : 
     717          22 :     bool bPartialRefreshFromProjWin = false;
     718          22 :     double dfULX = 0;
     719          22 :     double dfULY = 0;
     720          22 :     double dfLRX = 0;
     721          22 :     double dfLRY = 0;
     722          22 :     if (auto oProjWin = argParser.present<std::vector<double>>(
     723          44 :             "--partial-refresh-from-projwin"))
     724             :     {
     725           1 :         bPartialRefreshFromProjWin = true;
     726           1 :         dfULX = (*oProjWin)[0];
     727           1 :         dfULY = (*oProjWin)[1];
     728           1 :         dfLRX = (*oProjWin)[2];
     729           1 :         dfLRY = (*oProjWin)[3];
     730             :     }
     731             : 
     732             :     /* -------------------------------------------------------------------- */
     733             :     /*      Open data file.                                                 */
     734             :     /* -------------------------------------------------------------------- */
     735          22 :     GDALDatasetH hDataset = nullptr;
     736          22 :     if (!bReadOnly)
     737             :     {
     738          17 :         CPLPushErrorHandler(GDALAddoErrorHandler);
     739          17 :         CPLSetCurrentErrorHandlerCatchDebug(FALSE);
     740             :         hDataset =
     741          17 :             GDALOpenEx(osFilename.c_str(), GDAL_OF_RASTER | GDAL_OF_UPDATE,
     742          17 :                        nullptr, aosOpenOptions.List(), nullptr);
     743          17 :         CPLPopErrorHandler();
     744          17 :         if (hDataset != nullptr)
     745             :         {
     746          17 :             for (size_t i = 0; i < aoErrors.size(); i++)
     747             :             {
     748           0 :                 CPLError(aoErrors[i].m_eErr, aoErrors[i].m_errNum, "%s",
     749           0 :                          aoErrors[i].m_osMsg.c_str());
     750             :             }
     751             :         }
     752             :     }
     753             : 
     754          22 :     if (hDataset == nullptr)
     755           5 :         hDataset = GDALOpenEx(osFilename.c_str(),
     756             :                               GDAL_OF_RASTER | GDAL_OF_VERBOSE_ERROR, nullptr,
     757           5 :                               aosOpenOptions.List(), nullptr);
     758          22 :     if (hDataset == nullptr)
     759           0 :         exit(2);
     760             : 
     761          22 :     if (!bClean && osResampling.empty())
     762             :     {
     763           8 :         auto poDS = GDALDataset::FromHandle(hDataset);
     764           8 :         if (poDS->GetRasterCount() > 0)
     765             :         {
     766           8 :             auto poBand = poDS->GetRasterBand(1);
     767           8 :             if (poBand->GetOverviewCount() > 0)
     768             :             {
     769             :                 const char *pszResampling =
     770           2 :                     poBand->GetOverview(0)->GetMetadataItem("RESAMPLING");
     771           2 :                 if (pszResampling)
     772             :                 {
     773           2 :                     osResampling = pszResampling;
     774           2 :                     if (pfnProgress == GDALDummyProgress)
     775           0 :                         CPLDebug("GDAL",
     776             :                                  "Reusing resampling method %s from existing "
     777             :                                  "overview",
     778             :                                  pszResampling);
     779             :                     else
     780           2 :                         printf("Info: reusing resampling method %s from "
     781             :                                "existing overview.\n",
     782             :                                pszResampling);
     783             :                 }
     784             :             }
     785             :         }
     786           8 :         if (osResampling.empty())
     787           6 :             osResampling = "nearest";
     788             :     }
     789             : 
     790             :     /* -------------------------------------------------------------------- */
     791             :     /*      Clean overviews.                                                */
     792             :     /* -------------------------------------------------------------------- */
     793          22 :     int nResultStatus = 0;
     794          22 :     void *pProgressArg = nullptr;
     795          22 :     const int nBandCount = static_cast<int>(anBandList.size());
     796          22 :     if (bClean)
     797             :     {
     798           1 :         if (GDALBuildOverviews(hDataset, "NONE", 0, nullptr, 0, nullptr,
     799           1 :                                pfnProgress, pProgressArg) != CE_None)
     800             :         {
     801           0 :             fprintf(stderr, "Cleaning overviews failed.\n");
     802           0 :             nResultStatus = 200;
     803             :         }
     804             :     }
     805          21 :     else if (bPartialRefreshFromSourceTimestamp)
     806             :     {
     807           2 :         if (!PartialRefreshFromSourceTimestamp(
     808             :                 GDALDataset::FromHandle(hDataset), osResampling.c_str(),
     809           2 :                 static_cast<int>(anLevels.size()), anLevels.data(), nBandCount,
     810           2 :                 anBandList.data(), bMinSizeSpecified, nMinSize, pfnProgress,
     811             :                 pProgressArg))
     812             :         {
     813           0 :             nResultStatus = 1;
     814             :         }
     815             :     }
     816          19 :     else if (bPartialRefreshFromProjWin)
     817             :     {
     818           1 :         if (!PartialRefreshFromProjWin(
     819             :                 GDALDataset::FromHandle(hDataset), dfULX, dfULY, dfLRX, dfLRY,
     820           1 :                 osResampling.c_str(), static_cast<int>(anLevels.size()),
     821           1 :                 anLevels.data(), nBandCount, anBandList.data(),
     822             :                 bMinSizeSpecified, nMinSize, pfnProgress, pProgressArg))
     823             :         {
     824           0 :             nResultStatus = 1;
     825             :         }
     826             :     }
     827          18 :     else if (!aosSources.empty())
     828             :     {
     829           1 :         if (!PartialRefreshFromSourceExtent(
     830             :                 GDALDataset::FromHandle(hDataset), aosSources,
     831           1 :                 osResampling.c_str(), static_cast<int>(anLevels.size()),
     832           1 :                 anLevels.data(), nBandCount, anBandList.data(),
     833             :                 bMinSizeSpecified, nMinSize, pfnProgress, pProgressArg))
     834             :         {
     835           0 :             nResultStatus = 1;
     836             :         }
     837             :     }
     838             :     else
     839             :     {
     840             :         /* --------------------------------------------------------------------
     841             :          */
     842             :         /*      Generate overviews. */
     843             :         /* --------------------------------------------------------------------
     844             :          */
     845             : 
     846             :         // If no levels are specified, reuse the potentially existing ones.
     847          17 :         if (anLevels.empty())
     848             :         {
     849           7 :             auto poDS = GDALDataset::FromHandle(hDataset);
     850           7 :             if (poDS->GetRasterCount() > 0)
     851             :             {
     852           7 :                 auto poBand = poDS->GetRasterBand(1);
     853           7 :                 const int nExistingCount = poBand->GetOverviewCount();
     854           7 :                 if (nExistingCount > 0)
     855             :                 {
     856          12 :                     for (int iOvr = 0; iOvr < nExistingCount; ++iOvr)
     857             :                     {
     858           8 :                         auto poOverview = poBand->GetOverview(iOvr);
     859           8 :                         if (poOverview)
     860             :                         {
     861           8 :                             const int nOvFactor = GDALComputeOvFactor(
     862             :                                 poOverview->GetXSize(), poBand->GetXSize(),
     863           8 :                                 poOverview->GetYSize(), poBand->GetYSize());
     864           8 :                             anLevels.push_back(nOvFactor);
     865             :                         }
     866             :                     }
     867             :                 }
     868             :             }
     869             :         }
     870             : 
     871          17 :         if (anLevels.empty())
     872             :         {
     873           3 :             const int nXSize = GDALGetRasterXSize(hDataset);
     874           3 :             const int nYSize = GDALGetRasterYSize(hDataset);
     875           3 :             int nOvrFactor = 1;
     876           9 :             while (DIV_ROUND_UP(nXSize, nOvrFactor) > nMinSize ||
     877           3 :                    DIV_ROUND_UP(nYSize, nOvrFactor) > nMinSize)
     878             :             {
     879           6 :                 nOvrFactor *= 2;
     880           6 :                 anLevels.push_back(nOvrFactor);
     881             :             }
     882             :         }
     883             : 
     884             :         // Only HFA supports selected layers
     885          17 :         if (nBandCount > 0)
     886           0 :             CPLSetConfigOption("USE_RRD", "YES");
     887             : 
     888          33 :         if (!anLevels.empty() &&
     889          16 :             GDALBuildOverviews(hDataset, osResampling.c_str(),
     890          16 :                                static_cast<int>(anLevels.size()),
     891          16 :                                anLevels.data(), nBandCount, anBandList.data(),
     892             :                                pfnProgress, pProgressArg) != CE_None)
     893             :         {
     894           0 :             fprintf(stderr, "Overview building failed.\n");
     895           0 :             nResultStatus = 100;
     896             :         }
     897             :     }
     898             : 
     899             :     /* -------------------------------------------------------------------- */
     900             :     /*      Cleanup                                                         */
     901             :     /* -------------------------------------------------------------------- */
     902          22 :     if (GDALClose(hDataset) != CE_None)
     903             :     {
     904           0 :         if (nResultStatus == 0)
     905           0 :             nResultStatus = 1;
     906             :     }
     907             : 
     908          22 :     GDALDestroyDriverManager();
     909             : 
     910          22 :     return nResultStatus;
     911             : }
     912             : 
     913           0 : MAIN_END

Generated by: LCOV version 1.14