Coverage Report

Created: 2025-06-13 06:29

/src/gdal/ogr/ogrmultipoint.cpp
Line
Count
Source (jump to first uncovered line)
1
/******************************************************************************
2
 *
3
 * Project:  OpenGIS Simple Features Reference Implementation
4
 * Purpose:  The OGRMultiPoint class.
5
 * Author:   Frank Warmerdam, warmerdam@pobox.com
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 1999, Frank Warmerdam
9
 * Copyright (c) 2008-2013, Even Rouault <even dot rouault at spatialys.com>
10
 *
11
 * SPDX-License-Identifier: MIT
12
 ****************************************************************************/
13
14
#include "cpl_port.h"
15
#include "ogr_geometry.h"
16
17
#include <cstddef>
18
#include <cstdio>
19
#include <cstring>
20
#include <new>
21
22
#include "cpl_conv.h"
23
#include "cpl_error.h"
24
#include "cpl_vsi.h"
25
#include "ogr_core.h"
26
#include "ogr_p.h"
27
28
/************************************************************************/
29
/*                OGRMultiPoint( const OGRMultiPoint& )                 */
30
/************************************************************************/
31
32
/**
33
 * \brief Copy constructor.
34
 *
35
 * Note: before GDAL 2.1, only the default implementation of the constructor
36
 * existed, which could be unsafe to use.
37
 *
38
 * @since GDAL 2.1
39
 */
40
41
0
OGRMultiPoint::OGRMultiPoint(const OGRMultiPoint &) = default;
42
43
/************************************************************************/
44
/*                  operator=( const OGRMultiPoint&)                    */
45
/************************************************************************/
46
47
/**
48
 * \brief Assignment operator.
49
 *
50
 * Note: before GDAL 2.1, only the default implementation of the operator
51
 * existed, which could be unsafe to use.
52
 *
53
 * @since GDAL 2.1
54
 */
55
56
OGRMultiPoint &OGRMultiPoint::operator=(const OGRMultiPoint &other)
57
0
{
58
0
    if (this != &other)
59
0
    {
60
0
        OGRGeometryCollection::operator=(other);
61
0
    }
62
0
    return *this;
63
0
}
64
65
/************************************************************************/
66
/*                               clone()                                */
67
/************************************************************************/
68
69
OGRMultiPoint *OGRMultiPoint::clone() const
70
71
0
{
72
0
    return new (std::nothrow) OGRMultiPoint(*this);
73
0
}
74
75
/************************************************************************/
76
/*                          getGeometryType()                           */
77
/************************************************************************/
78
79
OGRwkbGeometryType OGRMultiPoint::getGeometryType() const
80
81
6.41k
{
82
6.41k
    if ((flags & OGR_G_3D) && (flags & OGR_G_MEASURED))
83
3.32k
        return wkbMultiPointZM;
84
3.09k
    else if (flags & OGR_G_MEASURED)
85
39
        return wkbMultiPointM;
86
3.05k
    else if (flags & OGR_G_3D)
87
2.45k
        return wkbMultiPoint25D;
88
598
    else
89
598
        return wkbMultiPoint;
90
6.41k
}
91
92
/************************************************************************/
93
/*                            getDimension()                            */
94
/************************************************************************/
95
96
int OGRMultiPoint::getDimension() const
97
98
0
{
99
0
    return 0;
100
0
}
101
102
/************************************************************************/
103
/*                          getGeometryName()                           */
104
/************************************************************************/
105
106
const char *OGRMultiPoint::getGeometryName() const
107
108
967
{
109
967
    return "MULTIPOINT";
110
967
}
111
112
/************************************************************************/
113
/*                          isCompatibleSubType()                       */
114
/************************************************************************/
115
116
OGRBoolean
117
OGRMultiPoint::isCompatibleSubType(OGRwkbGeometryType eGeomType) const
118
4.09k
{
119
4.09k
    return wkbFlatten(eGeomType) == wkbPoint;
120
4.09k
}
121
122
/************************************************************************/
123
/*                            exportToWkt()                             */
124
/*                                                                      */
125
/*      Translate this structure into its well known text format        */
126
/*      equivalent.                                                     */
127
/************************************************************************/
128
129
std::string OGRMultiPoint::exportToWkt(const OGRWktOptions &opts,
130
                                       OGRErr *err) const
