Coverage Report

Created: 2025-11-16 06:25

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