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

Generated by: LCOV version 1.14