Skip to content
Ignoring revisions in .git-blame-ignore-revs.

Latest commit

 

History

History
790 lines (656 loc) · 23.7 KB

HeuristicOverlay.cpp

File metadata and controls

790 lines (656 loc) · 23.7 KB
 
1
2
3
/**********************************************************************
*
* GEOS - Geometry Engine Open Source
Jan 16, 2012
Jan 16, 2012
4
* http://geos.osgeo.org
Sep 14, 2020
Sep 14, 2020
6
* Copyright (C) 2013-2020 Sandro Santilli <strk@kbt.io>
7
8
9
10
* Copyright (C) 2006 Refractions Research Inc.
*
* This is free software; you can redistribute and/or modify it under
* the terms of the GNU Lesser General Public Licence as published
Apr 7, 2017
Apr 7, 2017
11
* by the Free Software Foundation.
12
13
14
15
16
17
18
19
20
21
* See the COPYING file for more information.
*
**********************************************************************
*
* Last port: ORIGINAL WORK
*
**********************************************************************
*
* This file provides a single templated function, taking two
* const Geometry pointers, applying a binary operator to them
Sep 7, 2017
Sep 7, 2017
22
* and returning a result Geometry in an unique_ptr<>.
May 17, 2006
May 17, 2006
24
* The binary operator is expected to take two const Geometry pointers
25
26
27
28
29
30
31
32
* and return a newly allocated Geometry pointer, possibly throwing
* a TopologyException to signal it couldn't succeed due to robustness
* issues.
*
* This function will catch TopologyExceptions and try again with
* slightly modified versions of the input. The following heuristic
* is used:
*
Sep 15, 2020
Sep 15, 2020
33
34
35
36
37
* - Try with original input.
* - Try removing common bits from input coordinate values
* - Try snaping input geometries to each other
* - Try snaping input coordinates to a increasing grid (size from 1/25 to 1)
* - Try simplifiying input with increasing tolerance (from 0.01 to 0.04)
38
39
40
*
* If none of the step succeeds the original exception is thrown.
*
Jul 26, 2006
Jul 26, 2006
41
* Note that you can skip Grid snapping, Geometry snapping and Simplify policies
May 18, 2006
May 18, 2006
42
* by a compile-time define when building geos.
Jul 26, 2006
Jul 26, 2006
43
44
* See USE_TP_SIMPLIFY_POLICY, USE_PRECISION_REDUCTION_POLICY and
* USE_SNAPPING_POLICY macros below.
May 18, 2006
May 18, 2006
45
*
46
47
**********************************************************************/
Sep 14, 2020
Sep 14, 2020
48
49
#include <geos/geom/HeuristicOverlay.h>
#include <geos/operation/overlay/OverlayOp.h>
Sep 14, 2020
Sep 14, 2020
50
#include <geos/operation/overlayng/OverlayNG.h>
Sep 16, 2020
Sep 16, 2020
51
#include <geos/operation/overlayng/OverlayNGRobust.h>
Sep 14, 2020
Sep 14, 2020
52
53
54
55
56
57
58
59
#include <geos/simplify/TopologyPreservingSimplifier.h>
#include <geos/operation/IsSimpleOp.h>
#include <geos/operation/valid/IsValidOp.h>
#include <geos/operation/valid/TopologyValidationError.h>
#include <geos/util/TopologyException.h>
#include <geos/util.h>
Apr 17, 2009
Apr 17, 2009
60
Jul 31, 2013
Jul 31, 2013
61
#include <geos/algorithm/BoundaryNodeRule.h>
62
#include <geos/geom/Geometry.h>
Jan 17, 2013
Jan 17, 2013
63
64
#include <geos/geom/GeometryCollection.h>
#include <geos/geom/Polygon.h>
65
#include <geos/geom/PrecisionModel.h>
Jul 31, 2013
Jul 31, 2013
66
#include <geos/geom/GeometryFactory.h>
67
68
#include <geos/precision/CommonBitsRemover.h>
#include <geos/precision/SimpleGeometryPrecisionReducer.h>
Jul 31, 2013
Jul 31, 2013
69
#include <geos/precision/GeometryPrecisionReducer.h>
May 5, 2009
May 5, 2009
70
71
72
#include <geos/operation/overlay/snap/GeometrySnapper.h>
Sep 14, 2020
Sep 14, 2020
73
#define GEOS_DEBUG_HEURISTICOVERLAY 0
Sep 14, 2020
Sep 14, 2020
74
75
#define GEOS_DEBUG_HEURISTICOVERLAY_PRINT_INVALID 0
Sep 14, 2020
Sep 14, 2020
77
#ifdef GEOS_DEBUG_HEURISTICOVERLAY
Aug 27, 2010
Aug 27, 2010
78
79
# include <iostream>
# include <iomanip>
Dec 15, 2011
Dec 15, 2011
80
# include <sstream>
Aug 27, 2010
Aug 27, 2010
81
82
#endif
Oct 9, 2006
Oct 9, 2006
83
Sep 15, 2020
Sep 15, 2020
84
85
86
87
88
89
90
/*
* Define this to use OverlayNG policy with whatever precision
*/
#if ! defined(USE_OVERLAYNG_SNAPIFNEEDED) && defined(USE_OVERLAYNG)
# define USE_OVERLAYNG_SNAPIFNEEDED
#endif
Oct 9, 2006
Oct 9, 2006
91
92
93
94
/*
* Always try original input first
*/
#ifndef USE_ORIGINAL_INPUT
Oct 24, 2006
Oct 24, 2006
95
# define USE_ORIGINAL_INPUT 1
Oct 9, 2006
Oct 9, 2006
96
97
#endif
Jun 30, 2017
Jun 30, 2017
98
99
100
101
102
/*
* Check validity of operation between original geometries
*/
#define GEOS_CHECK_ORIGINAL_RESULT_VALIDITY 0
Sep 14, 2020
Sep 14, 2020
103
104
105
106
107
108
109
/*
* Define this to use OverlayNG policy with fixed precision
*/
#ifndef USE_FIXED_PRECISION_OVERLAYNG
# define USE_FIXED_PRECISION_OVERLAYNG 0
#endif
May 18, 2006
May 18, 2006
110
111
112
113
114
115
/*
* Define this to use PrecisionReduction policy
* in an attempt at by-passing binary operation
* robustness problems (handles TopologyExceptions)
*/
#ifndef USE_PRECISION_REDUCTION_POLICY
Jul 31, 2013
Jul 31, 2013
116
# define USE_PRECISION_REDUCTION_POLICY 1
May 18, 2006
May 18, 2006
117
118
#endif
Jun 30, 2017
Jun 30, 2017
119
120
121
122
123
124
125
126
127
128
129
/*
* Check validity of operation performed
* by precision reduction policy.
*
* Precision reduction policy reduces precision of inputs
* and restores it in the result. The restore phase may
* introduce invalidities.
*
*/
#define GEOS_CHECK_PRECISION_REDUCTION_VALIDITY 0
May 18, 2006
May 18, 2006
130
131
132
133
134
/*
* Define this to use TopologyPreserving simplification policy
* in an attempt at by-passing binary operation
* robustness problems (handles TopologyExceptions)
*/
Apr 7, 2017
Apr 7, 2017
135
#ifndef USE_TP_SIMPLIFY_POLICY
Oct 9, 2006
Oct 9, 2006
136
137
138
139
//# define USE_TP_SIMPLIFY_POLICY 1
#endif
/*
Nov 8, 2006
Nov 8, 2006
140
141
142
* Use common bits removal policy.
* If enabled, this would be tried /before/
* Geometry snapping.
Oct 9, 2006
Oct 9, 2006
143
144
*/
#ifndef USE_COMMONBITS_POLICY
Nov 8, 2006
Nov 8, 2006
145
# define USE_COMMONBITS_POLICY 1
May 18, 2006
May 18, 2006
146
#endif
Aug 27, 2010
Aug 27, 2010
148
149
150
151
152
153
154
155
156
157
158
/*
* Check validity of operation performed
* by common bits removal policy.
*
* This matches what EnhancedPrecisionOp does in JTS
* and fixes 5 tests of invalid outputs in our testsuite
* (stmlf-cases-20061020-invalid-output.xml)
* and breaks 1 test (robustness-invalid-output.xml) so much
* to prevent a result.
*
*/
Aug 27, 2010
Aug 27, 2010
159
#define GEOS_CHECK_COMMONBITS_VALIDITY 1
Aug 27, 2010
Aug 27, 2010
160
Jul 26, 2006
Jul 26, 2006
161
162
163
164
165
166
167
/*
* Use snapping policy
*/
#ifndef USE_SNAPPING_POLICY
# define USE_SNAPPING_POLICY 1
#endif
Jul 11, 2017
Jul 11, 2017
168
169
170
171
172
173
/* Remove common bits before snapping */
#ifndef CBR_BEFORE_SNAPPING
# define CBR_BEFORE_SNAPPING 1
#endif
Jun 30, 2017
Jun 30, 2017
174
175
176
177
178
/*
* Check validity of result from SnapOp
*/
#define GEOS_CHECK_SNAPPINGOP_VALIDITY 0
Sep 14, 2020
Sep 14, 2020
179
using geos::operation::overlay::OverlayOp;
Sep 14, 2020
Sep 14, 2020
180
using geos::operation::overlayng::OverlayNG;
Jun 30, 2017
Jun 30, 2017
181
182
183
184
namespace geos {
namespace geom { // geos::geom
Apr 17, 2009
Apr 17, 2009
185
inline bool
Jul 31, 2013
Jul 31, 2013
186
check_valid(const Geometry& g, const std::string& label, bool doThrow = false, bool validOnly = false)
Oct 23, 2006
Oct 23, 2006
187
{
Jun 14, 2019
Jun 14, 2019
188
if(g.isLineal()) {
Jul 31, 2013
Jul 31, 2013
189
190
191
192
193
194
if(! validOnly) {
operation::IsSimpleOp sop(g, algorithm::BoundaryNodeRule::getBoundaryEndPoint());
if(! sop.isSimple()) {
if(doThrow) {
throw geos::util::TopologyException(
label + " is not simple");
Feb 1, 2019
Feb 1, 2019
195
}
Jul 31, 2013
Jul 31, 2013
196
return false;
Feb 1, 2019
Feb 1, 2019
197
}
Jul 31, 2013
Jul 31, 2013
198
199
200
201
202
203
204
}
}
else {
operation::valid::IsValidOp ivo(&g);
if(! ivo.isValid()) {
using operation::valid::TopologyValidationError;
TopologyValidationError* err = ivo.getValidationError();
Sep 14, 2020
Sep 14, 2020
205
#ifdef GEOS_DEBUG_HEURISTICOVERLAY
Jul 31, 2013
Jul 31, 2013
206
207
208
209
std::cerr << label << " is INVALID: "
<< err->toString()
<< " (" << std::setprecision(20)
<< err->getCoordinate() << ")"
Jun 30, 2017
Jun 30, 2017
210
<< std::endl
Sep 14, 2020
Sep 14, 2020
211
#ifdef GEOS_DEBUG_HEURISTICOVERLAY_PRINT_INVALID
Jun 30, 2017
Jun 30, 2017
212
213
214
<< "<A>" << std::endl
<< g.toString()
<< std::endl
Sep 1, 2017
Sep 1, 2017
215
<< "</A>" << std::endl
Jun 30, 2017
Jun 30, 2017
216
217
#endif
;
Jul 31, 2013
Jul 31, 2013
218
219
220
#endif
if(doThrow) {
throw geos::util::TopologyException(
Sep 16, 2020
Sep 16, 2020
221
label + " is invalid: " + err->getMessage(),
Jul 31, 2013
Jul 31, 2013
222
223
224
err->getCoordinate());
}
return false;
Feb 1, 2019
Feb 1, 2019
225
}
Apr 7, 2017
Apr 7, 2017
226
}
Oct 23, 2006
Oct 23, 2006
227
228
229
return true;
}
Jan 17, 2013
Jan 17, 2013
230
231
/*
* Attempt to fix noding of multilines and
Apr 7, 2017
Apr 7, 2017
232
* self-intersection of multipolygons
Jan 17, 2013
Jan 17, 2013
233
234
235
*
* May return the input untouched.
*/
Sep 7, 2017
Sep 7, 2017
236
237
inline std::unique_ptr<Geometry>
fix_self_intersections(std::unique_ptr<Geometry> g, const std::string& label)
Dec 15, 2011
Dec 15, 2011
238
{
Aug 28, 2013
Aug 28, 2013
239
::geos::ignore_unused_variable_warning(label);
Sep 14, 2020
Sep 14, 2020
240
#ifdef GEOS_DEBUG_HEURISTICOVERLAY
Sep 10, 2012
Sep 10, 2012
241
242
std::cerr << label << " fix_self_intersection (UnaryUnion)" << std::endl;
#endif
Jan 17, 2013
Jan 17, 2013
243
244
245
246
// Only multi-components can be fixed by UnaryUnion
if(! dynamic_cast<const GeometryCollection*>(g.get())) {
return g;
Feb 1, 2019
Feb 1, 2019
247
}
Jan 17, 2013
Jan 17, 2013
248
249
250
251
252
253
254
255
using operation::valid::IsValidOp;
IsValidOp ivo(g.get());
// Polygon is valid, nothing to do
if(ivo.isValid()) {
return g;
Feb 1, 2019
Feb 1, 2019
256
}
Jan 17, 2013
Jan 17, 2013
257
258
259
260
261
262
263
264
// Not all invalidities can be fixed by this code
using operation::valid::TopologyValidationError;
TopologyValidationError* err = ivo.getValidationError();
switch(err->getErrorType()) {
case TopologyValidationError::eRingSelfIntersection:
case TopologyValidationError::eTooFewPoints: // collapsed lines
Sep 14, 2020
Sep 14, 2020
265
#ifdef GEOS_DEBUG_HEURISTICOVERLAY
Jan 17, 2013
Jan 17, 2013
266
267
268
std::cerr << label << " ATTEMPT_TO_FIX: " << err->getErrorType() << ": " << *g << std::endl;
#endif
g = g->Union();
Sep 14, 2020
Sep 14, 2020
269
#ifdef GEOS_DEBUG_HEURISTICOVERLAY
Jan 17, 2013
Jan 17, 2013
270
271
272
273
274
275
std::cerr << label << " ATTEMPT_TO_FIX succeeded.. " << std::endl;
#endif
return g;
case TopologyValidationError::eSelfIntersection:
// this one is within a single component, won't be fixed
default:
Sep 14, 2020
Sep 14, 2020
276
#ifdef GEOS_DEBUG_HEURISTICOVERLAY
Jan 17, 2013
Jan 17, 2013
277
278
279
280
std::cerr << label << " invalidity is: " << err->getErrorType() << std::endl;
#endif
return g;
}
Dec 15, 2011
Dec 15, 2011
281
282
283
}
Oct 23, 2006
Oct 23, 2006
284
/// \brief
Sep 14, 2020
Sep 14, 2020
285
/// Apply an overlay operation to the given geometries
Oct 23, 2006
Oct 23, 2006
286
287
288
/// after snapping them to each other after common-bits
/// removal.
///
Sep 7, 2017
Sep 7, 2017
289
std::unique_ptr<Geometry>
Sep 14, 2020
Sep 14, 2020
290
SnapOp(const Geometry* g0, const Geometry* g1, int opCode)
Oct 9, 2006
Oct 9, 2006
291
{
Sep 7, 2017
Sep 7, 2017
292
typedef std::unique_ptr<Geometry> GeomPtr;
Oct 9, 2006
Oct 9, 2006
293
May 5, 2009
May 5, 2009
294
295
//using geos::precision::GeometrySnapper;
using geos::operation::overlay::snap::GeometrySnapper;
Oct 9, 2006
Oct 9, 2006
296
297
298
// Snap tolerance must be computed on the original
// (not commonbits-removed) geoms
Dec 18, 2006
Dec 18, 2006
299
double snapTolerance = GeometrySnapper::computeOverlaySnapTolerance(*g0, *g1);
Sep 14, 2020
Sep 14, 2020
300
#if GEOS_DEBUG_HEURISTICOVERLAY
Aug 27, 2010
Aug 27, 2010
301
std::cerr << std::setprecision(20) << "Computed snap tolerance: " << snapTolerance << std::endl;
Dec 5, 2006
Dec 5, 2006
302
#endif
Oct 9, 2006
Oct 9, 2006
303
Oct 23, 2006
Oct 23, 2006
304
305
#if CBR_BEFORE_SNAPPING
Aug 23, 2010
Aug 23, 2010
306
307
308
309
// Compute common bits
geos::precision::CommonBitsRemover cbr;
cbr.add(g0);
cbr.add(g1);
Sep 14, 2020
Sep 14, 2020
310
#if GEOS_DEBUG_HEURISTICOVERLAY
Aug 27, 2010
Aug 27, 2010
311
312
std::cerr << "Computed common bits: " << cbr.getCommonCoordinate() << std::endl;
#endif
Aug 23, 2010
Aug 23, 2010
313
Oct 23, 2006
Oct 23, 2006
314
// Now remove common bits
May 29, 2019
May 29, 2019
315
316
317
318
GeomPtr rG0 = g0->clone();
cbr.removeCommonBits(rG0.get());
GeomPtr rG1 = g1->clone();
cbr.removeCommonBits(rG1.get());
Oct 23, 2006
Oct 23, 2006
319
Sep 14, 2020
Sep 14, 2020
320
#if GEOS_DEBUG_HEURISTICOVERLAY
Oct 23, 2006
Oct 23, 2006
321
322
323
324
325
326
327
check_valid(*rG0, "CBR: removed-bits geom 0");
check_valid(*rG1, "CBR: removed-bits geom 1");
#endif
const Geometry& operand0 = *rG0;
const Geometry& operand1 = *rG1;
#else // don't CBR before snapping
Dec 15, 2011
Dec 15, 2011
328
329
const Geometry& operand0 = *g0;
const Geometry& operand1 = *g1;
Oct 23, 2006
Oct 23, 2006
330
331
#endif
Aug 27, 2010
Aug 27, 2010
332
Oct 23, 2006
Oct 23, 2006
333
334
GeometrySnapper snapper0(operand0);
GeomPtr snapG0(snapper0.snapTo(operand1, snapTolerance));
Jul 31, 2013
Jul 31, 2013
335
//snapG0 = fix_self_intersections(snapG0, "SNAP: snapped geom 0");
Oct 9, 2006
Oct 9, 2006
336
337
// NOTE: second geom is snapped on the snapped first one
Oct 23, 2006
Oct 23, 2006
338
GeometrySnapper snapper1(operand1);
Oct 17, 2006
Oct 17, 2006
339
GeomPtr snapG1(snapper1.snapTo(*snapG0, snapTolerance));
Jul 31, 2013
Jul 31, 2013
340
//snapG1 = fix_self_intersections(snapG1, "SNAP: snapped geom 1");
Oct 9, 2006
Oct 9, 2006
341
Sep 14, 2020
Sep 14, 2020
342
343
// Run the overlay op
GeomPtr result(OverlayOp::overlayOp(snapG0.get(), snapG1.get(), OverlayOp::OpCode(opCode)));
Oct 23, 2006
Oct 23, 2006
344
Sep 14, 2020
Sep 14, 2020
345
#if GEOS_DEBUG_HEURISTICOVERLAY
Aug 23, 2010
Aug 23, 2010
346
check_valid(*result, "SNAP: result (before common-bits addition");
Oct 23, 2006
Oct 23, 2006
347
348
349
350
351
#endif
#if CBR_BEFORE_SNAPPING
// Add common bits back in
cbr.addCommonBits(result.get());
Jul 31, 2013
Jul 31, 2013
352
353
354
//result = fix_self_intersections(result, "SNAP: result (after common-bits addition)");
check_valid(*result, "CBR: result (after common-bits addition)", true);
Oct 23, 2006
Oct 23, 2006
355
356
357
358
#endif
return result;
Oct 9, 2006
Oct 9, 2006
359
360
}
Sep 14, 2020
Sep 14, 2020
361
Sep 7, 2017
Sep 7, 2017
362
std::unique_ptr<Geometry>
Sep 14, 2020
Sep 14, 2020
363
HeuristicOverlay(const Geometry* g0, const Geometry* g1, int opCode)
Sep 7, 2017
Sep 7, 2017
365
typedef std::unique_ptr<Geometry> GeomPtr;
Feb 13, 2011
Feb 13, 2011
368
geos::util::TopologyException origException;
Sep 15, 2020
Sep 15, 2020
370
371
372
373
/**************************************************************************/
/*
Sep 16, 2020
Sep 16, 2020
374
* overlayng::OverlayNGRobust carries out the following steps
Sep 15, 2020
Sep 15, 2020
375
376
377
378
379
380
381
382
383
384
385
386
387
388
*
* 1. Perform overlay operation using PrecisionModel(float).
* If no exception return result.
* 2. Perform overlay operation using SnappingNoder(tolerance), starting
* with a very very small tolerance and increasing it for 5 iterations.
* The SnappingNoder moves only nodes that are within tolerance of
* other nodes and lines, leaving all the rest undisturbed, for a very
* clean result, if it manages to create one.
* If a result is found with no exception, return.
* 3. Peform overlay operation using a PrecisionModel(scale), which
* uses a SnapRoundingNoder. Every vertex will be noded to the snapping
* grid, resulting in a modified geometry. The SnapRoundingNoder approach
* reliably produces results, assuming valid inputs.
*
Sep 16, 2020
Sep 16, 2020
389
* Running overlayng::OverlayNGRobust at this stage should guarantee
Sep 15, 2020
Sep 15, 2020
390
391
392
393
394
* that none of the other heuristics are ever needed.
*/
#ifdef USE_OVERLAYNG_SNAPIFNEEDED
#if GEOS_DEBUG_HEURISTICOVERLAY
Sep 16, 2020
Sep 16, 2020
395
std::cerr << "Trying with OverlayNGRobust" << std::endl;
Sep 15, 2020
Sep 15, 2020
396
397
398
399
400
401
402
403
404
405
#endif
try {
if (g0 == nullptr && g1 == nullptr) {
return std::unique_ptr<Geometry>(nullptr);
}
else if (g0 == nullptr) {
// Use a uniary union for the one-parameter case, as the pairwise
// union with one parameter is very intolerant to invalid
// collections and multi-polygons.
Sep 16, 2020
Sep 16, 2020
406
ret = operation::overlayng::OverlayNGRobust::Union(g1);
Sep 15, 2020
Sep 15, 2020
407
408
409
410
411
}
else if (g1 == nullptr) {
// Use a uniary union for the one-parameter case, as the pairwise
// union with one parameter is very intolerant to invalid
// collections and multi-polygons.
Sep 16, 2020
Sep 16, 2020
412
ret = operation::overlayng::OverlayNGRobust::Union(g0);
Sep 15, 2020
Sep 15, 2020
413
414
}
else {
Sep 16, 2020
Sep 16, 2020
415
ret = operation::overlayng::OverlayNGRobust::Overlay(g0, g1, opCode);
Sep 15, 2020
Sep 15, 2020
416
417
418
}
#if GEOS_DEBUG_HEURISTICOVERLAY
Sep 16, 2020
Sep 16, 2020
419
std::cerr << "Attempt with OverlayNGRobust succeeded" << std::endl;
Sep 15, 2020
Sep 15, 2020
420
421
422
423
#endif
return ret;
}
Sep 16, 2020
Sep 16, 2020
424
catch(const std::exception& ex) {
Sep 15, 2020
Sep 15, 2020
425
::geos::ignore_unused_variable_warning(ex);
Sep 16, 2020
Sep 16, 2020
426
Sep 15, 2020
Sep 15, 2020
427
#if GEOS_DEBUG_HEURISTICOVERLAY
Sep 16, 2020
Sep 16, 2020
428
std::cerr << "OverlayNGRobust: " << ex.what() << std::endl;
Sep 15, 2020
Sep 15, 2020
429
430
#endif
}
Sep 16, 2020
Sep 16, 2020
431
432
433
434
check_valid(*g0, "Input geom 0", true, true);
check_valid(*g1, "Input geom 1", true, true);
Sep 15, 2020
Sep 15, 2020
435
436
437
438
439
#endif // USE_OVERLAYNG_SNAPIFNEEDED }
/**************************************************************************/
Oct 9, 2006
Oct 9, 2006
440
#ifdef USE_ORIGINAL_INPUT
441
442
// Try with original input
try {
Sep 14, 2020
Sep 14, 2020
443
#if GEOS_DEBUG_HEURISTICOVERLAY
Oct 9, 2006
Oct 9, 2006
444
std::cerr << "Trying with original input." << std::endl;
Jul 26, 2006
Jul 26, 2006
445
#endif
Sep 14, 2020
Sep 14, 2020
446
ret.reset(OverlayOp::overlayOp(g0, g1, OverlayOp::OpCode(opCode)));
Jun 30, 2017
Jun 30, 2017
447
448
449
450
451
#if GEOS_CHECK_ORIGINAL_RESULT_VALIDITY
check_valid(*ret, "Overlay result between original inputs", true, true);
#endif
Sep 14, 2020
Sep 14, 2020
452
#if GEOS_DEBUG_HEURISTICOVERLAY
Jun 30, 2017
Jun 30, 2017
453
454
std::cerr << "Attempt with original input succeeded" << std::endl;
#endif
Feb 13, 2011
Feb 13, 2011
457
catch(const geos::util::TopologyException& ex) {
Sep 14, 2020
Sep 14, 2020
459
#if GEOS_DEBUG_HEURISTICOVERLAY
Apr 20, 2006
Apr 20, 2006
460
std::cerr << "Original exception: " << ex.what() << std::endl;
Oct 9, 2006
Oct 9, 2006
463
#endif // USE_ORIGINAL_INPUT
Sep 15, 2020
Sep 15, 2020
465
466
/**************************************************************************/
Jun 30, 2017
Jun 30, 2017
467
468
469
check_valid(*g0, "Input geom 0", true, true);
check_valid(*g1, "Input geom 1", true, true);
Jul 11, 2017
Jul 11, 2017
470
#if USE_COMMONBITS_POLICY
Sep 5, 2006
Sep 5, 2006
471
// Try removing common bits (possibly obsoleted by snapping below)
Aug 27, 2010
Aug 27, 2010
472
//
Apr 7, 2017
Apr 7, 2017
473
// NOTE: this policy was _later_ implemented
Aug 27, 2010
Aug 27, 2010
474
475
476
// in JTS as EnhancedPrecisionOp
// TODO: consider using the now-ported EnhancedPrecisionOp
// here too
Apr 7, 2017
Apr 7, 2017
477
//
Oct 9, 2006
Oct 9, 2006
479
480
481
482
GeomPtr rG0;
GeomPtr rG1;
precision::CommonBitsRemover cbr;
Sep 14, 2020
Sep 14, 2020
483
#if GEOS_DEBUG_HEURISTICOVERLAY
Aug 23, 2010
Aug 23, 2010
484
std::cerr << "Trying with Common Bits Remover (CBR)" << std::endl;
Apr 20, 2006
Apr 20, 2006
485
#endif
486
487
488
489
cbr.add(g0);
cbr.add(g1);
May 29, 2019
May 29, 2019
490
491
492
493
494
rG0 = g0->clone();
cbr.removeCommonBits(rG0.get());
rG1 = g1->clone();
cbr.removeCommonBits(rG1.get());
Jul 26, 2006
Jul 26, 2006
495
Sep 14, 2020
Sep 14, 2020
496
#if GEOS_DEBUG_HEURISTICOVERLAY
Aug 23, 2010
Aug 23, 2010
497
498
check_valid(*rG0, "CBR: geom 0 (after common-bits removal)");
check_valid(*rG1, "CBR: geom 1 (after common-bits removal)");
Jul 26, 2006
Jul 26, 2006
499
#endif
Sep 14, 2020
Sep 14, 2020
501
ret.reset(OverlayOp::overlayOp(rG0.get(), rG1.get(), OverlayOp::OpCode(opCode)));
Sep 14, 2020
Sep 14, 2020
503
#if GEOS_DEBUG_HEURISTICOVERLAY
Aug 23, 2010
Aug 23, 2010
504
505
506
check_valid(*ret, "CBR: result (before common-bits addition)");
#endif
Apr 7, 2017
Apr 7, 2017
507
cbr.addCommonBits(ret.get());
Jun 30, 2017
Jun 30, 2017
509
#if GEOS_CHECK_COMMONBITS_VALIDITY
Jul 31, 2013
Jul 31, 2013
510
check_valid(*ret, "CBR: result (after common-bits addition)", true);
Jun 30, 2017
Jun 30, 2017
511
#endif
Aug 23, 2010
Aug 23, 2010
512
Sep 14, 2020
Sep 14, 2020
513
#if GEOS_DEBUG_HEURISTICOVERLAY
Jun 30, 2017
Jun 30, 2017
514
515
std::cerr << "Attempt with CBR succeeded" << std::endl;
#endif
Aug 27, 2010
Aug 27, 2010
516
Feb 13, 2011
Feb 13, 2011
519
catch(const geos::util::TopologyException& ex) {
Dec 1, 2009
Dec 1, 2009
520
::geos::ignore_unused_variable_warning(ex);
Sep 14, 2020
Sep 14, 2020
521
#if GEOS_DEBUG_HEURISTICOVERLAY
522
523
524
std::cerr << "CBR: " << ex.what() << std::endl;
#endif
}
Oct 9, 2006
Oct 9, 2006
525
#endif
Sep 15, 2020
Sep 15, 2020
527
528
529
530
531
532
533
534
/**************************************************************************/
// Try with snapping
//
// TODO: possible optimization would be reusing the
// already common-bit-removed inputs and just
// apply geometry snapping, whereas the current
// SnapOp function does both.
Jul 26, 2006
Jul 26, 2006
535
536
537
// {
#if USE_SNAPPING_POLICY
Sep 14, 2020
Sep 14, 2020
538
#if GEOS_DEBUG_HEURISTICOVERLAY
Jul 26, 2006
Jul 26, 2006
539
540
541
542
std::cerr << "Trying with snapping " << std::endl;
#endif
try {
Sep 14, 2020
Sep 14, 2020
543
ret = SnapOp(g0, g1, opCode);
Jun 30, 2017
Jun 30, 2017
544
545
546
#if GEOS_CHECK_SNAPPINGOP_VALIDITY
check_valid(*ret, "SNAP: result", true, true);
#endif
Sep 14, 2020
Sep 14, 2020
547
#if GEOS_DEBUG_HEURISTICOVERLAY
Jun 30, 2017
Jun 30, 2017
548
std::cerr << "SnapOp succeeded" << std::endl;
Jul 26, 2006
Jul 26, 2006
549
550
#endif
return ret;
Apr 7, 2017
Apr 7, 2017
551
Jul 26, 2006
Jul 26, 2006
552
}
Feb 13, 2011
Feb 13, 2011
553
catch(const geos::util::TopologyException& ex) {
Dec 1, 2009
Dec 1, 2009
554
::geos::ignore_unused_variable_warning(ex);
Sep 14, 2020
Sep 14, 2020
555
#if GEOS_DEBUG_HEURISTICOVERLAY
Jul 26, 2006
Jul 26, 2006
556
557
558
559
std::cerr << "SNAP: " << ex.what() << std::endl;
#endif
}
Oct 9, 2006
Oct 9, 2006
560
#endif // USE_SNAPPING_POLICY }
Jul 26, 2006
Jul 26, 2006
561
Sep 15, 2020
Sep 15, 2020
562
/**************************************************************************/
Sep 14, 2020
Sep 14, 2020
563
May 18, 2006
May 18, 2006
564
565
566
567
// {
#if USE_PRECISION_REDUCTION_POLICY
568
569
// Try reducing precision
try {
Apr 7, 2017
Apr 7, 2017
570
long unsigned int g0scale =
Aug 28, 2013
Aug 28, 2013
571
static_cast<long unsigned int>(g0->getFactory()->getPrecisionModel()->getScale());
Apr 7, 2017
Apr 7, 2017
572
long unsigned int g1scale =
Aug 28, 2013
Aug 28, 2013
573
static_cast<long unsigned int>(g1->getFactory()->getPrecisionModel()->getScale());
Jul 31, 2013
Jul 31, 2013
574
Sep 14, 2020
Sep 14, 2020
575
#if GEOS_DEBUG_HEURISTICOVERLAY
Jul 31, 2013
Jul 31, 2013
576
577
std::cerr << "Original input scales are: "
<< g0scale
Apr 7, 2017
Apr 7, 2017
578
<< " and "
Jul 31, 2013
Jul 31, 2013
579
580
581
582
<< g1scale
<< std::endl;
#endif
Sep 14, 2020
Sep 14, 2020
583
584
double maxScale = 1e16; // TODO: compute from input
double minScale = 1; // TODO: compute from input
Jul 31, 2013
Jul 31, 2013
586
// Don't use a scale bigger than the input one
Feb 5, 2018
Feb 5, 2018
587
588
if(g0scale && static_cast<double>(g0scale) < maxScale) {
maxScale = static_cast<double>(g0scale);
Feb 1, 2019
Feb 1, 2019
589
}
Feb 5, 2018
Feb 5, 2018
590
591
if(g1scale && static_cast<double>(g1scale) < maxScale) {
maxScale = static_cast<double>(g1scale);
Feb 1, 2019
Feb 1, 2019
592
}
Jul 31, 2013
Jul 31, 2013
593
594
Sep 14, 2020
Sep 14, 2020
595
for(double scale = maxScale; scale >= minScale; scale /= 10) {
Jul 31, 2013
Jul 31, 2013
596
PrecisionModel pm(scale);
Sep 7, 2017
Sep 7, 2017
597
GeometryFactory::Ptr gf = GeometryFactory::create(&pm);
Sep 14, 2020
Sep 14, 2020
598
#if GEOS_DEBUG_HEURISTICOVERLAY
Jul 31, 2013
Jul 31, 2013
599
std::cerr << "Trying with scale " << scale << std::endl;
Oct 2, 2015
Oct 2, 2015
602
precision::GeometryPrecisionReducer reducer(*gf);
Sep 14, 2020
Sep 14, 2020
603
604
reducer.setUseAreaReducer(false);
reducer.setChangePrecisionModel(true);
Jul 31, 2013
Jul 31, 2013
605
606
GeomPtr rG0(reducer.reduce(*g0));
GeomPtr rG1(reducer.reduce(*g1));
Sep 14, 2020
Sep 14, 2020
608
#if GEOS_DEBUG_HEURISTICOVERLAY
Jun 30, 2017
Jun 30, 2017
609
610
611
612
check_valid(*rG0, "PR: geom 0 (after precision reduction)");
check_valid(*rG1, "PR: geom 1 (after precision reduction)");
#endif
Sep 14, 2020
Sep 14, 2020
614
ret.reset(OverlayOp::overlayOp(rG0.get(), rG1.get(), OverlayOp::OpCode(opCode)));
Jul 31, 2013
Jul 31, 2013
615
616
617
618
619
620
621
// restore original precision (least precision between inputs)
if(g0->getFactory()->getPrecisionModel()->compareTo(g1->getFactory()->getPrecisionModel()) < 0) {
ret.reset(g0->getFactory()->createGeometry(ret.get()));
}
else {
ret.reset(g1->getFactory()->createGeometry(ret.get()));
}
Jun 30, 2017
Jun 30, 2017
622
623
624
625
626
#if GEOS_CHECK_PRECISION_REDUCTION_VALIDITY
check_valid(*ret, "PR: result (after restore of original precision)", true);
#endif
Sep 14, 2020
Sep 14, 2020
627
#if GEOS_DEBUG_HEURISTICOVERLAY
Jun 30, 2017
Jun 30, 2017
628
629
std::cerr << "Attempt with scale " << scale << " succeeded" << std::endl;
#endif
Feb 13, 2011
Feb 13, 2011
632
catch(const geos::util::TopologyException& ex) {
Sep 14, 2020
Sep 14, 2020
633
#if GEOS_DEBUG_HEURISTICOVERLAY
Jul 31, 2013
Jul 31, 2013
634
std::cerr << "Reduced with scale (" << scale << "): "
635
636
<< ex.what() << std::endl;
#endif
Jun 30, 2017
Jun 30, 2017
637
638
if(scale == 1) {
throw ex;
Feb 1, 2019
Feb 1, 2019
640
}
Feb 13, 2011
Feb 13, 2011
645
catch(const geos::util::TopologyException& ex) {
Sep 14, 2020
Sep 14, 2020
646
#if GEOS_DEBUG_HEURISTICOVERLAY
647
648
std::cerr << "Reduced: " << ex.what() << std::endl;
#endif
Jun 30, 2017
Jun 30, 2017
649
::geos::ignore_unused_variable_warning(ex);
May 18, 2006
May 18, 2006
652
653
654
#endif
// USE_PRECISION_REDUCTION_POLICY }
Sep 15, 2020
Sep 15, 2020
655
656
/**************************************************************************/
Sep 14, 2020
Sep 14, 2020
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
// {
#if USE_FIXED_PRECISION_OVERLAYNG
// Try OverlayNG with fixed precision
try {
long unsigned int g0scale =
static_cast<long unsigned int>(g0->getFactory()->getPrecisionModel()->getScale());
long unsigned int g1scale =
static_cast<long unsigned int>(g1->getFactory()->getPrecisionModel()->getScale());
#if GEOS_DEBUG_HEURISTICOVERLAY
std::cerr << "Original input scales are: "
<< g0scale
<< " and "
<< g1scale
<< std::endl;
#endif
double maxScale = 1e16; // TODO: compute from input
double minScale = 1e10; // TODO: compute from input
// Don't use a scale bigger than the input one
if(g0scale && static_cast<double>(g0scale) < maxScale) {
maxScale = static_cast<double>(g0scale);
}
if(g1scale && static_cast<double>(g1scale) < maxScale) {
maxScale = static_cast<double>(g1scale);
}
for(double scale = maxScale; scale >= minScale; scale /= 10) {
PrecisionModel pm(scale);
#if GEOS_DEBUG_HEURISTICOVERLAY
std::cerr << "Trying with precision scale " << scale << std::endl;
#endif
try {
ret = OverlayNG::overlay(g0, g1, opCode, &pm);
#if GEOS_DEBUG_HEURISTICOVERLAY
std::cerr << "Attempt with fixedNG scale " << scale << " succeeded" << std::endl;
#endif
return ret;
}
catch(const geos::util::TopologyException& ex) {
#if GEOS_DEBUG_HEURISTICOVERLAY
std::cerr << "fixedNG with scale (" << scale << "): "
<< ex.what() << std::endl;
#endif
if(scale == 1) {
throw ex;
}
}
}
}
catch(const geos::util::TopologyException& ex) {
#if GEOS_DEBUG_HEURISTICOVERLAY
std::cerr << "Reduced: " << ex.what() << std::endl;
#endif
::geos::ignore_unused_variable_warning(ex);
}
#endif
// USE_FIXED_PRECISION_OVERLAYNG }
Sep 15, 2020
Sep 15, 2020
724
/**************************************************************************/
Jul 31, 2013
Jul 31, 2013
725
May 18, 2006
May 18, 2006
726
// {
Apr 7, 2017
Apr 7, 2017
727
#if USE_TP_SIMPLIFY_POLICY
May 18, 2006
May 18, 2006
728
729
730
731
732
733
734
735
736
// Try simplifying
try {
double maxTolerance = 0.04;
double minTolerance = 0.01;
double tolStep = 0.01;
for(double tol = minTolerance; tol <= maxTolerance; tol += tolStep) {
Sep 14, 2020
Sep 14, 2020
737
#if GEOS_DEBUG_HEURISTICOVERLAY
738
739
740
741
742
743
744
std::cerr << "Trying simplifying with tolerance " << tol << std::endl;
#endif
GeomPtr rG0(simplify::TopologyPreservingSimplifier::simplify(g0, tol));
GeomPtr rG1(simplify::TopologyPreservingSimplifier::simplify(g1, tol));
try {
Sep 14, 2020
Sep 14, 2020
745
ret.reset(OverlayOp::overlayOp(rG0.get(), rG1.get(), geos::operation::overlay::OverlayOp::OpCode(opCode)));
Feb 13, 2011
Feb 13, 2011
748
catch(const geos::util::TopologyException& ex) {
749
750
if(tol >= maxTolerance) {
throw ex;
Feb 1, 2019
Feb 1, 2019
751
}
Sep 14, 2020
Sep 14, 2020
752
#if GEOS_DEBUG_HEURISTICOVERLAY
753
754
755
756
757
758
759
760
761
762
std::cerr << "Simplified with tolerance (" << tol << "): "
<< ex.what() << std::endl;
#endif
}
}
return ret;
}
Feb 13, 2011
Feb 13, 2011
763
catch(const geos::util::TopologyException& ex) {
Sep 14, 2020
Sep 14, 2020
764
#if GEOS_DEBUG_HEURISTICOVERLAY
765
766
767
std::cerr << "Simplified: " << ex.what() << std::endl;
#endif
}
May 18, 2006
May 18, 2006
768
769
770
771
#endif
// USE_TP_SIMPLIFY_POLICY }
Sep 15, 2020
Sep 15, 2020
772
/**************************************************************************/
Sep 14, 2020
Sep 14, 2020
773
774
#if GEOS_DEBUG_HEURISTICOVERLAY
Jun 30, 2017
Jun 30, 2017
775
776
777
778
779
780
781
782
783
784
std::cerr << "No attempts worked to union " << std::endl;
std::cerr << "Input geometries:" << std::endl
<< "<A>" << std::endl
<< g0->toString() << std::endl
<< "</A>" << std::endl
<< "<B>" << std::endl
<< g1->toString() << std::endl
<< "</B>" << std::endl;
#endif
May 18, 2006
May 18, 2006
785
throw origException;
Oct 9, 2006
Oct 9, 2006
788
789
790
} // namespace geos::geom
} // namespace geos