131
0
{
132
0
    try
133
0
    {
134
0
        std::string wkt = getGeometryName();
135
0
        wkt += wktTypeString(opts.variant);
136
137
0
        bool first(true);
138
        // OGRMultiPoint has a begin()/end().
139
0
        for (const OGRPoint *poPoint : this)
140
0
        {
141
0
            if (poPoint->IsEmpty())
142
0
                continue;
143
144
0
            if (first)
145
0
                wkt += '(';
146
0
            else
147
0
                wkt += ',';
148
0
            first = false;
149
150
0
            if (opts.variant == wkbVariantIso)
151
0
                wkt += '(';
152
153
0
            wkt += OGRMakeWktCoordinateM(
154
0
                poPoint->getX(), poPoint->getY(), poPoint->getZ(),
155
0
                poPoint->getM(), poPoint->Is3D(),
156
0
                poPoint->IsMeasured() && (opts.variant == wkbVariantIso), opts);
157
158
0
            if (opts.variant == wkbVariantIso)
159
0
                wkt += ')';
160
0
        }
161
162
0
        if (err)
163
0
            *err = OGRERR_NONE;
164
0
        if (first)
165
0
            wkt += "EMPTY";
166
0
        else
167
0
            wkt += ')';
168
0
        return wkt;
169
0
    }
170
0
    catch (const std::bad_alloc &e)
171
0
    {
172
0
        CPLError(CE_Failure, CPLE_OutOfMemory, "%s", e.what());
173
0
        if (err)
174
0
            *err = OGRERR_FAILURE;
175
0
        return std::string();
176
0
    }
177
0
}
178
179
/************************************************************************/
180
/*                           importFromWkt()                            */
181
/************************************************************************/
182
183
OGRErr OGRMultiPoint::importFromWkt(const char **ppszInput)
184
185
967
{
186
967
    const char *pszInputBefore = *ppszInput;
187
967
    int bHasZ = FALSE;
188
967
    int bHasM = FALSE;
189
967
    bool bIsEmpty = false;
190
967
    OGRErr eErr = importPreambleFromWkt(ppszInput, &bHasZ, &bHasM, &bIsEmpty);
191
967
    flags = 0;
192
967
    if (eErr != OGRERR_NONE)
193
7
        return eErr;
194
960
    if (bHasZ)
195
128
        flags |= OGR_G_3D;
196
960
    if (bHasM)
197
55
        flags |= OGR_G_MEASURED;
198
960
    if (bIsEmpty)
199
2
        return OGRERR_NONE;
200
201
958
    char szToken[OGR_WKT_TOKEN_MAX] = {};
202
958
    const char *pszInput = *ppszInput;
203
204
958
    const char *pszPreScan = OGRWktReadToken(pszInput, szToken);
205
958
    OGRWktReadToken(pszPreScan, szToken);
206
207
    // Do we have an inner bracket?
208
958
    if (EQUAL(szToken, "(") || EQUAL(szToken, "EMPTY"))
209
29
    {
210
29
        *ppszInput = pszInputBefore;
211
29
        return importFromWkt_Bracketed(ppszInput, bHasM, bHasZ);
212
29
    }
213
214
    /* -------------------------------------------------------------------- */
215
    /*      Read the point list.                                            */
216
    /* -------------------------------------------------------------------- */
217
929
    OGRRawPoint *paoPoints = nullptr;
218
929
    double *padfZ = nullptr;
219
929
    double *padfM = nullptr;
220
929
    int flagsFromInput = flags;
221
929
    int nMaxPoint = 0;
222
929
    int nPointCount = 0;
223
224
929
    pszInput = OGRWktReadPointsM(pszInput, &paoPoints, &padfZ, &padfM,
225
929
                                 &flagsFromInput, &nMaxPoint, &nPointCount);
226
929
    if (pszInput == nullptr)
227
21
    {
228
21
        CPLFree(paoPoints);
229
21
        CPLFree(padfZ);
230
21
        CPLFree(padfM);
231
21
        return OGRERR_CORRUPT_DATA;
232
21
    }
233
908
    if ((flagsFromInput & OGR_G_3D) && !(flags & OGR_G_3D))
234
620
    {
235
620
        flags |= OGR_G_3D;
236
620
        bHasZ = TRUE;
237
620
    }
238
908
    if ((flagsFromInput & OGR_G_MEASURED) && !(flags & OGR_G_MEASURED))
239
337
    {
240
337
        flags |= OGR_G_MEASURED;
241
337
        bHasM = TRUE;
242
337
    }
243
244
    /* -------------------------------------------------------------------- */
245
    /*      Transform raw points into point objects.                        */
246
    /* -------------------------------------------------------------------- */
247
4.76k
    for (int iGeom = 0; iGeom < nPointCount; iGeom++)
248
3.85k
    {
249
3.85k
        OGRPoint *poPoint =
250
3.85k
            new OGRPoint(paoPoints[iGeom].x, paoPoints[iGeom].y);
251
3.85k
        if (bHasM)
252
2.34k
        {
253
2.34k
            if (padfM != nullptr)
254
2.34k
                poPoint->setM(padfM[iGeom]);
255
0
            else
256
0
                poPoint->setM(0.0);
257
2.34k
        }
258
3.85k
        if (bHasZ)
259
3.60k
        {
260
3.60k
            if (padfZ != nullptr)
261
3.60k
                poPoint->setZ(padfZ[iGeom]);
262
0
            else
263
0
                poPoint->setZ(0.0);
264
3.60k
        }
265
266
3.85k
        eErr = addGeometryDirectly(poPoint);
267
3.85k
        if (eErr != OGRERR_NONE)
268
0
        {
269
0
            CPLFree(paoPoints);
270
0
            CPLFree(padfZ);
271
0
            CPLFree(padfM);
272
0
            delete poPoint;
273
0
            return eErr;
274
0
        }
275
3.85k
    }
276
277
908
    CPLFree(paoPoints);
278
908
    CPLFree(padfZ);
279
908
    CPLFree(padfM);
280
281
908
    *ppszInput = pszInput;
282
283
908
    return OGRERR_NONE;
284
908
}
285
286
/************************************************************************/
287
/*                      importFromWkt_Bracketed()                       */
288
/*                                                                      */
289
/*      This operates similar to importFromWkt(), but reads a format    */
290
/*      with brackets around each point.  This is the form defined      */
291
/*      in the BNF of the SFSQL spec.  It is called from                */
292
/*      importFromWkt().                                                */
293
/************************************************************************/
294
295
OGRErr OGRMultiPoint::importFromWkt_Bracketed(const char **ppszInput, int bHasM,
296
                                              int bHasZ)
