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 640 : OGRMultiPoint *OGRMultiPoint::clone() const
60 :
61 : {
62 640 : return new (std::nothrow) OGRMultiPoint(*this);
63 : }
64 :
65 : /************************************************************************/
66 : /* getGeometryType() */
67 : /************************************************************************/
68 :
69 13618 : OGRwkbGeometryType OGRMultiPoint::getGeometryType() const
70 :
71 : {
72 13618 : if ((flags & OGR_G_3D) && (flags & OGR_G_MEASURED))
73 3128 : return wkbMultiPointZM;
74 10490 : else if (flags & OGR_G_MEASURED)
75 345 : return wkbMultiPointM;
76 10145 : else if (flags & OGR_G_3D)
77 4931 : return wkbMultiPoint25D;
78 : else
79 5214 : 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 1750 : const char *OGRMultiPoint::getGeometryName() const
97 :
98 : {
99 1750 : return "MULTIPOINT";
100 : }
101 :
102 : /************************************************************************/
103 : /* isCompatibleSubType() */
104 : /************************************************************************/
105 :
106 : OGRBoolean
107 6784 : OGRMultiPoint::isCompatibleSubType(OGRwkbGeometryType eGeomType) const
108 : {
109 6784 : 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 212 : std::string OGRMultiPoint::exportToWkt(const OGRWktOptions &opts,
120 : OGRErr *err) const
121 : {
122 : try
123 : {
124 424 : std::string wkt = getGeometryName();
125 212 : wkt += wktTypeString(opts.variant);
126 :
127 212 : bool first(true);
128 : // OGRMultiPoint has a begin()/end().
129 604 : for (const OGRPoint *poPoint : this)
130 : {
131 392 : if (poPoint->IsEmpty())
132 13 : continue;
133 :
134 379 : if (first)
135 167 : wkt += '(';
136 : else
137 212 : wkt += ',';
138 379 : first = false;
139 :
140 379 : if (opts.variant == wkbVariantIso)
141 211 : wkt += '(';
142 :
143 758 : wkt += OGRMakeWktCoordinateM(
144 : poPoint->getX(), poPoint->getY(), poPoint->getZ(),
145 : poPoint->getM(), poPoint->Is3D(),
146 758 : poPoint->IsMeasured() && (opts.variant == wkbVariantIso), opts);
147 :
148 379 : if (opts.variant == wkbVariantIso)
149 211 : wkt += ')';
150 : }
151 :
152 212 : if (err)
153 196 : *err = OGRERR_NONE;
154 212 : if (first)
155 45 : wkt += "EMPTY";
156 : else
157 167 : wkt += ')';
158 212 : 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 587 : OGRErr OGRMultiPoint::importFromWkt(const char **ppszInput)
174 :
175 : {
176 587 : const char *pszInputBefore = *ppszInput;
177 587 : int bHasZ = FALSE;
178 587 : int bHasM = FALSE;
179 587 : bool bIsEmpty = false;
180 587 : OGRErr eErr = importPreambleFromWkt(ppszInput, &bHasZ, &bHasM, &bIsEmpty);
181 587 : flags = 0;
182 587 : if (eErr != OGRERR_NONE)
183 5 : return eErr;
184 582 : if (bHasZ)
185 87 : flags |= OGR_G_3D;
186 582 : if (bHasM)
187 62 : flags |= OGR_G_MEASURED;
188 582 : if (bIsEmpty)
189 62 : return OGRERR_NONE;
190 :
191 520 : char szToken[OGR_WKT_TOKEN_MAX] = {};
192 520 : const char *pszInput = *ppszInput;
193 :
194 520 : const char *pszPreScan = OGRWktReadToken(pszInput, szToken);
195 520 : OGRWktReadToken(pszPreScan, szToken);
196 :
197 : // Do we have an inner bracket?
198 520 : if (EQUAL(szToken, "(") || EQUAL(szToken, "EMPTY"))
199 : {
200 178 : *ppszInput = pszInputBefore;
201 178 : return importFromWkt_Bracketed(ppszInput, bHasM, bHasZ);
202 : }
203 :
204 : /* -------------------------------------------------------------------- */
205 : /* Read the point list. */
206 : /* -------------------------------------------------------------------- */
207 342 : OGRRawPoint *paoPoints = nullptr;
208 342 : double *padfZ = nullptr;
209 342 : double *padfM = nullptr;
210 342 : int flagsFromInput = flags;
211 342 : int nMaxPoint = 0;
212 342 : int nPointCount = 0;
213 :
214 342 : pszInput = OGRWktReadPointsM(pszInput, &paoPoints, &padfZ, &padfM,
215 : &flagsFromInput, &nMaxPoint, &nPointCount);
216 342 : if (pszInput == nullptr)
217 : {
218 11 : CPLFree(paoPoints);
219 11 : CPLFree(padfZ);
220 11 : CPLFree(padfM);
221 11 : return OGRERR_CORRUPT_DATA;
222 : }
223 331 : if ((flagsFromInput & OGR_G_3D) && !(flags & OGR_G_3D))
224 : {
225 151 : flags |= OGR_G_3D;
226 151 : bHasZ = TRUE;
227 : }
228 331 : 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 914 : for (int iGeom = 0; iGeom < nPointCount; iGeom++)
238 : {
239 : OGRPoint *poPoint =
240 583 : new OGRPoint(paoPoints[iGeom].x, paoPoints[iGeom].y);
241 583 : if (bHasM)
242 : {
243 5 : if (padfM != nullptr)
244 5 : poPoint->setM(padfM[iGeom]);
245 : else
246 0 : poPoint->setM(0.0);
247 : }
248 583 : if (bHasZ)
249 : {
250 308 : if (padfZ != nullptr)
251 308 : poPoint->setZ(padfZ[iGeom]);
252 : else
253 0 : poPoint->setZ(0.0);
254 : }
255 :
256 583 : eErr = addGeometryDirectly(poPoint);
257 583 : 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 331 : CPLFree(paoPoints);
268 331 : CPLFree(padfZ);
269 331 : CPLFree(padfM);
270 :
271 331 : *ppszInput = pszInput;
272 :
273 331 : 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 178 : OGRErr OGRMultiPoint::importFromWkt_Bracketed(const char **ppszInput, int bHasM,
286 : int bHasZ)
287 :
288 : {
289 : /* -------------------------------------------------------------------- */
290 : /* Skip MULTIPOINT keyword. */
291 : /* -------------------------------------------------------------------- */
292 178 : char szToken[OGR_WKT_TOKEN_MAX] = {};
293 178 : const char *pszInput = *ppszInput;
294 178 : pszInput = OGRWktReadToken(pszInput, szToken);
295 :
296 178 : if (bHasZ || bHasM)
297 : {
298 : // Skip Z, M or ZM.
299 80 : pszInput = OGRWktReadToken(pszInput, szToken);
300 : }
301 :
302 : /* -------------------------------------------------------------------- */
303 : /* Read points till we get to the closing bracket. */
304 : /* -------------------------------------------------------------------- */
305 :
306 178 : OGRRawPoint *paoPoints = nullptr;
307 178 : double *padfZ = nullptr;
308 178 : double *padfM = nullptr;
309 :
310 1074 : while ((pszInput = OGRWktReadToken(pszInput, szToken)) != nullptr &&
311 537 : (EQUAL(szToken, "(") || EQUAL(szToken, ",")))
312 : {
313 362 : const char *pszNext = OGRWktReadToken(pszInput, szToken);
314 362 : 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 345 : int flagsFromInput = flags;
332 345 : int nMaxPoint = 0;
333 345 : int nPointCount = 0;
334 345 : pszInput = OGRWktReadPointsM(pszInput, &paoPoints, &padfZ, &padfM,
335 : &flagsFromInput, &nMaxPoint, &nPointCount);
336 :
337 345 : 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 342 : if ((flagsFromInput & OGR_G_3D) && !(flags & OGR_G_3D))
345 : {
346 4 : flags |= OGR_G_3D;
347 4 : bHasZ = TRUE;
348 : }
349 342 : if ((flagsFromInput & OGR_G_MEASURED) && !(flags & OGR_G_MEASURED))
350 : {
351 0 : flags |= OGR_G_MEASURED;
352 0 : bHasM = TRUE;
353 : }
354 :
355 342 : OGRPoint *poPoint = new OGRPoint(paoPoints[0].x, paoPoints[0].y);
356 342 : if (bHasM)
357 : {
358 88 : if (padfM != nullptr)
359 88 : poPoint->setM(padfM[0]);
360 : else
361 0 : poPoint->setM(0.0);
362 : }
363 342 : if (bHasZ)
364 : {
365 115 : if (padfZ != nullptr)
366 115 : poPoint->setZ(padfZ[0]);
367 : else
368 0 : poPoint->setZ(0.0);
369 : }
370 :
371 342 : const OGRErr eErr = addGeometryDirectly(poPoint);
372 342 : 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 175 : CPLFree(paoPoints);
386 175 : CPLFree(padfZ);
387 175 : CPLFree(padfM);
388 :
389 175 : if (!EQUAL(szToken, ")"))
390 6 : return OGRERR_CORRUPT_DATA;
391 :
392 169 : *ppszInput = pszInput;
393 :
394 169 : return OGRERR_NONE;
395 : }
396 :
397 : /************************************************************************/
398 : /* hasCurveGeometry() */
399 : /************************************************************************/
400 :
401 2766 : OGRBoolean OGRMultiPoint::hasCurveGeometry(int /* bLookForNonLinear */) const
402 : {
403 2766 : return FALSE;
404 : }
|