/src/geos/src/geom/Geometry.cpp
Line | Count | Source |
1 | | /********************************************************************** |
2 | | * |
3 | | * GEOS - Geometry Engine Open Source |
4 | | * http://geos.osgeo.org |
5 | | * |
6 | | * Copyright (C) 2009 2011 Sandro Santilli <strk@kbt.io> |
7 | | * Copyright (C) 2005-2006 Refractions Research Inc. |
8 | | * Copyright (C) 2001-2002 Vivid Solutions Inc. |
9 | | * |
10 | | * This is free software; you can redistribute and/or modify it under |
11 | | * the terms of the GNU Lesser General Public Licence as published |
12 | | * by the Free Software Foundation. |
13 | | * See the COPYING file for more information. |
14 | | * |
15 | | ********************************************************************** |
16 | | * |
17 | | * Last port: geom/Geometry.java rev. 1.112 |
18 | | * |
19 | | **********************************************************************/ |
20 | | |
21 | | #include <geos/geom/HeuristicOverlay.h> |
22 | | #include <geos/geom/Geometry.h> |
23 | | #include <geos/geom/GeometryFactory.h> |
24 | | #include <geos/geom/PrecisionModel.h> |
25 | | #include <geos/geom/CoordinateSequence.h> |
26 | | #include <geos/geom/GeometryComponentFilter.h> |
27 | | #include <geos/geom/GeometryFilter.h> |
28 | | #include <geos/geom/GeometryCollection.h> |
29 | | #include <geos/geom/Point.h> |
30 | | #include <geos/geom/MultiPoint.h> |
31 | | #include <geos/geom/LineString.h> |
32 | | #include <geos/geom/LinearRing.h> |
33 | | #include <geos/geom/MultiLineString.h> |
34 | | #include <geos/geom/MultiPolygon.h> |
35 | | #include <geos/geom/IntersectionMatrix.h> |
36 | | #include <geos/util/IllegalArgumentException.h> |
37 | | #include <geos/algorithm/Centroid.h> |
38 | | #include <geos/algorithm/InteriorPointPoint.h> |
39 | | #include <geos/algorithm/InteriorPointLine.h> |
40 | | #include <geos/algorithm/InteriorPointArea.h> |
41 | | #include <geos/algorithm/ConvexHull.h> |
42 | | #include <geos/algorithm/locate/SimplePointInAreaLocator.h> |
43 | | #include <geos/geom/prep/PreparedGeometryFactory.h> |
44 | | #include <geos/operation/intersection/Rectangle.h> |
45 | | #include <geos/operation/intersection/RectangleIntersection.h> |
46 | | #include <geos/operation/predicate/RectangleContains.h> |
47 | | #include <geos/operation/predicate/RectangleIntersects.h> |
48 | | #include <geos/operation/relate/RelateOp.h> |
49 | | #include <geos/operation/relateng/RelateNG.h> |
50 | | #include <geos/operation/relateng/RelatePredicate.h> |
51 | | #include <geos/operation/valid/IsValidOp.h> |
52 | | #include <geos/operation/union/UnaryUnionOp.h> |
53 | | #include <geos/operation/buffer/BufferOp.h> |
54 | | #include <geos/operation/distance/DistanceOp.h> |
55 | | #include <geos/operation/valid/IsSimpleOp.h> |
56 | | #include <geos/operation/overlayng/OverlayNGRobust.h> |
57 | | #include <geos/operation/overlayng/OverlayUtil.h> |
58 | | #include <geos/io/WKBWriter.h> |
59 | | #include <geos/io/WKTWriter.h> |
60 | | #include <geos/version.h> |
61 | | |
62 | | #include <algorithm> |
63 | | #include <string> |
64 | | #include <typeinfo> |
65 | | #include <vector> |
66 | | #include <cassert> |
67 | | #include <memory> |
68 | | |
69 | | #ifdef _MSC_VER |
70 | | # ifdef MSVC_USE_VLD |
71 | | # include <vld.h> |
72 | | # endif |
73 | | #endif |
74 | | |
75 | | #define SHORTCIRCUIT_PREDICATES 1 |
76 | | //#define USE_RECTANGLE_INTERSECTION 1 |
77 | | #define USE_RELATENG 1 |
78 | | |
79 | | using namespace geos::algorithm; |
80 | | using namespace geos::operation::valid; |
81 | | using namespace geos::operation::relate; |
82 | | using namespace geos::operation::buffer; |
83 | | using namespace geos::operation::distance; |
84 | | using namespace geos::operation; |
85 | | using geos::operation::overlayng::OverlayNG; |
86 | | |
87 | | |
88 | | namespace geos { |
89 | | namespace geom { // geos::geom |
90 | | |
91 | | |
92 | | /* |
93 | | * Return current GEOS version |
94 | | */ |
95 | | std::string |
96 | | geosversion() |
97 | 0 | { |
98 | 0 | return GEOS_VERSION; |
99 | 0 | } |
100 | | |
101 | | /* |
102 | | * Return the version of JTS this GEOS |
103 | | * release has been ported from. |
104 | | */ |
105 | | std::string |
106 | | jtsport() |
107 | 0 | { |
108 | 0 | return GEOS_JTS_PORT; |
109 | 0 | } |
110 | | |
111 | | Geometry::GeometryChangedFilter Geometry::geometryChangedFilter; |
112 | | |
113 | | Geometry::Geometry(const GeometryFactory* newFactory) |
114 | | : |
115 | 22.7M | _factory(newFactory), |
116 | 22.7M | _userData(nullptr) |
117 | 22.7M | { |
118 | 22.7M | if(_factory == nullptr) { |
119 | 0 | _factory = GeometryFactory::getDefaultInstance(); |
120 | 0 | } |
121 | 22.7M | SRID = _factory->getSRID(); |
122 | 22.7M | _factory->addRef(); |
123 | 22.7M | } |
124 | | |
125 | | Geometry::Geometry(const Geometry& geom) |
126 | | : |
127 | 35.5M | SRID(geom.getSRID()), |
128 | 35.5M | _factory(geom._factory), |
129 | 35.5M | _userData(nullptr) |
130 | 35.5M | { |
131 | 35.5M | _factory->addRef(); |
132 | 35.5M | } |
133 | | |
134 | | bool |
135 | | Geometry::hasNullElements(const CoordinateSequence* list) |
136 | 0 | { |
137 | 0 | std::size_t npts = list->getSize(); |
138 | 0 | for(std::size_t i = 0; i < npts; ++i) { |
139 | 0 | if(list->getAt(i).isNull()) { |
140 | 0 | return true; |
141 | 0 | } |
142 | 0 | } |
143 | 0 | return false; |
144 | 0 | } |
145 | | |
146 | | /* public */ |
147 | | bool |
148 | | Geometry::isWithinDistance(const Geometry* geom, double cDistance) const |
149 | 0 | { |
150 | 0 | return DistanceOp::isWithinDistance(*this, *geom, cDistance); |
151 | 0 | } |
152 | | |
153 | | /*public*/ |
154 | | std::unique_ptr<Point> |
155 | | Geometry::getCentroid() const |
156 | 0 | { |
157 | 0 | Coordinate centPt; |
158 | 0 | if(! getCentroid(centPt)) { |
159 | 0 | return getFactory()->createPoint(getCoordinateDimension()); |
160 | 0 | } |
161 | | |
162 | | // We don't use createPointFromInternalCoord here |
163 | | // because ::getCentroid() takes care about rounding |
164 | 0 | return std::unique_ptr<Point>(getFactory()->createPoint(centPt)); |
165 | 0 | } |
166 | | |
167 | | /* public */ |
168 | | bool |
169 | | Geometry::isMixedDimension() const |
170 | 47.9k | { |
171 | 47.9k | Dimension::DimensionType baseDim = Dimension::DONTCARE; |
172 | 47.9k | return isMixedDimension(&baseDim); |
173 | 47.9k | } |
174 | | |
175 | | /* public */ |
176 | | bool |
177 | | Geometry::isMixedDimension(Dimension::DimensionType* baseDim) const |
178 | 15.8M | { |
179 | 15.8M | if (isCollection()) { |
180 | 15.8M | for (std::size_t i = 0; i < getNumGeometries(); i++) { |
181 | 15.7M | if (getGeometryN(i)->isMixedDimension(baseDim)) |
182 | 10.5k | return true; |
183 | 15.7M | } |
184 | 68.3k | return false; |
185 | 78.8k | } |
186 | 15.7M | else { |
187 | 15.7M | if (*baseDim == Dimension::DONTCARE) { |
188 | 46.8k | *baseDim = getDimension(); |
189 | 46.8k | return false; |
190 | 46.8k | } |
191 | 15.6M | return *baseDim != getDimension(); |
192 | 15.7M | } |
193 | 15.8M | } |
194 | | |
195 | | /*public*/ |
196 | | bool |
197 | | Geometry::getCentroid(CoordinateXY& ret) const |
198 | 0 | { |
199 | 0 | if(isEmpty()) { |
200 | 0 | return false; |
201 | 0 | } |
202 | 0 | if(! Centroid::getCentroid(*this, ret)) { |
203 | 0 | return false; |
204 | 0 | } |
205 | 0 | getPrecisionModel()->makePrecise(ret); // not in JTS |
206 | 0 | return true; |
207 | 0 | } |
208 | | |
209 | | std::unique_ptr<Point> |
210 | | Geometry::getInteriorPoint() const |
211 | 0 | { |
212 | 0 | geos::util::ensureNoCurvedComponents(this); |
213 | |
|
214 | 0 | Coordinate interiorPt; |
215 | 0 | int dim = getDimension(); |
216 | 0 | if(dim == 0) { |
217 | 0 | InteriorPointPoint intPt(this); |
218 | 0 | if(! intPt.getInteriorPoint(interiorPt)) { |
219 | 0 | return getFactory()->createPoint(getCoordinateDimension()); // POINT EMPTY |
220 | 0 | } |
221 | 0 | } |
222 | 0 | else if(dim == 1) { |
223 | 0 | InteriorPointLine intPt(this); |
224 | 0 | if(! intPt.getInteriorPoint(interiorPt)) { |
225 | 0 | return getFactory()->createPoint(getCoordinateDimension()); // POINT EMPTY |
226 | 0 | } |
227 | 0 | } |
228 | 0 | else { |
229 | 0 | InteriorPointArea intPt(this); |
230 | 0 | if(! intPt.getInteriorPoint(interiorPt)) { |
231 | 0 | return getFactory()->createPoint(getCoordinateDimension()); // POINT EMPTY |
232 | 0 | } |
233 | 0 | } |
234 | 0 | std::unique_ptr<Point> p(getFactory()->createPointFromInternalCoord(&interiorPt, this)); |
235 | 0 | return p; |
236 | 0 | } |
237 | | |
238 | | /** |
239 | | * Notifies this Geometry that its Coordinates have been changed by an external |
240 | | * party (using a CoordinateFilter, for example). The Geometry will flush |
241 | | * and/or update any information it has cached (such as its {@link Envelope} ). |
242 | | */ |
243 | | void |
244 | | Geometry::geometryChanged() |
245 | 37.9k | { |
246 | 37.9k | apply_rw(&geometryChangedFilter); |
247 | 37.9k | } |
248 | | |
249 | | bool |
250 | | Geometry::isValid() const |
251 | 0 | { |
252 | 0 | return IsValidOp(this).isValid(); |
253 | 0 | } |
254 | | |
255 | | std::unique_ptr<Geometry> |
256 | | Geometry::getEnvelope() const |
257 | 0 | { |
258 | 0 | return std::unique_ptr<Geometry>(getFactory()->toGeometry(getEnvelopeInternal())); |
259 | 0 | } |
260 | | |
261 | | bool |
262 | | Geometry::disjoint(const Geometry* g) const |
263 | 0 | { |
264 | 0 | #if USE_RELATENG |
265 | 0 | return operation::relateng::RelateNG::disjoint(this, g); |
266 | | #else |
267 | | return !intersects(g); |
268 | | #endif |
269 | 0 | } |
270 | | |
271 | | bool |
272 | | Geometry::touches(const Geometry* g) const |
273 | 0 | { |
274 | 0 | #ifdef SHORTCIRCUIT_PREDICATES |
275 | | // short-circuit test |
276 | 0 | if(! getEnvelopeInternal()->intersects(g->getEnvelopeInternal())) { |
277 | 0 | return false; |
278 | 0 | } |
279 | 0 | #endif |
280 | | |
281 | 0 | #if USE_RELATENG |
282 | 0 | return operation::relateng::RelateNG::touches(this, g); |
283 | | #else |
284 | | std::unique_ptr<IntersectionMatrix> im(relate(g)); |
285 | | bool res = im->isTouches(getDimension(), g->getDimension()); |
286 | | return res; |
287 | | #endif |
288 | 0 | } |
289 | | |
290 | | bool |
291 | | Geometry::intersects(const Geometry* g) const |
292 | 0 | { |
293 | 0 | #ifdef SHORTCIRCUIT_PREDICATES |
294 | | // short-circuit test |
295 | 0 | if(! getEnvelopeInternal()->intersects(g->getEnvelopeInternal())) { |
296 | 0 | return false; |
297 | 0 | } |
298 | 0 | #endif |
299 | | |
300 | | /* |
301 | | * TODO: (MD) Add optimizations: |
302 | | * |
303 | | * - for P-A case: |
304 | | * If P is in env(A), test for point-in-poly |
305 | | * |
306 | | * - for A-A case: |
307 | | * If env(A1).overlaps(env(A2)) |
308 | | * test for overlaps via point-in-poly first (both ways) |
309 | | * Possibly optimize selection of point to test by finding point of A1 |
310 | | * closest to centre of env(A2). |
311 | | * (Is there a test where we shouldn't bother - e.g. if env A |
312 | | * is much smaller than env B, maybe there's no point in testing |
313 | | * pt(B) in env(A)? |
314 | | */ |
315 | | |
316 | | // optimization for rectangle arguments |
317 | 0 | if(isRectangle()) { |
318 | 0 | const Polygon* p = detail::down_cast<const Polygon*>(this); |
319 | 0 | return predicate::RectangleIntersects::intersects(*p, *g); |
320 | 0 | } |
321 | 0 | if(g->isRectangle()) { |
322 | 0 | const Polygon* p = detail::down_cast<const Polygon*>(g); |
323 | 0 | return predicate::RectangleIntersects::intersects(*p, *this); |
324 | 0 | } |
325 | | |
326 | 0 | auto typ = getGeometryTypeId(); |
327 | 0 | if (typ == GEOS_CURVEPOLYGON && g->getGeometryTypeId() == GEOS_POINT) { |
328 | 0 | auto loc = locate::SimplePointInAreaLocator::locatePointInSurface(*g->getCoordinate(), *detail::down_cast<const Surface*>(this)); |
329 | 0 | return loc != Location::EXTERIOR; |
330 | 0 | } else if (typ == GEOS_POINT && g->getGeometryTypeId() == GEOS_CURVEPOLYGON) { |
331 | 0 | auto loc = locate::SimplePointInAreaLocator::locatePointInSurface(*getCoordinate(), *detail::down_cast<const Surface*>(g)); |
332 | 0 | return loc != Location::EXTERIOR; |
333 | 0 | } |
334 | | |
335 | 0 | #if USE_RELATENG |
336 | 0 | return operation::relateng::RelateNG::intersects(this, g); |
337 | | #else |
338 | | if (typ == GEOS_GEOMETRYCOLLECTION) { |
339 | | auto im = relate(g); |
340 | | bool res = im->isIntersects(); |
341 | | return res; |
342 | | } else { |
343 | | return prep::PreparedGeometryFactory::prepare(this)->intersects(g); |
344 | | } |
345 | | #endif |
346 | 0 | } |
347 | | |
348 | | /*public*/ |
349 | | bool |
350 | | Geometry::covers(const Geometry* g) const |
351 | 0 | { |
352 | 0 | #if USE_RELATENG |
353 | 0 | return operation::relateng::RelateNG::covers(this, g); |
354 | | #else |
355 | | // optimization - lower dimension cannot cover areas |
356 | | if(g->getDimension() == 2 && getDimension() < 2) { |
357 | | return false; |
358 | | } |
359 | | |
360 | | // optimization - P cannot cover a non-zero-length L |
361 | | // Note that a point can cover a zero-length lineal geometry |
362 | | if(g->getDimension() == 1 && getDimension() < 1 && g->getLength() > 0.0) { |
363 | | return false; |
364 | | } |
365 | | |
366 | | #ifdef SHORTCIRCUIT_PREDICATES |
367 | | // short-circuit test |
368 | | if(! getEnvelopeInternal()->covers(g->getEnvelopeInternal())) { |
369 | | return false; |
370 | | } |
371 | | #endif |
372 | | |
373 | | // optimization for rectangle arguments |
374 | | if(isRectangle()) { |
375 | | // since we have already tested that the test envelope |
376 | | // is covered |
377 | | return true; |
378 | | } |
379 | | |
380 | | std::unique_ptr<IntersectionMatrix> im(relate(g)); |
381 | | return im->isCovers(); |
382 | | #endif |
383 | 0 | } |
384 | | |
385 | | /*public*/ |
386 | | bool |
387 | | Geometry::coveredBy(const Geometry* g) const |
388 | 0 | { |
389 | 0 | #if USE_RELATENG |
390 | 0 | return operation::relateng::RelateNG::coveredBy(this, g); |
391 | | #else |
392 | | return covers(g, this); |
393 | | #endif |
394 | 0 | } |
395 | | |
396 | | bool |
397 | | Geometry::crosses(const Geometry* g) const |
398 | 0 | { |
399 | 0 | #if USE_RELATENG |
400 | 0 | return operation::relateng::RelateNG::crosses(this, g); |
401 | | #else |
402 | | |
403 | | #ifdef SHORTCIRCUIT_PREDICATES |
404 | | // short-circuit test |
405 | | if(! getEnvelopeInternal()->intersects(g->getEnvelopeInternal())) { |
406 | | return false; |
407 | | } |
408 | | #endif |
409 | | std::unique_ptr<IntersectionMatrix> im(relate(g)); |
410 | | bool res = im->isCrosses(getDimension(), g->getDimension()); |
411 | | return res; |
412 | | |
413 | | #endif |
414 | 0 | } |
415 | | |
416 | | bool |
417 | | Geometry::within(const Geometry* g) const |
418 | 0 | { |
419 | 0 | #if USE_RELATENG |
420 | 0 | return operation::relateng::RelateNG::within(this, g); |
421 | | #else |
422 | | return g->contains(this); |
423 | | #endif |
424 | 0 | } |
425 | | |
426 | | bool |
427 | | Geometry::contains(const Geometry* g) const |
428 | 0 | { |
429 | 0 | #if USE_RELATENG |
430 | 0 | return operation::relateng::RelateNG::contains(this, g); |
431 | | #else |
432 | | |
433 | | // optimization - lower dimension cannot contain areas |
434 | | if(g->getDimension() == 2 && getDimension() < 2) { |
435 | | return false; |
436 | | } |
437 | | |
438 | | // optimization - P cannot contain a non-zero-length L |
439 | | // Note that a point can contain a zero-length lineal geometry, |
440 | | // since the line has no boundary due to Mod-2 Boundary Rule |
441 | | if(g->getDimension() == 1 && getDimension() < 1 && g->getLength() > 0.0) { |
442 | | return false; |
443 | | } |
444 | | |
445 | | #ifdef SHORTCIRCUIT_PREDICATES |
446 | | // short-circuit test |
447 | | if(! getEnvelopeInternal()->contains(g->getEnvelopeInternal())) { |
448 | | return false; |
449 | | } |
450 | | #endif |
451 | | |
452 | | // optimization for rectangle arguments |
453 | | if(isRectangle()) { |
454 | | const Polygon* p = detail::down_cast<const Polygon*>(this); |
455 | | return predicate::RectangleContains::contains(*p, *g); |
456 | | } |
457 | | // Incorrect: contains is not commutative |
458 | | //if (g->isRectangle()) { |
459 | | // return predicate::RectangleContains::contains((const Polygon&)*g, *this); |
460 | | //} |
461 | | |
462 | | std::unique_ptr<IntersectionMatrix> im(relate(g)); |
463 | | bool res = im->isContains(); |
464 | | return res; |
465 | | #endif |
466 | 0 | } |
467 | | |
468 | | bool |
469 | | Geometry::overlaps(const Geometry* g) const |
470 | 0 | { |
471 | 0 | #if USE_RELATENG |
472 | 0 | return operation::relateng::RelateNG::overlaps(this, g); |
473 | | #else |
474 | | |
475 | | #ifdef SHORTCIRCUIT_PREDICATES |
476 | | // short-circuit test |
477 | | if(! getEnvelopeInternal()->intersects(g->getEnvelopeInternal())) { |
478 | | return false; |
479 | | } |
480 | | #endif |
481 | | std::unique_ptr<IntersectionMatrix> im(relate(g)); |
482 | | bool res = im->isOverlaps(getDimension(), g->getDimension()); |
483 | | return res; |
484 | | |
485 | | #endif |
486 | 0 | } |
487 | | |
488 | | bool |
489 | | Geometry::relate(const Geometry* g, const std::string& intersectionPattern) const |
490 | 0 | { |
491 | 0 | #if USE_RELATENG |
492 | 0 | return operation::relateng::RelateNG::relate(this, g, intersectionPattern); |
493 | | #else |
494 | | std::unique_ptr<IntersectionMatrix> im(relate(g)); |
495 | | bool res = im->matches(intersectionPattern); |
496 | | return res; |
497 | | #endif |
498 | 0 | } |
499 | | |
500 | | bool |
501 | | Geometry::equals(const Geometry* g) const |
502 | 0 | { |
503 | 0 | #if USE_RELATENG |
504 | 0 | return operation::relateng::RelateNG::equalsTopo(this, g); |
505 | | #else |
506 | | |
507 | | #ifdef SHORTCIRCUIT_PREDICATES |
508 | | // short-circuit test |
509 | | if(! getEnvelopeInternal()->equals(g->getEnvelopeInternal())) { |
510 | | return false; |
511 | | } |
512 | | #endif |
513 | | |
514 | | if(isEmpty()) { |
515 | | return g->isEmpty(); |
516 | | } |
517 | | else if(g->isEmpty()) { |
518 | | return isEmpty(); |
519 | | } |
520 | | |
521 | | std::unique_ptr<IntersectionMatrix> im(relate(g)); |
522 | | bool res = im->isEquals(getDimension(), g->getDimension()); |
523 | | return res; |
524 | | #endif |
525 | 0 | } |
526 | | |
527 | | std::unique_ptr<IntersectionMatrix> |
528 | | Geometry::relate(const Geometry* other) const |
529 | 0 | { |
530 | 0 | #if USE_RELATENG |
531 | 0 | return operation::relateng::RelateNG::relate(this, other); |
532 | | #else |
533 | | return RelateOp::relate(this, other); |
534 | | #endif |
535 | 0 | } |
536 | | |
537 | | std::unique_ptr<IntersectionMatrix> |
538 | | Geometry::relate(const Geometry& other) const |
539 | 0 | { |
540 | 0 | return relate(&other); |
541 | 0 | } |
542 | | |
543 | | std::string |
544 | | Geometry::toString() const |
545 | 0 | { |
546 | 0 | return toText(); |
547 | 0 | } |
548 | | |
549 | | std::ostream& |
550 | | operator<< (std::ostream& os, const Geometry& geom) |
551 | 0 | { |
552 | 0 | io::WKBWriter writer; |
553 | 0 | writer.writeHEX(geom, os); |
554 | 0 | return os; |
555 | 0 | } |
556 | | |
557 | | std::string |
558 | | Geometry::toText() const |
559 | 0 | { |
560 | 0 | io::WKTWriter writer; |
561 | | // To enable "GEOS<3.12" outputs, uncomment the following: |
562 | | // writer.setTrim(false); |
563 | | // writer.setOutputDimension(2); |
564 | 0 | return writer.write(this); |
565 | 0 | } |
566 | | |
567 | | std::unique_ptr<Geometry> |
568 | | Geometry::buffer(double p_distance) const |
569 | 0 | { |
570 | 0 | return std::unique_ptr<Geometry>(BufferOp::bufferOp(this, p_distance)); |
571 | 0 | } |
572 | | |
573 | | std::unique_ptr<Geometry> |
574 | | Geometry::buffer(double p_distance, int quadrantSegments) const |
575 | 0 | { |
576 | 0 | return std::unique_ptr<Geometry>(BufferOp::bufferOp(this, p_distance, quadrantSegments)); |
577 | 0 | } |
578 | | |
579 | | std::unique_ptr<Geometry> |
580 | | Geometry::buffer(double p_distance, int quadrantSegments, int endCapStyle) const |
581 | 0 | { |
582 | 0 | return std::unique_ptr<Geometry>(BufferOp::bufferOp(this, p_distance, quadrantSegments, endCapStyle)); |
583 | 0 | } |
584 | | |
585 | | std::unique_ptr<Geometry> |
586 | | Geometry::convexHull() const |
587 | 0 | { |
588 | 0 | return ConvexHull(this).getConvexHull(); |
589 | 0 | } |
590 | | |
591 | | std::unique_ptr<Geometry> |
592 | | Geometry::intersection(const Geometry* other) const |
593 | 8.41k | { |
594 | | /* |
595 | | * TODO: MD - add optimization for P-A case using Point-In-Polygon |
596 | | */ |
597 | | |
598 | | #ifdef USE_RECTANGLE_INTERSECTION |
599 | | // optimization for rectangle arguments |
600 | | using operation::intersection::Rectangle; |
601 | | using operation::intersection::RectangleIntersection; |
602 | | if(isRectangle()) { |
603 | | const Envelope* env = getEnvelopeInternal(); |
604 | | Rectangle rect(env->getMinX(), env->getMinY(), |
605 | | env->getMaxX(), env->getMaxY()); |
606 | | return RectangleIntersection::clip(*other, rect).release(); |
607 | | } |
608 | | if(other->isRectangle()) { |
609 | | const Envelope* env = other->getEnvelopeInternal(); |
610 | | Rectangle rect(env->getMinX(), env->getMinY(), |
611 | | env->getMaxX(), env->getMaxY()); |
612 | | return RectangleIntersection::clip(*this, rect).release(); |
613 | | } |
614 | | #endif |
615 | | |
616 | 8.41k | return HeuristicOverlay(this, other, OverlayNG::INTERSECTION); |
617 | 8.41k | } |
618 | | |
619 | | std::unique_ptr<Geometry> |
620 | | Geometry::Union(const Geometry* other) const |
621 | 8.41k | { |
622 | 8.41k | return HeuristicOverlay(this, other, OverlayNG::UNION); |
623 | 8.41k | } |
624 | | |
625 | | /* public */ |
626 | | Geometry::Ptr |
627 | | Geometry::Union() const |
628 | 0 | { |
629 | 0 | using geos::operation::geounion::UnaryUnionOp; |
630 | 0 | return UnaryUnionOp::Union(*this); |
631 | 0 | } |
632 | | |
633 | | std::unique_ptr<Geometry> |
634 | | Geometry::difference(const Geometry* other) const |
635 | 8.41k | { |
636 | 8.41k | return HeuristicOverlay(this, other, OverlayNG::DIFFERENCE); |
637 | 8.41k | } |
638 | | |
639 | | std::unique_ptr<Geometry> |
640 | | Geometry::symDifference(const Geometry* other) const |
641 | 0 | { |
642 | 0 | return HeuristicOverlay(this, other, OverlayNG::SYMDIFFERENCE); |
643 | 0 | } |
644 | | |
645 | | int |
646 | | Geometry::compareTo(const Geometry* geom) const |
647 | 0 | { |
648 | | // compare to self |
649 | 0 | if(this == geom) { |
650 | 0 | return 0; |
651 | 0 | } |
652 | | |
653 | 0 | if(getSortIndex() != geom->getSortIndex()) { |
654 | 0 | int diff = getSortIndex() - geom->getSortIndex(); |
655 | 0 | return (diff > 0) - (diff < 0); // signum() |
656 | 0 | } |
657 | 0 | if(isEmpty() && geom->isEmpty()) { |
658 | 0 | return 0; |
659 | 0 | } |
660 | 0 | if(isEmpty()) { |
661 | 0 | return -1; |
662 | 0 | } |
663 | 0 | if(geom->isEmpty()) { |
664 | 0 | return 1; |
665 | 0 | } |
666 | 0 | return compareToSameClass(geom); |
667 | 0 | } |
668 | | |
669 | | bool |
670 | | Geometry::isEquivalentClass(const Geometry* other) const |
671 | 0 | { |
672 | 0 | if(typeid(*this) == typeid(*other)) { |
673 | 0 | return true; |
674 | 0 | } |
675 | 0 | else { |
676 | 0 | return false; |
677 | 0 | } |
678 | 0 | } |
679 | | |
680 | | /*public static*/ |
681 | | void |
682 | | Geometry::checkNotGeometryCollection(const Geometry* g) |
683 | | //throw(IllegalArgumentException *) |
684 | 0 | { |
685 | 0 | if(g->getSortIndex() == SORTINDEX_GEOMETRYCOLLECTION) { |
686 | 0 | throw geos::util::IllegalArgumentException("This method does not support GeometryCollection arguments\n"); |
687 | 0 | } |
688 | 0 | } |
689 | | |
690 | | |
691 | | void |
692 | | Geometry::GeometryChangedFilter::filter_rw(Geometry* geom) |
693 | 37.9k | { |
694 | 37.9k | geom->geometryChangedAction(); |
695 | 37.9k | } |
696 | | |
697 | | |
698 | | /** |
699 | | * Returns the minimum distance between this Geometry |
700 | | * and the other Geometry |
701 | | * |
702 | | * @param other the Geometry from which to compute the distance |
703 | | */ |
704 | | double |
705 | | Geometry::distance(const Geometry* other) const |
706 | 0 | { |
707 | 0 | return DistanceOp::distance(this, other); |
708 | 0 | } |
709 | | |
710 | | /** |
711 | | * Returns the area of this <code>Geometry</code>. |
712 | | * Areal Geometries have a non-zero area. |
713 | | * They override this function to compute the area. |
714 | | * Others return 0.0 |
715 | | * |
716 | | * @return the area of the Geometry |
717 | | */ |
718 | | double |
719 | | Geometry::getArea() const |
720 | 5.29M | { |
721 | 5.29M | return 0.0; |
722 | 5.29M | } |
723 | | |
724 | | /** |
725 | | * Returns the length of this <code>Geometry</code>. |
726 | | * Linear geometries return their length. |
727 | | * Areal geometries return their perimeter. |
728 | | * They override this function to compute the area. |
729 | | * Others return 0.0 |
730 | | * |
731 | | * @return the length of the Geometry |
732 | | */ |
733 | | double |
734 | | Geometry::getLength() const |
735 | 0 | { |
736 | 0 | return 0.0; |
737 | 0 | } |
738 | | |
739 | | Geometry::~Geometry() |
740 | 58.3M | { |
741 | 58.3M | _factory->dropRef(); |
742 | 58.3M | } |
743 | | |
744 | | bool |
745 | | GeometryGreaterThen::operator()(const Geometry* first, const Geometry* second) |
746 | 0 | { |
747 | 0 | if(first->compareTo(second) > 0) { |
748 | 0 | return true; |
749 | 0 | } |
750 | 0 | else { |
751 | 0 | return false; |
752 | 0 | } |
753 | 0 | } |
754 | | |
755 | | bool |
756 | | Geometry::equal(const CoordinateXY& a, const CoordinateXY& b, |
757 | | double tolerance) const |
758 | 0 | { |
759 | 0 | if(tolerance == 0) { |
760 | 0 | return a == b; // 2D only !!! |
761 | 0 | } |
762 | | //double dist=a.distance(b); |
763 | 0 | return a.distance(b) <= tolerance; |
764 | 0 | } |
765 | | |
766 | | void |
767 | | Geometry::apply_ro(GeometryFilter* filter) const |
768 | 0 | { |
769 | 0 | filter->filter_ro(this); |
770 | 0 | } |
771 | | |
772 | | void |
773 | | Geometry::apply_rw(GeometryFilter* filter) |
774 | 0 | { |
775 | 0 | filter->filter_rw(this); |
776 | 0 | } |
777 | | |
778 | | void |
779 | | Geometry::apply_ro(GeometryComponentFilter* filter) const |
780 | 0 | { |
781 | 0 | filter->filter_ro(this); |
782 | 0 | } |
783 | | |
784 | | void |
785 | | Geometry::apply_rw(GeometryComponentFilter* filter) |
786 | 0 | { |
787 | 0 | filter->filter_rw(this); |
788 | 0 | } |
789 | | |
790 | | bool |
791 | | Geometry::isSimple() const |
792 | 0 | { |
793 | 0 | operation::valid::IsSimpleOp op(*this); |
794 | 0 | return op.isSimple(); |
795 | 0 | } |
796 | | |
797 | | /* public */ |
798 | | const PrecisionModel* |
799 | | Geometry::getPrecisionModel() const |
800 | 247k | { |
801 | 247k | return _factory->getPrecisionModel(); |
802 | 247k | } |
803 | | |
804 | | bool |
805 | 26.5M | Geometry::hasCurvedComponents() const { |
806 | 26.5M | return false; |
807 | 26.5M | } |
808 | | |
809 | | } // namespace geos::geom |
810 | | } // namespace geos |
811 | | |
812 | | |