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/Lineal.h>
57 #include <geos/geom/PrecisionModel.h>
58 #include <geos/geom/GeometryFactory.h>
59 #include <geos/precision/CommonBitsRemover.h>
60 #include <geos/precision/SimpleGeometryPrecisionReducer.h>
61 #include <geos/precision/GeometryPrecisionReducer.h>
63 #include <geos/operation/overlay/snap/GeometrySnapper.h>
65 #include <geos/simplify/TopologyPreservingSimplifier.h>
66 #include <geos/operation/IsSimpleOp.h>
67 #include <geos/operation/valid/IsValidOp.h>
68 #include <geos/operation/valid/TopologyValidationError.h>
69 #include <geos/util/TopologyException.h>
70 #include <geos/util.h>
75 #define GEOS_DEBUG_BINARYOP_PRINT_INVALID 1
77 #ifdef GEOS_DEBUG_BINARYOP
87 #ifndef USE_ORIGINAL_INPUT
88 # define USE_ORIGINAL_INPUT 1
94 #define GEOS_CHECK_ORIGINAL_RESULT_VALIDITY 0
102 #ifndef USE_PRECISION_REDUCTION_POLICY
103 # define USE_PRECISION_REDUCTION_POLICY 1
115 #define GEOS_CHECK_PRECISION_REDUCTION_VALIDITY 0
122 #ifndef USE_TP_SIMPLIFY_POLICY
131 #ifndef USE_COMMONBITS_POLICY
132 # define USE_COMMONBITS_POLICY 1
146 #define GEOS_CHECK_COMMONBITS_VALIDITY 1
151 #ifndef USE_SNAPPING_POLICY
152 # define USE_SNAPPING_POLICY 1
156 #ifndef CBR_BEFORE_SNAPPING
157 # define CBR_BEFORE_SNAPPING 1
164 #define GEOS_CHECK_SNAPPINGOP_VALIDITY 0
171 check_valid(
const Geometry& g,
const std::string& label,
bool doThrow=
false,
bool validOnly=
false)
173 if ( dynamic_cast<const Lineal*>(&g) ) {
176 if ( ! sop.isSimple() )
180 label +
" is not simple");
186 operation::valid::IsValidOp ivo(&g);
187 if ( ! ivo.isValid() )
189 using operation::valid::TopologyValidationError;
190 TopologyValidationError* err = ivo.getValidationError();
191 #ifdef GEOS_DEBUG_BINARYOP
192 std::cerr << label <<
" is INVALID: "
194 <<
" (" << std::setprecision(20)
195 << err->getCoordinate() <<
")"
197 #ifdef GEOS_DEBUG_BINARYOP_PRINT_INVALID
198 <<
"<A>" << std::endl
201 <<
"</A>" << std::endl
207 label +
" is invalid: " + err->toString(),
208 err->getCoordinate());
222 inline std::unique_ptr<Geometry>
223 fix_self_intersections(std::unique_ptr<Geometry> g,
const std::string& label)
225 ::geos::ignore_unused_variable_warning(label);
226 #ifdef GEOS_DEBUG_BINARYOP
227 std::cerr << label <<
" fix_self_intersection (UnaryUnion)" << std::endl;
231 if ( ! dynamic_cast<const GeometryCollection*>(g.get()) )
return g;
233 using operation::valid::IsValidOp;
235 IsValidOp ivo(g.get());
238 if ( ivo.isValid() )
return g;
242 using operation::valid::TopologyValidationError;
243 TopologyValidationError* err = ivo.getValidationError();
244 switch ( err->getErrorType() ) {
245 case TopologyValidationError::eRingSelfIntersection:
246 case TopologyValidationError::eTooFewPoints:
247 #ifdef GEOS_DEBUG_BINARYOP
248 std::cerr << label <<
" ATTEMPT_TO_FIX: " << err->getErrorType() <<
": " << *g << std::endl;
251 #ifdef GEOS_DEBUG_BINARYOP
252 std::cerr << label <<
" ATTEMPT_TO_FIX succeeded.. " << std::endl;
255 case TopologyValidationError::eSelfIntersection:
258 #ifdef GEOS_DEBUG_BINARYOP
259 std::cerr << label <<
" invalidity is: " << err->getErrorType() << std::endl;
271 template <
class BinOp>
272 std::unique_ptr<Geometry>
275 typedef std::unique_ptr<Geometry> GeomPtr;
282 double snapTolerance = GeometrySnapper::computeOverlaySnapTolerance(*g0, *g1);
283 #if GEOS_DEBUG_BINARYOP
284 std::cerr<< std::setprecision(20) <<
"Computed snap tolerance: "<<snapTolerance<<std::endl;
288 #if CBR_BEFORE_SNAPPING
292 #if GEOS_DEBUG_BINARYOP
300 #if GEOS_DEBUG_BINARYOP
301 check_valid(*rG0,
"CBR: removed-bits geom 0");
302 check_valid(*rG1,
"CBR: removed-bits geom 1");
307 #else // don't CBR before snapping
313 GeometrySnapper snapper0( operand0 );
314 GeomPtr snapG0( snapper0.snapTo(operand1, snapTolerance) );
318 GeometrySnapper snapper1( operand1 );
319 GeomPtr snapG1( snapper1.snapTo(*snapG0, snapTolerance) );
323 GeomPtr result( _Op(snapG0.get(), snapG1.get()) );
325 #if GEOS_DEBUG_BINARYOP
326 check_valid(*result,
"SNAP: result (before common-bits addition");
329 #if CBR_BEFORE_SNAPPING
334 check_valid(*result,
"CBR: result (after common-bits addition)",
true);
341 template <
class BinOp>
342 std::unique_ptr<Geometry>
343 BinaryOp(
const Geometry* g0,
const Geometry *g1, BinOp _Op)
345 typedef std::unique_ptr<Geometry> GeomPtr;
350 #ifdef USE_ORIGINAL_INPUT
354 #if GEOS_DEBUG_BINARYOP
355 std::cerr <<
"Trying with original input." << std::endl;
357 ret.reset(_Op(g0, g1));
359 #if GEOS_CHECK_ORIGINAL_RESULT_VALIDITY
360 check_valid(*ret,
"Overlay result between original inputs",
true,
true);
363 #if GEOS_DEBUG_BINARYOP
364 std::cerr <<
"Attempt with original input succeeded" << std::endl;
371 #if GEOS_DEBUG_BINARYOP
372 std::cerr <<
"Original exception: " << ex.what() << std::endl;
375 #endif // USE_ORIGINAL_INPUT
377 check_valid(*g0,
"Input geom 0",
true,
true);
378 check_valid(*g1,
"Input geom 1",
true,
true);
380 #if USE_COMMONBITS_POLICY
392 precision::CommonBitsRemover cbr;
394 #if GEOS_DEBUG_BINARYOP
395 std::cerr <<
"Trying with Common Bits Remover (CBR)" << std::endl;
401 rG0.reset( cbr.removeCommonBits(g0->clone()) );
402 rG1.reset( cbr.removeCommonBits(g1->clone()) );
404 #if GEOS_DEBUG_BINARYOP
405 check_valid(*rG0,
"CBR: geom 0 (after common-bits removal)");
406 check_valid(*rG1,
"CBR: geom 1 (after common-bits removal)");
409 ret.reset( _Op(rG0.get(), rG1.get()) );
411 #if GEOS_DEBUG_BINARYOP
412 check_valid(*ret,
"CBR: result (before common-bits addition)");
415 cbr.addCommonBits( ret.get() );
417 #if GEOS_CHECK_COMMONBITS_VALIDITY
418 check_valid(*ret,
"CBR: result (after common-bits addition)",
true);
421 #if GEOS_DEBUG_BINARYOP
422 std::cerr <<
"Attempt with CBR succeeded" << std::endl;
429 ::geos::ignore_unused_variable_warning(ex);
430 #if GEOS_DEBUG_BINARYOP
431 std::cerr <<
"CBR: " << ex.what() << std::endl;
443 #if USE_SNAPPING_POLICY
445 #if GEOS_DEBUG_BINARYOP
446 std::cerr <<
"Trying with snapping " << std::endl;
450 ret =
SnapOp(g0, g1, _Op);
451 #if GEOS_CHECK_SNAPPINGOP_VALIDITY
452 check_valid(*ret,
"SNAP: result",
true,
true);
454 #if GEOS_DEBUG_BINARYOP
455 std::cerr <<
"SnapOp succeeded" << std::endl;
462 ::geos::ignore_unused_variable_warning(ex);
463 #if GEOS_DEBUG_BINARYOP
464 std::cerr <<
"SNAP: " << ex.what() << std::endl;
468 #endif // USE_SNAPPING_POLICY }
471 #if USE_PRECISION_REDUCTION_POLICY
477 long unsigned int g0scale =
478 static_cast<long unsigned int>(g0->getFactory()->getPrecisionModel()->getScale());
479 long unsigned int g1scale =
480 static_cast<long unsigned int>(g1->getFactory()->getPrecisionModel()->getScale());
482 #if GEOS_DEBUG_BINARYOP
483 std::cerr <<
"Original input scales are: "
490 double maxScale = 1e16;
493 if ( g0scale && static_cast<double>(g0scale) < maxScale ) maxScale = static_cast<double>(g0scale);
494 if ( g1scale && static_cast<double>(g1scale) < maxScale ) maxScale = static_cast<double>(g1scale);
497 for (
double scale=maxScale; scale >= 1; scale /= 10)
499 PrecisionModel pm(scale);
501 #if GEOS_DEBUG_BINARYOP
502 std::cerr <<
"Trying with scale " << scale << std::endl;
505 precision::GeometryPrecisionReducer reducer( *gf );
506 GeomPtr rG0( reducer.reduce(*g0) );
507 GeomPtr rG1( reducer.reduce(*g1) );
509 #if GEOS_DEBUG_BINARYOP
510 check_valid(*rG0,
"PR: geom 0 (after precision reduction)");
511 check_valid(*rG1,
"PR: geom 1 (after precision reduction)");
516 ret.reset( _Op(rG0.get(), rG1.get()) );
518 if ( g0->getFactory()->getPrecisionModel()->compareTo( g1->getFactory()->getPrecisionModel() ) < 0 ) {
519 ret.reset( g0->getFactory()->createGeometry(ret.get()) );
522 ret.reset( g1->getFactory()->createGeometry(ret.get()) );
525 #if GEOS_CHECK_PRECISION_REDUCTION_VALIDITY
526 check_valid(*ret,
"PR: result (after restore of original precision)",
true);
529 #if GEOS_DEBUG_BINARYOP
530 std::cerr <<
"Attempt with scale " << scale <<
" succeeded" << std::endl;
536 #if GEOS_DEBUG_BINARYOP
537 std::cerr <<
"Reduced with scale (" << scale <<
"): "
538 << ex.what() << std::endl;
540 if ( scale == 1 )
throw ex;
548 #if GEOS_DEBUG_BINARYOP
549 std::cerr <<
"Reduced: " << ex.what() << std::endl;
551 ::geos::ignore_unused_variable_warning(ex);
562 #if USE_TP_SIMPLIFY_POLICY
568 double maxTolerance = 0.04;
569 double minTolerance = 0.01;
570 double tolStep = 0.01;
572 for (
double tol = minTolerance; tol <= maxTolerance; tol += tolStep)
574 #if GEOS_DEBUG_BINARYOP
575 std::cerr <<
"Trying simplifying with tolerance " << tol << std::endl;
578 GeomPtr rG0( simplify::TopologyPreservingSimplifier::simplify(g0, tol) );
579 GeomPtr rG1( simplify::TopologyPreservingSimplifier::simplify(g1, tol) );
583 ret.reset( _Op(rG0.get(), rG1.get()) );
588 if ( tol >= maxTolerance )
throw ex;
589 #if GEOS_DEBUG_BINARYOP
590 std::cerr <<
"Simplified with tolerance (" << tol <<
"): "
591 << ex.what() << std::endl;
602 #if GEOS_DEBUG_BINARYOP
603 std::cerr <<
"Simplified: " << ex.what() << std::endl;
610 #if GEOS_DEBUG_BINARYOP
611 std::cerr <<
"No attempts worked to union " << std::endl;
612 std::cerr <<
"Input geometries:" << std::endl
613 <<
"<A>" << std::endl
614 << g0->toString() << std::endl
615 <<
"</A>" << std::endl
616 <<
"<B>" << std::endl
617 << g1->toString() << std::endl
618 <<
"</B>" << std::endl;
628 #endif // GEOS_GEOM_BINARYOP_H
Allow computing and removing common mantissa bits from one or more Geometries.
Definition: CommonBitsRemover.h:40
virtual Geometry * clone() const =0
Make a deep-copy of this Geometry.
Basic implementation of Geometry, constructed and destructed by GeometryFactory.
Definition: Geometry.h:177
geom::Coordinate & getCommonCoordinate()
geom::Geometry * removeCommonBits(geom::Geometry *geom)
Removes the common coordinate bits from a Geometry. The coordinates of the Geometry are changed...
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:273
Snaps the vertices and segments of a Geometry to another Geometry's vertices.
Definition: GeometrySnapper.h:58
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...