/src/gdal/ogr/ogrcompoundcurve.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /****************************************************************************** |
2 | | * |
3 | | * Project: OpenGIS Simple Features Reference Implementation |
4 | | * Purpose: The OGRCompoundCurve geometry class. |
5 | | * Author: Even Rouault, even dot rouault at spatialys dot com |
6 | | * |
7 | | ****************************************************************************** |
8 | | * Copyright (c) 2014, Even Rouault <even dot rouault at spatialys dot com> |
9 | | * |
10 | | * SPDX-License-Identifier: MIT |
11 | | ****************************************************************************/ |
12 | | |
13 | | #include "cpl_port.h" |
14 | | #include "ogr_geometry.h" |
15 | | |
16 | | #include <cmath> |
17 | | #include <cstddef> |
18 | | |
19 | | #include "cpl_error.h" |
20 | | #include "ogr_core.h" |
21 | | #include "ogr_geometry.h" |
22 | | #include "ogr_p.h" |
23 | | #include "ogr_spatialref.h" |
24 | | |
25 | | /************************************************************************/ |
26 | | /* OGRCompoundCurve( const OGRCompoundCurve& ) */ |
27 | | /************************************************************************/ |
28 | | |
29 | | /** |
30 | | * \brief Copy constructor. |
31 | | * |
32 | | * Note: before GDAL 2.1, only the default implementation of the constructor |
33 | | * existed, which could be unsafe to use. |
34 | | * |
35 | | * @since GDAL 2.1 |
36 | | */ |
37 | | |
38 | 0 | OGRCompoundCurve::OGRCompoundCurve(const OGRCompoundCurve &) = default; |
39 | | |
40 | | /************************************************************************/ |
41 | | /* operator=( const OGRCompoundCurve&) */ |
42 | | /************************************************************************/ |
43 | | |
44 | | /** |
45 | | * \brief Assignment operator. |
46 | | * |
47 | | * Note: before GDAL 2.1, only the default implementation of the operator |
48 | | * existed, which could be unsafe to use. |
49 | | * |
50 | | * @since GDAL 2.1 |
51 | | */ |
52 | | |
53 | | OGRCompoundCurve &OGRCompoundCurve::operator=(const OGRCompoundCurve &other) |
54 | 0 | { |
55 | 0 | if (this != &other) |
56 | 0 | { |
57 | 0 | OGRCurve::operator=(other); |
58 | |
|
59 | 0 | oCC = other.oCC; |
60 | 0 | } |
61 | 0 | return *this; |
62 | 0 | } |
63 | | |
64 | | /************************************************************************/ |
65 | | /* clone() */ |
66 | | /************************************************************************/ |
67 | | |
68 | | OGRCompoundCurve *OGRCompoundCurve::clone() const |
69 | | |
70 | 0 | { |
71 | 0 | auto ret = new (std::nothrow) OGRCompoundCurve(*this); |
72 | 0 | if (ret) |
73 | 0 | { |
74 | 0 | if (ret->WkbSize() != WkbSize()) |
75 | 0 | { |
76 | 0 | delete ret; |
77 | 0 | ret = nullptr; |
78 | 0 | } |
79 | 0 | } |
80 | 0 | return ret; |
81 | 0 | } |
82 | | |
83 | | /************************************************************************/ |
84 | | /* getGeometryType() */ |
85 | | /************************************************************************/ |
86 | | |
87 | | OGRwkbGeometryType OGRCompoundCurve::getGeometryType() const |
88 | | |
89 | 5 | { |
90 | 5 | if ((flags & OGR_G_3D) && (flags & OGR_G_MEASURED)) |
91 | 2 | return wkbCompoundCurveZM; |
92 | 3 | else if (flags & OGR_G_MEASURED) |
93 | 0 | return wkbCompoundCurveM; |
94 | 3 | else if (flags & OGR_G_3D) |
95 | 3 | return wkbCompoundCurveZ; |
96 | 0 | else |
97 | 0 | return wkbCompoundCurve; |
98 | 5 | } |
99 | | |
100 | | /************************************************************************/ |
101 | | /* getGeometryName() */ |
102 | | /************************************************************************/ |
103 | | |
104 | | const char *OGRCompoundCurve::getGeometryName() const |
105 | | |
106 | 54 | { |
107 | 54 | return "COMPOUNDCURVE"; |
108 | 54 | } |
109 | | |
110 | | /************************************************************************/ |
111 | | /* WkbSize() */ |
112 | | /************************************************************************/ |
113 | | size_t OGRCompoundCurve::WkbSize() const |
114 | 0 | { |
115 | 0 | return oCC.WkbSize(); |
116 | 0 | } |
117 | | |
118 | | /************************************************************************/ |
119 | | /* addCurveDirectlyFromWkt() */ |
120 | | /************************************************************************/ |
121 | | |
122 | | OGRErr OGRCompoundCurve::addCurveDirectlyFromWkb(OGRGeometry *poSelf, |
123 | | OGRCurve *poCurve) |
124 | 0 | { |
125 | 0 | OGRCompoundCurve *poCC = poSelf->toCompoundCurve(); |
126 | 0 | return poCC->addCurveDirectlyInternal(poCurve, DEFAULT_TOLERANCE_EPSILON, |
127 | 0 | FALSE); |
128 | 0 | } |
129 | | |
130 | | /************************************************************************/ |
131 | | /* importFromWkb() */ |
132 | | /************************************************************************/ |
133 | | |
134 | | OGRErr OGRCompoundCurve::importFromWkb(const unsigned char *pabyData, |
135 | | size_t nSize, OGRwkbVariant eWkbVariant, |
136 | | size_t &nBytesConsumedOut) |
137 | 0 | { |
138 | 0 | OGRwkbByteOrder eByteOrder = wkbNDR; |
139 | 0 | size_t nDataOffset = 0; |
140 | | // coverity[tainted_data] |
141 | 0 | OGRErr eErr = oCC.importPreambleFromWkb(this, pabyData, nSize, nDataOffset, |
142 | 0 | eByteOrder, 9, eWkbVariant); |
143 | 0 | if (eErr != OGRERR_NONE) |
144 | 0 | return eErr; |
145 | | |
146 | 0 | eErr = oCC.importBodyFromWkb(this, pabyData + nDataOffset, nSize, |
147 | 0 | false, // bAcceptCompoundCurve |
148 | 0 | addCurveDirectlyFromWkb, eWkbVariant, |
149 | 0 | nBytesConsumedOut); |
150 | 0 | if (eErr == OGRERR_NONE) |
151 | 0 | nBytesConsumedOut += nDataOffset; |
152 | 0 | return eErr; |
153 | 0 | } |
154 | | |
155 | | /************************************************************************/ |
156 | | /* exportToWkb() */ |
157 | | /************************************************************************/ |
158 | | |
159 | | OGRErr OGRCompoundCurve::exportToWkb(unsigned char *pabyData, |
160 | | const OGRwkbExportOptions *psOptions) const |
161 | 0 | { |
162 | 0 | OGRwkbExportOptions sOptions(psOptions ? *psOptions |
163 | 0 | : OGRwkbExportOptions()); |
164 | | |
165 | | // Does not make sense for new geometries, so patch it. |
166 | 0 | if (sOptions.eWkbVariant == wkbVariantOldOgc) |
167 | 0 | sOptions.eWkbVariant = wkbVariantIso; |
168 | 0 | return oCC.exportToWkb(this, pabyData, &sOptions); |
169 | 0 | } |
170 | | |
171 | | /************************************************************************/ |
172 | | /* addCurveDirectlyFromWkt() */ |
173 | | /************************************************************************/ |
174 | | |
175 | | OGRErr OGRCompoundCurve::addCurveDirectlyFromWkt(OGRGeometry *poSelf, |
176 | | OGRCurve *poCurve) |
177 | 542 | { |
178 | 542 | return poSelf->toCompoundCurve()->addCurveDirectly(poCurve); |
179 | 542 | } |
180 | | |
181 | | /************************************************************************/ |
182 | | /* importFromWkt() */ |
183 | | /************************************************************************/ |
184 | | |
185 | | OGRErr OGRCompoundCurve::importFromWkt(const char **ppszInput) |
186 | 54 | { |
187 | 54 | return importCurveCollectionFromWkt(ppszInput, |
188 | 54 | FALSE, // bAllowEmptyComponent |
189 | 54 | TRUE, // bAllowLineString |
190 | 54 | TRUE, // bAllowCurve |
191 | 54 | FALSE, // bAllowCompoundCurve |
192 | 54 | addCurveDirectlyFromWkt); |
193 | 54 | } |
194 | | |
195 | | /************************************************************************/ |
196 | | /* exportToWkt() */ |
197 | | /************************************************************************/ |
198 | | std::string OGRCompoundCurve::exportToWkt(const OGRWktOptions &opts, |
199 | | OGRErr *err) const |
200 | 0 | { |
201 | 0 | return oCC.exportToWkt(this, opts, err); |
202 | 0 | } |
203 | | |
204 | | /************************************************************************/ |
205 | | /* empty() */ |
206 | | /************************************************************************/ |
207 | | |
208 | | void OGRCompoundCurve::empty() |
209 | 54 | { |
210 | 54 | oCC.empty(this); |
211 | 54 | } |
212 | | |
213 | | /************************************************************************/ |
214 | | /* getEnvelope() */ |
215 | | /************************************************************************/ |
216 | | |
217 | | void OGRCompoundCurve::getEnvelope(OGREnvelope *psEnvelope) const |
218 | 0 | { |
219 | 0 | oCC.getEnvelope(psEnvelope); |
220 | 0 | } |
221 | | |
222 | | /************************************************************************/ |
223 | | /* getEnvelope() */ |
224 | | /************************************************************************/ |
225 | | |
226 | | void OGRCompoundCurve::getEnvelope(OGREnvelope3D *psEnvelope) const |
227 | 0 | { |
228 | 0 | oCC.getEnvelope(psEnvelope); |
229 | 0 | } |
230 | | |
231 | | /************************************************************************/ |
232 | | /* IsEmpty() */ |
233 | | /************************************************************************/ |
234 | | |
235 | | OGRBoolean OGRCompoundCurve::IsEmpty() const |
236 | 0 | { |
237 | 0 | return oCC.IsEmpty(); |
238 | 0 | } |
239 | | |
240 | | /************************************************************************/ |
241 | | /* get_Length() */ |
242 | | /* */ |
243 | | /* For now we return a simple euclidean 2D distance. */ |
244 | | /************************************************************************/ |
245 | | |
246 | | double OGRCompoundCurve::get_Length() const |
247 | 0 | { |
248 | 0 | double dfLength = 0.0; |
249 | 0 | for (int iGeom = 0; iGeom < oCC.nCurveCount; iGeom++) |
250 | 0 | dfLength += oCC.papoCurves[iGeom]->get_Length(); |
251 | 0 | return dfLength; |
252 | 0 | } |
253 | | |
254 | | /************************************************************************/ |
255 | | /* StartPoint() */ |
256 | | /************************************************************************/ |
257 | | |
258 | | void OGRCompoundCurve::StartPoint(OGRPoint *p) const |
259 | 0 | { |
260 | 0 | CPLAssert(oCC.nCurveCount > 0); |
261 | 0 | oCC.papoCurves[0]->StartPoint(p); |
262 | 0 | } |
263 | | |
264 | | /************************************************************************/ |
265 | | /* EndPoint() */ |
266 | | /************************************************************************/ |
267 | | |
268 | | void OGRCompoundCurve::EndPoint(OGRPoint *p) const |
269 | 0 | { |
270 | 0 | CPLAssert(oCC.nCurveCount > 0); |
271 | 0 | oCC.papoCurves[oCC.nCurveCount - 1]->EndPoint(p); |
272 | 0 | } |
273 | | |
274 | | /************************************************************************/ |
275 | | /* Value() */ |
276 | | /************************************************************************/ |
277 | | |
278 | | void OGRCompoundCurve::Value(double dfDistance, OGRPoint *poPoint) const |
279 | 0 | { |
280 | |
|
281 | 0 | if (dfDistance < 0) |
282 | 0 | { |
283 | 0 | StartPoint(poPoint); |
284 | 0 | return; |
285 | 0 | } |
286 | | |
287 | 0 | double dfLength = 0.0; |
288 | 0 | for (int iGeom = 0; iGeom < oCC.nCurveCount; iGeom++) |
289 | 0 | { |
290 | 0 | const double dfSegLength = oCC.papoCurves[iGeom]->get_Length(); |
291 | 0 | if (dfSegLength > 0) |
292 | 0 | { |
293 | 0 | if ((dfLength <= dfDistance) && |
294 | 0 | ((dfLength + dfSegLength) >= dfDistance)) |
295 | 0 | { |
296 | 0 | oCC.papoCurves[iGeom]->Value(dfDistance - dfLength, poPoint); |
297 | |
|
298 | 0 | return; |
299 | 0 | } |
300 | | |
301 | 0 | dfLength += dfSegLength; |
302 | 0 | } |
303 | 0 | } |
304 | | |
305 | 0 | EndPoint(poPoint); |
306 | 0 | } |
307 | | |
308 | | /************************************************************************/ |
309 | | /* CurveToLineInternal() */ |
310 | | /************************************************************************/ |
311 | | |
312 | | OGRLineString * |
313 | | OGRCompoundCurve::CurveToLineInternal(double dfMaxAngleStepSizeDegrees, |
314 | | const char *const *papszOptions, |
315 | | int bIsLinearRing) const |
316 | 0 | { |
317 | 0 | OGRLineString *const poLine = |
318 | 0 | bIsLinearRing ? new OGRLinearRing() : new OGRLineString(); |
319 | 0 | poLine->assignSpatialReference(getSpatialReference()); |
320 | 0 | for (int iGeom = 0; iGeom < oCC.nCurveCount; iGeom++) |
321 | 0 | { |
322 | 0 | OGRLineString *poSubLS = oCC.papoCurves[iGeom]->CurveToLine( |
323 | 0 | dfMaxAngleStepSizeDegrees, papszOptions); |
324 | 0 | poLine->addSubLineString(poSubLS, (iGeom == 0) ? 0 : 1); |
325 | 0 | delete poSubLS; |
326 | 0 | } |
327 | 0 | return poLine; |
328 | 0 | } |
329 | | |
330 | | /************************************************************************/ |
331 | | /* CurveToLine() */ |
332 | | /************************************************************************/ |
333 | | |
334 | | OGRLineString * |
335 | | OGRCompoundCurve::CurveToLine(double dfMaxAngleStepSizeDegrees, |
336 | | const char *const *papszOptions) const |
337 | 0 | { |
338 | 0 | return CurveToLineInternal(dfMaxAngleStepSizeDegrees, papszOptions, FALSE); |
339 | 0 | } |
340 | | |
341 | | /************************************************************************/ |
342 | | /* Equals() */ |
343 | | /************************************************************************/ |
344 | | |
345 | | OGRBoolean OGRCompoundCurve::Equals(const OGRGeometry *poOther) const |
346 | 0 | { |
347 | 0 | if (poOther == this) |
348 | 0 | return TRUE; |
349 | | |
350 | 0 | if (poOther->getGeometryType() != getGeometryType()) |
351 | 0 | return FALSE; |
352 | | |
353 | 0 | return oCC.Equals(&(poOther->toCompoundCurve()->oCC)); |
354 | 0 | } |
355 | | |
356 | | /************************************************************************/ |
357 | | /* setCoordinateDimension() */ |
358 | | /************************************************************************/ |
359 | | |
360 | | bool OGRCompoundCurve::setCoordinateDimension(int nNewDimension) |
361 | 54 | { |
362 | 54 | return oCC.setCoordinateDimension(this, nNewDimension); |
363 | 54 | } |
364 | | |
365 | | bool OGRCompoundCurve::set3D(OGRBoolean bIs3D) |
366 | 51 | { |
367 | 51 | return oCC.set3D(this, bIs3D); |
368 | 51 | } |
369 | | |
370 | | bool OGRCompoundCurve::setMeasured(OGRBoolean bIsMeasured) |
371 | 83 | { |
372 | 83 | return oCC.setMeasured(this, bIsMeasured); |
373 | 83 | } |
374 | | |
375 | | /************************************************************************/ |
376 | | /* assignSpatialReference() */ |
377 | | /************************************************************************/ |
378 | | |
379 | | void OGRCompoundCurve::assignSpatialReference(const OGRSpatialReference *poSR) |
380 | 5 | { |
381 | 5 | oCC.assignSpatialReference(this, poSR); |
382 | 5 | } |
383 | | |
384 | | /************************************************************************/ |
385 | | /* getNumCurves() */ |
386 | | /************************************************************************/ |
387 | | |
388 | | /** |
389 | | * \brief Return the number of curves. |
390 | | * |
391 | | * Note that the number of curves making this compound curve. |
392 | | * |
393 | | * Relates to the ISO SQL/MM ST_NumCurves() function. |
394 | | * |
395 | | * @return number of curves. |
396 | | */ |
397 | | |
398 | | int OGRCompoundCurve::getNumCurves() const |
399 | 0 | { |
400 | 0 | return oCC.nCurveCount; |
401 | 0 | } |
402 | | |
403 | | /************************************************************************/ |
404 | | /* getCurve() */ |
405 | | /************************************************************************/ |
406 | | |
407 | | /** |
408 | | * \brief Fetch reference to indicated internal ring. |
409 | | * |
410 | | * Note that the returned curve pointer is to an internal data object of the |
411 | | * OGRCompoundCurve. It should not be modified or deleted by the application, |
412 | | * and the pointer is only valid till the polygon is next modified. Use the |
413 | | * OGRGeometry::clone() method to make a separate copy within the application. |
414 | | * |
415 | | * Relates to the ISO SQL/MM ST_CurveN() function. |
416 | | * |
417 | | * @param iRing curve index from 0 to getNumCurves() - 1. |
418 | | * |
419 | | * @return pointer to curve. May be NULL. |
420 | | */ |
421 | | |
422 | | OGRCurve *OGRCompoundCurve::getCurve(int iRing) |
423 | 0 | { |
424 | 0 | return oCC.getCurve(iRing); |
425 | 0 | } |
426 | | |
427 | | /************************************************************************/ |
428 | | /* getCurve() */ |
429 | | /************************************************************************/ |
430 | | |
431 | | /** |
432 | | * \brief Fetch reference to indicated internal ring. |
433 | | * |
434 | | * Note that the returned curve pointer is to an internal data object of the |
435 | | * OGRCompoundCurve. It should not be modified or deleted by the application, |
436 | | * and the pointer is only valid till the polygon is next modified. Use the |
437 | | * OGRGeometry::clone() method to make a separate copy within the application. |
438 | | * |
439 | | * Relates to the ISO SQL/MM ST_CurveN() function. |
440 | | * |
441 | | * @param iCurve curve index from 0 to getNumCurves() - 1. |
442 | | * |
443 | | * @return pointer to curve. May be NULL. |
444 | | */ |
445 | | |
446 | | const OGRCurve *OGRCompoundCurve::getCurve(int iCurve) const |
447 | 0 | { |
448 | 0 | return oCC.getCurve(iCurve); |
449 | 0 | } |
450 | | |
451 | | /************************************************************************/ |
452 | | /* stealCurve() */ |
453 | | /************************************************************************/ |
454 | | |
455 | | /** |
456 | | * \brief "Steal" reference to curve. |
457 | | * |
458 | | * @param iCurve curve index from 0 to getNumCurves() - 1. |
459 | | * |
460 | | * @return pointer to curve. May be NULL. |
461 | | */ |
462 | | |
463 | | OGRCurve *OGRCompoundCurve::stealCurve(int iCurve) |
464 | 0 | { |
465 | 0 | return oCC.stealCurve(iCurve); |
466 | 0 | } |
467 | | |
468 | | /************************************************************************/ |
469 | | /* addCurve() */ |
470 | | /************************************************************************/ |
471 | | |
472 | | /** |
473 | | * \brief Add a curve to the container. |
474 | | * |
475 | | * The passed geometry is cloned to make an internal copy. |
476 | | * |
477 | | * There is no ISO SQL/MM analog to this method. |
478 | | * |
479 | | * This method is the same as the C function OGR_G_AddGeometry(). |
480 | | * |
481 | | * @param poCurve geometry to add to the container. |
482 | | * @param dfToleranceEps relative tolerance when checking that the first point |
483 | | * of a segment matches then end point of the previous one. Default value: |
484 | | * OGRCompoundCurve::DEFAULT_TOLERANCE_EPSILON. |
485 | | * |
486 | | * @return OGRERR_NONE if successful, or OGRERR_FAILURE in case of error |
487 | | * (for example if curves are not contiguous) |
488 | | */ |
489 | | |
490 | | OGRErr OGRCompoundCurve::addCurve(const OGRCurve *poCurve, |
491 | | double dfToleranceEps) |
492 | 0 | { |
493 | 0 | OGRCurve *poClonedCurve = poCurve->clone(); |
494 | 0 | const OGRErr eErr = addCurveDirectly(poClonedCurve, dfToleranceEps); |
495 | 0 | if (eErr != OGRERR_NONE) |
496 | 0 | delete poClonedCurve; |
497 | 0 | return eErr; |
498 | 0 | } |
499 | | |
500 | | /************************************************************************/ |
501 | | /* addCurveDirectly() */ |
502 | | /************************************************************************/ |
503 | | |
504 | | /** |
505 | | * \brief Add a curve directly to the container. |
506 | | * |
507 | | * Ownership of the passed geometry is taken by the container rather than |
508 | | * cloning as addCurve() does, but only if the method is successful. |
509 | | * If the method fails, ownership still belongs to the caller. |
510 | | * |
511 | | * There is no ISO SQL/MM analog to this method. |
512 | | * |
513 | | * This method is the same as the C function OGR_G_AddGeometryDirectly(). |
514 | | * |
515 | | * @param poCurve geometry to add to the container. |
516 | | * @param dfToleranceEps relative tolerance when checking that the first point |
517 | | * of a segment matches then end point of the previous one. Default value: |
518 | | * OGRCompoundCurve::DEFAULT_TOLERANCE_EPSILON. |
519 | | * |
520 | | * @return OGRERR_NONE if successful, or OGRERR_FAILURE in case of error |
521 | | * (for example if curves are not contiguous) |
522 | | */ |
523 | | OGRErr OGRCompoundCurve::addCurveDirectly(OGRCurve *poCurve, |
524 | | double dfToleranceEps) |
525 | 542 | { |
526 | 542 | return addCurveDirectlyInternal(poCurve, dfToleranceEps, TRUE); |
527 | 542 | } |
528 | | |
529 | | OGRErr OGRCompoundCurve::addCurveDirectlyInternal(OGRCurve *poCurve, |
530 | | double dfToleranceEps, |
531 | | int bNeedRealloc) |
532 | 542 | { |
533 | 542 | if (poCurve->getNumPoints() == 1) |
534 | 1 | { |
535 | 1 | CPLError(CE_Failure, CPLE_AppDefined, |
536 | 1 | "Invalid curve: not enough points"); |
537 | 1 | return OGRERR_FAILURE; |
538 | 1 | } |
539 | | |
540 | 541 | const OGRwkbGeometryType eCurveType = |
541 | 541 | wkbFlatten(poCurve->getGeometryType()); |
542 | 541 | if (EQUAL(poCurve->getGeometryName(), "LINEARRING")) |
543 | 0 | { |
544 | 0 | CPLError(CE_Failure, CPLE_AppDefined, "Linearring not allowed."); |
545 | 0 | return OGRERR_FAILURE; |
546 | 0 | } |
547 | 541 | else if (eCurveType == wkbCompoundCurve) |
548 | 0 | { |
549 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
550 | 0 | "Cannot add a compound curve inside a compound curve"); |
551 | 0 | return OGRERR_FAILURE; |
552 | 0 | } |
553 | | |
554 | 541 | if (oCC.nCurveCount > 0) |
555 | 489 | { |
556 | 489 | if (oCC.papoCurves[oCC.nCurveCount - 1]->IsEmpty() || |
557 | 489 | poCurve->IsEmpty()) |
558 | 0 | { |
559 | 0 | CPLError(CE_Failure, CPLE_AppDefined, "Non contiguous curves"); |
560 | 0 | return OGRERR_FAILURE; |
561 | 0 | } |
562 | | |
563 | 489 | OGRPoint oEnd; |
564 | 489 | OGRPoint start; |
565 | 489 | oCC.papoCurves[oCC.nCurveCount - 1]->EndPoint(&oEnd); |
566 | 489 | poCurve->StartPoint(&start); |
567 | 489 | if (fabs(oEnd.getX() - start.getX()) > |
568 | 489 | dfToleranceEps * fabs(start.getX()) || |
569 | 489 | fabs(oEnd.getY() - start.getY()) > |
570 | 484 | dfToleranceEps * fabs(start.getY()) || |
571 | 489 | fabs(oEnd.getZ() - start.getZ()) > |
572 | 471 | dfToleranceEps * fabs(start.getZ())) |
573 | 241 | { |
574 | 241 | poCurve->EndPoint(&start); |
575 | 241 | if (fabs(oEnd.getX() - start.getX()) > |
576 | 241 | dfToleranceEps * fabs(start.getX()) || |
577 | 241 | fabs(oEnd.getY() - start.getY()) > |
578 | 239 | dfToleranceEps * fabs(start.getY()) || |
579 | 241 | fabs(oEnd.getZ() - start.getZ()) > |
580 | 235 | dfToleranceEps * fabs(start.getZ())) |
581 | 8 | { |
582 | 8 | CPLError(CE_Failure, CPLE_AppDefined, "Non contiguous curves"); |
583 | 8 | return OGRERR_FAILURE; |
584 | 8 | } |
585 | | |
586 | 233 | CPLDebug("GML", "reversing curve"); |
587 | 233 | poCurve->toSimpleCurve()->reversePoints(); |
588 | 233 | } |
589 | | // Patch so that it matches exactly. |
590 | 481 | poCurve->toSimpleCurve()->setPoint(0, &oEnd); |
591 | 481 | } |
592 | | |
593 | 533 | return oCC.addCurveDirectly(this, poCurve, bNeedRealloc); |
594 | 541 | } |
595 | | |
596 | | /************************************************************************/ |
597 | | /* addCurve() */ |
598 | | /************************************************************************/ |
599 | | |
600 | | /** |
601 | | * \brief Add a curve directly to the container. |
602 | | * |
603 | | * There is no ISO SQL/MM analog to this method. |
604 | | * |
605 | | * This method is the same as the C function OGR_G_AddGeometryDirectly(). |
606 | | * |
607 | | * @param poCurve geometry to add to the container. |
608 | | * @param dfToleranceEps relative tolerance when checking that the first point |
609 | | * of a segment matches then end point of the previous one. Default value: |
610 | | * OGRCompoundCurve::DEFAULT_TOLERANCE_EPSILON. |
611 | | * |
612 | | * @return OGRERR_NONE if successful, or OGRERR_FAILURE in case of error |
613 | | * (for example if curves are not contiguous) |
614 | | */ |
615 | | OGRErr OGRCompoundCurve::addCurve(std::unique_ptr<OGRCurve> poCurve, |
616 | | double dfToleranceEps) |
617 | 0 | { |
618 | 0 | OGRCurve *poCurvePtr = poCurve.release(); |
619 | 0 | OGRErr eErr = addCurveDirectlyInternal(poCurvePtr, dfToleranceEps, TRUE); |
620 | 0 | if (eErr != OGRERR_NONE) |
621 | 0 | delete poCurvePtr; |
622 | 0 | return eErr; |
623 | 0 | } |
624 | | |
625 | | /************************************************************************/ |
626 | | /* transform() */ |
627 | | /************************************************************************/ |
628 | | |
629 | | OGRErr OGRCompoundCurve::transform(OGRCoordinateTransformation *poCT) |
630 | 0 | { |
631 | 0 | return oCC.transform(this, poCT); |
632 | 0 | } |
633 | | |
634 | | /************************************************************************/ |
635 | | /* flattenTo2D() */ |
636 | | /************************************************************************/ |
637 | | |
638 | | void OGRCompoundCurve::flattenTo2D() |
639 | 0 | { |
640 | 0 | oCC.flattenTo2D(this); |
641 | 0 | } |
642 | | |
643 | | /************************************************************************/ |
644 | | /* segmentize() */ |
645 | | /************************************************************************/ |
646 | | |
647 | | bool OGRCompoundCurve::segmentize(double dfMaxLength) |
648 | 0 | { |
649 | 0 | return oCC.segmentize(dfMaxLength); |
650 | 0 | } |
651 | | |
652 | | /************************************************************************/ |
653 | | /* swapXY() */ |
654 | | /************************************************************************/ |
655 | | |
656 | | void OGRCompoundCurve::swapXY() |
657 | 0 | { |
658 | 0 | oCC.swapXY(); |
659 | 0 | } |
660 | | |
661 | | /************************************************************************/ |
662 | | /* hasCurveGeometry() */ |
663 | | /************************************************************************/ |
664 | | |
665 | | OGRBoolean OGRCompoundCurve::hasCurveGeometry(int bLookForNonLinear) const |
666 | 5 | { |
667 | 5 | if (bLookForNonLinear) |
668 | 0 | { |
669 | 0 | return oCC.hasCurveGeometry(bLookForNonLinear); |
670 | 0 | } |
671 | | |
672 | 5 | return TRUE; |
673 | 5 | } |
674 | | |
675 | | /************************************************************************/ |
676 | | /* getLinearGeometry() */ |
677 | | /************************************************************************/ |
678 | | |
679 | | OGRGeometry * |
680 | | OGRCompoundCurve::getLinearGeometry(double dfMaxAngleStepSizeDegrees, |
681 | | const char *const *papszOptions) const |
682 | 0 | { |
683 | 0 | return CurveToLine(dfMaxAngleStepSizeDegrees, papszOptions); |
684 | 0 | } |
685 | | |
686 | | /************************************************************************/ |
687 | | /* getNumPoints() */ |
688 | | /************************************************************************/ |
689 | | |
690 | | int OGRCompoundCurve::getNumPoints() const |
691 | 0 | { |
692 | 0 | int nPoints = 0; |
693 | 0 | for (int i = 0; i < oCC.nCurveCount; i++) |
694 | 0 | { |
695 | 0 | nPoints += oCC.papoCurves[i]->getNumPoints(); |
696 | 0 | if (i != 0) |
697 | 0 | nPoints--; |
698 | 0 | } |
699 | 0 | return nPoints; |
700 | 0 | } |
701 | | |
702 | | /************************************************************************/ |
703 | | /* OGRCompoundCurvePointIterator */ |
704 | | /************************************************************************/ |
705 | | |
706 | | class OGRCompoundCurvePointIterator final : public OGRPointIterator |
707 | | { |
708 | | CPL_DISALLOW_COPY_ASSIGN(OGRCompoundCurvePointIterator) |
709 | | |
710 | | const OGRCompoundCurve *poCC = nullptr; |
711 | | int iCurCurve = 0; |
712 | | OGRPointIterator *poCurveIter = nullptr; |
713 | | |
714 | | public: |
715 | | explicit OGRCompoundCurvePointIterator(const OGRCompoundCurve *poCCIn) |
716 | 0 | : poCC(poCCIn) |
717 | 0 | { |
718 | 0 | } |
719 | | |
720 | | ~OGRCompoundCurvePointIterator() override |
721 | 0 | { |
722 | 0 | delete poCurveIter; |
723 | 0 | } |
724 | | |
725 | | OGRBoolean getNextPoint(OGRPoint *p) override; |
726 | | }; |
727 | | |
728 | | /************************************************************************/ |
729 | | /* getNextPoint() */ |
730 | | /************************************************************************/ |
731 | | |
732 | | OGRBoolean OGRCompoundCurvePointIterator::getNextPoint(OGRPoint *p) |
733 | 0 | { |
734 | 0 | if (iCurCurve == poCC->getNumCurves()) |
735 | 0 | return FALSE; |
736 | 0 | if (poCurveIter == nullptr) |
737 | 0 | poCurveIter = poCC->getCurve(0)->getPointIterator(); |
738 | 0 | if (!poCurveIter->getNextPoint(p)) |
739 | 0 | { |
740 | 0 | iCurCurve++; |
741 | 0 | if (iCurCurve == poCC->getNumCurves()) |
742 | 0 | return FALSE; |
743 | 0 | delete poCurveIter; |
744 | 0 | poCurveIter = poCC->getCurve(iCurCurve)->getPointIterator(); |
745 | | // Skip first point. |
746 | 0 | return poCurveIter->getNextPoint(p) && poCurveIter->getNextPoint(p); |
747 | 0 | } |
748 | 0 | return TRUE; |
749 | 0 | } |
750 | | |
751 | | /************************************************************************/ |
752 | | /* getPointIterator() */ |
753 | | /************************************************************************/ |
754 | | |
755 | | OGRPointIterator *OGRCompoundCurve::getPointIterator() const |
756 | 0 | { |
757 | 0 | return new OGRCompoundCurvePointIterator(this); |
758 | 0 | } |
759 | | |
760 | | /************************************************************************/ |
761 | | /* CastToLineString() */ |
762 | | /************************************************************************/ |
763 | | |
764 | | //! @cond Doxygen_Suppress |
765 | | OGRLineString *OGRCompoundCurve::CastToLineString(OGRCompoundCurve *poCC) |
766 | 0 | { |
767 | 0 | for (int i = 0; i < poCC->oCC.nCurveCount; i++) |
768 | 0 | { |
769 | 0 | poCC->oCC.papoCurves[i] = |
770 | 0 | OGRCurve::CastToLineString(poCC->oCC.papoCurves[i]); |
771 | 0 | if (poCC->oCC.papoCurves[i] == nullptr) |
772 | 0 | { |
773 | 0 | delete poCC; |
774 | 0 | return nullptr; |
775 | 0 | } |
776 | 0 | } |
777 | | |
778 | 0 | if (poCC->oCC.nCurveCount == 1) |
779 | 0 | { |
780 | 0 | OGRLineString *poLS = poCC->oCC.papoCurves[0]->toLineString(); |
781 | 0 | poLS->assignSpatialReference(poCC->getSpatialReference()); |
782 | 0 | poCC->oCC.papoCurves[0] = nullptr; |
783 | 0 | delete poCC; |
784 | 0 | return poLS; |
785 | 0 | } |
786 | | |
787 | 0 | OGRLineString *poLS = poCC->CurveToLineInternal(0, nullptr, FALSE); |
788 | 0 | delete poCC; |
789 | 0 | return poLS; |
790 | 0 | } |
791 | | |
792 | | /************************************************************************/ |
793 | | /* CastToLinearRing() */ |
794 | | /************************************************************************/ |
795 | | |
796 | | /** |
797 | | * \brief Cast to linear ring. |
798 | | * |
799 | | * The passed in geometry is consumed and a new one returned (or NULL in case |
800 | | * of failure) |
801 | | * |
802 | | * @param poCC the input geometry - ownership is passed to the method. |
803 | | * @return new geometry. |
804 | | */ |
805 | | |
806 | | OGRLinearRing *OGRCompoundCurve::CastToLinearRing(OGRCompoundCurve *poCC) |
807 | 0 | { |
808 | 0 | for (int i = 0; i < poCC->oCC.nCurveCount; i++) |
809 | 0 | { |
810 | 0 | poCC->oCC.papoCurves[i] = |
811 | 0 | OGRCurve::CastToLineString(poCC->oCC.papoCurves[i]); |
812 | 0 | if (poCC->oCC.papoCurves[i] == nullptr) |
813 | 0 | { |
814 | 0 | delete poCC; |
815 | 0 | return nullptr; |
816 | 0 | } |
817 | 0 | } |
818 | | |
819 | 0 | if (poCC->oCC.nCurveCount == 1) |
820 | 0 | { |
821 | 0 | OGRLinearRing *poLR = |
822 | 0 | OGRCurve::CastToLinearRing(poCC->oCC.papoCurves[0]); |
823 | 0 | if (poLR != nullptr) |
824 | 0 | { |
825 | 0 | poLR->assignSpatialReference(poCC->getSpatialReference()); |
826 | 0 | } |
827 | 0 | poCC->oCC.papoCurves[0] = nullptr; |
828 | 0 | delete poCC; |
829 | 0 | return poLR; |
830 | 0 | } |
831 | | |
832 | 0 | OGRLinearRing *poLR = |
833 | 0 | poCC->CurveToLineInternal(0, nullptr, TRUE)->toLinearRing(); |
834 | 0 | delete poCC; |
835 | 0 | return poLR; |
836 | 0 | } |
837 | | |
838 | | /************************************************************************/ |
839 | | /* GetCasterToLineString() */ |
840 | | /************************************************************************/ |
841 | | |
842 | | OGRLineString *OGRCompoundCurve::CasterToLineString(OGRCurve *poCurve) |
843 | 0 | { |
844 | 0 | OGRCompoundCurve *poCC = poCurve->toCompoundCurve(); |
845 | 0 | return OGRCompoundCurve::CastToLineString(poCC); |
846 | 0 | } |
847 | | |
848 | | OGRCurveCasterToLineString OGRCompoundCurve::GetCasterToLineString() const |
849 | 0 | { |
850 | 0 | return OGRCompoundCurve::CasterToLineString; |
851 | 0 | } |
852 | | |
853 | | /************************************************************************/ |
854 | | /* GetCasterToLinearRing() */ |
855 | | /************************************************************************/ |
856 | | |
857 | | OGRLinearRing *OGRCompoundCurve::CasterToLinearRing(OGRCurve *poCurve) |
858 | 0 | { |
859 | 0 | OGRCompoundCurve *poCC = poCurve->toCompoundCurve(); |
860 | 0 | return OGRCompoundCurve::CastToLinearRing(poCC); |
861 | 0 | } |
862 | | |
863 | | OGRCurveCasterToLinearRing OGRCompoundCurve::GetCasterToLinearRing() const |
864 | 0 | { |
865 | 0 | return OGRCompoundCurve::CasterToLinearRing; |
866 | 0 | } |
867 | | |
868 | | //! @endcond |
869 | | |
870 | | /************************************************************************/ |
871 | | /* get_Area() */ |
872 | | /************************************************************************/ |
873 | | |
874 | | double OGRCompoundCurve::get_Area() const |
875 | 0 | { |
876 | 0 | if (IsEmpty() || !get_IsClosed()) |
877 | 0 | return 0; |
878 | | |
879 | | // Optimization for convex rings. |
880 | 0 | if (IsConvex()) |
881 | 0 | { |
882 | | // Compute area of shape without the circular segments. |
883 | 0 | OGRPointIterator *poIter = getPointIterator(); |
884 | 0 | OGRLineString oLS; |
885 | 0 | oLS.setNumPoints(getNumPoints()); |
886 | 0 | OGRPoint p; |
887 | 0 | for (int i = 0; poIter->getNextPoint(&p); i++) |
888 | 0 | { |
889 | 0 | oLS.setPoint(i, p.getX(), p.getY()); |
890 | 0 | } |
891 | 0 | double dfArea = oLS.get_Area(); |
892 | 0 | delete poIter; |
893 | | |
894 | | // Add the area of the spherical segments. |
895 | 0 | dfArea += get_AreaOfCurveSegments(); |
896 | |
|
897 | 0 | return dfArea; |
898 | 0 | } |
899 | | |
900 | 0 | OGRLineString *poLS = CurveToLine(); |
901 | 0 | double dfArea = poLS->get_Area(); |
902 | 0 | delete poLS; |
903 | |
|
904 | 0 | return dfArea; |
905 | 0 | } |
906 | | |
907 | | /************************************************************************/ |
908 | | /* get_GeodesicArea() */ |
909 | | /************************************************************************/ |
910 | | |
911 | | double OGRCompoundCurve::get_GeodesicArea( |
912 | | const OGRSpatialReference *poSRSOverride) const |
913 | 0 | { |
914 | 0 | if (IsEmpty()) |
915 | 0 | return 0; |
916 | | |
917 | 0 | if (!get_IsClosed()) |
918 | 0 | { |
919 | 0 | CPLError(CE_Failure, CPLE_AppDefined, "Non-closed geometry"); |
920 | 0 | return -1; |
921 | 0 | } |
922 | | |
923 | 0 | if (!poSRSOverride) |
924 | 0 | poSRSOverride = getSpatialReference(); |
925 | |
|
926 | 0 | auto poLS = std::unique_ptr<OGRLineString>(CurveToLine()); |
927 | 0 | return poLS->get_GeodesicArea(poSRSOverride); |
928 | 0 | } |
929 | | |
930 | | /************************************************************************/ |
931 | | /* get_GeodesicLength() */ |
932 | | /************************************************************************/ |
933 | | |
934 | | double OGRCompoundCurve::get_GeodesicLength( |
935 | | const OGRSpatialReference *poSRSOverride) const |
936 | 0 | { |
937 | 0 | if (IsEmpty()) |
938 | 0 | return 0; |
939 | | |
940 | 0 | if (!poSRSOverride) |
941 | 0 | poSRSOverride = getSpatialReference(); |
942 | |
|
943 | 0 | auto poLS = std::unique_ptr<OGRLineString>(CurveToLine()); |
944 | 0 | return poLS->get_GeodesicLength(poSRSOverride); |
945 | 0 | } |
946 | | |
947 | | /************************************************************************/ |
948 | | /* get_AreaOfCurveSegments() */ |
949 | | /************************************************************************/ |
950 | | |
951 | | /** Return area of curve segments |
952 | | * @return area. |
953 | | */ |
954 | | double OGRCompoundCurve::get_AreaOfCurveSegments() const |
955 | 0 | { |
956 | 0 | double dfArea = 0; |
957 | 0 | for (int i = 0; i < getNumCurves(); i++) |
958 | 0 | { |
959 | 0 | const OGRCurve *poPart = getCurve(i); |
960 | 0 | dfArea += poPart->get_AreaOfCurveSegments(); |
961 | 0 | } |
962 | 0 | return dfArea; |
963 | 0 | } |
964 | | |
965 | | /************************************************************************/ |
966 | | /* hasEmptyParts() */ |
967 | | /************************************************************************/ |
968 | | |
969 | | bool OGRCompoundCurve::hasEmptyParts() const |
970 | 0 | { |
971 | 0 | return oCC.hasEmptyParts(); |
972 | 0 | } |
973 | | |
974 | | /************************************************************************/ |
975 | | /* removeEmptyParts() */ |
976 | | /************************************************************************/ |
977 | | |
978 | | void OGRCompoundCurve::removeEmptyParts() |
979 | 0 | { |
980 | 0 | oCC.removeEmptyParts(); |
981 | 0 | } |
982 | | |
983 | | /************************************************************************/ |
984 | | /* reversePoints() */ |
985 | | /************************************************************************/ |
986 | | |
987 | | /** |
988 | | * \brief Reverse point order. |
989 | | * |
990 | | * This method updates the points in this curve in place |
991 | | * reversing the point ordering (first for last, etc) and component ordering. |
992 | | * |
993 | | * @since 3.10 |
994 | | */ |
995 | | void OGRCompoundCurve::reversePoints() |
996 | | |
997 | 0 | { |
998 | 0 | oCC.reversePoints(); |
999 | 0 | } |