Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | Related Pages

BinaryOp.h

00001 /**********************************************************************
00002  * $Id: BinaryOp.h 2127 2008-05-20 21:25:21Z mloskot $
00003  *
00004  * GEOS - Geometry Engine Open Source
00005  * http://geos.refractions.net
00006  *
00007  * Copyright (C) 2006 Refractions Research Inc.
00008  *
00009  * This is free software; you can redistribute and/or modify it under
00010  * the terms of the GNU Lesser General Public Licence as published
00011  * by the Free Software Foundation. 
00012  * See the COPYING file for more information.
00013  *
00014  **********************************************************************
00015  *
00016  * Last port: ORIGINAL WORK
00017  *
00018  **********************************************************************
00019  *
00020  * This file provides a single templated function, taking two
00021  * const Geometry pointers, applying a binary operator to them
00022  * and returning a result Geometry in an auto_ptr<>.
00023  *
00024  * The binary operator is expected to take two const Geometry pointers
00025  * and return a newly allocated Geometry pointer, possibly throwing
00026  * a TopologyException to signal it couldn't succeed due to robustness
00027  * issues.
00028  *
00029  * This function will catch TopologyExceptions and try again with
00030  * slightly modified versions of the input. The following heuristic
00031  * is used:
00032  *
00033  *      - Try with original input.
00034  *      - Try removing common bits from input coordinate values
00035  *      - Try snaping input geometries to each other
00036  *      - Try snaping input coordinates to a increasing grid (size from 1/25 to 1)
00037  *      - Try simplifiying input with increasing tolerance (from 0.01 to 0.04)
00038  *
00039  * If none of the step succeeds the original exception is thrown.
00040  *
00041  * Note that you can skip Grid snapping, Geometry snapping and Simplify policies
00042  * by a compile-time define when building geos.
00043  * See USE_TP_SIMPLIFY_POLICY, USE_PRECISION_REDUCTION_POLICY and
00044  * USE_SNAPPING_POLICY macros below.
00045  *
00046  *
00047  **********************************************************************/
00048 
00049 #include <geos/geom/Geometry.h>
00050 #include <geos/geom/PrecisionModel.h>
00051 #include <geos/precision/CommonBitsRemover.h>
00052 #include <geos/precision/SimpleGeometryPrecisionReducer.h>
00053 #include <geos/precision/GeometrySnapper.h>
00054 #include <geos/simplify/TopologyPreservingSimplifier.h>
00055 #include <geos/operation/valid/IsValidOp.h>
00056 #include <geos/util/TopologyException.h>
00057 #include <geos/util.h>
00058 
00059 #include <memory> // for auto_ptr
00060 
00061 //#define GEOS_DEBUG_BINARYOP 1
00062 
00063 
00064 /*
00065  * Always try original input first
00066  */
00067 #ifndef USE_ORIGINAL_INPUT
00068 # define USE_ORIGINAL_INPUT 1
00069 #endif
00070 
00071 /*
00072  * Define this to use PrecisionReduction policy
00073  * in an attempt at by-passing binary operation
00074  * robustness problems (handles TopologyExceptions)
00075  */
00076 #ifndef USE_PRECISION_REDUCTION_POLICY
00077 //# define USE_PRECISION_REDUCTION_POLICY 1
00078 #endif
00079 
00080 /*
00081  * Define this to use TopologyPreserving simplification policy
00082  * in an attempt at by-passing binary operation
00083  * robustness problems (handles TopologyExceptions)
00084  */
00085 #ifndef USE_TP_SIMPLIFY_POLICY 
00086 //# define USE_TP_SIMPLIFY_POLICY 1
00087 #endif
00088 
00089 /*
00090  * Use common bits removal policy.
00091  * If enabled, this would be tried /before/
00092  * Geometry snapping.
00093  */
00094 #ifndef USE_COMMONBITS_POLICY
00095 # define USE_COMMONBITS_POLICY 1
00096 #endif
00097 
00098 /*
00099  * Use snapping policy
00100  */
00101 #ifndef USE_SNAPPING_POLICY
00102 # define USE_SNAPPING_POLICY 1
00103 #endif
00104 
00105 namespace geos {
00106 namespace geom { // geos::geom
00107 
00108 bool
00109 check_valid(const Geometry& g, const std::string& label)
00110 {
00111         operation::valid::IsValidOp ivo(&g);
00112         if ( ! ivo.isValid() )
00113         {
00114                 std::cerr << label << ": is invalid!"
00115                         << ivo.getValidationError()->toString() << std::endl;
00116                 return false;
00117         } 
00118         return true;
00119 }
00120 
00126 template <class BinOp>
00127 std::auto_ptr<Geometry>
00128 SnapOp(const Geometry* g0, const Geometry *g1, BinOp _Op)
00129 {
00130         typedef std::auto_ptr<Geometry> GeomPtr;
00131 
00132 #define CBR_BEFORE_SNAPPING 1
00133 
00134         using geos::precision::GeometrySnapper;
00135 
00136         // Snap tolerance must be computed on the original
00137         // (not commonbits-removed) geoms
00138         double snapTolerance = GeometrySnapper::computeOverlaySnapTolerance(*g0, *g1);
00139 #if GEOS_DEBUG_BINARYOP
00140         std::cerr<<"Computed snap tolerance: "<<snapTolerance<<std::endl;
00141 #endif
00142 
00143         geos::precision::CommonBitsRemover cbr;
00144 
00145 #if CBR_BEFORE_SNAPPING
00146         // Now remove common bits
00147         GeomPtr rG0( cbr.removeCommonBits(g0->clone()) );
00148         GeomPtr rG1( cbr.removeCommonBits(g1->clone()) );
00149 
00150 #if GEOS_DEBUG_BINARYOP
00151         check_valid(*rG0, "CBR: removed-bits geom 0");
00152         check_valid(*rG1, "CBR: removed-bits geom 1");
00153 #endif
00154 
00155         const Geometry& operand0 = *rG0;
00156         const Geometry& operand1 = *rG1;
00157 #else // don't CBR before snapping
00158         const Geometry& operand0 = *g0
00159         const Geometry& operand1 = *g1
00160 #endif
00161 
00162         GeometrySnapper snapper0( operand0 );
00163         GeomPtr snapG0( snapper0.snapTo(operand1, snapTolerance) );
00164 
00165         // NOTE: second geom is snapped on the snapped first one
00166         GeometrySnapper snapper1( operand1 );
00167         GeomPtr snapG1( snapper1.snapTo(*snapG0, snapTolerance) );
00168 
00169 #if GEOS_DEBUG_BINARYOP
00170         check_valid(*snapG0, "SNAP: snapped geom 0");
00171         check_valid(*snapG1, "SNAP: snapped geom 1");
00172 #endif
00173 
00174         // Run the binary op
00175         GeomPtr result( _Op(snapG0.get(), snapG1.get()) );
00176 
00177 #if GEOS_DEBUG_BINARYOP
00178         check_valid(*result, "Op result (before common-bits addition");
00179 #endif
00180 
00181 #if CBR_BEFORE_SNAPPING
00182         // Add common bits back in
00183         cbr.addCommonBits( result.get() );
00184 #endif
00185 
00186 #if GEOS_DEBUG_BINARYOP
00187         check_valid(*result, "Op result (after common-bits addition");
00188 #endif
00189 
00190         return result;
00191 }
00192 
00193 template <class BinOp>
00194 std::auto_ptr<Geometry>
00195 BinaryOp(const Geometry* g0, const Geometry *g1, BinOp _Op)
00196 {
00197         typedef std::auto_ptr<Geometry> GeomPtr;
00198 
00199         GeomPtr ret;
00200         util::TopologyException origException;
00201 
00202 #ifdef USE_ORIGINAL_INPUT
00203         // Try with original input
00204         try
00205         {
00206 #if GEOS_DEBUG_BINARYOP
00207                 std::cerr << "Trying with original input." << std::endl;
00208 #endif
00209                 ret.reset(_Op(g0, g1));
00210                 return ret;
00211         }
00212         catch (const util::TopologyException& ex)
00213         {
00214                 origException=ex;
00215 #if GEOS_DEBUG_BINARYOP
00216                 std::cerr << "Original exception: " << ex.what() << std::endl;
00217 #endif
00218         }
00219 #endif // USE_ORIGINAL_INPUT
00220 
00221 
00222 #ifdef USE_COMMONBITS_POLICY
00223         // Try removing common bits (possibly obsoleted by snapping below)
00224         try
00225         {
00226                 GeomPtr rG0;
00227                 GeomPtr rG1;
00228                 precision::CommonBitsRemover cbr;
00229 
00230 #if GEOS_DEBUG_BINARYOP
00231                 std::cerr << "Trying with Common bits remover." << std::endl;
00232 #endif
00233 
00234                 cbr.add(g0);
00235                 cbr.add(g1);
00236 
00237                 rG0.reset( cbr.removeCommonBits(g0->clone()) );
00238                 rG1.reset( cbr.removeCommonBits(g1->clone()) );
00239 
00240 #if GEOS_DEBUG_BINARYOP
00241                 if ( ! rG0->isValid() )
00242                 {
00243                         std::cerr << " CBR: geom 0 is invalid!" << std::endl;
00244                 }
00245 
00246                 if ( ! rG1->isValid() )
00247                 {
00248                         std::cerr << " CBR: geom 1 is invalid!" << std::endl;
00249                 }
00250 #endif
00251 
00252                 ret.reset( _Op(rG0.get(), rG1.get()) );
00253 
00254                 cbr.addCommonBits( ret.get() );
00255 
00256                 return ret;
00257         }
00258         catch (const util::TopologyException& ex)
00259         {
00260         UNREFERENCED_PARAMETER(ex);
00261 #if GEOS_DEBUG_BINARYOP
00262                 std::cerr << "CBR: " << ex.what() << std::endl;
00263 #endif
00264         }
00265 #endif
00266 
00267         // Try with snapping
00268         //
00269         // TODO: possible optimization would be reusing the
00270         //       already common-bit-removed inputs and just
00271         //       apply geometry snapping, whereas the current
00272         //       SnapOp function does both.
00273 // {
00274 #if USE_SNAPPING_POLICY
00275 
00276 #if GEOS_DEBUG_BINARYOP
00277         std::cerr << "Trying with snapping " << std::endl;
00278 #endif
00279 
00280         try {
00281                 ret = SnapOp(g0, g1, _Op);
00282 #if GEOS_DEBUG_BINARYOP
00283         std::cerr << "SnapOp succeeded" << std::endl;
00284 #endif
00285                 return ret;
00286                 
00287         }
00288         catch (const util::TopologyException& ex)
00289         {
00290         UNREFERENCED_PARAMETER(ex);
00291 #if GEOS_DEBUG_BINARYOP
00292                 std::cerr << "SNAP: " << ex.what() << std::endl;
00293 #endif
00294         }
00295 
00296 #endif // USE_SNAPPING_POLICY }
00297 
00298 
00299 
00300 // {
00301 #if USE_PRECISION_REDUCTION_POLICY
00302 
00303 
00304         // Try reducing precision
00305         try
00306         {
00307                 int maxPrecision=25;
00308 
00309                 for (int precision=maxPrecision; precision; --precision)
00310                 {
00311                         std::auto_ptr<PrecisionModel> pm(new PrecisionModel(precision));
00312 #if GEOS_DEBUG_BINARYOP
00313                         std::cerr << "Trying with precision " << precision << std::endl;
00314 #endif
00315 
00316                         precision::SimpleGeometryPrecisionReducer reducer( pm.get() );
00317                         GeomPtr rG0( reducer.reduce(g0) );
00318                         GeomPtr rG1( reducer.reduce(g1) );
00319 
00320                         try
00321                         {
00322                                 ret.reset( _Op(rG0.get(), rG1.get()) );
00323                                 return ret;
00324                         }
00325                         catch (const util::TopologyException& ex)
00326                         {
00327                                 if ( precision == 1 ) throw ex;
00328 #if GEOS_DEBUG_BINARYOP
00329                                 std::cerr << "Reduced with precision (" << precision << "): "
00330                                           << ex.what() << std::endl;
00331 #endif
00332                         }
00333 
00334                 }
00335 
00336         }
00337         catch (const util::TopologyException& ex)
00338         {
00339 #if GEOS_DEBUG_BINARYOP
00340                 std::cerr << "Reduced: " << ex.what() << std::endl;
00341 #endif
00342         }
00343 
00344 #endif
00345 // USE_PRECISION_REDUCTION_POLICY }
00346 
00347 // {
00348 #if USE_TP_SIMPLIFY_POLICY 
00349 
00350         // Try simplifying
00351         try
00352         {
00353 
00354                 double maxTolerance = 0.04;
00355                 double minTolerance = 0.01;
00356                 double tolStep = 0.01;
00357 
00358                 for (double tol = minTolerance; tol <= maxTolerance; tol += tolStep)
00359                 {
00360 #if GEOS_DEBUG_BINARYOP
00361                         std::cerr << "Trying simplifying with tolerance " << tol << std::endl;
00362 #endif
00363 
00364                         GeomPtr rG0( simplify::TopologyPreservingSimplifier::simplify(g0, tol) );
00365                         GeomPtr rG1( simplify::TopologyPreservingSimplifier::simplify(g1, tol) );
00366 
00367                         try
00368                         {
00369                                 ret.reset( _Op(rG0.get(), rG1.get()) );
00370                                 return ret;
00371                         }
00372                         catch (const util::TopologyException& ex)
00373                         {
00374                                 if ( tol >= maxTolerance ) throw ex;
00375 #if GEOS_DEBUG_BINARYOP
00376                                 std::cerr << "Simplified with tolerance (" << tol << "): "
00377                                           << ex.what() << std::endl;
00378 #endif
00379                         }
00380 
00381                 }
00382 
00383                 return ret;
00384 
00385         }
00386         catch (const util::TopologyException& ex)
00387         {
00388 #if GEOS_DEBUG_BINARYOP
00389                 std::cerr << "Simplified: " << ex.what() << std::endl;
00390 #endif
00391         }
00392 
00393 #endif
00394 // USE_TP_SIMPLIFY_POLICY }
00395 
00396         throw origException;
00397 }
00398 
00399 
00400 } // namespace geos::geom
00401 } // namespace geos

Generated on Mon Jan 5 06:17:02 2009 for GEOS by  doxygen 1.4.4