LCOV - code coverage report
Current view: top level - apps - gdalalg_vector_make_point.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 115 120 95.8 %
Date: 2026-06-23 16:35:19 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          93 : GDALVectorMakePointAlgorithm::GDALVectorMakePointAlgorithm(bool standaloneStep)
      29             :     : GDALVectorPipelineStepAlgorithm(NAME, DESCRIPTION, HELP_URL,
      30          93 :                                       standaloneStep)
      31             : {
      32         186 :     AddArg("x", 0, _("Field from which X coordinate should be read"), &m_xField)
      33          93 :         .SetRequired();
      34         186 :     AddArg("y", 0, _("Field from which Y coordinate should be read"), &m_yField)
      35          93 :         .SetRequired();
      36             :     AddArg("z", 0, _("Optional field from which Z coordinate should be read"),
      37          93 :            &m_zField);
      38             :     AddArg("m", 0, _("Optional field from which M coordinate should be read"),
      39          93 :            &m_mField);
      40         186 :     AddArg(GDAL_ARG_NAME_OUTPUT_CRS, 0, _("Output CRS"), &m_dstCrs)
      41         186 :         .AddHiddenAlias("dst-crs")
      42          93 :         .SetIsCRSArg();
      43          93 : }
      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 :                 m_fatalError = true;
     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 :             m_fatalError = true;
     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 :             m_fatalError = true;
     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             :   protected:
     179             :     bool TranslateFeature(
     180             :         std::unique_ptr<OGRFeature> poSrcFeature,
     181             :         std::vector<std::unique_ptr<OGRFeature>> &apoOutFeatures) override;
     182             : 
     183             :   private:
     184             :     const std::string m_xField;
     185             :     const std::string m_yField;
     186             :     const std::string m_zField;
     187             :     const std::string m_mField;
     188             :     const int m_xFieldIndex;
     189             :     const int m_yFieldIndex;
     190             :     const int m_zFieldIndex;
     191             :     const int m_mFieldIndex;
     192             :     const bool m_hasZ;
     193             :     const bool m_hasM;
     194             :     bool m_fatalError = false;
     195             :     bool m_xFieldIsString = false;
     196             :     bool m_yFieldIsString = false;
     197             :     bool m_zFieldIsString = false;
     198             :     bool m_mFieldIsString = false;
     199             :     const OGRSpatialReferenceRefCountedPtr m_srs;
     200             :     const OGRFeatureDefnRefCountedPtr m_defn;
     201             : 
     202             :     CPL_DISALLOW_COPY_ASSIGN(GDALVectorMakePointAlgorithmLayer)
     203             : };
     204             : 
     205             : /************************************************************************/
     206             : /*                          TranslateFeature()                          */
     207             : /************************************************************************/
     208             : 
     209          19 : bool GDALVectorMakePointAlgorithmLayer::TranslateFeature(
     210             :     std::unique_ptr<OGRFeature> poSrcFeature,
     211             :     std::vector<std::unique_ptr<OGRFeature>> &apoOutFeatures)
     212             : {
     213          19 :     const double x = GetField(*poSrcFeature, m_xFieldIndex, m_xFieldIsString);
     214          19 :     const double y = GetField(*poSrcFeature, m_yFieldIndex, m_yFieldIsString);
     215             :     const double z =
     216          19 :         m_hasZ ? GetField(*poSrcFeature, m_zFieldIndex, m_zFieldIsString) : 0;
     217             :     const double m =
     218          19 :         m_hasM ? GetField(*poSrcFeature, m_mFieldIndex, m_mFieldIsString) : 0;
     219             : 
     220          19 :     if (m_fatalError)
     221             :     {
     222           7 :         return false;
     223             :     }
     224             : 
     225          12 :     std::unique_ptr<OGRPoint> poGeom;
     226             : 
     227          12 :     if (m_hasZ && m_hasM)
     228             :     {
     229           3 :         poGeom = std::make_unique<OGRPoint>(x, y, z, m);
     230             :     }
     231           9 :     else if (m_hasZ)
     232             :     {
     233           3 :         poGeom = std::make_unique<OGRPoint>(x, y, z);
     234             :     }
     235           6 :     else if (m_hasM)
     236             :     {
     237           3 :         poGeom.reset(OGRPoint::createXYM(x, y, m));
     238             :     }
     239             :     else
     240             :     {
     241           3 :         poGeom = std::make_unique<OGRPoint>(x, y);
     242             :     }
     243             : 
     244          12 :     if (m_srs)
     245             :     {
     246          12 :         poGeom->assignSpatialReference(m_srs.get());
     247             :     }
     248             : 
     249          12 :     auto poDstFeature = std::make_unique<OGRFeature>(m_defn.get());
     250          12 :     poDstFeature->SetFID(poSrcFeature->GetFID());
     251          12 :     poDstFeature->SetFrom(poSrcFeature.get());
     252          12 :     poDstFeature->SetGeometry(std::move(poGeom));
     253             : 
     254          12 :     apoOutFeatures.push_back(std::move(poDstFeature));
     255             : 
     256          12 :     return true;
     257             : }
     258             : 
     259             : }  // namespace
     260             : 
     261             : /************************************************************************/
     262             : /*               GDALVectorMakePointAlgorithm::RunStep()                */
     263             : /************************************************************************/
     264             : 
     265          13 : bool GDALVectorMakePointAlgorithm::RunStep(GDALPipelineStepRunContext &)
     266             : {
     267          13 :     GDALDataset *poSrcDS = m_inputDataset[0].GetDatasetRef();
     268          13 :     if (poSrcDS->GetLayerCount() == 0)
     269             :     {
     270           1 :         ReportError(CE_Failure, CPLE_AppDefined, "No input vector layer");
     271           1 :         return false;
     272             :     }
     273          12 :     OGRLayer *poSrcLayer = poSrcDS->GetLayer(0);
     274             : 
     275          24 :     OGRSpatialReferenceRefCountedPtr poCRS;
     276          12 :     if (!m_dstCrs.empty())
     277             :     {
     278           4 :         poCRS = OGRSpatialReferenceRefCountedPtr::makeInstance();
     279           4 :         poCRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     280           4 :         auto eErr = poCRS->SetFromUserInput(m_dstCrs.c_str());
     281           4 :         if (eErr != OGRERR_NONE)
     282             :         {
     283           0 :             return false;
     284             :         }
     285             :     }
     286             : 
     287          12 :     auto outDS = std::make_unique<GDALVectorPipelineOutputDataset>(*poSrcDS);
     288             : 
     289          24 :     outDS->AddLayer(*poSrcLayer,
     290          12 :                     std::make_unique<GDALVectorMakePointAlgorithmLayer>(
     291          12 :                         *poSrcLayer, m_xField, m_yField, m_zField, m_mField,
     292          12 :                         std::move(poCRS)));
     293             : 
     294          12 :     m_outputDataset.Set(std::move(outDS));
     295             : 
     296          12 :     return true;
     297             : }
     298             : 
     299             : GDALVectorMakePointAlgorithmStandalone::
     300             :     ~GDALVectorMakePointAlgorithmStandalone() = default;
     301             : 
     302             : //! @endcond

Generated by: LCOV version 1.14