297
298
29
{
299
    /* -------------------------------------------------------------------- */
300
    /*      Skip MULTIPOINT keyword.                                        */
301
    /* -------------------------------------------------------------------- */
302
29
    char szToken[OGR_WKT_TOKEN_MAX] = {};
303
29
    const char *pszInput = *ppszInput;
304
29
    pszInput = OGRWktReadToken(pszInput, szToken);
305
306
29
    if (bHasZ || bHasM)
307
1
    {
308
        // Skip Z, M or ZM.
309
1
        pszInput = OGRWktReadToken(pszInput, szToken);
310
1
    }
311
312
    /* -------------------------------------------------------------------- */
313
    /*      Read points till we get to the closing bracket.                 */
314
    /* -------------------------------------------------------------------- */
315
316
29
    OGRRawPoint *paoPoints = nullptr;
317
29
    double *padfZ = nullptr;
318
29
    double *padfM = nullptr;
319
320
269
    while ((pszInput = OGRWktReadToken(pszInput, szToken)) != nullptr &&
321
269
           (EQUAL(szToken, "(") || EQUAL(szToken, ",")))
322
262
    {
323
262
        const char *pszNext = OGRWktReadToken(pszInput, szToken);
324
262
        if (EQUAL(szToken, "EMPTY"))
325
0
        {
326
0
            OGRPoint *poGeom = new OGRPoint(0.0, 0.0);
327
0
            poGeom->empty();
328
0
            const OGRErr eErr = addGeometryDirectly(poGeom);
329
0
            if (eErr != OGRERR_NONE)
330
0
            {
331
0
                CPLFree(paoPoints);
332
0
                delete poGeom;
333
0
                return eErr;
334
0
            }
335
336
0
            pszInput = pszNext;
337
338
0
            continue;
339
0
        }
340
341
262
        int flagsFromInput = flags;
342
262
        int nMaxPoint = 0;
343
262
        int nPointCount = 0;
344
262
        pszInput = OGRWktReadPointsM(pszInput, &paoPoints, &padfZ, &padfM,
345
262
                                     &flagsFromInput, &nMaxPoint, &nPointCount);
346
347
262
        if (pszInput == nullptr || nPointCount != 1)
348
22
        {
349
22
            CPLFree(paoPoints);
350
22
            CPLFree(padfZ);
351
22
            CPLFree(padfM);
352
22
            return OGRERR_CORRUPT_DATA;
353
22
        }
354
240
        if ((flagsFromInput & OGR_G_3D) && !(flags & OGR_G_3D))
355
15
        {
356
15
            flags |= OGR_G_3D;
357
15
            bHasZ = TRUE;
358
15
        }
359
240
        if ((flagsFromInput & OGR_G_MEASURED) && !(flags & OGR_G_MEASURED))
360
12
        {
361
12
            flags |= OGR_G_MEASURED;
362
12
            bHasM = TRUE;
363
12
        }
364
365
240
        OGRPoint *poPoint = new OGRPoint(paoPoints[0].x, paoPoints[0].y);
366
240
        if (bHasM)
367
151
        {
368
151
            if (padfM != nullptr)
369
151
                poPoint->setM(padfM[0]);
370
0
            else
371
0
                poPoint->setM(0.0);
372
151
        }
373
240
        if (bHasZ)
374
203
        {
375
203
            if (padfZ != nullptr)
376
203
                poPoint->setZ(padfZ[0]);
377
0
            else
378
0
                poPoint->setZ(0.0);
379
203
        }
380
381
240
        const OGRErr eErr = addGeometryDirectly(poPoint);
382
240
        if (eErr != OGRERR_NONE)
383
0
        {
384
0
            CPLFree(paoPoints);
385
0
            CPLFree(padfZ);
386
0
            CPLFree(padfM);
387
0
            delete poPoint;
388
0
            return eErr;
389
0
        }
390
240
    }
391
392
    /* -------------------------------------------------------------------- */
393
    /*      Cleanup.                                                        */
394
    /* -------------------------------------------------------------------- */
395
7
    CPLFree(paoPoints);
396
7
    CPLFree(padfZ);
397
7
    CPLFree(padfM);
398
399
7
    if (!EQUAL(szToken, ")"))
400
6
        return OGRERR_CORRUPT_DATA;
401
402
1
    *ppszInput = pszInput;
403
404
1
    return OGRERR_NONE;
405
7
}
406
407
/************************************************************************/
408
/*                         hasCurveGeometry()                           */
409
/************************************************************************/
410
411
OGRBoolean OGRMultiPoint::hasCurveGeometry(int /* bLookForNonLinear */) const
412
911
{
413
911
    return FALSE;
414
911
}