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

Generated by: LCOV version 1.14