/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 | 50.0k | 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 | 50.0k | { |
61 | 50.0k | auto ret = new (std::nothrow) OGRCompoundCurve(*this); |
62 | 50.0k | if (ret) |
63 | 50.0k | { |
64 | 50.0k | if (ret->WkbSize() != WkbSize()) |
65 | 0 | { |
66 | 0 | delete ret; |
67 | 0 | ret = nullptr; |
68 | 0 | } |
69 | 50.0k | } |
70 | 50.0k | return ret; |
71 | 50.0k | } |
72 | | |
73 | | /************************************************************************/ |
74 | | /* getGeometryType() */ |
75 | | /************************************************************************/ |
76 | | |
77 | | OGRwkbGeometryType OGRCompoundCurve::getGeometryType() const |
78 | | |
79 | 471k | { |
80 | 471k | if ((flags & OGR_G_3D) && (flags & OGR_G_MEASURED)) |
81 | 136k | return wkbCompoundCurveZM; |
82 | 335k | else if (flags & OGR_G_MEASURED) |
83 | 47.7k | return wkbCompoundCurveM; |
84 | 287k | else if (flags & OGR_G_3D) |
85 | 50.3k | return wkbCompoundCurveZ; |
86 | 237k | else |
87 | 237k | return wkbCompoundCurve; |
88 | 471k | } |
89 | | |
90 | | /************************************************************************/ |
91 | | /* getGeometryName() */ |
92 | | /************************************************************************/ |
93 | | |
94 | | const char *OGRCompoundCurve::getGeometryName() const |
95 | | |
96 | 100k | { |
97 | 100k | return "COMPOUNDCURVE"; |
98 | 100k | } |
99 | | |
100 | | /************************************************************************/ |
101 | | /* WkbSize() */ |
102 | | /************************************************************************/ |
103 | | size_t OGRCompoundCurve::WkbSize() const |
104 | 367k | { |
105 | 367k | return oCC.WkbSize(); |
106 | 367k | } |
107 | | |
108 | | /************************************************************************/ |
109 | | /* addCurveDirectlyFromWkt() */ |
110 | | /************************************************************************/ |
111 | | |
112 | | OGRErr OGRCompoundCurve::addCurveDirectlyFromWkb(OGRGeometry *poSelf, |
113 | | OGRCurve *poCurve) |
114 | 26.1k | { |
115 | 26.1k | OGRCompoundCurve *poCC = poSelf->toCompoundCurve(); |
116 | 26.1k | return poCC->addCurveDirectlyInternal(poCurve, DEFAULT_TOLERANCE_EPSILON, |
117 | 26.1k | FALSE); |
118 | 26.1k | } |
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 | 84.1k | { |
128 | 84.1k | OGRwkbByteOrder eByteOrder = wkbNDR; |
129 | 84.1k | size_t nDataOffset = 0; |
130 | | // coverity[tainted_data] |
131 | 84.1k | OGRErr eErr = oCC.importPreambleFromWkb(this, pabyData, nSize, nDataOffset, |
132 | 84.1k | eByteOrder, 9, eWkbVariant); |
133 | 84.1k | if (eErr != OGRERR_NONE) |
134 | 8.44k | return eErr; |
135 | | |
136 | 75.7k | eErr = oCC.importBodyFromWkb(this, pabyData + nDataOffset, nSize, |
137 | 75.7k | false, // bAcceptCompoundCurve |
138 | 75.7k | addCurveDirectlyFromWkb, eWkbVariant, |
139 | 75.7k | nBytesConsumedOut); |
140 | 75.7k | if (eErr == OGRERR_NONE) |
141 | 64.3k | nBytesConsumedOut += nDataOffset; |
142 | 75.7k | return eErr; |
143 | 84.1k | } |
144 | | |
145 | | /************************************************************************/ |
146 | | /* exportToWkb() */ |
147 | | /************************************************************************/ |
148 | | |
149 | | OGRErr OGRCompoundCurve::exportToWkb(unsigned char *pabyData, |
150 | | const OGRwkbExportOptions *psOptions) const |
151 | 37.1k | { |
152 | 37.1k | OGRwkbExportOptions sOptions(psOptions ? *psOptions |
153 | 37.1k | : OGRwkbExportOptions()); |
154 | | |
155 | | // Does not make sense for new geometries, so patch it. |
156 | 37.1k | if (sOptions.eWkbVariant == wkbVariantOldOgc) |
157 | 9.07k | sOptions.eWkbVariant = wkbVariantIso; |
158 | 37.1k | return oCC.exportToWkb(this, pabyData, &sOptions); |
159 | 37.1k | } |
160 | | |
161 | | /************************************************************************/ |
162 | | /* addCurveDirectlyFromWkt() */ |
163 | | /************************************************************************/ |
164 | | |
165 | | OGRErr OGRCompoundCurve::addCurveDirectlyFromWkt(OGRGeometry *poSelf, |
166 | | OGRCurve *poCurve) |
167 | 21.9k | { |
168 | 21.9k | return poSelf->toCompoundCurve()->addCurveDirectly(poCurve); |
169 | 21.9k | } |
170 | | |
171 | | /************************************************************************/ |
172 | | /* importFromWkt() */ |
173 | | /************************************************************************/ |
174 | | |
175 | | OGRErr OGRCompoundCurve::importFromWkt(const char **ppszInput) |
176 | 33.2k | { |
177 | 33.2k | return importCurveCollectionFromWkt(ppszInput, |
178 | 33.2k | FALSE, // bAllowEmptyComponent |
179 | 33.2k | TRUE, // bAllowLineString |
180 | 33.2k | TRUE, // bAllowCurve |
181 | 33.2k | FALSE, // bAllowCompoundCurve |
182 | 33.2k | addCurveDirectlyFromWkt); |
183 | 33.2k | } |
184 | | |
185 | | /************************************************************************/ |
186 | | /* exportToWkt() */ |
187 | | /************************************************************************/ |
188 | | std::string OGRCompoundCurve::exportToWkt(const OGRWktOptions &opts, |
189 | | OGRErr *err) const |
190 | 32.9k | { |
191 | 32.9k | return oCC.exportToWkt(this, opts, err); |
192 | 32.9k | } |
193 | | |
194 | | /************************************************************************/ |
195 | | /* empty() */ |
196 | | /************************************************************************/ |
197 | | |
198 | | void OGRCompoundCurve::empty() |
199 | 117k | { |
200 | 117k | oCC.empty(this); |
201 | 117k | } |
202 | | |
203 | | /************************************************************************/ |
204 | | /* getEnvelope() */ |
205 | | /************************************************************************/ |
206 | | |
207 | | void OGRCompoundCurve::getEnvelope(OGREnvelope *psEnvelope) const |
208 | 226 | { |
209 | 226 | oCC.getEnvelope(psEnvelope); |
210 | 226 | } |
211 | | |
212 | | /************************************************************************/ |
213 | | /* getEnvelope() */ |
214 | | /************************************************************************/ |
215 | | |
216 | | void OGRCompoundCurve::getEnvelope(OGREnvelope3D *psEnvelope) const |
217 | 12.9k | { |
218 | 12.9k | oCC.getEnvelope(psEnvelope); |
219 | 12.9k | } |
220 | | |
221 | | /************************************************************************/ |
222 | | /* IsEmpty() */ |
223 | | /************************************************************************/ |
224 | | |
225 | | OGRBoolean OGRCompoundCurve::IsEmpty() const |
226 | 237k | { |
227 | 237k | return oCC.IsEmpty(); |
228 | 237k | } |
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 | 39.7k | { |
250 | 39.7k | CPLAssert(oCC.nCurveCount > 0); |
251 | 39.7k | oCC.papoCurves[0]->StartPoint(p); |
252 | 39.7k | } |
253 | | |
254 | | /************************************************************************/ |
255 | | /* EndPoint() */ |
256 | | /************************************************************************/ |
257 | | |
258 | | void OGRCompoundCurve::EndPoint(OGRPoint *p) const |
259 | 30.2k | { |
260 | 30.2k | CPLAssert(oCC.nCurveCount > 0); |
261 | 30.2k | oCC.papoCurves[oCC.nCurveCount - 1]->EndPoint(p); |
262 | 30.2k | } |
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 | 86.1k | { |
307 | 86.1k | OGRLineString *const poLine = |
308 | 86.1k | bIsLinearRing ? new OGRLinearRing() : new OGRLineString(); |
309 | 86.1k | poLine->assignSpatialReference(getSpatialReference()); |
310 | 314k | for (int iGeom = 0; iGeom < oCC.nCurveCount; iGeom++) |
311 | 228k | { |
312 | 228k | OGRLineString *poSubLS = oCC.papoCurves[iGeom]->CurveToLine( |
313 | 228k | dfMaxAngleStepSizeDegrees, papszOptions); |
314 | 228k | poLine->addSubLineString(poSubLS, (iGeom == 0) ? 0 : 1); |
315 | 228k | delete poSubLS; |
316 | 228k | } |
317 | 86.1k | return poLine; |
318 | 86.1k | } |
319 | | |
320 | | /************************************************************************/ |
321 | | /* CurveToLine() */ |
322 | | /************************************************************************/ |
323 | | |
324 | | OGRLineString * |
325 | | OGRCompoundCurve::CurveToLine(double dfMaxAngleStepSizeDegrees, |
326 | | const char *const *papszOptions) const |
327 | 84.5k | { |
328 | 84.5k | return CurveToLineInternal(dfMaxAngleStepSizeDegrees, papszOptions, FALSE); |
329 | 84.5k | } |
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 | 118k | { |
352 | 118k | return oCC.setCoordinateDimension(this, nNewDimension); |
353 | 118k | } |
354 | | |
355 | | bool OGRCompoundCurve::set3D(OGRBoolean bIs3D) |
356 | 101k | { |
357 | 101k | return oCC.set3D(this, bIs3D); |
358 | 101k | } |
359 | | |
360 | | bool OGRCompoundCurve::setMeasured(OGRBoolean bIsMeasured) |
361 | 225k | { |
362 | 225k | return oCC.setMeasured(this, bIsMeasured); |
363 | 225k | } |
364 | | |
365 | | /************************************************************************/ |
366 | | /* assignSpatialReference() */ |
367 | | /************************************************************************/ |
368 | | |
369 | | void OGRCompoundCurve::assignSpatialReference(const OGRSpatialReference *poSR) |
370 | 179k | { |
371 | 179k | oCC.assignSpatialReference(this, poSR); |
372 | 179k | } |
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 | 105k | { |
390 | 105k | return oCC.nCurveCount; |
391 | 105k | } |
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 | 33.3k | { |
438 | 33.3k | return oCC.getCurve(iCurve); |
439 | 33.3k | } |
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 | 2.78k | { |
455 | 2.78k | return oCC.stealCurve(iCurve); |
456 | 2.78k | } |
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 | 443k | { |
516 | 443k | return addCurveDirectlyInternal(poCurve, dfToleranceEps, TRUE); |
517 | 443k | } |
518 | | |
519 | | OGRErr OGRCompoundCurve::addCurveDirectlyInternal(OGRCurve *poCurve, |
520 | | double dfToleranceEps, |
521 | | int bNeedRealloc) |
522 | 508k | { |
523 | 508k | if (poCurve->getNumPoints() == 1) |
524 | 731 | { |
525 | 731 | CPLError(CE_Failure, CPLE_AppDefined, |
526 | 731 | "Invalid curve: not enough points"); |
527 | 731 | return OGRERR_FAILURE; |
528 | 731 | } |
529 | | |
530 | 507k | const OGRwkbGeometryType eCurveType = |
531 | 507k | wkbFlatten(poCurve->getGeometryType()); |
532 | 507k | if (EQUAL(poCurve->getGeometryName(), "LINEARRING")) |
533 | 1 | { |
534 | 1 | CPLError(CE_Failure, CPLE_AppDefined, "Linearring not allowed."); |
535 | 1 | return OGRERR_FAILURE; |
536 | 1 | } |
537 | 507k | else if (eCurveType == wkbCompoundCurve) |
538 | 155 | { |
539 | 155 | CPLError(CE_Failure, CPLE_AppDefined, |
540 | 155 | "Cannot add a compound curve inside a compound curve"); |
541 | 155 | return OGRERR_FAILURE; |
542 | 155 | } |
543 | | |
544 | 507k | if (oCC.nCurveCount > 0) |
545 | 373k | { |
546 | 373k | if (oCC.papoCurves[oCC.nCurveCount - 1]->IsEmpty() || |
547 | 372k | poCurve->IsEmpty()) |
548 | 968 | { |
549 | 968 | CPLError(CE_Failure, CPLE_AppDefined, "Non contiguous curves"); |
550 | 968 | return OGRERR_FAILURE; |
551 | 968 | } |
552 | | |
553 | 372k | OGRPoint oEnd; |
554 | 372k | OGRPoint start; |
555 | 372k | oCC.papoCurves[oCC.nCurveCount - 1]->EndPoint(&oEnd); |
556 | 372k | poCurve->StartPoint(&start); |
557 | 372k | if (fabs(oEnd.getX() - start.getX()) > |
558 | 372k | dfToleranceEps * fabs(start.getX()) || |
559 | 257k | fabs(oEnd.getY() - start.getY()) > |
560 | 257k | dfToleranceEps * fabs(start.getY()) || |
561 | 195k | fabs(oEnd.getZ() - start.getZ()) > |
562 | 195k | dfToleranceEps * fabs(start.getZ())) |
563 | 178k | { |
564 | 178k | poCurve->EndPoint(&start); |
565 | 178k | if (fabs(oEnd.getX() - start.getX()) > |
566 | 178k | dfToleranceEps * fabs(start.getX()) || |
567 | 84.5k | fabs(oEnd.getY() - start.getY()) > |
568 | 84.5k | dfToleranceEps * fabs(start.getY()) || |
569 | 33.5k | fabs(oEnd.getZ() - start.getZ()) > |
570 | 33.5k | dfToleranceEps * fabs(start.getZ())) |
571 | 144k | { |
572 | 144k | CPLError(CE_Failure, CPLE_AppDefined, "Non contiguous curves"); |
573 | 144k | return OGRERR_FAILURE; |
574 | 144k | } |
575 | | |
576 | 33.3k | CPLDebug("GML", "reversing curve"); |
577 | 33.3k | poCurve->toSimpleCurve()->reversePoints(); |
578 | 33.3k | } |
579 | | // Patch so that it matches exactly. |
580 | 227k | poCurve->toSimpleCurve()->setPoint(0, &oEnd); |
581 | 227k | } |
582 | | |
583 | 361k | return oCC.addCurveDirectly(this, poCurve, bNeedRealloc); |
584 | 507k | } |
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 | 38.4k | { |
608 | 38.4k | OGRCurve *poCurvePtr = poCurve.release(); |
609 | 38.4k | OGRErr eErr = addCurveDirectlyInternal(poCurvePtr, dfToleranceEps, TRUE); |
610 | 38.4k | if (eErr != OGRERR_NONE) |
611 | 448 | delete poCurvePtr; |
612 | 38.4k | return eErr; |
613 | 38.4k | } |
614 | | |
615 | | /************************************************************************/ |
616 | | /* transform() */ |
617 | | /************************************************************************/ |
618 | | |
619 | | OGRErr OGRCompoundCurve::transform(OGRCoordinateTransformation *poCT) |
620 | 963 | { |
621 | 963 | return oCC.transform(this, poCT); |
622 | 963 | } |
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 | 104k | { |
657 | 104k | if (bLookForNonLinear) |
658 | 24.1k | { |
659 | 24.1k | return oCC.hasCurveGeometry(bLookForNonLinear); |
660 | 24.1k | } |
661 | | |
662 | 80.4k | return TRUE; |
663 | 104k | } |
664 | | |
665 | | /************************************************************************/ |
666 | | /* getLinearGeometry() */ |
667 | | /************************************************************************/ |
668 | | |
669 | | OGRGeometry * |
670 | | OGRCompoundCurve::getLinearGeometry(double dfMaxAngleStepSizeDegrees, |
671 | | const char *const *papszOptions) const |
672 | 31.4k | { |
673 | 31.4k | return CurveToLine(dfMaxAngleStepSizeDegrees, papszOptions); |
674 | 31.4k | } |
675 | | |
676 | | /************************************************************************/ |
677 | | /* getNumPoints() */ |
678 | | /************************************************************************/ |
679 | | |
680 | | int OGRCompoundCurve::getNumPoints() const |
681 | 16.1k | { |
682 | 16.1k | int nPoints = 0; |
683 | 57.4k | for (int i = 0; i < oCC.nCurveCount; i++) |
684 | 41.3k | { |
685 | 41.3k | nPoints += oCC.papoCurves[i]->getNumPoints(); |
686 | 41.3k | if (i != 0) |
687 | 25.2k | nPoints--; |
688 | 41.3k | } |
689 | 16.1k | return nPoints; |
690 | 16.1k | } |
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 | 8.07k | : poCC(poCCIn) |
707 | 8.07k | { |
708 | 8.07k | } |
709 | | |
710 | | ~OGRCompoundCurvePointIterator() override |
711 | 8.07k | { |
712 | 8.07k | delete poCurveIter; |
713 | 8.07k | } |
714 | | |
715 | | OGRBoolean getNextPoint(OGRPoint *p) override; |
716 | | }; |
717 | | |
718 | | /************************************************************************/ |
719 | | /* getNextPoint() */ |
720 | | /************************************************************************/ |
721 | | |
722 | | OGRBoolean OGRCompoundCurvePointIterator::getNextPoint(OGRPoint *p) |
723 | 54.1k | { |
724 | 54.1k | if (iCurCurve == poCC->getNumCurves()) |
725 | 0 | return FALSE; |
726 | 54.1k | if (poCurveIter == nullptr) |
727 | 8.07k | poCurveIter = poCC->getCurve(0)->getPointIterator(); |
728 | 54.1k | if (!poCurveIter->getNextPoint(p)) |
729 | 15.3k | { |
730 | 15.3k | iCurCurve++; |
731 | 15.3k | if (iCurCurve == poCC->getNumCurves()) |
732 | 6.95k | return FALSE; |
733 | 8.39k | delete poCurveIter; |
734 | 8.39k | poCurveIter = poCC->getCurve(iCurCurve)->getPointIterator(); |
735 | | // Skip first point. |
736 | 8.39k | return poCurveIter->getNextPoint(p) && poCurveIter->getNextPoint(p); |
737 | 15.3k | } |
738 | 38.7k | return TRUE; |
739 | 54.1k | } |
740 | | |
741 | | /************************************************************************/ |
742 | | /* getPointIterator() */ |
743 | | /************************************************************************/ |
744 | | |
745 | | OGRPointIterator *OGRCompoundCurve::getPointIterator() const |
746 | 8.07k | { |
747 | 8.07k | return new OGRCompoundCurvePointIterator(this); |
748 | 8.07k | } |
749 | | |
750 | | /************************************************************************/ |
751 | | /* CastToLineString() */ |
752 | | /************************************************************************/ |
753 | | |
754 | | //! @cond Doxygen_Suppress |
755 | | OGRLineString *OGRCompoundCurve::CastToLineString(OGRCompoundCurve *poCC) |
756 | 1.63k | { |
757 | 2.15k | for (int i = 0; i < poCC->oCC.nCurveCount; i++) |
758 | 518 | { |
759 | 518 | poCC->oCC.papoCurves[i] = |
760 | 518 | OGRCurve::CastToLineString(poCC->oCC.papoCurves[i]); |
761 | 518 | if (poCC->oCC.papoCurves[i] == nullptr) |
762 | 0 | { |
763 | 0 | delete poCC; |
764 | 0 | return nullptr; |
765 | 0 | } |
766 | 518 | } |
767 | | |
768 | 1.63k | if (poCC->oCC.nCurveCount == 1) |
769 | 472 | { |
770 | 472 | OGRLineString *poLS = poCC->oCC.papoCurves[0]->toLineString(); |
771 | 472 | poLS->assignSpatialReference(poCC->getSpatialReference()); |
772 | 472 | poCC->oCC.papoCurves[0] = nullptr; |
773 | 472 | delete poCC; |
774 | 472 | return poLS; |
775 | 472 | } |
776 | | |
777 | 1.16k | OGRLineString *poLS = poCC->CurveToLineInternal(0, nullptr, FALSE); |
778 | 1.16k | delete poCC; |
779 | 1.16k | return poLS; |
780 | 1.63k | } |
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 | 687 | { |
798 | 1.63k | for (int i = 0; i < poCC->oCC.nCurveCount; i++) |
799 | 951 | { |
800 | 951 | poCC->oCC.papoCurves[i] = |
801 | 951 | OGRCurve::CastToLineString(poCC->oCC.papoCurves[i]); |
802 | 951 | if (poCC->oCC.papoCurves[i] == nullptr) |
803 | 0 | { |
804 | 0 | delete poCC; |
805 | 0 | return nullptr; |
806 | 0 | } |
807 | 951 | } |
808 | | |
809 | 687 | if (poCC->oCC.nCurveCount == 1) |
810 | 271 | { |
811 | 271 | OGRLinearRing *poLR = |
812 | 271 | OGRCurve::CastToLinearRing(poCC->oCC.papoCurves[0]); |
813 | 271 | if (poLR != nullptr) |
814 | 67 | { |
815 | 67 | poLR->assignSpatialReference(poCC->getSpatialReference()); |
816 | 67 | } |
817 | 271 | poCC->oCC.papoCurves[0] = nullptr; |
818 | 271 | delete poCC; |
819 | 271 | return poLR; |
820 | 271 | } |
821 | | |
822 | 416 | OGRLinearRing *poLR = |
823 | 416 | poCC->CurveToLineInternal(0, nullptr, TRUE)->toLinearRing(); |
824 | 416 | delete poCC; |
825 | 416 | return poLR; |
826 | 687 | } |
827 | | |
828 | | /************************************************************************/ |
829 | | /* GetCasterToLineString() */ |
830 | | /************************************************************************/ |
831 | | |
832 | | OGRLineString *OGRCompoundCurve::CasterToLineString(OGRCurve *poCurve) |
833 | 1.63k | { |
834 | 1.63k | OGRCompoundCurve *poCC = poCurve->toCompoundCurve(); |
835 | 1.63k | return OGRCompoundCurve::CastToLineString(poCC); |
836 | 1.63k | } |
837 | | |
838 | | OGRCurveCasterToLineString OGRCompoundCurve::GetCasterToLineString() const |
839 | 1.63k | { |
840 | 1.63k | return OGRCompoundCurve::CasterToLineString; |
841 | 1.63k | } |
842 | | |
843 | | /************************************************************************/ |
844 | | /* GetCasterToLinearRing() */ |
845 | | /************************************************************************/ |
846 | | |
847 | | OGRLinearRing *OGRCompoundCurve::CasterToLinearRing(OGRCurve *poCurve) |
848 | 687 | { |
849 | 687 | OGRCompoundCurve *poCC = poCurve->toCompoundCurve(); |
850 | 687 | return OGRCompoundCurve::CastToLinearRing(poCC); |
851 | 687 | } |
852 | | |
853 | | OGRCurveCasterToLinearRing OGRCompoundCurve::GetCasterToLinearRing() const |
854 | 687 | { |
855 | 687 | return OGRCompoundCurve::CasterToLinearRing; |
856 | 687 | } |
857 | | |
858 | | //! @endcond |
859 | | |
860 | | /************************************************************************/ |
861 | | /* get_Area() */ |
862 | | /************************************************************************/ |
863 | | |
864 | | double OGRCompoundCurve::get_Area() const |
865 | 9.50k | { |
866 | 9.50k | if (IsEmpty() || !get_IsClosed()) |
867 | 4.91k | return 0; |
868 | | |
869 | | // Optimization for convex rings. |
870 | 4.59k | if (IsConvex()) |
871 | 3.47k | { |
872 | | // Compute area of shape without the circular segments. |
873 | 3.47k | OGRPointIterator *poIter = getPointIterator(); |
874 | 3.47k | OGRLineString oLS; |
875 | 3.47k | oLS.setNumPoints(getNumPoints()); |
876 | 3.47k | OGRPoint p; |
877 | 24.8k | for (int i = 0; poIter->getNextPoint(&p); i++) |
878 | 21.4k | { |
879 | 21.4k | oLS.setPoint(i, p.getX(), p.getY()); |
880 | 21.4k | } |
881 | 3.47k | double dfArea = oLS.get_Area(); |
882 | 3.47k | delete poIter; |
883 | | |
884 | | // Add the area of the spherical segments. |
885 | 3.47k | dfArea += get_AreaOfCurveSegments(); |
886 | | |
887 | 3.47k | return dfArea; |
888 | 3.47k | } |
889 | | |
890 | 1.11k | OGRLineString *poLS = CurveToLine(); |
891 | 1.11k | double dfArea = poLS->get_Area(); |
892 | 1.11k | delete poLS; |
893 | | |
894 | 1.11k | return dfArea; |
895 | 4.59k | } |
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 | 3.47k | { |
946 | 3.47k | double dfArea = 0; |
947 | 10.9k | for (int i = 0; i < getNumCurves(); i++) |
948 | 7.43k | { |
949 | 7.43k | const OGRCurve *poPart = getCurve(i); |
950 | 7.43k | dfArea += poPart->get_AreaOfCurveSegments(); |
951 | 7.43k | } |
952 | 3.47k | return dfArea; |
953 | 3.47k | } |
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 | } |