LCOV - code coverage report
Current view: top level - apps - gdalalg_vector_make_point.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 113 118 95.8 %
Date: 2026-04-23 19:47:11 Functions: 8 8 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL
       4             :  * Purpose:  "gdal vector make-point"
       5             :  * Author:   Dan Baston
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2025, ISciences LLC
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #include "gdalalg_vector_make_point.h"
      14             : 
      15             : #include "gdal_priv.h"
      16             : #include "ogrsf_frmts.h"
      17             : 
      18             : //! @cond Doxygen_Suppress
      19             : 
      20             : #ifndef _
      21             : #define _(x) (x)
      22             : #endif
      23             : 
      24             : /************************************************************************/
      25             : /*                    GDALVectorMakePointAlgorithm()                    */
      26             : /************************************************************************/
      27             : 
      28          91 : GDALVectorMakePointAlgorithm::GDALVectorMakePointAlgorithm(bool standaloneStep)
      29             :     : GDALVectorPipelineStepAlgorithm(NAME, DESCRIPTION, HELP_URL,
      30          91 :                                       standaloneStep)
      31             : {
      32         182 :     AddArg("x", 0, _("Field from which X coordinate should be read"), &m_xField)
      33          91 :         .SetRequired();
      34         182 :     AddArg("y", 0, _("Field from which Y coordinate should be read"), &m_yField)
      35          91 :         .SetRequired();
      36             :     AddArg("z", 0, _("Optional field from which Z coordinate should be read"),
      37          91 :            &m_zField);
      38             :     AddArg("m", 0, _("Optional field from which M coordinate should be read"),
      39          91 :            &m_mField);
      40         182 :     AddArg(GDAL_ARG_NAME_OUTPUT_CRS, 0, _("Output CRS"), &m_dstCrs)
      41         182 :         .AddHiddenAlias("dst-crs")
      42          91 :         .SetIsCRSArg();
      43          91 : }
      44             : 
      45             : namespace
      46             : {
      47             : 
      48             : /************************************************************************/
      49             : /*                  GDALVectorMakePointAlgorithmLayer                   */
      50             : /************************************************************************/
      51             : 
      52             : class GDALVectorMakePointAlgorithmLayer final
      53             :     : public GDALVectorPipelineOutputLayer
      54             : {
      55             :   public:
      56          12 :     GDALVectorMakePointAlgorithmLayer(OGRLayer &oSrcLayer,
      57             :                                       const std::string &xField,
      58             :                                       const std::string &yField,
      59             :                                       const std::string &zField,
      60             :                                       const std::string &mField,
      61             :                                       OGRSpatialReferenceRefCountedPtr srs)
      62          12 :         : GDALVectorPipelineOutputLayer(oSrcLayer), m_xField(xField),
      63             :           m_yField(yField), m_zField(zField), m_mField(mField),
      64             :           m_xFieldIndex(
      65          12 :               oSrcLayer.GetLayerDefn()->GetFieldIndex(xField.c_str())),
      66             :           m_yFieldIndex(
      67          12 :               oSrcLayer.GetLayerDefn()->GetFieldIndex(yField.c_str())),
      68             :           m_zFieldIndex(
      69          12 :               zField.empty()
      70          12 :                   ? -1
      71           6 :                   : oSrcLayer.GetLayerDefn()->GetFieldIndex(zField.c_str())),
      72             :           m_mFieldIndex(
      73          12 :               mField.empty()
      74          12 :                   ? -1
      75           6 :                   : oSrcLayer.GetLayerDefn()->GetFieldIndex(mField.c_str())),
      76          36 :           m_hasZ(!zField.empty()), m_hasM(!mField.empty()),
      77          60 :           m_srs(std::move(srs)), m_defn(oSrcLayer.GetLayerDefn()->Clone())
      78             :     {
      79          12 :         if (!CheckField("X", m_xField, m_xFieldIndex, m_xFieldIsString))
      80           4 :             return;
      81          11 :         if (!CheckField("Y", m_yField, m_yFieldIndex, m_yFieldIsString))
      82           1 :             return;
      83          14 :         if (m_hasZ &&
      84          14 :             !CheckField("Z", m_zField, m_zFieldIndex, m_zFieldIsString))
      85           1 :             return;
      86          12 :         if (m_hasM &&
      87          12 :             !CheckField("M", m_mField, m_mFieldIndex, m_mFieldIsString))
      88           1 :             return;
      89             : 
      90           8 :         OGRwkbGeometryType eGeomType = wkbPoint;
      91           8 :         if (m_hasZ)
      92           2 :             eGeomType = OGR_GT_SetZ(eGeomType);
      93           8 :         if (m_hasM)
      94           2 :             eGeomType = OGR_GT_SetM(eGeomType);
      95             : 
      96             :         auto poGeomFieldDefn =
      97          16 :             std::make_unique<OGRGeomFieldDefn>("geometry", eGeomType);
      98           8 :         if (m_srs)
      99             :         {
     100           4 :             poGeomFieldDefn->SetSpatialRef(m_srs.get());
     101             :         }
     102             : 
     103           9 :         while (m_defn->GetGeomFieldCount() > 0)
     104           1 :             m_defn->DeleteGeomFieldDefn(0);
     105           8 :         m_defn->AddGeomFieldDefn(std::move(poGeomFieldDefn));
     106             :     }
     107             : 
     108          58 :     double GetField(const OGRFeature &feature, int fieldIndex, bool isString)
     109             :     {
     110          58 :         if (isString)
     111             :         {
     112           6 :             const char *pszValue = feature.GetFieldAsString(fieldIndex);
     113           8 :             while (std::isspace(static_cast<unsigned char>(*pszValue)))
     114             :             {
     115           2 :                 pszValue++;
     116             :             }
     117           6 :             char *end = nullptr;
     118           6 :             double dfValue = CPLStrtodM(pszValue, &end);
     119           6 :             while (std::isspace(static_cast<unsigned char>(*end)))
     120             :             {
     121           0 :                 end++;
     122             :             }
     123           6 :             if (end == pszValue || *end != '\0')
     124             :             {
     125             :                 const char *pszFieldName =
     126           3 :                     m_defn->GetFieldDefn(fieldIndex)->GetNameRef();
     127           3 :                 CPLError(CE_Failure, CPLE_AppDefined,
     128             :                          "Invalid value in field %s: %s ", pszFieldName,
     129             :                          pszValue);
     130           3 :                 FailTranslation();
     131             :             }
     132           6 :             return dfValue;
     133             :         }
     134             :         else
     135             :         {
     136          52 :             return feature.GetFieldAsDouble(fieldIndex);
     137             :         }
     138             :     }
     139             : 
     140          30 :     bool CheckField(const std::string &dim, const std::string &fieldName,
     141             :                     int index, bool &isStringVar)
     142             :     {
     143          30 :         if (index == -1)
     144             :         {
     145           4 :             CPLError(CE_Failure, CPLE_AppDefined,
     146             :                      "Specified %s field name '%s' does not exist", dim.c_str(),
     147             :                      fieldName.c_str());
     148           4 :             FailTranslation();
     149           4 :             return false;
     150             :         }
     151             : 
     152          26 :         const auto eType = m_defn->GetFieldDefn(index)->GetType();
     153          26 :         if (eType == OFTString)
     154             :         {
     155           6 :             isStringVar = true;
     156             :         }
     157          20 :         else if (eType != OFTInteger && eType != OFTReal)
     158             :         {
     159           0 :             CPLError(CE_Failure, CPLE_AppDefined, "Invalid %s field type: %s",
     160             :                      dim.c_str(), OGR_GetFieldTypeName(eType));
     161           0 :             FailTranslation();
     162           0 :             return false;
     163             :         }
     164             : 
     165          26 :         return true;
     166             :     }
     167             : 
     168          91 :     const OGRFeatureDefn *GetLayerDefn() const override
     169             :     {
     170          91 :         return m_defn.get();
     171             :     }
     172             : 
     173          12 :     int TestCapability(const char *pszCap) const override
     174             :     {
     175          12 :         return m_srcLayer.TestCapability(pszCap);
     176             :     }
     177             : 
     178             :   private:
     179             :     void TranslateFeature(
     180             :         std::unique_ptr<OGRFeature> poSrcFeature,
     181             :         std::vector<std::unique_ptr<OGRFeature>> &apoOutFeatures) override;
     182             : 
     183             :     const std::string m_xField;
     184             :     const std::string m_yField;
     185             :     const std::string m_zField;
     186             :     const std::string m_mField;
     187             :     const int m_xFieldIndex;
     188             :     const int m_yFieldIndex;
     189             :     const int m_zFieldIndex;
     190             :     const int m_mFieldIndex;
     191             :     const bool m_hasZ;
     192             :     const bool m_hasM;
     193             :     bool m_xFieldIsString = false;
     194             :     bool m_yFieldIsString = false;
     195             :     bool m_zFieldIsString = false;
     196             :     bool m_mFieldIsString = false;
     197             :     const OGRSpatialReferenceRefCountedPtr m_srs;
     198             :     const OGRFeatureDefnRefCountedPtr m_defn;
     199             : 
     200             :     CPL_DISALLOW_COPY_ASSIGN(GDALVectorMakePointAlgorithmLayer)
     201             : };
     202             : 
     203             : /************************************************************************/
     204             : /*                          TranslateFeature()                          */
     205             : /************************************************************************/
     206             : 
     207          19 : void GDALVectorMakePointAlgorithmLayer::TranslateFeature(
     208             :     std::unique_ptr<OGRFeature> poSrcFeature,
     209             :     std::vector<std::unique_ptr<OGRFeature>> &apoOutFeatures)
     210             : {
     211          19 :     const double x = GetField(*poSrcFeature, m_xFieldIndex, m_xFieldIsString);
     212          19 :     const double y = GetField(*poSrcFeature, m_yFieldIndex, m_yFieldIsString);
     213             :     const double z =
     214          19 :         m_hasZ ? GetField(*poSrcFeature, m_zFieldIndex, m_zFieldIsString) : 0;
     215             :     const double m =
     216          19 :         m_hasM ? GetField(*poSrcFeature, m_mFieldIndex, m_mFieldIsString) : 0;
     217             : 
     218          19 :     std::unique_ptr<OGRPoint> poGeom;
     219             : 
     220          19 :     if (m_hasZ && m_hasM)
     221             :     {
     222           7 :         poGeom = std::make_unique<OGRPoint>(x, y, z, m);
     223             :     }
     224          12 :     else if (m_hasZ)
     225             :     {
     226           3 :         poGeom = std::make_unique<OGRPoint>(x, y, z);
     227             :     }
     228           9 :     else if (m_hasM)
     229             :     {
     230           3 :         poGeom.reset(OGRPoint::createXYM(x, y, m));
     231             :     }
     232             :     else
     233             :     {
     234           6 :         poGeom = std::make_unique<OGRPoint>(x, y);
     235             :     }
     236             : 
     237          19 :     if (m_srs)
     238             :     {
     239          12 :         poGeom->assignSpatialReference(m_srs.get());
     240             :     }
     241             : 
     242          38 :     auto poDstFeature = std::make_unique<OGRFeature>(m_defn.get());
     243          19 :     poDstFeature->SetFID(poSrcFeature->GetFID());
     244          19 :     poDstFeature->SetFrom(poSrcFeature.get());
     245          19 :     poDstFeature->SetGeometry(std::move(poGeom));
     246             : 
     247          19 :     apoOutFeatures.push_back(std::move(poDstFeature));
     248          19 : }
     249             : 
     250             : }  // namespace
     251             : 
     252             : /************************************************************************/
     253             : /*               GDALVectorMakePointAlgorithm::RunStep()                */
     254             : /************************************************************************/
     255             : 
     256          13 : bool GDALVectorMakePointAlgorithm::RunStep(GDALPipelineStepRunContext &)
     257             : {
     258          13 :     GDALDataset *poSrcDS = m_inputDataset[0].GetDatasetRef();
     259          13 :     if (poSrcDS->GetLayerCount() == 0)
     260             :     {
     261           1 :         ReportError(CE_Failure, CPLE_AppDefined, "No input vector layer");
     262           1 :         return false;
     263             :     }
     264          12 :     OGRLayer *poSrcLayer = poSrcDS->GetLayer(0);
     265             : 
     266          24 :     OGRSpatialReferenceRefCountedPtr poCRS;
     267          12 :     if (!m_dstCrs.empty())
     268             :     {
     269           4 :         poCRS = OGRSpatialReferenceRefCountedPtr::makeInstance();
     270           4 :         poCRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     271           4 :         auto eErr = poCRS->SetFromUserInput(m_dstCrs.c_str());
     272           4 :         if (eErr != OGRERR_NONE)
     273             :         {
     274           0 :             return false;
     275             :         }
     276             :     }
     277             : 
     278          12 :     auto outDS = std::make_unique<GDALVectorPipelineOutputDataset>(*poSrcDS);
     279             : 
     280          24 :     outDS->AddLayer(*poSrcLayer,
     281          12 :                     std::make_unique<GDALVectorMakePointAlgorithmLayer>(
     282          12 :                         *poSrcLayer, m_xField, m_yField, m_zField, m_mField,
     283          12 :                         std::move(poCRS)));
     284             : 
     285          12 :     m_outputDataset.Set(std::move(outDS));
     286             : 
     287          12 :     return true;
     288             : }
     289             : 
     290             : GDALVectorMakePointAlgorithmStandalone::
     291             :     ~GDALVectorMakePointAlgorithmStandalone() = default;
     292             : 
     293             : //! @endcond

Generated by: LCOV version 1.14