LCOV - code coverage report
Current view: top level - gcore - gdalcomputedrasterband.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 323 331 97.6 %
Date: 2025-06-19 12:30:01 Functions: 26 26 100.0 %

          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             : 
      19             : /************************************************************************/
      20             : /*                        GDALComputedDataset                           */
      21             : /************************************************************************/
      22             : 
      23        1038 : class GDALComputedDataset final : public GDALDataset
      24             : {
      25             :     friend class GDALComputedRasterBand;
      26             : 
      27             :     const GDALComputedRasterBand::Operation m_op;
      28             :     CPLStringList m_aosOptions{};
      29             :     std::vector<std::unique_ptr<GDALDataset, GDALDatasetUniquePtrReleaser>>
      30             :         m_bandDS{};
      31             :     std::vector<GDALRasterBand *> m_poBands{};
      32             :     VRTDataset m_oVRTDS;
      33             : 
      34             :     void AddSources(GDALComputedRasterBand *poBand);
      35             : 
      36             :     static const char *
      37             :     OperationToFunctionName(GDALComputedRasterBand::Operation op);
      38             : 
      39             :     GDALComputedDataset &operator=(const GDALComputedDataset &) = delete;
      40             :     GDALComputedDataset(GDALComputedDataset &&) = delete;
      41             :     GDALComputedDataset &operator=(GDALComputedDataset &&) = delete;
      42             : 
      43             :   public:
      44             :     GDALComputedDataset(const GDALComputedDataset &other);
      45             : 
      46             :     GDALComputedDataset(GDALComputedRasterBand *poBand, int nXSize, int nYSize,
      47             :                         GDALDataType eDT, int nBlockXSize, int nBlockYSize,
      48             :                         GDALComputedRasterBand::Operation op,
      49             :                         const GDALRasterBand *firstBand, double *pFirstConstant,
      50             :                         const GDALRasterBand *secondBand,
      51             :                         double *pSecondConstant);
      52             : 
      53             :     GDALComputedDataset(GDALComputedRasterBand *poBand, int nXSize, int nYSize,
      54             :                         GDALDataType eDT, int nBlockXSize, int nBlockYSize,
      55             :                         GDALComputedRasterBand::Operation op,
      56             :                         const std::vector<const GDALRasterBand *> &bands,
      57             :                         double constant);
      58             : 
      59             :     ~GDALComputedDataset() override;
      60             : 
      61          80 :     CPLErr GetGeoTransform(double *padfGeoTransform) override
      62             :     {
      63          80 :         return m_oVRTDS.GetGeoTransform(padfGeoTransform);
      64             :     }
      65             : 
      66          80 :     const OGRSpatialReference *GetSpatialRef() const override
      67             :     {
      68          80 :         return m_oVRTDS.GetSpatialRef();
      69             :     }
      70             : 
      71           1 :     char **GetMetadata(const char *pszDomain) override
      72             :     {
      73           1 :         return m_oVRTDS.GetMetadata(pszDomain);
      74             :     }
      75             : 
      76         117 :     const char *GetMetadataItem(const char *pszName,
      77             :                                 const char *pszDomain) override
      78             :     {
      79         117 :         return m_oVRTDS.GetMetadataItem(pszName, pszDomain);
      80             :     }
      81             : 
      82          46 :     void *GetInternalHandle(const char *pszHandleName) override
      83             :     {
      84          46 :         if (pszHandleName && EQUAL(pszHandleName, "VRT_DATASET"))
      85          23 :             return &m_oVRTDS;
      86          23 :         return nullptr;
      87             :     }
      88             : };
      89             : 
      90             : /************************************************************************/
      91             : /*                        IsComparisonOperator()                        */
      92             : /************************************************************************/
      93             : 
      94         367 : static bool IsComparisonOperator(GDALComputedRasterBand::Operation op)
      95             : {
      96         367 :     switch (op)
      97             :     {
      98         192 :         case GDALComputedRasterBand::Operation::OP_GT:
      99             :         case GDALComputedRasterBand::Operation::OP_GE:
     100             :         case GDALComputedRasterBand::Operation::OP_LT:
     101             :         case GDALComputedRasterBand::Operation::OP_LE:
     102             :         case GDALComputedRasterBand::Operation::OP_EQ:
     103             :         case GDALComputedRasterBand::Operation::OP_NE:
     104         192 :             return true;
     105         175 :         default:
     106         175 :             break;
     107             :     }
     108         175 :     return false;
     109             : }
     110             : 
     111             : /************************************************************************/
     112             : /*                        GDALComputedDataset()                         */
     113             : /************************************************************************/
     114             : 
     115         279 : GDALComputedDataset::GDALComputedDataset(const GDALComputedDataset &other)
     116         279 :     : GDALDataset(), m_op(other.m_op), m_aosOptions(other.m_aosOptions),
     117         279 :       m_poBands(other.m_poBands),
     118             :       m_oVRTDS(other.GetRasterXSize(), other.GetRasterYSize(),
     119         279 :                other.m_oVRTDS.GetBlockXSize(), other.m_oVRTDS.GetBlockYSize())
     120             : {
     121         279 :     nRasterXSize = other.nRasterXSize;
     122         279 :     nRasterYSize = other.nRasterYSize;
     123             : 
     124             :     auto poBand = new GDALComputedRasterBand(
     125             :         const_cast<const GDALComputedRasterBand &>(
     126         279 :             *cpl::down_cast<GDALComputedRasterBand *>(
     127             :                 const_cast<GDALComputedDataset &>(other).GetRasterBand(1))),
     128         279 :         true);
     129         279 :     SetBand(1, poBand);
     130             : 
     131             :     double adfGT[6];
     132         279 :     if (const_cast<VRTDataset &>(other.m_oVRTDS).GetGeoTransform(adfGT) ==
     133             :         CE_None)
     134             :     {
     135         226 :         m_oVRTDS.SetGeoTransform(adfGT);
     136             :     }
     137             : 
     138         279 :     if (const auto *poSRS =
     139         279 :             const_cast<VRTDataset &>(other.m_oVRTDS).GetSpatialRef())
     140             :     {
     141         226 :         m_oVRTDS.SetSpatialRef(poSRS);
     142             :     }
     143             : 
     144         279 :     m_oVRTDS.AddBand(other.m_oVRTDS.GetRasterBand(1)->GetRasterDataType(),
     145             :                      m_aosOptions.List());
     146             : 
     147         279 :     AddSources(poBand);
     148         279 : }
     149             : 
     150             : /************************************************************************/
     151             : /*                        GDALComputedDataset()                         */
     152             : /************************************************************************/
     153             : 
     154         203 : GDALComputedDataset::GDALComputedDataset(
     155             :     GDALComputedRasterBand *poBand, int nXSize, int nYSize, GDALDataType eDT,
     156             :     int nBlockXSize, int nBlockYSize, GDALComputedRasterBand::Operation op,
     157             :     const GDALRasterBand *firstBand, double *pFirstConstant,
     158         203 :     const GDALRasterBand *secondBand, double *pSecondConstant)
     159         203 :     : m_op(op), m_oVRTDS(nXSize, nYSize, nBlockXSize, nBlockYSize)
     160             : {
     161         203 :     CPLAssert(firstBand != nullptr || secondBand != nullptr);
     162         203 :     if (firstBand)
     163         189 :         m_poBands.push_back(const_cast<GDALRasterBand *>(firstBand));
     164         203 :     if (secondBand)
     165          69 :         m_poBands.push_back(const_cast<GDALRasterBand *>(secondBand));
     166             : 
     167         203 :     nRasterXSize = nXSize;
     168         203 :     nRasterYSize = nYSize;
     169             : 
     170         203 :     if (auto poSrcDS = m_poBands.front()->GetDataset())
     171             :     {
     172             :         double adfGT[6];
     173         203 :         if (poSrcDS->GetGeoTransform(adfGT) == CE_None)
     174             :         {
     175         121 :             m_oVRTDS.SetGeoTransform(adfGT);
     176             :         }
     177             : 
     178         203 :         if (const auto *poSRS = poSrcDS->GetSpatialRef())
     179             :         {
     180         121 :             m_oVRTDS.SetSpatialRef(poSRS);
     181             :         }
     182             :     }
     183             : 
     184         203 :     if (op == GDALComputedRasterBand::Operation::OP_CAST)
     185             :     {
     186             : #ifdef DEBUG
     187             :         // Just for code coverage...
     188          24 :         CPL_IGNORE_RET_VAL(GDALComputedDataset::OperationToFunctionName(op));
     189             : #endif
     190          24 :         m_aosOptions.SetNameValue("subclass", "VRTSourcedRasterBand");
     191             :     }
     192             :     else
     193             :     {
     194         179 :         m_aosOptions.SetNameValue("subclass", "VRTDerivedRasterBand");
     195         179 :         if (IsComparisonOperator(op))
     196             :         {
     197          90 :             m_aosOptions.SetNameValue("PixelFunctionType", "expression");
     198          90 :             if (firstBand && secondBand)
     199             :             {
     200          30 :                 m_aosOptions.SetNameValue(
     201             :                     "_PIXELFN_ARG_expression",
     202             :                     CPLSPrintf(
     203             :                         "source1 %s source2",
     204          30 :                         GDALComputedDataset::OperationToFunctionName(op)));
     205             :             }
     206          60 :             else if (firstBand && pSecondConstant)
     207             :             {
     208          48 :                 m_aosOptions.SetNameValue(
     209             :                     "_PIXELFN_ARG_expression",
     210             :                     CPLSPrintf("source1 %s %.17g",
     211             :                                GDALComputedDataset::OperationToFunctionName(op),
     212          48 :                                *pSecondConstant));
     213             :             }
     214          12 :             else if (pFirstConstant && secondBand)
     215             :             {
     216          12 :                 m_aosOptions.SetNameValue(
     217             :                     "_PIXELFN_ARG_expression",
     218             :                     CPLSPrintf(
     219             :                         "%.17g %s source1", *pFirstConstant,
     220          12 :                         GDALComputedDataset::OperationToFunctionName(op)));
     221             :             }
     222             :             else
     223             :             {
     224           0 :                 CPLAssert(false);
     225             :             }
     226             :         }
     227          89 :         else if (op == GDALComputedRasterBand::Operation::OP_SUBTRACT &&
     228             :                  pSecondConstant)
     229             :         {
     230           2 :             m_aosOptions.SetNameValue("PixelFunctionType", "sum");
     231           2 :             m_aosOptions.SetNameValue("_PIXELFN_ARG_k",
     232           2 :                                       CPLSPrintf("%.17g", -(*pSecondConstant)));
     233             :         }
     234          87 :         else if (op == GDALComputedRasterBand::Operation::OP_DIVIDE)
     235             :         {
     236           6 :             if (pSecondConstant)
     237             :             {
     238           2 :                 m_aosOptions.SetNameValue("PixelFunctionType", "mul");
     239             :                 m_aosOptions.SetNameValue(
     240             :                     "_PIXELFN_ARG_k",
     241           2 :                     CPLSPrintf("%.17g", 1.0 / (*pSecondConstant)));
     242             :             }
     243           4 :             else if (pFirstConstant)
     244             :             {
     245           2 :                 m_aosOptions.SetNameValue("PixelFunctionType", "inv");
     246             :                 m_aosOptions.SetNameValue("_PIXELFN_ARG_k",
     247           2 :                                           CPLSPrintf("%.17g", *pFirstConstant));
     248             :             }
     249             :             else
     250             :             {
     251           2 :                 m_aosOptions.SetNameValue("PixelFunctionType", "div");
     252             :             }
     253             :         }
     254             :         else
     255             :         {
     256             :             m_aosOptions.SetNameValue("PixelFunctionType",
     257          81 :                                       OperationToFunctionName(op));
     258          81 :             if (pSecondConstant)
     259             :                 m_aosOptions.SetNameValue(
     260          58 :                     "_PIXELFN_ARG_k", CPLSPrintf("%.17g", *pSecondConstant));
     261             :         }
     262             :     }
     263         203 :     m_aosOptions.SetNameValue("_PIXELFN_ARG_propagateNoData", "true");
     264         203 :     m_oVRTDS.AddBand(eDT, m_aosOptions.List());
     265             : 
     266         203 :     SetBand(1, poBand);
     267             : 
     268         203 :     AddSources(poBand);
     269         203 : }
     270             : 
     271             : /************************************************************************/
     272             : /*                        GDALComputedDataset()                         */
     273             : /************************************************************************/
     274             : 
     275          37 : GDALComputedDataset::GDALComputedDataset(
     276             :     GDALComputedRasterBand *poBand, int nXSize, int nYSize, GDALDataType eDT,
     277             :     int nBlockXSize, int nBlockYSize, GDALComputedRasterBand::Operation op,
     278          37 :     const std::vector<const GDALRasterBand *> &bands, double constant)
     279          37 :     : m_op(op), m_oVRTDS(nXSize, nYSize, nBlockXSize, nBlockYSize)
     280             : {
     281         132 :     for (const GDALRasterBand *poIterBand : bands)
     282          95 :         m_poBands.push_back(const_cast<GDALRasterBand *>(poIterBand));
     283             : 
     284          37 :     nRasterXSize = nXSize;
     285          37 :     nRasterYSize = nYSize;
     286             : 
     287          37 :     if (auto poSrcDS = m_poBands.front()->GetDataset())
     288             :     {
     289             :         double adfGT[6];
     290          37 :         if (poSrcDS->GetGeoTransform(adfGT) == CE_None)
     291             :         {
     292          16 :             m_oVRTDS.SetGeoTransform(adfGT);
     293             :         }
     294             : 
     295          37 :         if (const auto *poSRS = poSrcDS->GetSpatialRef())
     296             :         {
     297          16 :             m_oVRTDS.SetSpatialRef(poSRS);
     298             :         }
     299             :     }
     300             : 
     301          37 :     m_aosOptions.SetNameValue("subclass", "VRTDerivedRasterBand");
     302          37 :     if (op == GDALComputedRasterBand::Operation::OP_TERNARY)
     303             :     {
     304          18 :         m_aosOptions.SetNameValue("PixelFunctionType", "expression");
     305             :         m_aosOptions.SetNameValue("_PIXELFN_ARG_expression",
     306          18 :                                   "source1 ? source2 : source3");
     307             :     }
     308             :     else
     309             :     {
     310             :         m_aosOptions.SetNameValue("PixelFunctionType",
     311          19 :                                   OperationToFunctionName(op));
     312          19 :         if (!std::isnan(constant))
     313             :         {
     314             :             m_aosOptions.SetNameValue("_PIXELFN_ARG_k",
     315           8 :                                       CPLSPrintf("%.17g", constant));
     316             :         }
     317          19 :         m_aosOptions.SetNameValue("_PIXELFN_ARG_propagateNoData", "true");
     318             :     }
     319          37 :     m_oVRTDS.AddBand(eDT, m_aosOptions.List());
     320             : 
     321          37 :     SetBand(1, poBand);
     322             : 
     323          37 :     AddSources(poBand);
     324          37 : }
     325             : 
     326             : /************************************************************************/
     327             : /*                       ~GDALComputedDataset()                         */
     328             : /************************************************************************/
     329             : 
     330             : GDALComputedDataset::~GDALComputedDataset() = default;
     331             : 
     332             : /************************************************************************/
     333             : /*                       HaveAllBandsSameNoDataValue()                  */
     334             : /************************************************************************/
     335             : 
     336         611 : static bool HaveAllBandsSameNoDataValue(GDALRasterBand **apoBands,
     337             :                                         size_t nBands, bool &hasAtLeastOneNDV,
     338             :                                         double &singleNDV)
     339             : {
     340         611 :     hasAtLeastOneNDV = false;
     341         611 :     singleNDV = 0;
     342             : 
     343         611 :     int bFirstBandHasNoData = false;
     344        1501 :     for (size_t i = 0; i < nBands; ++i)
     345             :     {
     346         896 :         int bHasNoData = false;
     347         896 :         const double dfNoData = apoBands[i]->GetNoDataValue(&bHasNoData);
     348         896 :         if (bHasNoData)
     349          18 :             hasAtLeastOneNDV = true;
     350         896 :         if (i == 0)
     351             :         {
     352         611 :             bFirstBandHasNoData = bHasNoData;
     353         611 :             singleNDV = dfNoData;
     354             :         }
     355         285 :         else if (bHasNoData != bFirstBandHasNoData)
     356             :         {
     357           6 :             return false;
     358             :         }
     359         291 :         else if (bFirstBandHasNoData &&
     360           8 :                  !((std::isnan(singleNDV) && std::isnan(dfNoData)) ||
     361           6 :                    (singleNDV == dfNoData)))
     362             :         {
     363           4 :             return false;
     364             :         }
     365             :     }
     366         605 :     return true;
     367             : }
     368             : 
     369             : /************************************************************************/
     370             : /*                  GDALComputedDataset::AddSources()                   */
     371             : /************************************************************************/
     372             : 
     373         519 : void GDALComputedDataset::AddSources(GDALComputedRasterBand *poBand)
     374             : {
     375             :     auto poSourcedRasterBand =
     376         519 :         cpl::down_cast<VRTSourcedRasterBand *>(m_oVRTDS.GetRasterBand(1));
     377             : 
     378         519 :     bool hasAtLeastOneNDV = false;
     379         519 :     double singleNDV = 0;
     380         519 :     const bool bSameNDV = HaveAllBandsSameNoDataValue(
     381             :         m_poBands.data(), m_poBands.size(), hasAtLeastOneNDV, singleNDV);
     382             : 
     383             :     // For inputs that are instances of GDALComputedDataset, clone them
     384             :     // to make sure we do not depend on temporary instances,
     385             :     // such as "a + b + c", which is evaluated as "(a + b) + c", and the
     386             :     // temporary band/dataset corresponding to a + b will go out of scope
     387             :     // quickly.
     388        1210 :     for (GDALRasterBand *&band : m_poBands)
     389             :     {
     390         691 :         auto poDS = band->GetDataset();
     391         691 :         if (auto poComputedDS = dynamic_cast<GDALComputedDataset *>(poDS))
     392             :         {
     393             :             auto poComputedDSNew =
     394         279 :                 std::make_unique<GDALComputedDataset>(*poComputedDS);
     395         279 :             band = poComputedDSNew->GetRasterBand(1);
     396         279 :             m_bandDS.emplace_back(poComputedDSNew.release());
     397             :         }
     398             : 
     399         691 :         int bHasNoData = false;
     400         691 :         const double dfNoData = band->GetNoDataValue(&bHasNoData);
     401         691 :         if (bHasNoData)
     402             :         {
     403           9 :             poSourcedRasterBand->AddComplexSource(band, -1, -1, -1, -1, -1, -1,
     404             :                                                   -1, -1, 0, 1, dfNoData);
     405             :         }
     406             :         else
     407             :         {
     408         682 :             poSourcedRasterBand->AddSimpleSource(band);
     409             :         }
     410         691 :         poSourcedRasterBand->papoSources[poSourcedRasterBand->nSources - 1]
     411         691 :             ->SetName(CPLSPrintf("source%d", poSourcedRasterBand->nSources));
     412             :     }
     413         519 :     if (hasAtLeastOneNDV)
     414             :     {
     415           5 :         poBand->m_bHasNoData = true;
     416           5 :         if (bSameNDV)
     417             :         {
     418           2 :             poBand->m_dfNoDataValue = singleNDV;
     419             :         }
     420             :         else
     421             :         {
     422           3 :             poBand->m_dfNoDataValue = std::numeric_limits<double>::quiet_NaN();
     423             :         }
     424           5 :         poSourcedRasterBand->SetNoDataValue(poBand->m_dfNoDataValue);
     425             :     }
     426         519 : }
     427             : 
     428             : /************************************************************************/
     429             : /*                       OperationToFunctionName()                      */
     430             : /************************************************************************/
     431             : 
     432         214 : /* static */ const char *GDALComputedDataset::OperationToFunctionName(
     433             :     GDALComputedRasterBand::Operation op)
     434             : {
     435         214 :     const char *ret = "";
     436         214 :     switch (op)
     437             :     {
     438          39 :         case GDALComputedRasterBand::Operation::OP_ADD:
     439          39 :             ret = "sum";
     440          39 :             break;
     441           3 :         case GDALComputedRasterBand::Operation::OP_SUBTRACT:
     442           3 :             ret = "diff";
     443           3 :             break;
     444          38 :         case GDALComputedRasterBand::Operation::OP_MULTIPLY:
     445          38 :             ret = "mul";
     446          38 :             break;
     447           0 :         case GDALComputedRasterBand::Operation::OP_DIVIDE:
     448           0 :             ret = "div";
     449           0 :             break;
     450           9 :         case GDALComputedRasterBand::Operation::OP_MIN:
     451           9 :             ret = "min";
     452           9 :             break;
     453           9 :         case GDALComputedRasterBand::Operation::OP_MAX:
     454           9 :             ret = "max";
     455           9 :             break;
     456           2 :         case GDALComputedRasterBand::Operation::OP_MEAN:
     457           2 :             ret = "mean";
     458           2 :             break;
     459          13 :         case GDALComputedRasterBand::Operation::OP_GT:
     460          13 :             ret = ">";
     461          13 :             break;
     462          16 :         case GDALComputedRasterBand::Operation::OP_GE:
     463          16 :             ret = ">=";
     464          16 :             break;
     465          13 :         case GDALComputedRasterBand::Operation::OP_LT:
     466          13 :             ret = "<";
     467          13 :             break;
     468          14 :         case GDALComputedRasterBand::Operation::OP_LE:
     469          14 :             ret = "<=";
     470          14 :             break;
     471          18 :         case GDALComputedRasterBand::Operation::OP_EQ:
     472          18 :             ret = "==";
     473          18 :             break;
     474          16 :         case GDALComputedRasterBand::Operation::OP_NE:
     475          16 :             ret = "!=";
     476          16 :             break;
     477          24 :         case GDALComputedRasterBand::Operation::OP_CAST:
     478             :         case GDALComputedRasterBand::Operation::OP_TERNARY:
     479          24 :             break;
     480             :     }
     481         214 :     return ret;
     482             : }
     483             : 
     484             : /************************************************************************/
     485             : /*                       GDALComputedRasterBand()                       */
     486             : /************************************************************************/
     487             : 
     488         279 : GDALComputedRasterBand::GDALComputedRasterBand(
     489         279 :     const GDALComputedRasterBand &other, bool)
     490         279 :     : GDALRasterBand()
     491             : {
     492         279 :     nRasterXSize = other.nRasterXSize;
     493         279 :     nRasterYSize = other.nRasterYSize;
     494         279 :     eDataType = other.eDataType;
     495         279 :     nBlockXSize = other.nBlockXSize;
     496         279 :     nBlockYSize = other.nBlockYSize;
     497         279 : }
     498             : 
     499             : //! @cond Doxygen_Suppress
     500             : 
     501             : /************************************************************************/
     502             : /*                       GDALComputedRasterBand()                       */
     503             : /************************************************************************/
     504             : 
     505          37 : GDALComputedRasterBand::GDALComputedRasterBand(
     506             :     Operation op, const std::vector<const GDALRasterBand *> &bands,
     507          37 :     double constant)
     508             : {
     509          37 :     CPLAssert(op == Operation::OP_ADD || op == Operation::OP_MIN ||
     510             :               op == Operation::OP_MAX || op == Operation::OP_MEAN ||
     511             :               op == Operation::OP_TERNARY);
     512             : 
     513          37 :     CPLAssert(!bands.empty());
     514          37 :     nRasterXSize = bands[0]->GetXSize();
     515          37 :     nRasterYSize = bands[0]->GetYSize();
     516          37 :     eDataType = bands[0]->GetRasterDataType();
     517          95 :     for (size_t i = 1; i < bands.size(); ++i)
     518             :     {
     519          58 :         eDataType = GDALDataTypeUnion(eDataType, bands[i]->GetRasterDataType());
     520             :     }
     521             : 
     522          37 :     bool hasAtLeastOneNDV = false;
     523          37 :     double singleNDV = 0;
     524             :     const bool bSameNDV =
     525          37 :         HaveAllBandsSameNoDataValue(const_cast<GDALRasterBand **>(bands.data()),
     526             :                                     bands.size(), hasAtLeastOneNDV, singleNDV);
     527             : 
     528          37 :     if (!bSameNDV)
     529             :     {
     530           0 :         eDataType = eDataType == GDT_Float64 ? GDT_Float64 : GDT_Float32;
     531             :     }
     532          37 :     else if (op == Operation::OP_TERNARY)
     533             :     {
     534          18 :         CPLAssert(bands.size() == 3);
     535          18 :         eDataType = GDALDataTypeUnion(bands[1]->GetRasterDataType(),
     536          18 :                                       bands[2]->GetRasterDataType());
     537             :     }
     538          19 :     else if (!std::isnan(constant) && eDataType != GDT_Float64)
     539             :     {
     540           4 :         if (op == Operation::OP_MIN || op == Operation::OP_MAX)
     541             :         {
     542           4 :             eDataType = GDALDataTypeUnionWithValue(eDataType, constant, false);
     543             :         }
     544             :         else
     545             :         {
     546           0 :             eDataType = (static_cast<float>(constant) == constant)
     547           0 :                             ? GDT_Float32
     548             :                             : GDT_Float64;
     549             :         }
     550             :     }
     551          37 :     bands[0]->GetBlockSize(&nBlockXSize, &nBlockYSize);
     552             :     auto l_poDS = std::make_unique<GDALComputedDataset>(
     553          37 :         this, nRasterXSize, nRasterYSize, eDataType, nBlockXSize, nBlockYSize,
     554          74 :         op, bands, constant);
     555          37 :     m_poOwningDS.reset(l_poDS.release());
     556          37 : }
     557             : 
     558             : /************************************************************************/
     559             : /*                       GDALComputedRasterBand()                       */
     560             : /************************************************************************/
     561             : 
     562          55 : GDALComputedRasterBand::GDALComputedRasterBand(Operation op,
     563             :                                                const GDALRasterBand &firstBand,
     564          55 :                                                const GDALRasterBand &secondBand)
     565             : {
     566          55 :     nRasterXSize = firstBand.GetXSize();
     567          55 :     nRasterYSize = firstBand.GetYSize();
     568             : 
     569          55 :     bool hasAtLeastOneNDV = false;
     570          55 :     double singleNDV = 0;
     571             :     GDALRasterBand *apoBands[] = {const_cast<GDALRasterBand *>(&firstBand),
     572          55 :                                   const_cast<GDALRasterBand *>(&secondBand)};
     573             :     const bool bSameNDV =
     574          55 :         HaveAllBandsSameNoDataValue(apoBands, 2, hasAtLeastOneNDV, singleNDV);
     575             : 
     576          55 :     const auto firstDT = firstBand.GetRasterDataType();
     577          55 :     const auto secondDT = secondBand.GetRasterDataType();
     578          55 :     if (!bSameNDV)
     579           6 :         eDataType = (firstDT == GDT_Float64 || secondDT == GDT_Float64)
     580           6 :                         ? GDT_Float64
     581             :                         : GDT_Float32;
     582          52 :     else if (IsComparisonOperator(op))
     583          30 :         eDataType = GDT_Byte;
     584          22 :     else if (op == Operation::OP_ADD && firstDT == GDT_Byte &&
     585             :              secondDT == GDT_Byte)
     586           2 :         eDataType = GDT_UInt16;
     587          20 :     else if (firstDT == GDT_Float32 && secondDT == GDT_Float32)
     588           1 :         eDataType = GDT_Float32;
     589          19 :     else if ((op == Operation::OP_MIN || op == Operation::OP_MAX) &&
     590             :              firstDT == secondDT)
     591           1 :         eDataType = firstDT;
     592             :     else
     593          18 :         eDataType = GDT_Float64;
     594          55 :     firstBand.GetBlockSize(&nBlockXSize, &nBlockYSize);
     595             :     auto l_poDS = std::make_unique<GDALComputedDataset>(
     596          55 :         this, nRasterXSize, nRasterYSize, eDataType, nBlockXSize, nBlockYSize,
     597         110 :         op, &firstBand, nullptr, &secondBand, nullptr);
     598          55 :     m_poOwningDS.reset(l_poDS.release());
     599          55 : }
     600             : 
     601             : /************************************************************************/
     602             : /*                       GDALComputedRasterBand()                       */
     603             : /************************************************************************/
     604             : 
     605          14 : GDALComputedRasterBand::GDALComputedRasterBand(Operation op, double constant,
     606          14 :                                                const GDALRasterBand &band)
     607             : {
     608          14 :     CPLAssert(op == Operation::OP_DIVIDE || IsComparisonOperator(op));
     609             : 
     610          14 :     nRasterXSize = band.GetXSize();
     611          14 :     nRasterYSize = band.GetYSize();
     612          14 :     const auto firstDT = band.GetRasterDataType();
     613          14 :     if (IsComparisonOperator(op))
     614          12 :         eDataType = GDT_Byte;
     615           2 :     else if (firstDT == GDT_Float32 && static_cast<float>(constant) == constant)
     616           0 :         eDataType = GDT_Float32;
     617             :     else
     618           2 :         eDataType = GDT_Float64;
     619          14 :     band.GetBlockSize(&nBlockXSize, &nBlockYSize);
     620             :     auto l_poDS = std::make_unique<GDALComputedDataset>(
     621          14 :         this, nRasterXSize, nRasterYSize, eDataType, nBlockXSize, nBlockYSize,
     622          28 :         op, nullptr, &constant, &band, nullptr);
     623          14 :     m_poOwningDS.reset(l_poDS.release());
     624          14 : }
     625             : 
     626             : /************************************************************************/
     627             : /*                       GDALComputedRasterBand()                       */
     628             : /************************************************************************/
     629             : 
     630         110 : GDALComputedRasterBand::GDALComputedRasterBand(Operation op,
     631             :                                                const GDALRasterBand &band,
     632         110 :                                                double constant)
     633             : {
     634         110 :     nRasterXSize = band.GetXSize();
     635         110 :     nRasterYSize = band.GetYSize();
     636         110 :     const auto firstDT = band.GetRasterDataType();
     637         110 :     if (IsComparisonOperator(op))
     638          48 :         eDataType = GDT_Byte;
     639          62 :     else if (op == Operation::OP_ADD && firstDT == GDT_Byte &&
     640          10 :              constant >= -128 && constant <= 127 &&
     641          10 :              std::floor(constant) == constant)
     642          10 :         eDataType = GDT_Byte;
     643          52 :     else if (firstDT == GDT_Float32 && static_cast<float>(constant) == constant)
     644           8 :         eDataType = GDT_Float32;
     645             :     else
     646          44 :         eDataType = GDT_Float64;
     647         110 :     band.GetBlockSize(&nBlockXSize, &nBlockYSize);
     648             :     auto l_poDS = std::make_unique<GDALComputedDataset>(
     649         110 :         this, nRasterXSize, nRasterYSize, eDataType, nBlockXSize, nBlockYSize,
     650         220 :         op, &band, nullptr, nullptr, &constant);
     651         110 :     m_poOwningDS.reset(l_poDS.release());
     652         110 : }
     653             : 
     654             : /************************************************************************/
     655             : /*                       GDALComputedRasterBand()                       */
     656             : /************************************************************************/
     657             : 
     658          24 : GDALComputedRasterBand::GDALComputedRasterBand(Operation op,
     659             :                                                const GDALRasterBand &band,
     660          24 :                                                GDALDataType dt)
     661             : {
     662          24 :     CPLAssert(op == Operation::OP_CAST);
     663          24 :     nRasterXSize = band.GetXSize();
     664          24 :     nRasterYSize = band.GetYSize();
     665          24 :     eDataType = dt;
     666          24 :     band.GetBlockSize(&nBlockXSize, &nBlockYSize);
     667             :     auto l_poDS = std::make_unique<GDALComputedDataset>(
     668          24 :         this, nRasterXSize, nRasterYSize, eDataType, nBlockXSize, nBlockYSize,
     669          48 :         op, &band, nullptr, nullptr, nullptr);
     670          24 :     m_poOwningDS.reset(l_poDS.release());
     671          24 : }
     672             : 
     673             : //! @endcond
     674             : 
     675             : /************************************************************************/
     676             : /*                      ~GDALComputedRasterBand()                       */
     677             : /************************************************************************/
     678             : 
     679         929 : GDALComputedRasterBand::~GDALComputedRasterBand()
     680             : {
     681         519 :     if (m_poOwningDS)
     682         240 :         cpl::down_cast<GDALComputedDataset *>(m_poOwningDS.get())->nBands = 0;
     683         519 :     poDS = nullptr;
     684         929 : }
     685             : 
     686             : /************************************************************************/
     687             : /*                  GDALComputedRasterBand::GetNoDataValue()            */
     688             : /************************************************************************/
     689             : 
     690         849 : double GDALComputedRasterBand::GetNoDataValue(int *pbHasNoData)
     691             : {
     692         849 :     if (pbHasNoData)
     693         849 :         *pbHasNoData = m_bHasNoData;
     694         849 :     return m_dfNoDataValue;
     695             : }
     696             : 
     697             : /************************************************************************/
     698             : /*                    GDALComputedRasterBandRelease()                   */
     699             : /************************************************************************/
     700             : 
     701             : /** Release a GDALComputedRasterBandH
     702             :  *
     703             :  * @since 3.12
     704             :  */
     705         131 : void GDALComputedRasterBandRelease(GDALComputedRasterBandH hBand)
     706             : {
     707         131 :     delete GDALComputedRasterBand::FromHandle(hBand);
     708         131 : }
     709             : 
     710             : /************************************************************************/
     711             : /*                           IReadBlock()                               */
     712             : /************************************************************************/
     713             : 
     714         168 : CPLErr GDALComputedRasterBand::IReadBlock(int nBlockXOff, int nBlockYOff,
     715             :                                           void *pData)
     716             : {
     717         168 :     auto l_poDS = cpl::down_cast<GDALComputedDataset *>(poDS);
     718         168 :     return l_poDS->m_oVRTDS.GetRasterBand(1)->ReadBlock(nBlockXOff, nBlockYOff,
     719         168 :                                                         pData);
     720             : }
     721             : 
     722             : /************************************************************************/
     723             : /*                           IRasterIO()                                */
     724             : /************************************************************************/
     725             : 
     726         151 : CPLErr GDALComputedRasterBand::IRasterIO(
     727             :     GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize, int nYSize,
     728             :     void *pData, int nBufXSize, int nBufYSize, GDALDataType eBufType,
     729             :     GSpacing nPixelSpace, GSpacing nLineSpace, GDALRasterIOExtraArg *psExtraArg)
     730             : {
     731         151 :     auto l_poDS = cpl::down_cast<GDALComputedDataset *>(poDS);
     732         151 :     return l_poDS->m_oVRTDS.GetRasterBand(1)->RasterIO(
     733             :         eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
     734         151 :         eBufType, nPixelSpace, nLineSpace, psExtraArg);
     735             : }

Generated by: LCOV version 1.14