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