diff --git a/include/boost/geometry/algorithms/detail/relate/turns.hpp b/include/boost/geometry/algorithms/detail/relate/turns.hpp index b6259bcdb..571a62d84 100644 --- a/include/boost/geometry/algorithms/detail/relate/turns.hpp +++ b/include/boost/geometry/algorithms/detail/relate/turns.hpp @@ -14,13 +14,18 @@ #include #include +#include #include +#include + namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace relate { namespace turns { +// TURN_INFO + template struct distance_info { @@ -50,7 +55,285 @@ struct turn_operation_with_distance : public overlay::turn_operation distance_info

enriched; }; -template +// GET_TURN_INFO + +template +struct get_turn_info_linear_linear +{ + template + < + typename Point1, + typename Point2, + typename TurnInfo, + typename RescalePolicy, + typename OutputIterator + > + static inline OutputIterator apply( + Point1 const& pi, Point1 const& pj, Point1 const& pk, + Point2 const& qi, Point2 const& qj, Point2 const& qk, + TurnInfo const& tp_model, + RescalePolicy const& , // TODO: this will be used. rescale_policy, + OutputIterator out) + { + typedef model::referring_segment segment_type1; + typedef model::referring_segment segment_type2; + segment_type1 p1(pi, pj), p2(pj, pk); + segment_type2 q1(qi, qj), q2(qj, qk); + + overlay::side_calculator side_calc(pi, pj, pk, qi, qj, qk); + + typedef strategy_intersection + < + typename cs_tag::type, + Point1, + Point2, + typename TurnInfo::point_type + > si; + + typedef typename si::segment_intersection_strategy_type strategy; + + typename strategy::return_type result = strategy::apply(p1, q1); + + char const method = result.template get<1>().how; + + // Copy, to copy possibly extended fields + TurnInfo tp = tp_model; + + // Select method and apply + switch(method) + { + case 'a' : // collinear, "at" + case 'f' : // collinear, "from" + case 's' : // starts from the middle + handle_first(pi, pj, pk, qi, qj, qk, tp_model, result, out); + break; + + case 'd' : // disjoint: never do anything + break; + + case 'm' : + { + typedef overlay::touch_interior + < + TurnInfo + > policy; + + // If Q (1) arrives (1) + if (result.template get<1>().arrival[1] == 1) + { + policy::template apply<0>(pi, pj, pk, qi, qj, qk, + tp, result.template get<0>(), result.template get<1>(), + side_calc); + } + else + { + // Swap p/q + overlay::side_calculator swapped_side_calc(qi, qj, qk, pi, pj, pk); + policy::template apply<1>(qi, qj, qk, pi, pj, pk, + tp, result.template get<0>(), result.template get<1>(), + swapped_side_calc); + } + AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>()); + *out++ = tp; + } + break; + case 'i' : + { + overlay::crosses::apply(pi, pj, pk, qi, qj, qk, + tp, result.template get<0>(), result.template get<1>()); + AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>()); + *out++ = tp; + } + break; + case 't' : + { + // Both touch (both arrive there) + overlay::touch::apply(pi, pj, pk, qi, qj, qk, + tp, result.template get<0>(), result.template get<1>(), side_calc); + AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>()); + *out++ = tp; + } + break; + case 'e': + { + handle_first(pi, pj, pk, qi, qj, qk, tp_model, result, out); + + if (! result.template get<1>().opposite) + { + // Both equal + // or collinear-and-ending at intersection point + overlay::equal::apply(pi, pj, pk, qi, qj, qk, + tp, result.template get<0>(), result.template get<1>(), side_calc); + AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>()); + *out++ = tp; + } + else + { + overlay::equal_opposite + < + TurnInfo, + AssignPolicy + >::apply(pi, qi, + tp, out, result.template get<0>(), result.template get<1>()); + } + } + break; + case 'c' : + { + handle_first(pi, pj, pk, qi, qj, qk, tp_model, result, out); + + // Collinear + if (! result.template get<1>().opposite) + { + + if (result.template get<1>().arrival[0] == 0) + { + // Collinear, but similar thus handled as equal + overlay::equal::apply(pi, pj, pk, qi, qj, qk, + tp, result.template get<0>(), result.template get<1>(), side_calc); + + // override assigned method + tp.method = overlay::method_collinear; + } + else + { + overlay::collinear::apply(pi, pj, pk, qi, qj, qk, + tp, result.template get<0>(), result.template get<1>(), side_calc); + } + + AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>()); + *out++ = tp; + } + else + { + overlay::collinear_opposite + < + TurnInfo, + AssignPolicy + >::apply(pi, pj, pk, qi, qj, qk, + tp, out, result.template get<0>(), result.template get<1>(), side_calc); + } + } + break; + case '0' : + { + // degenerate points + if (AssignPolicy::include_degenerate) + { + overlay::only_convert::apply(tp, result.template get<0>()); + AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>()); + *out++ = tp; + } + } + break; + default : + { +#if defined(BOOST_GEOMETRY_DEBUG_ROBUSTNESS) + std::cout << "TURN: Unknown method: " << method << std::endl; +#endif +#if ! defined(BOOST_GEOMETRY_OVERLAY_NO_THROW) + throw turn_info_exception(method); +#endif + } + break; + } + + return out; + } + + template + < + typename Point1, + typename Point2, + typename TurnInfo, + typename IntersectionResult, + typename OutputIterator + > + static inline void handle_first(Point1 const& pi, Point1 const& pj, Point1 const& pk, + Point2 const& qi, Point2 const& qj, Point2 const& qk, + TurnInfo const& tp_model, + IntersectionResult const& result, + OutputIterator out) + { + bool has_intersections = result.template get<0>().count > 0; + if ( !has_intersections ) + return; + + bool is_p_first_ip = tp_model.operations[0].seg_id.segment_index == 0 + && equals::equals_point_point(pi, result.template get<0>().intersections[0]); + bool is_q_first_ip = tp_model.operations[1].seg_id.segment_index == 0 + && equals::equals_point_point(qi, result.template get<0>().intersections[0]); + + bool should_handle = has_intersections && ( is_p_first_ip || is_q_first_ip ); + + if ( !should_handle ) + return; + + TurnInfo tp = tp_model; + + overlay::side_calculator side_calc(pi, pi, pj, qi, qi, qj); + +// FROM SWITCH FOR COLINEAR + if (result.template get<1>().arrival[0] == 0) + { + // Collinear, but similar thus handled as equal + overlay::equal::apply(pi, pi, pj, qi, qi, qj, + tp, result.template get<0>(), result.template get<1>(), side_calc); + + // override assigned method + tp.method = overlay::method_collinear; + } + else + { + overlay::collinear::apply(pi, pi, pj, qi, qi, qj, + tp, result.template get<0>(), result.template get<1>(), side_calc); + } + + geometry::convert(result.template get<0>().intersections[0], tp.point); + + AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>()); + *out++ = tp; + } +}; + +// GET_TURN_INFO_TYPE + +template ::value, + bool IsAreal = boost::is_base_of::value> +struct tag_base : not_implemented +{}; + +template +struct tag_base +{ + typedef linear_tag type; +}; + +template +struct tag_base +{ + typedef areal_tag type; +}; + +template ::type, typename Tag2 = typename tag::type, + typename TagBase1 = typename tag_base::type, typename TagBase2 = typename tag_base::type> +struct get_turn_info + : overlay::get_turn_info +{}; + +template +struct get_turn_info + : get_turn_info_linear_linear +{}; + +// GET_TURNS + +template > struct get_turns { typedef typename geometry::point_type::type point1_type; @@ -64,33 +347,22 @@ struct get_turns template static inline void apply(Turns & turns, Geometry1 const& geometry1, Geometry2 const& geometry2) { - typedef //overlay::assign_null_policy - overlay::calculate_distance_policy assign_policy; - detail::get_turns::no_interrupt_policy interrupt_policy; static const bool reverse1 = detail::overlay::do_reverse::value>::value; static const bool reverse2 = detail::overlay::do_reverse::value>::value; -// boost::geometry::get_turns -// < -// reverse1, reverse2, assign_policy -// >(geometry1, geometry2, detail::no_rescale_policy(), turns, interrupt_policy); - - typedef detail::overlay::get_turn_info - < - assign_policy - > turn_policy; - dispatch::get_turns < typename bg::tag::type, typename bg::tag::type, Geometry1, Geometry2, reverse1, reverse2, - turn_policy + GetTurnPolicy >::apply(0, geometry1, 1, geometry2, bg::detail::no_rescale_policy(), turns, interrupt_policy); } }; +// TURNS SORTING AND SEARCHING + struct operation_order_uibc { template static inline diff --git a/test/algorithms/relate.cpp b/test/algorithms/relate.cpp index 0f154353e..f84c42d91 100644 --- a/test/algorithms/relate.cpp +++ b/test/algorithms/relate.cpp @@ -74,6 +74,17 @@ template void test_linestring_linestring() { typedef bg::model::linestring

