LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/generic - ogrwarpedlayer.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 190 250 76.0 %
Date: 2026-06-19 21:24:00 Functions: 19 27 70.4 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  OpenGIS Simple Features Reference Implementation
       4             :  * Purpose:  Implements OGRWarpedLayer class
       5             :  * Author:   Even Rouault, even dot rouault at spatialys.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2012-2014, Even Rouault <even dot rouault at spatialys.com>
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #ifndef DOXYGEN_SKIP
      14             : 
      15             : #include <cmath>
      16             : 
      17             : #include "ogrwarpedlayer.h"
      18             : 
      19             : /************************************************************************/
      20             : /*                           OGRWarpedLayer()                           */
      21             : /************************************************************************/
      22             : 
      23          41 : OGRWarpedLayer::OGRWarpedLayer(
      24             :     OGRLayer *poDecoratedLayer, int iGeomField, int bTakeLayerOwnership,
      25             :     std::unique_ptr<OGRCoordinateTransformation> poCT,
      26          41 :     std::unique_ptr<OGRCoordinateTransformation> poReversedCT)
      27             :     : OGRLayerDecorator(poDecoratedLayer, bTakeLayerOwnership),
      28          41 :       m_poFeatureDefn(poDecoratedLayer->GetLayerDefn()->Clone()),
      29          41 :       m_iGeomField(iGeomField), m_poCT(std::move(poCT)),
      30          41 :       m_poReversedCT(std::move(poReversedCT)),
      31          82 :       m_poSRS(const_cast<OGRSpatialReference *>(m_poCT->GetTargetCS()))
      32             : {
      33          41 :     SetDescription(poDecoratedLayer->GetDescription());
      34             : 
      35          41 :     m_poFeatureDefn->Reference();
      36          41 :     if (m_poFeatureDefn->GetGeomFieldCount() > 0)
      37          41 :         m_poFeatureDefn->GetGeomFieldDefn(m_iGeomField)->SetSpatialRef(m_poSRS);
      38             : 
      39          41 :     if (m_poSRS != nullptr)
      40             :     {
      41          41 :         m_poSRS->Reference();
      42             :     }
      43          41 : }
      44             : 
      45             : /************************************************************************/
      46             : /*                          ~OGRWarpedLayer()                           */
      47             : /************************************************************************/
      48             : 
      49          82 : OGRWarpedLayer::~OGRWarpedLayer()
      50             : {
      51          41 :     if (m_poFeatureDefn != nullptr)
      52          41 :         m_poFeatureDefn->Release();
      53          41 :     if (m_poSRS != nullptr)
      54          41 :         m_poSRS->Release();
      55          82 : }
      56             : 
      57             : /************************************************************************/
      58             : /*                         ISetSpatialFilter()                          */
      59             : /************************************************************************/
      60             : 
      61         130 : OGRErr OGRWarpedLayer::ISetSpatialFilter(int iGeomField,
      62             :                                          const OGRGeometry *poGeom)
      63             : {
      64             : 
      65         130 :     m_iGeomFieldFilter = iGeomField;
      66         130 :     if (InstallFilter(poGeom))
      67          57 :         ResetReading();
      68             : 
      69         130 :     if (m_iGeomFieldFilter == m_iGeomField)
      70             :     {
      71          50 :         if (poGeom == nullptr || m_poReversedCT == nullptr)
      72             :         {
      73          22 :             return m_poDecoratedLayer->SetSpatialFilter(m_iGeomFieldFilter,
      74          22 :                                                         nullptr);
      75             :         }
      76             :         else
      77             :         {
      78          28 :             OGREnvelope sEnvelope;
      79          28 :             poGeom->getEnvelope(&sEnvelope);
      80          34 :             if (std::isinf(sEnvelope.MinX) && std::isinf(sEnvelope.MinY) &&
      81          34 :                 std::isinf(sEnvelope.MaxX) && std::isinf(sEnvelope.MaxY))
      82             :             {
      83           3 :                 return m_poDecoratedLayer->SetSpatialFilterRect(
      84             :                     m_iGeomFieldFilter, sEnvelope.MinX, sEnvelope.MinY,
      85           3 :                     sEnvelope.MaxX, sEnvelope.MaxY);
      86             :             }
      87          25 :             else if (ReprojectEnvelope(&sEnvelope, m_poReversedCT.get()))
      88             :             {
      89          22 :                 return m_poDecoratedLayer->SetSpatialFilterRect(
      90             :                     m_iGeomFieldFilter, sEnvelope.MinX, sEnvelope.MinY,
      91          22 :                     sEnvelope.MaxX, sEnvelope.MaxY);
      92             :             }
      93             :             else
      94             :             {
      95           3 :                 return m_poDecoratedLayer->SetSpatialFilter(m_iGeomFieldFilter,
      96           3 :                                                             nullptr);
      97             :             }
      98             :         }
      99             :     }
     100             :     else
     101             :     {
     102          80 :         return m_poDecoratedLayer->SetSpatialFilter(m_iGeomFieldFilter, poGeom);
     103             :     }
     104             : }
     105             : 
     106             : /************************************************************************/
     107             : /*                          TranslateFeature()                          */
     108             : /************************************************************************/
     109             : 
     110           8 : bool OGRWarpedLayer::TranslateFeature(
     111             :     std::unique_ptr<OGRFeature> poSrcFeature,
     112             :     std::vector<std::unique_ptr<OGRFeature>> &apoOutFeatures)
     113             : {
     114           8 :     apoOutFeatures.push_back(
     115          16 :         SrcFeatureToWarpedFeature(std::move(poSrcFeature)));
     116           8 :     return true;
     117             : }
     118             : 
     119             : /************************************************************************/
     120             : /*                     SrcFeatureToWarpedFeature()                      */
     121             : /************************************************************************/
     122             : 
     123             : std::unique_ptr<OGRFeature>
     124         503 : OGRWarpedLayer::SrcFeatureToWarpedFeature(std::unique_ptr<OGRFeature> poFeature)
     125             : {
     126             :     // This is safe to do here as they have matching attribute and geometry
     127             :     // fields
     128         503 :     OGRLayer *poThisLayer = this;
     129         503 :     poFeature->SetFDefnUnsafe(poThisLayer->GetLayerDefn());
     130             : 
     131         503 :     OGRGeometry *poGeom = poFeature->GetGeomFieldRef(m_iGeomField);
     132         503 :     if (poGeom)
     133             :     {
     134         465 :         auto poNewGeom = OGRGeometryFactory::transformWithOptions(
     135         465 :             poGeom, m_poCT.get(), nullptr, m_transformCacheForward);
     136         465 :         poFeature->SetGeomFieldDirectly(m_iGeomField, poNewGeom);
     137             :     }
     138             : 
     139         503 :     return poFeature;
     140             : }
     141             : 
     142             : /************************************************************************/
     143             : /*                     WarpedFeatureToSrcFeature()                      */
     144             : /************************************************************************/
     145             : 
     146             : std::unique_ptr<OGRFeature>
     147           9 : OGRWarpedLayer::WarpedFeatureToSrcFeature(std::unique_ptr<OGRFeature> poFeature)
     148             : {
     149             :     // This is safe to do here as they have matching attribute and geometry
     150             :     // fields
     151           9 :     poFeature->SetFDefnUnsafe(m_poDecoratedLayer->GetLayerDefn());
     152             : 
     153           9 :     OGRGeometry *poGeom = poFeature->GetGeomFieldRef(m_iGeomField);
     154           9 :     if (poGeom)
     155             :     {
     156           7 :         if (!m_poReversedCT)
     157           0 :             return nullptr;
     158           7 :         auto poNewGeom = OGRGeometryFactory::transformWithOptions(
     159           7 :             poGeom, m_poReversedCT.get(), nullptr, m_transformCacheReverse);
     160           7 :         if (!poNewGeom)
     161           2 :             return nullptr;
     162           5 :         poFeature->SetGeomFieldDirectly(m_iGeomField, poNewGeom);
     163             :     }
     164             : 
     165           7 :     return poFeature;
     166             : }
     167             : 
     168             : /************************************************************************/
     169             : /*                           GetNextFeature()                           */
     170             : /************************************************************************/
     171             : 
     172         599 : OGRFeature *OGRWarpedLayer::GetNextFeature()
     173             : {
     174             :     while (true)
     175             :     {
     176             :         auto poFeature =
     177         599 :             std::unique_ptr<OGRFeature>(m_poDecoratedLayer->GetNextFeature());
     178         599 :         if (!poFeature)
     179         110 :             return nullptr;
     180             : 
     181         489 :         auto poFeatureNew = SrcFeatureToWarpedFeature(std::move(poFeature));
     182         489 :         const OGRGeometry *poGeom = poFeatureNew->GetGeomFieldRef(m_iGeomField);
     183         489 :         if (m_poFilterGeom != nullptr && !FilterGeometry(poGeom))
     184             :         {
     185           1 :             continue;
     186             :         }
     187             : 
     188         488 :         return poFeatureNew.release();
     189           1 :     }
     190             : }
     191             : 
     192             : /************************************************************************/
     193             : /*                             GetFeature()                             */
     194             : /************************************************************************/
     195             : 
     196           9 : OGRFeature *OGRWarpedLayer::GetFeature(GIntBig nFID)
     197             : {
     198             :     auto poFeature =
     199          18 :         std::unique_ptr<OGRFeature>(m_poDecoratedLayer->GetFeature(nFID));
     200           9 :     if (poFeature)
     201             :     {
     202           6 :         poFeature = SrcFeatureToWarpedFeature(std::move(poFeature));
     203             :     }
     204          18 :     return poFeature.release();
     205             : }
     206             : 
     207             : /************************************************************************/
     208             : /*                            ISetFeature()                             */
     209             : /************************************************************************/
     210             : 
     211           5 : OGRErr OGRWarpedLayer::ISetFeature(OGRFeature *poFeature)
     212             : {
     213             :     auto poFeatureNew = WarpedFeatureToSrcFeature(
     214          10 :         std::unique_ptr<OGRFeature>(poFeature->Clone()));
     215           5 :     if (!poFeatureNew)
     216           1 :         return OGRERR_FAILURE;
     217             : 
     218           4 :     return m_poDecoratedLayer->SetFeature(poFeatureNew.get());
     219             : }
     220             : 
     221             : /************************************************************************/
     222             : /*                         ISetFeatureUniqPtr()                         */
     223             : /************************************************************************/
     224             : 
     225           0 : OGRErr OGRWarpedLayer::ISetFeatureUniqPtr(std::unique_ptr<OGRFeature> poFeature)
     226             : {
     227           0 :     auto poFeatureNew = WarpedFeatureToSrcFeature(std::move(poFeature));
     228           0 :     if (!poFeatureNew)
     229           0 :         return OGRERR_FAILURE;
     230             : 
     231           0 :     return m_poDecoratedLayer->SetFeature(std::move(poFeatureNew));
     232             : }
     233             : 
     234             : /************************************************************************/
     235             : /*                           ICreateFeature()                           */
     236             : /************************************************************************/
     237             : 
     238           4 : OGRErr OGRWarpedLayer::ICreateFeature(OGRFeature *poFeature)
     239             : {
     240             :     auto poFeatureNew = WarpedFeatureToSrcFeature(
     241           8 :         std::unique_ptr<OGRFeature>(poFeature->Clone()));
     242           4 :     if (!poFeatureNew)
     243           1 :         return OGRERR_FAILURE;
     244             : 
     245           3 :     return m_poDecoratedLayer->CreateFeature(poFeatureNew.get());
     246             : }
     247             : 
     248             : /************************************************************************/
     249             : /*                       ICreateFeatureUniqPtr()                        */
     250             : /************************************************************************/
     251             : 
     252             : OGRErr
     253           0 : OGRWarpedLayer::ICreateFeatureUniqPtr(std::unique_ptr<OGRFeature> poFeature,
     254             :                                       GIntBig *pnFID)
     255             : {
     256           0 :     auto poFeatureNew = WarpedFeatureToSrcFeature(std::move(poFeature));
     257           0 :     if (!poFeatureNew)
     258           0 :         return OGRERR_FAILURE;
     259             : 
     260           0 :     return m_poDecoratedLayer->CreateFeature(std::move(poFeatureNew), pnFID);
     261             : }
     262             : 
     263             : /************************************************************************/
     264             : /*                           IUpsertFeature()                           */
     265             : /************************************************************************/
     266             : 
     267           0 : OGRErr OGRWarpedLayer::IUpsertFeature(OGRFeature *poFeature)
     268             : {
     269             :     auto poFeatureNew = WarpedFeatureToSrcFeature(
     270           0 :         std::unique_ptr<OGRFeature>(poFeature->Clone()));
     271           0 :     if (poFeatureNew == nullptr)
     272           0 :         return OGRERR_FAILURE;
     273             : 
     274           0 :     return m_poDecoratedLayer->UpsertFeature(poFeatureNew.get());
     275             : }
     276             : 
     277             : /************************************************************************/
     278             : /*                           IUpdateFeature()                           */
     279             : /************************************************************************/
     280             : 
     281           0 : OGRErr OGRWarpedLayer::IUpdateFeature(OGRFeature *poFeature,
     282             :                                       int nUpdatedFieldsCount,
     283             :                                       const int *panUpdatedFieldsIdx,
     284             :                                       int nUpdatedGeomFieldsCount,
     285             :                                       const int *panUpdatedGeomFieldsIdx,
     286             :                                       bool bUpdateStyleString)
     287             : {
     288             :     auto poFeatureNew = WarpedFeatureToSrcFeature(
     289           0 :         std::unique_ptr<OGRFeature>(poFeature->Clone()));
     290           0 :     if (!poFeatureNew)
     291           0 :         return OGRERR_FAILURE;
     292             : 
     293           0 :     return m_poDecoratedLayer->UpdateFeature(
     294             :         poFeatureNew.get(), nUpdatedFieldsCount, panUpdatedFieldsIdx,
     295           0 :         nUpdatedGeomFieldsCount, panUpdatedGeomFieldsIdx, bUpdateStyleString);
     296             : }
     297             : 
     298             : /************************************************************************/
     299             : /*                            GetLayerDefn()                            */
     300             : /************************************************************************/
     301             : 
     302         984 : const OGRFeatureDefn *OGRWarpedLayer::GetLayerDefn() const
     303             : {
     304         984 :     return m_poFeatureDefn;
     305             : }
     306             : 
     307             : /************************************************************************/
     308             : /*                           GetSpatialRef()                            */
     309             : /************************************************************************/
     310             : 
     311          31 : const OGRSpatialReference *OGRWarpedLayer::GetSpatialRef() const
     312             : {
     313          31 :     if (m_iGeomField == 0)
     314          31 :         return m_poSRS;
     315             :     else
     316           0 :         return OGRLayer::GetSpatialRef();
     317             : }
     318             : 
     319             : /************************************************************************/
     320             : /*                          GetFeatureCount()                           */
     321             : /************************************************************************/
     322             : 
     323          47 : GIntBig OGRWarpedLayer::GetFeatureCount(int bForce)
     324             : {
     325          47 :     if (m_poFilterGeom == nullptr)
     326          27 :         return m_poDecoratedLayer->GetFeatureCount(bForce);
     327             : 
     328          20 :     return OGRLayer::GetFeatureCount(bForce);
     329             : }
     330             : 
     331             : /************************************************************************/
     332             : /*                             IGetExtent()                             */
     333             : /************************************************************************/
     334             : 
     335          12 : OGRErr OGRWarpedLayer::IGetExtent(int iGeomField, OGREnvelope *psExtent,
     336             :                                   bool bForce)
     337             : {
     338          12 :     if (iGeomField == m_iGeomField)
     339             :     {
     340           8 :         if (sStaticEnvelope.IsInit())
     341             :         {
     342           1 :             *psExtent = sStaticEnvelope;
     343           1 :             return OGRERR_NONE;
     344             :         }
     345             : 
     346           7 :         OGREnvelope sExtent;
     347             :         OGRErr eErr =
     348           7 :             m_poDecoratedLayer->GetExtent(m_iGeomField, &sExtent, bForce);
     349           7 :         if (eErr != OGRERR_NONE)
     350           0 :             return eErr;
     351             : 
     352           7 :         if (ReprojectEnvelope(&sExtent, m_poCT.get()))
     353             :         {
     354           7 :             *psExtent = sExtent;
     355           7 :             return OGRERR_NONE;
     356             :         }
     357             :         else
     358           0 :             return OGRERR_FAILURE;
     359             :     }
     360             :     else
     361           4 :         return m_poDecoratedLayer->GetExtent(iGeomField, psExtent, bForce);
     362             : }
     363             : 
     364             : /************************************************************************/
     365             : /*                   TransformAndUpdateBBAndReturnX()                   */
     366             : /************************************************************************/
     367             : 
     368           0 : static double TransformAndUpdateBBAndReturnX(OGRCoordinateTransformation *poCT,
     369             :                                              double dfX, double dfY,
     370             :                                              double &dfMinX, double &dfMinY,
     371             :                                              double &dfMaxX, double &dfMaxY)
     372             : {
     373           0 :     int bSuccess = FALSE;
     374           0 :     poCT->Transform(1, &dfX, &dfY, nullptr, nullptr, &bSuccess);
     375           0 :     if (bSuccess)
     376             :     {
     377           0 :         if (dfX < dfMinX)
     378           0 :             dfMinX = dfX;
     379           0 :         if (dfY < dfMinY)
     380           0 :             dfMinY = dfY;
     381           0 :         if (dfX > dfMaxX)
     382           0 :             dfMaxX = dfX;
     383           0 :         if (dfY > dfMaxY)
     384           0 :             dfMaxY = dfY;
     385           0 :         return dfX;
     386             :     }
     387             : 
     388           0 :     return 0.0;
     389             : }
     390             : 
     391             : /************************************************************************/
     392             : /*                         FindXDiscontinuity()                         */
     393             : /************************************************************************/
     394             : 
     395           0 : static void FindXDiscontinuity(OGRCoordinateTransformation *poCT, double dfX1,
     396             :                                double dfX2, double dfY, double &dfMinX,
     397             :                                double &dfMinY, double &dfMaxX, double &dfMaxY,
     398             :                                int nRecLevel = 0)
     399             : {
     400           0 :     double dfXMid = (dfX1 + dfX2) / 2;
     401             : 
     402           0 :     double dfWrkX1 = TransformAndUpdateBBAndReturnX(poCT, dfX1, dfY, dfMinX,
     403             :                                                     dfMinY, dfMaxX, dfMaxY);
     404           0 :     double dfWrkXMid = TransformAndUpdateBBAndReturnX(poCT, dfXMid, dfY, dfMinX,
     405             :                                                       dfMinY, dfMaxX, dfMaxY);
     406           0 :     double dfWrkX2 = TransformAndUpdateBBAndReturnX(poCT, dfX2, dfY, dfMinX,
     407             :                                                     dfMinY, dfMaxX, dfMaxY);
     408             : 
     409           0 :     double dfDX1 = dfWrkXMid - dfWrkX1;
     410           0 :     double dfDX2 = dfWrkX2 - dfWrkXMid;
     411             : 
     412           0 :     if (dfDX1 * dfDX2 < 0 && nRecLevel < 30)
     413             :     {
     414           0 :         FindXDiscontinuity(poCT, dfX1, dfXMid, dfY, dfMinX, dfMinY, dfMaxX,
     415             :                            dfMaxY, nRecLevel + 1);
     416           0 :         FindXDiscontinuity(poCT, dfXMid, dfX2, dfY, dfMinX, dfMinY, dfMaxX,
     417             :                            dfMaxY, nRecLevel + 1);
     418             :     }
     419           0 : }
     420             : 
     421             : /************************************************************************/
     422             : /*                         ReprojectEnvelope()                          */
     423             : /************************************************************************/
     424             : 
     425          32 : int OGRWarpedLayer::ReprojectEnvelope(OGREnvelope *psEnvelope,
     426             :                                       OGRCoordinateTransformation *poCT)
     427             : {
     428          32 :     const int NSTEP = 20;
     429          32 :     double dfXStep = (psEnvelope->MaxX - psEnvelope->MinX) / NSTEP;
     430          32 :     double dfYStep = (psEnvelope->MaxY - psEnvelope->MinY) / NSTEP;
     431             : 
     432             :     double *padfX = static_cast<double *>(
     433          32 :         VSI_MALLOC_VERBOSE((NSTEP + 1) * (NSTEP + 1) * sizeof(double)));
     434             :     double *padfY = static_cast<double *>(
     435          32 :         VSI_MALLOC_VERBOSE((NSTEP + 1) * (NSTEP + 1) * sizeof(double)));
     436             :     int *pabSuccess = static_cast<int *>(
     437          32 :         VSI_MALLOC_VERBOSE((NSTEP + 1) * (NSTEP + 1) * sizeof(int)));
     438          32 :     if (padfX == nullptr || padfY == nullptr || pabSuccess == nullptr)
     439             :     {
     440           0 :         VSIFree(padfX);
     441           0 :         VSIFree(padfY);
     442           0 :         VSIFree(pabSuccess);
     443           0 :         return FALSE;
     444             :     }
     445             : 
     446         704 :     for (int j = 0; j <= NSTEP; j++)
     447             :     {
     448       14784 :         for (int i = 0; i <= NSTEP; i++)
     449             :         {
     450       14112 :             padfX[j * (NSTEP + 1) + i] = psEnvelope->MinX + i * dfXStep;
     451       14112 :             padfY[j * (NSTEP + 1) + i] = psEnvelope->MinY + j * dfYStep;
     452             :         }
     453             :     }
     454             : 
     455          32 :     int bRet = FALSE;
     456             : 
     457          64 :     if (poCT->Transform((NSTEP + 1) * (NSTEP + 1), padfX, padfY, nullptr,
     458          32 :                         nullptr, pabSuccess))
     459             :     {
     460          29 :         double dfMinX = 0.0;
     461          29 :         double dfMinY = 0.0;
     462          29 :         double dfMaxX = 0.0;
     463          29 :         double dfMaxY = 0.0;
     464          29 :         int bSet = FALSE;
     465         638 :         for (int j = 0; j <= NSTEP; j++)
     466             :         {
     467         609 :             double dfXOld = 0.0;
     468         609 :             double dfDXOld = 0.0;
     469         609 :             int iOld = -1;
     470         609 :             int iOldOld = -1;
     471       13398 :             for (int i = 0; i <= NSTEP; i++)
     472             :             {
     473       12789 :                 if (pabSuccess[j * (NSTEP + 1) + i])
     474             :                 {
     475       12789 :                     double dfX = padfX[j * (NSTEP + 1) + i];
     476       12789 :                     double dfY = padfY[j * (NSTEP + 1) + i];
     477             : 
     478       12789 :                     if (!bSet)
     479             :                     {
     480          29 :                         dfMinX = dfX;
     481          29 :                         dfMaxX = dfX;
     482          29 :                         dfMinY = dfY;
     483          29 :                         dfMaxY = dfY;
     484          29 :                         bSet = TRUE;
     485             :                     }
     486             :                     else
     487             :                     {
     488       12760 :                         if (dfX < dfMinX)
     489         150 :                             dfMinX = dfX;
     490       12760 :                         if (dfY < dfMinY)
     491          84 :                             dfMinY = dfY;
     492       12760 :                         if (dfX > dfMaxX)
     493         662 :                             dfMaxX = dfX;
     494       12760 :                         if (dfY > dfMaxY)
     495        3796 :                             dfMaxY = dfY;
     496             :                     }
     497             : 
     498       12789 :                     if (iOld >= 0)
     499             :                     {
     500       12180 :                         double dfDXNew = dfX - dfXOld;
     501       12180 :                         if (iOldOld >= 0 && dfDXNew * dfDXOld < 0)
     502             :                         {
     503           0 :                             FindXDiscontinuity(
     504           0 :                                 poCT, psEnvelope->MinX + iOldOld * dfXStep,
     505           0 :                                 psEnvelope->MinX + i * dfXStep,
     506           0 :                                 psEnvelope->MinY + j * dfYStep, dfMinX, dfMinY,
     507             :                                 dfMaxX, dfMaxY);
     508             :                         }
     509       12180 :                         dfDXOld = dfDXNew;
     510             :                     }
     511             : 
     512       12789 :                     dfXOld = dfX;
     513       12789 :                     iOldOld = iOld;
     514       12789 :                     iOld = i;
     515             :                 }
     516             :             }
     517             :         }
     518          29 :         if (bSet)
     519             :         {
     520          29 :             psEnvelope->MinX = dfMinX;
     521          29 :             psEnvelope->MinY = dfMinY;
     522          29 :             psEnvelope->MaxX = dfMaxX;
     523          29 :             psEnvelope->MaxY = dfMaxY;
     524          29 :             bRet = TRUE;
     525             :         }
     526             :     }
     527             : 
     528          32 :     VSIFree(padfX);
     529          32 :     VSIFree(padfY);
     530          32 :     VSIFree(pabSuccess);
     531             : 
     532          32 :     return bRet;
     533             : }
     534             : 
     535             : /************************************************************************/
     536             : /*                           TestCapability()                           */
     537             : /************************************************************************/
     538             : 
     539         126 : int OGRWarpedLayer::TestCapability(const char *pszCapability) const
     540             : {
     541         126 :     if (EQUAL(pszCapability, OLCFastGetExtent) && sStaticEnvelope.IsInit())
     542           0 :         return TRUE;
     543             : 
     544         126 :     int bVal = m_poDecoratedLayer->TestCapability(pszCapability);
     545             : 
     546         126 :     if (EQUAL(pszCapability, OLCFastGetArrowStream))
     547           9 :         return false;
     548             : 
     549         117 :     if (EQUAL(pszCapability, OLCFastSpatialFilter) ||
     550         117 :         EQUAL(pszCapability, OLCRandomWrite) ||
     551         116 :         EQUAL(pszCapability, OLCSequentialWrite))
     552             :     {
     553           2 :         if (bVal)
     554           0 :             bVal = m_poReversedCT != nullptr;
     555             :     }
     556         115 :     else if (EQUAL(pszCapability, OLCFastFeatureCount))
     557             :     {
     558           2 :         if (bVal)
     559           2 :             bVal = m_poFilterGeom == nullptr;
     560             :     }
     561             : 
     562         117 :     return bVal;
     563             : }
     564             : 
     565             : /************************************************************************/
     566             : /*                             SetExtent()                              */
     567             : /************************************************************************/
     568             : 
     569           1 : void OGRWarpedLayer::SetExtent(double dfXMin, double dfYMin, double dfXMax,
     570             :                                double dfYMax)
     571             : {
     572           1 :     sStaticEnvelope.MinX = dfXMin;
     573           1 :     sStaticEnvelope.MinY = dfYMin;
     574           1 :     sStaticEnvelope.MaxX = dfXMax;
     575           1 :     sStaticEnvelope.MaxY = dfYMax;
     576           1 : }
     577             : 
     578             : /************************************************************************/
     579             : /*                           GetArrowStream()                           */
     580             : /************************************************************************/
     581             : 
     582           7 : bool OGRWarpedLayer::GetArrowStream(struct ArrowArrayStream *out_stream,
     583             :                                     CSLConstList papszOptions)
     584             : {
     585           7 :     return OGRLayer::GetArrowStream(out_stream, papszOptions);
     586             : }
     587             : 
     588             : #endif /* #ifndef DOXYGEN_SKIP */

Generated by: LCOV version 1.14