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 719 : OGRMultiPoint *OGRMultiPoint::clone() const
60 :
61 : {
62 719 : return new (std::nothrow) OGRMultiPoint(*this);
63 : }
64 :
65 : /************************************************************************/
66 : /* getGeometryType() */
67 : /************************************************************************/
68 :
69 15533 : OGRwkbGeometryType OGRMultiPoint::getGeometryType() const
70 :
71 : {
72 15533 : if ((flags & OGR_G_3D) && (flags & OGR_G_MEASURED))
73 3129 : return wkbMultiPointZM;
74 12404 : else if (flags & OGR_G_MEASURED)
75 350 : return wkbMultiPointM;
76 12054 : else if (flags & OGR_G_3D)
77 5969 : return wkbMultiPoint25D;
78 : else
79 6085 : 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 2066 : const char *OGRMultiPoint::getGeometryName() const
97 :
98 : {
99 2066 : return "MULTIPOINT";
100 : }
101 :
102 : /************************************************************************/
103 : /* isCompatibleSubType() */
104 : /************************************************************************/
105 :
106 : OGRBoolean
107 7385 : OGRMultiPoint::isCompatibleSubType(OGRwkbGeometryType eGeomType) const
108 : {
109 7385 : return wkbFlatten(eGeomType) == wkbPoint;
110 : }
111 :
112 : /************************************************************************/
113 : /* exportToWkt() */
114 : /* */
115 : /* Translate this structure into its well known text format */
116 : /* equivalent. */
117 : /************************************************************************/
118 :
119 220 : std::string OGRMultiPoint::exportToWkt(const OGRWktOptions &opts,
120 : OGRErr *err) const
121 : {
122 : try
123 : {
124 440 : std::string wkt = getGeometryName();
125 220 : wkt += wktTypeString(opts.variant);
126 :
127 220 : bool first(true);
128 : // OGRMultiPoint has a begin()/end().
129 621 : for (const OGRPoint *poPoint : this)
130 : {
131 401 : if (poPoint->IsEmpty())
132 13 : continue;
133 :
134 388 : if (first)
135 175 : wkt += '(';
136 : else
137 213 : wkt += ',';
138 388 : first = false;
139 :
140 388 : if (opts.variant == wkbVariantIso)
141 211 : wkt += '(';
142 :
143 776 : wkt += OGRMakeWktCoordinateM(
144 : poPoint->getX(), poPoint->getY(), poPoint->getZ(),
145 : poPoint->getM(), poPoint->Is3D(),
146 776 : poPoint->IsMeasured() && (opts.variant == wkbVariantIso), opts);
147 :
148 388 : if (opts.variant == wkbVariantIso)
149 211 : wkt += ')';
150 : }
151 :
152 220 : if (err)
153 204 : *err = OGRERR_NONE;
154 220 : if (first)
155 45 : wkt += "EMPTY";
156 : else
157 175 : wkt += ')';
158 220 : return wkt;
159 : }
160 0 : catch (const std::bad_alloc &e)
161 : {
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 : }
167 : }
168 :
169 : /************************************************************************/
170 : /* importFromWkt() */
171 : /************************************************************************/
172 :
173 639 : OGRErr OGRMultiPoint::importFromWkt(const char **ppszInput)
174 :
175 : {
176 639 : const char *pszInputBefore = *ppszInput;
177 639 : int bHasZ = FALSE;
178 639 : int bHasM = FALSE;
179 639 : bool bIsEmpty = false;
180 639 : OGRErr eErr = importPreambleFromWkt(ppszInput, &bHasZ, &bHasM, &bIsEmpty);
181 639 : flags = 0;
182 639 : if (eErr != OGRERR_NONE)
183 5 : return eErr;
184 634 : if (bHasZ)
185 92 : flags |= OGR_G_3D;
186 634 : if (bHasM)
187 64 : flags |= OGR_G_MEASURED;
188 634 : if (bIsEmpty)
189 64 : return OGRERR_NONE;
190 :
191 570 : char szToken[OGR_WKT_TOKEN_MAX] = {};
192 570 : const char *pszInput = *ppszInput;
193 :
194 570 : const char *pszPreScan = OGRWktReadToken(pszInput, szToken);
195 570 : OGRWktReadToken(pszPreScan, szToken);
196 :
197 : // Do we have an inner bracket?
198 570 : if (EQUAL(szToken, "(") || EQUAL(szToken, "EMPTY"))
199 : {
200 199 : *ppszInput = pszInputBefore;
201 199 : return importFromWkt_Bracketed(ppszInput, bHasM, bHasZ);
202 : }
203 :
204 : /* -------------------------------------------------------------------- */
205 : /* Read the point list. */
206 : /* -------------------------------------------------------------------- */
207 371 : OGRRawPoint *paoPoints = nullptr;
208 371 : double *padfZ = nullptr;
209 371 : double *padfM = nullptr;
210 371 : int flagsFromInput = flags;
211 371 : int nMaxPoint = 0;
212 371 : int nPointCount = 0;
213 :
214 371 : pszInput = OGRWktReadPointsM(pszInput, &paoPoints, &padfZ, &padfM,
215 : &flagsFromInput, &nMaxPoint, &nPointCount);
216 371 : if (pszInput == nullptr)
217 : {
218 11 : CPLFree(paoPoints);
219 11 : CPLFree(padfZ);
220 11 : CPLFree(padfM);
221 11 : return OGRERR_CORRUPT_DATA;
222 : }
223 360 : if ((flagsFromInput & OGR_G_3D) && !(flags & OGR_G_3D))
224 : {
225 175 : flags |= OGR_G_3D;
226 175 : bHasZ = TRUE;
227 : }
228 360 : if ((flagsFromInput & OGR_G_MEASURED) && !(flags & OGR_G_MEASURED))
229 : {
230 1 : flags |= OGR_G_MEASURED;
231 1 : bHasM = TRUE;
232 : }
233 :
234 : /* -------------------------------------------------------------------- */
235 : /* Transform raw points into point objects. */
236 : /* -------------------------------------------------------------------- */
237 1035 : for (int iGeom = 0; iGeom < nPointCount; iGeom++)
238 : {
239 : OGRPoint *poPoint =
240 675 : new OGRPoint(paoPoints[iGeom].x, paoPoints[iGeom].y);
241 675 : if (bHasM)
242 : {
243 7 : if (padfM != nullptr)
244 7 : poPoint->setM(padfM[iGeom]);
245 : else
246 0 : poPoint->setM(0.0);
247 : }
248 675 : if (bHasZ)
249 : {
250 392 : if (padfZ != nullptr)
251 392 : poPoint->setZ(padfZ[iGeom]);
252 : else
253 0 : poPoint->setZ(0.0);
254 : }
255 :
256 675 : eErr = addGeometryDirectly(poPoint);
257 675 : if (eErr != OGRERR_NONE)
258 : {
259 0 : CPLFree(paoPoints);
260 0 : CPLFree(padfZ);
261 0 : CPLFree(padfM);
262 0 : delete poPoint;
263 0 : return eErr;
264 : }
265 : }
266 :
267 360 : CPLFree(paoPoints);
268 360 : CPLFree(padfZ);
269 360 : CPLFree(padfM);
270 :
271 360 : *ppszInput = pszInput;
272 :
273 360 : return OGRERR_NONE;
274 : }
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 199 : OGRErr OGRMultiPoint::importFromWkt_Bracketed(const char **ppszInput, int bHasM,
286 : int bHasZ)
287 :
288 : {
289 : /* -------------------------------------------------------------------- */
290 : /* Skip MULTIPOINT keyword. */
291 : /* -------------------------------------------------------------------- */
292 199 : char szToken[OGR_WKT_TOKEN_MAX] = {};
293 199 : const char *pszInput = *ppszInput;
294 199 : pszInput = OGRWktReadToken(pszInput, szToken);
295 :
296 199 : if (bHasZ || bHasM)
297 : {
298 : // Skip Z, M or ZM.
299 84 : pszInput = OGRWktReadToken(pszInput, szToken);
300 : }
301 :
302 : /* -------------------------------------------------------------------- */
303 : /* Read points till we get to the closing bracket. */
304 : /* -------------------------------------------------------------------- */
305 :
306 199 : OGRRawPoint *paoPoints = nullptr;
307 199 : double *padfZ = nullptr;
308 199 : double *padfM = nullptr;
309 :
310 1194 : while ((pszInput = OGRWktReadToken(pszInput, szToken)) != nullptr &&
311 597 : (EQUAL(szToken, "(") || EQUAL(szToken, ",")))
312 : {
313 401 : const char *pszNext = OGRWktReadToken(pszInput, szToken);
314 401 : if (EQUAL(szToken, "EMPTY"))
315 : {
316 17 : OGRPoint *poGeom = new OGRPoint(0.0, 0.0);
317 17 : poGeom->empty();
318 17 : const OGRErr eErr = addGeometryDirectly(poGeom);
319 17 : if (eErr != OGRERR_NONE)
320 : {
321 0 : CPLFree(paoPoints);
322 0 : delete poGeom;
323 3 : return eErr;
324 : }
325 :
326 17 : pszInput = pszNext;
327 :
328 17 : continue;
329 : }
330 :
331 384 : int flagsFromInput = flags;
332 384 : int nMaxPoint = 0;
333 384 : int nPointCount = 0;
334 384 : pszInput = OGRWktReadPointsM(pszInput, &paoPoints, &padfZ, &padfM,
335 : &flagsFromInput, &nMaxPoint, &nPointCount);
336 :
337 384 : if (pszInput == nullptr || nPointCount != 1)
338 : {
339 3 : CPLFree(paoPoints);
340 3 : CPLFree(padfZ);
341 3 : CPLFree(padfM);
342 3 : return OGRERR_CORRUPT_DATA;
343 : }
344 381 : if ((flagsFromInput & OGR_G_3D) && !(flags & OGR_G_3D))
345 : {
346 4 : flags |= OGR_G_3D;
347 4 : bHasZ = TRUE;
348 : }
349 381 : if ((flagsFromInput & OGR_G_MEASURED) && !(flags & OGR_G_MEASURED))
350 : {
351 0 : flags |= OGR_G_MEASURED;
352 0 : bHasM = TRUE;
353 : }
354 :
355 381 : OGRPoint *poPoint = new OGRPoint(paoPoints[0].x, paoPoints[0].y);
356 381 : if (bHasM)
357 : {
358 88 : if (padfM != nullptr)
359 88 : poPoint->setM(padfM[0]);
360 : else
361 0 : poPoint->setM(0.0);
362 : }
363 381 : if (bHasZ)
364 : {
365 123 : if (padfZ != nullptr)
366 123 : poPoint->setZ(padfZ[0]);
367 : else
368 0 : poPoint->setZ(0.0);
369 : }
370 :
371 381 : const OGRErr eErr = addGeometryDirectly(poPoint);
372 381 : if (eErr != OGRERR_NONE)
373 : {
374 0 : CPLFree(paoPoints);
375 0 : CPLFree(padfZ);
376 0 : CPLFree(padfM);
377 0 : delete poPoint;
378 0 : return eErr;
379 : }
380 : }
381 :
382 : /* -------------------------------------------------------------------- */
383 : /* Cleanup. */
384 : /* -------------------------------------------------------------------- */
385 196 : CPLFree(paoPoints);
386 196 : CPLFree(padfZ);
387 196 : CPLFree(padfM);
388 :
389 196 : if (!EQUAL(szToken, ")"))
390 6 : return OGRERR_CORRUPT_DATA;
391 :
392 190 : *ppszInput = pszInput;
393 :
394 190 : return OGRERR_NONE;
395 : }
396 :
397 : /************************************************************************/
398 : /* hasCurveGeometry() */
399 : /************************************************************************/
400 :
401 3146 : OGRBoolean OGRMultiPoint::hasCurveGeometry(int /* bLookForNonLinear */) const
402 : {
403 3146 : return FALSE;
404 : }
|