diff --git a/include/boost/geometry/algorithms/detail/overlay/follow_linear_linear.hpp b/include/boost/geometry/algorithms/detail/overlay/follow_linear_linear.hpp index a3b74967b..7fe4fadc6 100644 --- a/include/boost/geometry/algorithms/detail/overlay/follow_linear_linear.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/follow_linear_linear.hpp @@ -11,6 +11,7 @@ #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_FOLLOW_LINEAR_LINEAR_HPP #include +#include namespace boost { namespace geometry { @@ -63,7 +64,6 @@ static inline bool is_staying_inside(Turn const& turn, template static inline bool is_leaving(Turn const& turn, Operation const& operation, - Operation const& reverse_operation, bool entered) { if ( !entered ) @@ -89,29 +89,29 @@ static inline bool is_leaving(Turn const& turn, return false; } - if ( turn.operations[1].operation == operation_intersection ) - { - return true; - } - - BOOST_ASSERT( turn.operations[1].operation == operation_union - || turn.operations[1].operation == operation_blocked ); - - return reverse_operation.operation == operation_intersection; + return operation.is_collinear; } + template static inline bool is_isolated_point(Turn const& turn, Operation const& operation, - Operation const& reverse_operation, - bool entered) + bool entered, + bool is_point1, + bool is_point2) { if ( entered ) { return false; } + if ( turn.method == method_collinear && (is_point1 || is_point2) ) + { + BOOST_ASSERT( operation.operation == operation_continue ); + return true; + } + if ( turn.method == method_crosses ) { return true; @@ -132,17 +132,42 @@ static inline bool is_isolated_point(Turn const& turn, return false; } - if ( turn.operations[1].operation == operation_intersection ) + return !operation.is_collinear; +} + + + + +template +struct is_point +{ + template + static inline bool apply(Linestring const& linestring) { return false; } +}; + + +template<> +struct is_point +{ + template + static inline bool apply(Linestring const& linestring) + { + BOOST_ASSERT( boost::size(linestring) >= 2 ); + + return boost::size(linestring) == 2 + && geometry::equals(*boost::begin(linestring), + *(++boost::begin(linestring)) + ); + } +}; + + + - BOOST_ASSERT( turn.operations[1].operation == operation_union - || turn.operations[1].operation == operation_blocked ); - return reverse_operation.operation == operation_union - || reverse_operation.operation == operation_blocked; -} template @@ -166,11 +191,14 @@ protected: typename OutputIterator > static inline OutputIterator - process_turn(TurnIterator it, TurnIterator it_r, - TurnOperationIterator op_it, TurnOperationIterator op_it_r, + process_turn(TurnIterator it, + TurnOperationIterator op_it, bool& first, bool& entered, std::size_t& enter_count, - LineString1 const& linestring1, LineString2 const&, + LineString1 const& linestring1, + LineString2 const& linestring2, + bool is_point1, + bool is_point2, LineStringOut& current_piece, SegmentIdentifier& current_segment_id, OutputIterator oit) @@ -178,7 +206,7 @@ protected: if ( is_entering(*it, *op_it) ) { #ifdef GEOMETRY_TEST_DEBUG - detail::overlay::debug_traverse(*it, *op_it, "-> Entering"); + detail::turns::debug_turn(*it, *op_it, "-> Entering"); #endif entered = true; @@ -191,18 +219,10 @@ protected: } ++enter_count; } - else if ( is_staying_inside(*it, *op_it, entered) ) + else if ( is_leaving(*it, *op_it, entered) ) { #ifdef GEOMETRY_TEST_DEBUG - detail::overlay::debug_traverse(*it, *op_it, "-> Staying inside"); -#endif - - entered = true; - } - else if ( is_leaving(*it, *op_it, *op_it_r, entered) ) - { -#ifdef GEOMETRY_TEST_DEBUG - detail::overlay::debug_traverse(*it, *op_it, "-> Leaving"); + detail::turns::debug_turn(*it, *op_it, "-> Leaving"); #endif --enter_count; @@ -216,11 +236,11 @@ protected: } } #ifndef BOOST_GEOMETRY_INTERSECTION_DO_NOT_INCLUDE_ISOLATED_POINTS - else if ( FollowIsolatedPoints && - is_isolated_point(*it, *op_it, *op_it_r, entered) ) + else if ( FollowIsolatedPoints + && is_isolated_point(*it, *op_it, entered, is_point1, is_point2) ) { #ifdef GEOMETRY_TEST_DEBUG - detail::overlay::debug_traverse(*it, *op_it, "-> Isolated point"); + detail::turns::debug_turn(*it, *op_it, "-> Isolated point"); #endif action::isolated_point(current_piece, linestring1, @@ -229,6 +249,14 @@ protected: it->point, *op_it, oit); } #endif + else if ( is_staying_inside(*it, *op_it, entered) ) + { +#ifdef GEOMETRY_TEST_DEBUG + detail::turns::debug_turn(*it, *op_it, "-> Staying inside"); +#endif + + entered = true; + } first = false; return oit; } @@ -267,11 +295,8 @@ public: static inline OutputIterator apply(LineString1 const& linestring1, LineString2 const& linestring2, Turns const& turns, - Turns const& reverse_turns, OutputIterator oit) { - BOOST_ASSERT( boost::size(turns) == boost::size(reverse_turns) ); - typedef typename boost::range_iterator::type TurnIterator; typedef typename boost::range_value::type TurnInfo; typedef typename boost::range_iterator @@ -289,17 +314,17 @@ public: bool first = true; std::size_t enter_count = 0; - TurnIterator it = boost::begin(turns); - TurnIterator it_r = boost::begin(reverse_turns); - for (; it != boost::end(turns); ++it, ++it_r) + bool is_point1 = is_point::apply(linestring1); + bool is_point2 = is_point::apply(linestring2); + + for (TurnIterator it = boost::begin(turns); it != boost::end(turns); ++it) { TurnOperationIterator op_it = boost::begin(it->operations); - TurnOperationIterator op_it_r = boost::begin(it_r->operations); - ++op_it_r; - oit = process_turn(it, it_r, op_it, op_it_r, + oit = process_turn(it, op_it, first, entered, enter_count, linestring1, linestring2, + is_point1, is_point2, current_piece, current_segment_id, oit); } @@ -348,11 +373,8 @@ public: static inline OutputIterator apply(LineString const& linestring, MultiLineString const& multilinestring, Turns const& turns, - Turns const& reverse_turns, OutputIterator oit) { - BOOST_ASSERT( boost::size(turns) == boost::size(reverse_turns) ); - typedef typename boost::range_iterator::type TurnIterator; typedef typename boost::range_value::type TurnInfo; typedef typename boost::range_iterator @@ -370,20 +392,20 @@ public: bool first = true; std::size_t enter_count = 0; - TurnIterator it = boost::begin(turns); - TurnIterator it_r = boost::begin(reverse_turns); - for (; it != boost::end(turns); ++it, ++it_r) + bool is_point1 = is_point::apply(linestring); + + for (TurnIterator it = boost::begin(turns); it != boost::end(turns); ++it) { TurnOperationIterator op_it = boost::begin(it->operations); - TurnOperationIterator op_it_r = boost::begin(it_r->operations); - ++op_it_r; LineString2 const* linestring2 = &*(boost::begin(multilinestring) + op_it->other_id.multi_index); - oit = Base::process_turn(it, it_r, op_it, op_it_r, + oit = Base::process_turn(it, op_it, first, entered, enter_count, linestring, *linestring2, + is_point1, + is_point::apply(*linestring2), current_piece, current_segment_id, oit); } @@ -434,11 +456,8 @@ public: static inline OutputIterator apply(MultiLineString const& multilinestring, LineString const& linestring, Turns const& turns, - Turns const& reverse_turns, OutputIterator oit) { - BOOST_ASSERT( boost::size(turns) == boost::size(reverse_turns) ); - typedef typename boost::range_iterator::type TurnIterator; typedef typename boost::range_value::type TurnInfo; typedef typename boost::range_iterator @@ -461,13 +480,13 @@ public: // dummy initialization LineString1 const* linestring1 = &*boost::begin(multilinestring); + bool is_point1 = is_point::apply(*linestring1); + bool is_point2 = is_point::apply(linestring); + TurnIterator it = boost::begin(turns); - TurnIterator it_r = boost::begin(reverse_turns); - for (; it != boost::end(turns); ++it, ++it_r) + for (TurnIterator it = boost::begin(turns); it != boost::end(turns); ++it) { TurnOperationIterator op_it = boost::begin(it->operations); - TurnOperationIterator op_it_r = boost::begin(it_r->operations); - ++op_it_r; if ( op_it->seg_id.multi_index != current_multi_id ) { @@ -492,11 +511,13 @@ public: current_multi_id = op_it->seg_id.multi_index; linestring1 = &*(boost::begin(multilinestring) + current_multi_id); + is_point1 = is_point::apply(*linestring1); } - oit = Base::process_turn(it, it_r, op_it, op_it_r, + oit = Base::process_turn(it, op_it, first, entered, enter_count, *linestring1, linestring, + is_point1, is_point2, current_piece, current_segment_id, oit); } @@ -546,11 +567,8 @@ public: static inline OutputIterator apply(MultiLineString1 const& multilinestring1, MultiLineString2 const& multilinestring2, Turns const& turns, - Turns const& reverse_turns, OutputIterator oit) { - BOOST_ASSERT( boost::size(turns) == boost::size(reverse_turns) ); - typedef typename boost::range_iterator::type TurnIterator; typedef typename boost::range_value::type TurnInfo; typedef typename boost::range_iterator @@ -573,13 +591,11 @@ public: // dummy initialization LineString1 const* linestring1 = &*boost::begin(multilinestring1); - TurnIterator it = boost::begin(turns); - TurnIterator it_r = boost::begin(reverse_turns); - for (; it != boost::end(turns); ++it, ++it_r) + bool is_point1 = is_point::apply(*linestring1); + + for (TurnIterator it = boost::begin(turns); it != boost::end(turns); ++it) { TurnOperationIterator op_it = boost::begin(it->operations); - TurnOperationIterator op_it_r = boost::begin(it_r->operations); - ++op_it_r; if ( op_it->seg_id.multi_index != current_multi_id ) { @@ -604,14 +620,16 @@ public: current_multi_id = op_it->seg_id.multi_index; linestring1 = &*(boost::begin(multilinestring1) + current_multi_id); + is_point1 = is_point::apply(*linestring1); } LineString2 const* linestring2 = &*(boost::begin(multilinestring2) + op_it->other_id.multi_index); - - oit = Base::process_turn(it, it_r, op_it, op_it_r, + oit = Base::process_turn(it, op_it, first, entered, enter_count, *linestring1, *linestring2, + is_point1, + is_point::apply(*linestring2), current_piece, current_segment_id, oit); } diff --git a/include/boost/geometry/algorithms/detail/overlay/linear_linear.hpp b/include/boost/geometry/algorithms/detail/overlay/linear_linear.hpp index 16b97cef7..5fb2ca42a 100644 --- a/include/boost/geometry/algorithms/detail/overlay/linear_linear.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/linear_linear.hpp @@ -13,20 +13,19 @@ #include +#include #include +#include + #include #include #include +#include +#include + #include -#ifndef BOOST_GEOMETRY_DIFFERENCE_DO_NOT_FILTER_CONTINUE_TURNS -#include -#endif - -#ifndef BOOST_GEOMETRY_DIFFERENCE_DO_NOT_REMOVE_DUPLICATE_TURNS -#include -#endif namespace boost { namespace geometry @@ -111,6 +110,48 @@ struct linear_linear_no_intersections }; +template +< + typename Geometry, + bool Enable = false, + typename GeometryTag = typename tag::type +> +struct remove_extra_points +{ + static inline void apply(Geometry& ) {} +}; + + +template +struct remove_extra_points +{ + static inline void apply(Linestring& linestring) + { + geometry::unique(linestring); + if ( boost::size(linestring) == 1 ) + { + geometry::append(linestring, *boost::begin(linestring)); + } + } +}; + + +template +struct remove_extra_points +{ + static inline void apply(MultiLinestring& multilinestring) + { + BOOST_AUTO_TPL(it, boost::begin(multilinestring)); + for (; it != boost::end(multilinestring); ++it) + { + remove_extra_points + < + typename boost::range_value::type, + true + >::apply(*it); + } + } +}; @@ -126,7 +167,8 @@ template typename Linear2, typename LinestringOut, overlay_type OverlayType, - bool EnableFilterContinueTurns = true, + bool EnableRemoveExtraPoints = true, + bool EnableFilterContinueTurns = false, bool EnableRemoveDuplicateTurns = true, bool EnableDegenerateTurns = true > @@ -136,11 +178,7 @@ protected: struct AssignPolicy { static bool const include_no_turn = false; -#ifdef BOOST_GEOMETRY_DIFFERENCE_INCLUDE_DEGENERATE_TURNS - static bool const include_degenerate = true; -#else static bool const include_degenerate = EnableDegenerateTurns; -#endif static bool const include_opposite = false; template @@ -194,7 +232,6 @@ protected: typename OutputIterator > static inline OutputIterator follow_turns(Turns const& turns, - Turns const& reverse_turns, LinearGeometry1 const& linear1, LinearGeometry2 const& linear2, OutputIterator oit) @@ -206,7 +243,7 @@ protected: LinearGeometry2, OverlayTypeForFollow, FollowIsolatedPoints - >::apply(linear1, linear2, turns, reverse_turns, oit); + >::apply(linear1, linear2, turns, oit); } @@ -221,54 +258,91 @@ protected: > static inline OutputIterator sort_and_follow_turns(Turns& turns, - Turns& reverse_turns, LinearGeometry1 const& linear1, LinearGeometry2 const& linear2, OutputIterator oit) { -#ifndef BOOST_GEOMETRY_DIFFERENCE_DO_NOT_FILTER_CONTINUE_TURNS // remove turns that have no added value turns::filter_continue_turns < Turns, EnableFilterContinueTurns >::apply(turns); - turns::filter_continue_turns - < - Turns, EnableFilterContinueTurns - >::apply(reverse_turns); -#endif // sort by seg_id, distance, and operation std::sort(boost::begin(turns), boost::end(turns), detail::turns::less_seg_dist_other_op<>()); - std::sort(boost::begin(reverse_turns), boost::end(reverse_turns), - detail::turns::less_seg_dist_other_op >()); - -#ifndef BOOST_GEOMETRY_DIFFERENCE_DO_NOT_REMOVE_DUPLICATE_TURNS // remove duplicate turns turns::remove_duplicate_turns < Turns, EnableRemoveDuplicateTurns >::apply(turns); + +#ifdef GEOMETRY_TEST_DEBUG + Linear2 linear2_reverse(linear2); + geometry::reverse(linear2_reverse); + Turns reverse_turns; + compute_turns(reverse_turns, linear1, linear2_reverse); + + + Turns turns_copy(turns); + Turns reverse_turns_copy(reverse_turns); + + turns::filter_continue_turns + < + Turns, true //EnableFilterContinueTurns + >::apply(turns_copy); + + turns::filter_continue_turns + < + Turns, EnableFilterContinueTurns + >::apply(reverse_turns); + + turns::filter_continue_turns + < + Turns, true //EnableFilterContinueTurns + >::apply(reverse_turns_copy); + + std::sort(boost::begin(turns_copy), boost::end(turns_copy), + detail::turns::less_seg_dist_other_op<>()); + + std::sort(boost::begin(reverse_turns), boost::end(reverse_turns), + detail::turns::less_seg_dist_other_op >()); + + std::sort(boost::begin(reverse_turns_copy), boost::end(reverse_turns_copy), + detail::turns::less_seg_dist_other_op >()); + turns::remove_duplicate_turns < Turns, EnableRemoveDuplicateTurns >::apply(reverse_turns); -#endif -#ifdef GEOMETRY_TEST_DEBUG + turns::remove_duplicate_turns + < + Turns, EnableRemoveDuplicateTurns + >::apply(reverse_turns_copy); + + BOOST_ASSERT( boost::size(turns_copy) == boost::size(reverse_turns_copy) ); + + std::cout << std::endl << std::endl; + std::cout << "### ORIGINAL TURNS ###" << std::endl; detail::turns::print_turns(linear1, linear2, turns); std::cout << std::endl << std::endl; - Linear2 linear2_reverse = linear2; - geometry::reverse(linear2_reverse); - detail::turns::print_turns(linear1, linear2_reverse, reverse_turns); + std::cout << "### ORIGINAL REVERSE TURNS ###" << std::endl; + detail::turns::print_turns(linear1, linear2, reverse_turns); + std::cout << std::endl << std::endl; + std::cout << "### TURNS W/O CONTINUE TURNS ###" << std::endl; + detail::turns::print_turns(linear1, linear2, turns_copy); + std::cout << std::endl << std::endl; + std::cout << "### REVERSE TURNS W/O CONTINUE TURNS ###" << std::endl; + detail::turns::print_turns(linear1, linear2_reverse, reverse_turns_copy); + std::cout << std::endl << std::endl; #endif return follow_turns < OverlayTypeForFollow, FollowIsolatedPoints - >(turns, reverse_turns, linear1, linear2, oit); + >(turns, linear1, linear2, oit); } public: @@ -276,15 +350,21 @@ public: < typename OutputIterator, typename Strategy > - static inline OutputIterator apply(Linear1 const& linear1, - Linear2 const& linear2, + static inline OutputIterator apply(Linear1 const& lineargeometry1, + Linear2 const& lineargeometry2, OutputIterator oit, Strategy const& ) { - typedef traversal_turn_info + Linear1 linear1(lineargeometry1); + Linear2 linear2(lineargeometry2); + + remove_extra_points::apply(linear1); + remove_extra_points::apply(linear2); + + typedef typename detail::relate::turns::get_turns < - typename point_type::type - > turn_info; + Linear1, Linear2 + >::turn_info turn_info; typedef std::vector Turns; @@ -306,16 +386,10 @@ public: >::apply(linear1, oit); } - - Turns reverse_turns; - Linear2 linear2_reverse = linear2; - geometry::reverse(linear2_reverse); - compute_turns(reverse_turns, linear1, linear2_reverse); - return sort_and_follow_turns < OverlayType, OverlayType == overlay_intersection - >(turns, reverse_turns, linear1, linear2, oit); + >(turns, linear1, linear2, oit); } }; @@ -326,19 +400,34 @@ template < typename Linear1, typename Linear2, - typename LinestringOut + typename LinestringOut, + bool EnableRemoveExtraPoints, + bool EnableFilterContinueTurns, + bool EnableRemoveDuplicateTurns, + bool EnableDegenerateTurns > -struct linear_linear_linestring +struct linear_linear_linestring + < + Linear1, Linear2, LinestringOut, overlay_union, + EnableRemoveExtraPoints, EnableFilterContinueTurns, + EnableRemoveDuplicateTurns, EnableDegenerateTurns + > { template < typename OutputIterator, typename Strategy > - static inline OutputIterator apply(Linear1 const& linear1, - Linear2 const& linear2, + static inline OutputIterator apply(Linear1 const& lineargeometry1, + Linear2 const& lineargeometry2, OutputIterator oit, Strategy const& strategy) { + Linear1 linear1(lineargeometry1); + Linear2 linear2(lineargeometry2); + + remove_extra_points::apply(linear1); + remove_extra_points::apply(linear2); + oit = linear_linear_no_intersections < LinestringOut, @@ -349,7 +438,9 @@ struct linear_linear_linestring return linear_linear_linestring < - Linear2, Linear1, LinestringOut, overlay_difference + Linear2, Linear1, LinestringOut, overlay_difference, + false, EnableFilterContinueTurns, + EnableRemoveDuplicateTurns, EnableDegenerateTurns >::apply(linear2, linear1, oit, strategy); } };