50 #ifndef GEOS_GEOM_BINARYOP_H
51 #define GEOS_GEOM_BINARYOP_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/precision/CommonBitsRemover.h>
58 #include <geos/precision/SimpleGeometryPrecisionReducer.h>
60 #include <geos/operation/overlay/snap/GeometrySnapper.h>
62 #include <geos/simplify/TopologyPreservingSimplifier.h>
63 #include <geos/operation/valid/IsValidOp.h>
64 #include <geos/operation/valid/TopologyValidationError.h>
65 #include <geos/util/TopologyException.h>
66 #include <geos/util.h>
72 #ifdef GEOS_DEBUG_BINARYOP
82 #ifndef USE_ORIGINAL_INPUT
83 # define USE_ORIGINAL_INPUT 1
91 #ifndef USE_PRECISION_REDUCTION_POLICY
100 #ifndef USE_TP_SIMPLIFY_POLICY
109 #ifndef USE_COMMONBITS_POLICY
110 # define USE_COMMONBITS_POLICY 1
124 #define GEOS_CHECK_COMMONBITS_VALIDITY 1
129 #ifndef USE_SNAPPING_POLICY
130 # define USE_SNAPPING_POLICY 1
137 check_valid(
const Geometry& g,
const std::string& label)
139 operation::valid::IsValidOp ivo(&g);
140 if ( ! ivo.isValid() )
142 #ifdef GEOS_DEBUG_BINARYOP
143 using operation::valid::TopologyValidationError;
144 TopologyValidationError* err = ivo.getValidationError();
145 std::cerr << label <<
" is INVALID: "
147 <<
" (" << std::setprecision(20)
148 << err->getCoordinate() <<
")"
164 inline std::auto_ptr<Geometry>
165 fix_self_intersections(std::auto_ptr<Geometry> g,
const std::string& label)
167 #ifdef GEOS_DEBUG_BINARYOP
168 std::cerr << label <<
" fix_self_intersection (UnaryUnion)" << std::endl;
172 if ( ! dynamic_cast<const GeometryCollection*>(g.get()) )
return g;
174 using operation::valid::IsValidOp;
176 IsValidOp ivo(g.get());
179 if ( ivo.isValid() )
return g;
183 using operation::valid::TopologyValidationError;
184 TopologyValidationError* err = ivo.getValidationError();
185 switch ( err->getErrorType() ) {
186 case TopologyValidationError::eRingSelfIntersection:
187 case TopologyValidationError::eTooFewPoints:
188 #ifdef GEOS_DEBUG_BINARYOP
189 std::cerr << label <<
" ATTEMPT_TO_FIX: " << err->getErrorType() <<
": " << *g << std::endl;
192 #ifdef GEOS_DEBUG_BINARYOP
193 std::cerr << label <<
" ATTEMPT_TO_FIX succeeded.. " << std::endl;
196 case TopologyValidationError::eSelfIntersection:
199 #ifdef GEOS_DEBUG_BINARYOP
200 std::cerr << label <<
" invalidity is: " << err->getErrorType() << std::endl;
212 template <
class BinOp>
213 std::auto_ptr<Geometry>
216 typedef std::auto_ptr<Geometry> GeomPtr;
218 #define CBR_BEFORE_SNAPPING 1
225 double snapTolerance = GeometrySnapper::computeOverlaySnapTolerance(*g0, *g1);
226 #if GEOS_DEBUG_BINARYOP
227 std::cerr<< std::setprecision(20) <<
"Computed snap tolerance: "<<snapTolerance<<std::endl;
231 #if CBR_BEFORE_SNAPPING
235 #if GEOS_DEBUG_BINARYOP
243 #if GEOS_DEBUG_BINARYOP
244 check_valid(*rG0,
"CBR: removed-bits geom 0");
245 check_valid(*rG1,
"CBR: removed-bits geom 1");
250 #else // don't CBR before snapping
256 GeometrySnapper snapper0( operand0 );
257 GeomPtr snapG0( snapper0.snapTo(operand1, snapTolerance) );
258 snapG0 = fix_self_intersections(snapG0,
"SNAP: snapped geom 0");
261 GeometrySnapper snapper1( operand1 );
262 GeomPtr snapG1( snapper1.snapTo(*snapG0, snapTolerance) );
263 snapG1 = fix_self_intersections(snapG1,
"SNAP: snapped geom 1");
266 GeomPtr result( _Op(snapG0.get(), snapG1.get()) );
268 #if GEOS_DEBUG_BINARYOP
269 check_valid(*result,
"SNAP: result (before common-bits addition");
272 #if CBR_BEFORE_SNAPPING
275 result = fix_self_intersections(result,
"SNAP: result (after common-bits addition)");
278 #if GEOS_DEBUG_BINARYOP
279 check_valid(*result,
"SNAP: result (after common-bits addition");
285 template <
class BinOp>
286 std::auto_ptr<Geometry>
287 BinaryOp(
const Geometry* g0,
const Geometry *g1, BinOp _Op)
289 typedef std::auto_ptr<Geometry> GeomPtr;
294 #ifdef USE_ORIGINAL_INPUT
298 #if GEOS_DEBUG_BINARYOP
299 std::cerr <<
"Trying with original input." << std::endl;
301 ret.reset(_Op(g0, g1));
307 #if GEOS_DEBUG_BINARYOP
308 std::cerr <<
"Original exception: " << ex.what() << std::endl;
312 #if GEOS_DEBUG_BINARYOP
314 check_valid(*g0,
"Input geom 0");
315 check_valid(*g1,
"Input geom 1");
318 #endif // USE_ORIGINAL_INPUT
321 #ifdef USE_COMMONBITS_POLICY
333 precision::CommonBitsRemover cbr;
335 #if GEOS_DEBUG_BINARYOP
336 std::cerr <<
"Trying with Common Bits Remover (CBR)" << std::endl;
342 rG0.reset( cbr.removeCommonBits(g0->clone()) );
343 rG1.reset( cbr.removeCommonBits(g1->clone()) );
345 #if GEOS_DEBUG_BINARYOP
346 check_valid(*rG0,
"CBR: geom 0 (after common-bits removal)");
347 check_valid(*rG1,
"CBR: geom 1 (after common-bits removal)");
350 ret.reset( _Op(rG0.get(), rG1.get()) );
352 #if GEOS_DEBUG_BINARYOP
353 check_valid(*ret,
"CBR: result (before common-bits addition)");
356 cbr.addCommonBits( ret.get() );
358 #if GEOS_DEBUG_BINARYOP
359 check_valid(*ret,
"CBR: result (after common-bits addition)");
363 ret = fix_self_intersections(ret,
"CBR: result (after common-bits addition)");
365 #if GEOS_DEBUG_BINARYOP
366 check_valid(*ret,
"CBR: result (after common-bits addition and fix_self_intersections)");
369 #if GEOS_CHECK_COMMONBITS_VALIDITY
372 using operation::valid::IsValidOp;
373 using operation::valid::TopologyValidationError;
374 IsValidOp ivo(ret.get());
375 if ( ! ivo.isValid() )
377 TopologyValidationError* e = ivo.getValidationError();
379 "Result of overlay became invalid "
380 "after re-addin common bits of operand "
381 "coordinates: " + e->toString(),
384 #endif // GEOS_CHECK_COMMONBITS_VALIDITY
390 ::geos::ignore_unused_variable_warning(ex);
391 #if GEOS_DEBUG_BINARYOP
392 std::cerr <<
"CBR: " << ex.what() << std::endl;
404 #if USE_SNAPPING_POLICY
406 #if GEOS_DEBUG_BINARYOP
407 std::cerr <<
"Trying with snapping " << std::endl;
411 ret =
SnapOp(g0, g1, _Op);
412 #if GEOS_DEBUG_BINARYOP
413 std::cerr <<
"SnapOp succeeded" << std::endl;
420 ::geos::ignore_unused_variable_warning(ex);
421 #if GEOS_DEBUG_BINARYOP
422 std::cerr <<
"SNAP: " << ex.what() << std::endl;
426 #endif // USE_SNAPPING_POLICY }
431 #if USE_PRECISION_REDUCTION_POLICY
439 for (
int precision=maxPrecision; precision; --precision)
441 std::auto_ptr<PrecisionModel> pm(
new PrecisionModel(precision));
442 #if GEOS_DEBUG_BINARYOP
443 std::cerr <<
"Trying with precision " << precision << std::endl;
446 precision::SimpleGeometryPrecisionReducer reducer( pm.get() );
447 GeomPtr rG0( reducer.reduce(g0) );
448 GeomPtr rG1( reducer.reduce(g1) );
452 ret.reset( _Op(rG0.get(), rG1.get()) );
457 if ( precision == 1 )
throw ex;
458 #if GEOS_DEBUG_BINARYOP
459 std::cerr <<
"Reduced with precision (" << precision <<
"): "
460 << ex.what() << std::endl;
469 #if GEOS_DEBUG_BINARYOP
470 std::cerr <<
"Reduced: " << ex.what() << std::endl;
478 #if USE_TP_SIMPLIFY_POLICY
484 double maxTolerance = 0.04;
485 double minTolerance = 0.01;
486 double tolStep = 0.01;
488 for (
double tol = minTolerance; tol <= maxTolerance; tol += tolStep)
490 #if GEOS_DEBUG_BINARYOP
491 std::cerr <<
"Trying simplifying with tolerance " << tol << std::endl;
494 GeomPtr rG0( simplify::TopologyPreservingSimplifier::simplify(g0, tol) );
495 GeomPtr rG1( simplify::TopologyPreservingSimplifier::simplify(g1, tol) );
499 ret.reset( _Op(rG0.get(), rG1.get()) );
504 if ( tol >= maxTolerance )
throw ex;
505 #if GEOS_DEBUG_BINARYOP
506 std::cerr <<
"Simplified with tolerance (" << tol <<
"): "
507 << ex.what() << std::endl;
518 #if GEOS_DEBUG_BINARYOP
519 std::cerr <<
"Simplified: " << ex.what() << std::endl;
533 #endif // GEOS_GEOM_BINARYOP_H