Skip to content

Commit a9c3a24

Browse files
authored
Merge pull request boostorg#1346 from barendgehrels/fix/issue-1345
fix: add condition to handle_imperfect_touch
2 parents 372e86c + 68d4129 commit a9c3a24

File tree

11 files changed

+135
-11
lines changed

11 files changed

+135
-11
lines changed

doc/release_notes.qbk

+1
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
* [@https://github.com/boostorg/geometry/issues/1293 1293] [@https://github.com/boostorg/geometry/issues/1294 1294] [@https://github.com/boostorg/geometry/issues/1295 1295] Fix traversal through non clustered rings
4545
* [@https://github.com/boostorg/geometry/issues/893 893] [@https://github.com/boostorg/geometry/issues/1299 1299] Fix blocking rings for non union conditions
4646
* [@https://github.com/boostorg/geometry/issues/1342 1342] Fix discarding a start turn for combination with touch
47+
* [@https://github.com/boostorg/geometry/issues/1288 1288] [@https://github.com/boostorg/geometry/issues/1345 1345] Fixes in handling (imperfect) touch
4748

4849
[/=================]
4950
[heading Boost 1.85]

include/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp

+32-5
Original file line numberDiff line numberDiff line change
@@ -343,17 +343,35 @@ struct touch_interior : public base_turn_handler
343343
template
344344
<
345345
typename IntersectionInfo,
346-
typename UniqueSubRange
346+
typename SideCalculator,
347+
typename UniqueSubRange1,
348+
typename UniqueSubRange2
347349
>
348350
static bool handle_as_touch(IntersectionInfo const& info,
349-
UniqueSubRange const& non_touching_range)
351+
SideCalculator const& side,
352+
UniqueSubRange1 const& non_touching_range,
353+
UniqueSubRange2 const& other_range)
350354
{
351355
if BOOST_GEOMETRY_CONSTEXPR (! VerifyPolicy::use_handle_as_touch)
352356
{
353357
return false;
354358
}
355359
else // else prevents unreachable code warning
356360
{
361+
bool const has_k = ! non_touching_range.is_last_segment()
362+
&& ! other_range.is_last_segment();
363+
if (has_k
364+
&& (same(side.pj_wrt_q1(), side.qj_wrt_p2())
365+
|| same(side.pj_wrt_q2(), side.qj_wrt_p1())))
366+
{
367+
// At a touch, the touching points (pj and qj) should be collinear
368+
// with both other segments.
369+
// If that is not the case (both left or both right), it should not be handled as a touch,
370+
// (though the intersection point might be close to the end),
371+
// because segments might cross each other or touch the other in the middle.
372+
return false;
373+
}
374+
357375
//
358376
//
359377
// ^ Q(i) ^ P(i)
@@ -569,7 +587,7 @@ struct touch : public base_turn_handler
569587
// ||
570588
// |^----
571589
// >----->P
572-
// * * they touch here (P/Q are (nearly) on top)
590+
// * * they touch here (P/Q are (nearly) on top of each other)
573591
//
574592
// Q continues from where P comes.
575593
// P continues from where Q comes
@@ -586,6 +604,14 @@ struct touch : public base_turn_handler
586604
// >----->P qj is LEFT of P1 and pi is LEFT of Q2
587605
// (the other way round is also possible)
588606

607+
// There are also cases like this:
608+
// P
609+
// ^
610+
// ||
611+
// ||
612+
// P----^-----<Q
613+
// This code is not for these cases because of the condition opposite(side.pi_wrt_q1(), side.qk_wrt_p2())
614+
589615
auto has_distance = [&](auto const& r1, auto const& r2) -> bool
590616
{
591617
auto const d1 = get_distance_measure(r1.at(0), r1.at(1), r2.at(1), umbrella_strategy);
@@ -674,6 +700,7 @@ struct touch : public base_turn_handler
674700
{
675701
if (side_qk_p1 == 0 && side_pk_q1 == 0
676702
&& has_pk && has_qk
703+
&& opposite(side.pi_wrt_q1(), side.qk_wrt_p2())
677704
&& handle_imperfect_touch(range_p, range_q, side_pk_q2, umbrella_strategy, ti))
678705
{
679706
// If q continues collinearly (opposite) with p, it should be blocked
@@ -1452,7 +1479,7 @@ struct get_turn_info
14521479
if ( inters.d_info().arrival[1] == 1 )
14531480
{
14541481
// Q arrives
1455-
if (handler::handle_as_touch(inters.i_info(), range_p))
1482+
if (handler::handle_as_touch(inters.i_info(), inters.sides(), range_p, range_q))
14561483
{
14571484
handle_as_touch = true;
14581485
}
@@ -1466,7 +1493,7 @@ struct get_turn_info
14661493
else
14671494
{
14681495
// P arrives, swap p/q
1469-
if (handler::handle_as_touch(inters.i_info(), range_q))
1496+
if (handler::handle_as_touch(inters.i_info(), inters.swapped_sides(), range_q, range_p))
14701497
{
14711498
handle_as_touch = true;
14721499
}

include/boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp

+7-6
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,13 @@ struct side_calculator
5858
, m_range_q(range_q)
5959
{}
6060

61+
inline int pi_wrt_q1() const { return m_side_strategy.apply(get_qi(), get_qj(), get_pi()); }
62+
63+
inline int pj_wrt_q1() const { return m_side_strategy.apply(get_qi(), get_qj(), get_pj()); }
64+
inline int pj_wrt_q2() const { return m_side_strategy.apply(get_qj(), get_qk(), get_pj()); }
65+
inline int qj_wrt_p1() const { return m_side_strategy.apply(get_pi(), get_pj(), get_qj()); }
66+
inline int qj_wrt_p2() const { return m_side_strategy.apply(get_pj(), get_pk(), get_qj()); }
67+
6168
inline int pk_wrt_p1() const { return m_side_strategy.apply(get_pi(), get_pj(), get_pk()); }
6269
inline int pk_wrt_q1() const { return m_side_strategy.apply(get_qi(), get_qj(), get_pk()); }
6370
inline int qk_wrt_p1() const { return m_side_strategy.apply(get_pi(), get_pj(), get_qk()); }
@@ -66,12 +73,6 @@ struct side_calculator
6673
inline int pk_wrt_q2() const { return m_side_strategy.apply(get_qj(), get_qk(), get_pk()); }
6774
inline int qk_wrt_p2() const { return m_side_strategy.apply(get_pj(), get_pk(), get_qk()); }
6875

69-
// Necessary when rescaling turns off:
70-
inline int qj_wrt_p1() const { return m_side_strategy.apply(get_pi(), get_pj(), get_qj()); }
71-
inline int qj_wrt_p2() const { return m_side_strategy.apply(get_pj(), get_pk(), get_qj()); }
72-
inline int pj_wrt_q1() const { return m_side_strategy.apply(get_qi(), get_qj(), get_pj()); }
73-
inline int pj_wrt_q2() const { return m_side_strategy.apply(get_qj(), get_qk(), get_pj()); }
74-
7576
inline auto const& get_pi() const { return m_range_p.at(0); }
7677
inline auto const& get_pj() const { return m_range_p.at(1); }
7778
inline auto const& get_pk() const { return m_range_p.at(2); }

test/algorithms/overlay/multi_overlay_cases.hpp

+14
Original file line numberDiff line numberDiff line change
@@ -1580,6 +1580,20 @@ static std::string issue_1109[2] =
15801580
"MULTIPOLYGON(((0 -88,0 -115.40000152587890625,-10 -88,0 -88)))"
15811581
};
15821582

1583+
static std::string issue_1222[2] =
1584+
{
1585+
"MULTIPOLYGON(((2 4,2 2,0 2,0 4,2 4)),((6 4,4 4,2 4,2 6,0 6,0 10,6 10,6 4)))",
1586+
"MULTIPOLYGON(((4 4,4 2,2 2,2 4,4 4)),((4 8,4 6,2 6,2 8,4 8)))"
1587+
};
1588+
1589+
static std::string issue_1288[3] =
1590+
{
1591+
// Issue with differences in behaviour for multi polygon vs polygon
1592+
"MULTIPOLYGON(((-2.0 -1.5, 2.0 -1.5, 2.0 1.5, -2.0 1.5)))",
1593+
"MULTIPOLYGON(((-0.5 -1.49999999, -2.0 -0.1, -1.99999999 -1.5)))",
1594+
"POLYGON((-0.5 -1.49999999, -2.0 -0.1, -1.99999999 -1.5))"
1595+
};
1596+
15831597
static std::string bug_21155501[2] =
15841598
{
15851599
"MULTIPOLYGON(((-8.3935546875 27.449790329784214,4.9658203125 18.729501999072138,11.8212890625 23.563987128451217,9.7119140625 25.48295117535531,9.8876953125 31.728167146023935,8.3056640625 32.99023555965106,8.5693359375 37.16031654673677,-1.8896484375 35.60371874069731,-0.5712890625 32.02670629333614,-8.9208984375 29.458731185355344,-8.3935546875 27.449790329784214)))",

test/algorithms/overlay/overlay_cases.hpp

+53
Original file line numberDiff line numberDiff line change
@@ -1237,6 +1237,59 @@ static std::string issue_1342_b[2] =
12371237
"POLYGON((2.000000861538488 2.944711629068049e-16,2.000000861538488 2.0000008,23.52786548447633 2.0000008,23.52786548447633 2.944711629068049e-16,2.000000861538488 2.944711629068049e-16))"
12381238
};
12391239

1240+
static std::string issue_1345_a[2] =
1241+
{
1242+
// Needs check for opposite in handle_imperfect_touch
1243+
R""""(
1244+
POLYGON((
1245+
-2.0785311235613415 -0.6304193410175202,
1246+
-2.0534946127981359 -0.6304193410175202,
1247+
-2.0534946127981359 -0.8867932112327471,
1248+
-2.3098684830133629 -0.8867932112327471,
1249+
-2.3098684830133629 -0.6554558517807265,
1250+
-2.2848319722501573 -0.6554558517807265,
1251+
-2.0785311235613415 -0.6554558517807265,
1252+
-2.0785311235613415 -0.6304193410175202
1253+
))
1254+
)"""",
1255+
R""""(
1256+
POLYGON((
1257+
-2.0785311235613420 -0.6304193410175202,
1258+
-2.0534946127981359 -0.6304193410175202,
1259+
-2.0534946127981359 -0.6554558517807265,
1260+
-2.0785311235613420 -0.6554558517807265,
1261+
-2.0785311235613420 -0.6304193410175202
1262+
))
1263+
)""""
1264+
};
1265+
1266+
static std::string issue_1345_b[2] =
1267+
{
1268+
// Needs check for opposite in handle_imperfect_touch
1269+
R""""(
1270+
POLYGON((
1271+
-6.1723606999999996 3.2834021000000000,
1272+
-6.1723606999999996 2.8006724999999992,
1273+
-5.7133718999999994 2.8006724999999992,
1274+
-5.7133718999999994 3.2834021000000000,
1275+
-5.6896310999999997 3.2834021000000000,
1276+
-5.6896310999999997 2.7769316999999996,
1277+
-6.1961014999999993 2.7769316999999996,
1278+
-6.1961014999999993 3.2834021000000000,
1279+
-6.1723606999999996 3.2834021000000000
1280+
))
1281+
)"""",
1282+
R""""(
1283+
POLYGON((
1284+
-6.1723606999999996 2.8006724999999997,
1285+
-5.7133718999999994 2.8006724999999997,
1286+
-5.7133718999999994 2.7769316999999996,
1287+
-6.1723606999999996 2.7769316999999996,
1288+
-6.1723606999999996 2.8006724999999997
1289+
))
1290+
)""""
1291+
};
1292+
12401293
static std::string ggl_list_20120229_volker[3] =
12411294
{
12421295
"POLYGON((1716 1554,2076 2250,2436 2352,2796 1248,3156 2484,3516 2688,3516 2688,3156 2484,2796 1248,2436 2352,2076 2250, 1716 1554))",

test/algorithms/set_operations/difference/difference.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -655,6 +655,9 @@ void test_all()
655655
TEST_DIFFERENCE(issue_1342_a, 2, 5.762381026454777, 0, 0.0, 2);
656656
TEST_DIFFERENCE(issue_1342_b, 2, 5.762381026454777, 1, 2.55e-14, 3);
657657

658+
TEST_DIFFERENCE(issue_1345_a, 1, 0.059308854, 0, 0.0, 1);
659+
TEST_DIFFERENCE(issue_1345_b, 2, 0.024048025, 0, 0.0, 2);
660+
658661
TEST_DIFFERENCE(mysql_21977775, 2, 160.856568913, 2, 92.3565689126, 4);
659662
TEST_DIFFERENCE(mysql_21965285, 1, 92.0, 1, 14.0, 1);
660663
TEST_DIFFERENCE(mysql_23023665_1, 1, 92.0, 1, 142.5, 2);

test/algorithms/set_operations/difference/difference_multi.cpp

+10
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,16 @@ void test_areal()
199199

200200
TEST_DIFFERENCE(issue_900, 0, 0.0, 2, 35, 2);
201201

202+
TEST_DIFFERENCE(issue_1222, 2, 32.0, 1, 4.0, 1);
203+
{
204+
// "method: t; operations: c/c;" still happening in the result
205+
// for multi/multi
206+
ut_settings settings;
207+
settings.set_test_validity(BG_IF_TEST_FAILURES);
208+
settings.validity_of_sym = BG_IF_TEST_FAILURES;
209+
TEST_DIFFERENCE_WITH(0, 1, issue_1288, 2, 10.95, 0, 0.0, 2);
210+
}
211+
202212
// Areas and #clips correspond with POSTGIS (except sym case)
203213
test_one<Polygon, MultiPolygon, MultiPolygon>("case_101_multi",
204214
case_101_multi[0], case_101_multi[1],

test/algorithms/set_operations/intersection/intersection.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,9 @@ void test_areal()
317317
TEST_INTERSECTION(issue_1342_a, 1, -1, 43.05575);
318318
TEST_INTERSECTION(issue_1342_b, 1, -1, 43.05575);
319319

320+
TEST_INTERSECTION(issue_1345_a, 1, -1, 0.00062682687);
321+
TEST_INTERSECTION(issue_1345_b, 1, -1, 0.010896761);
322+
320323
test_one<Polygon, Polygon, Polygon>("buffer_mp1", buffer_mp1[0], buffer_mp1[1],
321324
1, 31, 2.271707796);
322325
test_one<Polygon, Polygon, Polygon>("buffer_mp2", buffer_mp2[0], buffer_mp2[1],

test/algorithms/set_operations/intersection/intersection_multi.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,9 @@ void test_areal()
362362
TEST_INTERSECTION(issue_888_34, 7, -1, 0.0256838);
363363
TEST_INTERSECTION(issue_888_37, 13, -1, 0.0567043);
364364

365+
TEST_INTERSECTION(issue_1222, 1, -1, 4.0);
366+
TEST_INTERSECTION(issue_1288, 1, -1, 1.05);
367+
365368
TEST_INTERSECTION(mysql_23023665_7, 2, 11, 9.80505786783);
366369
TEST_INTERSECTION(mysql_23023665_12, 2, 0, 11.812440191387557);
367370
TEST_INTERSECTION(mysql_regression_1_65_2017_08_31, 2, -1, 29.9022122);

test/algorithms/set_operations/union/union.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,12 @@ void test_areal()
496496
TEST_UNION(issue_1342_b, 1, 0, -1, 48.81812749462214);
497497
TEST_UNION_REV(issue_1342_b, 1, 0, -1, 48.81812749462214);
498498

499+
TEST_UNION(issue_1345_a, 1, 0, -1, 0.059935681);
500+
TEST_UNION_REV(issue_1345_a, 1, 0, -1, 0.059935681);
501+
502+
TEST_UNION(issue_1345_b, 1, 0, -1, 0.034944786);
503+
TEST_UNION_REV(issue_1345_b, 1, 0, -1, 0.034944786);
504+
499505
TEST_UNION(geos_1, 1, 0, -1, expectation_limits(3458.0, 3461.3203125));
500506
TEST_UNION(geos_2, 1, 0, -1, expectation_limits(349.0625, 350.55102539));
501507
TEST_UNION(geos_3, 1, 0, -1, 29391548.4998779);

test/algorithms/set_operations/union/union_multi.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,9 @@ void test_areal()
437437

438438
TEST_UNION(issue_1109, 2, 0, -1, 3946.5);
439439

440+
TEST_UNION(issue_1222, 1, 0, -1, 40.0);
441+
TEST_UNION(issue_1288, 1, 0, -1, 12.0);
442+
440443
// One or two polygons, the ideal case is 1
441444
TEST_UNION(mail_2019_01_21_johan, count_set(1, 2), 0, -1, 0.00058896);
442445

0 commit comments

Comments
 (0)