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..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 @@ -408,185 +408,6 @@ struct get_turn_info_linear_linear op1 = operation_union; } - template - static inline - void handle_segment(bool /*first_a*/, bool last_a, int how_a, int arrival_a, - bool /*first_b*/, bool last_b, int how_b, int arrival_b, - bool opposite, std::size_t ip_count, bool same_dirs/*collinear*/, - Point const& ip0, Point const& /*ip1*/, - operation_type & op0_a, operation_type & op0_b, - operation_type & op1_a, operation_type & op1_b, - bool & i0_a, bool & j0_a, bool & i0_b, bool & j0_b, - bool & i1_a, bool & j1_a, bool & i1_b, bool & j1_b, - Point1 const& pi, Point1 const& /*pj*/, Point1 const& /*pk*/, - Point2 const& qi, Point2 const& /*qj*/, Point2 const& /*qk*/) - { - namespace ov = overlay; - - i0_a = false; j0_a = false; i0_b = false; j0_b = false; - i1_a = false; j1_a = false; i1_b = false; j1_b = false; - - if ( same_dirs ) - { - if ( ip_count == 2 ) - { - BOOST_ASSERT( how_a == 0 && how_b == 0 ); - - if ( !opposite ) - { - op0_a = operation_intersection; - op0_b = operation_intersection; - op1_a = arrival_to_union_or_blocked(arrival_a, last_a); - op1_b = arrival_to_union_or_blocked(arrival_b, last_b); - - i0_a = equals::equals_point_point(pi, ip0); - i0_b = equals::equals_point_point(qi, ip0); - j1_a = arrival_a != -1; - j1_b = arrival_b != -1; - } - else - { - op0_a = operation_intersection; - op0_b = arrival_to_union_or_blocked(arrival_b, last_b); - op1_a = arrival_to_union_or_blocked(arrival_a, last_a); - op1_b = operation_intersection; - - i0_a = arrival_b != 1; - j0_b = arrival_b != -1; - j1_a = arrival_a != -1; - i1_b = arrival_a != 1; - } - } - else - { - BOOST_ASSERT(ip_count == 1); - op0_a = arrival_to_union_or_blocked(arrival_a, last_a); - op0_b = arrival_to_union_or_blocked(arrival_b, last_b); - - i0_a = how_a == -1; - i0_b = how_b == -1; - j0_a = arrival_a == 0; - j0_b = arrival_b == 0; - } - } - else - { - op0_a = how_to_union_or_blocked(how_a, last_a); - op0_b = how_to_union_or_blocked(how_b, last_b); - - i0_a = how_a == -1; - i0_b = how_b == -1; - j0_a = how_a == 1; - j0_b = how_b == 1; - } - } - - // only if collinear (same_dirs) - static inline operation_type arrival_to_union_or_blocked(int arrival, bool is_last) - { - if ( arrival == 1 ) - return operation_blocked; - else if ( arrival == -1 ) - return operation_union; - else - return is_last ? operation_blocked : operation_union; - //return operation_blocked; - } - - // only if not collinear (!same_dirs) - static inline operation_type how_to_union_or_blocked(int how, bool is_last) - { - if ( how == 1 ) - //return operation_blocked; - return is_last ? operation_blocked : operation_union; - else - return operation_union; - } - -// TODO: IT'S ALSO PROBABLE THAT ALL THIS FUNCTION COULD BE INTEGRATED WITH handle_segment - - template - static inline bool handle_internal(Point1 const& i1, Point1 const& j1, Point1 const& /*k1*/, - Point2 const& i2, Point2 const& j2, Point2 const& k2, - Point const& ip, - bool first1, bool last1, bool first2, bool last2, - bool ip_i2, bool ip_j2, - TurnInfo const& tp_model, - IntersectionResult const& result, - operation_type & op1, operation_type & op2) - { - if ( first1 || last1 ) - { - if ( !first2 && !last2 ) - { - BOOST_ASSERT(ip_i2 == equals::equals_point_point(i2, ip)); - BOOST_ASSERT(ip_j2 == equals::equals_point_point(j2, ip)); - - if ( ip_i2 ) - { - // don't output this IP - for the first point of other geometry segment - op1 = operation_none; - op2 = operation_none; - return true; - } - else if ( ip_j2 ) - { - 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) ) - { - op1 = operation_intersection; - op2 = opposite ? operation_union : operation_intersection; - } - else - { - BOOST_ASSERT(tp.combination(operation_intersection, operation_union)); - op1 = operation_union; - op2 = operation_union; - } - } - else // last1 - { - 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 - } - } - } - - return false; - } - template + static inline + void handle_segment(bool /*first_a*/, bool last_a, int how_a, int arrival_a, + bool /*first_b*/, bool last_b, int how_b, int arrival_b, + bool opposite, std::size_t ip_count, bool same_dirs/*collinear*/, + Point const& ip0, Point const& /*ip1*/, + operation_type & op0_a, operation_type & op0_b, + operation_type & op1_a, operation_type & op1_b, + bool & i0_a, bool & j0_a, bool & i0_b, bool & j0_b, + bool & i1_a, bool & j1_a, bool & i1_b, bool & j1_b, + Point1 const& pi, Point1 const& /*pj*/, Point1 const& /*pk*/, + Point2 const& qi, Point2 const& /*qj*/, Point2 const& /*qk*/) + { + namespace ov = overlay; + + i0_a = false; j0_a = false; i0_b = false; j0_b = false; + i1_a = false; j1_a = false; i1_b = false; j1_b = false; + + if ( same_dirs ) + { + if ( ip_count == 2 ) + { + BOOST_ASSERT( how_a == 0 && how_b == 0 ); + + if ( !opposite ) + { + op0_a = operation_intersection; + op0_b = operation_intersection; + op1_a = arrival_to_union_or_blocked(arrival_a, last_a); + op1_b = arrival_to_union_or_blocked(arrival_b, last_b); + + i0_a = equals::equals_point_point(pi, ip0); + i0_b = equals::equals_point_point(qi, ip0); + j1_a = arrival_a != -1; + j1_b = arrival_b != -1; + } + else + { + op0_a = operation_intersection; + op0_b = arrival_to_union_or_blocked(arrival_b, last_b); + op1_a = arrival_to_union_or_blocked(arrival_a, last_a); + op1_b = operation_intersection; + + i0_a = arrival_b != 1; + j0_b = arrival_b != -1; + j1_a = arrival_a != -1; + i1_b = arrival_a != 1; + } + } + else + { + BOOST_ASSERT(ip_count == 1); + op0_a = arrival_to_union_or_blocked(arrival_a, last_a); + op0_b = arrival_to_union_or_blocked(arrival_b, last_b); + + i0_a = how_a == -1; + i0_b = how_b == -1; + j0_a = arrival_a == 0; + j0_b = arrival_b == 0; + } + } + else + { + op0_a = how_to_union_or_blocked(how_a, last_a); + op0_b = how_to_union_or_blocked(how_b, last_b); + + i0_a = how_a == -1; + i0_b = how_b == -1; + j0_a = how_a == 1; + j0_b = how_b == 1; + } + } + + // only if collinear (same_dirs) + static inline operation_type arrival_to_union_or_blocked(int arrival, bool is_last) + { + if ( arrival == 1 ) + return operation_blocked; + else if ( arrival == -1 ) + return operation_union; + else + return is_last ? operation_blocked : operation_union; + //return operation_blocked; + } + + // only if not collinear (!same_dirs) + static inline operation_type how_to_union_or_blocked(int how, bool is_last) + { + if ( how == 1 ) + //return operation_blocked; + return is_last ? operation_blocked : operation_union; + else + return operation_union; + } + +// TODO: IT'S ALSO PROBABLE THAT ALL THIS FUNCTION COULD BE INTEGRATED WITH handle_segment + + template + static inline bool handle_internal(Point1 const& i1, Point1 const& j1, Point1 const& /*k1*/, + Point2 const& i2, Point2 const& j2, Point2 const& k2, + Point const& ip, + bool first1, bool last1, bool first2, bool last2, + bool ip_i2, bool ip_j2, + TurnInfo const& tp_model, + IntersectionResult const& result, + operation_type & op1, operation_type & op2) + { + 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)); + + if ( ip_i2 ) + { + // don't output this IP - for the first point of other geometry segment + op1 = operation_none; + op2 = operation_none; + return true; + } + else if ( ip_j2 ) + { + bool opposite = result.template get<1>().opposite; + + TurnInfo tp = tp_model; + 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; + } + + return true; + } + // 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; + } + 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/include/boost/geometry/algorithms/detail/relate/linear_linear.hpp b/include/boost/geometry/algorithms/detail/relate/linear_linear.hpp index ec9bf4e92..cb9cdc937 100644 --- a/include/boost/geometry/algorithms/detail/relate/linear_linear.hpp +++ b/include/boost/geometry/algorithms/detail/relate/linear_linear.hpp @@ -25,6 +25,135 @@ namespace boost { namespace geometry #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace relate { +// update_result + +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); +} + +// 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 @@ -62,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 @@ -74,20 +202,367 @@ struct linear_linear turns::get_turns::apply(turns, geometry1, geometry2); + if ( turns.empty() ) + { + 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<>()); + 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, + 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, + boundary_checker2, boundary_checker1); return res; } - template + // 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_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 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, + BoundaryChecker boundary_checker, + OtherBoundaryChecker other_boundary_checker) + { + // point_type should be the same as the one stored in Turn + typedef typename point_type::type point_type; + static const bool reverse_result = OpId != 0; + + if ( first == last ) + return; + + 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); // TODO: could be calculated only for i and u + 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 ) ) + { + // real exit point - may be multiple + // we know that we entered and now we exit + if ( !detail::equals::equals_point_point(it->point, exit_watcher.get_exit_point()) ) + { + 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_intersection ) + { + exit_watcher.reset_detected_exit(); + fake_enter_detected = true; + } + } + + // i/i, i/x, i/u + if ( op == overlay::operation_intersection ) + { + bool was_outside = exit_watcher.enter(it->point, other_id); + + // interiors overlaps + update_result(res); + + // going inside on boundary point + 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); + } + } + // 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); + + 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); + + // 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 + { + update_result(res); + + if ( first_in_range ) + 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 ( exit_watcher.is_exit_detected() ) + { + 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); + } + } + + 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/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 ) diff --git a/test/algorithms/overlay/get_turns_linear_linear.cpp b/test/algorithms/overlay/get_turns_linear_linear.cpp index fd7b110c9..bc48ca3c8 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() { @@ -178,6 +181,19 @@ 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"); + + 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* []) diff --git a/test/algorithms/relate.cpp b/test/algorithms/relate.cpp index 8d4a4d12e..31d08668b 100644 --- a/test/algorithms/relate.cpp +++ b/test/algorithms/relate.cpp @@ -124,13 +124,19 @@ 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"); 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");