Coverage Report

Created: 2026-04-10 07:04

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