From ed87d4374317b232e616691b83361016e4a6cc6e Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Mon, 29 Jun 2026 19:59:10 +0200 Subject: [PATCH] fix: nearly identical input should give an intersection Fixes: #1471 --- .../algorithms/detail/overlay/overlay.hpp | 4 ++- .../detail/overlay/select_rings.hpp | 36 ++++++++++++------- .../overlay/multi_overlay_cases.hpp | 16 +++++++++ .../set_operations/set_ops_areal_areal.cpp | 12 +++++++ 4 files changed, 54 insertions(+), 14 deletions(-) diff --git a/include/boost/geometry/algorithms/detail/overlay/overlay.hpp b/include/boost/geometry/algorithms/detail/overlay/overlay.hpp index 037886c6a8..e78da2bb6f 100644 --- a/include/boost/geometry/algorithms/detail/overlay/overlay.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/overlay.hpp @@ -342,8 +342,10 @@ struct overlay // Select all rings which are NOT touched by any intersection point std::map selected_ring_properties; + // When the overlay produced no turns, allow a point on the boundary to + // count as within the other geometry (see issue 1471). select_rings(geometry1, geometry2, turn_info_per_ring, - selected_ring_properties, strategy); + selected_ring_properties, strategy, turns.empty()); // Add rings created during traversal { diff --git a/include/boost/geometry/algorithms/detail/overlay/select_rings.hpp b/include/boost/geometry/algorithms/detail/overlay/select_rings.hpp index ab5a37e12f..75b26569b7 100644 --- a/include/boost/geometry/algorithms/detail/overlay/select_rings.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/select_rings.hpp @@ -238,7 +238,8 @@ inline void update_ring_selection(Geometry1 const& geometry1, TurnInfoMap const& turn_info_map, RingPropertyMap const& all_ring_properties, RingPropertyMap& selected_ring_properties, - Strategy const& strategy) + Strategy const& strategy, + bool include_on_boundary = false) { selected_ring_properties.clear(); @@ -261,23 +262,30 @@ inline void update_ring_selection(Geometry1 const& geometry1, continue; } - // Check if the ring is within the other geometry, by taking - // a point lying on the ring + // Check if the ring is within the other geometry, by using + // a point on the ring. + int code = 0; switch(id.source_index) { // within case 0 : - info.within_other = range_in_geometry(pair.second.point, - geometry1, geometry2, - strategy) > 0; + code = range_in_geometry(pair.second.point, + geometry1, geometry2, strategy); break; case 1 : - info.within_other = range_in_geometry(pair.second.point, - geometry2, geometry1, - strategy) > 0; + code = range_in_geometry(pair.second.point, + geometry2, geometry1, strategy); break; } + // Code 0: the point is located on the boundary. Normally such a + // situation is resolved by the turns (the rings are traversed). + // But if the overlay produced no turns at all, and the inputs are (nearly) + // coincident without any segment intersection being detected (such as + // issue 1471), then a point on the boundary should be counted as being + // within the other geometry. + info.within_other = include_on_boundary ? code >= 0 : code > 0; + if (decide::include(id, info)) { auto properties = pair.second; // Copy by value @@ -303,7 +311,8 @@ template inline void select_rings(Geometry1 const& geometry1, Geometry2 const& geometry2, RingTurnInfoMap const& turn_info_per_ring, RingPropertyMap& selected_ring_properties, - Strategy const& strategy) + Strategy const& strategy, + bool include_on_boundary = false) { using tag1 = geometry::tag_t; using tag2 = geometry::tag_t; @@ -318,7 +327,7 @@ inline void select_rings(Geometry1 const& geometry1, Geometry2 const& geometry2, update_ring_selection(geometry1, geometry2, turn_info_per_ring, all_ring_properties, selected_ring_properties, - strategy); + strategy, include_on_boundary); } template @@ -332,7 +341,8 @@ template inline void select_rings(Geometry const& geometry, RingTurnInfoMap const& turn_info_per_ring, RingPropertyMap& selected_ring_properties, - Strategy const& strategy) + Strategy const& strategy, + bool include_on_boundary = false) { RingPropertyMap all_ring_properties; dispatch::select_rings, Geometry>::apply(geometry, @@ -341,7 +351,7 @@ inline void select_rings(Geometry const& geometry, update_ring_selection(geometry, geometry, turn_info_per_ring, all_ring_properties, selected_ring_properties, - strategy); + strategy, include_on_boundary); } diff --git a/test/algorithms/overlay/multi_overlay_cases.hpp b/test/algorithms/overlay/multi_overlay_cases.hpp index 4bd03f2ae6..c780c52eba 100644 --- a/test/algorithms/overlay/multi_overlay_cases.hpp +++ b/test/algorithms/overlay/multi_overlay_cases.hpp @@ -1985,6 +1985,22 @@ static std::string issue_1354[2] = "MULTIPOLYGON(((-161.64096882920154 -24.7006892825620064,-161.289685158351034 -24.4725629993453921,-160.946576972490334 -24.2323160611842638,-160.612062296092091 -23.9802411719655595,-160.286548683761538 -23.7166454461126293,-159.970432723693705 -23.4418500344136262,-159.664099554492026 -23.1561897327487074,-159.367922395936176 -22.8600125741928615,-159.082262094271272 -22.5536794049911933,-158.807466682572255 -22.2375634449233637,-158.543870956719331 -21.9120498325927926,-158.291796067500627 -21.5775351561945712,-158.051549129339492 -21.2344269703338533,-157.823422846122895 -20.8831432994833506,-157.607695154586736 -20.5241121286848909,-157.404628885692887 -20.1577708821155781,-157.21447144440998 -19.7845658901538215,-157.037454508288789 -19.4049518455944927,-156.873793745198554 -19.0193912496758344,-156.723688550569108 -18.6283538485929157,-156.587321804458156 -18.2323160611842603,-156.464859648740173 -17.8317603984888819,-156.356451284688035 -17.4271748758809046,-156.262228791194332 -17.0190524184980028,-156.182306963853506 -16.6078902606880554,-156.116783175101148 -16.1941893402056749,-156.065737255580729 -15.7784536878967323,-156.029231396882096 -15.361189813614395,-156.007310075770846 -14.9429060891149028,-156 -14.5241121286848909,-156 -0.659861765609321083,-156 -0.659861765609321083,-156.007310075770874 -0.24106780517901305,-156.029231396882125 0.177215919320473647,-156.065737255580757 0.594479793602806117,-156.116783175101205 1.01021544591174406,-156.182306963853563 1.42391636639411612,-156.262228791194389 1.8350785242040577,-156.35645128468812 2.24320098158695203,-156.464859648740259 2.64778650419492223,-156.587321804458242 3.04834216689029436,-156.723688550569193 3.44437995429894173,-156.87379374519864 3.83541735538185424,-157.037454508288874 4.22097795130050457,-157.214471444410094 4.6005919958598227,-157.404628885693 4.97379698782157575,-157.60769515458685 5.34013823439087876,-157.823422846123009 5.69916940518932957,-158.051549129339634 6.0504530760398243,-158.291796067500769 6.39356126190053153,-158.543870956719473 6.72807593829874495,-158.807466682572397 7.05358955062930804,-159.082262094271414 7.36970551069712698,-159.367922395936318 7.67603867989878808,-159.664099554492168 7.97221583845462689,-159.970432723693847 8.25787614011953508,-160.28654868376168 8.53267155181853276,-160.612062296092233 8.79626727767145233,-160.946576972490448 9.04834216689014958,-161.289685158351176 9.28858910505127255,-161.640968829201682 9.51671538826787611,-162.000000000000142 9.73244307980402112,-162.366341246569448 9.93550934869787383,-162.739546238531204 10.1256667899807482,-163.119160283090537 10.3026837261019484,-163.504720879009199 10.4663444891921795,-163.89575828009211 10.6164496838216245,-164.291796067500741 10.7528164299325617,-164.692351730196123 10.8752785856505412,-165.096937252804111 10.9836869497026655,-165.505059710186998 11.0779094431963721,-165.916221867996938 11.1578312705371943,-166.329922788479308 11.2233550592895384,-166.745658440788247 11.2744009788099682,-167.162922315070603 11.3109068375085773,-167.581206039570077 11.3328281586198312,-168.000000000000085 11.3401382343906789,-168.418793960430094 11.3328281586198258,-168.837077684929568 11.3109068375085648,-169.254341559211923 11.2744009788099522,-169.670077211520862 11.2233550592895135,-170.083778132003232 11.1578312705371641,-170.494940289813172 11.077909443196333,-170.90306274719606 10.9836869497026228,-171.307648269804048 10.8752785856504914,-171.708203932499401 10.7528164299325084,-172.10424171990806 10.6164496838215658,-172.495279120990972 10.4663444891921138,-172.880839716909634 10.3026837261018773,-173.260453761468966 10.1256667899806718,-173.633658753430694 9.93550934869779212,-174 9.73244307980393408,-174.35903117079846 9.51671538826778551,-174.710314841648966 9.28858910505117663,-175.053423027509666 9.04834216689004656,-175.387937703907909 8.79626727767134398,-175.713451316238462 8.53267155181842085,-176.029567276306295 8.25787614011941784,-176.335900445507946 7.97221583845450077,-176.632077604063795 7.67603867989865307,-176.917737905728728 7.36970551069698487,-177.192533317427717 7.05358955062915793,-177.456129043280669 6.72807593829858508,-177.708203932499373 6.39356126190036278,-177.948450870660508 6.05045307603964844,-178.176577153877105 5.69916940518914394,-178.392304845413264 5.34013823439068602,-178.595371114307113 4.97379698782137414,-178.785528555589991 4.60059199585961309,-178.962545491711211 4.22097795130028608,-179.126206254801446 3.83541735538162776,-179.276311449430892 3.44437995429870725,-179.412678195541844 3.04834216689005189,-179.535140351259827 2.64778650419467221,-179.643548715311965 2.24320098158669401,-179.737771208805668 1.83507852420379303,-179.817693036146494 1.42391636639384433,-179.883216824898852 1.01021544591146517,-179.934262744419271 0.59447979360252079,-179.970768603117904 0.177215919320182214,-179.992689924229154 -0.241067805179310257,-180 -0.659861765609321083,-180 -14.5241121286848909,-179.992689924229154 -14.942906089114862,-179.970768603117904 -15.3611898136143541,-179.9342627444193 -15.7784536878966932,-179.883216824898852 -16.1941893402056394,-179.817693036146494 -16.6078902606880163,-179.737771208805668 -17.0190524184979672,-179.643548715311965 -17.4271748758808691,-179.535140351259827 -17.8317603984888464,-179.412678195541844 -18.2323160611842248,-179.276311449430921 -18.6283538485928801,-179.126206254801474 -19.0193912496758024,-178.962545491711239 -19.4049518455944607,-178.78552855559002 -19.7845658901537895,-178.595371114307142 -20.1577708821155497,-178.392304845413292 -20.5241121286848625,-178.176577153877133 -20.8831432994833222,-177.948450870660508 -21.2344269703338284,-177.708203932499373 -21.5775351561945428,-177.456129043280669 -21.9120498325927642,-177.192533317427745 -22.2375634449233388,-176.917737905728757 -22.5536794049911684,-176.632077604063824 -22.8600125741928366,-176.335900445507974 -23.1561897327486861,-176.029567276306324 -23.4418500344136049,-175.713451316238491 -23.7166454461126079,-175.387937703907909 -23.9802411719655382,-175.053423027509695 -24.2323160611842425,-174.710314841648994 -24.4725629993453779,-174.359031170798488 -24.7006892825619886,-174.000000000000028 -24.9164169740981407,-173.633658753430723 -25.1194832429920041,-173.260453761468938 -25.3096406842748856,-172.880839716909634 -25.4866576203960911,-172.495279120990972 -25.6503183834863329,-172.104241719908032 -25.8004235781157831,-171.708203932499401 -25.9367903242267275,-171.307648269804019 -26.0592524799447105,-170.903062747196032 -26.1676608439968419,-170.494940289813144 -26.2618833374905556,-170.083778132003175 -26.3418051648313849,-169.670077211520805 -26.4073289535837326,-169.254341559211866 -26.4583748731041695,-168.837077684929511 -26.4948807318027804,-168.418793960430037 -26.5168020529140378,-168.000000000000028 -26.5241121286848909,-167.581206039569992 -26.5168020529140378,-167.162922315070517 -26.4948807318027804,-166.745658440788162 -26.4583748731041695,-166.329922788479223 -26.4073289535837361,-165.916221867996853 -26.341805164831392,-165.505059710186913 -26.2618833374905591,-165.096937252803997 -26.167660843996849,-164.692351730196009 -26.0592524799447212,-164.291796067500627 -25.9367903242267381,-163.895758280091997 -25.8004235781157938,-163.504720879009056 -25.6503183834863435,-163.119160283090395 -25.4866576203961053,-162.739546238531091 -25.3096406842748962,-162.366341246569306 -25.1194832429920183,-162 -24.9164169740981585,-161.64096882920154 -24.7006892825620064)))" }; +static std::string issue_1471[2] = +{ + "MULTIPOLYGON(((" + "20.0970444515398512 -0.3449179410282249," + "21.9812157674818778 -0.3449179410282249," + "21.9812157674818778 -2.2293927797379025," + "20.0970444515398512 -2.2293927797379025," + "20.0970444515398512 -0.3449179410282249)))", + "MULTIPOLYGON(((" + "20.0970444515398476 -0.3449179410282246," + "21.9812157674818813 -0.3449179410282246," + "21.9812157674818813 -2.2293927797379034," + "20.0970444515398476 -2.2293927797379034," + "20.0970444515398476 -0.3449179410282246)))" +}; + static std::string bug_21155501[2] = { "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)))", diff --git a/test/algorithms/set_operations/set_ops_areal_areal.cpp b/test/algorithms/set_operations/set_ops_areal_areal.cpp index 2f819673ff..33382b11e5 100644 --- a/test/algorithms/set_operations/set_ops_areal_areal.cpp +++ b/test/algorithms/set_operations/set_ops_areal_areal.cpp @@ -155,6 +155,16 @@ void test_detail(std::string const& name, std::string const& wkt1, std::string c BOOST_CHECK_MESSAGE(bgeo::math::abs(balance) < eps, "Case: " << name << " wrong union or intersection " << balance); + + // The relate-based predicates do not depend on the overlay ring traversal + // If two geometries intersect but do not merely touch, their interiors overlap + // and the intersection cannot be empty. This catches cases such as issue 1471. + BOOST_CHECK_MESSAGE( + ! (bgeo::intersects(geometry1, geometry2) + && ! bgeo::touches(geometry1, geometry2) + && result_intersection.empty()), + "Case: " << name << " geometries intersect (not touching) but the intersection is empty"); + if (settings.test_difference) { BOOST_CHECK_MESSAGE(bgeo::math::abs(balance_d1) < eps, @@ -318,5 +328,7 @@ int test_main(int, char* []) TEST_CASE_WITH(issue_1354, 0, 1, ut_settings().ignore_validity_union().ignore_diff()); #endif + TEST_CASE(issue_1471); + return 0; }