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