LCOV - code coverage report
Current view: top level - gcore - gdalcomputedrasterband.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 460 491 93.7 %
Date: 2026-07-09 08:35:43 Functions: 26 27 96.3 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL
       4             :  * Purpose:  GDALComputedDataset and GDALComputedRasterBand
       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 "gdal_priv.h"
      14             : #include "vrtdataset.h"
      15             : 
      16             : #include <cmath>
      17             : #include <limits>
      18             : #include <set>
      19             : #include <utility>
      20             : 
      21             : /************************************************************************/
      22             : /*                         GDALComputedDataset                          */
      23             : /************************************************************************/
      24             : 
      25         658 : class GDALComputedDataset final : public GDALDataset
      26             : {
      27             :     friend class GDALComputedRasterBand;
      28             : 
      29             :     std::string m_expr{};
      30             :     CPLStringList m_aosOptions{};
      31             :     std::vector<std::pair<std::string, GDALRasterBand *>> m_apoBands{};
      32             :     VRTDataset m_oVRTDS;
      33             : 
      34             :     std::pair<bool, std::string> AddSourceBand(const GDALRasterBand *band);
      35             : 
      36             :     void AddSources(GDALComputedRasterBand *poBand);
      37             : 
      38             :     static const char *
      39             :     OperationToFunctionName(GDALComputedRasterBand::Operation op,
      40             :                             bool bForceMuparser = false);
      41             : 
      42             :     GDALComputedDataset &operator=(const GDALComputedDataset &) = delete;
      43             :     GDALComputedDataset(GDALComputedDataset &&) = delete;
      44             :     GDALComputedDataset &operator=(GDALComputedDataset &&) = delete;
      45             : 
      46             :   public:
      47             :     GDALComputedDataset(GDALComputedRasterBand *poBand, int nXSize, int nYSize,
      48             :                         GDALDataType eDT, int nBlockXSize, int nBlockYSize,
      49             :                         GDALComputedRasterBand::Operation op,
      50             :                         const GDALRasterBand *firstBand, double *pFirstConstant,
      51             :                         const GDALRasterBand *secondBand,
      52             :                         double *pSecondConstant);
      53             : 
      54             :     GDALComputedDataset(GDALComputedRasterBand *poBand, int nXSize, int nYSize,
      55             :                         GDALDataType eDT, int nBlockXSize, int nBlockYSize,
      56             :                         GDALComputedRasterBand::Operation op,
      57             :                         const std::vector<const GDALRasterBand *> &bands,
      58             :                         double constant);
      59             : 
      60             :     ~GDALComputedDataset() override;
      61             : 
      62           1 :     CPLErr GetGeoTransform(GDALGeoTransform &gt) const override
      63             :     {
      64           1 :         return m_oVRTDS.GetGeoTransform(gt);
      65             :     }
      66             : 
      67           1 :     const OGRSpatialReference *GetSpatialRef() const override
      68             :     {
      69           1 :         return m_oVRTDS.GetSpatialRef();
      70             :     }
      71             : 
      72           1 :     CSLConstList GetMetadata(const char *pszDomain) override
      73             :     {
      74           1 :         return m_oVRTDS.GetMetadata(pszDomain);
      75             :     }
      76             : 
      77         176 :     const char *GetMetadataItem(const char *pszName,
      78             :                                 const char *pszDomain) override
      79             :     {
      80         176 :         return m_oVRTDS.GetMetadataItem(pszName, pszDomain);
      81             :     }
      82             : 
      83           6 :     void *GetInternalHandle(const char *pszHandleName) override
      84             :     {
      85           6 :         if (pszHandleName && EQUAL(pszHandleName, "VRT_DATASET"))
      86           3 :             return &m_oVRTDS;
      87           3 :         return nullptr;
      88             :     }
      89             : };
      90             : 
      91             : /************************************************************************/
      92             : /*                        IsComparisonOperator()                        */
      93             : /************************************************************************/
      94             : 
      95         544 : static bool IsComparisonOperator(GDALComputedRasterBand::Operation op)
      96             : {
      97         544 :     switch (op)
      98             :     {
      99         288 :         case GDALComputedRasterBand::Operation::OP_GT:
     100             :         case GDALComputedRasterBand::Operation::OP_GE:
     101             :         case GDALComputedRasterBand::Operation::OP_LT:
     102             :         case GDALComputedRasterBand::Operation::OP_LE:
     103             :         case GDALComputedRasterBand::Operation::OP_EQ:
     104             :         case GDALComputedRasterBand::Operation::OP_NE:
     105             :         case GDALComputedRasterBand::Operation::OP_LOGICAL_AND:
     106             :         case GDALComputedRasterBand::Operation::OP_LOGICAL_OR:
     107         288 :             return true;
     108         256 :         default:
     109         256 :             break;
     110             :     }
     111         256 :     return false;
     112             : }
     113             : 
     114             : /************************************************************************/
     115             : /*                           AddSourceBand()                            */
     116             : /************************************************************************/
     117             : 
     118             : /** Returns a pair (bIsExprBand, osBandName) */
     119             : std::pair<bool, std::string>
     120         483 : GDALComputedDataset::AddSourceBand(const GDALRasterBand *band)
     121             : {
     122         483 :     auto bandDS = band->GetDataset();
     123         483 :     if (auto poComputedDS = dynamic_cast<GDALComputedDataset *>(bandDS))
     124             :     {
     125         151 :         m_apoBands.insert(m_apoBands.end(), poComputedDS->m_apoBands.begin(),
     126         302 :                           poComputedDS->m_apoBands.end());
     127         151 :         return {true, poComputedDS->m_expr};
     128             :     }
     129             :     else
     130             :     {
     131         332 :         std::string osName = CPLSPrintf("band_%p", band);
     132         332 :         m_apoBands.emplace_back(osName, const_cast<GDALRasterBand *>(band));
     133         332 :         return {false, osName};
     134             :     }
     135             : }
     136             : 
     137             : /************************************************************************/
     138             : /*                        GDALComputedDataset()                         */
     139             : /************************************************************************/
     140             : 
     141         292 : GDALComputedDataset::GDALComputedDataset(
     142             :     GDALComputedRasterBand *poBand, int nXSize, int nYSize, GDALDataType eDT,
     143             :     int nBlockXSize, int nBlockYSize, GDALComputedRasterBand::Operation op,
     144             :     const GDALRasterBand *firstBand, double *pFirstConstant,
     145         292 :     const GDALRasterBand *secondBand, double *pSecondConstant)
     146         292 :     : m_oVRTDS(nXSize, nYSize, nBlockXSize, nBlockYSize)
     147             : {
     148         292 :     CPLAssert(firstBand != nullptr || secondBand != nullptr);
     149         584 :     std::string osFirstBand;
     150         292 :     bool bCanUseBuiltin = true;
     151         292 :     if (firstBand)
     152             :     {
     153         540 :         const auto [bIsExprBand, name] = AddSourceBand(firstBand);
     154         270 :         bCanUseBuiltin = bCanUseBuiltin && !bIsExprBand;
     155         270 :         if (bIsExprBand)
     156          89 :             osFirstBand = "(";
     157         270 :         osFirstBand += name;
     158         270 :         if (bIsExprBand)
     159          89 :             osFirstBand += ')';
     160             :     }
     161         584 :     std::string osSecondBand;
     162         292 :     if (secondBand)
     163             :     {
     164         236 :         const auto [bIsExprBand, name] = AddSourceBand(secondBand);
     165         118 :         bCanUseBuiltin = bCanUseBuiltin && !bIsExprBand;
     166         118 :         if (bIsExprBand)
     167          33 :             osSecondBand = "(";
     168         118 :         osSecondBand += name;
     169         118 :         if (bIsExprBand)
     170          33 :             osSecondBand += ')';
     171             :     }
     172             : 
     173         292 :     nRasterXSize = nXSize;
     174         292 :     nRasterYSize = nYSize;
     175             : 
     176         292 :     if (auto poSrcDS = m_apoBands.front().second->GetDataset())
     177             :     {
     178         292 :         GDALGeoTransform gt;
     179         292 :         if (poSrcDS->GetGeoTransform(gt) == CE_None)
     180             :         {
     181         140 :             m_oVRTDS.SetGeoTransform(gt);
     182             :         }
     183             : 
     184         292 :         if (const auto *poSRS = poSrcDS->GetSpatialRef())
     185             :         {
     186         140 :             m_oVRTDS.SetSpatialRef(poSRS);
     187             :         }
     188             :     }
     189             : 
     190         292 :     if (op == GDALComputedRasterBand::Operation::OP_CAST)
     191             :     {
     192             : #ifdef DEBUG
     193             :         // Just for code coverage...
     194          24 :         CPL_IGNORE_RET_VAL(GDALComputedDataset::OperationToFunctionName(op));
     195             : #endif
     196             : 
     197          24 :         m_expr = osFirstBand;
     198          24 :         if (m_apoBands.size() > 1)
     199             :         {
     200           5 :             m_aosOptions.SetNameValue("subclass", "VRTDerivedRasterBand");
     201           5 :             m_aosOptions.SetNameValue("PixelFunctionType", "expression");
     202             :             m_aosOptions.SetNameValue("_PIXELFN_ARG_expression",
     203           5 :                                       m_expr.c_str());
     204             :         }
     205             :         else
     206             :         {
     207          19 :             m_aosOptions.SetNameValue("subclass", "VRTSourcedRasterBand");
     208             :         }
     209             :     }
     210             :     else
     211             :     {
     212         268 :         m_aosOptions.SetNameValue("subclass", "VRTDerivedRasterBand");
     213         268 :         if (IsComparisonOperator(op))
     214             :         {
     215         135 :             m_aosOptions.SetNameValue("PixelFunctionType", "expression");
     216         135 :             if (firstBand && secondBand)
     217             :             {
     218          43 :                 m_expr = osFirstBand;
     219          43 :                 m_expr += ' ';
     220          43 :                 m_expr += GDALComputedDataset::OperationToFunctionName(op);
     221          43 :                 m_expr += ' ';
     222          43 :                 m_expr += osSecondBand;
     223             :             }
     224          92 :             else if (firstBand && pSecondConstant)
     225             :             {
     226          74 :                 m_expr = osFirstBand;
     227          74 :                 m_expr += ' ';
     228          74 :                 m_expr += GDALComputedDataset::OperationToFunctionName(op);
     229          74 :                 m_expr += ' ';
     230          74 :                 m_expr += CPLSPrintf("%.17g", *pSecondConstant);
     231             :             }
     232          18 :             else if (pFirstConstant && secondBand)
     233             :             {
     234          18 :                 m_expr = CPLSPrintf("%.17g", *pFirstConstant);
     235          18 :                 m_expr += ' ';
     236          18 :                 m_expr += GDALComputedDataset::OperationToFunctionName(op);
     237          18 :                 m_expr += ' ';
     238          18 :                 m_expr += osSecondBand;
     239             :             }
     240             :             else
     241             :             {
     242           0 :                 CPLAssert(false);
     243             :             }
     244             :             m_aosOptions.SetNameValue("_PIXELFN_ARG_expression",
     245         135 :                                       m_expr.c_str());
     246             :         }
     247         133 :         else if (op == GDALComputedRasterBand::Operation::OP_SUBTRACT &&
     248             :                  pSecondConstant)
     249             :         {
     250           2 :             m_aosOptions.SetNameValue("PixelFunctionType", "sum");
     251             :             m_aosOptions.SetNameValue("_PIXELFN_ARG_k",
     252           2 :                                       CPLSPrintf("%.17g", -(*pSecondConstant)));
     253           2 :             m_expr = osFirstBand;
     254           2 :             m_expr += CPLSPrintf(" - %.17g", *pSecondConstant);
     255             :         }
     256         131 :         else if (op == GDALComputedRasterBand::Operation::OP_DIVIDE)
     257             :         {
     258           6 :             if (pSecondConstant)
     259             :             {
     260           1 :                 m_aosOptions.SetNameValue("PixelFunctionType", "mul");
     261             :                 m_aosOptions.SetNameValue(
     262             :                     "_PIXELFN_ARG_k",
     263           1 :                     CPLSPrintf("%.17g", 1.0 / (*pSecondConstant)));
     264           1 :                 m_expr = osFirstBand;
     265           1 :                 m_expr += CPLSPrintf(" * %.17g", 1.0 / (*pSecondConstant));
     266             :             }
     267           5 :             else if (pFirstConstant)
     268             :             {
     269           2 :                 m_aosOptions.SetNameValue("PixelFunctionType", "inv");
     270             :                 m_aosOptions.SetNameValue("_PIXELFN_ARG_k",
     271           2 :                                           CPLSPrintf("%.17g", *pFirstConstant));
     272           2 :                 m_expr = CPLSPrintf("%.17g / ", *pFirstConstant);
     273           2 :                 m_expr += osSecondBand;
     274             :             }
     275             :             else
     276             :             {
     277           3 :                 m_aosOptions.SetNameValue("PixelFunctionType", "div");
     278           3 :                 m_expr = osFirstBand;
     279           3 :                 m_expr += " / ";
     280           3 :                 m_expr += osSecondBand;
     281             :             }
     282             :         }
     283         125 :         else if (op == GDALComputedRasterBand::Operation::OP_LOG)
     284             :         {
     285           2 :             CPLAssert(firstBand);
     286           2 :             CPLAssert(!secondBand);
     287           2 :             CPLAssert(!pFirstConstant);
     288           2 :             CPLAssert(!pSecondConstant);
     289           2 :             m_aosOptions.SetNameValue("PixelFunctionType", "expression");
     290           2 :             m_expr = "log(";
     291           2 :             m_expr += osFirstBand;
     292           2 :             m_expr += ')';
     293             :             m_aosOptions.SetNameValue("_PIXELFN_ARG_expression",
     294           2 :                                       m_expr.c_str());
     295             :         }
     296         123 :         else if (op == GDALComputedRasterBand::Operation::OP_POW)
     297             :         {
     298           6 :             if (firstBand && secondBand)
     299             :             {
     300           2 :                 m_aosOptions.SetNameValue("PixelFunctionType", "expression");
     301           2 :                 m_expr = osFirstBand;
     302           2 :                 m_expr += " ^ ";
     303           2 :                 m_expr += osSecondBand;
     304           2 :                 m_aosOptions.SetNameValue("_PIXELFN_ARG_expression",
     305           2 :                                           m_expr.c_str());
     306             :             }
     307           4 :             else if (firstBand && pSecondConstant)
     308             :             {
     309           2 :                 m_aosOptions.SetNameValue("PixelFunctionType", "pow");
     310             :                 m_aosOptions.SetNameValue(
     311             :                     "_PIXELFN_ARG_power",
     312           2 :                     CPLSPrintf("%.17g", *pSecondConstant));
     313           2 :                 m_expr = osFirstBand;
     314           2 :                 m_expr += " ^ ";
     315           2 :                 m_expr += CPLSPrintf("%.17g", *pSecondConstant);
     316             :             }
     317           2 :             else if (pFirstConstant && secondBand)
     318             :             {
     319           2 :                 m_aosOptions.SetNameValue("PixelFunctionType", "exp");
     320             :                 m_aosOptions.SetNameValue("_PIXELFN_ARG_base",
     321           2 :                                           CPLSPrintf("%.17g", *pFirstConstant));
     322           2 :                 m_expr = CPLSPrintf("%.17g", *pFirstConstant);
     323           2 :                 m_expr += " ^ ";
     324           2 :                 m_expr += osSecondBand;
     325             :             }
     326             :             else
     327             :             {
     328           0 :                 CPLAssert(false);
     329             :             }
     330             :         }
     331             :         else
     332             :         {
     333         117 :             if (firstBand && secondBand)
     334             :             {
     335          48 :                 if (op == GDALComputedRasterBand::Operation::OP_MIN ||
     336          47 :                     op == GDALComputedRasterBand::Operation::OP_MAX ||
     337             :                     op == GDALComputedRasterBand::Operation::OP_MEAN)
     338             :                 {
     339             :                     m_expr +=
     340           1 :                         GDALComputedDataset::OperationToFunctionName(op, true);
     341           1 :                     m_expr += '(';
     342           1 :                     m_expr += osFirstBand;
     343           1 :                     m_expr += ',';
     344           1 :                     m_expr += osSecondBand;
     345           1 :                     m_expr += ')';
     346             :                 }
     347             :                 else
     348             :                 {
     349          47 :                     m_expr = osFirstBand;
     350          47 :                     m_expr += ' ';
     351             :                     m_expr +=
     352          47 :                         GDALComputedDataset::OperationToFunctionName(op, true);
     353          47 :                     m_expr += ' ';
     354          47 :                     m_expr += osSecondBand;
     355             :                 }
     356             :             }
     357          69 :             else if (firstBand && pSecondConstant)
     358             :             {
     359          62 :                 m_expr = osFirstBand;
     360          62 :                 m_expr += ' ';
     361             :                 m_expr +=
     362          62 :                     GDALComputedDataset::OperationToFunctionName(op, true);
     363          62 :                 m_expr += ' ';
     364          62 :                 m_expr += CPLSPrintf("%.17g", *pSecondConstant);
     365             :             }
     366           7 :             else if (pFirstConstant && secondBand)
     367             :             {
     368           0 :                 m_expr = CPLSPrintf("%.17g", *pFirstConstant);
     369           0 :                 m_expr += ' ';
     370             :                 m_expr +=
     371           0 :                     GDALComputedDataset::OperationToFunctionName(op, true);
     372           0 :                 m_expr += ' ';
     373           0 :                 m_expr += osSecondBand;
     374             :             }
     375             :             else
     376             :             {
     377           7 :                 m_expr = GDALComputedDataset::OperationToFunctionName(op, true);
     378           7 :                 m_expr += '(';
     379           7 :                 m_expr += osFirstBand;
     380           7 :                 m_expr += ')';
     381             :             }
     382             : 
     383         117 :             if (bCanUseBuiltin)
     384             :             {
     385             :                 m_aosOptions.SetNameValue("PixelFunctionType",
     386          51 :                                           OperationToFunctionName(op));
     387          51 :                 if (pSecondConstant)
     388             :                 {
     389             :                     m_aosOptions.SetNameValue(
     390             :                         "_PIXELFN_ARG_k",
     391          31 :                         CPLSPrintf("%.17g", *pSecondConstant));
     392             :                 }
     393             :             }
     394             :             else
     395             :             {
     396          66 :                 m_aosOptions.SetNameValue("PixelFunctionType", "expression");
     397             :                 m_aosOptions.SetNameValue("_PIXELFN_ARG_expression",
     398          66 :                                           m_expr.c_str());
     399             :             }
     400             :         }
     401             :     }
     402         292 :     m_aosOptions.SetNameValue("_PIXELFN_ARG_propagateNoData", "true");
     403         292 :     m_oVRTDS.AddBand(eDT, m_aosOptions.List());
     404             : 
     405         292 :     SetBand(1, poBand);
     406             : 
     407         292 :     AddSources(poBand);
     408             : 
     409             :     // Otherwise coverity scan suggets adding annoying std::move()s
     410         292 :     CPL_IGNORE_RET_VAL(osFirstBand);
     411         292 :     CPL_IGNORE_RET_VAL(osSecondBand);
     412         292 : }
     413             : 
     414             : /************************************************************************/
     415             : /*                        GDALComputedDataset()                         */
     416             : /************************************************************************/
     417             : 
     418          37 : GDALComputedDataset::GDALComputedDataset(
     419             :     GDALComputedRasterBand *poBand, int nXSize, int nYSize, GDALDataType eDT,
     420             :     int nBlockXSize, int nBlockYSize, GDALComputedRasterBand::Operation op,
     421          37 :     const std::vector<const GDALRasterBand *> &bands, double constant)
     422          37 :     : m_oVRTDS(nXSize, nYSize, nBlockXSize, nBlockYSize)
     423             : {
     424          37 :     bool bCanUseBuiltin = true;
     425          74 :     std::vector<std::string> aosNames;
     426         132 :     for (const GDALRasterBand *poIterBand : bands)
     427             :     {
     428         190 :         const auto [bIsExprBand, name] = AddSourceBand(poIterBand);
     429          95 :         bCanUseBuiltin = bCanUseBuiltin && !bIsExprBand;
     430          95 :         if (!bIsExprBand)
     431          66 :             aosNames.push_back(std::move(name));
     432             :         else
     433          29 :             aosNames.push_back(std::string("(").append(name).append(")"));
     434             :     }
     435             : 
     436          37 :     nRasterXSize = nXSize;
     437          37 :     nRasterYSize = nYSize;
     438             : 
     439          37 :     if (auto poSrcDS = m_apoBands.front().second->GetDataset())
     440             :     {
     441          37 :         GDALGeoTransform gt;
     442          37 :         if (poSrcDS->GetGeoTransform(gt) == CE_None)
     443             :         {
     444          16 :             m_oVRTDS.SetGeoTransform(gt);
     445             :         }
     446             : 
     447          37 :         if (const auto *poSRS = poSrcDS->GetSpatialRef())
     448             :         {
     449          16 :             m_oVRTDS.SetSpatialRef(poSRS);
     450             :         }
     451             :     }
     452             : 
     453          37 :     m_aosOptions.SetNameValue("subclass", "VRTDerivedRasterBand");
     454          37 :     if (op == GDALComputedRasterBand::Operation::OP_TERNARY)
     455             :     {
     456          18 :         m_expr = aosNames[0];
     457          18 :         m_expr += " ? ";
     458          18 :         m_expr += aosNames[1];
     459          18 :         m_expr += " : ";
     460          18 :         m_expr += aosNames[2];
     461             : 
     462          18 :         m_aosOptions.SetNameValue("PixelFunctionType", "expression");
     463          18 :         m_aosOptions.SetNameValue("_PIXELFN_ARG_expression", m_expr.c_str());
     464             :     }
     465             :     else
     466             :     {
     467          19 :         m_expr = OperationToFunctionName(op);
     468          19 :         m_expr += '(';
     469          19 :         bool first = true;
     470          60 :         for (const auto &name : aosNames)
     471             :         {
     472          41 :             if (!first)
     473          22 :                 m_expr += ", ";
     474          41 :             m_expr += name;
     475          41 :             first = false;
     476             :         }
     477          19 :         if (!std::isnan(constant))
     478             :         {
     479           8 :             if (!first)
     480           8 :                 m_expr += ", ";
     481           8 :             m_expr += CPLSPrintf("%.17g", constant);
     482             :         }
     483          19 :         m_expr += ')';
     484             : 
     485          19 :         if (bCanUseBuiltin)
     486             :         {
     487             :             m_aosOptions.SetNameValue("PixelFunctionType",
     488          14 :                                       OperationToFunctionName(op));
     489          14 :             if (!std::isnan(constant))
     490             :             {
     491             :                 m_aosOptions.SetNameValue("_PIXELFN_ARG_k",
     492           4 :                                           CPLSPrintf("%.17g", constant));
     493             :             }
     494          14 :             m_aosOptions.SetNameValue("_PIXELFN_ARG_propagateNoData", "true");
     495             :         }
     496             :         else
     497             :         {
     498           5 :             m_aosOptions.SetNameValue("PixelFunctionType", "expression");
     499             :             m_aosOptions.SetNameValue("_PIXELFN_ARG_expression",
     500           5 :                                       m_expr.c_str());
     501             :         }
     502             :     }
     503          37 :     m_oVRTDS.AddBand(eDT, m_aosOptions.List());
     504             : 
     505          37 :     SetBand(1, poBand);
     506             : 
     507          37 :     AddSources(poBand);
     508          37 : }
     509             : 
     510             : /************************************************************************/
     511             : /*                        ~GDALComputedDataset()                        */
     512             : /************************************************************************/
     513             : 
     514             : GDALComputedDataset::~GDALComputedDataset() = default;
     515             : 
     516             : /************************************************************************/
     517             : /*                    HaveAllBandsSameNoDataValue()                     */
     518             : /************************************************************************/
     519             : 
     520         462 : static bool HaveAllBandsSameNoDataValue(GDALRasterBand **apoBands,
     521             :                                         size_t nBands, bool &hasAtLeastOneNDV,
     522             :                                         double &singleNDV)
     523             : {
     524         462 :     hasAtLeastOneNDV = false;
     525         462 :     singleNDV = 0;
     526             : 
     527         462 :     int bFirstBandHasNoData = false;
     528        1867 :     for (size_t i = 0; i < nBands; ++i)
     529             :     {
     530        1411 :         int bHasNoData = false;
     531        1411 :         const double dfNoData = apoBands[i]->GetNoDataValue(&bHasNoData);
     532        1411 :         if (bHasNoData)
     533          18 :             hasAtLeastOneNDV = true;
     534        1411 :         if (i == 0)
     535             :         {
     536         462 :             bFirstBandHasNoData = bHasNoData;
     537         462 :             singleNDV = dfNoData;
     538             :         }
     539         949 :         else if (bHasNoData != bFirstBandHasNoData)
     540             :         {
     541           6 :             return false;
     542             :         }
     543         955 :         else if (bFirstBandHasNoData &&
     544           8 :                  !((std::isnan(singleNDV) && std::isnan(dfNoData)) ||
     545           6 :                    (singleNDV == dfNoData)))
     546             :         {
     547           4 :             return false;
     548             :         }
     549             :     }
     550         456 :     return true;
     551             : }
     552             : 
     553             : /************************************************************************/
     554             : /*                  GDALComputedDataset::AddSources()                   */
     555             : /************************************************************************/
     556             : 
     557         329 : void GDALComputedDataset::AddSources(GDALComputedRasterBand *poBand)
     558             : {
     559             :     auto poSourcedRasterBand =
     560         329 :         cpl::down_cast<VRTSourcedRasterBand *>(m_oVRTDS.GetRasterBand(1));
     561             : 
     562         329 :     bool hasAtLeastOneNDV = false;
     563         329 :     double singleNDV = 0;
     564         658 :     std::vector<GDALRasterBand *> apoSrcBands;
     565        1453 :     for (auto &[_, band] : m_apoBands)
     566             :     {
     567        1124 :         apoSrcBands.push_back(band);
     568             :     }
     569         329 :     const bool bSameNDV = HaveAllBandsSameNoDataValue(
     570             :         apoSrcBands.data(), m_apoBands.size(), hasAtLeastOneNDV, singleNDV);
     571             : 
     572         658 :     std::set<std::string> alreadyAdded;
     573        1453 :     for (auto &[name, band] : m_apoBands)
     574             :     {
     575        1124 :         if (alreadyAdded.insert(name).second)
     576             :         {
     577         480 :             int bHasNoData = false;
     578         480 :             const double dfNoData = band->GetNoDataValue(&bHasNoData);
     579         480 :             if (bHasNoData)
     580             :             {
     581           9 :                 poSourcedRasterBand->AddComplexSource(
     582             :                     band, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, dfNoData);
     583             :             }
     584             :             else
     585             :             {
     586         471 :                 poSourcedRasterBand->AddSimpleSource(band);
     587             :             }
     588         480 :             poSourcedRasterBand->m_papoSources.back()->SetName(name.c_str());
     589             :         }
     590             :     }
     591         329 :     if (hasAtLeastOneNDV)
     592             :     {
     593           5 :         poBand->m_bHasNoData = true;
     594           5 :         if (bSameNDV)
     595             :         {
     596           2 :             poBand->m_dfNoDataValue = singleNDV;
     597             :         }
     598             :         else
     599             :         {
     600           3 :             poBand->m_dfNoDataValue = std::numeric_limits<double>::quiet_NaN();
     601             :         }
     602           5 :         poSourcedRasterBand->SetNoDataValue(poBand->m_dfNoDataValue);
     603             :     }
     604         329 : }
     605             : 
     606             : /************************************************************************/
     607             : /*                      OperationToFunctionName()                       */
     608             : /************************************************************************/
     609             : 
     610         360 : /* static */ const char *GDALComputedDataset::OperationToFunctionName(
     611             :     GDALComputedRasterBand::Operation op, bool bForceMuparser)
     612             : {
     613         360 :     const char *ret = "";
     614         360 :     switch (op)
     615             :     {
     616          64 :         case GDALComputedRasterBand::Operation::OP_ADD:
     617          64 :             ret = bForceMuparser ? "+" : "sum";
     618          64 :             break;
     619          14 :         case GDALComputedRasterBand::Operation::OP_SUBTRACT:
     620          14 :             ret = bForceMuparser ? "-" : "diff";
     621          14 :             break;
     622          76 :         case GDALComputedRasterBand::Operation::OP_MULTIPLY:
     623          76 :             ret = bForceMuparser ? "*" : "mul";
     624          76 :             break;
     625           0 :         case GDALComputedRasterBand::Operation::OP_DIVIDE:
     626           0 :             ret = bForceMuparser ? "/" : "div";
     627           0 :             break;
     628          15 :         case GDALComputedRasterBand::Operation::OP_MIN:
     629          15 :             ret = "min";
     630          15 :             break;
     631          16 :         case GDALComputedRasterBand::Operation::OP_MAX:
     632          16 :             ret = "max";
     633          16 :             break;
     634           4 :         case GDALComputedRasterBand::Operation::OP_MEAN:
     635           4 :             ret = "mean";
     636           4 :             break;
     637          13 :         case GDALComputedRasterBand::Operation::OP_GT:
     638          13 :             ret = ">";
     639          13 :             break;
     640          16 :         case GDALComputedRasterBand::Operation::OP_GE:
     641          16 :             ret = ">=";
     642          16 :             break;
     643          13 :         case GDALComputedRasterBand::Operation::OP_LT:
     644          13 :             ret = "<";
     645          13 :             break;
     646          14 :         case GDALComputedRasterBand::Operation::OP_LE:
     647          14 :             ret = "<=";
     648          14 :             break;
     649          18 :         case GDALComputedRasterBand::Operation::OP_EQ:
     650          18 :             ret = "==";
     651          18 :             break;
     652          20 :         case GDALComputedRasterBand::Operation::OP_NE:
     653          20 :             ret = "!=";
     654          20 :             break;
     655          18 :         case GDALComputedRasterBand::Operation::OP_LOGICAL_AND:
     656          18 :             ret = "&&";
     657          18 :             break;
     658          23 :         case GDALComputedRasterBand::Operation::OP_LOGICAL_OR:
     659          23 :             ret = "||";
     660          23 :             break;
     661          24 :         case GDALComputedRasterBand::Operation::OP_CAST:
     662             :         case GDALComputedRasterBand::Operation::OP_TERNARY:
     663          24 :             break;
     664           4 :         case GDALComputedRasterBand::Operation::OP_ABS:
     665           4 :             ret = bForceMuparser ? "abs" : "mod";
     666           4 :             break;
     667           4 :         case GDALComputedRasterBand::Operation::OP_SQRT:
     668           4 :             ret = "sqrt";
     669           4 :             break;
     670           0 :         case GDALComputedRasterBand::Operation::OP_LOG:
     671           0 :             ret = "log";
     672           0 :             break;
     673           4 :         case GDALComputedRasterBand::Operation::OP_LOG10:
     674           4 :             ret = "log10";
     675           4 :             break;
     676           0 :         case GDALComputedRasterBand::Operation::OP_POW:
     677           0 :             ret = "pow";
     678           0 :             break;
     679             :     }
     680         360 :     return ret;
     681             : }
     682             : 
     683             : /************************************************************************/
     684             : /*                       GDALComputedRasterBand()                       */
     685             : /************************************************************************/
     686             : 
     687           0 : GDALComputedRasterBand::GDALComputedRasterBand(
     688           0 :     const GDALComputedRasterBand &other, bool)
     689           0 :     : GDALRasterBand()
     690             : {
     691           0 :     nRasterXSize = other.nRasterXSize;
     692           0 :     nRasterYSize = other.nRasterYSize;
     693           0 :     eDataType = other.eDataType;
     694           0 :     nBlockXSize = other.nBlockXSize;
     695           0 :     nBlockYSize = other.nBlockYSize;
     696           0 : }
     697             : 
     698             : //! @cond Doxygen_Suppress
     699             : 
     700             : /************************************************************************/
     701             : /*                       GDALComputedRasterBand()                       */
     702             : /************************************************************************/
     703             : 
     704          37 : GDALComputedRasterBand::GDALComputedRasterBand(
     705             :     Operation op, const std::vector<const GDALRasterBand *> &bands,
     706          37 :     double constant)
     707             : {
     708          37 :     CPLAssert(op == Operation::OP_ADD || op == Operation::OP_MIN ||
     709             :               op == Operation::OP_MAX || op == Operation::OP_MEAN ||
     710             :               op == Operation::OP_TERNARY);
     711             : 
     712          37 :     CPLAssert(!bands.empty());
     713          37 :     nRasterXSize = bands[0]->GetXSize();
     714          37 :     nRasterYSize = bands[0]->GetYSize();
     715          37 :     eDataType = bands[0]->GetRasterDataType();
     716          95 :     for (size_t i = 1; i < bands.size(); ++i)
     717             :     {
     718          58 :         eDataType = GDALDataTypeUnion(eDataType, bands[i]->GetRasterDataType());
     719             :     }
     720             : 
     721          37 :     bool hasAtLeastOneNDV = false;
     722          37 :     double singleNDV = 0;
     723             :     const bool bSameNDV =
     724          37 :         HaveAllBandsSameNoDataValue(const_cast<GDALRasterBand **>(bands.data()),
     725             :                                     bands.size(), hasAtLeastOneNDV, singleNDV);
     726             : 
     727          37 :     if (!bSameNDV)
     728             :     {
     729           0 :         eDataType = eDataType == GDT_Float64 ? GDT_Float64 : GDT_Float32;
     730             :     }
     731          37 :     else if (op == Operation::OP_TERNARY)
     732             :     {
     733          18 :         CPLAssert(bands.size() == 3);
     734          18 :         eDataType = GDALDataTypeUnion(bands[1]->GetRasterDataType(),
     735          18 :                                       bands[2]->GetRasterDataType());
     736             :     }
     737          19 :     else if (!std::isnan(constant) && eDataType != GDT_Float64)
     738             :     {
     739           4 :         if (op == Operation::OP_MIN || op == Operation::OP_MAX)
     740             :         {
     741           4 :             eDataType = GDALDataTypeUnionWithValue(eDataType, constant, false);
     742             :         }
     743             :         else
     744             :         {
     745           0 :             eDataType =
     746           0 :                 (static_cast<double>(static_cast<float>(constant)) == constant)
     747           0 :                     ? GDT_Float32
     748             :                     : GDT_Float64;
     749             :         }
     750             :     }
     751          37 :     bands[0]->GetBlockSize(&nBlockXSize, &nBlockYSize);
     752             :     auto l_poDS = std::make_unique<GDALComputedDataset>(
     753          37 :         this, nRasterXSize, nRasterYSize, eDataType, nBlockXSize, nBlockYSize,
     754          74 :         op, bands, constant);
     755          37 :     m_poOwningDS.reset(l_poDS.release());
     756          37 : }
     757             : 
     758             : /************************************************************************/
     759             : /*                       GDALComputedRasterBand()                       */
     760             : /************************************************************************/
     761             : 
     762          96 : GDALComputedRasterBand::GDALComputedRasterBand(Operation op,
     763             :                                                const GDALRasterBand &firstBand,
     764          96 :                                                const GDALRasterBand &secondBand)
     765             : {
     766          96 :     nRasterXSize = firstBand.GetXSize();
     767          96 :     nRasterYSize = firstBand.GetYSize();
     768             : 
     769          96 :     bool hasAtLeastOneNDV = false;
     770          96 :     double singleNDV = 0;
     771             :     GDALRasterBand *apoBands[] = {const_cast<GDALRasterBand *>(&firstBand),
     772          96 :                                   const_cast<GDALRasterBand *>(&secondBand)};
     773             :     const bool bSameNDV =
     774          96 :         HaveAllBandsSameNoDataValue(apoBands, 2, hasAtLeastOneNDV, singleNDV);
     775             : 
     776          96 :     const auto firstDT = firstBand.GetRasterDataType();
     777          96 :     const auto secondDT = secondBand.GetRasterDataType();
     778          96 :     if (!bSameNDV)
     779           6 :         eDataType = (firstDT == GDT_Float64 || secondDT == GDT_Float64)
     780           6 :                         ? GDT_Float64
     781             :                         : GDT_Float32;
     782          93 :     else if (IsComparisonOperator(op))
     783          43 :         eDataType = GDT_UInt8;
     784          50 :     else if (op == Operation::OP_ADD && firstDT == GDT_UInt8 &&
     785             :              secondDT == GDT_UInt8)
     786           3 :         eDataType = GDT_UInt16;
     787          47 :     else if (firstDT == GDT_Float32 && secondDT == GDT_Float32)
     788           5 :         eDataType = GDT_Float32;
     789          42 :     else if ((op == Operation::OP_MIN || op == Operation::OP_MAX) &&
     790             :              firstDT == secondDT)
     791           1 :         eDataType = firstDT;
     792             :     else
     793          41 :         eDataType = GDT_Float64;
     794          96 :     firstBand.GetBlockSize(&nBlockXSize, &nBlockYSize);
     795             :     auto l_poDS = std::make_unique<GDALComputedDataset>(
     796          96 :         this, nRasterXSize, nRasterYSize, eDataType, nBlockXSize, nBlockYSize,
     797         192 :         op, &firstBand, nullptr, &secondBand, nullptr);
     798          96 :     m_poOwningDS.reset(l_poDS.release());
     799          96 : }
     800             : 
     801             : /************************************************************************/
     802             : /*                       GDALComputedRasterBand()                       */
     803             : /************************************************************************/
     804             : 
     805          22 : GDALComputedRasterBand::GDALComputedRasterBand(Operation op, double constant,
     806          22 :                                                const GDALRasterBand &band)
     807             : {
     808          22 :     CPLAssert(op == Operation::OP_DIVIDE || IsComparisonOperator(op) ||
     809             :               op == Operation::OP_POW);
     810             : 
     811          22 :     nRasterXSize = band.GetXSize();
     812          22 :     nRasterYSize = band.GetYSize();
     813          22 :     const auto firstDT = band.GetRasterDataType();
     814          22 :     if (IsComparisonOperator(op))
     815          18 :         eDataType = GDT_UInt8;
     816           4 :     else if (firstDT == GDT_Float32 &&
     817           0 :              static_cast<double>(static_cast<float>(constant)) == constant)
     818           0 :         eDataType = GDT_Float32;
     819             :     else
     820           4 :         eDataType = GDT_Float64;
     821          22 :     band.GetBlockSize(&nBlockXSize, &nBlockYSize);
     822             :     auto l_poDS = std::make_unique<GDALComputedDataset>(
     823          22 :         this, nRasterXSize, nRasterYSize, eDataType, nBlockXSize, nBlockYSize,
     824          44 :         op, nullptr, &constant, &band, nullptr);
     825          22 :     m_poOwningDS.reset(l_poDS.release());
     826          22 : }
     827             : 
     828             : /************************************************************************/
     829             : /*                       GDALComputedRasterBand()                       */
     830             : /************************************************************************/
     831             : 
     832         141 : GDALComputedRasterBand::GDALComputedRasterBand(Operation op,
     833             :                                                const GDALRasterBand &band,
     834         141 :                                                double constant)
     835             : {
     836         141 :     nRasterXSize = band.GetXSize();
     837         141 :     nRasterYSize = band.GetYSize();
     838         141 :     const auto firstDT = band.GetRasterDataType();
     839         141 :     if (IsComparisonOperator(op))
     840          74 :         eDataType = GDT_UInt8;
     841          67 :     else if (op == Operation::OP_ADD && firstDT == GDT_UInt8 &&
     842          10 :              constant >= -128 && constant <= 127 &&
     843          10 :              std::floor(constant) == constant)
     844          10 :         eDataType = GDT_UInt8;
     845          57 :     else if (firstDT == GDT_Float32 &&
     846           8 :              static_cast<double>(static_cast<float>(constant)) == constant)
     847           8 :         eDataType = GDT_Float32;
     848             :     else
     849          49 :         eDataType = GDT_Float64;
     850         141 :     band.GetBlockSize(&nBlockXSize, &nBlockYSize);
     851             :     auto l_poDS = std::make_unique<GDALComputedDataset>(
     852         141 :         this, nRasterXSize, nRasterYSize, eDataType, nBlockXSize, nBlockYSize,
     853         282 :         op, &band, nullptr, nullptr, &constant);
     854         141 :     m_poOwningDS.reset(l_poDS.release());
     855         141 : }
     856             : 
     857             : /************************************************************************/
     858             : /*                       GDALComputedRasterBand()                       */
     859             : /************************************************************************/
     860             : 
     861           9 : GDALComputedRasterBand::GDALComputedRasterBand(Operation op,
     862           9 :                                                const GDALRasterBand &band)
     863             : {
     864           9 :     CPLAssert(op == Operation::OP_ABS || op == Operation::OP_SQRT ||
     865             :               op == Operation::OP_LOG || op == Operation::OP_LOG10);
     866           9 :     nRasterXSize = band.GetXSize();
     867           9 :     nRasterYSize = band.GetYSize();
     868           9 :     eDataType =
     869           9 :         band.GetRasterDataType() == GDT_Float32 ? GDT_Float32 : GDT_Float64;
     870           9 :     band.GetBlockSize(&nBlockXSize, &nBlockYSize);
     871             :     auto l_poDS = std::make_unique<GDALComputedDataset>(
     872           9 :         this, nRasterXSize, nRasterYSize, eDataType, nBlockXSize, nBlockYSize,
     873          18 :         op, &band, nullptr, nullptr, nullptr);
     874           9 :     m_poOwningDS.reset(l_poDS.release());
     875           9 : }
     876             : 
     877             : /************************************************************************/
     878             : /*                       GDALComputedRasterBand()                       */
     879             : /************************************************************************/
     880             : 
     881          24 : GDALComputedRasterBand::GDALComputedRasterBand(Operation op,
     882             :                                                const GDALRasterBand &band,
     883          24 :                                                GDALDataType dt)
     884             : {
     885          24 :     CPLAssert(op == Operation::OP_CAST);
     886          24 :     nRasterXSize = band.GetXSize();
     887          24 :     nRasterYSize = band.GetYSize();
     888          24 :     eDataType = dt;
     889          24 :     band.GetBlockSize(&nBlockXSize, &nBlockYSize);
     890             :     auto l_poDS = std::make_unique<GDALComputedDataset>(
     891          24 :         this, nRasterXSize, nRasterYSize, eDataType, nBlockXSize, nBlockYSize,
     892          48 :         op, &band, nullptr, nullptr, nullptr);
     893          24 :     m_poOwningDS.reset(l_poDS.release());
     894          24 : }
     895             : 
     896             : //! @endcond
     897             : 
     898             : /************************************************************************/
     899             : /*                      ~GDALComputedRasterBand()                       */
     900             : /************************************************************************/
     901             : 
     902         500 : GDALComputedRasterBand::~GDALComputedRasterBand()
     903             : {
     904         329 :     if (m_poOwningDS)
     905         329 :         cpl::down_cast<GDALComputedDataset *>(m_poOwningDS.get())->nBands = 0;
     906         329 :     poDS = nullptr;
     907         500 : }
     908             : 
     909             : /************************************************************************/
     910             : /*               GDALComputedRasterBand::GetNoDataValue()               */
     911             : /************************************************************************/
     912             : 
     913         480 : double GDALComputedRasterBand::GetNoDataValue(int *pbHasNoData)
     914             : {
     915         480 :     if (pbHasNoData)
     916         480 :         *pbHasNoData = m_bHasNoData;
     917         480 :     return m_dfNoDataValue;
     918             : }
     919             : 
     920             : /************************************************************************/
     921             : /*                   GDALComputedRasterBandRelease()                    */
     922             : /************************************************************************/
     923             : 
     924             : /** Release a GDALComputedRasterBandH
     925             :  *
     926             :  * @since 3.12
     927             :  */
     928         171 : void GDALComputedRasterBandRelease(GDALComputedRasterBandH hBand)
     929             : {
     930         171 :     delete GDALComputedRasterBand::FromHandle(hBand);
     931         171 : }
     932             : 
     933             : /************************************************************************/
     934             : /*                             IReadBlock()                             */
     935             : /************************************************************************/
     936             : 
     937         247 : CPLErr GDALComputedRasterBand::IReadBlock(int nBlockXOff, int nBlockYOff,
     938             :                                           void *pData)
     939             : {
     940         247 :     auto l_poDS = cpl::down_cast<GDALComputedDataset *>(poDS);
     941         247 :     return l_poDS->m_oVRTDS.GetRasterBand(1)->ReadBlock(nBlockXOff, nBlockYOff,
     942         247 :                                                         pData);
     943             : }
     944             : 
     945             : /************************************************************************/
     946             : /*                             IRasterIO()                              */
     947             : /************************************************************************/
     948             : 
     949           7 : CPLErr GDALComputedRasterBand::IRasterIO(
     950             :     GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize, int nYSize,
     951             :     void *pData, int nBufXSize, int nBufYSize, GDALDataType eBufType,
     952             :     GSpacing nPixelSpace, GSpacing nLineSpace, GDALRasterIOExtraArg *psExtraArg)
     953             : {
     954           7 :     auto l_poDS = cpl::down_cast<GDALComputedDataset *>(poDS);
     955           7 :     return l_poDS->m_oVRTDS.GetRasterBand(1)->RasterIO(
     956             :         eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
     957           7 :         eBufType, nPixelSpace, nLineSpace, psExtraArg);
     958             : }

Generated by: LCOV version 1.14