ls; + + 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)", "lsls03.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)", "lsls06.svg"); + to_svg("LINESTRING(0 0,10 0,10 10)", "LINESTRING(1 0,9 9)", "lsls07.svg"); + to_svg("LINESTRING(0 0,1 0,10 0,10 10)", "LINESTRING(1 0,9 9)", "lsls08.svg"); + test_geometry("LINESTRING(0 0, 2 2, 3 2)", "LINESTRING(0 0, 2 2, 3 2)", "1FFF0FFFT"); test_geometry("LINESTRING(0 0,3 2)", "LINESTRING(0 0, 2 2, 3 2)", "FF1F0F1FT"); @@ -131,7 +142,9 @@ void test_linestring_linestring() 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)", "lsls163.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)", "lsls164.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"); diff --git a/test/to_svg.hpp b/test/to_svg.hpp index 98f169e02..d96592697 100644 --- a/test/to_svg.hpp +++ b/test/to_svg.hpp @@ -172,13 +172,13 @@ inline void turns_to_svg(Turns const& turns, Mapper & mapper, bool enrich = fals } } -//struct to_svg_assign_policy -// : bg::detail::overlay::calculate_distance_policy -//{ -// static bool const include_no_turn = true; -// static bool const include_degenerate = true; -// static bool const include_opposite = true; -//}; +struct to_svg_assign_policy + : bg::detail::overlay::calculate_distance_policy +{ + static bool const include_no_turn = false; + static bool const include_degenerate = false; + static bool const include_opposite = true; +}; template inline void to_svg(G const& g, std::string const& filename, bool sort = true) @@ -200,6 +200,7 @@ inline void to_svg(G const& g, std::string const& filename, bool sort = true) typedef bg::detail::overlay::traversal_turn_info

