From c0598807db559d9abda57d0864dd7daca0da0670 Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Thu, 6 Feb 2014 00:22:54 +0100 Subject: [PATCH 1/7] handled non-simple Linestrings, for now without spikes --- .../detail/relate/linear_linear.hpp | 219 +++++++++++++++++- test/algorithms/relate.cpp | 3 +- 2 files changed, 216 insertions(+), 6 deletions(-) diff --git a/include/boost/geometry/algorithms/detail/relate/linear_linear.hpp b/include/boost/geometry/algorithms/detail/relate/linear_linear.hpp index ec9bf4e92..16c3384c6 100644 --- a/include/boost/geometry/algorithms/detail/relate/linear_linear.hpp +++ b/include/boost/geometry/algorithms/detail/relate/linear_linear.hpp @@ -25,6 +25,30 @@ namespace boost { namespace geometry #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace relate { +template +struct update_result_dispatch +{ + static inline void apply(result & res) + { + res.template update(); + } +}; + +template +struct update_result_dispatch +{ + static inline void apply(result & res) + { + res.template update(); + } +}; + +template +inline void update_result(result & res) +{ + update_result_dispatch::apply(res); +} + // currently works only for linestrings template struct linear_linear @@ -74,20 +98,205 @@ struct linear_linear turns::get_turns::apply(turns, geometry1, geometry2); + if ( turns.empty() ) + { + return res; + } + // TODO: turns must be sorted and followed only if it's possible to go out and in on the same point // for linear geometries union operation must be detected which I guess would be quite often - std::sort(turns.begin(), turns.end(), turns::less_seg_dist_op<>()); + std::sort(turns.begin(), turns.end(), turns::less_seg_dist_op<0,1,2,4,3,0,0>()); - analyse_turns(res, turns.begin(), turns.end(), geometry1, geometry2, has_boundary1, has_boundary2); + analyse_turns<0, 1>(res, turns.begin(), turns.end(), geometry1, geometry2, has_boundary1, has_boundary2); + + std::sort(turns.begin(), turns.end(), turns::less_seg_dist_op<0,1,2,4,3,0,1>()); + + analyse_turns<1, 0>(res, turns.begin(), turns.end(), geometry2, geometry1, has_boundary2, has_boundary1); return res; } - template + 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)) + {} + + template + bool operator()(point_identifier const& pid) + { + return pid.seg_id().multi_index == sid_ptr->multi_index + && pid.seg_id().ring_index == sid_ptr->ring_index; + } + private: + const segment_identifier * sid_ptr; + }; + + template static inline void analyse_turns(result & res, TurnIt first, TurnIt last, - Geometry1 const& geometry1, Geometry2 const& geometry2, - bool has_boundary1, bool has_boundary2) + Geometry const& geometry, + OtherGeometry const& other_geometry, + bool has_boundary, + bool other_has_boundary) + { + // should be the same as the one stored in Turn + typedef typename point_type::type point_type; + typedef point_identifier point_identifier; + static const bool reverse_result = OpId != 0; + + if ( first == last ) + return; + + typedef typename std::vector::iterator point_iterator; + std::vector entry_points; // TODO: use map here or sorted vector? + + bool possible_exit_detected = false; + point_identifier possible_exit_point; + + for ( TurnIt it = first ; it != last ; ++it ) + { + overlay::operation_type op = it->operations[OpId].operation; + + // handle possible exit + if ( possible_exit_detected && + ( op == overlay::operation_union || op == overlay::operation_intersection + || op == overlay::operation_continue || op == overlay::operation_blocked ) ) + { + // real exit point - may be multiple + // we know that we entered and now we exit + if ( !detail::equals::equals_point_point(it->point, possible_exit_point.point()) ) + { + possible_exit_detected = false; + + // not the last IP + update_result(res); + } + // fake exit point, reset state + // in reality this will be op == overlay::operation_intersection + else if ( op != overlay::operation_union ) + { + possible_exit_detected = false; + } + } + + if ( op == overlay::operation_intersection ) + { + // here we know that we entered the range + entry_points.push_back(point_identifier(it->operations[OpId].seg_id, it->point)); + + update_result(res); + // if the first point of P and/or Q is boundary then also + //update_result(res); + // or + //update_result(res); + } + else if ( op == overlay::operation_blocked + || op == overlay::operation_union ) + { + if ( !entry_points.empty() ) + { + segment_identifier const& seg_id = it->operations[OpId].seg_id; + point_iterator entry_it = std::find_if(entry_points.begin(), + entry_points.end(), + same_ranges(seg_id)); + if ( entry_it != entry_points.end() ) + { + if ( op == overlay::operation_union ) + { + // here we know that we possibly left LS + // we must still check if we didn't get back on the same point + possible_exit_detected = true; + possible_exit_point = point_identifier(seg_id, it->point); + } + else // op == overlay::operation_blocked + { + // here we know that we're on the last point of the range + + // depending on the other operation + //update_result(res); + // or + //update_result(res); + } + + // erase the corresponding entry point, + // don't postpone the erasure decision because + // there may be multiple exit IPs on the same point + // and we'd be forced to store them all just like the entry points + entry_points.erase(entry_it); + } + } + else + { + update_result(res); + + if ( it->method == overlay::method_crosses ) + update_result(res); + + // or depending on the IP + //update_result(res); + // or + //update_result(res); + } + } + else if ( op == overlay::operation_continue ) + { + update_result(res); + } + } + + // here, the possible exit is the real one + // we know that we entered and now we exit + if ( possible_exit_detected ) + { + update_result(res); + // if has boundary on the last point of the current range + //update_result(res); + } + } + + 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 ) { diff --git a/test/algorithms/relate.cpp b/test/algorithms/relate.cpp index 8d4a4d12e..7c578ac4a 100644 --- a/test/algorithms/relate.cpp +++ b/test/algorithms/relate.cpp @@ -124,7 +124,8 @@ void test_linestring_linestring() test_geometry("LINESTRING(0 0,2 2,3 3,1 1,5 3)", "LINESTRING(6 3,3 3,0 0)", "1F100F102"); test_geometry("LINESTRING(5 3,1 1,3 3,2 2,0 0)", "LINESTRING(6 3,3 3,0 0)", "1F100F102"); - + test_geometry("LINESTRING(0 0,10 0)", + "LINESTRING(1 0,9 0,2 0)", "101FF0FF2"); test_geometry("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)", "1FFF0FFF2"); From 4881b94ee66e6e4470beacf2df07edeff9d9f07a Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Thu, 6 Feb 2014 00:47:16 +0100 Subject: [PATCH 2/7] added a comment --- .../multi/algorithms/detail/within/point_in_geometry.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/boost/geometry/multi/algorithms/detail/within/point_in_geometry.hpp b/include/boost/geometry/multi/algorithms/detail/within/point_in_geometry.hpp index b9ef5e406..da8005512 100644 --- a/include/boost/geometry/multi/algorithms/detail/within/point_in_geometry.hpp +++ b/include/boost/geometry/multi/algorithms/detail/within/point_in_geometry.hpp @@ -84,6 +84,8 @@ struct point_in_geometry if ( pip < 0 ) return -1; + // TODO: the following isn't needed for covered_by() + unsigned boundaries = pip == 0 ? 1 : 0; for ( ; it != boost::end(geometry) ; ++it ) From 5e3223e4676075ce086d63bc638ccd89ad5012ea Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Thu, 6 Feb 2014 01:27:52 +0100 Subject: [PATCH 3/7] fixed error in relate(), entry points seg_id replaced by other_seg_id - required for MultiLinestrings --- .../detail/relate/linear_linear.hpp | 20 +++++++++---------- test/algorithms/relate.cpp | 5 +++++ 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/include/boost/geometry/algorithms/detail/relate/linear_linear.hpp b/include/boost/geometry/algorithms/detail/relate/linear_linear.hpp index 16c3384c6..d76ecd69d 100644 --- a/include/boost/geometry/algorithms/detail/relate/linear_linear.hpp +++ b/include/boost/geometry/algorithms/detail/relate/linear_linear.hpp @@ -185,7 +185,7 @@ struct linear_linear return; typedef typename std::vector::iterator point_iterator; - std::vector entry_points; // TODO: use map here or sorted vector? + std::vector other_entry_points; // TODO: use map here or sorted vector? bool possible_exit_detected = false; point_identifier possible_exit_point; @@ -219,7 +219,7 @@ struct linear_linear if ( op == overlay::operation_intersection ) { // here we know that we entered the range - entry_points.push_back(point_identifier(it->operations[OpId].seg_id, it->point)); + other_entry_points.push_back(point_identifier(it->operations[OpId].other_id, it->point)); update_result(res); // if the first point of P and/or Q is boundary then also @@ -230,20 +230,20 @@ struct linear_linear else if ( op == overlay::operation_blocked || op == overlay::operation_union ) { - if ( !entry_points.empty() ) + if ( !other_entry_points.empty() ) { - segment_identifier const& seg_id = it->operations[OpId].seg_id; - point_iterator entry_it = std::find_if(entry_points.begin(), - entry_points.end(), - same_ranges(seg_id)); - if ( entry_it != entry_points.end() ) + segment_identifier const& other_id = it->operations[OpId].other_id; + point_iterator entry_it = std::find_if(other_entry_points.begin(), + other_entry_points.end(), + same_ranges(other_id)); + if ( entry_it != other_entry_points.end() ) { if ( op == overlay::operation_union ) { // here we know that we possibly left LS // we must still check if we didn't get back on the same point possible_exit_detected = true; - possible_exit_point = point_identifier(seg_id, it->point); + possible_exit_point = point_identifier(other_id, it->point); } else // op == overlay::operation_blocked { @@ -259,7 +259,7 @@ struct linear_linear // don't postpone the erasure decision because // there may be multiple exit IPs on the same point // and we'd be forced to store them all just like the entry points - entry_points.erase(entry_it); + other_entry_points.erase(entry_it); } } else diff --git a/test/algorithms/relate.cpp b/test/algorithms/relate.cpp index 7c578ac4a..8343f7bbc 100644 --- a/test/algorithms/relate.cpp +++ b/test/algorithms/relate.cpp @@ -124,9 +124,14 @@ void test_linestring_linestring() test_geometry("LINESTRING(0 0,2 2,3 3,1 1,5 3)", "LINESTRING(6 3,3 3,0 0)", "1F100F102"); test_geometry("LINESTRING(5 3,1 1,3 3,2 2,0 0)", "LINESTRING(6 3,3 3,0 0)", "1F100F102"); + // spike test_geometry("LINESTRING(0 0,10 0)", "LINESTRING(1 0,9 0,2 0)", "101FF0FF2"); + // loop i/i i/i u/u u/u + test_geometry("LINESTRING(0 0,10 0)", + "LINESTRING(1 1,1 0,6 0,6 1,4 1,4 0,9 0,9 1)", "1F1FF0102"); + test_geometry("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)", "1FFF0FFF2"); From d56a7bcc2ebe3eadd8c2a41cb5aaccfc9cb05f6c Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Fri, 7 Feb 2014 18:58:53 +0100 Subject: [PATCH 4/7] relate(L,L) algorithm without preliminary boundaries analisys - work in progress --- .../detail/relate/linear_linear.hpp | 409 ++++++++++++++---- 1 file changed, 336 insertions(+), 73 deletions(-) diff --git a/include/boost/geometry/algorithms/detail/relate/linear_linear.hpp b/include/boost/geometry/algorithms/detail/relate/linear_linear.hpp index d76ecd69d..2652f4114 100644 --- a/include/boost/geometry/algorithms/detail/relate/linear_linear.hpp +++ b/include/boost/geometry/algorithms/detail/relate/linear_linear.hpp @@ -25,6 +25,8 @@ namespace boost { namespace geometry #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace relate { +// update_result + template struct update_result_dispatch { @@ -49,6 +51,109 @@ inline void update_result(result & res) update_result_dispatch::apply(res); } +// boundary_checker + +template ::type> +class boundary_checker {}; + +template +class boundary_checker +{ + typedef typename point_type::type point_type; + +public: + boundary_checker(Geometry const& g) + : has_boundary(! detail::equals::equals_point_point(range::front(g), range::back(g))) + , geometry(g) + {} + + // TODO: optimization expect ENTRY or EXIT + bool is_boundary(point_type const& pt, segment_identifier const& sid) + { + // TODO: replace with assert? + if ( boost::size(geometry) < 2 ) + return false; + + // TODO: handle also linestrings with points_num == 2 and equals(front, back) - treat like point? + + return has_boundary + && ( ( sid.segment_index == 0 + && detail::equals::equals_point_point(pt, range::front(geometry)) ) + || ( sid.segment_index + 2 == geometry::num_points(geometry) + && detail::equals::equals_point_point(pt, range::back(geometry)) ) ); + } + +private: + bool has_boundary; + Geometry const& geometry; +}; + +template +class boundary_checker +{ + typedef typename point_type::type point_type; + +public: + boundary_checker(Geometry const& g) + : is_filled(false), geometry(g) + {} + + // TODO: optimization expect ENTRY or EXIT + bool is_boundary(point_type const& pt, segment_identifier const& sid) + { + typedef typename boost::range_size::type size_type; + size_type multi_count = boost::size(geometry); + + // TODO: replace with assert? + if ( multi_count < 1 ) + return false; + + if ( sid.segment_index != 0 && sid.segment_index + 2 != geometry::num_points(geometry) ) + return false; + + if ( ! is_filled ) + { + //boundary_points.clear(); + boundary_points.reserve(multi_count * 2); + + typedef typename boost::range_iterator::type multi_iterator; + for ( multi_iterator it = boost::begin(geometry) ; + it != boost::end(geometry) ; ++ it ) + { + // point - no boundary + if ( boost::size(*it) < 2 ) + continue; + + // TODO: handle also linestrings with points_num == 2 and equals(front, back) - treat like point? + + boundary_points.push_back(range::front(geometry)); + boundary_points.push_back(range::back(geometry)); + } + + std::sort(boundary_points.begin(), boundary_points.end(), geometry::less()); + + is_filled = true; + } + + std::size_t equal_points_count + = boost::size( + std::equal_range(boundary_points.begin(), + boundary_points.end(), + geometry::less()) + ); + + return equal_points_count % 2 != 0 && equal_points_count > 0; // the number is odd and > 0 + + } + +private: + bool is_filled; + // TODO: store references/pointers instead of points? + std::vector boundary_points; + Geometry const& geometry; +}; + // currently works only for linestrings template struct linear_linear @@ -86,11 +191,10 @@ struct linear_linear if ( dimension < 10 ) res.template set(); - // TODO: implement generic function working also for multilinestrings, also use it in point_in_geometry - bool has_boundary1 = ! detail::equals::equals_point_point(range::front(geometry1), range::back(geometry1)); - bool has_boundary2 = ! detail::equals::equals_point_point(range::front(geometry2), range::back(geometry2)); - - handle_boundaries(res, geometry1, geometry2, has_boundary1, has_boundary2); + // TEMP + //bool has_boundary1 = ! detail::equals::equals_point_point(range::front(geometry1), range::back(geometry1)); + //bool has_boundary2 = ! detail::equals::equals_point_point(range::front(geometry2), range::back(geometry2)); + //handle_boundaries(res, geometry1, geometry2, has_boundary1, has_boundary2); // get and analyse turns @@ -103,19 +207,27 @@ struct linear_linear return res; } + boundary_checker boundary_checker1(geometry1); + boundary_checker boundary_checker2(geometry2); + // TODO: turns must be sorted and followed only if it's possible to go out and in on the same point // for linear geometries union operation must be detected which I guess would be quite often std::sort(turns.begin(), turns.end(), turns::less_seg_dist_op<0,1,2,4,3,0,0>()); - analyse_turns<0, 1>(res, turns.begin(), turns.end(), geometry1, geometry2, has_boundary1, has_boundary2); + analyse_turns<0, 1>(res, turns.begin(), turns.end(), + geometry1, geometry2, + boundary_checker1, boundary_checker2); std::sort(turns.begin(), turns.end(), turns::less_seg_dist_op<0,1,2,4,3,0,1>()); - analyse_turns<1, 0>(res, turns.begin(), turns.end(), geometry2, geometry1, has_boundary2, has_boundary1); + analyse_turns<1, 0>(res, turns.begin(), turns.end(), + geometry2, geometry1, + boundary_checker2, boundary_checker1); return res; } + // TODO: rename to point_id_ref? template class point_identifier { @@ -154,140 +266,291 @@ struct linear_linear : sid_ptr(boost::addressof(sid)) {} - template - bool operator()(point_identifier const& pid) + bool operator()(segment_identifier const& sid) const { - return pid.seg_id().multi_index == sid_ptr->multi_index - && pid.seg_id().ring_index == sid_ptr->ring_index; + 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_identifier; + + public: + exit_watcher() + : exit_detected(false) + {} + + // 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_identifier(other_id, point)); + return result; + } + + // returns true if before the call we were outside + bool exit(Point const& point, + segment_identifier const& other_id, + bool is_last_point) + { + // 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() ) + { + if ( ! is_last_point ) + { + // here we know that we possibly left LS + // we must still check if we didn't get back on the same point + exit_detected = true; + exit_id = point_identifier(other_id, point); + } + + // erase the corresponding entry point + other_entry_points.erase(entry_it); + } + + return false; + } + + bool is_exit_detected() const + { + return exit_detected; + } + + Point const& get_exit_point() const + { + BOOST_ASSERT(exit_detected); + return exit_id.point(); + } + + overlay::operation_type get_exit_operation() const + { + BOOST_ASSERT(exit_detected); + return exit_operation; + } + + void reset_detected_exit() + { + exit_detected = false; + } + + private: + bool exit_detected; + point_identifier exit_id; + std::vector other_entry_points; // TODO: use map here or sorted vector? + }; + template + typename OtherGeometry, + typename BoundaryChecker, + typename OtherBoundaryChecker> static inline void analyse_turns(result & res, TurnIt first, TurnIt last, Geometry const& geometry, OtherGeometry const& other_geometry, - bool has_boundary, - bool other_has_boundary) + BoundaryChecker boundary_checker, + OtherBoundaryChecker other_boundary_checker) { - // should be the same as the one stored in Turn + // point_type should be the same as the one stored in Turn typedef typename point_type::type point_type; - typedef point_identifier point_identifier; static const bool reverse_result = OpId != 0; if ( first == last ) return; - typedef typename std::vector::iterator point_iterator; - std::vector other_entry_points; // TODO: use map here or sorted vector? - - bool possible_exit_detected = false; - point_identifier possible_exit_point; + exit_watcher exit_watcher; + segment_watcher seg_watcher; for ( TurnIt it = first ; it != last ; ++it ) { overlay::operation_type op = it->operations[OpId].operation; - + segment_identifier const& seg_id = it->operations[OpId].seg_id; + segment_identifier const& other_id = it->operations[OtherOpId].seg_id; + + bool first_in_range = seg_watcher.update(seg_id); + bool fake_enter_detected = false; + // handle possible exit - if ( possible_exit_detected && + if ( exit_watcher.is_exit_detected() && ( op == overlay::operation_union || op == overlay::operation_intersection || op == overlay::operation_continue || op == overlay::operation_blocked ) ) { // real exit point - may be multiple // we know that we entered and now we exit - if ( !detail::equals::equals_point_point(it->point, possible_exit_point.point()) ) + if ( !detail::equals::equals_point_point(it->point, exit_watcher.get_exit_point()) ) { - possible_exit_detected = false; + exit_watcher.reset_detected_exit(); // not the last IP update_result(res); } // fake exit point, reset state // in reality this will be op == overlay::operation_intersection - else if ( op != overlay::operation_union ) + else if ( op == overlay::operation_intersection ) { - possible_exit_detected = false; + exit_watcher.reset_detected_exit(); + fake_enter_detected = true; } } + // i/i, i/x, i/u if ( op == overlay::operation_intersection ) { - // here we know that we entered the range - other_entry_points.push_back(point_identifier(it->operations[OpId].other_id, it->point)); + bool was_outside = exit_watcher.enter(it->point, other_id); + // interiors overlaps update_result(res); - // if the first point of P and/or Q is boundary then also - //update_result(res); - // or - //update_result(res); - } - else if ( op == overlay::operation_blocked - || op == overlay::operation_union ) - { - if ( !other_entry_points.empty() ) + + // going inside on boundary point + if ( boundary_checker.is_boundary(it->point, seg_id) ) { - segment_identifier const& other_id = it->operations[OpId].other_id; - point_iterator entry_it = std::find_if(other_entry_points.begin(), - other_entry_points.end(), - same_ranges(other_id)); - if ( entry_it != other_entry_points.end() ) + // TODO: check operation_blocked here - only for Ls, for MLs it's not enough + if ( other_boundary_checker.is_boundary(it->point, other_id) ) { - if ( op == overlay::operation_union ) - { - // here we know that we possibly left LS - // we must still check if we didn't get back on the same point - possible_exit_detected = true; - possible_exit_point = point_identifier(other_id, it->point); - } - else // op == overlay::operation_blocked - { - // here we know that we're on the last point of the range - - // depending on the other operation - //update_result(res); - // or - //update_result(res); - } - - // erase the corresponding entry point, - // don't postpone the erasure decision because - // there may be multiple exit IPs on the same point - // and we'd be forced to store them all just like the entry points - other_entry_points.erase(entry_it); + update_result(res); + } + else + { + update_result(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_result(res); + + if ( first_in_range ) + update_result(res); + } + } + } + // u/i, u/u, u/x, x/i, x/u, x/x + else if ( op == overlay::operation_union || op == overlay::operation_blocked ) + { + bool is_last_point = op == overlay::operation_blocked; + bool was_outside = exit_watcher.exit(it->point, other_id, is_last_point); + + // we're inside, possibly going out right now + if ( ! was_outside ) + { + if ( is_last_point ) + { + // check if this is indeed the boundary point +// TODO: For Linestring it's enough to check has_boundary +// because we know that this is the last point of the range + if ( boundary_checker.is_boundary(it->point, seg_id) ) + { + // TODO: check operation_blocked here - only for Ls, for MLs it's not enough + if ( other_boundary_checker.is_boundary(it->point, other_id) ) + { + update_result(res); + } + else + { + update_result(res); + } + } + } + } + // we're outside else { update_result(res); + // boundaries don't overlap - just an optimization if ( it->method == overlay::method_crosses ) + { update_result(res); - // or depending on the IP - //update_result(res); - // or - //update_result(res); + if ( first_in_range ) + update_result(res); + } + else + { + // TODO: check operation_blocked here - only for Ls, for MLs it's not enough + if ( boundary_checker.is_boundary(it->point, seg_id) ) + { + // TODO: check operation_blocked here - only for Ls, for MLs it's not enough + if ( other_boundary_checker.is_boundary(it->point, other_id) ) + update_result(res); + else + update_result(res); + } + // boundaries don't overlap + else + { + update_result(res); + + if ( first_in_range ) + update_result(res); + } + } + +// TODO: if this IP is not on the last point then also B/E should be updated: +// update_result(res); + } } else if ( op == overlay::operation_continue ) { - update_result(res); + //update_result(res); } } // here, the possible exit is the real one // we know that we entered and now we exit - if ( possible_exit_detected ) + if ( exit_watcher.is_exit_detected() ) { update_result(res); - // if has boundary on the last point of the current range - //update_result(res); + +// TODO: check if the last point is indeed the boundary +// For LS it's sufficient to check has_boundary + update_result(res); } } From e36c2027ec5eb8968c1fc6ebc0c1acd16ad1f882 Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Sat, 8 Feb 2014 23:40:42 +0100 Subject: [PATCH 5/7] relate(L,L) handled one special case, still not fully working --- .../algorithms/detail/relate/linear_linear.hpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/include/boost/geometry/algorithms/detail/relate/linear_linear.hpp b/include/boost/geometry/algorithms/detail/relate/linear_linear.hpp index 2652f4114..cb9cdc937 100644 --- a/include/boost/geometry/algorithms/detail/relate/linear_linear.hpp +++ b/include/boost/geometry/algorithms/detail/relate/linear_linear.hpp @@ -409,7 +409,7 @@ struct linear_linear segment_identifier const& seg_id = it->operations[OpId].seg_id; segment_identifier const& other_id = it->operations[OtherOpId].seg_id; - bool first_in_range = seg_watcher.update(seg_id); + bool first_in_range = seg_watcher.update(seg_id); // TODO: could be calculated only for i and u bool fake_enter_detected = false; // handle possible exit @@ -520,6 +520,13 @@ struct linear_linear update_result(res); else update_result(res); + + // first IP on the last segment point - this means that the first point is outside + if ( first_in_range && is_last_point ) + update_result(res); + + // TODO symetric case + // last IP and the first segment point -> last IP and op == union } // boundaries don't overlap else @@ -530,10 +537,6 @@ struct linear_linear update_result(res); } } - -// TODO: if this IP is not on the last point then also B/E should be updated: -// update_result(res); - } } else if ( op == overlay::operation_continue ) From 21dfef6f055a8aec225d9173639593e00628f3c0 Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Tue, 11 Feb 2014 01:30:22 +0100 Subject: [PATCH 6/7] get_turn_info_linear_linear<>::handle_first_last() method moved to better reflect calling dependency --- .../detail/overlay/get_turn_info_ll.hpp | 292 +++++++++--------- .../overlay/get_turns_linear_linear.cpp | 16 + test/algorithms/relate.cpp | 2 +- 3 files changed, 163 insertions(+), 147 deletions(-) diff --git a/include/boost/geometry/algorithms/detail/overlay/get_turn_info_ll.hpp b/include/boost/geometry/algorithms/detail/overlay/get_turn_info_ll.hpp index 830d66118..446299f52 100644 --- a/include/boost/geometry/algorithms/detail/overlay/get_turn_info_ll.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/get_turn_info_ll.hpp @@ -408,6 +408,152 @@ struct get_turn_info_linear_linear op1 = operation_union; } + template + static inline bool handle_first_last(Point1 const& pi, Point1 const& pj, Point1 const& pk, + Point2 const& qi, Point2 const& qj, Point2 const& qk, +// TODO: should this always be std::size_t or replace with template parameter? + std::size_t p_segments_count, + std::size_t q_segments_count, + TurnInfo const& tp_model, + IntersectionResult const& result, + method_type method, + OutputIterator out, + bool enable_first = true, + bool enable_last = true) + { + namespace ov = overlay; + + //if ( !enable_first && !enable_last ) + // return false; + + std::size_t ip_count = result.template get<0>().count; + // no intersection points + if ( ip_count == 0 ) + return false; + + int segment_index0 = tp_model.operations[0].seg_id.segment_index; + int segment_index1 = tp_model.operations[1].seg_id.segment_index; + BOOST_ASSERT(segment_index0 >= 0 && segment_index1 >= 0); + + bool is_p_first = segment_index0 == 0; + bool is_q_first = segment_index1 == 0; + bool is_p_last = static_cast(segment_index0) + 1 == p_segments_count; + bool is_q_last = static_cast(segment_index1) + 1 == q_segments_count; + + if ( !is_p_first && !is_p_last && !is_q_first && !is_q_last ) + return false; + + ov::operation_type p_operation0 = ov::operation_none; + ov::operation_type q_operation0 = ov::operation_none; + ov::operation_type p_operation1 = ov::operation_none; + ov::operation_type q_operation1 = ov::operation_none; + bool p0i, p0j, q0i, q0j; // assign false? + bool p1i, p1j, q1i, q1j; // assign false? + + { + int p_how = result.template get<1>().how_a; + int q_how = result.template get<1>().how_b; + int p_arrival = result.template get<1>().arrival[0]; + int q_arrival = result.template get<1>().arrival[1]; + bool opposite = result.template get<1>().opposite; + bool same_dirs = result.template get<1>().dir_a == 0 && result.template get<1>().dir_b == 0; + + handle_segment(is_p_first, is_p_last, p_how, p_arrival, + is_q_first, is_q_last, q_how, q_arrival, + opposite, ip_count, same_dirs, + result.template get<0>().intersections[0], + result.template get<0>().intersections[1], + p_operation0, q_operation0, p_operation1, q_operation1, + p0i, p0j, q0i, q0j, + p1i, p1j, q1i, q1j, + pi, pj, pk, qi, qj, qk); + } + + bool result_ignore_ip = false; + + { + BOOST_ASSERT(p0i == equals::equals_point_point(pi, result.template get<0>().intersections[0])); + BOOST_ASSERT(q0i == equals::equals_point_point(qi, result.template get<0>().intersections[0])); + BOOST_ASSERT(p0j == equals::equals_point_point(pj, result.template get<0>().intersections[0])); + BOOST_ASSERT(q0j == equals::equals_point_point(qj, result.template get<0>().intersections[0])); + // TODO - calculate first/last only if needed + bool p0_first = is_p_first && p0i; + bool p0_last = is_p_last && p0j; + bool q0_first = is_q_first && q0i; + bool q0_last = is_q_last && q0j; + bool append0_first = enable_first && (p0_first || q0_first); + bool append0_last = enable_last && (p0_last || q0_last); + + result_ignore_ip = append0_last; + + if ( append0_first || append0_last ) + { + bool handled = handle_internal(pi, pj, pk, qi, qj, qk, result.template get<0>().intersections[0], + p0_first, p0_last, q0_first, q0_last, q0i, q0j, + tp_model, result, p_operation0, q_operation0); + if ( !handled ) + { + handled = handle_internal(qi, qj, qk, pi, pj, pk, result.template get<0>().intersections[0], + q0_first, q0_last, p0_first, p0_last, p0i, p0j, + tp_model, result, q_operation0, p_operation0); + } + + method = endpoint_ip_method(p0i, p0j, q0i, q0j); + + if ( p_operation0 != operation_none ) + assign(pi, qi, result, result.template get<0>().intersections[0], + method, p_operation0, q_operation0, + tp_model, out); + } + } + + if ( p_operation1 != ov::operation_none ) + { + BOOST_ASSERT(p1i == equals::equals_point_point(pi, result.template get<0>().intersections[1])); + BOOST_ASSERT(q1i == equals::equals_point_point(qi, result.template get<0>().intersections[1])); + BOOST_ASSERT(p1j == equals::equals_point_point(pj, result.template get<0>().intersections[1])); + BOOST_ASSERT(q1j == equals::equals_point_point(qj, result.template get<0>().intersections[1])); + // TODO - calculate first/last only if needed + bool p1_first = is_p_first && p1i; + bool p1_last = is_p_last && p1j; + bool q1_first = is_q_first && q1i; + bool q1_last = is_q_last && q1j; + bool append1_first = enable_first && (p1_first || q1_first); + bool append1_last = enable_last && (p1_last || q1_last); + + result_ignore_ip = result_ignore_ip || append1_last; + + if ( append1_first || append1_last ) + { + bool handled = handle_internal(pi, pj, pk, qi, qj, qk, result.template get<0>().intersections[1], + p1_first, p1_last, q1_first, q1_last, q1i, q1j, + tp_model, result, p_operation1, q_operation1); + if ( !handled ) + { + handled = handle_internal(qi, qj, qk, pi, pj, pk, result.template get<0>().intersections[1], + q1_first, q1_last, p1_first, p1_last, p1i, p1j, + tp_model, result, q_operation1, p_operation1); + } + + if ( p_operation1 != operation_none ) + { + method = endpoint_ip_method(p1i, p1j, q1i, q1j); + + assign(pi, qi, result, result.template get<0>().intersections[1], + method, p_operation1, q_operation1, + tp_model, out); + } + } + } + + return result_ignore_ip; + } + template static inline void handle_segment(bool /*first_a*/, bool last_a, int how_a, int arrival_a, @@ -587,152 +733,6 @@ struct get_turn_info_linear_linear return false; } - template - static inline bool handle_first_last(Point1 const& pi, Point1 const& pj, Point1 const& pk, - Point2 const& qi, Point2 const& qj, Point2 const& qk, -// TODO: should this always be std::size_t or replace with template parameter? - std::size_t p_segments_count, - std::size_t q_segments_count, - TurnInfo const& tp_model, - IntersectionResult const& result, - method_type method, - OutputIterator out, - bool enable_first = true, - bool enable_last = true) - { - namespace ov = overlay; - - //if ( !enable_first && !enable_last ) - // return false; - - std::size_t ip_count = result.template get<0>().count; - // no intersection points - if ( ip_count == 0 ) - return false; - - int segment_index0 = tp_model.operations[0].seg_id.segment_index; - int segment_index1 = tp_model.operations[1].seg_id.segment_index; - BOOST_ASSERT(segment_index0 >= 0 && segment_index1 >= 0); - - bool is_p_first = segment_index0 == 0; - bool is_q_first = segment_index1 == 0; - bool is_p_last = static_cast(segment_index0) + 1 == p_segments_count; - bool is_q_last = static_cast(segment_index1) + 1 == q_segments_count; - - if ( !is_p_first && !is_p_last && !is_q_first && !is_q_last ) - return false; - - ov::operation_type p_operation0 = ov::operation_none; - ov::operation_type q_operation0 = ov::operation_none; - ov::operation_type p_operation1 = ov::operation_none; - ov::operation_type q_operation1 = ov::operation_none; - bool p0i, p0j, q0i, q0j; // assign false? - bool p1i, p1j, q1i, q1j; // assign false? - - { - int p_how = result.template get<1>().how_a; - int q_how = result.template get<1>().how_b; - int p_arrival = result.template get<1>().arrival[0]; - int q_arrival = result.template get<1>().arrival[1]; - bool opposite = result.template get<1>().opposite; - bool same_dirs = result.template get<1>().dir_a == 0 && result.template get<1>().dir_b == 0; - - handle_segment(is_p_first, is_p_last, p_how, p_arrival, - is_q_first, is_q_last, q_how, q_arrival, - opposite, ip_count, same_dirs, - result.template get<0>().intersections[0], - result.template get<0>().intersections[1], - p_operation0, q_operation0, p_operation1, q_operation1, - p0i, p0j, q0i, q0j, - p1i, p1j, q1i, q1j, - pi, pj, pk, qi, qj, qk); - } - - bool result_ignore_ip = false; - - { - BOOST_ASSERT(p0i == equals::equals_point_point(pi, result.template get<0>().intersections[0])); - BOOST_ASSERT(q0i == equals::equals_point_point(qi, result.template get<0>().intersections[0])); - BOOST_ASSERT(p0j == equals::equals_point_point(pj, result.template get<0>().intersections[0])); - BOOST_ASSERT(q0j == equals::equals_point_point(qj, result.template get<0>().intersections[0])); - // TODO - calculate first/last only if needed - bool p0_first = is_p_first && p0i; - bool p0_last = is_p_last && p0j; - bool q0_first = is_q_first && q0i; - bool q0_last = is_q_last && q0j; - bool append0_first = enable_first && (p0_first || q0_first); - bool append0_last = enable_last && (p0_last || q0_last); - - result_ignore_ip = append0_last; - - if ( append0_first || append0_last ) - { - bool handled = handle_internal(pi, pj, pk, qi, qj, qk, result.template get<0>().intersections[0], - p0_first, p0_last, q0_first, q0_last, q0i, q0j, - tp_model, result, p_operation0, q_operation0); - if ( !handled ) - { - handled = handle_internal(qi, qj, qk, pi, pj, pk, result.template get<0>().intersections[0], - q0_first, q0_last, p0_first, p0_last, p0i, p0j, - tp_model, result, q_operation0, p_operation0); - } - - method = endpoint_ip_method(p0i, p0j, q0i, q0j); - - if ( p_operation0 != operation_none ) - assign(pi, qi, result, result.template get<0>().intersections[0], - method, p_operation0, q_operation0, - tp_model, out); - } - } - - if ( p_operation1 != ov::operation_none ) - { - BOOST_ASSERT(p1i == equals::equals_point_point(pi, result.template get<0>().intersections[1])); - BOOST_ASSERT(q1i == equals::equals_point_point(qi, result.template get<0>().intersections[1])); - BOOST_ASSERT(p1j == equals::equals_point_point(pj, result.template get<0>().intersections[1])); - BOOST_ASSERT(q1j == equals::equals_point_point(qj, result.template get<0>().intersections[1])); - // TODO - calculate first/last only if needed - bool p1_first = is_p_first && p1i; - bool p1_last = is_p_last && p1j; - bool q1_first = is_q_first && q1i; - bool q1_last = is_q_last && q1j; - bool append1_first = enable_first && (p1_first || q1_first); - bool append1_last = enable_last && (p1_last || q1_last); - - result_ignore_ip = result_ignore_ip || append1_last; - - if ( append1_first || append1_last ) - { - bool handled = handle_internal(pi, pj, pk, qi, qj, qk, result.template get<0>().intersections[1], - p1_first, p1_last, q1_first, q1_last, q1i, q1j, - tp_model, result, p_operation1, q_operation1); - if ( !handled ) - { - handled = handle_internal(qi, qj, qk, pi, pj, pk, result.template get<0>().intersections[1], - q1_first, q1_last, p1_first, p1_last, p1i, p1j, - tp_model, result, q_operation1, p_operation1); - } - - if ( p_operation1 != operation_none ) - { - method = endpoint_ip_method(p1i, p1j, q1i, q1j); - - assign(pi, qi, result, result.template get<0>().intersections[1], - method, p_operation1, q_operation1, - tp_model, out); - } - } - } - - return result_ignore_ip; - } - static inline method_type endpoint_ip_method(bool ip_pi, bool ip_pj, bool ip_qi, bool ip_qj) { int pc = (ip_pi ? 1 : 0) + (ip_pj ? 1 : 0); diff --git a/test/algorithms/overlay/get_turns_linear_linear.cpp b/test/algorithms/overlay/get_turns_linear_linear.cpp index fd7b110c9..695976721 100644 --- a/test/algorithms/overlay/get_turns_linear_linear.cpp +++ b/test/algorithms/overlay/get_turns_linear_linear.cpp @@ -138,6 +138,9 @@ void test_geometry(std::string const& wkt1, std::string const& wkt2, test_geometry(wkt1, wkt2, expected); } +//TEST +#include + template void test_all() { @@ -148,6 +151,9 @@ void test_all() test_geometry("LINESTRING(0 0,2 0)", "LINESTRING(2 0,0 0)", "tix", "txi"); test_geometry("LINESTRING(1 0,1 1)", "LINESTRING(0 0,1 0,2 0)", "tuu"); + + to_svg("LINESTRING(1 0,1 1)", "LINESTRING(0 0,1 0,2 0)", "test00.svg"); + test_geometry("LINESTRING(1 0,0 0)", "LINESTRING(0 0,1 0,2 0)", "txi", "tiu"); test_geometry("LINESTRING(1 0,2 0)", "LINESTRING(0 0,1 0,2 0)", "tii", "txx"); test_geometry("LINESTRING(1 1,1 0)", "LINESTRING(0 0,1 0,2 0)", "txu"); @@ -178,6 +184,16 @@ void test_all() test_geometry("LINESTRING(0 0,2 0,3 0,4 0,6 0)", "LINESTRING(2 -1,2 0,3 0,4 0,4 -1)", "tii", "ecc", "tuu"); test_geometry("LINESTRING(0 0,2 0,3 0,4 0,6 0)", "LINESTRING(4 1,4 0,3 0,2 0,2 1)", "tiu", "ecc", "tui"); test_geometry("LINESTRING(0 0,2 0,3 0,4 0,6 0)", "LINESTRING(4 -1,4 0,3 0,2 0,2 -1)", "tiu", "ecc", "tui"); + + if ( boost::is_same::value ) + { + to_svg("LINESTRING(0 0,1 0,2 0,2.5 0,3 1)", "LINESTRING(0 0,2 0,2.5 0,3 1)", "test11.svg"); + to_svg("LINESTRING(0 0,1 0,2 0,2.5 0,3 1)", "LINESTRING(3 1,2.5 0,2 0,0 0)", "test12.svg"); + to_svg("LINESTRING(-1 1,0 0,1 0,4 0,5 5,10 5,15 0,20 0,30 0,31 1)", "LINESTRING(30 0,3 0,2.5 1,2 0,1 0,0 0,-1 -1)", "test21.svg"); + to_svg("LINESTRING(-1 1,0 0,1 0,4 0,5 5,10 5,15 0,20 0,30 0,31 1)", "LINESTRING(-1 -1,0 0,1 0,2 0,2.5 1,3 0,30 0)", "test22.svg"); + to_svg("LINESTRING(0 0,1 0,2 1,3 5,4 0)", "LINESTRING(1 0,2 1,3 5)", "test31.svg"); + to_svg("LINESTRING(0 0,1 0,2 1,3 5,4 0)", "LINESTRING(3 5,2 1,1 0)", "test32.svg"); + } } int test_main(int, char* []) diff --git a/test/algorithms/relate.cpp b/test/algorithms/relate.cpp index 8343f7bbc..31d08668b 100644 --- a/test/algorithms/relate.cpp +++ b/test/algorithms/relate.cpp @@ -136,7 +136,7 @@ void test_linestring_linestring() "LINESTRING(0 5,5 5,5 10,10 10,10 5,5 5,5 0)", "1FFF0FFF2"); 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)", "relate1.svg"); - + // TEST ERROR - wrong result // test_geometry("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)", "1FFF0FFF2"); From 4a4acf00cb14c66acd271caa698ba86603a87d34 Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Tue, 11 Feb 2014 02:57:39 +0100 Subject: [PATCH 7/7] [get_turns] fixed error in get_turn_info_linear_linear - invalid operations generated for the endpoint-internal IP for opposite segments --- .../detail/overlay/get_turn_info_ll.hpp | 89 +++++++++++-------- .../overlay/get_turns_linear_linear.cpp | 26 +++--- 2 files changed, 65 insertions(+), 50 deletions(-) diff --git a/include/boost/geometry/algorithms/detail/overlay/get_turn_info_ll.hpp b/include/boost/geometry/algorithms/detail/overlay/get_turn_info_ll.hpp index 446299f52..000514f12 100644 --- a/include/boost/geometry/algorithms/detail/overlay/get_turn_info_ll.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/get_turn_info_ll.hpp @@ -666,9 +666,9 @@ struct get_turn_info_linear_linear IntersectionResult const& result, operation_type & op1, operation_type & op2) { - if ( first1 || last1 ) + if ( !first2 && !last2 ) { - if ( !first2 && !last2 ) + if ( first1 ) { BOOST_ASSERT(ip_i2 == equals::equals_point_point(i2, ip)); BOOST_ASSERT(ip_j2 == equals::equals_point_point(j2, ip)); @@ -685,49 +685,64 @@ struct get_turn_info_linear_linear bool opposite = result.template get<1>().opposite; TurnInfo tp = tp_model; - if ( first1 ) + side_calculator side_calc(i2, i1, j1, i2, j2, k2); + equal::apply(i2, i1, j1, i2, j2, k2, + tp, result.template get<0>(), result.template get<1>(), side_calc); + + if ( tp.both(operation_continue) ) { - side_calculator side_calc(i2, i1, j1, i2, j2, k2); - equal::apply(i2, i1, j1, i2, j2, k2, - tp, result.template get<0>(), result.template get<1>(), side_calc); - if ( tp.both(operation_continue) ) - { - op1 = operation_intersection; - op2 = opposite ? operation_union : operation_intersection; - } - else - { - BOOST_ASSERT(tp.combination(operation_intersection, operation_union)); - op1 = operation_union; - op2 = operation_union; - } + op1 = operation_intersection; + op2 = opposite ? operation_union : operation_intersection; } - else // last1 + else { - side_calculator side_calc(i2, j1, i1, i2, j2, k2); - equal::apply(i2, j1, i1, i2, j2, k2, - tp, result.template get<0>(), result.template get<1>(), side_calc); - if ( tp.both(operation_continue) ) - { - op1 = operation_blocked; - op2 = opposite ? operation_intersection : operation_union; - } - else - { - BOOST_ASSERT(tp.combination(operation_intersection, operation_union)); - op1 = operation_blocked; - op2 = operation_union; - } + BOOST_ASSERT(tp.combination(operation_intersection, operation_union)); + //op1 = operation_union; + //op2 = operation_union; } return true; } - else - { - // do nothing - // shouldn't be handled this way - } + // else do nothing - shouldn't be handled this way } + else if ( last1 ) + { + BOOST_ASSERT(ip_i2 == equals::equals_point_point(i2, ip)); + BOOST_ASSERT(ip_j2 == equals::equals_point_point(j2, ip)); + + if ( ip_j2 ) + { + // don't output this IP - for the first point of other geometry segment + op1 = operation_none; + op2 = operation_none; + return true; + } + else if ( ip_i2 ) + { + bool opposite = result.template get<1>().opposite; + + TurnInfo tp = tp_model; + side_calculator side_calc(i2, j1, i1, i2, j2, k2); + equal::apply(i2, j1, i1, i2, j2, k2, + tp, result.template get<0>(), result.template get<1>(), side_calc); + + if ( tp.both(operation_continue) ) + { + op1 = operation_blocked; + op2 = opposite ? operation_intersection : operation_union; + } + else + { + BOOST_ASSERT(tp.combination(operation_intersection, operation_union)); + op1 = operation_blocked; + op2 = operation_union; + } + + return true; + } + // else do nothing - shouldn't be handled this way + } + // else do nothing - shouldn't be handled this way } return false; diff --git a/test/algorithms/overlay/get_turns_linear_linear.cpp b/test/algorithms/overlay/get_turns_linear_linear.cpp index 695976721..bc48ca3c8 100644 --- a/test/algorithms/overlay/get_turns_linear_linear.cpp +++ b/test/algorithms/overlay/get_turns_linear_linear.cpp @@ -139,7 +139,7 @@ void test_geometry(std::string const& wkt1, std::string const& wkt2, } //TEST -#include +//#include template void test_all() @@ -151,9 +151,6 @@ void test_all() test_geometry("LINESTRING(0 0,2 0)", "LINESTRING(2 0,0 0)", "tix", "txi"); test_geometry("LINESTRING(1 0,1 1)", "LINESTRING(0 0,1 0,2 0)", "tuu"); - - to_svg("LINESTRING(1 0,1 1)", "LINESTRING(0 0,1 0,2 0)", "test00.svg"); - test_geometry("LINESTRING(1 0,0 0)", "LINESTRING(0 0,1 0,2 0)", "txi", "tiu"); test_geometry("LINESTRING(1 0,2 0)", "LINESTRING(0 0,1 0,2 0)", "tii", "txx"); test_geometry("LINESTRING(1 1,1 0)", "LINESTRING(0 0,1 0,2 0)", "txu"); @@ -185,15 +182,18 @@ void test_all() test_geometry("LINESTRING(0 0,2 0,3 0,4 0,6 0)", "LINESTRING(4 1,4 0,3 0,2 0,2 1)", "tiu", "ecc", "tui"); test_geometry("LINESTRING(0 0,2 0,3 0,4 0,6 0)", "LINESTRING(4 -1,4 0,3 0,2 0,2 -1)", "tiu", "ecc", "tui"); - if ( boost::is_same::value ) - { - to_svg("LINESTRING(0 0,1 0,2 0,2.5 0,3 1)", "LINESTRING(0 0,2 0,2.5 0,3 1)", "test11.svg"); - to_svg("LINESTRING(0 0,1 0,2 0,2.5 0,3 1)", "LINESTRING(3 1,2.5 0,2 0,0 0)", "test12.svg"); - to_svg("LINESTRING(-1 1,0 0,1 0,4 0,5 5,10 5,15 0,20 0,30 0,31 1)", "LINESTRING(30 0,3 0,2.5 1,2 0,1 0,0 0,-1 -1)", "test21.svg"); - to_svg("LINESTRING(-1 1,0 0,1 0,4 0,5 5,10 5,15 0,20 0,30 0,31 1)", "LINESTRING(-1 -1,0 0,1 0,2 0,2.5 1,3 0,30 0)", "test22.svg"); - to_svg("LINESTRING(0 0,1 0,2 1,3 5,4 0)", "LINESTRING(1 0,2 1,3 5)", "test31.svg"); - to_svg("LINESTRING(0 0,1 0,2 1,3 5,4 0)", "LINESTRING(3 5,2 1,1 0)", "test32.svg"); - } + test_geometry("LINESTRING(0 0,1 0,2 1,3 5,4 0)", "LINESTRING(1 0,2 1,3 5)", "tii", "ecc", "tux"); + test_geometry("LINESTRING(0 0,1 0,2 1,3 5,4 0)", "LINESTRING(3 5,2 1,1 0)", "tix", "ecc", "tui"); + test_geometry("LINESTRING(1 0,2 1,3 5)", "LINESTRING(0 0,1 0,2 1,3 5,4 0)", "txu", "ecc", "tii"); + test_geometry("LINESTRING(3 5,2 1,1 0)", "LINESTRING(0 0,1 0,2 1,3 5,4 0)", "tiu", "ecc", "txi"); + + //if ( boost::is_same::value ) + //{ + // to_svg("LINESTRING(0 0,1 0,2 0,2.5 0,3 1)", "LINESTRING(0 0,2 0,2.5 0,3 1)", "test11.svg"); + // to_svg("LINESTRING(0 0,1 0,2 0,2.5 0,3 1)", "LINESTRING(3 1,2.5 0,2 0,0 0)", "test12.svg"); + // to_svg("LINESTRING(-1 1,0 0,1 0,4 0,5 5,10 5,15 0,20 0,30 0,31 1)", "LINESTRING(30 0,3 0,2.5 1,2 0,1 0,0 0,-1 -1)", "test21.svg"); + // to_svg("LINESTRING(-1 1,0 0,1 0,4 0,5 5,10 5,15 0,20 0,30 0,31 1)", "LINESTRING(-1 -1,0 0,1 0,2 0,2.5 1,3 0,30 0)", "test22.svg"); + //} } int test_main(int, char* [])