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 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #include "cpl_port.h"
31 : #include "ogr_geometry.h"
32 :
33 : #include <cstddef>
34 : #include <cstdio>
35 : #include <cstring>
36 : #include <new>
37 :
38 : #include "cpl_conv.h"
39 : #include "cpl_error.h"
40 : #include "cpl_vsi.h"
41 : #include "ogr_core.h"
42 : #include "ogr_p.h"
43 :
44 : /************************************************************************/
45 : /* OGRMultiPoint() */
46 : /************************************************************************/
47 :
48 : /**
49 : * \brief Create an empty multi point collection.
50 : */
51 :
52 : OGRMultiPoint::OGRMultiPoint() = default;
53 :
54 : /************************************************************************/
55 : /* OGRMultiPoint( const OGRMultiPoint& ) */
56 : /************************************************************************/
57 :
58 : /**
59 : * \brief Copy constructor.
60 : *
61 : * Note: before GDAL 2.1, only the default implementation of the constructor
62 : * existed, which could be unsafe to use.
63 : *
64 : * @since GDAL 2.1
65 : */
66 :
67 : OGRMultiPoint::OGRMultiPoint(const OGRMultiPoint &) = default;
68 :
69 : /************************************************************************/
70 : /* ~OGRMultiPoint() */
71 : /************************************************************************/
72 :
73 : OGRMultiPoint::~OGRMultiPoint() = default;
74 :
75 : /************************************************************************/
76 : /* operator=( const OGRMultiPoint&) */
77 : /************************************************************************/
78 :
79 : /**
80 : * \brief Assignment operator.
81 : *
82 : * Note: before GDAL 2.1, only the default implementation of the operator
83 : * existed, which could be unsafe to use.
84 : *
85 : * @since GDAL 2.1
86 : */
87 :
88 5 : OGRMultiPoint &OGRMultiPoint::operator=(const OGRMultiPoint &other)
89 : {
90 5 : if (this != &other)
91 : {
92 4 : OGRGeometryCollection::operator=(other);
93 : }
94 5 : return *this;
95 : }
96 :
97 : /************************************************************************/
98 : /* clone() */
99 : /************************************************************************/
100 :
101 649 : OGRMultiPoint *OGRMultiPoint::clone() const
102 :
103 : {
104 649 : return new (std::nothrow) OGRMultiPoint(*this);
105 : }
106 :
107 : /************************************************************************/
108 : /* getGeometryType() */
109 : /************************************************************************/
110 :
111 12491 : OGRwkbGeometryType OGRMultiPoint::getGeometryType() const
112 :
113 : {
114 12491 : if ((flags & OGR_G_3D) && (flags & OGR_G_MEASURED))
115 3084 : return wkbMultiPointZM;
116 9407 : else if (flags & OGR_G_MEASURED)
117 321 : return wkbMultiPointM;
118 9086 : else if (flags & OGR_G_3D)
119 4374 : return wkbMultiPoint25D;
120 : else
121 4712 : return wkbMultiPoint;
122 : }
123 :
124 : /************************************************************************/
125 : /* getDimension() */
126 : /************************************************************************/
127 :
128 1 : int OGRMultiPoint::getDimension() const
129 :
130 : {
131 1 : return 0;
132 : }
133 :
134 : /************************************************************************/
135 : /* getGeometryName() */
136 : /************************************************************************/
137 :
138 1434 : const char *OGRMultiPoint::getGeometryName() const
139 :
140 : {
141 1434 : return "MULTIPOINT";
142 : }
143 :
144 : /************************************************************************/
145 : /* isCompatibleSubType() */
146 : /************************************************************************/
147 :
148 : OGRBoolean
149 6395 : OGRMultiPoint::isCompatibleSubType(OGRwkbGeometryType eGeomType) const
150 : {
151 6395 : return wkbFlatten(eGeomType) == wkbPoint;
152 : }
153 :
154 : /************************************************************************/
155 : /* exportToWkt() */
156 : /* */
157 : /* Translate this structure into its well known text format */
158 : /* equivalent. */
159 : /************************************************************************/
160 :
161 184 : std::string OGRMultiPoint::exportToWkt(const OGRWktOptions &opts,
162 : OGRErr *err) const
163 : {
164 : try
165 : {
166 368 : std::string wkt = getGeometryName();
167 184 : wkt += wktTypeString(opts.variant);
168 :
169 184 : bool first(true);
170 : // OGRMultiPoint has a begin()/end().
171 543 : for (const OGRPoint *poPoint : this)
172 : {
173 359 : if (poPoint->IsEmpty())
174 8 : continue;
175 :
176 351 : if (first)
177 149 : wkt += '(';
178 : else
179 202 : wkt += ',';
180 351 : first = false;
181 :
182 351 : if (opts.variant == wkbVariantIso)
183 172 : wkt += '(';
184 :
185 702 : wkt += OGRMakeWktCoordinateM(
186 : poPoint->getX(), poPoint->getY(), poPoint->getZ(),
187 : poPoint->getM(), poPoint->Is3D(),
188 702 : poPoint->IsMeasured() && (opts.variant == wkbVariantIso), opts);
189 :
190 351 : if (opts.variant == wkbVariantIso)
191 172 : wkt += ')';
192 : }
193 :
194 184 : if (err)
195 168 : *err = OGRERR_NONE;
196 184 : if (first)
197 35 : wkt += "EMPTY";
198 : else
199 149 : wkt += ')';
200 184 : return wkt;
201 : }
202 0 : catch (const std::bad_alloc &e)
203 : {
204 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "%s", e.what());
205 0 : if (err)
206 0 : *err = OGRERR_FAILURE;
207 0 : return std::string();
208 : }
209 : }
210 :
211 : /************************************************************************/
212 : /* importFromWkt() */
213 : /************************************************************************/
214 :
215 579 : OGRErr OGRMultiPoint::importFromWkt(const char **ppszInput)
216 :
217 : {
218 579 : const char *pszInputBefore = *ppszInput;
219 579 : int bHasZ = FALSE;
220 579 : int bHasM = FALSE;
221 579 : bool bIsEmpty = false;
222 579 : OGRErr eErr = importPreambleFromWkt(ppszInput, &bHasZ, &bHasM, &bIsEmpty);
223 579 : flags = 0;
224 579 : if (eErr != OGRERR_NONE)
225 5 : return eErr;
226 574 : if (bHasZ)
227 72 : flags |= OGR_G_3D;
228 574 : if (bHasM)
229 56 : flags |= OGR_G_MEASURED;
230 574 : if (bIsEmpty)
231 49 : return OGRERR_NONE;
232 :
233 525 : char szToken[OGR_WKT_TOKEN_MAX] = {};
234 525 : const char *pszInput = *ppszInput;
235 :
236 525 : const char *pszPreScan = OGRWktReadToken(pszInput, szToken);
237 525 : OGRWktReadToken(pszPreScan, szToken);
238 :
239 : // Do we have an inner bracket?
240 525 : if (EQUAL(szToken, "(") || EQUAL(szToken, "EMPTY"))
241 : {
242 150 : *ppszInput = pszInputBefore;
243 150 : return importFromWkt_Bracketed(ppszInput, bHasM, bHasZ);
244 : }
245 :
246 : /* -------------------------------------------------------------------- */
247 : /* Read the point list. */
248 : /* -------------------------------------------------------------------- */
249 375 : OGRRawPoint *paoPoints = nullptr;
250 375 : double *padfZ = nullptr;
251 375 : double *padfM = nullptr;
252 375 : int flagsFromInput = flags;
253 375 : int nMaxPoint = 0;
254 375 : int nPointCount = 0;
255 :
256 375 : pszInput = OGRWktReadPointsM(pszInput, &paoPoints, &padfZ, &padfM,
257 : &flagsFromInput, &nMaxPoint, &nPointCount);
258 375 : if (pszInput == nullptr)
259 : {
260 11 : CPLFree(paoPoints);
261 11 : CPLFree(padfZ);
262 11 : CPLFree(padfM);
263 11 : return OGRERR_CORRUPT_DATA;
264 : }
265 364 : if ((flagsFromInput & OGR_G_3D) && !(flags & OGR_G_3D))
266 : {
267 174 : flags |= OGR_G_3D;
268 174 : bHasZ = TRUE;
269 : }
270 364 : if ((flagsFromInput & OGR_G_MEASURED) && !(flags & OGR_G_MEASURED))
271 : {
272 1 : flags |= OGR_G_MEASURED;
273 1 : bHasM = TRUE;
274 : }
275 :
276 : /* -------------------------------------------------------------------- */
277 : /* Transform raw points into point objects. */
278 : /* -------------------------------------------------------------------- */
279 1005 : for (int iGeom = 0; iGeom < nPointCount; iGeom++)
280 : {
281 : OGRPoint *poPoint =
282 641 : new OGRPoint(paoPoints[iGeom].x, paoPoints[iGeom].y);
283 641 : if (bHasM)
284 : {
285 5 : if (padfM != nullptr)
286 5 : poPoint->setM(padfM[iGeom]);
287 : else
288 0 : poPoint->setM(0.0);
289 : }
290 641 : if (bHasZ)
291 : {
292 351 : if (padfZ != nullptr)
293 351 : poPoint->setZ(padfZ[iGeom]);
294 : else
295 0 : poPoint->setZ(0.0);
296 : }
297 :
298 641 : eErr = addGeometryDirectly(poPoint);
299 641 : if (eErr != OGRERR_NONE)
300 : {
301 0 : CPLFree(paoPoints);
302 0 : CPLFree(padfZ);
303 0 : CPLFree(padfM);
304 0 : delete poPoint;
305 0 : return eErr;
306 : }
307 : }
308 :
309 364 : CPLFree(paoPoints);
310 364 : CPLFree(padfZ);
311 364 : CPLFree(padfM);
312 :
313 364 : *ppszInput = pszInput;
314 :
315 364 : return OGRERR_NONE;
316 : }
317 :
318 : /************************************************************************/
319 : /* importFromWkt_Bracketed() */
320 : /* */
321 : /* This operates similar to importFromWkt(), but reads a format */
322 : /* with brackets around each point. This is the form defined */
323 : /* in the BNF of the SFSQL spec. It is called from */
324 : /* importFromWkt(). */
325 : /************************************************************************/
326 :
327 150 : OGRErr OGRMultiPoint::importFromWkt_Bracketed(const char **ppszInput, int bHasM,
328 : int bHasZ)
329 :
330 : {
331 : /* -------------------------------------------------------------------- */
332 : /* Skip MULTIPOINT keyword. */
333 : /* -------------------------------------------------------------------- */
334 150 : char szToken[OGR_WKT_TOKEN_MAX] = {};
335 150 : const char *pszInput = *ppszInput;
336 150 : pszInput = OGRWktReadToken(pszInput, szToken);
337 :
338 150 : if (bHasZ || bHasM)
339 : {
340 : // Skip Z, M or ZM.
341 69 : pszInput = OGRWktReadToken(pszInput, szToken);
342 : }
343 :
344 : /* -------------------------------------------------------------------- */
345 : /* Read points till we get to the closing bracket. */
346 : /* -------------------------------------------------------------------- */
347 :
348 150 : OGRRawPoint *paoPoints = nullptr;
349 150 : double *padfZ = nullptr;
350 150 : double *padfM = nullptr;
351 :
352 916 : while ((pszInput = OGRWktReadToken(pszInput, szToken)) != nullptr &&
353 458 : (EQUAL(szToken, "(") || EQUAL(szToken, ",")))
354 : {
355 311 : const char *pszNext = OGRWktReadToken(pszInput, szToken);
356 311 : if (EQUAL(szToken, "EMPTY"))
357 : {
358 12 : OGRPoint *poGeom = new OGRPoint(0.0, 0.0);
359 12 : poGeom->empty();
360 12 : const OGRErr eErr = addGeometryDirectly(poGeom);
361 12 : if (eErr != OGRERR_NONE)
362 : {
363 0 : CPLFree(paoPoints);
364 0 : delete poGeom;
365 3 : return eErr;
366 : }
367 :
368 12 : pszInput = pszNext;
369 :
370 12 : continue;
371 : }
372 :
373 299 : int flagsFromInput = flags;
374 299 : int nMaxPoint = 0;
375 299 : int nPointCount = 0;
376 299 : pszInput = OGRWktReadPointsM(pszInput, &paoPoints, &padfZ, &padfM,
377 : &flagsFromInput, &nMaxPoint, &nPointCount);
378 :
379 299 : if (pszInput == nullptr || nPointCount != 1)
380 : {
381 3 : CPLFree(paoPoints);
382 3 : CPLFree(padfZ);
383 3 : CPLFree(padfM);
384 3 : return OGRERR_CORRUPT_DATA;
385 : }
386 296 : if ((flagsFromInput & OGR_G_3D) && !(flags & OGR_G_3D))
387 : {
388 4 : flags |= OGR_G_3D;
389 4 : bHasZ = TRUE;
390 : }
391 296 : if ((flagsFromInput & OGR_G_MEASURED) && !(flags & OGR_G_MEASURED))
392 : {
393 0 : flags |= OGR_G_MEASURED;
394 0 : bHasM = TRUE;
395 : }
396 :
397 296 : OGRPoint *poPoint = new OGRPoint(paoPoints[0].x, paoPoints[0].y);
398 296 : if (bHasM)
399 : {
400 84 : if (padfM != nullptr)
401 84 : poPoint->setM(padfM[0]);
402 : else
403 0 : poPoint->setM(0.0);
404 : }
405 296 : if (bHasZ)
406 : {
407 99 : if (padfZ != nullptr)
408 99 : poPoint->setZ(padfZ[0]);
409 : else
410 0 : poPoint->setZ(0.0);
411 : }
412 :
413 296 : const OGRErr eErr = addGeometryDirectly(poPoint);
414 296 : if (eErr != OGRERR_NONE)
415 : {
416 0 : CPLFree(paoPoints);
417 0 : CPLFree(padfZ);
418 0 : CPLFree(padfM);
419 0 : delete poPoint;
420 0 : return eErr;
421 : }
422 : }
423 :
424 : /* -------------------------------------------------------------------- */
425 : /* Cleanup. */
426 : /* -------------------------------------------------------------------- */
427 147 : CPLFree(paoPoints);
428 147 : CPLFree(padfZ);
429 147 : CPLFree(padfM);
430 :
431 147 : if (!EQUAL(szToken, ")"))
432 6 : return OGRERR_CORRUPT_DATA;
433 :
434 141 : *ppszInput = pszInput;
435 :
436 141 : return OGRERR_NONE;
437 : }
438 :
439 : /************************************************************************/
440 : /* hasCurveGeometry() */
441 : /************************************************************************/
442 :
443 2314 : OGRBoolean OGRMultiPoint::hasCurveGeometry(int /* bLookForNonLinear */) const
444 : {
445 2314 : return FALSE;
446 : }
|