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

Generated by: LCOV version 1.14