LCOV - code coverage report
Current view: top level - apps - gdalalg_vector_reproject.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 75 80 93.8 %
Date: 2026-07-24 18:27:47 Functions: 2 2 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL
       4             :  * Purpose:  "reproject" step of "vector pipeline"
       5             :  * Author:   Even Rouault <even dot rouault at spatialys.com>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2024, Even Rouault <even dot rouault at spatialys.com>
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #include "gdalalg_vector_reproject.h"
      14             : 
      15             : #include "gdal_priv.h"
      16             : #include "ogr_spatialref.h"
      17             : #include "ogrsf_frmts.h"
      18             : #include "ogrwarpedlayer.h"
      19             : 
      20             : //! @cond Doxygen_Suppress
      21             : 
      22             : #ifndef _
      23             : #define _(x) (x)
      24             : #endif
      25             : 
      26             : /************************************************************************/
      27             : /*     GDALVectorReprojectAlgorithm::GDALVectorReprojectAlgorithm()     */
      28             : /************************************************************************/
      29             : 
      30         113 : GDALVectorReprojectAlgorithm::GDALVectorReprojectAlgorithm(bool standaloneStep)
      31             :     : GDALVectorPipelineStepAlgorithm(NAME, DESCRIPTION, HELP_URL,
      32         113 :                                       standaloneStep)
      33             : {
      34         113 :     AddActiveLayerArg(&m_activeLayer);
      35         226 :     AddArg(GDAL_ARG_NAME_INPUT_CRS, 's', _("Input CRS"), &m_srcCrs)
      36         226 :         .SetIsCRSArg()
      37         226 :         .AddHiddenAlias("src-crs")
      38         113 :         .AddHiddenAlias("s_srs");
      39         226 :     AddArg(GDAL_ARG_NAME_OUTPUT_CRS, 'd', _("Output CRS"), &m_dstCrs)
      40         226 :         .SetIsCRSArg()
      41         226 :         .AddHiddenAlias("dst-crs")
      42         226 :         .AddHiddenAlias("t_srs")
      43         113 :         .SetMutualExclusionGroup("output-crs");
      44             :     AddArg("like", 0, _("Dataset from which an output CRS should be extracted"),
      45         226 :            &m_likeDataset, GDAL_OF_RASTER | GDAL_OF_VECTOR)
      46         226 :         .SetMetaVar("DATASET")
      47         113 :         .SetMutualExclusionGroup("output-crs");
      48             :     AddArg("like-layer", 0, ("Name of the layer of the 'like' dataset"),
      49         226 :            &m_likeLayer)
      50         113 :         .SetMetaVar("LAYER-NAME");
      51         113 : }
      52             : 
      53             : /************************************************************************/
      54             : /*               GDALVectorReprojectAlgorithm::RunStep()                */
      55             : /************************************************************************/
      56             : 
      57          23 : bool GDALVectorReprojectAlgorithm::RunStep(GDALPipelineStepRunContext &)
      58             : {
      59          23 :     auto poSrcDS = m_inputDataset[0].GetDatasetRef();
      60          23 :     CPLAssert(poSrcDS);
      61             : 
      62          23 :     CPLAssert(m_outputDataset.GetName().empty());
      63          23 :     CPLAssert(!m_outputDataset.GetDatasetRef());
      64             : 
      65          23 :     std::unique_ptr<OGRSpatialReference> poSrcCRS;
      66          23 :     if (!m_srcCrs.empty())
      67             :     {
      68           3 :         poSrcCRS = std::make_unique<OGRSpatialReference>();
      69           3 :         poSrcCRS->SetFromUserInput(m_srcCrs.c_str());
      70           3 :         poSrcCRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
      71             :     }
      72             : 
      73          46 :     OGRSpatialReference oDstCRS;
      74          23 :     if (!m_dstCrs.empty())
      75             :     {
      76          14 :         oDstCRS.SetFromUserInput(m_dstCrs.c_str());
      77          14 :         oDstCRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
      78             :     }
      79           9 :     else if (auto *poLikeDS = m_likeDataset.GetDatasetRef())
      80             :     {
      81           5 :         if (!m_likeLayer.empty())
      82             :         {
      83             :             const auto *poLikeLayer =
      84           3 :                 poLikeDS->GetLayerByName(m_likeLayer.c_str());
      85           3 :             if (!poLikeLayer)
      86             :             {
      87           1 :                 ReportError(CE_Failure, CPLE_AppDefined,
      88             :                             "Specified layer '%s' not found.",
      89             :                             m_likeLayer.c_str());
      90           1 :                 return false;
      91             :             }
      92           2 :             if (!poLikeLayer->GetSpatialRef())
      93             :             {
      94           0 :                 ReportError(
      95             :                     CE_Failure, CPLE_AppDefined,
      96             :                     "Specified layer '%s' has no spatial reference system.",
      97             :                     m_likeLayer.c_str());
      98           0 :                 return false;
      99             :             }
     100             : 
     101           2 :             oDstCRS = *poLikeLayer->GetSpatialRef();
     102             :         }
     103             :         else
     104             :         {
     105           2 :             const auto *poLikeCRS = poLikeDS->GetSpatialRef();
     106             : 
     107           2 :             if (!poLikeCRS)
     108             :             {
     109           0 :                 ReportError(
     110             :                     CE_Failure, CPLE_AppDefined,
     111             :                     "Dataset specified by --like has no spatial reference "
     112             :                     "system, or has multiple layers with different spatial "
     113             :                     "reference systems. An individual layer can be specified "
     114             :                     "with --like-layer.");
     115           0 :                 return false;
     116             :             }
     117           2 :             oDstCRS = *poLikeCRS;
     118             :         }
     119             :     }
     120             :     else
     121             :     {
     122           4 :         ReportError(CE_Failure, CPLE_AppDefined,
     123             :                     "Must specify --output-crs or --like");
     124           4 :         return false;
     125             :     }
     126             : 
     127             :     auto reprojectedDataset =
     128          36 :         std::make_unique<GDALVectorPipelineOutputDataset>(*poSrcDS);
     129             : 
     130          18 :     const int nLayerCount = poSrcDS->GetLayerCount();
     131          18 :     bool ret = true;
     132          52 :     for (int i = 0; ret && i < nLayerCount; ++i)
     133             :     {
     134          35 :         auto poSrcLayer = poSrcDS->GetLayer(i);
     135          35 :         ret = (poSrcLayer != nullptr);
     136          35 :         if (ret)
     137             :         {
     138          35 :             if ((m_activeLayer.empty() &&
     139          53 :                  poSrcLayer->GetGeomType() != wkbNone) ||
     140          18 :                 m_activeLayer == poSrcLayer->GetDescription())
     141             :             {
     142             :                 const OGRSpatialReference *poSrcLayerCRS;
     143          18 :                 if (poSrcCRS)
     144           3 :                     poSrcLayerCRS = poSrcCRS.get();
     145             :                 else
     146          15 :                     poSrcLayerCRS = poSrcLayer->GetSpatialRef();
     147          18 :                 if (!poSrcLayerCRS)
     148             :                 {
     149           1 :                     ReportError(CE_Failure, CPLE_AppDefined,
     150             :                                 "Layer '%s' has no spatial reference system",
     151           1 :                                 poSrcLayer->GetName());
     152           1 :                     return false;
     153             :                 }
     154             :                 auto poCT = std::unique_ptr<OGRCoordinateTransformation>(
     155          34 :                     OGRCreateCoordinateTransformation(poSrcLayerCRS, &oDstCRS));
     156             :                 auto poReversedCT =
     157             :                     std::unique_ptr<OGRCoordinateTransformation>(
     158             :                         OGRCreateCoordinateTransformation(&oDstCRS,
     159          34 :                                                           poSrcLayerCRS));
     160          17 :                 ret = (poCT != nullptr) && (poReversedCT != nullptr);
     161          17 :                 if (ret)
     162             :                 {
     163          34 :                     reprojectedDataset->AddLayer(
     164             :                         *poSrcLayer,
     165          17 :                         std::make_unique<OGRWarpedLayer>(
     166           0 :                             poSrcLayer, /* iGeomField = */ 0,
     167          34 :                             /*bTakeOwnership = */ false, std::move(poCT),
     168          17 :                             std::move(poReversedCT)));
     169             :                 }
     170             :             }
     171             :             else
     172             :             {
     173          34 :                 reprojectedDataset->AddLayer(
     174             :                     *poSrcLayer,
     175          34 :                     std::make_unique<GDALVectorPipelinePassthroughLayer>(
     176             :                         *poSrcLayer));
     177             :             }
     178             :         }
     179             :     }
     180             : 
     181          17 :     if (ret)
     182          17 :         m_outputDataset.Set(std::move(reprojectedDataset));
     183             : 
     184          17 :     return ret;
     185             : }
     186             : 
     187             : GDALVectorReprojectAlgorithmStandalone::
     188             :     ~GDALVectorReprojectAlgorithmStandalone() = default;
     189             : 
     190             : //! @endcond

Generated by: LCOV version 1.14