-
Notifications
You must be signed in to change notification settings - Fork 347
/
HeuristicOverlay.cpp
Ignoring revisions in .git-blame-ignore-revs.
790 lines (656 loc) · 23.7 KB
1
2
3
/**********************************************************************
*
* GEOS - Geometry Engine Open Source
4
* http://geos.osgeo.org
5
*
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
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
22
* and returning a result Geometry in an unique_ptr<>.
23
*
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:
*
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.
*
41
* Note that you can skip Grid snapping, Geometry snapping and Simplify policies
42
* by a compile-time define when building geos.
43
44
* See USE_TP_SIMPLIFY_POLICY, USE_PRECISION_REDUCTION_POLICY and
* USE_SNAPPING_POLICY macros below.
45
*
46
47
**********************************************************************/
48
49
#include <geos/geom/HeuristicOverlay.h>
#include <geos/operation/overlay/OverlayOp.h>
50
#include <geos/operation/overlayng/OverlayNG.h>
51
#include <geos/operation/overlayng/OverlayNGRobust.h>
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>
60
61
#include <geos/algorithm/BoundaryNodeRule.h>
62
#include <geos/geom/Geometry.h>
63
64
#include <geos/geom/GeometryCollection.h>
#include <geos/geom/Polygon.h>
65
#include <geos/geom/PrecisionModel.h>
66
#include <geos/geom/GeometryFactory.h>
67
68
#include <geos/precision/CommonBitsRemover.h>
#include <geos/precision/SimpleGeometryPrecisionReducer.h>
69
#include <geos/precision/GeometryPrecisionReducer.h>
70
71
72
#include <geos/operation/overlay/snap/GeometrySnapper.h>
73
#define GEOS_DEBUG_HEURISTICOVERLAY 0
74
75
#define GEOS_DEBUG_HEURISTICOVERLAY_PRINT_INVALID 0
76
77
#ifdef GEOS_DEBUG_HEURISTICOVERLAY
78
79
# include <iostream>
# include <iomanip>
80
# include <sstream>
81
82
#endif
83
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
91
92
93
94
/*
* Always try original input first
*/
#ifndef USE_ORIGINAL_INPUT
95
# define USE_ORIGINAL_INPUT 1
96
97
#endif
98
99
100
101
102
/*
* Check validity of operation between original geometries
*/
#define GEOS_CHECK_ORIGINAL_RESULT_VALIDITY 0
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
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
116
# define USE_PRECISION_REDUCTION_POLICY 1
117
118
#endif
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
130
131
132
133
134
/*
* Define this to use TopologyPreserving simplification policy
* in an attempt at by-passing binary operation
* robustness problems (handles TopologyExceptions)
*/
135
#ifndef USE_TP_SIMPLIFY_POLICY
136
137
138
139
//# define USE_TP_SIMPLIFY_POLICY 1
#endif
/*
140
141
142
* Use common bits removal policy.
* If enabled, this would be tried /before/
* Geometry snapping.
143
144
*/
#ifndef USE_COMMONBITS_POLICY
145
# define USE_COMMONBITS_POLICY 1
146
#endif
147
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.
*
*/
159
#define GEOS_CHECK_COMMONBITS_VALIDITY 1
160
161
162
163
164
165
166
167
/*
* Use snapping policy
*/
#ifndef USE_SNAPPING_POLICY
# define USE_SNAPPING_POLICY 1
#endif
168
169
170
171
172
173
/* Remove common bits before snapping */
#ifndef CBR_BEFORE_SNAPPING
# define CBR_BEFORE_SNAPPING 1
#endif
174
175
176
177
178
/*
* Check validity of result from SnapOp
*/
#define GEOS_CHECK_SNAPPINGOP_VALIDITY 0
179
using geos::operation::overlay::OverlayOp;
180
using geos::operation::overlayng::OverlayNG;
181
182
183
184
namespace geos {
namespace geom { // geos::geom
185
inline bool
186
check_valid(const Geometry& g, const std::string& label, bool doThrow = false, bool validOnly = false)
187
{
188
if(g.isLineal()) {
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");
195
}
196
return false;
197
}
198
199
200
201
202
203
204
}
}
else {
operation::valid::IsValidOp ivo(&g);
if(! ivo.isValid()) {
using operation::valid::TopologyValidationError;
TopologyValidationError* err = ivo.getValidationError();
205
#ifdef GEOS_DEBUG_HEURISTICOVERLAY
206
207
208
209
std::cerr << label << " is INVALID: "
<< err->toString()
<< " (" << std::setprecision(20)
<< err->getCoordinate() << ")"
210
<< std::endl
211
#ifdef GEOS_DEBUG_HEURISTICOVERLAY_PRINT_INVALID
212
213
214
<< "<A>" << std::endl
<< g.toString()
<< std::endl
215
<< "</A>" << std::endl
216
217
#endif
;
218
219
220
#endif
if(doThrow) {
throw geos::util::TopologyException(
221
label + " is invalid: " + err->getMessage(),
222
223
224
err->getCoordinate());
}
return false;
225
}
226
}
227
228
229
return true;
}
230
231
/*
* Attempt to fix noding of multilines and
232
* self-intersection of multipolygons
233
234
235
*
* May return the input untouched.
*/
236
237
inline std::unique_ptr<Geometry>
fix_self_intersections(std::unique_ptr<Geometry> g, const std::string& label)
238
{
239
::geos::ignore_unused_variable_warning(label);
240
#ifdef GEOS_DEBUG_HEURISTICOVERLAY
241
242
std::cerr << label << " fix_self_intersection (UnaryUnion)" << std::endl;
#endif
243
244
245
246
// Only multi-components can be fixed by UnaryUnion
if(! dynamic_cast<const GeometryCollection*>(g.get())) {
return g;
247
}
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;
256
}
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
265
#ifdef GEOS_DEBUG_HEURISTICOVERLAY
266
267
268
std::cerr << label << " ATTEMPT_TO_FIX: " << err->getErrorType() << ": " << *g << std::endl;
#endif
g = g->Union();
269
#ifdef GEOS_DEBUG_HEURISTICOVERLAY
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:
276
#ifdef GEOS_DEBUG_HEURISTICOVERLAY
277
278
279
280
std::cerr << label << " invalidity is: " << err->getErrorType() << std::endl;
#endif
return g;
}
281
282
283
}
284
/// \brief
285
/// Apply an overlay operation to the given geometries
286
287
288
/// after snapping them to each other after common-bits
/// removal.
///
289
std::unique_ptr<Geometry>
290
SnapOp(const Geometry* g0, const Geometry* g1, int opCode)
291
{
292
typedef std::unique_ptr<Geometry> GeomPtr;
293
294
295
//using geos::precision::GeometrySnapper;
using geos::operation::overlay::snap::GeometrySnapper;
296
297
298
// Snap tolerance must be computed on the original
// (not commonbits-removed) geoms
299
double snapTolerance = GeometrySnapper::computeOverlaySnapTolerance(*g0, *g1);
300
#if GEOS_DEBUG_HEURISTICOVERLAY
301
std::cerr << std::setprecision(20) << "Computed snap tolerance: " << snapTolerance << std::endl;
302
#endif
303
304
305
#if CBR_BEFORE_SNAPPING
306
307
308
309
// Compute common bits
geos::precision::CommonBitsRemover cbr;
cbr.add(g0);
cbr.add(g1);
310
#if GEOS_DEBUG_HEURISTICOVERLAY
311
312
std::cerr << "Computed common bits: " << cbr.getCommonCoordinate() << std::endl;
#endif
313
314
// Now remove common bits
315
316
317
318
GeomPtr rG0 = g0->clone();
cbr.removeCommonBits(rG0.get());
GeomPtr rG1 = g1->clone();
cbr.removeCommonBits(rG1.get());
319
320
#if GEOS_DEBUG_HEURISTICOVERLAY
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
328
329
const Geometry& operand0 = *g0;
const Geometry& operand1 = *g1;
330
331
#endif
332
333
334
GeometrySnapper snapper0(operand0);
GeomPtr snapG0(snapper0.snapTo(operand1, snapTolerance));
335
//snapG0 = fix_self_intersections(snapG0, "SNAP: snapped geom 0");
336
337
// NOTE: second geom is snapped on the snapped first one
338
GeometrySnapper snapper1(operand1);
339
GeomPtr snapG1(snapper1.snapTo(*snapG0, snapTolerance));
340
//snapG1 = fix_self_intersections(snapG1, "SNAP: snapped geom 1");
341
342
343
// Run the overlay op
GeomPtr result(OverlayOp::overlayOp(snapG0.get(), snapG1.get(), OverlayOp::OpCode(opCode)));
344
345
#if GEOS_DEBUG_HEURISTICOVERLAY
346
check_valid(*result, "SNAP: result (before common-bits addition");
347
348
349
350
351
#endif
#if CBR_BEFORE_SNAPPING
// Add common bits back in
cbr.addCommonBits(result.get());
352
353
354
//result = fix_self_intersections(result, "SNAP: result (after common-bits addition)");
check_valid(*result, "CBR: result (after common-bits addition)", true);
355
356
357
358
#endif
return result;
359
360
}
361
362
std::unique_ptr<Geometry>
363
HeuristicOverlay(const Geometry* g0, const Geometry* g1, int opCode)
364
{
365
typedef std::unique_ptr<Geometry> GeomPtr;
366
367
GeomPtr ret;
368
geos::util::TopologyException origException;
369
370
371
372
373
/**************************************************************************/
/*
374
* overlayng::OverlayNGRobust carries out the following steps
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.
*
389
* Running overlayng::OverlayNGRobust at this stage should guarantee
390
391
392
393
394
* that none of the other heuristics are ever needed.
*/
#ifdef USE_OVERLAYNG_SNAPIFNEEDED
#if GEOS_DEBUG_HEURISTICOVERLAY
395
std::cerr << "Trying with OverlayNGRobust" << std::endl;
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.
406
ret = operation::overlayng::OverlayNGRobust::Union(g1);
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.
412
ret = operation::overlayng::OverlayNGRobust::Union(g0);
413
414
}
else {
415
ret = operation::overlayng::OverlayNGRobust::Overlay(g0, g1, opCode);
416
417
418
}
#if GEOS_DEBUG_HEURISTICOVERLAY
419
std::cerr << "Attempt with OverlayNGRobust succeeded" << std::endl;
420
421
422
423
#endif
return ret;
}
424
catch(const std::exception& ex) {
425
::geos::ignore_unused_variable_warning(ex);
426
427
#if GEOS_DEBUG_HEURISTICOVERLAY
428
std::cerr << "OverlayNGRobust: " << ex.what() << std::endl;
429
430
#endif
}
431
432
433
434
check_valid(*g0, "Input geom 0", true, true);
check_valid(*g1, "Input geom 1", true, true);
435
436
437
438
439
#endif // USE_OVERLAYNG_SNAPIFNEEDED }
/**************************************************************************/
440
#ifdef USE_ORIGINAL_INPUT
441
442
// Try with original input
try {
443
#if GEOS_DEBUG_HEURISTICOVERLAY
444
std::cerr << "Trying with original input." << std::endl;
445
#endif
446
ret.reset(OverlayOp::overlayOp(g0, g1, OverlayOp::OpCode(opCode)));
447
448
449
450
451
#if GEOS_CHECK_ORIGINAL_RESULT_VALIDITY
check_valid(*ret, "Overlay result between original inputs", true, true);
#endif
452
#if GEOS_DEBUG_HEURISTICOVERLAY
453
454
std::cerr << "Attempt with original input succeeded" << std::endl;
#endif
455
456
return ret;
}
457
catch(const geos::util::TopologyException& ex) {
458
origException = ex;
459
#if GEOS_DEBUG_HEURISTICOVERLAY
460
std::cerr << "Original exception: " << ex.what() << std::endl;
461
462
#endif
}
463
#endif // USE_ORIGINAL_INPUT
464
465
466
/**************************************************************************/
467
468
469
check_valid(*g0, "Input geom 0", true, true);
check_valid(*g1, "Input geom 1", true, true);
470
#if USE_COMMONBITS_POLICY
471
// Try removing common bits (possibly obsoleted by snapping below)
472
//
473
// NOTE: this policy was _later_ implemented
474
475
476
// in JTS as EnhancedPrecisionOp
// TODO: consider using the now-ported EnhancedPrecisionOp
// here too
477
//
478
try {
479
480
481
482
GeomPtr rG0;
GeomPtr rG1;
precision::CommonBitsRemover cbr;
483
#if GEOS_DEBUG_HEURISTICOVERLAY
484
std::cerr << "Trying with Common Bits Remover (CBR)" << std::endl;
485
#endif
486
487
488
489
cbr.add(g0);
cbr.add(g1);
490
491
492
493
494
rG0 = g0->clone();
cbr.removeCommonBits(rG0.get());
rG1 = g1->clone();
cbr.removeCommonBits(rG1.get());
495
496
#if GEOS_DEBUG_HEURISTICOVERLAY
497
498
check_valid(*rG0, "CBR: geom 0 (after common-bits removal)");
check_valid(*rG1, "CBR: geom 1 (after common-bits removal)");
499
#endif
500
501
ret.reset(OverlayOp::overlayOp(rG0.get(), rG1.get(), OverlayOp::OpCode(opCode)));
502
503
#if GEOS_DEBUG_HEURISTICOVERLAY
504
505
506
check_valid(*ret, "CBR: result (before common-bits addition)");
#endif
507
cbr.addCommonBits(ret.get());
508
509
#if GEOS_CHECK_COMMONBITS_VALIDITY
510
check_valid(*ret, "CBR: result (after common-bits addition)", true);
511
#endif
512
513
#if GEOS_DEBUG_HEURISTICOVERLAY
514
515
std::cerr << "Attempt with CBR succeeded" << std::endl;
#endif
516
517
518
return ret;
}
519
catch(const geos::util::TopologyException& ex) {
520
::geos::ignore_unused_variable_warning(ex);
521
#if GEOS_DEBUG_HEURISTICOVERLAY
522
523
524
std::cerr << "CBR: " << ex.what() << std::endl;
#endif
}
525
#endif
526
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.
535
536
537
// {
#if USE_SNAPPING_POLICY
538
#if GEOS_DEBUG_HEURISTICOVERLAY
539
540
541
542
std::cerr << "Trying with snapping " << std::endl;
#endif
try {
543
ret = SnapOp(g0, g1, opCode);
544
545
546
#if GEOS_CHECK_SNAPPINGOP_VALIDITY
check_valid(*ret, "SNAP: result", true, true);
#endif
547
#if GEOS_DEBUG_HEURISTICOVERLAY
548
std::cerr << "SnapOp succeeded" << std::endl;
549
550
#endif
return ret;
551
552
}
553
catch(const geos::util::TopologyException& ex) {
554
::geos::ignore_unused_variable_warning(ex);
555
#if GEOS_DEBUG_HEURISTICOVERLAY
556
557
558
559
std::cerr << "SNAP: " << ex.what() << std::endl;
#endif
}
560
#endif // USE_SNAPPING_POLICY }
561
562
/**************************************************************************/
563
564
565
566
567
// {
#if USE_PRECISION_REDUCTION_POLICY
568
569
// Try reducing precision
try {
570
long unsigned int g0scale =
571
static_cast<long unsigned int>(g0->getFactory()->getPrecisionModel()->getScale());
572
long unsigned int g1scale =
573
static_cast<long unsigned int>(g1->getFactory()->getPrecisionModel()->getScale());
574
575
#if GEOS_DEBUG_HEURISTICOVERLAY
576
577
std::cerr << "Original input scales are: "
<< g0scale
578
<< " and "
579
580
581
582
<< g1scale
<< std::endl;
#endif
583
584
double maxScale = 1e16; // TODO: compute from input
double minScale = 1; // TODO: compute from input
585
586
// Don't use a scale bigger than the input one
587
588
if(g0scale && static_cast<double>(g0scale) < maxScale) {
maxScale = static_cast<double>(g0scale);
589
}
590
591
if(g1scale && static_cast<double>(g1scale) < maxScale) {
maxScale = static_cast<double>(g1scale);
592
}
593
594
595
for(double scale = maxScale; scale >= minScale; scale /= 10) {
596
PrecisionModel pm(scale);
597
GeometryFactory::Ptr gf = GeometryFactory::create(&pm);
598
#if GEOS_DEBUG_HEURISTICOVERLAY
599
std::cerr << "Trying with scale " << scale << std::endl;
600
601
#endif
602
precision::GeometryPrecisionReducer reducer(*gf);
603
604
reducer.setUseAreaReducer(false);
reducer.setChangePrecisionModel(true);
605
606
GeomPtr rG0(reducer.reduce(*g0));
GeomPtr rG1(reducer.reduce(*g1));
607
608
#if GEOS_DEBUG_HEURISTICOVERLAY
609
610
611
612
check_valid(*rG0, "PR: geom 0 (after precision reduction)");
check_valid(*rG1, "PR: geom 1 (after precision reduction)");
#endif
613
try {
614
ret.reset(OverlayOp::overlayOp(rG0.get(), rG1.get(), OverlayOp::OpCode(opCode)));
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()));
}
622
623
624
625
626
#if GEOS_CHECK_PRECISION_REDUCTION_VALIDITY
check_valid(*ret, "PR: result (after restore of original precision)", true);
#endif
627
#if GEOS_DEBUG_HEURISTICOVERLAY
628
629
std::cerr << "Attempt with scale " << scale << " succeeded" << std::endl;
#endif
630
631
return ret;
}
632
catch(const geos::util::TopologyException& ex) {
633
#if GEOS_DEBUG_HEURISTICOVERLAY
634
std::cerr << "Reduced with scale (" << scale << "): "
635
636
<< ex.what() << std::endl;
#endif
637
638
if(scale == 1) {
throw ex;
639
}
640
}
641
642
643
644
}
}
645
catch(const geos::util::TopologyException& ex) {
646
#if GEOS_DEBUG_HEURISTICOVERLAY
647
648
std::cerr << "Reduced: " << ex.what() << std::endl;
#endif
649
::geos::ignore_unused_variable_warning(ex);
650
651
}
652
653
654
#endif
// USE_PRECISION_REDUCTION_POLICY }
655
656
/**************************************************************************/
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 }
724
/**************************************************************************/
725
726
// {
727
#if USE_TP_SIMPLIFY_POLICY
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) {
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 {
745
ret.reset(OverlayOp::overlayOp(rG0.get(), rG1.get(), geos::operation::overlay::OverlayOp::OpCode(opCode)));
746
747
return ret;
}
748
catch(const geos::util::TopologyException& ex) {
749
750
if(tol >= maxTolerance) {
throw ex;
751
}
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;
}
763
catch(const geos::util::TopologyException& ex) {
764
#if GEOS_DEBUG_HEURISTICOVERLAY
765
766
767
std::cerr << "Simplified: " << ex.what() << std::endl;
#endif
}
768
769
770
771
#endif
// USE_TP_SIMPLIFY_POLICY }
772
/**************************************************************************/
773
774
#if GEOS_DEBUG_HEURISTICOVERLAY
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
785
throw origException;
786
787
}
788
789
790
} // namespace geos::geom
} // namespace geos