From da1a8da80bbc2b6dda178eca2722bd6861e73554 Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Wed, 11 Jun 2014 15:53:31 +0200 Subject: [PATCH] [buffer] use partition to check relation turn/piece --- .../algorithms/buffer/buffer_policies.hpp | 5 +- .../buffer/buffered_piece_collection.hpp | 112 ++---------- .../buffer/turn_in_piece_visitor.hpp | 165 ++++++++++++++++++ 3 files changed, 183 insertions(+), 99 deletions(-) create mode 100644 include/boost/geometry/extensions/algorithms/buffer/turn_in_piece_visitor.hpp diff --git a/include/boost/geometry/extensions/algorithms/buffer/buffer_policies.hpp b/include/boost/geometry/extensions/algorithms/buffer/buffer_policies.hpp index b9058ae8a..b0c5e7737 100644 --- a/include/boost/geometry/extensions/algorithms/buffer/buffer_policies.hpp +++ b/include/boost/geometry/extensions/algorithms/buffer/buffer_policies.hpp @@ -103,6 +103,8 @@ struct buffer_turn_info buffer_turn_operation > { + int turn_index; // TODO: this might go if partition can operate on non-const input + RobustPoint robust_point; RobustPoint mapped_robust_point; // alas... we still need to adapt our points, offsetting them 1 integer to be co-located with neighbours @@ -119,7 +121,8 @@ struct buffer_turn_info #endif inline buffer_turn_info() - : location(location_ok) + : turn_index(-1) + , location(location_ok) , count_within(0) , count_on_offsetted(0) , count_on_helper(0) diff --git a/include/boost/geometry/extensions/algorithms/buffer/buffered_piece_collection.hpp b/include/boost/geometry/extensions/algorithms/buffer/buffered_piece_collection.hpp index f1c85aa6b..75d10a0ac 100644 --- a/include/boost/geometry/extensions/algorithms/buffer/buffered_piece_collection.hpp +++ b/include/boost/geometry/extensions/algorithms/buffer/buffered_piece_collection.hpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -104,34 +105,6 @@ struct check_original } }; -// TODO: move this -template -inline bool projection_on_segment(Point const& subject, Point const& p, Point const& q) -{ - typedef Point vector_type; - typedef typename geometry::coordinate_type::type coordinate_type; - - vector_type v = q; - vector_type w = subject; - subtract_point(v, p); - subtract_point(w, p); - - coordinate_type const zero = coordinate_type(); - coordinate_type const c1 = dot_product(w, v); - - if (c1 < zero) - { - return false; - } - coordinate_type const c2 = dot_product(v, v); - if (c2 < c1) - { - return false; - } - - return true; -} - template struct buffered_piece_collection @@ -235,65 +208,9 @@ struct buffered_piece_collection : m_robust_policy(robust_policy) {} - inline bool on_offsetted(robust_point_type const& point, piece const& piece) const - { - for (int i = 1; i < piece.offsetted_count; i++) - { - robust_point_type const& previous = piece.robust_ring[i - 1]; - robust_point_type const& current = piece.robust_ring[i]; - int const side = side_strategy::apply(point, previous, current); - if (side == 0) - { - // Collinear, check if projection falls on it - if (projection_on_segment(point, previous, current)) - { - return true; - } - } - - } - return false; - } inline void classify_turn(buffer_turn_info_type& turn, piece const& pc) const { - if (pc.type == buffered_flat_end) - { - // Turns cannot be inside a flat end (though they can be on border) - return; - } - - for (int i = 0; i < 2; i++) - { - // Don't compare against one of the two source-pieces - if (turn.operations[i].piece_index == pc.index) - { - return; - } - } - - int geometry_code = detail::within::point_in_geometry(turn.robust_point, pc.robust_ring); - - if (geometry_code == 0) - { - if (! on_offsetted(turn.robust_point, pc)) - { - // It is on the border but not on the offsetted ring. - // Then it is somewhere on the helper-segments - // Classify it as inside - // TODO: for neighbouring flat ends this does not apply - geometry_code = 1; - turn.count_on_helper++; - } - } - - switch (geometry_code) - { - case 1 : turn.count_within++; break; - case 0 : turn.count_on_offsetted++; break; - } - - } template @@ -505,21 +422,19 @@ struct buffered_piece_collection inline void classify_turns() { - // Check if it is inside any of the pieces - // Now: quadratic - // TODO: in partition. - for (typename boost::range_iterator::type it = - boost::begin(m_turns); it != boost::end(m_turns); ++it) - { - typename std::vector::const_iterator pit; - for (pit = boost::begin(m_pieces); - pit != boost::end(m_pieces); - ++pit) - { - classify_turn(*it, *pit); - } - } + + turn_in_piece_visitor + < + turn_vector_type + > visitor(m_turns); + + geometry::partition + < + model::box, + turn_get_box, turn_ovelaps_box, + piece_get_box, piece_ovelaps_box + >::apply(m_turns, m_pieces, visitor); } template @@ -645,6 +560,7 @@ struct buffered_piece_collection it->mapped_robust_point = it->robust_point; robust_turn turn; + it->turn_index = index; turn.turn_index = index; turn.point = it->robust_point; for (int i = 0; i < 2; i++) diff --git a/include/boost/geometry/extensions/algorithms/buffer/turn_in_piece_visitor.hpp b/include/boost/geometry/extensions/algorithms/buffer/turn_in_piece_visitor.hpp new file mode 100644 index 000000000..ac86d2d46 --- /dev/null +++ b/include/boost/geometry/extensions/algorithms/buffer/turn_in_piece_visitor.hpp @@ -0,0 +1,165 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_TURN_IN_PIECE_VISITOR +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_TURN_IN_PIECE_VISITOR + +#include + +#include +#include +#include +#include +#include + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace buffer +{ + + +struct turn_get_box +{ + template + static inline void apply(Box& total, Turn const& turn) + { + geometry::expand(total, turn.robust_point); + } +}; + +struct turn_ovelaps_box +{ + template + static inline bool apply(Box const& box, Turn const& turn) + { + return ! geometry::disjoint(box, turn.robust_point); + } +}; +template +class turn_in_piece_visitor +{ + Turns& m_turns; // because partition is currently operating on const input only + + template + static inline bool projection_on_segment(Point const& subject, Point const& p, Point const& q) + { + typedef Point vector_type; + typedef typename geometry::coordinate_type::type coordinate_type; + + vector_type v = q; + vector_type w = subject; + subtract_point(v, p); + subtract_point(w, p); + + coordinate_type const zero = coordinate_type(); + coordinate_type const c1 = dot_product(w, v); + + if (c1 < zero) + { + return false; + } + coordinate_type const c2 = dot_product(v, v); + if (c2 < c1) + { + return false; + } + + return true; + } + + + template + inline bool on_offsetted(Point const& point, Piece const& piece) const + { + typedef typename strategy::side::services::default_strategy + < + typename cs_tag::type + >::type side_strategy; + + for (int i = 1; i < piece.offsetted_count; i++) + { + Point const& previous = piece.robust_ring[i - 1]; + Point const& current = piece.robust_ring[i]; + int const side = side_strategy::apply(point, previous, current); + if (side == 0) + { + // Collinear, check if projection falls on it + if (projection_on_segment(point, previous, current)) + { + return true; + } + } + + } + return false; + } + +public: + + inline turn_in_piece_visitor(Turns& turns) + : m_turns(turns) + {} + + template + inline void apply(Turn const& turn, Piece const& piece, bool first = true) + { + boost::ignore_unused_variable_warning(first); + if (piece.type == buffered_flat_end) + { + // Turns cannot be inside a flat end (though they can be on border) + return; + } + + for (int i = 0; i < 2; i++) + { + // Don't compare against one of the two source-pieces + if (turn.operations[i].piece_index == piece.index) + { + return; + } + } + + int geometry_code = detail::within::point_in_geometry(turn.robust_point, piece.robust_ring); + if (geometry_code == -1) + { + return; + } + + Turn& mutable_turn = m_turns[turn.turn_index]; + if (geometry_code == 0) + { + if (! on_offsetted(turn.robust_point, piece)) + { + // It is on the border but not on the offsetted ring. + // Then it is somewhere on the helper-segments + // Classify it as inside + // TODO: for neighbouring flat ends this does not apply + geometry_code = 1; + mutable_turn.count_on_helper++; + } + } + + switch (geometry_code) + { + case 1 : mutable_turn.count_within++; break; + case 0 : mutable_turn.count_on_offsetted++; break; + } + } +}; + + +}} // namespace detail::buffer +#endif // DOXYGEN_NO_DETAIL + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_TURN_IN_PIECE_VISITOR