00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049 #ifndef GEOS_GEOM_BINARYOP_H
00050 #define GEOS_GEOM_BINARYOP_H
00051
00052 #include <geos/geom/Geometry.h>
00053 #include <geos/geom/PrecisionModel.h>
00054 #include <geos/precision/CommonBitsRemover.h>
00055 #include <geos/precision/SimpleGeometryPrecisionReducer.h>
00056
00057 #include <geos/operation/overlay/snap/GeometrySnapper.h>
00058
00059 #include <geos/simplify/TopologyPreservingSimplifier.h>
00060 #include <geos/operation/valid/IsValidOp.h>
00061 #include <geos/operation/valid/TopologyValidationError.h>
00062 #include <geos/util/TopologyException.h>
00063 #include <geos/util.h>
00064
00065 #include <memory>
00066
00067
00068
00069 #ifdef GEOS_DEBUG_BINARYOP
00070 # include <iostream>
00071 # include <iomanip>
00072 # include <sstream>
00073 #endif
00074
00075
00076
00077
00078
00079 #ifndef USE_ORIGINAL_INPUT
00080 # define USE_ORIGINAL_INPUT 1
00081 #endif
00082
00083
00084
00085
00086
00087
00088 #ifndef USE_PRECISION_REDUCTION_POLICY
00089
00090 #endif
00091
00092
00093
00094
00095
00096
00097 #ifndef USE_TP_SIMPLIFY_POLICY
00098
00099 #endif
00100
00101
00102
00103
00104
00105
00106 #ifndef USE_COMMONBITS_POLICY
00107 # define USE_COMMONBITS_POLICY 1
00108 #endif
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121 #define GEOS_CHECK_COMMONBITS_VALIDITY 1
00122
00123
00124
00125
00126 #ifndef USE_SNAPPING_POLICY
00127 # define USE_SNAPPING_POLICY 1
00128 #endif
00129
00130 namespace geos {
00131 namespace geom {
00132
00133 inline bool
00134 check_valid(const Geometry& g, const std::string& label)
00135 {
00136 operation::valid::IsValidOp ivo(&g);
00137 if ( ! ivo.isValid() )
00138 {
00139 #ifdef GEOS_DEBUG_BINARYOP
00140 using operation::valid::TopologyValidationError;
00141 TopologyValidationError* err = ivo.getValidationError();
00142 std::cerr << label << " is INVALID: "
00143 << err->toString()
00144 << " (" << std::setprecision(20)
00145 << err->getCoordinate() << ")"
00146 << std::endl;
00147 #else
00148 (void)label;
00149 #endif
00150 return false;
00151 }
00152 return true;
00153 }
00154
00155
00156 inline std::auto_ptr<Geometry>
00157 fix_self_intersections(std::auto_ptr<Geometry> g, const std::string& label)
00158 {
00159
00160 return g->Union();
00161 }
00162
00163
00169 template <class BinOp>
00170 std::auto_ptr<Geometry>
00171 SnapOp(const Geometry* g0, const Geometry *g1, BinOp _Op)
00172 {
00173 typedef std::auto_ptr<Geometry> GeomPtr;
00174
00175 #define CBR_BEFORE_SNAPPING 1
00176
00177
00178 using geos::operation::overlay::snap::GeometrySnapper;
00179
00180
00181
00182 double snapTolerance = GeometrySnapper::computeOverlaySnapTolerance(*g0, *g1);
00183 #if GEOS_DEBUG_BINARYOP
00184 std::cerr<< std::setprecision(20) << "Computed snap tolerance: "<<snapTolerance<<std::endl;
00185 #endif
00186
00187
00188 #if CBR_BEFORE_SNAPPING
00189
00190 geos::precision::CommonBitsRemover cbr;
00191 cbr.add(g0); cbr.add(g1);
00192 #if GEOS_DEBUG_BINARYOP
00193 std::cerr<<"Computed common bits: "<<cbr.getCommonCoordinate()<<std::endl;
00194 #endif
00195
00196
00197 GeomPtr rG0( cbr.removeCommonBits(g0->clone()) );
00198 GeomPtr rG1( cbr.removeCommonBits(g1->clone()) );
00199
00200 #if GEOS_DEBUG_BINARYOP
00201 check_valid(*rG0, "CBR: removed-bits geom 0");
00202 check_valid(*rG1, "CBR: removed-bits geom 1");
00203 #endif
00204
00205 const Geometry& operand0 = *rG0;
00206 const Geometry& operand1 = *rG1;
00207 #else // don't CBR before snapping
00208 const Geometry& operand0 = *g0;
00209 const Geometry& operand1 = *g1;
00210 #endif
00211
00212
00213 GeometrySnapper snapper0( operand0 );
00214 GeomPtr snapG0( snapper0.snapTo(operand1, snapTolerance) );
00215 snapG0 = fix_self_intersections(snapG0, "SNAP: snapped geom 0");
00216
00217
00218 GeometrySnapper snapper1( operand1 );
00219 GeomPtr snapG1( snapper1.snapTo(*snapG0, snapTolerance) );
00220 snapG1 = fix_self_intersections(snapG1, "SNAP: snapped geom 1");
00221
00222
00223 GeomPtr result( _Op(snapG0.get(), snapG1.get()) );
00224
00225 #if GEOS_DEBUG_BINARYOP
00226 check_valid(*result, "SNAP: result (before common-bits addition");
00227 #endif
00228
00229 #if CBR_BEFORE_SNAPPING
00230
00231 cbr.addCommonBits( result.get() );
00232 result = fix_self_intersections(result, "SNAP: result (after common-bits addition)");
00233 #endif
00234
00235 #if GEOS_DEBUG_BINARYOP
00236 check_valid(*result, "SNAP: result (after common-bits addition");
00237 #endif
00238
00239 return result;
00240 }
00241
00242 template <class BinOp>
00243 std::auto_ptr<Geometry>
00244 BinaryOp(const Geometry* g0, const Geometry *g1, BinOp _Op)
00245 {
00246 typedef std::auto_ptr<Geometry> GeomPtr;
00247
00248 GeomPtr ret;
00249 geos::util::TopologyException origException;
00250
00251 #ifdef USE_ORIGINAL_INPUT
00252
00253 try
00254 {
00255 #if GEOS_DEBUG_BINARYOP
00256 std::cerr << "Trying with original input." << std::endl;
00257 #endif
00258 ret.reset(_Op(g0, g1));
00259 return ret;
00260 }
00261 catch (const geos::util::TopologyException& ex)
00262 {
00263 origException=ex;
00264 #if GEOS_DEBUG_BINARYOP
00265 std::cerr << "Original exception: " << ex.what() << std::endl;
00266 #endif
00267 }
00268
00269
00270
00271 check_valid(*g0, "Input geom 0");
00272 check_valid(*g1, "Input geom 1");
00273
00274
00275 #endif // USE_ORIGINAL_INPUT
00276
00277
00278 #ifdef USE_COMMONBITS_POLICY
00279
00280
00281
00282
00283
00284
00285
00286 try
00287 {
00288 GeomPtr rG0;
00289 GeomPtr rG1;
00290 precision::CommonBitsRemover cbr;
00291
00292 #if GEOS_DEBUG_BINARYOP
00293 std::cerr << "Trying with Common Bits Remover (CBR)" << std::endl;
00294 #endif
00295
00296 cbr.add(g0);
00297 cbr.add(g1);
00298
00299 rG0.reset( cbr.removeCommonBits(g0->clone()) );
00300 rG1.reset( cbr.removeCommonBits(g1->clone()) );
00301
00302 #if GEOS_DEBUG_BINARYOP
00303 check_valid(*rG0, "CBR: geom 0 (after common-bits removal)");
00304 check_valid(*rG1, "CBR: geom 1 (after common-bits removal)");
00305 #endif
00306
00307 ret.reset( _Op(rG0.get(), rG1.get()) );
00308
00309 #if GEOS_DEBUG_BINARYOP
00310 check_valid(*ret, "CBR: result (before common-bits addition)");
00311 #endif
00312
00313 cbr.addCommonBits( ret.get() );
00314
00315 #if GEOS_DEBUG_BINARYOP
00316 check_valid(*ret, "CBR: result (after common-bits addition)");
00317 #endif
00318
00319
00320 ret = fix_self_intersections(ret, "CBR: result (after common-bits addition)");
00321
00322 #if GEOS_DEBUG_BINARYOP
00323 check_valid(*ret, "CBR: result (after common-bits addition and fix_self_intersections)");
00324 #endif
00325
00326 #if GEOS_CHECK_COMMONBITS_VALIDITY
00327
00328
00329 using operation::valid::IsValidOp;
00330 using operation::valid::TopologyValidationError;
00331 IsValidOp ivo(ret.get());
00332 if ( ! ivo.isValid() )
00333 {
00334 TopologyValidationError* e = ivo.getValidationError();
00335 throw geos::util::TopologyException(
00336 "Result of overlay became invalid "
00337 "after re-addin common bits of operand "
00338 "coordinates: " + e->toString(),
00339 e->getCoordinate());
00340 }
00341 #endif // GEOS_CHECK_COMMONBITS_VALIDITY
00342
00343 return ret;
00344 }
00345 catch (const geos::util::TopologyException& ex)
00346 {
00347 ::geos::ignore_unused_variable_warning(ex);
00348 #if GEOS_DEBUG_BINARYOP
00349 std::cerr << "CBR: " << ex.what() << std::endl;
00350 #endif
00351 }
00352 #endif
00353
00354
00355
00356
00357
00358
00359
00360
00361 #if USE_SNAPPING_POLICY
00362
00363 #if GEOS_DEBUG_BINARYOP
00364 std::cerr << "Trying with snapping " << std::endl;
00365 #endif
00366
00367 try {
00368 ret = SnapOp(g0, g1, _Op);
00369 #if GEOS_DEBUG_BINARYOP
00370 std::cerr << "SnapOp succeeded" << std::endl;
00371 #endif
00372 return ret;
00373
00374 }
00375 catch (const geos::util::TopologyException& ex)
00376 {
00377 ::geos::ignore_unused_variable_warning(ex);
00378 #if GEOS_DEBUG_BINARYOP
00379 std::cerr << "SNAP: " << ex.what() << std::endl;
00380 #endif
00381 }
00382
00383 #endif // USE_SNAPPING_POLICY }
00384
00385
00386
00387
00388 #if USE_PRECISION_REDUCTION_POLICY
00389
00390
00391
00392 try
00393 {
00394 int maxPrecision=25;
00395
00396 for (int precision=maxPrecision; precision; --precision)
00397 {
00398 std::auto_ptr<PrecisionModel> pm(new PrecisionModel(precision));
00399 #if GEOS_DEBUG_BINARYOP
00400 std::cerr << "Trying with precision " << precision << std::endl;
00401 #endif
00402
00403 precision::SimpleGeometryPrecisionReducer reducer( pm.get() );
00404 GeomPtr rG0( reducer.reduce(g0) );
00405 GeomPtr rG1( reducer.reduce(g1) );
00406
00407 try
00408 {
00409 ret.reset( _Op(rG0.get(), rG1.get()) );
00410 return ret;
00411 }
00412 catch (const geos::util::TopologyException& ex)
00413 {
00414 if ( precision == 1 ) throw ex;
00415 #if GEOS_DEBUG_BINARYOP
00416 std::cerr << "Reduced with precision (" << precision << "): "
00417 << ex.what() << std::endl;
00418 #endif
00419 }
00420
00421 }
00422
00423 }
00424 catch (const geos::util::TopologyException& ex)
00425 {
00426 #if GEOS_DEBUG_BINARYOP
00427 std::cerr << "Reduced: " << ex.what() << std::endl;
00428 #endif
00429 }
00430
00431 #endif
00432
00433
00434
00435 #if USE_TP_SIMPLIFY_POLICY
00436
00437
00438 try
00439 {
00440
00441 double maxTolerance = 0.04;
00442 double minTolerance = 0.01;
00443 double tolStep = 0.01;
00444
00445 for (double tol = minTolerance; tol <= maxTolerance; tol += tolStep)
00446 {
00447 #if GEOS_DEBUG_BINARYOP
00448 std::cerr << "Trying simplifying with tolerance " << tol << std::endl;
00449 #endif
00450
00451 GeomPtr rG0( simplify::TopologyPreservingSimplifier::simplify(g0, tol) );
00452 GeomPtr rG1( simplify::TopologyPreservingSimplifier::simplify(g1, tol) );
00453
00454 try
00455 {
00456 ret.reset( _Op(rG0.get(), rG1.get()) );
00457 return ret;
00458 }
00459 catch (const geos::util::TopologyException& ex)
00460 {
00461 if ( tol >= maxTolerance ) throw ex;
00462 #if GEOS_DEBUG_BINARYOP
00463 std::cerr << "Simplified with tolerance (" << tol << "): "
00464 << ex.what() << std::endl;
00465 #endif
00466 }
00467
00468 }
00469
00470 return ret;
00471
00472 }
00473 catch (const geos::util::TopologyException& ex)
00474 {
00475 #if GEOS_DEBUG_BINARYOP
00476 std::cerr << "Simplified: " << ex.what() << std::endl;
00477 #endif
00478 }
00479
00480 #endif
00481
00482
00483 throw origException;
00484 }
00485
00486
00487 }
00488 }
00489
00490 #endif // GEOS_GEOM_BINARYOP_H