From 7039aba4f7f984e44a9c8a3dcffde92406047318 Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Sat, 14 Dec 2024 12:00:01 +0100 Subject: [PATCH 1/4] test: add test cases --- .../overlay/multi_overlay_cases.hpp | 191 +++++++++++++++++- .../difference/difference_multi.cpp | 1 - .../intersection/intersection_multi.cpp | 1 - .../set_operations/set_ops_areal_areal.cpp | 111 ++++++++-- .../set_operations/union/union_multi.cpp | 1 - 5 files changed, 278 insertions(+), 27 deletions(-) diff --git a/test/algorithms/overlay/multi_overlay_cases.hpp b/test/algorithms/overlay/multi_overlay_cases.hpp index 2fac8f0db5..1f2cd53343 100644 --- a/test/algorithms/overlay/multi_overlay_cases.hpp +++ b/test/algorithms/overlay/multi_overlay_cases.hpp @@ -653,8 +653,157 @@ static std::string case_140_multi[2] = static std::string case_141_multi[2] = { // Version to test more isolation/validity cases - "MULTIPOLYGON(((0 0,0 10,10 10,10 0,0 0),(2 3,1 2,2 1,3 2,2 3),(2 7,3 8,2 9,1 8,2 7),(10 3,9 4,8 3,9 2,10 3),(7 10,6 9,7 8,8 9,7 10),(10 7,9 8,8 7,9 6,10 7)))", - "MULTIPOLYGON(((0 0,0 10,10 10,10 0,0 0),(0 5,2 3,4 5,2 7),(3 2,4 1,5 2,4 3,3 2),(3 8,4 7,5 8,4 9,3 8),(7 2,8 1,9 2,8 2,8 3,7 2),(8 7,7 8,6 7,7 6,8 7)))" + R""""( + MULTIPOLYGON( + ((0 0,0 10,10 10,10 0,0 0), + (2 3,1 2,2 1,3 2,2 3), + (2 7,3 8,2 9,1 8,2 7), + (10 3,9 4,8 3,9 2,10 3), + (7 10,6 9,7 8,8 9,7 10), + (10 7,9 8,8 7,9 6,10 7))) + )"""", + R""""( + MULTIPOLYGON( + ((0 0,0 10,10 10,10 0,0 0), + (0 5,2 3,4 5,2 7), + (3 2,4 1,5 2,4 3,3 2), + (3 8,4 7,5 8,4 9,3 8), + (7 2,8 1,9 2,8 2,8 3,7 2), + (8 7,7 8,6 7,7 6,8 7))) + )"""" +}; + +static std::string case_142_multi[2] = +{ + // Simpler version of 141 with one isolated interior (in intersection), + // no clusters, no self-turns. Only cc, ii and ui turns. + R""""( + MULTIPOLYGON( + ((0 0,0 10,0 10,10 10,10 0,0 0), + (2 7,4 5,6 5,8 7,2 7)) + ) + )"""", + R""""( + MULTIPOLYGON( + ((0 0,0 10,4 10,5 11,6 10,10 10,10 0,0 0), + (5 10,2 7,5 4,8 7,5 10)) + ) + )"""" +}; + +static std::string case_143_multi[2] = +{ + // Same but with one extra inteior + R""""( + MULTIPOLYGON( + ((0 0,0 10,10 10,10 8,10 6,10 4,10 2,10 0,0 0), + (2 7,4 5,6 5,8 7,2 7), + (5 4,4 3,5 2,6 3,5 4) + ) + ) + )"""", + R""""( + MULTIPOLYGON( + ((0 0,0 10,4 10,5 11,6 10,10 10,10 9,10 7,10 5,10 3,10 1,10 0,0 0), + (5 10,2 7,5 4,8 7,5 10)) + ) + )"""" +}; + +static std::string case_144_multi[2] = +{ + // Simple case resulting in two separate exterior rings. + R""""( + MULTIPOLYGON( + ((0 0,0 10,10 10,10 0,0 0), + (2 7,4 5,6 5,8 7,2 7), + (5 4,4 3,5 2,6 3,5 4) + ) + ) + )"""", + R""""( + MULTIPOLYGON( + ((0 0,0 10,4 10,5 11,6 10,10 10,10 9,10 1,10 0,6 0,5 -1,4 0,0 0), + (5 10,2 7,5 4,8 7,5 10), + (4 1,5 0,6 1,5 2,4 1) + ) + ) + )"""" +}; + +static std::string case_145_multi[2] = +{ + // Simpler version of 141 with two isolated interiors, and two variations in the lower corners. + // This gives mainly cc, some ii, and some iu cases. + R""""( + MULTIPOLYGON( + ((0 2,0 9,0 10,2 10,6 10,10 10,10 4,10 0,7 0,2 0,0 2), + (10 7,9 8,8 7,9 6,10 7), + (3 8,5 6,7 8,3 8), + (5 0,6 1,5 2,4 1,5 0)) + ) + )"""", + R""""( + MULTIPOLYGON( + ((0 0,0 1,0 10,4 10,5 11,6 10,10 10,10 4,10 2,8 0,3 0,0 0), + (5 10,3 8,5 6,7 8,5 10), + (0 5,2 3,4 5,2 7)) + ) + )"""" +}; + +static std::string case_146_multi[2] = +{ + // As 141, with an interior ring and a separate island, + // but 1: attached is another isolated interior ring + // and 2: these combined shapes are copied to the left, in reversed order. + R""""( + MULTIPOLYGON( + ((0 0,0 10,10 10,10 0,0 0), + (10 3,9 4,8 3,9 2,10 3), + (2 2,1 3,0 2,1 1,2 2), + (5 3,4 4,3 3,4 2,5 3), + (7 2,6 3,5 2,6 1,7 2), + (7 10,6 9,7 8,8 9,7 10), + (10 7,9 8,8 7,9 6,10 7)) + ) + )"""", + R""""( + MULTIPOLYGON( + ((0 0,0 10,10 10,10 0,0 0), + (7 2,8 1,9 2,8 2,8 3,7 2), + (2 2,3 1,4 2,3 2,3 3,2 2), + (8 7,7 8,6 7,7 6,8 7)) + ) + )"""" +}; + +static std::string case_147_multi[2] = +{ + // Version with touching islands in holes in various ways. + R""""( + MULTIPOLYGON( + ((10 0,0 10,10 20,20 10,10 0), + (5 5,7 5,7 7,5 7,5 5), + (15 5,15 9,11 9,11 5,15 5), + (5 15,5 11,7 11,6 12,7 13,7 15,5 15), + (15 15,11 15,11 11,15 11,15 15)), + ((15 9,14 6,11 5,12 8,15 9)), + ((15 15,14 12,11 11,12 14,15 15)) + ) + )"""", + R""""( + MULTIPOLYGON( + ((10 0,0 10,10 20,20 10,10 0), + (7 7,9 7,9 9,7 9,7 7), + (15 5,15 9,11 9,11 5,15 5), + (7 15,8 14,7 13,7 11,9 11,9 15,7 15), + (15 15,11 15,11 11,15 11,15 15)), + ((15 9,14 6,11 5,12 8,15 9)), + ((15 15,14 12,11 11,12 14,15 15)), + ((7 9,8.5 8.5,9 7,7.5 7.5,7 9)) + ) + )"""" }; static std::string case_recursive_boxes_1[2] = @@ -1528,6 +1677,13 @@ static std::string issue_869_a[2] = "MULTIPOLYGON(((50 50,50 70,70 70,70 50,50 50)),((50 50,50 30,30 30,30 50,50 50)))" }; +// To use intersection for difference research (made valid in tests) +static std::string issue_869_a_inverse[2] = +{ + "MULTIPOLYGON(((70 50,70 10,10 10,10 70,50 70,50 90,70 90,70 70,90 70,90 50,70 50)))", + "MULTIPOLYGON(((0 0,0 100,100 100,100 0,0 0),(50 50,50 70,70 70,70 50,50 50),(50 50,50 30,30 30,30 50,50 50)))" +}; + // For union static std::string issue_869_b[2] = { @@ -1580,12 +1736,24 @@ static std::string issue_1109[2] = "MULTIPOLYGON(((0 -88,0 -115.40000152587890625,-10 -88,0 -88)))" }; +static std::string issue_1221[2] = +{ + "MULTIPOLYGON(((1 2,1 3,0 3,0 4,1 4,1 5,3 5,3 0,0 0,0 2,1 2),(1 2,1 1,2 1,2 2,1 2)))", + "POLYGON((1 3,1 4,2 4,2 3,1 3))" +}; + static std::string issue_1222[2] = { "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)))", "MULTIPOLYGON(((4 4,4 2,2 2,2 4,4 4)),((4 8,4 6,2 6,2 8,4 8)))" }; +static std::string issue_1241[2] = +{ + "POLYGON((-124.19999999845255 51.901455507812500, -124.19999999460376 51.935823093966235, -123.99999999648789 51.935823093966235, -123.99999999317222 51.902564290309876, -124.19999999845255 51.901455507812500))", + "POLYGON((-123.99999999367975 51.907655109375000, -123.99999999291659 51.900000006653443, -124.19999999861555 51.900000005468293, -124.19999999792353 51.906179355468751, -123.99999999367975 51.907655109375000))" +}; + static std::string issue_1288[3] = { // Issue with differences in behaviour for multi polygon vs polygon @@ -1600,12 +1768,31 @@ static std::string issue_1299[2] = "MULTIPOLYGON(((-0.87500000000000000 -0.84999999999999998, -0.87500000000000000 -0.070000000000000201, -1.2549999999999999 -0.070000000000000201, -1.2549999999999999 -0.84999999999999998)))" }; +static std::string issue_1349[2] = +{ + "MULTIPOLYGON(((0 0,0 1178,2002 1178,2002 0,0 0),(1000.99879999999996 124.985299999999995,1011.01279999999997 134.999300000000005,1011.01400000000001 325.002599999999973,1001 335.016599999999983,990.98599999999999 325.002599999999973,990.98479999999995 134.999300000000005,1000.99879999999996 124.985299999999995)))", + "MULTIPOLYGON(((1592.0101999999999407 1149.8399999999999181, 1586.9901999999999589 1149.8399999999999181, 1586.9901999999999589 1178.0000000000000000, 1592.0101999999999407 1178.0000000000000000, 1592.0101999999999407 1149.8399999999999181)), ((2001.9988000000000739 230.0014999999999930, 2001.9988000000000739 0.0015000000000000, 1000.9238000000000284 0.0000000000000000, 1000.9238000000000284 230.0765000000000100, 2001.9988000000000739 230.0014999999999930)))" +}; + +// To use intersection for difference research (made valid in tests) +static std::string issue_1349_inverse[2] = +{ + "MULTIPOLYGON(((0 0,0 1178,2002 1178,2002 0,0 0),(1000.99879999999996 124.985299999999995,1011.01279999999997 134.999300000000005,1011.01400000000001 325.002599999999973,1001 335.016599999999983,990.98599999999999 325.002599999999973,990.98479999999995 134.999300000000005,1000.99879999999996 124.985299999999995)))", + "MULTIPOLYGON(((-1000 -1000,-1000 3000,3000 3000,3000 -1000,-1000 -1000),(1592.0101999999999407 1149.8399999999999181, 1586.9901999999999589 1149.8399999999999181, 1586.9901999999999589 1178.0000000000000000, 1592.0101999999999407 1178.0000000000000000, 1592.0101999999999407 1149.8399999999999181),(2001.9988000000000739 230.0014999999999930, 2001.9988000000000739 0.0015000000000000, 1000.9238000000000284 0.0000000000000000, 1000.9238000000000284 230.0765000000000100, 2001.9988000000000739 230.0014999999999930)))" +}; + static std::string issue_1350_comment[2] = { "MULTIPOLYGON(((2 10,2 8,0 8,0 10,2 10)),((10 8,10 2,8 2,8 0,0 0,0 4,2 4,2 8,4 8,4 10,6 10,6 8,6 6,8 6,8 8,10 8),(8 2,8 4,4 4,4 2,8 2)))", "MULTIPOLYGON(((2 6,2 4,2 2,2 0,0 0,0 6,2 6)),((2 10,2 8,0 8,0 10,2 10)),((6 8,6 6,2 6,2 8,6 8)),((8 4,8 2,6 2,6 4,8 4)),((10 8,10 6,8 6,8 8,10 8)),((8 10,8 8,6 8,6 10,8 10)))" }; +static std::string issue_1354[2] = +{ + "MULTIPOLYGON(((295.199999999999989 -295.199999999999989,295.199999999999989 295.199999999999989,-295.199999999999989 295.199999999999989,-295.199999999999989 -295.199999999999989,295.199999999999989 -295.199999999999989),(-179.997681584096682 -159.068022953381728,-179.997941555125578 -158.950077048237887,-180 -158.832148820362704,-180 -14.5241121286848625,-179.998787156680379 -14.4546283814396119,-179.999195199119924 -14.3851352478099308,-179.995132365653177 -14.2452455437218966,-179.992689924229154 -14.1053181682548523,-179.989052871933012 -14.0359190762519734,-179.987035390416196 -13.9664540354863789,-179.978092951651348 -13.8267913392705939,-179.970768603117904 -13.6870344437553584,-179.96471177303323 -13.6178045590987882,-179.960271225550514 -13.5484522436487858,-179.899302518930739 -12.8010583222347041,-179.862001646775752 -12.4192286301278614,-179.812514069087342 -12.0387864551623842,-179.756717919995367 -11.6575893141408002,-179.69354553378804 -11.2702990769800557,-179.617743949785876 -10.8852814175903685,-179.449050736785438 -10.0966985448598905,-179.370713374286112 -9.75497969251792263,-179.282427103876586 -9.41569507620525137,-179.18426728065765 -9.07913428598321026,-178.935424198586816 -8.27008653807789607,-178.812412221610401 -7.89249729706248626,-178.67697357776251 -7.51918515533267851,-178.52206744438692 -7.11329246102736157,-178.372718942212316 -6.74078412878685995,-178.210997411857903 -6.37347828985937515,-177.83796586524096 -5.56325522558086671,-177.683643331306087 -5.24079944287654875,-177.519784336166936 -4.92308352260890025,-177.346534296916872 -4.61038942260158002,-176.888642811189385 -3.8122348268109878,-176.682925174829364 -3.46716074752500347,-176.4657719066781 -3.12916618508967126,-176.203261097574938 -2.73523344331954199,-175.97364845346371 -2.40292746742542196,-175.732982121071331 -2.078537355980135,-175.143129804051284 -1.310831533374758,-174.920901565835123 -1.03035395323309942,-174.690409107515819 -0.756627283942919782,-174.451857396213086 -0.489894938965182547,-173.780108917183412 0.239037812837519681,-173.533488205359163 0.498765442860035435,-173.279226152669509 0.751017352386726955,-173.017549264610096 0.995568826627545533,-172.318055071282714 1.62999550300293983,-172.067822666567167 1.85068903895734671,-171.811551390238662 2.06434045156852441,-171.549439357600335 2.27078457361611186,-171.281689199261223 2.46986180961050472,-171.031950157793972 2.65021087534550936,-170.768065071279523 2.835433324854856,-170.499299340935181 3.01349982052276921,-170.225846968387685 3.18428182963124229,-169.947905338195852 3.34765607758145833,-169.680262243237394 3.50017672557883053,-169.398031980415396 3.65602528487362832,-169.111716805616084 3.80423566024079918,-168.821523388081118 3.94470086983453072,-168.527661196461878 4.07731952245764262,-168.245202320314831 4.20025185193289374,-167.947883471472693 4.32492822022349799,-167.64732257736847 4.44157230975317141,-167.343736590149689 4.55009992398729324,-167.037344645549581 4.6504327250600852,-166.743329216418374 4.74235824805159822,-166.434352475578294 4.83442381331231275,-166.123013965408205 4.91815568760162414,-165.809538417600521 4.99349343122062095,-165.494152106413281 5.06038266355761301,-165.191972700917376 5.12024067253396975,-164.874903279844006 5.17863311131773951,-164.556379617287462 5.2284866074688674,-164.23663163135754 5.26976517552396029,-163.915890123910316 5.3024390196108131,-163.609033520920434 5.32953882673178825,-163.287530010959983 5.35358436207679489,-162.965496567522251 5.36898423202898734,-162.643165642162018 5.375727320588501,-162.320769901163743 5.37380876043037148,-162.012776848660081 5.36783766723553946,-161.690549005093743 5.35725884322304502,-161.368721650836875 5.33802739140809557,-161.047527088684063 5.31015719351933235,-160.727197164665256 5.27366836694196373,-160.421621523858249 5.23469527250653854,-160.102387459886472 5.18961415576110952,-159.784479686856571 5.13597328949175136,-159.468127678314318 5.07381139297753059,-159.153559784816935 5.00317333618393612,-158.853927522957889 4.93164794210813451,-158.541370807245158 4.85258471329888774,-158.231050880339666 4.7651533822312695,-157.923191738695721 4.66941705896188797,-157.618015602513111 4.56544484829227759,-157.327784107566345 4.46219246969767802,-157.025511260386196 4.35005942129268952,-156.726359890085519 4.22984647550804382,-156.430545931383392 4.1016404049654156,-156.138282909974265 3.96553375191790813,-155.860801096610373 3.83174579432549756,-155.572299975036202 3.68783680385857515,-155.287769000407764 3.53622935297387997,-155.007413554087719 3.37703287560877818,-154.731436003441075 3.21036228364411969,-154.46990567067823 3.04758249561918326,-154.198505222998278 2.87355809593285194,-153.931877781715087 2.69230550356012799,-153.670215804986441 2.50395555102093859,-153.413708166777326 2.30864419388203324,-153.171147053156858 2.11875085407343189,-152.87864945418977 1.88227751953715927,-152.593706706865078 1.63675335759936136,-152.316598756515816 1.38241958634308926,-152.047597851087176 1.11952607895504297,-151.758492641328019 0.827987423984159143,-151.497863063903992 0.556792463263721338,-151.245860873059797 0.277562487870442354,-151.002733651293767 -0.00942816944216584574,-150.768720261787024 -0.303897551347931838,-150.580866676220865 -0.54804178071738896,-150.387712159765329 -0.806177457173726353,-150.201562005690334 -1.06940894241931783,-150.022550581694702 -1.33754622957983571,-149.850807102568638 -1.61039577065407258,-149.690225111389282 -1.87328129413026989,-149.633025334764199 -1.97070420726289952,-149.574266655031067 -2.06719491150401513,-149.526997232690093 -2.15129174077182661,-149.478152856477351 -2.23448369888000897,-149.424387935046411 -2.33384350802175922)))", + "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 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/difference/difference_multi.cpp b/test/algorithms/set_operations/difference/difference_multi.cpp index 734ba09b2d..e98cc17891 100644 --- a/test/algorithms/set_operations/difference/difference_multi.cpp +++ b/test/algorithms/set_operations/difference/difference_multi.cpp @@ -201,7 +201,6 @@ void test_areal() TEST_DIFFERENCE(case_138_multi, 5, 16.6, 3, 8.225, 8); TEST_DIFFERENCE(case_139_multi, 4, 16.328125, 3, 8.078125, 7); TEST_DIFFERENCE(case_140_multi, 4, 16.328125, 3, 8.078125, 7); - TEST_DIFFERENCE(case_141_multi, 5, 15.5, 5, 10.0, 10); // Areas correspond with POSTGIS, // #clips in PostGIS is 11,11,5 but should most probably be be 12,12,6 diff --git a/test/algorithms/set_operations/intersection/intersection_multi.cpp b/test/algorithms/set_operations/intersection/intersection_multi.cpp index ec45ce3fd1..7a2298f37b 100644 --- a/test/algorithms/set_operations/intersection/intersection_multi.cpp +++ b/test/algorithms/set_operations/intersection/intersection_multi.cpp @@ -156,7 +156,6 @@ void test_areal() TEST_INTERSECTION(case_138_multi, 2, 23, 40.4); TEST_INTERSECTION(case_139_multi, 2, 23, 40.546875); TEST_INTERSECTION(case_140_multi, 2, 23, 40.546875); - TEST_INTERSECTION(case_141_multi, 3, -1, 74.5); TEST_INTERSECTION(case_recursive_boxes_1, 10, 89, 47.0); diff --git a/test/algorithms/set_operations/set_ops_areal_areal.cpp b/test/algorithms/set_operations/set_ops_areal_areal.cpp index 6a2b9a835a..f4157119b5 100644 --- a/test/algorithms/set_operations/set_ops_areal_areal.cpp +++ b/test/algorithms/set_operations/set_ops_areal_areal.cpp @@ -17,40 +17,71 @@ // Use another alias, on purpose it is not "bg::" here namespace bgeo = boost::geometry; +// For convenience and to test current failures +#if defined(BOOST_GEOMETRY_TEST_FAILURES) +#define BG_IF_TEST_FAILURES true +#else +#define BG_IF_TEST_FAILURES false +#endif + struct ut_settings { explicit ut_settings() {} + inline ut_settings& ignore_reverse() + { + test_reverse = BG_IF_TEST_FAILURES; + return *this; + } + + inline ut_settings& ignore_diff() + { + test_difference = BG_IF_TEST_FAILURES; + return *this; + } + inline ut_settings& ignore_validity() { - test_validity = false; + test_validity = BG_IF_TEST_FAILURES; + return *this; + } + + inline ut_settings& ignore_validity_union() + { + test_validity_union = BG_IF_TEST_FAILURES; + return *this; + } + + inline ut_settings& ignore_validity_intersection() + { + test_validity_intersection = BG_IF_TEST_FAILURES; return *this; } inline ut_settings& ignore_validity_diff() { - test_validity_diff1 = false; - test_validity_diff2 = false; - test_validity_diff_sym = false; + test_validity_diff1 = BG_IF_TEST_FAILURES; + test_validity_diff2 = BG_IF_TEST_FAILURES; + test_validity_diff_sym = BG_IF_TEST_FAILURES; return *this; } inline ut_settings& ignore_validity_diff1() { - test_validity_diff1 = false; + test_validity_diff1 = BG_IF_TEST_FAILURES; return *this; } inline ut_settings& ignore_validity_diff2() { - test_validity_diff2 = false; + test_validity_diff2 = BG_IF_TEST_FAILURES; return *this; } inline ut_settings& ignore_validity_diff_sym() { - test_validity_diff_sym = false; + test_validity_diff_sym = BG_IF_TEST_FAILURES; return *this; } @@ -60,7 +91,12 @@ struct ut_settings return *this; } + bool test_reverse{true}; + bool test_difference{true}; + bool test_validity{true}; + bool test_validity_union{true}; + bool test_validity_intersection{true}; bool test_validity_diff1{true}; bool test_validity_diff2{true}; bool test_validity_diff_sym{true}; @@ -112,17 +148,23 @@ 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); - BOOST_CHECK_MESSAGE(bgeo::math::abs(balance_d1) < eps, - "Case: " << name << " wrong difference (a-b) " << balance_d1); - BOOST_CHECK_MESSAGE(bgeo::math::abs(balance_d2) < eps, - "Case: " << name << " wrong difference (b-a) " << balance_d2); - BOOST_CHECK_MESSAGE(bgeo::math::abs(balance_sym) < eps, - "Case: " << name << " wrong symmetric difference " << balance_sym); - - BOOST_CHECK_MESSAGE(bgeo::math::abs(area_union - bgeo::area(result_union_rev)) < eps, - "Case: " << name << " wrong union reversed: " << area_union << " != " << bgeo::area(result_union_rev)); - BOOST_CHECK_MESSAGE(bgeo::math::abs(area_intersection - bgeo::area(result_intersection_rev)) < eps, - "Case: " << name << " wrong intersection reversed: " << area_intersection << " != " << bgeo::area(result_intersection_rev)); + if (settings.test_difference) + { + BOOST_CHECK_MESSAGE(bgeo::math::abs(balance_d1) < eps, + "Case: " << name << " wrong difference (a-b) " << balance_d1); + BOOST_CHECK_MESSAGE(bgeo::math::abs(balance_d2) < eps, + "Case: " << name << " wrong difference (b-a) " << balance_d2); + BOOST_CHECK_MESSAGE(bgeo::math::abs(balance_sym) < eps, + "Case: " << name << " wrong symmetric difference " << balance_sym); + } + + if (settings.test_reverse) + { + BOOST_CHECK_MESSAGE(bgeo::math::abs(area_union - bgeo::area(result_union_rev)) < eps, + "Case: " << name << " wrong union reversed: " << area_union << " != " << bgeo::area(result_union_rev)); + BOOST_CHECK_MESSAGE(bgeo::math::abs(area_intersection - bgeo::area(result_intersection_rev)) < eps, + "Case: " << name << " wrong intersection reversed: " << area_intersection << " != " << bgeo::area(result_intersection_rev)); + } if (settings.test_validity) { @@ -130,10 +172,16 @@ void test_detail(std::string const& name, std::string const& wkt1, std::string c "Case: " << name << " geometry1 is not valid"); BOOST_CHECK_MESSAGE(bgeo::is_valid(geometry2), "Case: " << name << " geometry2 is not valid"); - BOOST_CHECK_MESSAGE(bgeo::is_valid(result_union), - "Case: " << name << " union is not valid"); - BOOST_CHECK_MESSAGE(bgeo::is_valid(result_intersection), - "Case: " << name << " intersection is not valid"); + if (settings.test_validity_union) + { + BOOST_CHECK_MESSAGE(bgeo::is_valid(result_union), + "Case: " << name << " union is not valid"); + } + if (settings.test_validity_intersection) + { + BOOST_CHECK_MESSAGE(bgeo::is_valid(result_intersection), + "Case: " << name << " intersection is not valid"); + } if (settings.test_validity_diff1) { BOOST_CHECK_MESSAGE(bgeo::is_valid(diff1), @@ -193,9 +241,20 @@ void test_all(std::string const& name, std::string const& wkt1, std::string cons int test_main(int, char* []) { + TEST_CASE_WITH(case_141_multi, 0, 1, ut_settings().ignore_reverse()); + TEST_CASE(case_142_multi); + TEST_CASE(case_143_multi); + TEST_CASE(case_144_multi); + TEST_CASE(case_145_multi); + TEST_CASE_WITH(case_146_multi, 0, 1, ut_settings().ignore_validity_intersection()); + TEST_CASE(case_147_multi); + + TEST_CASE_WITH(issue_1221, 0, 1, ut_settings().ignore_validity_diff()); + TEST_CASE(issue_1222); TEST_CASE_WITH(issue_1226, 0, 1, ut_settings().ignore_validity_diff()); TEST_CASE(issue_1231); + TEST_CASE_WITH(issue_1241, 0, 1, ut_settings().ignore_diff()); TEST_CASE(issue_1244); TEST_CASE_WITH(issue_1288, 0, 1, ut_settings().ignore_validity_diff()); TEST_CASE_WITH(issue_1288, 0, 2, ut_settings()); @@ -212,7 +271,15 @@ int test_main(int, char* []) TEST_CASE_WITH(issue_1345_a, 1, 0, ut_settings()); TEST_CASE_WITH(issue_1345_b, 1, 0, ut_settings()); + TEST_CASE_WITH(issue_1349, 0, 1, ut_settings().ignore_diff()); + TEST_CASE(issue_1349_inverse); + TEST_CASE(issue_1350_comment); +#if defined(BOOST_GEOMETRY_TEST_FAILURES) + // Fails in union or intersection, and in difference. Also the union is invalid. + TEST_CASE_WITH(issue_1354, 0, 1, ut_settings().ignore_validity_union().ignore_diff()); +#endif + return 0; } \ No newline at end of file diff --git a/test/algorithms/set_operations/union/union_multi.cpp b/test/algorithms/set_operations/union/union_multi.cpp index fc3307d16a..8f12698474 100644 --- a/test/algorithms/set_operations/union/union_multi.cpp +++ b/test/algorithms/set_operations/union/union_multi.cpp @@ -199,7 +199,6 @@ void test_areal() TEST_UNION(case_138_multi, 2, 1, -1, 65.225); TEST_UNION(case_139_multi, 2, 1, -1, 64.953); TEST_UNION(case_140_multi, 2, 1, -1, 64.953); - TEST_UNION(case_141_multi, 1, 0, -1, 100.0); TEST_UNION(case_multi_rectangular, 1, 1, -1, 33125); TEST_UNION(case_multi_diagonal, 1, 2, -1, 5350); From fbea2f9c3c01467a6bd3122b4885a479c6319a6b Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Wed, 4 Dec 2024 17:47:44 +0100 Subject: [PATCH 2/4] fix: revise traversal_switch_detector for isolated areas Fixes: issue #1349 --- .../overlay/traversal_switch_detector.hpp | 304 ++++++++---------- .../algorithms/detail/overlay/traverse.hpp | 2 +- .../overlay/multi_overlay_cases.hpp | 1 + .../intersection/intersection_multi.cpp | 3 +- 4 files changed, 132 insertions(+), 178 deletions(-) diff --git a/include/boost/geometry/algorithms/detail/overlay/traversal_switch_detector.hpp b/include/boost/geometry/algorithms/detail/overlay/traversal_switch_detector.hpp index 0756034afa..49e23376e2 100644 --- a/include/boost/geometry/algorithms/detail/overlay/traversal_switch_detector.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/traversal_switch_detector.hpp @@ -77,8 +77,6 @@ namespace detail { namespace overlay // There is also "isolated", making it more complex, and documented below. template < - bool Reverse1, - bool Reverse2, overlay_type OverlayType, typename Geometry1, typename Geometry2, @@ -88,18 +86,34 @@ template > struct traversal_switch_detector { - static const operation_type target_operation - = operation_from_overlay::value; + static const operation_type target_operation = operation_from_overlay::value; enum isolation_type { - isolation_no = 0, + isolation_unknown = 0, isolation_yes = 1, - isolation_multiple = 2 + isolation_multiple = 2, + isolation_via = 3, + isolation_never = 4 }; +#if defined(BOOST_GEOMETRY_DEBUG_TRAVERSAL_SWITCH_DETECTOR) + static std::string isolation_to_string(isolation_type const& iso) + { + switch(iso) + { + case isolation_unknown : return "unknown"; + case isolation_yes : return "yes"; + case isolation_via : return "via"; + case isolation_multiple : return "multiple"; + case isolation_never : return "never"; + } + return "error"; + } +#endif + using turn_type = typename boost::range_value::type; - using set_type= std::set; + using set_type = std::set; // Per ring, first turns are collected (in turn_indices), and later // a region_id is assigned @@ -124,7 +138,7 @@ struct traversal_switch_detector struct region_properties { signed_size_type region_id = -1; - isolation_type isolated = isolation_no; + isolation_type isolated = isolation_unknown; set_type unique_turn_ids; connection_map connected_region_counts; }; @@ -224,130 +238,100 @@ struct traversal_switch_detector return true; } - bool ii_turn_connects_two_regions(region_properties const& region, - region_properties const& connected_region, - signed_size_type turn_index) const + bool detect_connected_isolation_for_region(region_properties& properties) { - turn_type const& turn = m_turns[turn_index]; - if (! turn.both(operation_intersection)) - { - return false; - } + // If all but one are isolated, + // and the connection to the remaining one is via one turn + // then it is complex isolated - signed_size_type const id0 = turn.operations[0].enriched.region_id; - signed_size_type const id1 = turn.operations[1].enriched.region_id; - - return (id0 == region.region_id && id1 == connected_region.region_id) - || (id1 == region.region_id && id0 == connected_region.region_id); - } - - - bool isolated_multiple_connection(region_properties const& region, - region_properties const& connected_region) const - { - if (connected_region.isolated != isolation_multiple) - { - return false; - } - - // First step: compare turns of regions with turns of connected region - set_type turn_ids = region.unique_turn_ids; - for (auto turn_id : connected_region.unique_turn_ids) + set_type turns_of_region; + bool has_other_region_turns = false; + for (auto const& turn_id : properties.unique_turn_ids) { - turn_ids.erase(turn_id); + if (turn_id < 0) + { + turns_of_region.insert(turn_id); + continue; + } + turn_type const& turn = m_turns[turn_id]; + if (turn.operations[0].enriched.region_id != turn.operations[1].enriched.region_id) + { + turns_of_region.insert(turn_id); + } + else + { + has_other_region_turns = true; + } } + + set_type turns_to_remaining; + set_type turns_multiple; - // There should be one connection (turn or cluster) left - if (turn_ids.size() != 1) + for (auto const& key_val : properties.connected_region_counts) { - return false; - } + signed_size_type const& region_id = key_val.first; + region_properties const& connected_region = m_connected_regions[region_id]; - for (auto id_or_index : connected_region.unique_turn_ids) - { - if (id_or_index >= 0) + if (connected_region.isolated == isolation_yes + || connected_region.isolated == isolation_via) { - if (! ii_turn_connects_two_regions(region, connected_region, id_or_index)) + for (auto const& turn_id : key_val.second.unique_turn_ids) { - return false; + turns_of_region.erase(turn_id); } } + else if (connected_region.isolated == isolation_multiple) + { + turns_multiple.insert(key_val.second.unique_turn_ids.begin(), key_val.second.unique_turn_ids.end()); + } else { - signed_size_type const cluster_id = -id_or_index; - auto it = m_clusters.find(cluster_id); - if (it != m_clusters.end()) - { - cluster_info const& cinfo = it->second; - for (auto turn_index : cinfo.turn_indices) - { - if (! ii_turn_connects_two_regions(region, connected_region, turn_index)) - { - return false; - } - } - } + turns_to_remaining.insert(key_val.second.unique_turn_ids.begin(), key_val.second.unique_turn_ids.end()); } } - return true; - } - - bool has_only_isolated_children(region_properties const& region) const - { - bool first_with_turn = true; - signed_size_type first_turn_id = 0; + bool const has_one_remaining = turns_to_remaining.size() == 1; - for (auto const& key_val : region.connected_region_counts) + turns_to_remaining.insert(turns_multiple.begin(), turns_multiple.end()); + if (!has_other_region_turns + && has_one_remaining + && turns_multiple.size() > 0 + && turns_to_remaining == turns_of_region) { - signed_size_type const region_id = key_val.first; - connection_properties const& cprop = key_val.second; - - auto mit = m_connected_regions.find(region_id); - if (mit == m_connected_regions.end()) - { - // Should not occur - return false; - } - - region_properties const& connected_region = mit->second; - - if (cprop.count != 1) - { - // If there are more connections, check their isolation - if (! isolated_multiple_connection(region, connected_region)) - { - return false; - } - } + // Handles cases like this (#case_141_multi): + // +----------------------+ * where "m" are turns classified as multiple + // | _____ m ___ | * E is separate output polygon, located WITHIN the interior ring + // | | / \ \| * around it is an isolated interior ring (one, it is not divided) + // | O | x E | x * located within the exterior ring E + // | | ___\m/____/| + // | | + // +----------------------+ + + // There are geometrically quite different cases with a similar configuration (#case_128_multi) + // where this condition applies for the whole exterior ring as well. + // And #case_recursive_boxes_81 which is similar, but reversed (a polygon with an interior ring + // touching at two sides of the exterior - and therefore splitting it) + // At this place of the code, it is not known whether it will be (in the result) + // an exterior ring and the area is not known yet. + + properties.isolated = isolation_via; + return true; + } - if (connected_region.isolated != isolation_yes - && connected_region.isolated != isolation_multiple) - { - signed_size_type const unique_turn_id = *cprop.unique_turn_ids.begin(); - if (first_with_turn) - { - first_turn_id = unique_turn_id; - first_with_turn = false; - } - else if (first_turn_id != unique_turn_id) - { - return false; - } - } + if (turns_of_region.size() <= 1 && turns_to_remaining.size() <= 1) + { + // It is connected to the remaining with maximum one turn (or cluster. + // The other turns of this region (if there were) were isolated (and therefore removed). + properties.isolated = isolation_via; + return true; } - // If there is only one connection (with a 'parent'), and all other - // connections are itself isolated, it is isolated - return true; + return false; } + void get_isolated_regions() { - // First time: check regions isolated (one connection only), - // semi-isolated (multiple connections between same region), - // and complex isolated (connection with multiple rings but all - // at same point) for (auto& key_val : m_connected_regions) { region_properties& properties = key_val.second; @@ -364,9 +348,10 @@ struct traversal_switch_detector properties.isolated = isolation_yes; } } + } - // Propagate isolation to next level - // TODO: should be optimized + void get_connecting_isolated_regions() + { std::size_t defensive_check = 0; bool changed = true; while (changed && defensive_check++ < m_connected_regions.size()) @@ -375,11 +360,13 @@ struct traversal_switch_detector for (auto& key_val : m_connected_regions) { region_properties& properties = key_val.second; + if (properties.isolated != isolation_unknown) + { + continue; + } - if (properties.isolated == isolation_no - && has_only_isolated_children(properties)) + if (detect_connected_isolation_for_region(properties)) { - properties.isolated = isolation_yes; changed = true; } } @@ -390,45 +377,19 @@ struct traversal_switch_detector { for (turn_type& turn : m_turns) { - constexpr auto order1 = geometry::point_order::value; - constexpr bool reverse1 = (order1 == boost::geometry::counterclockwise) - ? ! Reverse1 : Reverse1; - - constexpr auto order2 = geometry::point_order::value; - constexpr bool reverse2 = (order2 == boost::geometry::counterclockwise) - ? ! Reverse2 : Reverse2; - - // For difference, for the input walked through in reverse, - // the meaning is reversed: what is isolated is actually not, - // and vice versa. - bool const reverseMeaningInTurn - = (reverse1 || reverse2) - && ! turn.is_self() - && ! turn.is_clustered() - && uu_or_ii(turn) - && turn.operations[0].enriched.region_id - != turn.operations[1].enriched.region_id; - for (auto& op : turn.operations) { auto mit = m_connected_regions.find(op.enriched.region_id); - if (mit != m_connected_regions.end()) + if (mit == m_connected_regions.end()) { - bool const reverseMeaningInOp - = reverseMeaningInTurn - && ((op.seg_id.source_index == 0 && reverse1) - || (op.seg_id.source_index == 1 && reverse2)); - - // It is assigned to isolated if it's property is "Yes", - // (one connected interior, or chained). - // "Multiple" doesn't count for isolation, - // neither for intersection, neither for difference. - region_properties const& prop = mit->second; - op.enriched.isolated - = reverseMeaningInOp - ? false - : prop.isolated == isolation_yes; + continue; } + // It is assigned to isolated if its property is "Yes", + // (one connected interior, or chained). + // "Multiple" doesn't count for isolation, + // neither for intersection, neither for difference. + region_properties const& prop = mit->second; + op.enriched.isolated = prop.isolated == isolation_yes || prop.isolated == isolation_via; } } } @@ -605,18 +566,8 @@ struct traversal_switch_detector } #if defined(BOOST_GEOMETRY_DEBUG_TRAVERSAL_SWITCH_DETECTOR) - void debug_show_results() + void debug_show_region(region_properties const& prop) const { - auto isolation_to_string = [](isolation_type const& iso) -> std::string - { - switch(iso) - { - case isolation_no : return "no"; - case isolation_yes : return "yes"; - case isolation_multiple : return "multiple"; - } - return "error"; - }; auto set_to_string = [](auto const& s) -> std::string { std::ostringstream result; @@ -624,24 +575,27 @@ struct traversal_switch_detector return result.str(); }; - for (auto const& kv : m_connected_regions) + std::ostringstream sub; + sub << "[turns" << set_to_string(prop.unique_turn_ids) + << "] regions"; + for (auto const& kvs : prop.connected_region_counts) { - auto const& prop = kv.second; + sub << " { " << kvs.first + << " : turns [" << set_to_string(kvs.second.unique_turn_ids) + << " ] }"; + } - std::ostringstream sub; - sub << "[turns" << set_to_string(prop.unique_turn_ids) - << "] regions"; - for (auto const& kvs : prop.connected_region_counts) - { - sub << " { " << kvs.first - << " : via [" << set_to_string(kvs.second.unique_turn_ids) - << " ] }"; - } + std::cout << "REGION " << prop.region_id + << " " << isolation_to_string(prop.isolated) + << " " << sub.str() + << std::endl; + } - std::cout << "REGION " << prop.region_id - << " " << isolation_to_string(prop.isolated) - << " " << sub.str() - << std::endl; + void debug_show_results() + { + for (auto const& kv : m_connected_regions) + { + debug_show_region(kv.second); } for (std::size_t turn_index = 0; turn_index < m_turns.size(); ++turn_index) @@ -677,10 +631,7 @@ struct traversal_switch_detector void iterate() { #if defined(BOOST_GEOMETRY_DEBUG_TRAVERSAL_SWITCH_DETECTOR) - std::cout << "BEGIN SWITCH DETECTOR (region_ids and isolation)" - << (Reverse1 ? " REVERSE_1" : "") - << (Reverse2 ? " REVERSE_2" : "") - << std::endl; + std::cout << "BEGIN SWITCH DETECTOR (region_ids and isolation)" << std::endl; #endif // Collect turns per ring @@ -717,6 +668,7 @@ struct traversal_switch_detector assign_region_ids_to_enriched(); assign_connected_regions(); get_isolated_regions(); + get_connecting_isolated_regions(); assign_isolation_to_enriched(); } diff --git a/include/boost/geometry/algorithms/detail/overlay/traverse.hpp b/include/boost/geometry/algorithms/detail/overlay/traverse.hpp index 6c0b4488e8..c18e76ecbe 100644 --- a/include/boost/geometry/algorithms/detail/overlay/traverse.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/traverse.hpp @@ -78,7 +78,7 @@ public : { traversal_switch_detector < - Reverse1, Reverse2, OverlayType, + OverlayType, Geometry1, Geometry2, Turns, Clusters, Visitor diff --git a/test/algorithms/overlay/multi_overlay_cases.hpp b/test/algorithms/overlay/multi_overlay_cases.hpp index 1f2cd53343..936a982e72 100644 --- a/test/algorithms/overlay/multi_overlay_cases.hpp +++ b/test/algorithms/overlay/multi_overlay_cases.hpp @@ -1764,6 +1764,7 @@ static std::string issue_1288[3] = static std::string issue_1299[2] = { + // Needs "is_used" for visited. "MULTIPOLYGON(((1.2549999979079400 0.85000000411847698, -1.2550000020920500 0.84999999897038103, -1.2549999999999999 -0.85000000102961903, 1.2549999999999999 -0.84999999999999998)))", "MULTIPOLYGON(((-0.87500000000000000 -0.84999999999999998, -0.87500000000000000 -0.070000000000000201, -1.2549999999999999 -0.070000000000000201, -1.2549999999999999 -0.84999999999999998)))" }; diff --git a/test/algorithms/set_operations/intersection/intersection_multi.cpp b/test/algorithms/set_operations/intersection/intersection_multi.cpp index 7a2298f37b..d587241f01 100644 --- a/test/algorithms/set_operations/intersection/intersection_multi.cpp +++ b/test/algorithms/set_operations/intersection/intersection_multi.cpp @@ -356,7 +356,8 @@ void test_areal() TEST_INTERSECTION(issue_643, 1, -1, 3.4615); - TEST_INTERSECTION(issue_869_c, 3, -1, 3600); + TEST_INTERSECTION(issue_869_a_inverse, 3, -1, 3600.0); + TEST_INTERSECTION(issue_869_c, 3, -1, 3600.0); TEST_INTERSECTION(issue_888_34, 7, -1, 0.0256838); TEST_INTERSECTION(issue_888_37, 13, -1, 0.0567043); From 8a669bfab20f5b4e3aa68905a99c403fada11add Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Sun, 15 Dec 2024 15:18:11 +0100 Subject: [PATCH 3/4] fix: add condition for one connection having multiple regions --- .../overlay/traversal_switch_detector.hpp | 71 +++++++++++++++++-- 1 file changed, 65 insertions(+), 6 deletions(-) diff --git a/include/boost/geometry/algorithms/detail/overlay/traversal_switch_detector.hpp b/include/boost/geometry/algorithms/detail/overlay/traversal_switch_detector.hpp index 49e23376e2..280a5dab62 100644 --- a/include/boost/geometry/algorithms/detail/overlay/traversal_switch_detector.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/traversal_switch_detector.hpp @@ -98,7 +98,7 @@ struct traversal_switch_detector }; #if defined(BOOST_GEOMETRY_DEBUG_TRAVERSAL_SWITCH_DETECTOR) - static std::string isolation_to_string(isolation_type const& iso) + static std::string isolation_to_string(isolation_type const& iso) { switch(iso) { @@ -110,7 +110,7 @@ struct traversal_switch_detector } return "error"; } -#endif +#endif using turn_type = typename boost::range_value::type; using set_type = std::set; @@ -238,9 +238,58 @@ struct traversal_switch_detector return true; } + bool one_connection_having_one_multiple_region(region_properties const& region) const + { + for (auto const& turn_id : region.unique_turn_ids) + { + // This loop avoids satisfying the condition for the main (exterior ring) region. + if (turn_id < 0) + { + // Skip clustered turns + continue; + } + turn_type const& turn = m_turns[turn_id]; + if (turn.has(operation_blocked)) + { + return false; + } + } + + std::size_t multiple_count = 0; + std::size_t via_count = 0; + std::size_t other_count = 0; + for (auto const& key_val : region.connected_region_counts) + { + signed_size_type const& region_id = key_val.first; + auto it = m_connected_regions.find(region_id); + if (it == m_connected_regions.end()) + { + continue; + } + auto const& connected_region = it->second; + + if (connected_region.isolated == isolation_multiple) + { + multiple_count++; + } + else if (connected_region.isolated == isolation_unknown && key_val.second.count <= 1) + { + // It is connected with just one turn to the exterior. + via_count++; + } + else + { + other_count++; + } + } + + return multiple_count == 1 && via_count == 1 && other_count == 0; + } + + bool detect_connected_isolation_for_region(region_properties& properties) { - // If all but one are isolated, + // If all but one are isolated, // and the connection to the remaining one is via one turn // then it is complex isolated @@ -250,7 +299,7 @@ struct traversal_switch_detector { if (turn_id < 0) { - turns_of_region.insert(turn_id); + // Skip clusters continue; } turn_type const& turn = m_turns[turn_id]; @@ -263,7 +312,7 @@ struct traversal_switch_detector has_other_region_turns = true; } } - + set_type turns_to_remaining; set_type turns_multiple; @@ -272,7 +321,7 @@ struct traversal_switch_detector signed_size_type const& region_id = key_val.first; region_properties const& connected_region = m_connected_regions[region_id]; - if (connected_region.isolated == isolation_yes + if (connected_region.isolated == isolation_yes || connected_region.isolated == isolation_via) { for (auto const& turn_id : key_val.second.unique_turn_ids) @@ -348,6 +397,16 @@ struct traversal_switch_detector properties.isolated = isolation_yes; } } + + // Second pass - for isolated regions, itself containing a multiple connected region. + for (auto& key_val : m_connected_regions) + { + region_properties& properties = key_val.second; + if (one_connection_having_one_multiple_region(properties)) + { + properties.isolated = isolation_yes; + } + } } void get_connecting_isolated_regions() From d4aec02477f38f22c3801491ec5c8c8cafc82b44 Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Sun, 15 Dec 2024 15:35:42 +0100 Subject: [PATCH 4/4] test: update test cases now fixed for validity --- .../set_operations/difference/difference_multi.cpp | 7 +------ test/algorithms/set_operations/set_ops_areal_areal.cpp | 9 ++++----- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/test/algorithms/set_operations/difference/difference_multi.cpp b/test/algorithms/set_operations/difference/difference_multi.cpp index e98cc17891..9f0877aa6b 100644 --- a/test/algorithms/set_operations/difference/difference_multi.cpp +++ b/test/algorithms/set_operations/difference/difference_multi.cpp @@ -132,12 +132,7 @@ void test_areal() ggl_list_20120915_h2[0], ggl_list_20120915_h2[2], 2, 13, 17.0, 0, 0, 0.0); - { - ut_settings settings; - settings.percentage = 0.001; - settings.set_test_validity(false); - TEST_DIFFERENCE_WITH(0, 1, ggl_list_20120221_volker, 2, 7962.66, 2, 2775258.93, 4); - } + TEST_DIFFERENCE(ggl_list_20120221_volker, 2, 7962.66, 2, 2775258.93, 4); TEST_DIFFERENCE(bug_21155501, 1, 3.758937, 1, 1.78e-15, 1); diff --git a/test/algorithms/set_operations/set_ops_areal_areal.cpp b/test/algorithms/set_operations/set_ops_areal_areal.cpp index f4157119b5..9a9da85218 100644 --- a/test/algorithms/set_operations/set_ops_areal_areal.cpp +++ b/test/algorithms/set_operations/set_ops_areal_areal.cpp @@ -249,9 +249,9 @@ int test_main(int, char* []) TEST_CASE_WITH(case_146_multi, 0, 1, ut_settings().ignore_validity_intersection()); TEST_CASE(case_147_multi); - TEST_CASE_WITH(issue_1221, 0, 1, ut_settings().ignore_validity_diff()); - + TEST_CASE(issue_1221); TEST_CASE(issue_1222); + TEST_CASE_WITH(issue_1226, 0, 1, ut_settings().ignore_validity_diff()); TEST_CASE(issue_1231); TEST_CASE_WITH(issue_1241, 0, 1, ut_settings().ignore_diff()); @@ -271,9 +271,8 @@ int test_main(int, char* []) TEST_CASE_WITH(issue_1345_a, 1, 0, ut_settings()); TEST_CASE_WITH(issue_1345_b, 1, 0, ut_settings()); - TEST_CASE_WITH(issue_1349, 0, 1, ut_settings().ignore_diff()); + TEST_CASE(issue_1349); TEST_CASE(issue_1349_inverse); - TEST_CASE(issue_1350_comment); #if defined(BOOST_GEOMETRY_TEST_FAILURES) @@ -282,4 +281,4 @@ int test_main(int, char* []) #endif return 0; -} \ No newline at end of file +}