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