From 0147d4d2c33812f954c32f76aa4101eb91662d6c Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Tue, 4 Mar 2014 14:36:42 +0100 Subject: [PATCH 01/32] get_turns(L,A) tests added --- .../overlay/get_turns_linear_areal.cpp | 172 +----------------- 1 file changed, 8 insertions(+), 164 deletions(-) diff --git a/test/algorithms/overlay/get_turns_linear_areal.cpp b/test/algorithms/overlay/get_turns_linear_areal.cpp index a3ba4befa..0324abca6 100644 --- a/test/algorithms/overlay/get_turns_linear_areal.cpp +++ b/test/algorithms/overlay/get_turns_linear_areal.cpp @@ -20,11 +20,6 @@ #include "test_get_turns.hpp" #include -//TEST -#include -//#include -//#include - template void test_all() { @@ -49,26 +44,14 @@ void test_all() "POLYGON((0 0,5 5,0 10,20 10,20 2,19 0,0 0)(10 3,15 3,15 7,10 7,10 3))", expected("tcu")("miu")("mcu")("miu")("mxu").vec); - - to_svg("LINESTRING(15 5,24 5,20 2,19 0,13 -4,1 0,10 0,13 3,15 7,16 10,10 10,8 10,4 6,2 8,1 10)", - "POLYGON((0 0,5 5,0 10,20 10,20 2,19 0,0 0)(10 3,15 3,15 7,10 7,10 3))", - "ls_poly1.svg"); - to_svg("LINESTRING(15 3,15 5,24 5,20 2,19 0,13 -4,1 0,10 0,13 3,15 7,16 10,10 10,8 10,4 6,2 8,1 10)", - "POLYGON((0 0,5 5,0 10,20 10,20 2,19 0,0 0)(10 3,15 3,15 7,10 7,10 3))", - "ls_poly2.svg"); - to_svg("LINESTRING(15 7,15 5,24 5,20 2,19 0,13 -4,1 0,10 0,13 3,15 7,16 10,10 10,8 10,4 6,2 8,1 10)", - "POLYGON((0 0,5 5,0 10,20 10,20 2,19 0,0 0)(10 3,15 3,15 7,10 7,10 3))", - "ls_poly3.svg"); - to_svg("LINESTRING(15 5,15 7,24 5,20 2,19 0,13 -4,1 0,10 0,13 3,15 7,16 10,10 10,8 10,4 6,2 8,1 10)", - "POLYGON((0 0,5 5,0 10,20 10,20 2,19 0,0 0)(10 3,15 3,15 7,10 7,10 3))", - "ls_poly4.svg"); - to_svg("LINESTRING(15 5,15 3,24 5,20 2,19 0,13 -4,1 0,10 0,13 3,15 7,16 10,10 10,8 10,4 6,2 8,1 10)", - "POLYGON((0 0,5 5,0 10,20 10,20 2,19 0,0 0)(10 3,15 3,15 7,10 7,10 3))", - "ls_poly5.svg"); - - to_svg("POLYGON((0 0,5 5,0 10,20 10,20 2,19 0,0 0)(10 3,15 3,15 7,10 7,10 3))", - "LINESTRING(15 5,24 5,20 2,19 0,13 -4,1 0,10 0,13 3,15 7,16 10,10 10,8 10,4 6,2 8,1 10)", - "poly_ls.svg"); + // true hole + test_geometry("LINESTRING(9 1,10 5,9 9)", + "POLYGON((0 0,0 10,10 10,10 5,10 0,0 0)(2 2,10 5,2 8,2 2))", + expected("tiu")("tiu").vec); + // fake hole + test_geometry("LINESTRING(9 1,10 5,9 9)", + "POLYGON((0 0,0 10,10 10,10 5,2 8,2 2,10 5,10 0,0 0))", + expected("tuu")("tiu").vec); } int test_main(int, char* []) @@ -85,142 +68,3 @@ int test_main(int, char* []) #endif return 0; } - -/* -to_svg("LINESTRING(0 0,2 0)", "LINESTRING(1 0,3 0)", "lsls0000.svg"); -to_svg("LINESTRING(1 0,3 0)", "LINESTRING(2 0,0 0)", "lsls0001.svg"); -to_svg("LINESTRING(0 0,2 0)", "LINESTRING(3 0,1 0)", "lsls0002.svg"); - -to_svg("LINESTRING(0 0,1 0)", "LINESTRING(1 0,2 0)", "lsls0003.svg"); -to_svg("LINESTRING(0 0,1 0)", "LINESTRING(2 0,1 0)", "lsls0004.svg"); -to_svg("LINESTRING(1 0,2 0)", "LINESTRING(1 0,0 0)", "lsls0005.svg"); - -to_svg("LINESTRING(0 0,2 0)", "LINESTRING(0 0,2 0)", "lsls0006.svg"); -to_svg("LINESTRING(0 0,2 0)", "LINESTRING(2 0,0 0)", "lsls0007.svg"); - -to_svg("LINESTRING(0 0,3 0)", "LINESTRING(1 0,2 0)", "lsls0008.svg"); -to_svg("LINESTRING(0 0,3 0)", "LINESTRING(2 0,1 0)", "lsls0009.svg"); - -to_svg("LINESTRING(0 0,1 0)", "LINESTRING(1 0,1 1)", "lsls00010.svg"); -to_svg("LINESTRING(0 0,1 0)", "LINESTRING(1 1,1 0)", "lsls00011.svg"); -to_svg("LINESTRING(0 0,1 0)", "LINESTRING(0 0,0 1)", "lsls00012.svg"); -to_svg("LINESTRING(0 0,1 0)", "LINESTRING(0 1,0 0)", "lsls00013.svg"); -to_svg("LINESTRING(0 0,2 0)", "LINESTRING(1 0,1 1)", "lsls00014.svg"); -to_svg("LINESTRING(0 0,2 0)", "LINESTRING(1 1,1 0)", "lsls00015.svg"); - -to_svg("LINESTRING(0 0,2 0)", "LINESTRING(1 0,3 1)", "lsls00016.svg"); - -to_svg("LINESTRING(0 0,2 0)", "LINESTRING(2 0,1 0)", "lsls00017.svg"); -to_svg("LINESTRING(0 0,2 0)", "LINESTRING(0 0,1 0)", "lsls00018.svg"); -to_svg("LINESTRING(0 0,2 0)", "LINESTRING(1 0,0 0)", "lsls00019.svg"); -to_svg("LINESTRING(0 0,2 0)", "LINESTRING(1 0,2 0)", "lsls00020.svg"); - -to_svg("LINESTRING(0 0,2 0)", "LINESTRING(0 0,2 0)", "lsls000.svg"); -to_svg("LINESTRING(0 0,2 0,2 0,3 0)", "LINESTRING(0 0,2 0)", "lsls001.svg"); -to_svg("LINESTRING(1 0,1 1)", "LINESTRING(0 0,1 0,2 0)", "lsls0020.svg"); -to_svg("LINESTRING(1 0,0 0)", "LINESTRING(0 0,1 0,2 0)", "lsls0021.svg"); -to_svg("LINESTRING(1 0,2 0)", "LINESTRING(0 0,1 0,2 0)", "lsls0022.svg"); -to_svg("LINESTRING(1 1,1 0)", "LINESTRING(0 0,1 0,2 0)", "lsls0023.svg"); -to_svg("LINESTRING(0 0,1 0)", "LINESTRING(0 0,1 0,2 0)", "lsls0024.svg"); -to_svg("LINESTRING(2 0,1 0)", "LINESTRING(0 0,1 0,2 0)", "lsls0025.svg"); -to_svg("LINESTRING(0 0,1 0,2 0)", "LINESTRING(1 0,1 1)", "lsls00200.svg"); -to_svg("LINESTRING(0 0,1 0,2 0)", "LINESTRING(1 0,0 0)", "lsls00211.svg"); -to_svg("LINESTRING(0 0,1 0,2 0)", "LINESTRING(1 0,2 0)", "lsls00222.svg"); -to_svg("LINESTRING(0 0,1 0,2 0)", "LINESTRING(1 1,1 0)", "lsls00233.svg"); -to_svg("LINESTRING(0 0,1 0,2 0)", "LINESTRING(0 0,1 0)", "lsls00244.svg"); -to_svg("LINESTRING(0 0,1 0,2 0)", "LINESTRING(2 0,1 0)", "lsls00255.svg"); - -to_svg("LINESTRING(0 0,2 0,4 0,6 0,8 0)", "LINESTRING(1 0,3 0,5 0,6 0,9 0)", "lsls01.svg"); -to_svg("LINESTRING(0 0,2 0,4 0,4 4)", "LINESTRING(1 0,3 0,4 0,4 2,4 5)", "lsls02.svg"); -to_svg("LINESTRING(0 0,2 0,4 0,4 4)", "LINESTRING(1 0,4 0,4 4)", "lsls031.svg"); -to_svg("LINESTRING(0 0,2 0,4 0,4 4)", "LINESTRING(4 0,2 0,0 0)", "lsls032.svg"); -to_svg("LINESTRING(0 0,2 0,4 0,4 4)", "LINESTRING(4 0,2 2,0 2)", "lsls0321.svg"); -to_svg("LINESTRING(0 0,2 0,4 0,4 4)", "LINESTRING(4 0,2 0)", "lsls033.svg"); -to_svg("LINESTRING(0 0,2 0,4 0,4 4)", "LINESTRING(4 0,4 4)", "lsls034.svg"); -to_svg("LINESTRING(0 0,2 0,4 0,4 4)", "LINESTRING(4 0,3 1)", "lsls035.svg"); -to_svg("LINESTRING(0 0,2 0,4 0,4 4)", "LINESTRING(4 0,4 -1)", "lsls036.svg"); -to_svg("LINESTRING(0 0,2 0,4 0,4 4)", "LINESTRING(1 0,4 0,4 3)", "lsls04.svg"); -to_svg("LINESTRING(1 0,2 0,4 0,6 0,8 0)", "LINESTRING(0 0,3 0,5 0,6 0,9 0)", "lsls05.svg"); - -to_svg("LINESTRING(0 0,10 0,10 10)", "LINESTRING(1 0,10 9)", "lsls061.svg"); -to_svg("LINESTRING(0 0,10 0,10 10)", "LINESTRING(1 0,10 -9)", "lsls062.svg"); -to_svg("LINESTRING(0 0,10 0,10 10)", "LINESTRING(1 0,-10 9)", "lsls063.svg"); -to_svg("LINESTRING(0 0,10 0,10 10)", "LINESTRING(1 0,-10 -9)", "lsls064.svg"); -to_svg("LINESTRING(0 0,1 0,10 9,10 10)", "LINESTRING(1 0,10 9)", "lsls065.svg"); -to_svg("LINESTRING(0 0,10 0,10 10)", "LINESTRING(1 0,9 9)", "lsls071.svg"); -to_svg("LINESTRING(0 0,10 0,10 10)", "LINESTRING(1 0,9 -9)", "lsls072.svg"); -to_svg("LINESTRING(0 0,10 0,10 10)", "LINESTRING(1 0,-9 9)", "lsls073.svg"); -to_svg("LINESTRING(0 0,10 0,10 10)", "LINESTRING(1 0,-9 -9)", "lsls074.svg"); -to_svg("LINESTRING(0 0,1 0,10 0,10 10)", "LINESTRING(1 0,9 9)", "lsls081.svg"); -to_svg("LINESTRING(0 0,1 0,10 0,10 10)", "LINESTRING(0 0,9 9)", "lsls082.svg"); -to_svg("LINESTRING(0 0,1 0)", "LINESTRING(1 0,9 9)", "lsls083.svg"); -to_svg("LINESTRING(0 0,1 0)", "LINESTRING(9 9,1 0)", "lsls084.svg"); -to_svg("LINESTRING(0 0,1 0)", "LINESTRING(1 0,2 0)", "lsls085.svg"); -to_svg("LINESTRING(0 0,1 0)", "LINESTRING(2 0,1 0)", "lsls086.svg"); -to_svg("LINESTRING(0 0,10 0,10 10)", "LINESTRING(1 1,10 5)", "lsls091.svg"); -to_svg("LINESTRING(0 0,10 0,10 5,10 10)", "LINESTRING(1 1,10 5)", "lsls092.svg"); -to_svg("LINESTRING(0 0,10 0,10 10)", "LINESTRING(19 1,10 5)", "lsls093.svg"); -to_svg("LINESTRING(0 0,10 0,10 5,10 10)", "LINESTRING(19 1,10 5)", "lsls094.svg"); - -to_svg("LINESTRING(5 3,1 1,3 3,2 2,0 0)", "LINESTRING(0 0,3 3,6 3)", "1F100F10T.svg"); - -to_svg("LINESTRING(0 0,2 0,4 0)", "LINESTRING(1 1,1 0,3 0,3 1)", "lsls_01.svg"); -to_svg("LINESTRING(0 0,2 0,4 0)", "LINESTRING(1 -1,1 0,3 0,3 -1)", "lsls_02.svg"); -to_svg("LINESTRING(0 0,2 0,4 0)", "LINESTRING(3 1,3 0,1 0,1 1)", "lsls_03.svg"); -to_svg("LINESTRING(0 0,2 0,4 0)", "LINESTRING(3 -1,3 0,1 0,1 -1)", "lsls_04.svg"); -to_svg("LINESTRING(0 0,2 0,3 0,4 0,6 0)", "LINESTRING(2 1,2 0,4 0,4 1)", "lsls_05.svg"); -to_svg("LINESTRING(0 0,2 0,3 0,4 0,6 0)", "LINESTRING(2 -1,2 0,4 0,4 -1)", "lsls_06.svg"); -to_svg("LINESTRING(0 0,2 0,3 0,4 0,6 0)", "LINESTRING(4 1,4 0,2 0,2 1)", "lsls_07.svg"); -to_svg("LINESTRING(0 0,2 0,3 0,4 0,6 0)", "LINESTRING(4 -1,4 0,2 0,2 -1)", "lsls_08.svg"); - -to_svg("LINESTRING(0 0,2 0,4 0)", "LINESTRING(1 1,1 0,2 0,3 0,3 1)", "lsls_11.svg"); -to_svg("LINESTRING(0 0,2 0,4 0)", "LINESTRING(1 -1,1 0,2 0,3 0,3 -1)", "lsls_12.svg"); -to_svg("LINESTRING(0 0,2 0,4 0)", "LINESTRING(3 1,3 0,2 0,1 0,1 1)", "lsls_13.svg"); -to_svg("LINESTRING(0 0,2 0,4 0)", "LINESTRING(3 -1,3 0,2 0,1 0,1 -1)", "lsls_14.svg"); -to_svg("LINESTRING(0 0,2 0,3 0,4 0,6 0)", "LINESTRING(2 1,2 0,3 0,4 0,4 1)", "lsls_15.svg"); -to_svg("LINESTRING(0 0,2 0,3 0,4 0,6 0)", "LINESTRING(2 -1,2 0,3 0,4 0,4 -1)", "lsls_16.svg"); -to_svg("LINESTRING(0 0,2 0,3 0,4 0,6 0)", "LINESTRING(4 1,4 0,3 0,2 0,2 1)", "lsls_17.svg"); -to_svg("LINESTRING(0 0,2 0,3 0,4 0,6 0)", "LINESTRING(4 -1,4 0,3 0,2 0,2 -1)", "lsls_18.svg"); - -to_svg("LINESTRING(0 5,5 5,10 5,10 10,5 10,5 5,5 0)", "LINESTRING(0 5,5 5,5 10,10 10,10 5,5 5,5 0)", "lsls11.svg"); -to_svg("LINESTRING(0 5,5 5,10 5,10 10,5 10,5 5,5 0)", "LINESTRING(5 0,5 5,10 5,10 10,5 10,5 5,0 5)", "lsls12.svg"); -to_svg("LINESTRING(5 0,5 5,5 10,10 10,10 5,5 5,0 5)", "LINESTRING(0 5,5 5,5 10,10 10,10 5,5 5,5 0)", "lsls13.svg"); -to_svg("LINESTRING(5 0,5 5,5 10,10 10,10 5,5 5,0 5)", "LINESTRING(5 0,5 5,10 5,10 10,5 10,5 5,0 5)", "lsls14.svg"); - -to_svg("LINESTRING(0 5,10 5,10 10,5 10,5 0)", "LINESTRING(0 5,5 5,5 10,10 10,10 5,5 5,5 0)", "lsls15.svg"); -to_svg("LINESTRING(0 5,10 5,10 10,5 10,5 0)", "LINESTRING(5 0,5 10,10 10,10 5,0 5)", "lsls16.svg"); -to_svg("LINESTRING(0 5,10 5)", "LINESTRING(5 0,5 10,10 10,10 5,0 5)", "lsls161.svg"); -to_svg("LINESTRING(0 5,8 5,10 5)", "LINESTRING(5 0,5 10,10 10,10 5,0 5)", "lsls162.svg"); -to_svg("LINESTRING(0 5,8 5)", "LINESTRING(5 0,5 10,10 10,10 5,0 5)", "lsls1631.svg"); -to_svg("LINESTRING(0 5,1 5,7 5,8 5)", "LINESTRING(5 0,5 10,10 10,10 5,0 5)", "lsls1632.svg"); -to_svg("LINESTRING(0 5,1 5,7 5,8 5)", "LINESTRING(5 10,10 10,10 5,0 5)", "lsls1633.svg"); -to_svg("LINESTRING(0 5,8 4)", "LINESTRING(5 0,5 10,10 10,10 5,0 5)", "lsls1641.svg"); -to_svg("LINESTRING(0 5,8 6)", "LINESTRING(5 0,5 10,10 10,10 5,0 5)", "lsls1642.svg"); -to_svg("LINESTRING(1 5,8 4)", "LINESTRING(5 0,5 10,10 10,10 5,0 5)", "lsls1643.svg"); -to_svg("LINESTRING(1 5,8 5)", "LINESTRING(5 0,5 10,10 10,10 5,0 5)", "lsls1644.svg"); -to_svg("LINESTRING(0 5,5 5,8 4)", "LINESTRING(5 0,5 10,10 10,10 5,0 5)", "lsls165.svg"); -to_svg("LINESTRING(0 5,5 5,8 5)", "LINESTRING(5 0,5 10,10 10,10 5,0 5)", "lsls166.svg"); -to_svg("LINESTRING(0 5,5 5,8 5)", "LINESTRING(0 10,10 0,5 0,5 10,10 10,10 5,0 5)", "lsls167.svg"); -to_svg("LINESTRING(0 5,5 5,8 5)", "LINESTRING(0 10,5 5,10 0,5 0,5 5,5 10,10 10,10 5,0 5)", "lsls168.svg"); - -to_svg("LINESTRING(0 0,0 10,10 10,10 0,0 0)", "LINESTRING(0 2,0 0,10 0,10 10,0 10,0 8,0 2)", "lsls1690.svg"); -to_svg("LINESTRING(0 0,10 0,10 10,0 10,0 0)", "LINESTRING(0 8,0 0,10 0,10 10,0 10,0 8)", "lsls1691.svg"); -to_svg("LINESTRING(0 0,10 0,10 10,0 10,0 0)", "LINESTRING(0 2,0 0,10 0,10 10,0 10,0 8)", "lsls1692.svg"); -to_svg("LINESTRING(0 0,0 10,10 10,10 0,0 0)", "LINESTRING(0 2,0 0,10 0,10 10,0 10,0 8)", "lsls1693.svg"); -to_svg("LINESTRING(0 2,0 0,10 0,10 10,0 10,0 8)", "LINESTRING(0 0,10 0,10 10,0 10,0 0)", "lsls1694.svg"); -to_svg("LINESTRING(0 2,0 0,10 0,10 10,0 10,0 8)", "LINESTRING(0 0,0 10,10 10,10 0,0 0)", "lsls1695.svg"); - -to_svg("LINESTRING(0 8,0 0,10 0,10 10,0 10,0 2)", "ls1.svg"); -to_svg("LINESTRING(8 8,0 0,10 0,10 10,0 10,8 2)", "ls2.svg"); - -typedef bg::model::multi_linestring mls; -to_svg("LINESTRING(0 5,10 5,10 10,5 10,5 0)", "MULTILINESTRING((5 0,5 7),(5 8,5 10,10 10,10 5,0 5))", "lsls17.svg"); -to_svg("LINESTRING(0 5,10 5,10 10,5 10,5 0)", "MULTILINESTRING((5 0,5 4,5 6,5 7),(5 8,5 10,10 10,10 5,0 5))", "lsls18.svg"); -to_svg("LINESTRING(0 5,10 5,10 10,5 10,5 0)", "MULTILINESTRING((5 0,5 8),(5 7,5 10,10 10,10 5,0 5))", "lsls19.svg"); -to_svg("MULTILINESTRING((5 0,5 7),(5 8,5 10,10 10,10 5,0 5))", "LINESTRING(0 5,10 5,10 10,5 10,5 0)", "lsls20.svg"); -to_svg("MULTILINESTRING((5 0,5 8),(5 7,5 10,10 10,10 5,0 5))", "LINESTRING(0 5,10 5,10 10,5 10,5 0)", "lsls21.svg"); - -to_svg("LINESTRING(0 5,5 5,10 5,10 10,5 10,5 5,5 0)", "LINESTRING(0 5,5 5,0 10,10 10,10 5,5 5,5 0)", "lsls100.svg"); - -to_svg("LINESTRING(5 0,5 5,5 0)", "LINESTRING(0 5,5 5,0 10,2 10,5 5,5 10,10 10,10 5,5 5,10 2,10 0,8 0,5 5,5 0)", "lsls101.svg"); -*/ From 8ae3b591d389550e789505b5675c1f550a82e7ab Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Tue, 4 Mar 2014 15:37:34 +0100 Subject: [PATCH 02/32] relate(L,L) unused code commented out --- .../detail/relate/linear_linear.hpp | 226 +++++++++--------- 1 file changed, 113 insertions(+), 113 deletions(-) diff --git a/include/boost/geometry/algorithms/detail/relate/linear_linear.hpp b/include/boost/geometry/algorithms/detail/relate/linear_linear.hpp index 24c6925fc..5a5b508e7 100644 --- a/include/boost/geometry/algorithms/detail/relate/linear_linear.hpp +++ b/include/boost/geometry/algorithms/detail/relate/linear_linear.hpp @@ -27,39 +27,6 @@ namespace boost { namespace geometry #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace relate { -enum linestring_kind { linestring_exterior, linestring_point, linestring_closed, linestring_open }; - -template -linestring_kind check_linestring_kind(Linestring const& ls) -{ - std::size_t count = boost::size(ls); - if ( count == 0 ) - return linestring_exterior; - else if ( count == 1 ) - return linestring_point; - else - { - bool equal_fb = equals::equals_point_point(range::front(ls), range::back(ls)); - if ( equal_fb ) - { - typedef typename boost::range_iterator::type iterator; - iterator first = boost::begin(ls); - ++first; - iterator last = boost::end(ls); - --last; - for ( iterator it = first ; it != last ; ++it ) - { - if ( !equals::equals_point_point(range::front(ls), *it) ) - return linestring_closed; - } - - return linestring_point; - } - else - return linestring_open; - } -} - // TODO: // For 1-point linestrings or with all equal points turns won't be generated! // Check for those degenerated cases may be connected with this one! @@ -172,92 +139,125 @@ private: BoundaryChecker * m_boundary_checker_ptr; }; +//enum linestring_kind { linestring_exterior, linestring_point, linestring_closed, linestring_open }; +// +//template +//linestring_kind check_linestring_kind(Linestring const& ls) +//{ +// std::size_t count = boost::size(ls); +// if ( count == 0 ) +// return linestring_exterior; +// else if ( count == 1 ) +// return linestring_point; +// else +// { +// bool equal_fb = equals::equals_point_point(range::front(ls), range::back(ls)); +// if ( equal_fb ) +// { +// typedef typename boost::range_iterator::type iterator; +// iterator first = boost::begin(ls); +// ++first; +// iterator last = boost::end(ls); +// --last; +// for ( iterator it = first ; it != last ; ++it ) +// { +// if ( !equals::equals_point_point(range::front(ls), *it) ) +// return linestring_closed; +// } +// +// return linestring_point; +// } +// else +// return linestring_open; +// } +//} + // Called in a loop for: // Ls/Ls - worst O(N) - 1x point_in_geometry(MLs) // Ls/MLs - worst O(N) - 1x point_in_geometry(MLs) // MLs/Ls - worst O(N^2) - Bx point_in_geometry(Ls) // MLs/MLs - worst O(N^2) - Bx point_in_geometry(Ls) // TODO: later use spatial index -template -class disjoint_linestring_pred_with_point_size_handling -{ - static const bool transpose_result = OpId != 0; - -public: - disjoint_linestring_pred_with_point_size_handling(Result & res, - BoundaryChecker & boundary_checker, - OtherGeometry const& other_geometry) - : m_result_ptr(boost::addressof(res)) - , m_boundary_checker_ptr(boost::addressof(boundary_checker)) - , m_other_geometry(boost::addressof(other_geometry)) - , m_detected_mask_point(0) - , m_detected_open_boundary(false) - {} - - template - bool operator()(Linestring const& linestring) - { - linestring_kind lk = check_linestring_kind(linestring); - - if ( lk == linestring_point ) // just an optimization - { - if ( m_detected_mask_point != 7 ) - { - // check the relation - int pig = within::point_in_geometry(range::front(linestring), *m_other_geometry); - - // point inside - if ( pig > 0 ) - { - update(*m_result_ptr); - m_detected_mask_point |= 1; - } - // point on boundary - else if ( pig == 0 ) - { - update(*m_result_ptr); - m_detected_mask_point |= 2; - } - // point outside - else - { - update(*m_result_ptr); - m_detected_mask_point |= 4; - } - } - } - // NOTE: For closed Linestrings I/I=1 could be set automatically - // but for MultiLinestrings endpoints of closed Linestrings must also be checked for boundary - else if ( lk == linestring_open || lk == linestring_closed ) - { - if ( !m_detected_open_boundary ) // just an optimization - { - update(*m_result_ptr); - - // check if there is a boundary - if ( m_boundary_checker_ptr->template - is_endpoint_boundary(range::front(linestring)) - || m_boundary_checker_ptr->template - is_endpoint_boundary(range::back(linestring)) ) - { - update(*m_result_ptr); - - m_detected_open_boundary = true; - } - } - } - - bool all_detected = m_detected_mask_point == 7 && m_detected_open_boundary; - return !all_detected && !m_result_ptr->interrupt; - } - -private: - Result * m_result_ptr; - BoundaryChecker * m_boundary_checker_ptr; - const OtherGeometry * m_other_geometry; - char m_detected_mask_point; - bool m_detected_open_boundary; -}; +//template +//class disjoint_linestring_pred_with_point_size_handling +//{ +// static const bool transpose_result = OpId != 0; +// +//public: +// disjoint_linestring_pred_with_point_size_handling(Result & res, +// BoundaryChecker & boundary_checker, +// OtherGeometry const& other_geometry) +// : m_result_ptr(boost::addressof(res)) +// , m_boundary_checker_ptr(boost::addressof(boundary_checker)) +// , m_other_geometry(boost::addressof(other_geometry)) +// , m_detected_mask_point(0) +// , m_detected_open_boundary(false) +// {} +// +// template +// bool operator()(Linestring const& linestring) +// { +// linestring_kind lk = check_linestring_kind(linestring); +// +// if ( lk == linestring_point ) // just an optimization +// { +// if ( m_detected_mask_point != 7 ) +// { +// // check the relation +// int pig = within::point_in_geometry(range::front(linestring), *m_other_geometry); +// +// // point inside +// if ( pig > 0 ) +// { +// update(*m_result_ptr); +// m_detected_mask_point |= 1; +// } +// // point on boundary +// else if ( pig == 0 ) +// { +// update(*m_result_ptr); +// m_detected_mask_point |= 2; +// } +// // point outside +// else +// { +// update(*m_result_ptr); +// m_detected_mask_point |= 4; +// } +// } +// } +// // NOTE: For closed Linestrings I/I=1 could be set automatically +// // but for MultiLinestrings endpoints of closed Linestrings must also be checked for boundary +// else if ( lk == linestring_open || lk == linestring_closed ) +// { +// if ( !m_detected_open_boundary ) // just an optimization +// { +// update(*m_result_ptr); +// +// // check if there is a boundary +// if ( m_boundary_checker_ptr->template +// is_endpoint_boundary(range::front(linestring)) +// || m_boundary_checker_ptr->template +// is_endpoint_boundary(range::back(linestring)) ) +// { +// update(*m_result_ptr); +// +// m_detected_open_boundary = true; +// } +// } +// } +// +// bool all_detected = m_detected_mask_point == 7 && m_detected_open_boundary; +// return !all_detected && !m_result_ptr->interrupt; +// } +// +//private: +// Result * m_result_ptr; +// BoundaryChecker * m_boundary_checker_ptr; +// const OtherGeometry * m_other_geometry; +// char m_detected_mask_point; +// bool m_detected_open_boundary; +//}; template struct linear_linear From 38147c2fc7b342f3e003a6382143192e29925614 Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Tue, 4 Mar 2014 16:55:18 +0100 Subject: [PATCH 03/32] relate() for_each_disjoint_linestring_if utility now works for all geometries, renamed to for_each_disjoint_geometry_if --- .../detail/relate/linear_linear.hpp | 31 +++++++++++++------ 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/include/boost/geometry/algorithms/detail/relate/linear_linear.hpp b/include/boost/geometry/algorithms/detail/relate/linear_linear.hpp index 5a5b508e7..d0f4d81af 100644 --- a/include/boost/geometry/algorithms/detail/relate/linear_linear.hpp +++ b/include/boost/geometry/algorithms/detail/relate/linear_linear.hpp @@ -31,13 +31,20 @@ namespace detail { namespace relate { // For 1-point linestrings or with all equal points turns won't be generated! // Check for those degenerated cases may be connected with this one! +// TODO: +// Move this to separate file, maybe name it differently e.g. for_each_turnless_geometry_if + template ::type> -struct for_each_disjoint_linestring_if {}; + typename Tag = typename geometry::tag::type, + bool IsMulti = boost::is_base_of::value +> +struct for_each_disjoint_geometry_if + : public not_implemented +{}; -template -struct for_each_disjoint_linestring_if +template +struct for_each_disjoint_geometry_if { template static inline bool apply(TurnIt first, TurnIt last, @@ -51,8 +58,8 @@ struct for_each_disjoint_linestring_if } }; -template -struct for_each_disjoint_linestring_if +template +struct for_each_disjoint_geometry_if { template static inline bool apply(TurnIt first, TurnIt last, @@ -61,7 +68,11 @@ struct for_each_disjoint_linestring_if { BOOST_ASSERT(first != last); - std::size_t count = boost::size(geometry); + const std::size_t count = boost::size(geometry); + boost::ignore_unused_variable_warning(count); + + // O(I) + // gather info about turns generated for contained geometries std::vector detected_intersections(count, false); for ( TurnIt it = first ; it != last ; ++it ) { @@ -74,6 +85,8 @@ struct for_each_disjoint_linestring_if bool found = false; + // O(N) + // check predicate for each contained geometry without generated turn for ( std::vector::iterator it = detected_intersections.begin() ; it != detected_intersections.end() ; ++it ) { @@ -286,13 +299,13 @@ struct linear_linear boundary_checker boundary_checker1(geometry1); disjoint_linestring_pred<0, Result, boundary_checker > pred1(result, boundary_checker1); - for_each_disjoint_linestring_if<0, Geometry1>::apply(turns.begin(), turns.end(), geometry1, pred1); + for_each_disjoint_geometry_if<0, Geometry1>::apply(turns.begin(), turns.end(), geometry1, pred1); if ( result.interrupt ) return; boundary_checker boundary_checker2(geometry2); disjoint_linestring_pred<1, Result, boundary_checker > pred2(result, boundary_checker2); - for_each_disjoint_linestring_if<1, Geometry2>::apply(turns.begin(), turns.end(), geometry2, pred2); + for_each_disjoint_geometry_if<1, Geometry2>::apply(turns.begin(), turns.end(), geometry2, pred2); if ( result.interrupt ) return; From 9ff0624b410019ad797e2253e2a946e190f60c91 Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Tue, 4 Mar 2014 17:37:12 +0100 Subject: [PATCH 04/32] relate(L,A) added preliminary implementation, for now working only for disjoint geometries --- .../algorithms/detail/relate/linear_areal.hpp | 669 ++++++++++++++++++ .../detail/relate/linear_linear.hpp | 12 +- .../algorithms/detail/relate/relate.hpp | 11 + test/algorithms/relate.cpp | 11 + 4 files changed, 696 insertions(+), 7 deletions(-) create mode 100644 include/boost/geometry/algorithms/detail/relate/linear_areal.hpp diff --git a/include/boost/geometry/algorithms/detail/relate/linear_areal.hpp b/include/boost/geometry/algorithms/detail/relate/linear_areal.hpp new file mode 100644 index 000000000..9ba6491c5 --- /dev/null +++ b/include/boost/geometry/algorithms/detail/relate/linear_areal.hpp @@ -0,0 +1,669 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. + +// This file was modified by Oracle on 2013, 2014. +// Modifications copyright (c) 2013-2014 Oracle and/or its affiliates. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_LINEAR_AREAL_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_LINEAR_AREAL_HPP + +#include +#include + +#include +#include +#include + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace relate { + +template +class disjoint_areal_pred +{ +public: + disjoint_areal_pred(Result & res) + : m_result_ptr(boost::addressof(res)) + {} + + template + bool operator()(Areal const& areal) + { + // TODO: + // add an assertion for empty/invalid geometries + + update(*m_result_ptr); + update(*m_result_ptr); + + return false; + } + +private: + Result * m_result_ptr; +}; + +template +struct linear_areal +{ + static const bool is_linear1 = boost::is_base_of< + linear_tag, + typename geometry::tag::type + >::value; + static const bool is_areal2 = boost::is_base_of< + areal_tag, + typename geometry::tag::type + >::value; + BOOST_STATIC_ASSERT(is_linear1 && is_areal2); + + static const bool interruption_enabled = true; + + typedef typename geometry::point_type::type point1_type; + typedef typename geometry::point_type::type point2_type; + + // if the result should be transposed, because the order of geometries was reversed + // then not transposed result becomes the transposed one, and the opposite + static const bool transpose = !TransposeResult; + + template + static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Result & result) + { + // The result should be FFFFFFFFF + set::value, !transpose>(result);// FFFFFFFFd, d in [1,9] or T + if ( result.interrupt ) + return; + + // get and analyse turns + typedef typename turns::get_turns::turn_info turn_type; + typedef typename std::vector::iterator turn_iterator; + std::vector turns; + +// TODO: INTEGRATE INTERRUPT POLICY WITH THE PASSED RESULT + + turns::get_turns::apply(turns, geometry1, geometry2); + + boundary_checker boundary_checker1(geometry1); + disjoint_linestring_pred, !transpose> pred1(result, boundary_checker1); + for_each_disjoint_geometry_if<0, Geometry1>::apply(turns.begin(), turns.end(), geometry1, pred1); + if ( result.interrupt ) + return; + + disjoint_areal_pred pred2(result); + for_each_disjoint_geometry_if<1, Geometry2>::apply(turns.begin(), turns.end(), geometry2, pred2); + if ( result.interrupt ) + return; + + if ( turns.empty() ) + return; + + std::sort(turns.begin(), turns.end(), turns::less_seg_dist_op<0,2,3,1,4,0,0>()); + + // TODO: + /*turns_analyser<0, turn_type> analyser; + analyse_each_turn(result, analyser, + turns.begin(), turns.end(), + geometry1, geometry2, + boundary_checker1, boundary_checker2);*/ + } +// +// // TODO: rename to point_id_ref? +// template +// class point_identifier +// { +// public: +// point_identifier() : sid_ptr(0), pt_ptr(0) {} +// point_identifier(segment_identifier const& sid, Point const& pt) +// : sid_ptr(boost::addressof(sid)) +// , pt_ptr(boost::addressof(pt)) +// {} +// segment_identifier const& seg_id() const +// { +// BOOST_ASSERT(sid_ptr); +// return *sid_ptr; +// } +// Point const& point() const +// { +// BOOST_ASSERT(pt_ptr); +// return *pt_ptr; +// } +// +// //friend bool operator==(point_identifier const& l, point_identifier const& r) +// //{ +// // return l.seg_id() == r.seg_id() +// // && detail::equals::equals_point_point(l.point(), r.point()); +// //} +// +// private: +// const segment_identifier * sid_ptr; +// const Point * pt_ptr; +// }; +// +// class same_ranges +// { +// public: +// same_ranges(segment_identifier const& sid) +// : sid_ptr(boost::addressof(sid)) +// {} +// +// bool operator()(segment_identifier const& sid) const +// { +// return sid.multi_index == sid_ptr->multi_index +// && sid.ring_index == sid_ptr->ring_index; +// } +// +// template +// bool operator()(point_identifier const& pid) const +// { +// return operator()(pid.seg_id()); +// } +// +// private: +// const segment_identifier * sid_ptr; +// }; +// +// class segment_watcher +// { +// public: +// segment_watcher() +// : m_seg_id_ptr(0) +// {} +// +// bool update(segment_identifier const& seg_id) +// { +// bool result = m_seg_id_ptr == 0 || !same_ranges(*m_seg_id_ptr)(seg_id); +// m_seg_id_ptr = boost::addressof(seg_id); +// return result; +// } +// +// private: +// const segment_identifier * m_seg_id_ptr; +// }; +// +// template +// class exit_watcher +// { +// typedef point_identifier point_info; +// +// public: +// exit_watcher() +// : exit_operation(overlay::operation_none) +// {} +// +// // returns true if before the call we were outside +// bool enter(Point const& point, segment_identifier const& other_id) +// { +// bool result = other_entry_points.empty(); +// other_entry_points.push_back(point_info(other_id, point)); +// return result; +// } +// +// // returns true if before the call we were outside +// bool exit(Point const& point, +// segment_identifier const& other_id, +// overlay::operation_type exit_op) +// { +// // if we didn't entered anything in the past, we're outside +// if ( other_entry_points.empty() ) +// return true; +// +// typedef typename std::vector::iterator point_iterator; +// // search for the entry point in the same range of other geometry +// point_iterator entry_it = std::find_if(other_entry_points.begin(), +// other_entry_points.end(), +// same_ranges(other_id)); +// +// // this end point has corresponding entry point +// if ( entry_it != other_entry_points.end() ) +// { +// // here we know that we possibly left LS +// // we must still check if we didn't get back on the same point +// exit_operation = exit_op; +// exit_id = point_info(other_id, point); +// +// // erase the corresponding entry point +// other_entry_points.erase(entry_it); +// } +// +// return false; +// } +// +// overlay::operation_type get_exit_operation() const +// { +// return exit_operation; +// } +// +// Point const& get_exit_point() const +// { +// BOOST_ASSERT(exit_operation != overlay::operation_none); +// return exit_id.point(); +// } +// +// void reset_detected_exit() +// { +// exit_operation = overlay::operation_none; +// } +// +// private: +// overlay::operation_type exit_operation; +// point_info exit_id; +// std::vector other_entry_points; // TODO: use map here or sorted vector? +// }; +// +// // This analyser should be used like Input or SinglePass Iterator +// template +// class turns_analyser +// { +// typedef typename TurnInfo::point_type turn_point_type; +// +// static const std::size_t op_id = OpId; +// static const std::size_t other_op_id = (OpId + 1) % 2; +// static const bool transpose_result = OpId != 0; +// +// public: +// turns_analyser() +// : m_previous_turn_ptr(0) +// , m_previous_operation(overlay::operation_none) +// {} +// +// template +// void apply(Result & res, +// TurnIt first, TurnIt it, TurnIt last, +// Geometry const& geometry, +// OtherGeometry const& other_geometry, +// BoundaryChecker & boundary_checker, +// OtherBoundaryChecker & other_boundary_checker) +// { +// if ( it != last ) +// { +// overlay::operation_type op = it->operations[op_id].operation; +// +// if ( op != overlay::operation_union +// && op != overlay::operation_intersection +// && op != overlay::operation_blocked ) +// { +// return; +// } +// +// segment_identifier const& seg_id = it->operations[op_id].seg_id; +// segment_identifier const& other_id = it->operations[other_op_id].seg_id; +// +// const bool first_in_range = m_seg_watcher.update(seg_id); +// +// // handle possible exit +// bool fake_enter_detected = false; +// if ( m_exit_watcher.get_exit_operation() == overlay::operation_union ) +// { +// // real exit point - may be multiple +// // we know that we entered and now we exit +// if ( !detail::equals::equals_point_point(it->point, m_exit_watcher.get_exit_point()) ) +// { +// m_exit_watcher.reset_detected_exit(); +// +// // not the last IP +// update(res); +// } +// // fake exit point, reset state +// else if ( op == overlay::operation_intersection ) +// { +// m_exit_watcher.reset_detected_exit(); +// fake_enter_detected = true; +// } +// } +// else if ( m_exit_watcher.get_exit_operation() == overlay::operation_blocked ) +// { +// // ignore multiple BLOCKs +// if ( op == overlay::operation_blocked ) +// return; +// +// m_exit_watcher.reset_detected_exit(); +// } +// +// // if the new linestring started just now, +// // but the previous one went out on the previous point, +// // we must check if the boundary of the previous segment is outside +// // NOTE: couldn't it be integrated with the handling of the union above? +// if ( first_in_range +// && ! fake_enter_detected +// && m_previous_operation == overlay::operation_union ) +// { +// BOOST_ASSERT(it != first); +// BOOST_ASSERT(m_previous_turn_ptr); +// +// segment_identifier const& prev_seg_id = m_previous_turn_ptr->operations[op_id].seg_id; +// +// bool prev_back_b = is_endpoint_on_boundary( +// range::back(sub_geometry::get(geometry, prev_seg_id)), +// boundary_checker); +// +// // if there is a boundary on the last point +// if ( prev_back_b ) +// { +// update(res); +// } +// } +// +// // i/i, i/x, i/u +// if ( op == overlay::operation_intersection ) +// { +// bool was_outside = m_exit_watcher.enter(it->point, other_id); +// +// // interiors overlaps +// update(res); +// +// bool this_b = is_ip_on_boundary(it->point, +// it->operations[op_id], +// boundary_checker, +// seg_id); +// +// // going inside on boundary point +// // may be front only +// if ( this_b ) +// { +// // may be front and back +// bool other_b = is_ip_on_boundary(it->point, +// it->operations[other_op_id], +// other_boundary_checker, +// other_id); +// +// // it's also the boundary of the other geometry +// if ( other_b ) +// { +// update(res); +// } +// else +// { +// update(res); +// } +// } +// // going inside on non-boundary point +// else +// { +// // if we didn't enter in the past, we were outside +// if ( was_outside && !fake_enter_detected ) +// { +// update(res); +// +// // if it's the first IP then the first point is outside +// if ( first_in_range ) +// { +// bool front_b = is_endpoint_on_boundary( +// range::front(sub_geometry::get(geometry, seg_id)), +// boundary_checker); +// +// // if there is a boundary on the first point +// if ( front_b ) +// { +// update(res); +// } +// } +// } +// } +// } +// // u/i, u/u, u/x, x/i, x/u, x/x +// else if ( op == overlay::operation_union || op == overlay::operation_blocked ) +// { +// bool op_blocked = op == overlay::operation_blocked; +// bool was_outside = m_exit_watcher.exit(it->point, other_id, op); +// +// // we're inside, possibly going out right now +// if ( ! was_outside ) +// { +// if ( op_blocked ) +// { +// // check if this is indeed the boundary point +// // NOTE: is_ip_on_boundary<>() should be called here but the result will be the same +// if ( is_endpoint_on_boundary(it->point, boundary_checker) ) +// { +// // may be front and back +// bool other_b = is_ip_on_boundary(it->point, +// it->operations[other_op_id], +// other_boundary_checker, +// other_id); +// // it's also the boundary of the other geometry +// if ( other_b ) +// { +// update(res); +// } +// else +// { +// update(res); +// } +// } +// } +// } +// // we're outside +// else +// { +// update(res); +// +// // boundaries don't overlap - just an optimization +// if ( it->method == overlay::method_crosses ) +// { +// update(res); +// +// // it's the first point in range +// if ( first_in_range ) +// { +// bool front_b = is_endpoint_on_boundary( +// range::front(sub_geometry::get(geometry, seg_id)), +// boundary_checker); +// +// // if there is a boundary on the first point +// if ( front_b ) +// { +// update(res); +// } +// } +// } +// // method other than crosses, check more conditions +// else +// { +// bool this_b = is_ip_on_boundary(it->point, +// it->operations[op_id], +// boundary_checker, +// seg_id); +// +// bool other_b = is_ip_on_boundary(it->point, +// it->operations[other_op_id], +// other_boundary_checker, +// other_id); +// +// // if current IP is on boundary of the geometry +// if ( this_b ) +// { +// // it's also the boundary of the other geometry +// if ( other_b ) +// update(res); +// else +// update(res); +// } +// // if current IP is not on boundary of the geometry +// else +// { +// // it's also the boundary of the other geometry +// if ( other_b ) +// update(res); +// else +// update(res); +// } +// +// // first IP on the last segment point - this means that the first point is outside +// if ( first_in_range && ( !this_b || op_blocked ) ) +// { +// bool front_b = is_endpoint_on_boundary( +// range::front(sub_geometry::get(geometry, seg_id)), +// boundary_checker); +// +// // if there is a boundary on the first point +// if ( front_b ) +// { +// update(res); +// } +// } +// +// } +// } +// } +// +// // store ref to previously analysed (valid) turn +// m_previous_turn_ptr = boost::addressof(*it); +// // and previously analysed (valid) operation +// m_previous_operation = op; +// } +// // it == last +// else +// { +// // here, the possible exit is the real one +// // we know that we entered and now we exit +// if ( m_exit_watcher.get_exit_operation() == overlay::operation_union // THIS CHECK IS REDUNDANT +// || m_previous_operation == overlay::operation_union ) +// { +// // for sure +// update(res); +// +// BOOST_ASSERT(first != last); +// BOOST_ASSERT(m_previous_turn_ptr); +// +// segment_identifier const& prev_seg_id = m_previous_turn_ptr->operations[OpId].seg_id; +// +// bool prev_back_b = is_endpoint_on_boundary( +// range::back(sub_geometry::get(geometry, prev_seg_id)), +// boundary_checker); +// +// // if there is a boundary on the last point +// if ( prev_back_b ) +// { +// update(res); +// } +// } +// } +// } +// +// template +// static inline +// bool is_endpoint_on_boundary(Point const& pt, +// BoundaryChecker & boundary_checker) +// { +// return boundary_checker.template is_endpoint_boundary(pt); +// } +// +// template +// static inline +// bool is_ip_on_boundary(IntersectionPoint const& ip, +// OperationInfo const& operation_info, +// BoundaryChecker & boundary_checker, +// segment_identifier const& seg_id) +// { +// boost::ignore_unused_variable_warning(seg_id); +// +// bool res = false; +// +// // IP on the last point of the linestring +// if ( (BoundaryQuery == boundary_back || BoundaryQuery == boundary_any) +// && operation_info.operation == overlay::operation_blocked ) +// { +// BOOST_ASSERT(operation_info.position == overlay::position_back); +// // check if this point is a boundary +// res = boundary_checker.template is_endpoint_boundary(ip); +// +//#ifdef BOOST_GEOMETRY_DEBUG_RELATE_LINEAR_LINEAR +// BOOST_ASSERT(res == boundary_checker.template is_boundary(ip, seg_id)); +//#endif +// } +// // IP on the last point of the linestring +// else if ( (BoundaryQuery == boundary_front || BoundaryQuery == boundary_any) +// && operation_info.position == overlay::position_front ) +// { +// // check if this point is a boundary +// res = boundary_checker.template is_endpoint_boundary(ip); +// +//#ifdef BOOST_GEOMETRY_DEBUG_RELATE_LINEAR_LINEAR +// BOOST_ASSERT(res == boundary_checker.template is_boundary(ip, seg_id)); +//#endif +// } +// // IP somewhere in the interior +// else +// { +//#ifdef BOOST_GEOMETRY_DEBUG_RELATE_LINEAR_LINEAR +// BOOST_ASSERT(res == boundary_checker.template is_boundary(ip, seg_id)); +//#endif +// } +// +// return res; +// } +// +// private: +// exit_watcher m_exit_watcher; +// segment_watcher m_seg_watcher; +// TurnInfo * m_previous_turn_ptr; +// overlay::operation_type m_previous_operation; +// }; +// +// template +// static inline void analyse_each_turn(Result & res, +// Analyser & analyser, +// TurnIt first, TurnIt last, +// Geometry const& geometry, +// OtherGeometry const& other_geometry, +// BoundaryChecker & boundary_checker, +// OtherBoundaryChecker & other_boundary_checker) +// { +// if ( first == last ) +// return; +// +// for ( TurnIt it = first ; it != last ; ++it ) +// { +// analyser.apply(res, first, it, last, +// geometry, other_geometry, +// boundary_checker, other_boundary_checker); +// +// if ( res.interrupt ) +// return; +// } +// +// analyser.apply(res, first, last, last, +// geometry, other_geometry, +// boundary_checker, other_boundary_checker); +// } +}; + +template +struct areal_linear +{ + template + static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Result & result) + { + linear_areal::apply(geometry2, geometry1, result); + } +}; + +}} // namespace detail::relate +#endif // DOXYGEN_NO_DETAIL + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_LINEAR_AREAL_HPP diff --git a/include/boost/geometry/algorithms/detail/relate/linear_linear.hpp b/include/boost/geometry/algorithms/detail/relate/linear_linear.hpp index d0f4d81af..e2ba8dcff 100644 --- a/include/boost/geometry/algorithms/detail/relate/linear_linear.hpp +++ b/include/boost/geometry/algorithms/detail/relate/linear_linear.hpp @@ -106,11 +106,9 @@ struct for_each_disjoint_geometry_if } }; -template +template class disjoint_linestring_pred { - static const bool transpose_result = OpId != 0; - public: disjoint_linestring_pred(Result & res, BoundaryChecker & boundary_checker) @@ -131,7 +129,7 @@ public: return true; } - update(*m_result_ptr); + update(*m_result_ptr); // check if there is a boundary if ( m_boundary_checker_ptr->template @@ -139,7 +137,7 @@ public: || m_boundary_checker_ptr->template is_endpoint_boundary(range::back(linestring)) ) { - update(*m_result_ptr); + update(*m_result_ptr); return false; } @@ -298,13 +296,13 @@ struct linear_linear turns::get_turns::apply(turns, geometry1, geometry2); boundary_checker boundary_checker1(geometry1); - disjoint_linestring_pred<0, Result, boundary_checker > pred1(result, boundary_checker1); + disjoint_linestring_pred, false> pred1(result, boundary_checker1); for_each_disjoint_geometry_if<0, Geometry1>::apply(turns.begin(), turns.end(), geometry1, pred1); if ( result.interrupt ) return; boundary_checker boundary_checker2(geometry2); - disjoint_linestring_pred<1, Result, boundary_checker > pred2(result, boundary_checker2); + disjoint_linestring_pred, true> pred2(result, boundary_checker2); for_each_disjoint_geometry_if<1, Geometry2>::apply(turns.begin(), turns.end(), geometry2, pred2); if ( result.interrupt ) return; diff --git a/include/boost/geometry/algorithms/detail/relate/relate.hpp b/include/boost/geometry/algorithms/detail/relate/relate.hpp index f3352e00d..7591d073d 100644 --- a/include/boost/geometry/algorithms/detail/relate/relate.hpp +++ b/include/boost/geometry/algorithms/detail/relate/relate.hpp @@ -46,6 +46,7 @@ #include #include #include +#include namespace boost { namespace geometry { @@ -120,6 +121,16 @@ struct relate {}; +template +struct relate + : detail::relate::linear_areal +{}; + +template +struct relate + : detail::relate::areal_linear +{}; + }} // namespace detail_dispatch::relate namespace detail { namespace relate { diff --git a/test/algorithms/relate.cpp b/test/algorithms/relate.cpp index 25fd490f2..edfa836a6 100644 --- a/test/algorithms/relate.cpp +++ b/test/algorithms/relate.cpp @@ -344,6 +344,16 @@ void test_linestring_multi_linestring() //test_geometry("LINESTRING(0 0,10 0)", "MULTILINESTRING((1 0,9 0),(2 0,2 0,2 0))", "101FF0FF2"); } +template +void test_linestring_polygon() +{ + typedef bg::model::linestring