turn_info; typedef bg::detail::overlay::calculate_distance_policy AssignPolicy; + //typedef to_svg_assign_policy AssignPolicy; typedef std::deque Turns; typedef bg::detail::self_get_turn_points::no_interrupt_policy InterruptPolicy; @@ -218,7 +219,7 @@ inline void to_svg(G const& g, std::string const& filename, bool sort = true) } template -inline void to_svg(G1 const& g1, G2 const& g2, std::string const& filename, bool sort = true, bool reverse_by_geometry_id = false, bool enrich = false) +inline void to_svg(G1 const& g1, G2 const& g2, std::string const& filename, bool sort = true, bool use_old_turns_policy = false, bool enrich = false) { namespace bg = boost::geometry; @@ -240,7 +241,8 @@ inline void to_svg(G1 const& g1, G2 const& g2, std::string const& filename, bool // GET TURNS typedef bg::detail::overlay::traversal_turn_info turn_info; - typedef bg::detail::overlay::calculate_distance_policy AssignPolicy; + //typedef bg::detail::overlay::calculate_distance_policy AssignPolicy; + typedef to_svg_assign_policy AssignPolicy; typedef std::deque Turns; typedef bg::detail::get_turns::no_interrupt_policy InterruptPolicy; @@ -250,7 +252,7 @@ inline void to_svg(G1 const& g1, G2 const& g2, std::string const& filename, bool Turns turns; InterruptPolicy interrupt_policy; - if ( reverse_by_geometry_id ) + if ( use_old_turns_policy ) { boost::geometry::get_turns < @@ -259,17 +261,15 @@ inline void to_svg(G1 const& g1, G2 const& g2, std::string const& filename, bool } else { - typedef bg::detail::overlay::get_turn_info + typedef bg::detail::relate::turns::get_turn_info < - AssignPolicy + G1, G2, AssignPolicy > TurnPolicy; - bg::dispatch::get_turns + bg::detail::relate::turns::get_turns < - typename bg::tag::type, typename bg::tag::type, - G1, G2, Reverse1, Reverse2, - TurnPolicy - >::apply(0, g1, 1, g2, bg::detail::no_rescale_policy(), turns, interrupt_policy); + G1, G2, TurnPolicy + >::apply(turns, g1, g2); } if ( sort )