LCOV - code coverage report
Current view: top level - gcore/multidim - gdalmultidim_pam.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 223 245 91.0 %
Date: 2026-04-15 22:10:00 Functions: 17 20 85.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Name:     gdalmultidim_pam.cpp
       4             :  * Project:  GDAL Core
       5             :  * Purpose:  Implementation of GDALPamMDArray and GDALPamMultiDim classes
       6             :  * Author:   Even Rouault <even.rouault at spatialys.com>
       7             :  *
       8             :  ******************************************************************************
       9             :  * Copyright (c) 2019, Even Rouault <even.rouault at spatialys.com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include "cpl_error_internal.h"
      15             : #include "gdal_multidim.h"
      16             : #include "gdal_pam.h"
      17             : #include "gdal_pam_multidim.h"
      18             : #include "ogr_spatialref.h"
      19             : 
      20             : #include <map>
      21             : 
      22             : #if defined(__clang__) || defined(_MSC_VER)
      23             : #define COMPILER_WARNS_ABOUT_ABSTRACT_VBASE_INIT
      24             : #endif
      25             : 
      26             : //! @cond Doxygen_Suppress
      27             : 
      28             : /************************************************************************/
      29             : /*                       GDALPamMultiDim::Private                       */
      30             : /************************************************************************/
      31             : 
      32             : struct GDALPamMultiDim::Private
      33             : {
      34             :     std::string m_osFilename{};
      35             :     std::string m_osPamFilename{};
      36             : 
      37             :     struct Statistics
      38             :     {
      39             :         bool bHasStats = false;
      40             :         bool bApproxStats = false;
      41             :         double dfMin = 0;
      42             :         double dfMax = 0;
      43             :         double dfMean = 0;
      44             :         double dfStdDev = 0;
      45             :         GUInt64 nValidCount = 0;
      46             :     };
      47             : 
      48             :     struct ArrayInfo
      49             :     {
      50             :         std::shared_ptr<OGRSpatialReference> poSRS{};
      51             :         // cppcheck-suppress unusedStructMember
      52             :         Statistics stats{};
      53             :         std::string osOvrFilename{};
      54             :     };
      55             : 
      56             :     typedef std::pair<std::string, std::string> NameContext;
      57             :     std::map<NameContext, ArrayInfo> m_oMapArray{};
      58             :     std::vector<CPLXMLTreeCloser> m_apoOtherNodes{};
      59             :     bool m_bDirty = false;
      60             :     bool m_bLoaded = false;
      61             : };
      62             : 
      63             : /************************************************************************/
      64             : /*                           GDALPamMultiDim                            */
      65             : /************************************************************************/
      66             : 
      67        2741 : GDALPamMultiDim::GDALPamMultiDim(const std::string &osFilename)
      68        2741 :     : d(new Private())
      69             : {
      70        2741 :     d->m_osFilename = osFilename;
      71        2741 : }
      72             : 
      73             : /************************************************************************/
      74             : /*                 GDALPamMultiDim::~GDALPamMultiDim()                  */
      75             : /************************************************************************/
      76             : 
      77        2741 : GDALPamMultiDim::~GDALPamMultiDim()
      78             : {
      79        2741 :     if (d->m_bDirty)
      80          37 :         Save();
      81        2741 : }
      82             : 
      83             : /************************************************************************/
      84             : /*                       GDALPamMultiDim::Load()                        */
      85             : /************************************************************************/
      86             : 
      87         182 : void GDALPamMultiDim::Load()
      88             : {
      89         182 :     if (d->m_bLoaded)
      90         169 :         return;
      91          71 :     d->m_bLoaded = true;
      92             : 
      93          71 :     const char *pszProxyPam = PamGetProxy(d->m_osFilename.c_str());
      94          71 :     d->m_osPamFilename =
      95         142 :         pszProxyPam ? std::string(pszProxyPam) : d->m_osFilename + ".aux.xml";
      96          71 :     CPLXMLTreeCloser oTree(nullptr);
      97             :     {
      98         142 :         CPLErrorStateBackuper oErrorStateBackuper(CPLQuietErrorHandler);
      99          71 :         oTree.reset(CPLParseXMLFile(d->m_osPamFilename.c_str()));
     100             :     }
     101          71 :     if (!oTree)
     102             :     {
     103          58 :         return;
     104             :     }
     105          13 :     const auto poPAMMultiDim = CPLGetXMLNode(oTree.get(), "=PAMDataset");
     106          13 :     if (!poPAMMultiDim)
     107           0 :         return;
     108          40 :     for (CPLXMLNode *psIter = poPAMMultiDim->psChild; psIter;
     109          27 :          psIter = psIter->psNext)
     110             :     {
     111          27 :         if (psIter->eType == CXT_Element &&
     112          27 :             strcmp(psIter->pszValue, "Array") == 0)
     113             :         {
     114          16 :             const char *pszName = CPLGetXMLValue(psIter, "name", nullptr);
     115          16 :             if (!pszName)
     116           0 :                 continue;
     117          16 :             const char *pszContext = CPLGetXMLValue(psIter, "context", "");
     118             :             const auto oKey =
     119          32 :                 std::pair<std::string, std::string>(pszName, pszContext);
     120             : 
     121             :             /* --------------------------------------------------------------------
     122             :              */
     123             :             /*      Check for an SRS node. */
     124             :             /* --------------------------------------------------------------------
     125             :              */
     126          16 :             const CPLXMLNode *psSRSNode = CPLGetXMLNode(psIter, "SRS");
     127          16 :             if (psSRSNode)
     128             :             {
     129             :                 std::shared_ptr<OGRSpatialReference> poSRS =
     130           6 :                     std::make_shared<OGRSpatialReference>();
     131           3 :                 poSRS->SetFromUserInput(
     132             :                     CPLGetXMLValue(psSRSNode, nullptr, ""),
     133             :                     OGRSpatialReference::SET_FROM_USER_INPUT_LIMITATIONS);
     134           3 :                 const char *pszMapping = CPLGetXMLValue(
     135             :                     psSRSNode, "dataAxisToSRSAxisMapping", nullptr);
     136           3 :                 if (pszMapping)
     137             :                 {
     138             :                     char **papszTokens =
     139           3 :                         CSLTokenizeStringComplex(pszMapping, ",", FALSE, FALSE);
     140           6 :                     std::vector<int> anMapping;
     141           9 :                     for (int i = 0; papszTokens && papszTokens[i]; i++)
     142             :                     {
     143           6 :                         anMapping.push_back(atoi(papszTokens[i]));
     144             :                     }
     145           3 :                     CSLDestroy(papszTokens);
     146           3 :                     poSRS->SetDataAxisToSRSAxisMapping(anMapping);
     147             :                 }
     148             :                 else
     149             :                 {
     150           0 :                     poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     151             :                 }
     152             : 
     153             :                 const char *pszCoordinateEpoch =
     154           3 :                     CPLGetXMLValue(psSRSNode, "coordinateEpoch", nullptr);
     155           3 :                 if (pszCoordinateEpoch)
     156           3 :                     poSRS->SetCoordinateEpoch(CPLAtof(pszCoordinateEpoch));
     157             : 
     158           3 :                 d->m_oMapArray[oKey].poSRS = std::move(poSRS);
     159             :             }
     160             : 
     161             :             const CPLXMLNode *psStatistics =
     162          16 :                 CPLGetXMLNode(psIter, "Statistics");
     163          16 :             if (psStatistics)
     164             :             {
     165           7 :                 Private::Statistics sStats;
     166           7 :                 sStats.bHasStats = true;
     167           7 :                 sStats.bApproxStats = CPLTestBool(
     168             :                     CPLGetXMLValue(psStatistics, "ApproxStats", "false"));
     169           7 :                 sStats.dfMin =
     170           7 :                     CPLAtofM(CPLGetXMLValue(psStatistics, "Minimum", "0"));
     171           7 :                 sStats.dfMax =
     172           7 :                     CPLAtofM(CPLGetXMLValue(psStatistics, "Maximum", "0"));
     173           7 :                 sStats.dfMean =
     174           7 :                     CPLAtofM(CPLGetXMLValue(psStatistics, "Mean", "0"));
     175           7 :                 sStats.dfStdDev =
     176           7 :                     CPLAtofM(CPLGetXMLValue(psStatistics, "StdDev", "0"));
     177           7 :                 sStats.nValidCount = static_cast<GUInt64>(CPLAtoGIntBig(
     178             :                     CPLGetXMLValue(psStatistics, "ValidSampleCount", "0")));
     179           7 :                 d->m_oMapArray[oKey].stats = sStats;
     180             :             }
     181             : 
     182             :             const char *pszOverviewFile =
     183          16 :                 CPLGetXMLValue(psIter, "OverviewFile", nullptr);
     184          16 :             if (pszOverviewFile)
     185             :             {
     186           3 :                 d->m_oMapArray[oKey].osOvrFilename = pszOverviewFile;
     187          16 :             }
     188             :         }
     189             :         else
     190             :         {
     191          11 :             CPLXMLNode *psNextBackup = psIter->psNext;
     192          11 :             psIter->psNext = nullptr;
     193          11 :             d->m_apoOtherNodes.emplace_back(
     194          11 :                 CPLXMLTreeCloser(CPLCloneXMLTree(psIter)));
     195          11 :             psIter->psNext = psNextBackup;
     196             :         }
     197             :     }
     198             : }
     199             : 
     200             : /************************************************************************/
     201             : /*                       GDALPamMultiDim::Save()                        */
     202             : /************************************************************************/
     203             : 
     204          37 : void GDALPamMultiDim::Save()
     205             : {
     206             :     CPLXMLTreeCloser oTree(
     207          74 :         CPLCreateXMLNode(nullptr, CXT_Element, "PAMDataset"));
     208          41 :     for (const auto &poOtherNode : d->m_apoOtherNodes)
     209             :     {
     210           4 :         CPLAddXMLChild(oTree.get(), CPLCloneXMLTree(poOtherNode.get()));
     211             :     }
     212         137 :     for (const auto &kv : d->m_oMapArray)
     213             :     {
     214             :         CPLXMLNode *psArrayNode =
     215         100 :             CPLCreateXMLNode(oTree.get(), CXT_Element, "Array");
     216         100 :         CPLAddXMLAttributeAndValue(psArrayNode, "name", kv.first.first.c_str());
     217         100 :         if (!kv.first.second.empty())
     218             :         {
     219           1 :             CPLAddXMLAttributeAndValue(psArrayNode, "context",
     220             :                                        kv.first.second.c_str());
     221             :         }
     222         100 :         if (kv.second.poSRS)
     223             :         {
     224          86 :             char *pszWKT = nullptr;
     225             :             {
     226         172 :                 CPLErrorStateBackuper oErrorStateBackuper(CPLQuietErrorHandler);
     227          86 :                 const char *const apszOptions[] = {"FORMAT=WKT2", nullptr};
     228          86 :                 kv.second.poSRS->exportToWkt(&pszWKT, apszOptions);
     229             :             }
     230             :             CPLXMLNode *psSRSNode =
     231          86 :                 CPLCreateXMLElementAndValue(psArrayNode, "SRS", pszWKT);
     232          86 :             CPLFree(pszWKT);
     233             :             const auto &mapping =
     234          86 :                 kv.second.poSRS->GetDataAxisToSRSAxisMapping();
     235         172 :             CPLString osMapping;
     236         258 :             for (size_t i = 0; i < mapping.size(); ++i)
     237             :             {
     238         172 :                 if (!osMapping.empty())
     239          86 :                     osMapping += ",";
     240         172 :                 osMapping += CPLSPrintf("%d", mapping[i]);
     241             :             }
     242          86 :             CPLAddXMLAttributeAndValue(psSRSNode, "dataAxisToSRSAxisMapping",
     243             :                                        osMapping.c_str());
     244             : 
     245             :             const double dfCoordinateEpoch =
     246          86 :                 kv.second.poSRS->GetCoordinateEpoch();
     247          86 :             if (dfCoordinateEpoch > 0)
     248             :             {
     249             :                 std::string osCoordinateEpoch =
     250           2 :                     CPLSPrintf("%f", dfCoordinateEpoch);
     251           1 :                 if (osCoordinateEpoch.find('.') != std::string::npos)
     252             :                 {
     253           6 :                     while (osCoordinateEpoch.back() == '0')
     254           5 :                         osCoordinateEpoch.resize(osCoordinateEpoch.size() - 1);
     255             :                 }
     256           1 :                 CPLAddXMLAttributeAndValue(psSRSNode, "coordinateEpoch",
     257             :                                            osCoordinateEpoch.c_str());
     258             :             }
     259             :         }
     260             : 
     261         100 :         if (kv.second.stats.bHasStats)
     262             :         {
     263             :             CPLXMLNode *psStats =
     264           8 :                 CPLCreateXMLNode(psArrayNode, CXT_Element, "Statistics");
     265           8 :             CPLCreateXMLElementAndValue(psStats, "ApproxStats",
     266           8 :                                         kv.second.stats.bApproxStats ? "1"
     267             :                                                                      : "0");
     268           8 :             CPLCreateXMLElementAndValue(
     269           8 :                 psStats, "Minimum", CPLSPrintf("%.17g", kv.second.stats.dfMin));
     270           8 :             CPLCreateXMLElementAndValue(
     271           8 :                 psStats, "Maximum", CPLSPrintf("%.17g", kv.second.stats.dfMax));
     272           8 :             CPLCreateXMLElementAndValue(
     273           8 :                 psStats, "Mean", CPLSPrintf("%.17g", kv.second.stats.dfMean));
     274           8 :             CPLCreateXMLElementAndValue(
     275             :                 psStats, "StdDev",
     276           8 :                 CPLSPrintf("%.17g", kv.second.stats.dfStdDev));
     277           8 :             CPLCreateXMLElementAndValue(
     278             :                 psStats, "ValidSampleCount",
     279           8 :                 CPLSPrintf(CPL_FRMT_GUIB, kv.second.stats.nValidCount));
     280             :         }
     281             : 
     282         100 :         if (!kv.second.osOvrFilename.empty())
     283             :         {
     284           3 :             CPLCreateXMLElementAndValue(psArrayNode, "OverviewFile",
     285             :                                         kv.second.osOvrFilename.c_str());
     286             :         }
     287             :     }
     288             : 
     289             :     int bSaved;
     290          74 :     CPLErrorAccumulator oErrorAccumulator;
     291             :     {
     292          37 :         auto oAccumulator = oErrorAccumulator.InstallForCurrentScope();
     293          37 :         CPL_IGNORE_RET_VAL(oAccumulator);
     294             :         bSaved =
     295          37 :             CPLSerializeXMLTreeToFile(oTree.get(), d->m_osPamFilename.c_str());
     296             :     }
     297             : 
     298          37 :     const char *pszNewPam = nullptr;
     299          37 :     if (!bSaved && PamGetProxy(d->m_osFilename.c_str()) == nullptr &&
     300           0 :         ((pszNewPam = PamAllocateProxy(d->m_osFilename.c_str())) != nullptr))
     301             :     {
     302           0 :         CPLErrorReset();
     303           0 :         CPLSerializeXMLTreeToFile(oTree.get(), pszNewPam);
     304             :     }
     305             :     else
     306             :     {
     307          37 :         oErrorAccumulator.ReplayErrors();
     308             :     }
     309          37 : }
     310             : 
     311             : /************************************************************************/
     312             : /*                GDALPamMultiDim::GetOverviewFilename()                */
     313             : /************************************************************************/
     314             : 
     315             : /** Return the file name of the overview filene name for the specified
     316             :  * array
     317             :  */
     318             : std::string
     319          48 : GDALPamMultiDim::GetOverviewFilename(const std::string &osArrayFullName,
     320             :                                      const std::string &osContext)
     321             : {
     322          48 :     Load();
     323          96 :     const auto oKey = std::make_pair(osArrayFullName, osContext);
     324          48 :     auto oIter = d->m_oMapArray.find(oKey);
     325          48 :     if (oIter != d->m_oMapArray.end())
     326           2 :         return oIter->second.osOvrFilename;
     327             : 
     328          46 :     return std::string();
     329             : }
     330             : 
     331             : /************************************************************************/
     332             : /*             GDALPamMultiDim::GenerateOverviewFilename()              */
     333             : /************************************************************************/
     334             : 
     335             : /** Ggenerate an overview filene name for the specified
     336             :  * array
     337             :  */
     338             : std::string
     339           2 : GDALPamMultiDim::GenerateOverviewFilename(const std::string &osArrayFullName,
     340             :                                           const std::string &osContext)
     341             : {
     342           2 :     Load();
     343             : 
     344           2 :     constexpr int ARBITRARY_ITERATION_COUNT = 1000;
     345           3 :     for (int i = 0; i < ARBITRARY_ITERATION_COUNT; ++i)
     346             :     {
     347           3 :         std::string osOvrFilename(d->m_osFilename);
     348           3 :         osOvrFilename += '.';
     349           3 :         osOvrFilename += std::to_string(i);
     350           3 :         osOvrFilename += ".ovr";
     351             :         VSIStatBufL sStatBuf;
     352           3 :         if (VSIStatL(osOvrFilename.c_str(), &sStatBuf) != 0)
     353             :         {
     354           2 :             d->m_bDirty = true;
     355           4 :             const auto oKey = std::make_pair(osArrayFullName, osContext);
     356           2 :             d->m_oMapArray[oKey].osOvrFilename = osOvrFilename;
     357           2 :             return osOvrFilename;
     358             :         }
     359             :     }
     360           0 :     CPLError(CE_Failure, CPLE_AppDefined,
     361             :              "Cannot establish overview filename for array %s",
     362             :              osArrayFullName.c_str());
     363           0 :     return std::string();
     364             : }
     365             : 
     366             : /************************************************************************/
     367             : /*                   GDALPamMultiDim::GetSpatialRef()                   */
     368             : /************************************************************************/
     369             : 
     370             : std::shared_ptr<OGRSpatialReference>
     371          20 : GDALPamMultiDim::GetSpatialRef(const std::string &osArrayFullName,
     372             :                                const std::string &osContext)
     373             : {
     374          20 :     Load();
     375             :     auto oIter =
     376          20 :         d->m_oMapArray.find(std::make_pair(osArrayFullName, osContext));
     377          20 :     if (oIter != d->m_oMapArray.end())
     378           2 :         return oIter->second.poSRS;
     379          18 :     return nullptr;
     380             : }
     381             : 
     382             : /************************************************************************/
     383             : /*                   GDALPamMultiDim::SetSpatialRef()                   */
     384             : /************************************************************************/
     385             : 
     386          87 : void GDALPamMultiDim::SetSpatialRef(const std::string &osArrayFullName,
     387             :                                     const std::string &osContext,
     388             :                                     const OGRSpatialReference *poSRS)
     389             : {
     390          87 :     Load();
     391          87 :     d->m_bDirty = true;
     392          87 :     if (poSRS && !poSRS->IsEmpty())
     393          86 :         d->m_oMapArray[std::make_pair(osArrayFullName, osContext)].poSRS.reset(
     394             :             poSRS->Clone());
     395             :     else
     396           2 :         d->m_oMapArray[std::make_pair(osArrayFullName, osContext)]
     397           1 :             .poSRS.reset();
     398          87 : }
     399             : 
     400             : /************************************************************************/
     401             : /*                           GetStatistics()                            */
     402             : /************************************************************************/
     403             : 
     404          16 : CPLErr GDALPamMultiDim::GetStatistics(const std::string &osArrayFullName,
     405             :                                       const std::string &osContext,
     406             :                                       bool bApproxOK, double *pdfMin,
     407             :                                       double *pdfMax, double *pdfMean,
     408             :                                       double *pdfStdDev, GUInt64 *pnValidCount)
     409             : {
     410          16 :     Load();
     411             :     auto oIter =
     412          16 :         d->m_oMapArray.find(std::make_pair(osArrayFullName, osContext));
     413          16 :     if (oIter == d->m_oMapArray.end())
     414           9 :         return CE_Failure;
     415           7 :     const auto &stats = oIter->second.stats;
     416           7 :     if (!stats.bHasStats)
     417           1 :         return CE_Failure;
     418           6 :     if (!bApproxOK && stats.bApproxStats)
     419           0 :         return CE_Failure;
     420           6 :     if (pdfMin)
     421           6 :         *pdfMin = stats.dfMin;
     422           6 :     if (pdfMax)
     423           6 :         *pdfMax = stats.dfMax;
     424           6 :     if (pdfMean)
     425           6 :         *pdfMean = stats.dfMean;
     426           6 :     if (pdfStdDev)
     427           6 :         *pdfStdDev = stats.dfStdDev;
     428           6 :     if (pnValidCount)
     429           6 :         *pnValidCount = stats.nValidCount;
     430           6 :     return CE_None;
     431             : }
     432             : 
     433             : /************************************************************************/
     434             : /*                           SetStatistics()                            */
     435             : /************************************************************************/
     436             : 
     437           8 : void GDALPamMultiDim::SetStatistics(const std::string &osArrayFullName,
     438             :                                     const std::string &osContext,
     439             :                                     bool bApproxStats, double dfMin,
     440             :                                     double dfMax, double dfMean,
     441             :                                     double dfStdDev, GUInt64 nValidCount)
     442             : {
     443           8 :     Load();
     444           8 :     d->m_bDirty = true;
     445             :     auto &stats =
     446           8 :         d->m_oMapArray[std::make_pair(osArrayFullName, osContext)].stats;
     447           8 :     stats.bHasStats = true;
     448           8 :     stats.bApproxStats = bApproxStats;
     449           8 :     stats.dfMin = dfMin;
     450           8 :     stats.dfMax = dfMax;
     451           8 :     stats.dfMean = dfMean;
     452           8 :     stats.dfStdDev = dfStdDev;
     453           8 :     stats.nValidCount = nValidCount;
     454           8 : }
     455             : 
     456             : /************************************************************************/
     457             : /*                          ClearStatistics()                           */
     458             : /************************************************************************/
     459             : 
     460           0 : void GDALPamMultiDim::ClearStatistics(const std::string &osArrayFullName,
     461             :                                       const std::string &osContext)
     462             : {
     463           0 :     Load();
     464           0 :     d->m_bDirty = true;
     465           0 :     d->m_oMapArray[std::make_pair(osArrayFullName, osContext)].stats.bHasStats =
     466             :         false;
     467           0 : }
     468             : 
     469             : /************************************************************************/
     470             : /*                          ClearStatistics()                           */
     471             : /************************************************************************/
     472             : 
     473           1 : void GDALPamMultiDim::ClearStatistics()
     474             : {
     475           1 :     Load();
     476           1 :     d->m_bDirty = true;
     477           3 :     for (auto &kv : d->m_oMapArray)
     478           2 :         kv.second.stats.bHasStats = false;
     479           1 : }
     480             : 
     481             : /************************************************************************/
     482             : /*                               GetPAM()                               */
     483             : /************************************************************************/
     484             : 
     485             : /*static*/ std::shared_ptr<GDALPamMultiDim>
     486        1530 : GDALPamMultiDim::GetPAM(const std::shared_ptr<GDALMDArray> &poParent)
     487             : {
     488        1530 :     auto poPamArray = dynamic_cast<GDALPamMDArray *>(poParent.get());
     489        1530 :     if (poPamArray)
     490         793 :         return poPamArray->GetPAM();
     491         737 :     return nullptr;
     492             : }
     493             : 
     494             : /************************************************************************/
     495             : /*                            GDALPamMDArray                            */
     496             : /************************************************************************/
     497             : 
     498        6222 : GDALPamMDArray::GDALPamMDArray(const std::string &osParentName,
     499             :                                const std::string &osName,
     500             :                                const std::shared_ptr<GDALPamMultiDim> &poPam,
     501           0 :                                const std::string &osContext)
     502             :     :
     503             : #if !defined(COMPILER_WARNS_ABOUT_ABSTRACT_VBASE_INIT)
     504             :       GDALAbstractMDArray(osParentName, osName),
     505             : #endif
     506        6222 :       GDALMDArray(osParentName, osName, osContext), m_poPam(poPam)
     507             : {
     508        6222 : }
     509             : 
     510             : /************************************************************************/
     511             : /*                   GDALPamMDArray::SetSpatialRef()                    */
     512             : /************************************************************************/
     513             : 
     514          87 : bool GDALPamMDArray::SetSpatialRef(const OGRSpatialReference *poSRS)
     515             : {
     516          87 :     if (!m_poPam)
     517           0 :         return false;
     518          87 :     m_poPam->SetSpatialRef(GetFullName(), GetContext(), poSRS);
     519          87 :     return true;
     520             : }
     521             : 
     522             : /************************************************************************/
     523             : /*                   GDALPamMDArray::GetSpatialRef()                    */
     524             : /************************************************************************/
     525             : 
     526          20 : std::shared_ptr<OGRSpatialReference> GDALPamMDArray::GetSpatialRef() const
     527             : {
     528          20 :     if (!m_poPam)
     529           0 :         return nullptr;
     530          20 :     return m_poPam->GetSpatialRef(GetFullName(), GetContext());
     531             : }
     532             : 
     533             : /************************************************************************/
     534             : /*                           GetStatistics()                            */
     535             : /************************************************************************/
     536             : 
     537          16 : CPLErr GDALPamMDArray::GetStatistics(bool bApproxOK, bool bForce,
     538             :                                      double *pdfMin, double *pdfMax,
     539             :                                      double *pdfMean, double *pdfStdDev,
     540             :                                      GUInt64 *pnValidCount,
     541             :                                      GDALProgressFunc pfnProgress,
     542             :                                      void *pProgressData)
     543             : {
     544          16 :     if (m_poPam && m_poPam->GetStatistics(GetFullName(), GetContext(),
     545             :                                           bApproxOK, pdfMin, pdfMax, pdfMean,
     546          16 :                                           pdfStdDev, pnValidCount) == CE_None)
     547             :     {
     548           6 :         return CE_None;
     549             :     }
     550          10 :     if (!bForce)
     551           4 :         return CE_Warning;
     552             : 
     553           6 :     return GDALMDArray::GetStatistics(bApproxOK, bForce, pdfMin, pdfMax,
     554             :                                       pdfMean, pdfStdDev, pnValidCount,
     555           6 :                                       pfnProgress, pProgressData);
     556             : }
     557             : 
     558             : /************************************************************************/
     559             : /*                           SetStatistics()                            */
     560             : /************************************************************************/
     561             : 
     562           8 : bool GDALPamMDArray::SetStatistics(bool bApproxStats, double dfMin,
     563             :                                    double dfMax, double dfMean, double dfStdDev,
     564             :                                    GUInt64 nValidCount,
     565             :                                    CSLConstList /* papszOptions */)
     566             : {
     567           8 :     if (!m_poPam)
     568           0 :         return false;
     569           8 :     m_poPam->SetStatistics(GetFullName(), GetContext(), bApproxStats, dfMin,
     570             :                            dfMax, dfMean, dfStdDev, nValidCount);
     571           8 :     return true;
     572             : }
     573             : 
     574             : /************************************************************************/
     575             : /*                          ClearStatistics()                           */
     576             : /************************************************************************/
     577             : 
     578           0 : void GDALPamMDArray::ClearStatistics()
     579             : {
     580           0 :     if (!m_poPam)
     581           0 :         return;
     582           0 :     m_poPam->ClearStatistics(GetFullName(), GetContext());
     583             : }
     584             : 
     585             : //! @endcond

Generated by: LCOV version 1.14