49 #ifndef GEOS_GEOM_BINARYOP_H
50 #define GEOS_GEOM_BINARYOP_H
52 #include <geos/algorithm/BoundaryNodeRule.h>
53 #include <geos/geom/Geometry.h>
54 #include <geos/geom/GeometryCollection.h>
55 #include <geos/geom/Polygon.h>
56 #include <geos/geom/PrecisionModel.h>
57 #include <geos/geom/GeometryFactory.h>
58 #include <geos/precision/CommonBitsRemover.h>
59 #include <geos/precision/SimpleGeometryPrecisionReducer.h>
60 #include <geos/precision/GeometryPrecisionReducer.h>
62 #include <geos/operation/overlay/snap/GeometrySnapper.h>
64 #include <geos/simplify/TopologyPreservingSimplifier.h>
65 #include <geos/operation/IsSimpleOp.h>
66 #include <geos/operation/valid/IsValidOp.h>
67 #include <geos/operation/valid/TopologyValidationError.h>
68 #include <geos/util/TopologyException.h>
69 #include <geos/util.h>
74 #define GEOS_DEBUG_BINARYOP_PRINT_INVALID 1
76 #ifdef GEOS_DEBUG_BINARYOP
86 #ifndef USE_ORIGINAL_INPUT
87 # define USE_ORIGINAL_INPUT 1
93 #define GEOS_CHECK_ORIGINAL_RESULT_VALIDITY 0
101 #ifndef USE_PRECISION_REDUCTION_POLICY
102 # define USE_PRECISION_REDUCTION_POLICY 1
114 #define GEOS_CHECK_PRECISION_REDUCTION_VALIDITY 0
121 #ifndef USE_TP_SIMPLIFY_POLICY
130 #ifndef USE_COMMONBITS_POLICY
131 # define USE_COMMONBITS_POLICY 1
145 #define GEOS_CHECK_COMMONBITS_VALIDITY 1
150 #ifndef USE_SNAPPING_POLICY
151 # define USE_SNAPPING_POLICY 1
155 #ifndef CBR_BEFORE_SNAPPING
156 # define CBR_BEFORE_SNAPPING 1
163 #define GEOS_CHECK_SNAPPINGOP_VALIDITY 0
170 check_valid(
const Geometry& g,
const std::string& label,
bool doThrow =
false,
bool validOnly =
false)
175 if(! sop.isSimple()) {
178 label +
" is not simple");
185 operation::valid::IsValidOp ivo(&g);
186 if(! ivo.isValid()) {
187 using operation::valid::TopologyValidationError;
188 TopologyValidationError* err = ivo.getValidationError();
189 #ifdef GEOS_DEBUG_BINARYOP
190 std::cerr << label <<
" is INVALID: "
192 <<
" (" << std::setprecision(20)
193 << err->getCoordinate() <<
")"
195 #ifdef GEOS_DEBUG_BINARYOP_PRINT_INVALID
196 <<
"<A>" << std::endl
199 <<
"</A>" << std::endl
205 label +
" is invalid: " + err->toString(),
206 err->getCoordinate());
220 inline std::unique_ptr<Geometry>
221 fix_self_intersections(std::unique_ptr<Geometry> g,
const std::string& label)
223 ::geos::ignore_unused_variable_warning(label);
224 #ifdef GEOS_DEBUG_BINARYOP
225 std::cerr << label <<
" fix_self_intersection (UnaryUnion)" << std::endl;
229 if(! dynamic_cast<const GeometryCollection*>(g.get())) {
233 using operation::valid::IsValidOp;
235 IsValidOp ivo(g.get());
244 using operation::valid::TopologyValidationError;
245 TopologyValidationError* err = ivo.getValidationError();
246 switch(err->getErrorType()) {
247 case TopologyValidationError::eRingSelfIntersection:
248 case TopologyValidationError::eTooFewPoints:
249 #ifdef GEOS_DEBUG_BINARYOP
250 std::cerr << label <<
" ATTEMPT_TO_FIX: " << err->getErrorType() <<
": " << *g << std::endl;
253 #ifdef GEOS_DEBUG_BINARYOP
254 std::cerr << label <<
" ATTEMPT_TO_FIX succeeded.. " << std::endl;
257 case TopologyValidationError::eSelfIntersection:
260 #ifdef GEOS_DEBUG_BINARYOP
261 std::cerr << label <<
" invalidity is: " << err->getErrorType() << std::endl;
273 template <
class BinOp>
274 std::unique_ptr<Geometry>
277 typedef std::unique_ptr<Geometry> GeomPtr;
284 double snapTolerance = GeometrySnapper::computeOverlaySnapTolerance(*g0, *g1);
285 #if GEOS_DEBUG_BINARYOP
286 std::cerr << std::setprecision(20) <<
"Computed snap tolerance: " << snapTolerance << std::endl;
290 #if CBR_BEFORE_SNAPPING
295 #if GEOS_DEBUG_BINARYOP
300 GeomPtr rG0 = g0->
clone();
302 GeomPtr rG1 = g1->
clone();
305 #if GEOS_DEBUG_BINARYOP
306 check_valid(*rG0,
"CBR: removed-bits geom 0");
307 check_valid(*rG1,
"CBR: removed-bits geom 1");
312 #else // don't CBR before snapping
318 GeometrySnapper snapper0(operand0);
319 GeomPtr snapG0(snapper0.snapTo(operand1, snapTolerance));
323 GeometrySnapper snapper1(operand1);
324 GeomPtr snapG1(snapper1.snapTo(*snapG0, snapTolerance));
328 GeomPtr result(_Op(snapG0.get(), snapG1.get()));
330 #if GEOS_DEBUG_BINARYOP
331 check_valid(*result,
"SNAP: result (before common-bits addition");
334 #if CBR_BEFORE_SNAPPING
339 check_valid(*result,
"CBR: result (after common-bits addition)",
true);
346 template <
class BinOp>
347 std::unique_ptr<Geometry>
348 BinaryOp(
const Geometry* g0,
const Geometry* g1, BinOp _Op)
350 typedef std::unique_ptr<Geometry> GeomPtr;
355 #ifdef USE_ORIGINAL_INPUT
358 #if GEOS_DEBUG_BINARYOP
359 std::cerr <<
"Trying with original input." << std::endl;
361 ret.reset(_Op(g0, g1));
363 #if GEOS_CHECK_ORIGINAL_RESULT_VALIDITY
364 check_valid(*ret,
"Overlay result between original inputs",
true,
true);
367 #if GEOS_DEBUG_BINARYOP
368 std::cerr <<
"Attempt with original input succeeded" << std::endl;
374 #if GEOS_DEBUG_BINARYOP
375 std::cerr <<
"Original exception: " << ex.what() << std::endl;
378 #endif // USE_ORIGINAL_INPUT
380 check_valid(*g0,
"Input geom 0",
true,
true);
381 check_valid(*g1,
"Input geom 1",
true,
true);
383 #if USE_COMMONBITS_POLICY
394 precision::CommonBitsRemover cbr;
396 #if GEOS_DEBUG_BINARYOP
397 std::cerr <<
"Trying with Common Bits Remover (CBR)" << std::endl;
404 cbr.removeCommonBits(rG0.get());
407 cbr.removeCommonBits(rG1.get());
409 #if GEOS_DEBUG_BINARYOP
410 check_valid(*rG0,
"CBR: geom 0 (after common-bits removal)");
411 check_valid(*rG1,
"CBR: geom 1 (after common-bits removal)");
414 ret.reset(_Op(rG0.get(), rG1.get()));
416 #if GEOS_DEBUG_BINARYOP
417 check_valid(*ret,
"CBR: result (before common-bits addition)");
420 cbr.addCommonBits(ret.get());
422 #if GEOS_CHECK_COMMONBITS_VALIDITY
423 check_valid(*ret,
"CBR: result (after common-bits addition)",
true);
426 #if GEOS_DEBUG_BINARYOP
427 std::cerr <<
"Attempt with CBR succeeded" << std::endl;
433 ::geos::ignore_unused_variable_warning(ex);
434 #if GEOS_DEBUG_BINARYOP
435 std::cerr <<
"CBR: " << ex.what() << std::endl;
447 #if USE_SNAPPING_POLICY
449 #if GEOS_DEBUG_BINARYOP
450 std::cerr <<
"Trying with snapping " << std::endl;
454 ret =
SnapOp(g0, g1, _Op);
455 #if GEOS_CHECK_SNAPPINGOP_VALIDITY
456 check_valid(*ret,
"SNAP: result",
true,
true);
458 #if GEOS_DEBUG_BINARYOP
459 std::cerr <<
"SnapOp succeeded" << std::endl;
465 ::geos::ignore_unused_variable_warning(ex);
466 #if GEOS_DEBUG_BINARYOP
467 std::cerr <<
"SNAP: " << ex.what() << std::endl;
471 #endif // USE_SNAPPING_POLICY }
474 #if USE_PRECISION_REDUCTION_POLICY
479 long unsigned int g0scale =
480 static_cast<long unsigned int>(g0->getFactory()->getPrecisionModel()->getScale());
481 long unsigned int g1scale =
482 static_cast<long unsigned int>(g1->getFactory()->getPrecisionModel()->getScale());
484 #if GEOS_DEBUG_BINARYOP
485 std::cerr <<
"Original input scales are: "
492 double maxScale = 1e16;
495 if(g0scale && static_cast<double>(g0scale) < maxScale) {
496 maxScale =
static_cast<double>(g0scale);
498 if(g1scale && static_cast<double>(g1scale) < maxScale) {
499 maxScale =
static_cast<double>(g1scale);
503 for(
double scale = maxScale; scale >= 1; scale /= 10) {
504 PrecisionModel pm(scale);
506 #if GEOS_DEBUG_BINARYOP
507 std::cerr <<
"Trying with scale " << scale << std::endl;
510 precision::GeometryPrecisionReducer reducer(*gf);
511 GeomPtr rG0(reducer.reduce(*g0));
512 GeomPtr rG1(reducer.reduce(*g1));
514 #if GEOS_DEBUG_BINARYOP
515 check_valid(*rG0,
"PR: geom 0 (after precision reduction)");
516 check_valid(*rG1,
"PR: geom 1 (after precision reduction)");
520 ret.reset(_Op(rG0.get(), rG1.get()));
522 if(g0->getFactory()->getPrecisionModel()->compareTo(g1->getFactory()->getPrecisionModel()) < 0) {
523 ret.reset(g0->getFactory()->createGeometry(ret.get()));
526 ret.reset(g1->getFactory()->createGeometry(ret.get()));
529 #if GEOS_CHECK_PRECISION_REDUCTION_VALIDITY
530 check_valid(*ret,
"PR: result (after restore of original precision)",
true);
533 #if GEOS_DEBUG_BINARYOP
534 std::cerr <<
"Attempt with scale " << scale <<
" succeeded" << std::endl;
539 #if GEOS_DEBUG_BINARYOP
540 std::cerr <<
"Reduced with scale (" << scale <<
"): "
541 << ex.what() << std::endl;
552 #if GEOS_DEBUG_BINARYOP
553 std::cerr <<
"Reduced: " << ex.what() << std::endl;
555 ::geos::ignore_unused_variable_warning(ex);
566 #if USE_TP_SIMPLIFY_POLICY
571 double maxTolerance = 0.04;
572 double minTolerance = 0.01;
573 double tolStep = 0.01;
575 for(
double tol = minTolerance; tol <= maxTolerance; tol += tolStep) {
576 #if GEOS_DEBUG_BINARYOP
577 std::cerr <<
"Trying simplifying with tolerance " << tol << std::endl;
580 GeomPtr rG0(simplify::TopologyPreservingSimplifier::simplify(g0, tol));
581 GeomPtr rG1(simplify::TopologyPreservingSimplifier::simplify(g1, tol));
584 ret.reset(_Op(rG0.get(), rG1.get()));
588 if(tol >= maxTolerance) {
591 #if GEOS_DEBUG_BINARYOP
592 std::cerr <<
"Simplified with tolerance (" << tol <<
"): "
593 << ex.what() << std::endl;
603 #if GEOS_DEBUG_BINARYOP
604 std::cerr <<
"Simplified: " << ex.what() << std::endl;
611 #if GEOS_DEBUG_BINARYOP
612 std::cerr <<
"No attempts worked to union " << std::endl;
613 std::cerr <<
"Input geometries:" << std::endl
614 <<
"<A>" << std::endl
615 << g0->toString() << std::endl
616 <<
"</A>" << std::endl
617 <<
"<B>" << std::endl
618 << g1->toString() << std::endl
619 <<
"</B>" << std::endl;
629 #endif // GEOS_GEOM_BINARYOP_H
Allow computing and removing common mantissa bits from one or more Geometries.
Definition: CommonBitsRemover.h:40
void removeCommonBits(geom::Geometry *geom)
Removes the common coordinate bits from a Geometry. The coordinates of the Geometry are changed...
Basic implementation of Geometry, constructed and destructed by GeometryFactory.
Definition: Geometry.h:188
geom::Coordinate & getCommonCoordinate()
std::unique_ptr< Geometry > SnapOp(const Geometry *g0, const Geometry *g1, BinOp _Op)
Apply a binary operation to the given geometries after snapping them to each other after common-bits ...
Definition: BinaryOp.h:275
Snaps the vertices and segments of a geom::Geometry to another Geometry's vertices.
Definition: GeometrySnapper.h:58
virtual std::unique_ptr< Geometry > clone() const =0
Make a deep-copy of this Geometry.
Indicates an invalid or inconsistent topological situation encountered during processing.
Definition: TopologyException.h:35
geom::Geometry * addCommonBits(geom::Geometry *geom)
Adds the common coordinate bits back into a Geometry. The coordinates of the Geometry are changed...
void add(const geom::Geometry *geom)
static const BoundaryNodeRule & getBoundaryEndPoint()
The Endpoint Boundary Node Rule.
static GeometryFactory::Ptr create()
Constructs a GeometryFactory that generates Geometries having a floating PrecisionModel and a spatial...