ls; + typedef bg::model::polygon

poly; + + // LS disjoint + test_geometry("LINESTRING(11 0,11 10)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "FF1FF0212"); +} + template void test_all() { @@ -354,6 +364,7 @@ void test_all() test_point_multilinestring

(); test_linestring_linestring

(); test_linestring_multi_linestring

(); + test_linestring_polygon

(); } int test_main( int , char* [] ) From b6ad82a0c2ac475a9be8d2bd8ed9ae76f1c0ef05 Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Fri, 7 Mar 2014 19:41:54 +0100 Subject: [PATCH 05/32] relate() naming of results changed, added de4im matrix --- .../algorithms/detail/relate/linear_areal.hpp | 232 +++--------- .../detail/relate/linear_linear.hpp | 136 +------ .../algorithms/detail/relate/result.hpp | 345 ++++++++++++++---- test/algorithms/relate.cpp | 16 +- 4 files changed, 332 insertions(+), 397 deletions(-) diff --git a/include/boost/geometry/algorithms/detail/relate/linear_areal.hpp b/include/boost/geometry/algorithms/detail/relate/linear_areal.hpp index 9ba6491c5..cf55898be 100644 --- a/include/boost/geometry/algorithms/detail/relate/linear_areal.hpp +++ b/include/boost/geometry/algorithms/detail/relate/linear_areal.hpp @@ -104,168 +104,27 @@ struct linear_areal if ( turns.empty() ) return; + // x, u, i, c std::sort(turns.begin(), turns.end(), turns::less_seg_dist_op<0,2,3,1,4,0,0>()); - // TODO: - /*turns_analyser<0, turn_type> analyser; - analyse_each_turn(result, analyser, - turns.begin(), turns.end(), - geometry1, geometry2, - boundary_checker1, boundary_checker2);*/ + //turns_analyser analyser; + //analyse_each_turn(result, analyser, + // turns.begin(), turns.end(), + // geometry1, geometry2, + // boundary_checker1); } // -// // TODO: rename to point_id_ref? -// template -// class point_identifier -// { -// public: -// point_identifier() : sid_ptr(0), pt_ptr(0) {} -// point_identifier(segment_identifier const& sid, Point const& pt) -// : sid_ptr(boost::addressof(sid)) -// , pt_ptr(boost::addressof(pt)) -// {} -// segment_identifier const& seg_id() const -// { -// BOOST_ASSERT(sid_ptr); -// return *sid_ptr; -// } -// Point const& point() const -// { -// BOOST_ASSERT(pt_ptr); -// return *pt_ptr; -// } -// -// //friend bool operator==(point_identifier const& l, point_identifier const& r) -// //{ -// // return l.seg_id() == r.seg_id() -// // && detail::equals::equals_point_point(l.point(), r.point()); -// //} -// -// private: -// const segment_identifier * sid_ptr; -// const Point * pt_ptr; -// }; -// -// class same_ranges -// { -// public: -// same_ranges(segment_identifier const& sid) -// : sid_ptr(boost::addressof(sid)) -// {} -// -// bool operator()(segment_identifier const& sid) const -// { -// return sid.multi_index == sid_ptr->multi_index -// && sid.ring_index == sid_ptr->ring_index; -// } -// -// template -// bool operator()(point_identifier const& pid) const -// { -// return operator()(pid.seg_id()); -// } -// -// private: -// const segment_identifier * sid_ptr; -// }; -// -// class segment_watcher -// { -// public: -// segment_watcher() -// : m_seg_id_ptr(0) -// {} -// -// bool update(segment_identifier const& seg_id) -// { -// bool result = m_seg_id_ptr == 0 || !same_ranges(*m_seg_id_ptr)(seg_id); -// m_seg_id_ptr = boost::addressof(seg_id); -// return result; -// } -// -// private: -// const segment_identifier * m_seg_id_ptr; -// }; -// -// template -// class exit_watcher -// { -// typedef point_identifier point_info; -// -// public: -// exit_watcher() -// : exit_operation(overlay::operation_none) -// {} -// -// // returns true if before the call we were outside -// bool enter(Point const& point, segment_identifier const& other_id) -// { -// bool result = other_entry_points.empty(); -// other_entry_points.push_back(point_info(other_id, point)); -// return result; -// } -// -// // returns true if before the call we were outside -// bool exit(Point const& point, -// segment_identifier const& other_id, -// overlay::operation_type exit_op) -// { -// // if we didn't entered anything in the past, we're outside -// if ( other_entry_points.empty() ) -// return true; -// -// typedef typename std::vector::iterator point_iterator; -// // search for the entry point in the same range of other geometry -// point_iterator entry_it = std::find_if(other_entry_points.begin(), -// other_entry_points.end(), -// same_ranges(other_id)); -// -// // this end point has corresponding entry point -// if ( entry_it != other_entry_points.end() ) -// { -// // here we know that we possibly left LS -// // we must still check if we didn't get back on the same point -// exit_operation = exit_op; -// exit_id = point_info(other_id, point); -// -// // erase the corresponding entry point -// other_entry_points.erase(entry_it); -// } -// -// return false; -// } -// -// overlay::operation_type get_exit_operation() const -// { -// return exit_operation; -// } -// -// Point const& get_exit_point() const -// { -// BOOST_ASSERT(exit_operation != overlay::operation_none); -// return exit_id.point(); -// } -// -// void reset_detected_exit() -// { -// exit_operation = overlay::operation_none; -// } -// -// private: -// overlay::operation_type exit_operation; -// point_info exit_id; -// std::vector other_entry_points; // TODO: use map here or sorted vector? -// }; -// // // This analyser should be used like Input or SinglePass Iterator -// template +// template // class turns_analyser // { // typedef typename TurnInfo::point_type turn_point_type; // -// static const std::size_t op_id = OpId; -// static const std::size_t other_op_id = (OpId + 1) % 2; -// static const bool transpose_result = OpId != 0; +// static const std::size_t op_id = 0; +// static const std::size_t other_op_id = 1; +// // if the result should be transposed, because the order of geometries was reversed +// // then not transposed result becomes the transposed one, and the opposite +// static const bool transpose_result = !TransposeResult; // // public: // turns_analyser() @@ -283,8 +142,7 @@ struct linear_areal // TurnIt first, TurnIt it, TurnIt last, // Geometry const& geometry, // OtherGeometry const& other_geometry, -// BoundaryChecker & boundary_checker, -// OtherBoundaryChecker & other_boundary_checker) +// BoundaryChecker & boundary_checker) // { // if ( it != last ) // { @@ -616,39 +474,37 @@ struct linear_areal // TurnInfo * m_previous_turn_ptr; // overlay::operation_type m_previous_operation; // }; -// -// template -// static inline void analyse_each_turn(Result & res, -// Analyser & analyser, -// TurnIt first, TurnIt last, -// Geometry const& geometry, -// OtherGeometry const& other_geometry, -// BoundaryChecker & boundary_checker, -// OtherBoundaryChecker & other_boundary_checker) -// { -// if ( first == last ) -// return; -// -// for ( TurnIt it = first ; it != last ; ++it ) -// { -// analyser.apply(res, first, it, last, -// geometry, other_geometry, -// boundary_checker, other_boundary_checker); -// -// if ( res.interrupt ) -// return; -// } -// -// analyser.apply(res, first, last, last, -// geometry, other_geometry, -// boundary_checker, other_boundary_checker); -// } + + template + static inline void analyse_each_turn(Result & res, + Analyser & analyser, + TurnIt first, TurnIt last, + Geometry const& geometry, + OtherGeometry const& other_geometry, + BoundaryChecker & boundary_checker) + { + if ( first == last ) + return; + + for ( TurnIt it = first ; it != last ; ++it ) + { + analyser.apply(res, first, it, last, + geometry, other_geometry, + boundary_checker); + + if ( res.interrupt ) + return; + } + + analyser.apply(res, first, last, last, + geometry, other_geometry, + boundary_checker); + } }; template diff --git a/include/boost/geometry/algorithms/detail/relate/linear_linear.hpp b/include/boost/geometry/algorithms/detail/relate/linear_linear.hpp index e2ba8dcff..cff274910 100644 --- a/include/boost/geometry/algorithms/detail/relate/linear_linear.hpp +++ b/include/boost/geometry/algorithms/detail/relate/linear_linear.hpp @@ -316,6 +316,7 @@ struct linear_linear // TODO: ADD A CHECK TO THE RESULT INDICATING IF THE FIRST AND/OR SECOND GEOMETRY MUST BE ANALYSED { + // x, u, i, c std::sort(turns.begin(), turns.end(), turns::less_seg_dist_op<0,2,3,1,4,0,0>()); turns_analyser<0, turn_type> analyser; @@ -329,6 +330,7 @@ struct linear_linear return; { + // x, u, i, c std::sort(turns.begin(), turns.end(), turns::less_seg_dist_op<0,2,3,1,4,0,1>()); turns_analyser<1, turn_type> analyser; @@ -874,140 +876,6 @@ struct linear_linear geometry, other_geometry, boundary_checker, other_boundary_checker); } - - //template - //static inline void analyse_turns_simple(result & res, - // TurnIt first, TurnIt last, - // Geometry1 const& geometry1, - // Geometry2 const& geometry2, - // bool has_boundary1, bool has_boundary2) - //{ - // for ( TurnIt it = first ; it != last ; ++it ) - // { - // // 'i' - // if ( it->method == overlay::method_crosses ) - // { - // res.template update(); // always true - // res.template update(); // not always true - // res.template update(); // not always true - // } - // // 'e' 'c' - // else if ( it->method == overlay::method_equal - // || it->method == overlay::method_collinear ) - // { - // res.template update(); // always true - // } - // // 't' 'm' - // else if ( it->method == overlay::method_touch - // || it->method == overlay::method_touch_interior ) - // { - // bool b = handle_boundary_point(res, *it, geometry1, geometry2, has_boundary1, has_boundary2); - // - // if ( it->has(overlay::operation_union) ) - // { - // if ( !b ) - // res.template update(); - // if ( it->operations[0].operation == overlay::operation_union ) - // res.template update(); - // if ( it->operations[1].operation == overlay::operation_union ) - // res.template update(); - // } - - // if ( it->has(overlay::operation_intersection) ) - // res.template update(); - - // if ( it->has(overlay::operation_blocked) ) - // if ( !b ) - // res.template update(); - // } - // - // } - //} - - //template - //static inline bool handle_boundary_point(result & res, - // Turn const& turn, - // Geometry1 const& geometry1, Geometry2 const& geometry2, - // bool has_boundary1, bool has_boundary2) - //{ - // bool pt_on_boundary1 = has_boundary1 && equals_terminal_point(turn.point, geometry1); - // bool pt_on_boundary2 = has_boundary2 && equals_terminal_point(turn.point, geometry2); - - // if ( pt_on_boundary1 && pt_on_boundary2 ) - // res.template update(); - // else if ( pt_on_boundary1 ) - // res.template update(); - // else if ( pt_on_boundary2 ) - // res.template update(); - // else - // return false; - // return true; - //} - - //// TODO: replace with generic point_in_boundary working also for multilinestrings - //template - //static inline bool equals_terminal_point(Point const& point, Geometry const& geometry) - //{ - // return detail::equals::equals_point_point(point, range::front(geometry)) - // || detail::equals::equals_point_point(point, range::back(geometry)); - //} - - //static inline void handle_boundaries(result & res, - // Geometry1 const& geometry1, Geometry2 const& geometry2, - // bool has_boundary1, bool has_boundary2) - //{ - // int pig_front = detail::within::point_in_geometry(range::front(geometry1), geometry2); - - // if ( has_boundary1 ) - // { - // int pig_back = detail::within::point_in_geometry(range::back(geometry1), geometry2); - - // if ( pig_front > 0 || pig_back > 0 ) - // res.template set(); - // if ( pig_front == 0 || pig_back == 0 ) - // res.template set(); - // if ( pig_front < 0 || pig_back < 0 ) - // { - // res.template set(); - // res.template set(); - // } - // } - // else - // { - // if ( pig_front > 0 ) - // res.template set(); - // else if ( pig_front == 0 ) - // res.template set(); - // else if ( pig_front < 0 ) - // res.template set(); - // } - - // pig_front = detail::within::point_in_geometry(range::front(geometry2), geometry1); - - // if ( has_boundary2 ) - // { - // int pig_back = detail::within::point_in_geometry(range::back(geometry2), geometry1); - - // if ( pig_front > 0 || pig_back > 0 ) - // res.template set(); - // if ( pig_front == 0 || pig_back == 0 ) - // res.template set(); - // if ( pig_front < 0 || pig_back < 0 ) - // { - // res.template set(); - // res.template set(); - // } - // } - // else - // { - // if ( pig_front > 0 ) - // res.template set(); - // else if ( pig_front == 0 ) - // res.template set(); - // else if ( pig_front < 0 ) - // res.template set(); - // } - //} }; }} // namespace detail::relate diff --git a/include/boost/geometry/algorithms/detail/relate/result.hpp b/include/boost/geometry/algorithms/detail/relate/result.hpp index d5bf04f3d..f268a0533 100644 --- a/include/boost/geometry/algorithms/detail/relate/result.hpp +++ b/include/boost/geometry/algorithms/detail/relate/result.hpp @@ -19,38 +19,136 @@ namespace detail { namespace relate { enum field { interior = 0, boundary = 1, exterior = 2 }; -// With DE9IM only Dimension < 10 is supported -class result +// TODO add EnableDimensions parameter + +template +class matrix { + BOOST_STATIC_ASSERT(Width == 2 || Width == 3); + public: static const bool interrupt = false; -// TODO: replace with std::string? - inline result() + static const std::size_t size = Width * Width; + + inline matrix() { - ::memset(m_array, 'F', 9); - } - - template - inline char get() const - { - return m_array[F1 * 3 + F2]; + ::memset(m_array, 'F', size); } template inline void set() { - m_array[F1 * 3 + F2] = V; + static const bool in_bounds = F1 * Width + F2 < size; + set_dispatch(integral_constant()); } - inline std::pair get_code() const + template + inline void update() { - return std::make_pair(m_array, m_array+9); + static const bool in_bounds = F1 * Width + F2 < size; + update_dispatch(integral_constant()); + } + + inline const char * data() const + { + return m_array; } private: - char m_array[9]; + template + inline void set_dispatch(integral_constant) + { + BOOST_STATIC_ASSERT('0' <= V && V <= '9' || V == 'T' || V == 'F'); + m_array[F1 * Width + F2] = V; + } + template + inline void set_dispatch(integral_constant) + {} + + template + inline void update_dispatch(integral_constant) + { + BOOST_STATIC_ASSERT('0' <= D && D <= '9'); + char c = m_array[F1 * Width + F2]; + if ( D > c || c > '9') + m_array[F1 * Width + F2] = D; + } + template + inline void update_dispatch(integral_constant) + {} + + char m_array[size]; +}; + +class matrix9 + : public matrix<3> +{}; + +class matrix4 + : public matrix<2> +{}; + +inline bool check_element(char mask_el, char el) +{ + if ( mask_el == 'F' ) + { + return el == 'F'; + } + else if ( mask_el == 'T' ) + { + return el == 'T' || ( el >= '0' && el <= '9' ); + } + else if ( mask_el >= '0' && mask_el <= '9' ) + { + return el == mask_el; + } + + return true; +} + +template +inline bool check_element(char el) +{ + if ( MaskEl == 'F' ) + { + return el == 'F'; + } + else if ( MaskEl == 'T' ) + { + return el == 'T' || ( el >= '0' && el <= '9' ); + } + else if ( MaskEl >= '0' && MaskEl <= '9' ) + { + return el == mask_el; + } + + return true; +} + +template +inline bool interrupt(char mask_el) +{ + if ( V >= '0' && V <= '9' ) + { + return mask_el == 'F' || ( mask_el < V && mask_el >= '0' && mask_el <= '9' ); + } + else if ( V == 'T' ) + { + return mask_el == 'F'; + } + return false; +} + +template +struct static_interrupt +{ + static const bool value + = ( V >= '0' && V <= '9' ) ? + ( MaskEl == 'F' || ( MaskEl < V && MaskEl >= '0' && MaskEl <= '9' ) ) : + ( ( V == 'T' ) ? MaskEl == 'F' : false ); + }; // TODO: possible optimizations @@ -58,14 +156,14 @@ private: // 2. static_mask setting interrupt in compile-time template -class mask - : public result +class mask9 + : public matrix9 { public: bool interrupt; - inline mask(std::string const& de9im_mask) + inline mask9(std::string const& de9im_mask) : interrupt(false) { BOOST_ASSERT(de9im_mask.size() == 9); @@ -76,71 +174,187 @@ public: inline void set() { handle_interrupt_dispatch(boost::integral_constant()); - - result::set(); + matrix9::set(); } inline bool check() const { if ( interrupt ) return false; - - std::pair range = result::get_code(); - const char* m_it = m_mask; - const char* a_it = range.first; - for ( ; a_it != range.second ; ++a_it, ++m_it ) + + for ( std::size_t i = 0 ; i < 9 ; ++i ) { - if ( *m_it == 'F' ) - { - if ( *a_it != 'F' ) - return false; - } - else if ( *m_it == 'T' ) - { - if ( *a_it != 'T' && ( *a_it < '0' || *a_it > '9' ) ) - return false; - } - else if ( *m_it >= '0' && *m_it <= '9' ) - { - if ( *a_it != *m_it ) - return false; - } + if ( !check_element(m_mask[i], matrix9::data()[i]) ) + return false; } return true; } private: + template + void handle_interrupt_dispatch(boost::integral_constant) + { + char m = m_mask[F1 * 3 + F2]; + if ( relate::interrupt(m) ) + interrupt = true; + } + template void handle_interrupt_dispatch(boost::integral_constant) {} - template - void handle_interrupt_dispatch(boost::integral_constant) - { - char m = get_mask(); - - if ( V >= '0' && V <= '9' ) - { - if ( m == 'F' || ( m < V && m >= '0' && m <= '9' ) ) - interrupt = true; - } - else if ( V == 'T' ) - { - if ( m == 'F' ) - interrupt = true; - } - } - - template - inline char get_mask() const - { - return m_mask[F1 * 3 + F2]; - } - char m_mask[9]; }; +//template