LCOV - code coverage report
Current view: top level - gcore - gdalmultidim_gltorthorectification.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 156 175 89.1 %
Date: 2024-05-04 12:52:34 Functions: 14 16 87.5 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  * Name:     gdalmultidim_gltorthorectification.cpp
       3             :  * Project:  GDAL Core
       4             :  * Purpose:  GLT orthorectification implementation
       5             :  * Author:   Even Rouault <even.rouault at spatialys.com>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2023, Even Rouault <even.rouault at spatialys.com>
       9             :  *
      10             :  * Permission is hereby granted, free of charge, to any person obtaining a
      11             :  * copy of this software and associated documentation files (the "Software"),
      12             :  * to deal in the Software without restriction, including without limitation
      13             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      14             :  * and/or sell copies of the Software, and to permit persons to whom the
      15             :  * Software is furnished to do so, subject to the following conditions:
      16             :  *
      17             :  * The above copyright notice and this permission notice shall be included
      18             :  * in all copies or substantial portions of the Software.
      19             :  *
      20             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      21             :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      22             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      23             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      24             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      25             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      26             :  * DEALINGS IN THE SOFTWARE.
      27             :  ****************************************************************************/
      28             : 
      29             : #include "gdal_priv.h"
      30             : #include "gdal_pam.h"
      31             : 
      32             : #include <algorithm>
      33             : #include <limits>
      34             : 
      35             : /************************************************************************/
      36             : /*                        GLTOrthoRectifiedArray                        */
      37             : /************************************************************************/
      38             : 
      39             : class GLTOrthoRectifiedArray final : public GDALPamMDArray
      40             : {
      41             :   private:
      42             :     std::shared_ptr<GDALMDArray> m_poParent{};
      43             :     std::vector<std::shared_ptr<GDALDimension>> m_apoDims;
      44             :     std::vector<GUInt64> m_anBlockSize;
      45             :     GDALExtendedDataType m_dt;
      46             :     std::shared_ptr<OGRSpatialReference> m_poSRS{};
      47             :     std::shared_ptr<GDALMDArray> m_poVarX{};
      48             :     std::shared_ptr<GDALMDArray> m_poVarY{};
      49             :     std::shared_ptr<GDALMDArray> m_poGLTX{};
      50             :     std::shared_ptr<GDALMDArray> m_poGLTY{};
      51             :     int m_nGLTIndexOffset = 0;
      52             : 
      53             :   protected:
      54           5 :     GLTOrthoRectifiedArray(
      55             :         const std::shared_ptr<GDALMDArray> &poParent,
      56             :         const std::vector<std::shared_ptr<GDALDimension>> &apoDims,
      57             :         const std::vector<GUInt64> &anBlockSize)
      58          10 :         : GDALAbstractMDArray(std::string(), "GLTOrthoRectifiedArray view of " +
      59           5 :                                                  poParent->GetFullName()),
      60          10 :           GDALPamMDArray(std::string(),
      61          10 :                          "GLTOrthoRectifiedArray view of " +
      62           5 :                              poParent->GetFullName(),
      63          10 :                          GDALPamMultiDim::GetPAM(poParent)),
      64           5 :           m_poParent(std::move(poParent)), m_apoDims(apoDims),
      65          25 :           m_anBlockSize(anBlockSize), m_dt(m_poParent->GetDataType())
      66             :     {
      67           5 :         CPLAssert(apoDims.size() == m_poParent->GetDimensionCount());
      68           5 :         CPLAssert(anBlockSize.size() == m_poParent->GetDimensionCount());
      69           5 :     }
      70             : 
      71             :     bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
      72             :                const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
      73             :                const GDALExtendedDataType &bufferDataType,
      74             :                void *pDstBuffer) const override;
      75             : 
      76             :   public:
      77             :     static std::shared_ptr<GDALMDArray>
      78           5 :     Create(const std::shared_ptr<GDALMDArray> &poParent,
      79             :            const std::shared_ptr<GDALMDArray> &poGLTX,
      80             :            const std::shared_ptr<GDALMDArray> &poGLTY, int nGLTIndexOffset,
      81             :            const std::vector<double> &adfGeoTransform)
      82             :     {
      83          10 :         std::vector<std::shared_ptr<GDALDimension>> apoNewDims;
      84             : 
      85             :         auto poDimY = std::make_shared<GDALDimensionWeakIndexingVar>(
      86           0 :             std::string(), "lat", GDAL_DIM_TYPE_HORIZONTAL_Y, "NORTH",
      87          10 :             poGLTX->GetDimensions()[0]->GetSize());
      88             :         auto varY = GDALMDArrayRegularlySpaced::Create(
      89          15 :             std::string(), poDimY->GetName(), poDimY,
      90          20 :             adfGeoTransform[3] + adfGeoTransform[5] / 2, adfGeoTransform[5], 0);
      91           5 :         poDimY->SetIndexingVariable(varY);
      92           5 :         apoNewDims.emplace_back(poDimY);
      93             : 
      94             :         auto poDimX = std::make_shared<GDALDimensionWeakIndexingVar>(
      95           0 :             std::string(), "lon", GDAL_DIM_TYPE_HORIZONTAL_X, "EAST",
      96          10 :             poGLTX->GetDimensions()[1]->GetSize());
      97             :         auto varX = GDALMDArrayRegularlySpaced::Create(
      98          15 :             std::string(), poDimX->GetName(), poDimX,
      99          20 :             adfGeoTransform[0] + adfGeoTransform[1] / 2, adfGeoTransform[1], 0);
     100           5 :         poDimX->SetIndexingVariable(varX);
     101           5 :         apoNewDims.emplace_back(poDimX);
     102             : 
     103           5 :         if (poParent->GetDimensionCount() == 3)
     104           4 :             apoNewDims.emplace_back(poParent->GetDimensions()[2]);
     105             : 
     106             :         std::vector<GUInt64> anBlockSize = std::vector<GUInt64>{
     107           5 :             std::min<GUInt64>(apoNewDims[0]->GetSize(), 512),
     108          10 :             std::min<GUInt64>(apoNewDims[1]->GetSize(), 512)};
     109           5 :         if (poParent->GetDimensionCount() == 3)
     110             :         {
     111           4 :             anBlockSize.push_back(poParent->GetDimensions()[2]->GetSize());
     112             :         }
     113             : 
     114             :         auto newAr(std::shared_ptr<GLTOrthoRectifiedArray>(
     115          10 :             new GLTOrthoRectifiedArray(poParent, apoNewDims, anBlockSize)));
     116           5 :         newAr->SetSelf(newAr);
     117           5 :         newAr->m_poVarX = varX;
     118           5 :         newAr->m_poVarY = varY;
     119           5 :         newAr->m_poGLTX = poGLTX;
     120           5 :         newAr->m_poGLTY = poGLTY;
     121           5 :         newAr->m_nGLTIndexOffset = nGLTIndexOffset;
     122          10 :         OGRSpatialReference oSRS;
     123           5 :         oSRS.importFromEPSG(4326);
     124           5 :         newAr->m_poSRS.reset(oSRS.Clone());
     125           5 :         newAr->m_poSRS->SetDataAxisToSRSAxisMapping(
     126             :             {/*latIdx = */ 1, /* lonIdx = */ 2});
     127          10 :         return newAr;
     128             :     }
     129             : 
     130           2 :     bool IsWritable() const override
     131             :     {
     132           2 :         return false;
     133             :     }
     134             : 
     135          14 :     const std::string &GetFilename() const override
     136             :     {
     137          14 :         return m_poParent->GetFilename();
     138             :     }
     139             : 
     140             :     const std::vector<std::shared_ptr<GDALDimension>> &
     141          83 :     GetDimensions() const override
     142             :     {
     143          83 :         return m_apoDims;
     144             :     }
     145             : 
     146          61 :     const GDALExtendedDataType &GetDataType() const override
     147             :     {
     148          61 :         return m_dt;
     149             :     }
     150             : 
     151           4 :     std::shared_ptr<OGRSpatialReference> GetSpatialRef() const override
     152             :     {
     153           4 :         return m_poSRS;
     154             :     }
     155             : 
     156           5 :     std::vector<GUInt64> GetBlockSize() const override
     157             :     {
     158           5 :         return m_anBlockSize;
     159             :     }
     160             : 
     161             :     std::shared_ptr<GDALAttribute>
     162           3 :     GetAttribute(const std::string &osName) const override
     163             :     {
     164           3 :         return m_poParent->GetAttribute(osName);
     165             :     }
     166             : 
     167             :     std::vector<std::shared_ptr<GDALAttribute>>
     168           2 :     GetAttributes(CSLConstList papszOptions = nullptr) const override
     169             :     {
     170           2 :         return m_poParent->GetAttributes(papszOptions);
     171             :     }
     172             : 
     173           3 :     const std::string &GetUnit() const override
     174             :     {
     175           3 :         return m_poParent->GetUnit();
     176             :     }
     177             : 
     178          15 :     const void *GetRawNoDataValue() const override
     179             :     {
     180          15 :         return m_poParent->GetRawNoDataValue();
     181             :     }
     182             : 
     183           0 :     double GetOffset(bool *pbHasOffset,
     184             :                      GDALDataType *peStorageType) const override
     185             :     {
     186           0 :         return m_poParent->GetOffset(pbHasOffset, peStorageType);
     187             :     }
     188             : 
     189           0 :     double GetScale(bool *pbHasScale,
     190             :                     GDALDataType *peStorageType) const override
     191             :     {
     192           0 :         return m_poParent->GetScale(pbHasScale, peStorageType);
     193             :     }
     194             : };
     195             : 
     196             : /************************************************************************/
     197             : /*                   GDALMDArrayResampled::IRead()                      */
     198             : /************************************************************************/
     199             : 
     200          12 : bool GLTOrthoRectifiedArray::IRead(const GUInt64 *arrayStartIdx,
     201             :                                    const size_t *count, const GInt64 *arrayStep,
     202             :                                    const GPtrDiff_t *bufferStride,
     203             :                                    const GDALExtendedDataType &bufferDataType,
     204             :                                    void *pDstBuffer) const
     205             : {
     206          12 :     if (bufferDataType.GetClass() != GEDTC_NUMERIC)
     207           0 :         return false;
     208             : 
     209          12 :     const size_t nXYValsCount = count[0] * count[1];
     210          24 :     const auto eInt32DT = GDALExtendedDataType::Create(GDT_Int32);
     211          24 :     std::vector<int32_t> anGLTX;
     212          24 :     std::vector<int32_t> anGLTY;
     213             :     try
     214             :     {
     215          12 :         anGLTX.resize(nXYValsCount);
     216          12 :         anGLTY.resize(nXYValsCount);
     217             :     }
     218           0 :     catch (const std::bad_alloc &e)
     219             :     {
     220           0 :         CPLError(CE_Failure, CPLE_OutOfMemory,
     221           0 :                  "GLTOrthoRectifiedArray::IRead(): %s", e.what());
     222           0 :         return false;
     223             :     }
     224          24 :     if (!m_poGLTX->Read(arrayStartIdx, count, arrayStep, nullptr, eInt32DT,
     225          36 :                         anGLTX.data()) ||
     226          24 :         !m_poGLTY->Read(arrayStartIdx, count, arrayStep, nullptr, eInt32DT,
     227          12 :                         anGLTY.data()))
     228             :     {
     229           0 :         return false;
     230             :     }
     231             : 
     232          12 :     int32_t nMinX = std::numeric_limits<int32_t>::max();
     233          12 :     int32_t nMaxX = std::numeric_limits<int32_t>::min();
     234          12 :     const auto nXSize = m_poParent->GetDimensions()[0]->GetSize();
     235          74 :     for (size_t i = 0; i < nXYValsCount; ++i)
     236             :     {
     237             :         const int64_t nX64 =
     238          62 :             static_cast<int64_t>(anGLTX[i]) + m_nGLTIndexOffset;
     239          62 :         if (nX64 >= 0 && static_cast<uint64_t>(nX64) < nXSize)
     240             :         {
     241          26 :             const int32_t nX = static_cast<int32_t>(nX64);
     242          26 :             if (nX < nMinX)
     243           8 :                 nMinX = nX;
     244          26 :             if (nX > nMaxX)
     245          14 :                 nMaxX = nX;
     246             :         }
     247             :     }
     248             : 
     249          12 :     int32_t nMinY = std::numeric_limits<int32_t>::max();
     250          12 :     int32_t nMaxY = std::numeric_limits<int32_t>::min();
     251          12 :     const auto nYSize = m_poParent->GetDimensions()[0]->GetSize();
     252          74 :     for (size_t i = 0; i < nXYValsCount; ++i)
     253             :     {
     254             :         const int64_t nY64 =
     255          62 :             static_cast<int64_t>(anGLTY[i]) + m_nGLTIndexOffset;
     256          62 :         if (nY64 >= 0 && static_cast<uint64_t>(nY64) < nYSize)
     257             :         {
     258          26 :             const int32_t nY = static_cast<int32_t>(nY64);
     259          26 :             if (nY < nMinY)
     260          14 :                 nMinY = nY;
     261          26 :             if (nY > nMaxY)
     262           8 :                 nMaxY = nY;
     263             :         }
     264             :     }
     265             : 
     266          12 :     const auto eBufferDT = bufferDataType.GetNumericDataType();
     267          12 :     auto pRawNoDataValue = GetRawNoDataValue();
     268          24 :     std::vector<GByte> abyNoData(16);
     269          12 :     if (pRawNoDataValue)
     270          12 :         GDALCopyWords(pRawNoDataValue, GetDataType().GetNumericDataType(), 0,
     271          12 :                       abyNoData.data(), eBufferDT, 0, 1);
     272             : 
     273          12 :     const auto nBufferDTSize = bufferDataType.GetSize();
     274             :     const int nCopyWordsDstStride =
     275          12 :         m_apoDims.size() == 3
     276          12 :             ? static_cast<int>(bufferStride[2] * nBufferDTSize)
     277          12 :             : 0;
     278             :     const int nCopyWordsCount =
     279          12 :         m_apoDims.size() == 3 ? static_cast<int>(count[2]) : 1;
     280          12 :     if (nMinX > nMaxX || nMinY > nMaxY)
     281             :     {
     282           8 :         for (size_t iY = 0; iY < count[0]; ++iY)
     283             :         {
     284          10 :             for (size_t iX = 0; iX < count[1]; ++iX)
     285             :             {
     286           6 :                 GByte *pabyDstBuffer =
     287             :                     static_cast<GByte *>(pDstBuffer) +
     288           6 :                     (iY * bufferStride[0] + iX * bufferStride[1]) *
     289           6 :                         static_cast<int>(nBufferDTSize);
     290           6 :                 GDALCopyWords(abyNoData.data(), eBufferDT, 0, pabyDstBuffer,
     291             :                               eBufferDT, nCopyWordsDstStride, nCopyWordsCount);
     292             :             }
     293             :         }
     294           4 :         return true;
     295             :     }
     296             : 
     297             :     GUInt64 parentArrayIdxStart[3] = {
     298           8 :         static_cast<GUInt64>(nMinY), static_cast<GUInt64>(nMinX),
     299           8 :         m_apoDims.size() == 3 ? arrayStartIdx[2] : 0};
     300           8 :     size_t parentCount[3] = {static_cast<size_t>(nMaxY - nMinY + 1),
     301           8 :                              static_cast<size_t>(nMaxX - nMinX + 1),
     302           8 :                              m_apoDims.size() == 3 ? count[2] : 1};
     303           8 :     GInt64 parentArrayStep[3] = {1, 1,
     304           8 :                                  m_apoDims.size() == 3 ? arrayStep[2] : 0};
     305             : 
     306           8 :     size_t nParentValueSize = nBufferDTSize;
     307          32 :     for (int i = 0; i < 3; ++i)
     308             :     {
     309          48 :         if (parentCount[i] >
     310          24 :             std::numeric_limits<size_t>::max() / nParentValueSize)
     311             :         {
     312           0 :             CPLError(
     313             :                 CE_Failure, CPLE_OutOfMemory,
     314             :                 "GLTOrthoRectifiedArray::IRead(): too big temporary array");
     315           0 :             return false;
     316             :         }
     317          24 :         nParentValueSize *= parentCount[i];
     318             :     }
     319             : 
     320           8 :     GPtrDiff_t parentStride[3] = {
     321           8 :         static_cast<GPtrDiff_t>(parentCount[1] * parentCount[2]),
     322           8 :         static_cast<GPtrDiff_t>(parentCount[2]), 1};
     323          16 :     std::vector<GByte> parentValues;
     324             :     try
     325             :     {
     326           8 :         parentValues.resize(nParentValueSize);
     327             :     }
     328           0 :     catch (const std::bad_alloc &e)
     329             :     {
     330           0 :         CPLError(CE_Failure, CPLE_OutOfMemory,
     331           0 :                  "GLTOrthoRectifiedArray::IRead(): %s", e.what());
     332           0 :         return false;
     333             :     }
     334          16 :     if (!m_poParent->Read(parentArrayIdxStart, parentCount, parentArrayStep,
     335           8 :                           parentStride, bufferDataType, parentValues.data()))
     336             :     {
     337           0 :         return false;
     338             :     }
     339             : 
     340           8 :     size_t iGLTIndex = 0;
     341           8 :     const size_t nXCount = parentCount[1];
     342           8 :     const size_t nBandCount = m_apoDims.size() == 3 ? parentCount[2] : 1;
     343          28 :     for (size_t iY = 0; iY < count[0]; ++iY)
     344             :     {
     345          76 :         for (size_t iX = 0; iX < count[1]; ++iX, ++iGLTIndex)
     346             :         {
     347             :             const int64_t nX64 =
     348          56 :                 static_cast<int64_t>(anGLTX[iGLTIndex]) + m_nGLTIndexOffset;
     349             :             const int64_t nY64 =
     350          56 :                 static_cast<int64_t>(anGLTY[iGLTIndex]) + m_nGLTIndexOffset;
     351          56 :             GByte *pabyDstBuffer =
     352             :                 static_cast<GByte *>(pDstBuffer) +
     353          56 :                 (iY * bufferStride[0] + iX * bufferStride[1]) *
     354          56 :                     static_cast<int>(nBufferDTSize);
     355          56 :             if (nX64 >= nMinX && nX64 <= nMaxX && nY64 >= nMinY &&
     356          26 :                 nY64 <= nMaxY)
     357             :             {
     358          26 :                 const int32_t iSrcX = static_cast<int32_t>(nX64) - nMinX;
     359          26 :                 const int32_t iSrcY = static_cast<int32_t>(nY64) - nMinY;
     360             :                 const GByte *pabySrcBuffer =
     361          26 :                     parentValues.data() +
     362          26 :                     (iSrcY * nXCount + iSrcX) * nBandCount * nBufferDTSize;
     363          26 :                 GDALCopyWords(pabySrcBuffer, eBufferDT,
     364             :                               static_cast<int>(nBufferDTSize), pabyDstBuffer,
     365          26 :                               eBufferDT, nCopyWordsDstStride, nCopyWordsCount);
     366             :             }
     367             :             else
     368             :             {
     369          30 :                 GDALCopyWords(abyNoData.data(), eBufferDT, 0, pabyDstBuffer,
     370             :                               eBufferDT, nCopyWordsDstStride, nCopyWordsCount);
     371             :             }
     372             :         }
     373             :     }
     374             : 
     375           8 :     return true;
     376             : }
     377             : 
     378             : /************************************************************************/
     379             : /*                     CreateGLTOrthorectified()                        */
     380             : /************************************************************************/
     381             : 
     382             : //! @cond Doxygen_Suppress
     383             : 
     384           5 : /* static */ std::shared_ptr<GDALMDArray> GDALMDArray::CreateGLTOrthorectified(
     385             :     const std::shared_ptr<GDALMDArray> &poParent,
     386             :     const std::shared_ptr<GDALMDArray> &poGLTX,
     387             :     const std::shared_ptr<GDALMDArray> &poGLTY, int nGLTIndexOffset,
     388             :     const std::vector<double> &adfGeoTransform)
     389             : {
     390             :     return GLTOrthoRectifiedArray::Create(poParent, poGLTX, poGLTY,
     391           5 :                                           nGLTIndexOffset, adfGeoTransform);
     392             : }
     393             : 
     394             : //! @endcond

Generated by: LCOV version 1.14