From 9fe9d7259c5feef5b713faa9429095340dfd306e Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Thu, 13 Feb 2014 01:08:08 +0100 Subject: [PATCH] relate(L,L) handled G1 last range point boundary in the exterior of G2 --- .../detail/relate/linear_linear.hpp | 312 ++++++++++-------- 1 file changed, 173 insertions(+), 139 deletions(-) diff --git a/include/boost/geometry/algorithms/detail/relate/linear_linear.hpp b/include/boost/geometry/algorithms/detail/relate/linear_linear.hpp index 8ab8a8cb0..76d90d30e 100644 --- a/include/boost/geometry/algorithms/detail/relate/linear_linear.hpp +++ b/include/boost/geometry/algorithms/detail/relate/linear_linear.hpp @@ -248,13 +248,13 @@ struct linear_linear // 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>()); + std::sort(turns.begin(), turns.end(), turns::less_seg_dist_op<0,2,3,1,4,0,0>()); 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>()); + std::sort(turns.begin(), turns.end(), turns::less_seg_dist_op<0,2,3,1,4,0,1>()); analyse_turns<1, 0>(res, turns.begin(), turns.end(), geometry2, geometry1, @@ -438,20 +438,27 @@ struct linear_linear exit_watcher exit_watcher; segment_watcher seg_watcher; + bool last_union = false; for ( TurnIt it = first ; it != last ; ++it ) { overlay::operation_type op = it->operations[OpId].operation; + + if ( op != overlay::operation_union + && op != overlay::operation_intersection + && op != overlay::operation_blocked ) + { + continue; + } + 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); // TODO: could be calculated only for i and u + bool first_in_range = seg_watcher.update(seg_id); bool fake_enter_detected = false; // handle possible exit - if ( exit_watcher.is_exit_detected() && - ( op == overlay::operation_union || op == overlay::operation_intersection - || op == overlay::operation_continue || op == overlay::operation_blocked ) ) + if ( exit_watcher.is_exit_detected() ) { // real exit point - may be multiple // we know that we entered and now we exit @@ -471,6 +478,25 @@ struct linear_linear } } + if ( first_in_range && !fake_enter_detected && last_union ) + { + BOOST_ASSERT(it != first); + TurnIt prev = it; + --prev; + segment_identifier const& prev_seg_id = prev->operations[OpId].seg_id; + + // if there is a boundary on the last point + if ( boost::size(sub_geometry::get(geometry, prev_seg_id)) > 1 + && boundary_checker.template is_boundary + (range::back(sub_geometry::get(geometry, prev_seg_id)), prev_seg_id) ) + { + update_result(res); + } + } + + // reset state + last_union = (op == overlay::operation_union); + // i/i, i/x, i/u if ( op == overlay::operation_intersection ) { @@ -568,6 +594,7 @@ struct linear_linear } } } + // method other than crosses, check more conditions else { bool this_b = @@ -584,9 +611,13 @@ struct linear_linear other_boundary_checker.template is_boundary(it->point, other_id); // it's also the boundary of the other geometry if ( other_b ) + { 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 && op_blocked ) @@ -598,9 +629,6 @@ struct linear_linear update_result(res); } } - - // TODO symetric case - // last IP and the first segment point -> last IP and op == union } // boundaries don't overlap else @@ -620,157 +648,163 @@ struct linear_linear } } } - 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 ( exit_watcher.is_exit_detected() ) + if ( exit_watcher.is_exit_detected() || last_union ) // THIS CHECK IS REDUNDANT { + // for sure 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); + BOOST_ASSERT(first != last); + TurnIt prev = last; + --prev; + segment_identifier const& prev_seg_id = prev->operations[OpId].seg_id; + + // if there is a boundary on the last point + if ( boost::size(sub_geometry::get(geometry, prev_seg_id)) > 1 + && boundary_checker.template is_boundary + (range::back(sub_geometry::get(geometry, prev_seg_id)), prev_seg_id) ) + { + 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 ) - { - // '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(); - } + //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_intersection) ) + // res.template update(); - if ( it->has(overlay::operation_blocked) ) - if ( !b ) - 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); + //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; - } + // 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)); - } + //// 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); + //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 ( 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(); - } + // 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); + // 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 ( 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(); - } - } + // 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