diff options
author | DongHun Kwak <dh0128.kwak@samsung.com> | 2019-12-05 15:22:41 +0900 |
---|---|---|
committer | DongHun Kwak <dh0128.kwak@samsung.com> | 2019-12-05 15:22:41 +0900 |
commit | 3c1df2168531ad5580076ae08d529054689aeedd (patch) | |
tree | 941aff6f86393eecacddfec252a8508c7e8351c9 /boost/geometry/algorithms/detail | |
parent | d6a306e745acfee00e81ccaf3324a2a03516db41 (diff) | |
download | boost-3c1df2168531ad5580076ae08d529054689aeedd.tar.gz boost-3c1df2168531ad5580076ae08d529054689aeedd.tar.bz2 boost-3c1df2168531ad5580076ae08d529054689aeedd.zip |
Imported Upstream version 1.70.0upstream/1.70.0
Diffstat (limited to 'boost/geometry/algorithms/detail')
91 files changed, 3004 insertions, 4002 deletions
diff --git a/boost/geometry/algorithms/detail/buffer/buffer_box.hpp b/boost/geometry/algorithms/detail/buffer/buffer_box.hpp new file mode 100755 index 0000000000..f19a91d6ba --- /dev/null +++ b/boost/geometry/algorithms/detail/buffer/buffer_box.hpp @@ -0,0 +1,62 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2018-2019 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_BUFFER_BOX_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_BOX_HPP + +#include <cstddef> + +#include <boost/geometry/core/coordinate_dimension.hpp> +#include <boost/geometry/core/coordinate_type.hpp> +#include <boost/geometry/core/access.hpp> + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace buffer +{ + +template <typename BoxIn, typename BoxOut, typename T, std::size_t C, std::size_t D, std::size_t N> +struct box_loop +{ + typedef typename coordinate_type<BoxOut>::type coordinate_type; + + static inline void apply(BoxIn const& box_in, T const& distance, BoxOut& box_out) + { + coordinate_type d = distance; + set<C, D>(box_out, get<C, D>(box_in) + d); + box_loop<BoxIn, BoxOut, T, C, D + 1, N>::apply(box_in, distance, box_out); + } +}; + +template <typename BoxIn, typename BoxOut, typename T, std::size_t C, std::size_t N> +struct box_loop<BoxIn, BoxOut, T, C, N, N> +{ + static inline void apply(BoxIn const&, T const&, BoxOut&) {} +}; + +// Extends a box with the same amount in all directions +template<typename BoxIn, typename BoxOut, typename T> +inline void buffer_box(BoxIn const& box_in, T const& distance, BoxOut& box_out) +{ + assert_dimension_equal<BoxIn, BoxOut>(); + + static const std::size_t N = dimension<BoxIn>::value; + + box_loop<BoxIn, BoxOut, T, min_corner, 0, N>::apply(box_in, -distance, box_out); + box_loop<BoxIn, BoxOut, T, max_corner, 0, N>::apply(box_in, distance, box_out); +} + +}} // namespace detail::buffer +#endif // DOXYGEN_NO_DETAIL + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_BOX_HPP diff --git a/boost/geometry/algorithms/detail/buffer/buffer_policies.hpp b/boost/geometry/algorithms/detail/buffer/buffer_policies.hpp index 0374b53a99..a37eabbe25 100644 --- a/boost/geometry/algorithms/detail/buffer/buffer_policies.hpp +++ b/boost/geometry/algorithms/detail/buffer/buffer_policies.hpp @@ -2,8 +2,8 @@ // Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands. -// This file was modified by Oracle on 2017. -// Modifications copyright (c) 2017, Oracle and/or its affiliates. +// This file was modified by Oracle on 2017, 2018. +// Modifications copyright (c) 2017-2018, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, @@ -13,10 +13,6 @@ #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_POLICIES_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_POLICIES_HPP -#if ! defined(BOOST_GEOMETRY_NO_ROBUSTNESS) -# define BOOST_GEOMETRY_BUFFER_USE_SIDE_OF_INTERSECTION -#endif - #include <cstddef> #include <boost/range.hpp> @@ -26,6 +22,7 @@ #include <boost/geometry/algorithms/covered_by.hpp> #include <boost/geometry/algorithms/detail/overlay/backtrack_check_si.hpp> +#include <boost/geometry/algorithms/detail/overlay/traversal_info.hpp> #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp> #include <boost/geometry/strategies/buffer.hpp> @@ -181,9 +178,7 @@ struct buffer_turn_info intersection_location_type location; -#if defined(BOOST_GEOMETRY_BUFFER_USE_SIDE_OF_INTERSECTION) robust_point_type rob_pi, rob_pj, rob_qi, rob_qj; -#endif std::size_t count_within; @@ -193,9 +188,7 @@ struct buffer_turn_info std::size_t count_on_offsetted; std::size_t count_on_helper; -#if ! defined(BOOST_GEOMETRY_BUFFER_USE_SIDE_OF_INTERSECTION) std::size_t count_within_near_offsetted; -#endif bool remove_on_multi; @@ -212,9 +205,7 @@ struct buffer_turn_info , count_in_original(0) , count_on_offsetted(0) , count_on_helper(0) -#if ! defined(BOOST_GEOMETRY_BUFFER_USE_SIDE_OF_INTERSECTION) , count_within_near_offsetted(0) -#endif , remove_on_multi(false) , count_on_occupied(0) , count_on_multi(0) diff --git a/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp b/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp index ba824243cc..128f2beef3 100644 --- a/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp +++ b/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp @@ -3,8 +3,8 @@ // Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland. -// This file was modified by Oracle on 2016-2017. -// Modifications copyright (c) 2016-2017 Oracle and/or its affiliates. +// This file was modified by Oracle on 2016-2018. +// Modifications copyright (c) 2016-2018 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, @@ -145,6 +145,8 @@ struct buffered_piece_collection >::type robust_comparable_radius_type; typedef typename IntersectionStrategy::side_strategy_type side_strategy_type; + typedef typename IntersectionStrategy::envelope_strategy_type envelope_strategy_type; + typedef typename IntersectionStrategy::expand_strategy_type expand_strategy_type; typedef typename IntersectionStrategy::template area_strategy < @@ -165,6 +167,12 @@ struct buffered_piece_collection robust_point_type >::type robust_area_result_type; + typedef typename strategy::point_in_geometry::services::default_strategy + < + robust_point_type, + robust_ring_type + >::type point_in_geometry_strategy_type; + typedef typename geometry::rescale_policy_type < typename geometry::point_type<Ring>::type @@ -280,12 +288,14 @@ struct buffered_piece_collection {} inline robust_original(robust_ring_type const& ring, - bool is_interior, bool has_interiors) + bool is_interior, bool has_interiors, + envelope_strategy_type const& envelope_strategy, + expand_strategy_type const& expand_strategy) : m_ring(ring) , m_is_interior(is_interior) , m_has_interiors(has_interiors) { - geometry::envelope(m_ring, m_box); + geometry::envelope(m_ring, m_box, envelope_strategy); // create monotonic sections in x-dimension // The dimension is critical because the direction is later used @@ -293,7 +303,8 @@ struct buffered_piece_collection // and this strategy is scanning in x direction. typedef boost::mpl::vector_c<std::size_t, 0> dimensions; geometry::sectionalize<false, dimensions>(m_ring, - detail::no_rescale_policy(), m_sections); + detail::no_rescale_policy(), m_sections, + envelope_strategy, expand_strategy); } robust_ring_type m_ring; @@ -335,6 +346,9 @@ struct buffered_piece_collection IntersectionStrategy m_intersection_strategy; side_strategy_type m_side_strategy; area_strategy_type m_area_strategy; + envelope_strategy_type m_envelope_strategy; + expand_strategy_type m_expand_strategy; + robust_area_strategy_type m_robust_area_strategy; RobustPolicy const& m_robust_policy; @@ -354,6 +368,8 @@ struct buffered_piece_collection , m_intersection_strategy(intersection_strategy) , m_side_strategy(intersection_strategy.get_side_strategy()) , m_area_strategy(intersection_strategy.template get_area_strategy<point_type>()) + , m_envelope_strategy(intersection_strategy.get_envelope_strategy()) + , m_expand_strategy(intersection_strategy.get_expand_strategy()) , m_robust_area_strategy(intersection_strategy.template get_area_strategy<robust_point_type>()) , m_robust_policy(robust_policy) {} @@ -529,7 +545,6 @@ struct buffered_piece_collection { it->location = inside_buffer; } -#if ! defined(BOOST_GEOMETRY_BUFFER_USE_SIDE_OF_INTERSECTION) if (it->count_within_near_offsetted > 0) { // Within can have in rare cases a rounding issue. We don't discard this @@ -538,7 +553,6 @@ struct buffered_piece_collection it->operations[0].enriched.startable = false; it->operations[1].enriched.startable = false; } -#endif } } @@ -635,6 +649,15 @@ struct buffered_piece_collection { // Check if a turn is inside any of the originals + typedef turn_in_original_ovelaps_box + < + typename IntersectionStrategy::disjoint_point_box_strategy_type + > turn_in_original_ovelaps_box_type; + typedef original_ovelaps_box + < + typename IntersectionStrategy::disjoint_box_box_strategy_type + > original_ovelaps_box_type; + turn_in_original_visitor<turn_vector_type> visitor(m_turns); geometry::partition < @@ -642,8 +665,8 @@ struct buffered_piece_collection include_turn_policy, detail::partition::include_all_policy >::apply(m_turns, robust_originals, visitor, - turn_get_box(), turn_in_original_ovelaps_box(), - original_get_box(), original_ovelaps_box()); + turn_get_box(), turn_in_original_ovelaps_box_type(), + original_get_box(), original_ovelaps_box_type()); bool const deflate = distance_strategy.negative(); @@ -727,46 +750,47 @@ struct buffered_piece_collection } } -#if ! defined(BOOST_GEOMETRY_BUFFER_USE_SIDE_OF_INTERSECTION) - // Insert all rescaled turn-points into these rings, to form a - // reliable integer-based ring. All turns can be compared (inside) to this - // rings to see if they are inside. - - for (typename boost::range_iterator<piece_vector_type>::type - it = boost::begin(m_pieces); it != boost::end(m_pieces); ++it) + if (! use_side_of_intersection<typename geometry::cs_tag<point_type>::type>::value) { - piece& pc = *it; - signed_size_type piece_segment_index = pc.first_seg_id.segment_index; - if (! pc.robust_turns.empty()) + // Insert all rescaled turn-points into these rings, to form a + // reliable integer-based ring. All turns can be compared (inside) to this + // rings to see if they are inside. + + for (typename boost::range_iterator<piece_vector_type>::type + it = boost::begin(m_pieces); it != boost::end(m_pieces); ++it) { - if (pc.robust_turns.size() > 1u) + piece& pc = *it; + signed_size_type piece_segment_index = pc.first_seg_id.segment_index; + if (! pc.robust_turns.empty()) { - std::sort(pc.robust_turns.begin(), pc.robust_turns.end(), buffer_operation_less()); - } - // Walk through them, in reverse to insert at right index - signed_size_type index_offset = static_cast<signed_size_type>(pc.robust_turns.size()) - 1; - for (typename boost::range_reverse_iterator<const std::vector<robust_turn> >::type - rit = boost::const_rbegin(pc.robust_turns); - rit != boost::const_rend(pc.robust_turns); - ++rit, --index_offset) - { - signed_size_type const index_in_vector = 1 + rit->seg_id.segment_index - piece_segment_index; - BOOST_GEOMETRY_ASSERT - ( - index_in_vector > 0 - && index_in_vector < pc.offsetted_count - ); + if (pc.robust_turns.size() > 1u) + { + std::sort(pc.robust_turns.begin(), pc.robust_turns.end(), buffer_operation_less()); + } + // Walk through them, in reverse to insert at right index + signed_size_type index_offset = static_cast<signed_size_type>(pc.robust_turns.size()) - 1; + for (typename boost::range_reverse_iterator<const std::vector<robust_turn> >::type + rit = boost::const_rbegin(pc.robust_turns); + rit != boost::const_rend(pc.robust_turns); + ++rit, --index_offset) + { + signed_size_type const index_in_vector = 1 + rit->seg_id.segment_index - piece_segment_index; + BOOST_GEOMETRY_ASSERT + ( + index_in_vector > 0 + && index_in_vector < pc.offsetted_count + ); - pc.robust_ring.insert(boost::begin(pc.robust_ring) + index_in_vector, rit->point); - pc.offsetted_count++; + pc.robust_ring.insert(boost::begin(pc.robust_ring) + index_in_vector, rit->point); + pc.offsetted_count++; - m_turns[rit->turn_index].operations[rit->operation_index].index_in_robust_ring = index_in_vector + index_offset; + m_turns[rit->turn_index].operations[rit->operation_index].index_in_robust_ring = index_in_vector + index_offset; + } } } - } - BOOST_GEOMETRY_ASSERT(assert_indices_in_robust_rings()); -#endif + BOOST_GEOMETRY_ASSERT(assert_indices_in_robust_rings()); + } } template <std::size_t Dimension> @@ -842,7 +866,8 @@ struct buffered_piece_collection // create monotonic sections in y-dimension typedef boost::mpl::vector_c<std::size_t, 1> dimensions; geometry::sectionalize<false, dimensions>(pc.robust_ring, - detail::no_rescale_policy(), pc.sections); + detail::no_rescale_policy(), pc.sections, + m_envelope_strategy, m_expand_strategy); // Determine min/max radius typedef geometry::model::referring_segment<robust_point_type const> @@ -906,12 +931,21 @@ struct buffered_piece_collection > visitor(m_pieces, offsetted_rings, m_turns, m_intersection_strategy, m_robust_policy); + typedef detail::section::get_section_box + < + typename IntersectionStrategy::expand_box_strategy_type + > get_section_box_type; + typedef detail::section::overlaps_section_box + < + typename IntersectionStrategy::disjoint_box_box_strategy_type + > overlaps_section_box_type; + geometry::partition < robust_box_type >::apply(monotonic_sections, visitor, - detail::section::get_section_box(), - detail::section::overlaps_section_box()); + get_section_box_type(), + overlaps_section_box_type()); } insert_rescaled_piece_turns(); @@ -926,15 +960,26 @@ struct buffered_piece_collection // Check if it is inside any of the pieces turn_in_piece_visitor < - turn_vector_type, piece_vector_type - > visitor(m_turns, m_pieces); + typename geometry::cs_tag<point_type>::type, + turn_vector_type, piece_vector_type, + point_in_geometry_strategy_type + > visitor(m_turns, m_pieces, point_in_geometry_strategy_type()); + + typedef turn_ovelaps_box + < + typename IntersectionStrategy::disjoint_point_box_strategy_type + > turn_ovelaps_box_type; + typedef piece_ovelaps_box + < + typename IntersectionStrategy::disjoint_box_box_strategy_type + > piece_ovelaps_box_type; geometry::partition < robust_box_type >::apply(m_turns, m_pieces, visitor, - turn_get_box(), turn_ovelaps_box(), - piece_get_box(), piece_ovelaps_box()); + turn_get_box(), turn_ovelaps_box_type(), + piece_get_box(), piece_ovelaps_box_type()); } } @@ -1057,7 +1102,7 @@ struct buffered_piece_collection robust_originals.push_back( robust_original(current_robust_ring, - is_interior, has_interiors)); + is_interior, has_interiors, m_envelope_strategy, m_expand_strategy)); } } @@ -1174,7 +1219,7 @@ struct buffered_piece_collection return; } - geometry::envelope(pc.robust_ring, pc.robust_envelope); + geometry::envelope(pc.robust_ring, pc.robust_envelope, m_envelope_strategy); geometry::assign_inverse(pc.robust_offsetted_envelope); for (signed_size_type i = 0; i < pc.offsetted_count; i++) @@ -1400,6 +1445,8 @@ struct buffered_piece_collection inline bool point_coveredby_original(point_type const& point) { + typedef typename IntersectionStrategy::disjoint_point_box_strategy_type d_pb_strategy_type; + robust_point_type any_point; geometry::recalculate(any_point, point, m_robust_policy); @@ -1416,14 +1463,15 @@ struct buffered_piece_collection { robust_original const& original = *it; if (detail::disjoint::disjoint_point_box(any_point, - original.m_box)) + original.m_box, + d_pb_strategy_type())) { continue; } int const geometry_code = detail::within::point_in_geometry(any_point, - original.m_ring); + original.m_ring, point_in_geometry_strategy_type()); if (geometry_code == -1) { diff --git a/boost/geometry/algorithms/detail/buffer/get_piece_turns.hpp b/boost/geometry/algorithms/detail/buffer/get_piece_turns.hpp index 506ff58474..b2af001be2 100644 --- a/boost/geometry/algorithms/detail/buffer/get_piece_turns.hpp +++ b/boost/geometry/algorithms/detail/buffer/get_piece_turns.hpp @@ -3,8 +3,8 @@ // Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland. -// This file was modified by Oracle on 2017. -// Modifications copyright (c) 2017 Oracle and/or its affiliates. +// This file was modified by Oracle on 2017, 2018. +// Modifications copyright (c) 2017-2018 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, @@ -17,6 +17,7 @@ #include <boost/core/ignore_unused.hpp> #include <boost/range.hpp> +#include <boost/geometry/core/assert.hpp> #include <boost/geometry/algorithms/equals.hpp> #include <boost/geometry/algorithms/expand.hpp> #include <boost/geometry/algorithms/detail/disjoint/box_box.hpp> @@ -34,34 +35,81 @@ namespace boost { namespace geometry namespace detail { namespace buffer { - -#if defined(BOOST_GEOMETRY_BUFFER_USE_SIDE_OF_INTERSECTION) -struct buffer_assign_turn +// Implements a unique_sub_range for a buffered piece, +// the range can return subsequent points +// known as "i", "j" and "k" (and further), indexed as 0,1,2,3 +template <typename Ring> +struct unique_sub_range_from_piece { - static bool const include_no_turn = false; - static bool const include_degenerate = false; - static bool const include_opposite = false; - - template - < - typename Info, - typename Point1, - typename Point2, - typename IntersectionInfo - > - static inline void apply(Info& info, - Point1 const& /*p1*/, - Point2 const& /*p2*/, - IntersectionInfo const& iinfo) + typedef typename boost::range_iterator<Ring const>::type iterator_type; + typedef typename geometry::point_type<Ring const>::type point_type; + + unique_sub_range_from_piece(Ring const& ring, + iterator_type iterator_at_i, iterator_type iterator_at_j) + : m_ring(ring) + , m_iterator_at_i(iterator_at_i) + , m_iterator_at_j(iterator_at_j) + , m_point_retrieved(false) + {} + + static inline bool is_first_segment() { return false; } + static inline bool is_last_segment() { return false; } + + static inline std::size_t size() { return 3u; } + + inline point_type const& at(std::size_t index) const { - info.rob_pi = iinfo.rpi(); - info.rob_pj = iinfo.rpj(); - info.rob_qi = iinfo.rqi(); - info.rob_qj = iinfo.rqj(); + BOOST_GEOMETRY_ASSERT(index < size()); + switch (index) + { + case 0 : return *m_iterator_at_i; + case 1 : return *m_iterator_at_j; + case 2 : return get_point_k(); + default : return *m_iterator_at_i; + } + } + +private : + + inline point_type const& get_point_k() const + { + if (! m_point_retrieved) + { + m_iterator_at_k = advance_one(m_iterator_at_j); + m_point_retrieved = true; + } + return *m_iterator_at_k; + } + + inline void circular_advance_one(iterator_type& next) const + { + ++next; + if (next == boost::end(m_ring)) + { + next = boost::begin(m_ring) + 1; + } } + inline iterator_type advance_one(iterator_type it) const + { + iterator_type result = it; + circular_advance_one(result); + + // TODO: we could also use piece-boundaries + // to check if the point equals the last one + while (geometry::equals(*it, *result)) + { + circular_advance_one(result); + } + return result; + } + + Ring const& m_ring; + iterator_type m_iterator_at_i; + iterator_type m_iterator_at_j; + mutable iterator_type m_iterator_at_k; + mutable bool m_point_retrieved; }; -#endif template < @@ -102,29 +150,6 @@ class piece_turn_visitor return ! m_rings[piece1.first_seg_id.multi_index].has_concave; } - template <typename Range, typename Iterator> - inline void move_to_next_point(Range const& range, Iterator& next) const - { - ++next; - if (next == boost::end(range)) - { - next = boost::begin(range) + 1; - } - } - - template <typename Range, typename Iterator> - inline Iterator next_point(Range const& range, Iterator it) const - { - Iterator result = it; - move_to_next_point(range, result); - // TODO: we could use either piece-boundaries, or comparison with - // robust points, to check if the point equals the last one - while(geometry::equals(*it, *result)) - { - move_to_next_point(range, result); - } - return result; - } template <std::size_t Dimension, typename Iterator, typename Box> inline void move_begin_iterator(Iterator& it_begin, Iterator it_beyond, @@ -229,15 +254,19 @@ class piece_turn_visitor the_model.operations[1].piece_index = piece2.index; the_model.operations[1].seg_id = piece2.first_seg_id; the_model.operations[1].seg_id.segment_index = index2; // override + geometry::recalculate(the_model.rob_pi, *prev1, m_robust_policy); + geometry::recalculate(the_model.rob_pj, *it1, m_robust_policy); - iterator next1 = next_point(ring1, it1); + unique_sub_range_from_piece<ring_type> unique_sub_range1(ring1, prev1, it1); iterator it2 = it2_first; for (iterator prev2 = it2++; it2 != it2_beyond; prev2 = it2++, the_model.operations[1].seg_id.segment_index++) { - iterator next2 = next_point(ring2, it2); + unique_sub_range_from_piece<ring_type> unique_sub_range2(ring2, prev2, it2); + geometry::recalculate(the_model.rob_qi, *prev2, m_robust_policy); + geometry::recalculate(the_model.rob_qj, *it2, m_robust_policy); // TODO: internally get_turn_info calculates robust points. // But they are already calculated. @@ -246,20 +275,14 @@ class piece_turn_visitor // and iterating in sync with them... typedef detail::overlay::get_turn_info < -#if defined(BOOST_GEOMETRY_BUFFER_USE_SIDE_OF_INTERSECTION) - buffer_assign_turn -#else detail::overlay::assign_null_policy -#endif > turn_policy; - turn_policy::apply(*prev1, *it1, *next1, - *prev2, *it2, *next2, - false, false, false, false, - the_model, - m_intersection_strategy, - m_robust_policy, - std::back_inserter(m_turns)); + turn_policy::apply(unique_sub_range1, unique_sub_range2, + the_model, + m_intersection_strategy, + m_robust_policy, + std::back_inserter(m_turns)); } } } @@ -292,7 +315,8 @@ public: || is_adjacent(piece1, piece2) || is_on_same_convex_ring(piece1, piece2) || detail::disjoint::disjoint_box_box(section1.bounding_box, - section2.bounding_box) ) + section2.bounding_box, + m_intersection_strategy.get_disjoint_box_box_strategy()) ) { return true; } diff --git a/boost/geometry/algorithms/detail/buffer/turn_in_original_visitor.hpp b/boost/geometry/algorithms/detail/buffer/turn_in_original_visitor.hpp index 70053536fb..5236da1da8 100644 --- a/boost/geometry/algorithms/detail/buffer/turn_in_original_visitor.hpp +++ b/boost/geometry/algorithms/detail/buffer/turn_in_original_visitor.hpp @@ -2,8 +2,8 @@ // Copyright (c) 2014 Barend Gehrels, Amsterdam, the Netherlands. -// This file was modified by Oracle on 2016. -// Modifications copyright (c) 2016 Oracle and/or its affiliates. +// This file was modified by Oracle on 2016, 2018. +// Modifications copyright (c) 2016-2018 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, @@ -16,6 +16,7 @@ #include <boost/core/ignore_unused.hpp> +#include <boost/geometry/algorithms/detail/buffer/buffer_policies.hpp> #include <boost/geometry/algorithms/expand.hpp> #include <boost/geometry/strategies/agnostic/point_in_poly_winding.hpp> #include <boost/geometry/strategies/buffer.hpp> @@ -38,12 +39,14 @@ struct original_get_box } }; +template <typename DisjointBoxBoxStrategy> struct original_ovelaps_box { template <typename Box, typename Original> static inline bool apply(Box const& box, Original const& original) { - return ! detail::disjoint::disjoint_box_box(box, original.m_box); + return ! detail::disjoint::disjoint_box_box(box, original.m_box, + DisjointBoxBoxStrategy()); } }; @@ -56,6 +59,7 @@ struct include_turn_policy } }; +template <typename DisjointPointBoxStrategy> struct turn_in_original_ovelaps_box { template <typename Box, typename Turn> @@ -68,7 +72,7 @@ struct turn_in_original_ovelaps_box } return ! geometry::detail::disjoint::disjoint_point_box( - turn.robust_point, box); + turn.robust_point, box, DisjointPointBoxStrategy()); } }; diff --git a/boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp b/boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp index e066c27f36..5e2258dfce 100644 --- a/boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp +++ b/boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp @@ -3,8 +3,8 @@ // Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland. -// This file was modified by Oracle on 2016. -// Modifications copyright (c) 2016 Oracle and/or its affiliates. +// This file was modified by Oracle on 2016, 2018. +// Modifications copyright (c) 2016-2018 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, @@ -20,6 +20,7 @@ #include <boost/range.hpp> #include <boost/geometry/core/assert.hpp> +#include <boost/geometry/core/config.hpp> #include <boost/geometry/arithmetic/dot_product.hpp> #include <boost/geometry/algorithms/assign.hpp> @@ -34,11 +35,8 @@ #include <boost/geometry/strategies/buffer.hpp> #include <boost/geometry/algorithms/detail/buffer/buffer_policies.hpp> -#if defined(BOOST_GEOMETRY_BUFFER_USE_SIDE_OF_INTERSECTION) #include <boost/geometry/strategies/cartesian/side_of_intersection.hpp> -#else #include <boost/geometry/strategies/agnostic/point_in_poly_winding.hpp> -#endif namespace boost { namespace geometry @@ -58,6 +56,7 @@ struct piece_get_box } }; +template <typename DisjointBoxBoxStrategy> struct piece_ovelaps_box { template <typename Box, typename Piece> @@ -73,7 +72,8 @@ struct piece_ovelaps_box return false; } - return ! geometry::detail::disjoint::disjoint_box_box(box, piece.robust_envelope); + return ! geometry::detail::disjoint::disjoint_box_box(box, piece.robust_envelope, + DisjointBoxBoxStrategy()); } }; @@ -86,12 +86,14 @@ struct turn_get_box } }; +template <typename DisjointPointBoxStrategy> struct turn_ovelaps_box { template <typename Box, typename Turn> static inline bool apply(Box const& box, Turn const& turn) { - return ! geometry::detail::disjoint::disjoint_point_box(turn.robust_point, box); + return ! geometry::detail::disjoint::disjoint_point_box(turn.robust_point, box, + DisjointPointBoxStrategy()); } }; @@ -103,10 +105,8 @@ enum analyse_result analyse_disjoint, analyse_within, analyse_on_original_boundary, - analyse_on_offsetted -#if ! defined(BOOST_GEOMETRY_BUFFER_USE_SIDE_OF_INTERSECTION) - , analyse_near_offsetted -#endif + analyse_on_offsetted, + analyse_near_offsetted }; template <typename Point> @@ -123,85 +123,115 @@ inline bool in_box(Point const& previous, return geometry::covered_by(point, box); } -template <typename Point, typename Turn> -inline analyse_result check_segment(Point const& previous, - Point const& current, Turn const& turn, - bool from_monotonic) -{ +// meta-programming-structure defining if to use side-of-intersection +// (only for cartesian / only necessary with rescaling) +template <typename Tag> +struct use_side_of_intersection {}; -#if defined(BOOST_GEOMETRY_BUFFER_USE_SIDE_OF_INTERSECTION) - typedef geometry::model::referring_segment<Point const> segment_type; - segment_type const p(turn.rob_pi, turn.rob_pj); - segment_type const q(turn.rob_qi, turn.rob_qj); - segment_type const r(previous, current); - int const side = strategy::side::side_of_intersection::apply(p, q, r, - turn.robust_point); +#if defined(BOOST_GEOMETRY_USE_RESCALING) +// With rescaling, let Cartesian use side-of-intersection +template <> +struct use_side_of_intersection<cartesian_tag> { static bool const value = true; }; +#else +template <> +struct use_side_of_intersection<cartesian_tag> { static bool const value = false; }; +#endif - if (side == 0) - { - return analyse_on_offsetted; - } - if (side == -1 && from_monotonic) - { - return analyse_within; - } - if (side == 1 && from_monotonic) - { - return analyse_disjoint; - } - return analyse_continue; +template <> +struct use_side_of_intersection<spherical_tag> { static bool const value = false; }; -#else +template <> +struct use_side_of_intersection<geographic_tag> { static bool const value = false; }; - typedef typename strategy::side::services::default_strategy - < - typename cs_tag<Point>::type - >::type side_strategy; - typedef typename geometry::coordinate_type<Point>::type coordinate_type; - coordinate_type const twice_area - = side_strategy::template side_value - < - coordinate_type, - coordinate_type - >(previous, current, turn.robust_point); +template <bool UseSideOfIntersection> +struct check_segment {}; - if (twice_area == 0) +// Implementation using side-of-intersection +template <> +struct check_segment<true> +{ + template <typename Point, typename Turn> + static inline analyse_result apply(Point const& previous, + Point const& current, Turn const& turn, + bool from_monotonic) { - // Collinear, only on segment if it is covered by its bbox - if (in_box(previous, current, turn.robust_point)) + typedef geometry::model::referring_segment<Point const> segment_type; + segment_type const p(turn.rob_pi, turn.rob_pj); + segment_type const q(turn.rob_qi, turn.rob_qj); + segment_type const r(previous, current); + int const side = strategy::side::side_of_intersection::apply(p, q, r, + turn.robust_point); + + if (side == 0) { return analyse_on_offsetted; } + if (side == -1 && from_monotonic) + { + return analyse_within; + } + if (side == 1 && from_monotonic) + { + return analyse_disjoint; + } + return analyse_continue; } - else if (twice_area < 0) +}; + +template <> +struct check_segment<false> +{ + template <typename Point, typename Turn> + static inline analyse_result apply(Point const& previous, + Point const& current, Turn const& turn, + bool from_monotonic) { - // It is in the triangle right-of the segment where the - // segment is the hypothenusa. Check if it is close - // (within rounding-area) - if (twice_area * twice_area < geometry::comparable_distance(previous, current) - && in_box(previous, current, turn.robust_point)) + typedef typename strategy::side::services::default_strategy + < + typename cs_tag<Point>::type + >::type side_strategy; + + int const side = side_strategy::apply(previous, current, turn.robust_point); + + if (side == 0) + { + // Collinear, only on segment if it is covered by its bbox + if (in_box(previous, current, turn.robust_point)) + { + return analyse_on_offsetted; + } + } + else if (side == -1) { - return analyse_near_offsetted; + // It is in the triangle right-of the segment where the + // segment is the hypothenusa. Check if it is close + // (within rounding-area) + if (in_box(previous, current, turn.robust_point)) + { + return analyse_near_offsetted; + } + else if (from_monotonic) + { + return analyse_within; + } } else if (from_monotonic) { - return analyse_within; + // Left of segment + return analyse_disjoint; } - } - else if (twice_area > 0 && from_monotonic) - { - // Left of segment - return analyse_disjoint; - } - // Not monotonic, on left or right side: continue analysing - return analyse_continue; -#endif -} + // Not monotonic, on left or right side: continue analysing + return analyse_continue; + } +}; +template <bool UseSideOfIntersection> +class analyse_turn_wrt_point_piece {}; -class analyse_turn_wrt_point_piece +template <> +class analyse_turn_wrt_point_piece<true> { public : template <typename Turn, typename Piece> @@ -211,17 +241,9 @@ public : typedef typename Turn::robust_point_type point_type; typedef typename geometry::coordinate_type<point_type>::type coordinate_type; -#if defined(BOOST_GEOMETRY_BUFFER_USE_SIDE_OF_INTERSECTION) typedef geometry::model::referring_segment<point_type const> segment_type; segment_type const p(turn.rob_pi, turn.rob_pj); segment_type const q(turn.rob_qi, turn.rob_qj); -#else - typedef strategy::within::winding<point_type> strategy_type; - - typename strategy_type::state_type state; - strategy_type strategy; - boost::ignore_unused(strategy); -#endif BOOST_GEOMETRY_ASSERT(! piece.sections.empty()); @@ -241,7 +263,6 @@ public : point_type const& previous = piece.robust_ring[i - 1]; point_type const& current = piece.robust_ring[i]; -#if defined(BOOST_GEOMETRY_BUFFER_USE_SIDE_OF_INTERSECTION) // First check if it is in range - if it is not, the // expensive side_of_intersection does not need to be @@ -272,8 +293,51 @@ public : return analyse_on_offsetted; } } -#else - analyse_result code = check_segment(previous, current, turn, false); + } + } + } + + // It is nowhere outside, and not on segment, so it is within + return analyse_within; + } + +}; + +template <> +class analyse_turn_wrt_point_piece<false> +{ +public : + template <typename Turn, typename Piece> + static inline analyse_result apply(Turn const& turn, Piece const& piece) + { + typedef typename Piece::section_type section_type; + typedef typename Turn::robust_point_type point_type; + typedef typename geometry::coordinate_type<point_type>::type coordinate_type; + + typedef strategy::within::winding<point_type> strategy_type; + + typename strategy_type::state_type state; + strategy_type strategy; + + BOOST_GEOMETRY_ASSERT(! piece.sections.empty()); + + coordinate_type const point_x = geometry::get<0>(turn.robust_point); + + for (std::size_t s = 0; s < piece.sections.size(); s++) + { + section_type const& section = piece.sections[s]; + // If point within horizontal range of monotonic section: + if (! section.duplicate + && section.begin_index < section.end_index + && point_x >= geometry::get<min_corner, 0>(section.bounding_box) - 1 + && point_x <= geometry::get<max_corner, 0>(section.bounding_box) + 1) + { + for (signed_size_type i = section.begin_index + 1; i <= section.end_index; i++) + { + point_type const& previous = piece.robust_ring[i - 1]; + point_type const& current = piece.robust_ring[i]; + + analyse_result code = check_segment<false>::apply(previous, current, turn, false); if (code != analyse_continue) { return code; @@ -282,15 +346,10 @@ public : // Get the state (to determine it is within), we don't have // to cover the on-segment case (covered above) strategy.apply(turn.robust_point, previous, current, state); -#endif } } } -#if defined(BOOST_GEOMETRY_BUFFER_USE_SIDE_OF_INTERSECTION) - // It is nowhere outside, and not on segment, so it is within - return analyse_within; -#else int const code = strategy.result(state); if (code == 1) { @@ -303,25 +362,24 @@ public : // Should normally not occur - on-segment is covered return analyse_unknown; -#endif } }; -class analyse_turn_wrt_piece +template <bool UseSideOfIntersection> +struct check_helper_segment {}; + +template <> +struct check_helper_segment<true> { template <typename Point, typename Turn> - static inline analyse_result check_helper_segment(Point const& s1, + static inline analyse_result apply(Point const& s1, Point const& s2, Turn const& turn, -#if defined(BOOST_GEOMETRY_BUFFER_USE_SIDE_OF_INTERSECTION) - bool , // is on original, to be reused -#else bool is_original, -#endif Point const& offsetted) { boost::ignore_unused(offsetted); -#if defined(BOOST_GEOMETRY_BUFFER_USE_SIDE_OF_INTERSECTION) + boost::ignore_unused(is_original); typedef geometry::model::referring_segment<Point const> segment_type; segment_type const p(turn.rob_pi, turn.rob_pj); segment_type const q(turn.rob_qi, turn.rob_qj); @@ -360,7 +418,20 @@ class analyse_turn_wrt_piece // right of segment return analyse_continue; -#else + } + +}; + +template <> +struct check_helper_segment<false> +{ + template <typename Point, typename Turn> + static inline analyse_result apply(Point const& s1, + Point const& s2, Turn const& turn, + bool is_original, + Point const& offsetted) + { + boost::ignore_unused(offsetted); typedef typename strategy::side::services::default_strategy < typename cs_tag<Point>::type @@ -409,9 +480,12 @@ class analyse_turn_wrt_piece // right of segment return analyse_continue; -#endif } +}; +template <bool UseSideOfIntersection> +class analyse_turn_wrt_piece +{ template <typename Turn, typename Piece> static inline analyse_result check_helper_segments(Turn const& turn, Piece const& piece) { @@ -471,7 +545,7 @@ class analyse_turn_wrt_piece // Right side of the piece analyse_result result - = check_helper_segment(points[0], points[1], turn, + = check_helper_segment<UseSideOfIntersection>::apply(points[0], points[1], turn, false, points[0]); if (result != analyse_continue) { @@ -479,7 +553,7 @@ class analyse_turn_wrt_piece } // Left side of the piece - result = check_helper_segment(points[2], points[3], turn, + result = check_helper_segment<UseSideOfIntersection>::apply(points[2], points[3], turn, false, points[3]); if (result != analyse_continue) { @@ -489,7 +563,7 @@ class analyse_turn_wrt_piece if (! comparator(points[1], points[2])) { // Side of the piece at side of original geometry - result = check_helper_segment(points[1], points[2], turn, + result = check_helper_segment<UseSideOfIntersection>::apply(points[1], points[2], turn, true, point); if (result != analyse_continue) { @@ -536,7 +610,7 @@ class analyse_turn_wrt_piece // w.r.t. specified direction, and prev points to a point smaller // We now know if it is inside/outside it_type prev = it - 1; - return check_segment(*prev, *it, turn, true); + return check_segment<UseSideOfIntersection>::apply(*prev, *it, turn, true); } return analyse_continue; } @@ -593,7 +667,7 @@ public : // (on which any side or side-value would return 0) if (! comparator(previous, current)) { - code = check_segment(previous, current, turn, false); + code = check_segment<UseSideOfIntersection>::apply(previous, current, turn, false); if (code != analyse_continue) { return code; @@ -606,45 +680,17 @@ public : }; +// Helper Structure, of which the apply method returns a side value in {-1, 0, 1} +template <bool UseSideOfIntersection> +struct turn_in_piece {}; -template <typename Turns, typename Pieces> -class turn_in_piece_visitor +template <> +struct turn_in_piece<true> { - Turns& m_turns; // because partition is currently operating on const input only - Pieces const& m_pieces; // to check for piece-type - template <typename Operation, typename Piece> - inline bool skip(Operation const& op, Piece const& piece) const - { - if (op.piece_index == piece.index) - { - return true; - } - Piece const& pc = m_pieces[op.piece_index]; - if (pc.left_index == piece.index || pc.right_index == piece.index) - { - if (pc.type == strategy::buffer::buffered_flat_end) - { - // If it is a flat end, don't compare against its neighbor: - // it will always be located on one of the helper segments - return true; - } - if (pc.type == strategy::buffer::buffered_concave) - { - // If it is concave, the same applies: the IP will be - // located on one of the helper segments - return true; - } - } - - return false; - } - -#if defined(BOOST_GEOMETRY_BUFFER_USE_SIDE_OF_INTERSECTION) - // NOTE: this function returns a side value in {-1, 0, 1} +private : template <typename Turn, typename Piece> - static inline int turn_in_convex_piece(Turn const& turn, - Piece const& piece) + static inline int in_convex_piece(Turn const& turn, Piece const& piece) { typedef typename Turn::robust_point_type point_type; typedef typename Piece::piece_robust_ring_type ring_type; @@ -693,14 +739,90 @@ class turn_in_piece_visitor } return 1; // inside } -#endif + +public : + + template <typename Turn, typename Piece, typename Strategy> + static inline int apply(Turn const& turn, Piece const& piece, + Strategy const& strategy) + { + if (piece.is_convex) + { + return in_convex_piece(turn, piece); + } + else + { + // side-of-intersection only supported for convex pieces + // Call point_in_geometry, a performance-bottleneck + // TODO: might be replaced by extending analysing piece + return detail::within::point_in_geometry(turn.robust_point, + piece.robust_ring, strategy); + } + } +}; + +template <> +struct turn_in_piece<false> +{ +public : + + template <typename Turn, typename Piece, typename Strategy> + static inline int apply(Turn const& turn, Piece const& piece, + Strategy const& strategy) + { + return detail::within::point_in_geometry(turn.robust_point, + piece.robust_ring, strategy); + } +}; + +template +< + typename CsTag, + typename Turns, + typename Pieces, + typename PointInGeometryStrategy +> +class turn_in_piece_visitor +{ + Turns& m_turns; // because partition is currently operating on const input only + Pieces const& m_pieces; // to check for piece-type + PointInGeometryStrategy const& m_point_in_geometry_strategy; + + template <typename Operation, typename Piece> + inline bool skip(Operation const& op, Piece const& piece) const + { + if (op.piece_index == piece.index) + { + return true; + } + Piece const& pc = m_pieces[op.piece_index]; + if (pc.left_index == piece.index || pc.right_index == piece.index) + { + if (pc.type == strategy::buffer::buffered_flat_end) + { + // If it is a flat end, don't compare against its neighbor: + // it will always be located on one of the helper segments + return true; + } + if (pc.type == strategy::buffer::buffered_concave) + { + // If it is concave, the same applies: the IP will be + // located on one of the helper segments + return true; + } + } + + return false; + } public: - inline turn_in_piece_visitor(Turns& turns, Pieces const& pieces) + inline turn_in_piece_visitor(Turns& turns, Pieces const& pieces, + PointInGeometryStrategy const& strategy) : m_turns(turns) , m_pieces(pieces) + , m_point_in_geometry_strategy(strategy) {} template <typename Turn, typename Piece> @@ -759,10 +881,13 @@ public: } } + static const bool use_soi = use_side_of_intersection<CsTag>::value; + boost::ignore_unused(use_soi); + analyse_result analyse_code = piece.type == geometry::strategy::buffer::buffered_point - ? analyse_turn_wrt_point_piece::apply(turn, piece) - : analyse_turn_wrt_piece::apply(turn, piece); + ? analyse_turn_wrt_point_piece<use_soi>::apply(turn, piece) + : analyse_turn_wrt_piece<use_soi>::apply(turn, piece); switch(analyse_code) { @@ -777,32 +902,15 @@ public: case analyse_within : mutable_turn.count_within++; return true; -#if ! defined(BOOST_GEOMETRY_BUFFER_USE_SIDE_OF_INTERSECTION) case analyse_near_offsetted : mutable_turn.count_within_near_offsetted++; return true; -#endif default : break; } -#if defined(BOOST_GEOMETRY_BUFFER_USE_SIDE_OF_INTERSECTION) - // We don't know (yet) - int geometry_code = 0; - if (piece.is_convex) - { - geometry_code = turn_in_convex_piece(turn, piece); - } - else - { - - // TODO: this point_in_geometry is a performance-bottleneck here and - // will be replaced completely by extending analyse_piece functionality - geometry_code = detail::within::point_in_geometry(turn.robust_point, piece.robust_ring); - } -#else - int geometry_code = detail::within::point_in_geometry(turn.robust_point, piece.robust_ring); -#endif + int const geometry_code = turn_in_piece<use_soi>::apply(turn, piece, + m_point_in_geometry_strategy); if (geometry_code == 1) { diff --git a/boost/geometry/algorithms/detail/covered_by/implementation.hpp b/boost/geometry/algorithms/detail/covered_by/implementation.hpp index c5a02b9761..b180a3d5a3 100644 --- a/boost/geometry/algorithms/detail/covered_by/implementation.hpp +++ b/boost/geometry/algorithms/detail/covered_by/implementation.hpp @@ -4,8 +4,8 @@ // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. -// This file was modified by Oracle on 2013, 2014, 2017. -// Modifications copyright (c) 2013-2017 Oracle and/or its affiliates. +// This file was modified by Oracle on 2013, 2014, 2017, 2019. +// Modifications copyright (c) 2013-2019 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -36,7 +36,7 @@ struct use_point_in_geometry template <typename Geometry1, typename Geometry2, typename Strategy> static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { - return detail::within::point_in_geometry(geometry1, geometry2, strategy) >= 0; + return detail::within::covered_by_point_geometry(geometry1, geometry2, strategy); } }; diff --git a/boost/geometry/algorithms/detail/covered_by/interface.hpp b/boost/geometry/algorithms/detail/covered_by/interface.hpp index 6599078210..bdc92db43b 100644 --- a/boost/geometry/algorithms/detail/covered_by/interface.hpp +++ b/boost/geometry/algorithms/detail/covered_by/interface.hpp @@ -4,8 +4,8 @@ // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. -// This file was modified by Oracle on 2013, 2014, 2017. -// Modifications copyright (c) 2013-2017 Oracle and/or its affiliates. +// This file was modified by Oracle on 2013, 2014, 2017, 2018. +// Modifications copyright (c) 2013-2018 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -63,13 +63,7 @@ struct covered_by Geometry2 const& geometry2, Strategy const& strategy) { - concepts::within::check - < - typename tag<Geometry1>::type, - typename tag<Geometry2>::type, - typename tag_cast<typename tag<Geometry2>::type, areal_tag>::type, - Strategy - >(); + concepts::within::check<Geometry1, Geometry2, Strategy>(); concepts::check<Geometry1 const>(); concepts::check<Geometry2 const>(); assert_dimension_equal<Geometry1, Geometry2>(); diff --git a/boost/geometry/algorithms/detail/disjoint/areal_areal.hpp b/boost/geometry/algorithms/detail/disjoint/areal_areal.hpp index 664c995384..3fccc74d22 100644 --- a/boost/geometry/algorithms/detail/disjoint/areal_areal.hpp +++ b/boost/geometry/algorithms/detail/disjoint/areal_areal.hpp @@ -5,8 +5,8 @@ // Copyright (c) 2009-2014 Mateusz Loskot, London, UK. // Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland. -// This file was modified by Oracle on 2013-2017. -// Modifications copyright (c) 2013-2017, Oracle and/or its affiliates. +// This file was modified by Oracle on 2013-2019. +// Modifications copyright (c) 2013-2019, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle @@ -28,6 +28,9 @@ #include <boost/geometry/algorithms/detail/point_on_border.hpp> #include <boost/geometry/algorithms/detail/disjoint/linear_linear.hpp> +#include <boost/geometry/algorithms/detail/disjoint/segment_box.hpp> + +#include <boost/geometry/iterators/segment_iterator.hpp> namespace boost { namespace geometry @@ -38,30 +41,15 @@ namespace boost { namespace geometry namespace detail { namespace disjoint { - -template <typename Geometry, typename Tag = typename tag<Geometry>::type> -struct check_each_ring_for_within_call_covered_by +template <typename Geometry1, typename Geometry2, typename Strategy> +inline bool point_on_border_covered_by(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Strategy const& strategy) { - /*! - \tparam Strategy point_in_geometry strategy - */ - template <typename Point, typename Strategy> - static inline bool apply(Point const& p, Geometry const& g, Strategy const& strategy) - { - return geometry::covered_by(p, g, strategy); - } -}; - -template <typename Geometry> -struct check_each_ring_for_within_call_covered_by<Geometry, box_tag> -{ - template <typename Point, typename Strategy> - static inline bool apply(Point const& p, Geometry const& g, Strategy const& ) - { - return geometry::covered_by(p, g); - } -}; - + typename geometry::point_type<Geometry1>::type pt; + return geometry::point_on_border(pt, geometry1) + && geometry::covered_by(pt, geometry2, strategy); +} /*! \tparam Strategy point_in_geometry strategy @@ -83,13 +71,8 @@ struct check_each_ring_for_within template <typename Range> inline void apply(Range const& range) { - typename point_type<Range>::type pt; not_disjoint = not_disjoint - || ( geometry::point_on_border(pt, range) - && check_each_ring_for_within_call_covered_by - < - Geometry - >::apply(pt, m_geometry, m_strategy) ); + || point_on_border_covered_by(range, m_geometry, m_strategy); } }; @@ -113,7 +96,7 @@ inline bool rings_containing(FirstGeometry const& geometry1, template <typename Geometry1, typename Geometry2> -struct general_areal +struct areal_areal { /*! \tparam Strategy relate (segments intersection) strategy @@ -147,6 +130,56 @@ struct general_areal }; +template <typename Areal, typename Box> +struct areal_box +{ + /*! + \tparam Strategy relate (segments intersection) strategy + */ + template <typename Strategy> + static inline bool apply(Areal const& areal, + Box const& box, + Strategy const& strategy) + { + if ( ! for_each_segment(geometry::segments_begin(areal), + geometry::segments_end(areal), + box, + strategy.get_disjoint_segment_box_strategy()) ) + { + return false; + } + + // If there is no intersection of any segment and box, + // the box might be located inside areal geometry + + if ( point_on_border_covered_by(box, areal, + strategy.template get_point_in_geometry_strategy<Box, Areal>()) ) + { + return false; + } + + return true; + } + +private: + template <typename SegIter, typename Strategy> + static inline bool for_each_segment(SegIter first, + SegIter last, + Box const& box, + Strategy const& strategy) + { + for ( ; first != last ; ++first) + { + if (! disjoint_segment_box::apply(*first, box, strategy)) + { + return false; + } + } + return true; + } +}; + + }} // namespace detail::disjoint #endif // DOXYGEN_NO_DETAIL @@ -160,13 +193,13 @@ namespace dispatch template <typename Areal1, typename Areal2> struct disjoint<Areal1, Areal2, 2, areal_tag, areal_tag, false> - : detail::disjoint::general_areal<Areal1, Areal2> + : detail::disjoint::areal_areal<Areal1, Areal2> {}; template <typename Areal, typename Box> struct disjoint<Areal, Box, 2, areal_tag, box_tag, false> - : detail::disjoint::general_areal<Areal, Box> + : detail::disjoint::areal_box<Areal, Box> {}; diff --git a/boost/geometry/algorithms/detail/disjoint/box_box.hpp b/boost/geometry/algorithms/detail/disjoint/box_box.hpp index 87618939b8..67f0633218 100644 --- a/boost/geometry/algorithms/detail/disjoint/box_box.hpp +++ b/boost/geometry/algorithms/detail/disjoint/box_box.hpp @@ -5,8 +5,8 @@ // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // Copyright (c) 2013-2015 Adam Wulkiewicz, Lodz, Poland. -// This file was modified by Oracle on 2013-2017. -// Modifications copyright (c) 2013-2017, Oracle and/or its affiliates. +// This file was modified by Oracle on 2013-2018. +// Modifications copyright (c) 2013-2018, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle @@ -23,139 +23,30 @@ #include <cstddef> -#include <boost/geometry/core/access.hpp> -#include <boost/geometry/core/tags.hpp> - #include <boost/geometry/algorithms/dispatch/disjoint.hpp> -#include <boost/geometry/util/normalize_spheroidal_coordinates.hpp> -#include <boost/geometry/util/select_most_precise.hpp> - +// For backward compatibility +#include <boost/geometry/strategies/cartesian/disjoint_box_box.hpp> +#include <boost/geometry/strategies/spherical/disjoint_box_box.hpp> namespace boost { namespace geometry { + #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace disjoint { -template -< - typename Box1, typename Box2, - std::size_t Dimension = 0, - std::size_t DimensionCount = dimension<Box1>::value, - typename CSTag = typename tag_cast - < - typename cs_tag<Box1>::type, - spherical_tag - >::type -> -struct box_box -{ - template <typename Strategy> - static inline bool apply(Box1 const& box1, Box2 const& box2, Strategy const&) - { - return apply(box1, box2); - } - - static inline bool apply(Box1 const& box1, Box2 const& box2) - { - if (get<max_corner, Dimension>(box1) < get<min_corner, Dimension>(box2)) - { - return true; - } - if (get<min_corner, Dimension>(box1) > get<max_corner, Dimension>(box2)) - { - return true; - } - return box_box - < - Box1, Box2, - Dimension + 1, DimensionCount - >::apply(box1, box2); - } -}; - - -template <typename Box1, typename Box2, std::size_t DimensionCount, typename CSTag> -struct box_box<Box1, Box2, DimensionCount, DimensionCount, CSTag> -{ - static inline bool apply(Box1 const& , Box2 const& ) - { - return false; - } -}; - - -template <typename Box1, typename Box2, std::size_t DimensionCount> -struct box_box<Box1, Box2, 0, DimensionCount, spherical_tag> -{ - template <typename Strategy> - static inline bool apply(Box1 const& box1, Box2 const& box2, Strategy const&) - { - return apply(box1, box2); - } - - static inline bool apply(Box1 const& box1, Box2 const& box2) - { - typedef typename geometry::select_most_precise - < - typename coordinate_type<Box1>::type, - typename coordinate_type<Box2>::type - >::type calc_t; - typedef typename coordinate_system<Box1>::type::units units_t; - typedef math::detail::constants_on_spheroid<calc_t, units_t> constants; - - calc_t const b1_min = get<min_corner, 0>(box1); - calc_t const b1_max = get<max_corner, 0>(box1); - calc_t const b2_min = get<min_corner, 0>(box2); - calc_t const b2_max = get<max_corner, 0>(box2); - - // min <= max <=> diff >= 0 - calc_t const diff1 = b1_max - b1_min; - calc_t const diff2 = b2_max - b2_min; - - // check the intersection if neither box cover the whole globe - if (diff1 < constants::period() && diff2 < constants::period()) - { - // calculate positive longitude translation with b1_min as origin - calc_t const diff_min = math::longitude_distance_unsigned<units_t>(b1_min, b2_min); - calc_t const b2_min_transl = b1_min + diff_min; // always right of b1_min - calc_t b2_max_transl = b2_min_transl - constants::period() + diff2; - - // if the translation is too close then use the original point - // note that math::abs(b2_max_transl - b2_max) takes values very - // close to k*2*constants::period() for k=0,1,2,... - if (math::abs(b2_max_transl - b2_max) < constants::period() / 2) - { - b2_max_transl = b2_max; - } - - if (b2_min_transl > b1_max // b2_min right of b1_max - && b2_max_transl < b1_min) // b2_max left of b1_min - { - return true; - } - } - - return box_box - < - Box1, Box2, - 1, DimensionCount - >::apply(box1, box2); - } -}; - /*! \brief Internal utility function to detect if boxes are disjoint \note Is used from other algorithms, declared separately to avoid circular references */ -template <typename Box1, typename Box2> -inline bool disjoint_box_box(Box1 const& box1, Box2 const& box2) +template <typename Box1, typename Box2, typename Strategy> +inline bool disjoint_box_box(Box1 const& box1, Box2 const& box2, Strategy const&) { - return box_box<Box1, Box2>::apply(box1, box2); + return Strategy::apply(box1, box2); } @@ -170,8 +61,13 @@ namespace dispatch template <typename Box1, typename Box2, std::size_t DimensionCount> struct disjoint<Box1, Box2, DimensionCount, box_tag, box_tag, false> - : detail::disjoint::box_box<Box1, Box2, 0, DimensionCount> -{}; +{ + template <typename Strategy> + static inline bool apply(Box1 const& box1, Box2 const& box2, Strategy const&) + { + return Strategy::apply(box1, box2); + } +}; } // namespace dispatch diff --git a/boost/geometry/algorithms/detail/disjoint/linear_areal.hpp b/boost/geometry/algorithms/detail/disjoint/linear_areal.hpp index e6077d3e7f..55e3fe07fd 100644 --- a/boost/geometry/algorithms/detail/disjoint/linear_areal.hpp +++ b/boost/geometry/algorithms/detail/disjoint/linear_areal.hpp @@ -5,8 +5,8 @@ // Copyright (c) 2009-2014 Mateusz Loskot, London, UK. // Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland. -// This file was modified by Oracle on 2013-2017. -// Modifications copyright (c) 2013-2017, Oracle and/or its affiliates. +// This file was modified by Oracle on 2013-2018. +// Modifications copyright (c) 2013-2018, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle @@ -41,8 +41,9 @@ #include <boost/geometry/algorithms/detail/check_iterator_range.hpp> #include <boost/geometry/algorithms/detail/point_on_border.hpp> -#include <boost/geometry/algorithms/detail/disjoint/multirange_geometry.hpp> +#include <boost/geometry/algorithms/detail/disjoint/linear_linear.hpp> #include <boost/geometry/algorithms/detail/disjoint/linear_segment_or_box.hpp> +#include <boost/geometry/algorithms/detail/disjoint/multirange_geometry.hpp> #include <boost/geometry/algorithms/detail/disjoint/point_box.hpp> #include <boost/geometry/algorithms/detail/disjoint/segment_box.hpp> diff --git a/boost/geometry/algorithms/detail/disjoint/linear_linear.hpp b/boost/geometry/algorithms/detail/disjoint/linear_linear.hpp index 989b8df247..7b830f7d1f 100644 --- a/boost/geometry/algorithms/detail/disjoint/linear_linear.hpp +++ b/boost/geometry/algorithms/detail/disjoint/linear_linear.hpp @@ -93,18 +93,6 @@ struct assign_disjoint_policy static bool const include_no_turn = true; static bool const include_degenerate = true; static bool const include_opposite = true; - - // We don't assign extra info: - template - < - typename Info, - typename Point1, - typename Point2, - typename IntersectionInfo - > - static inline void apply(Info& , Point1 const& , Point2 const&, - IntersectionInfo const&) - {} }; diff --git a/boost/geometry/algorithms/detail/disjoint/multipoint_geometry.hpp b/boost/geometry/algorithms/detail/disjoint/multipoint_geometry.hpp index d7aa9089e3..029d68be5b 100644 --- a/boost/geometry/algorithms/detail/disjoint/multipoint_geometry.hpp +++ b/boost/geometry/algorithms/detail/disjoint/multipoint_geometry.hpp @@ -1,8 +1,8 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014-2017, Oracle and/or its affiliates. // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland. +// Copyright (c) 2014-2018, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -138,13 +138,15 @@ private: EnvelopeStrategy const& m_strategy; }; + template <typename DisjointPointBoxStrategy> struct overlaps_box_point { template <typename Box, typename Point> static inline bool apply(Box const& box, Point const& point) { // The default strategy is enough in this case - return ! detail::disjoint::disjoint_point_box(point, box); + return ! detail::disjoint::disjoint_point_box(point, box, + DisjointPointBoxStrategy()); } }; @@ -225,6 +227,7 @@ public: typedef typename Strategy::envelope_strategy_type envelope_strategy_type; typedef typename Strategy::disjoint_strategy_type disjoint_strategy_type; + typedef typename Strategy::disjoint_point_box_strategy_type disjoint_pb_strategy_type; // TODO: disjoint Segment/Box may be called in partition multiple times // possibly for non-cartesian segments which could be slow. We should consider @@ -236,7 +239,7 @@ public: geometry::model::box<typename point_type<MultiPoint>::type> >::apply(multipoint, segment_range(linear), visitor, expand_box_point(), - overlaps_box_point(), + overlaps_box_point<disjoint_pb_strategy_type>(), expand_box_segment<envelope_strategy_type>(strategy.get_envelope_strategy()), overlaps_box_segment<disjoint_strategy_type>(strategy.get_disjoint_strategy())); @@ -256,8 +259,12 @@ class multi_point_single_geometry { public: template <typename Strategy> - static inline bool apply(MultiPoint const& multi_point, SingleGeometry const& single_geometry, Strategy const& strategy) + static inline bool apply(MultiPoint const& multi_point, + SingleGeometry const& single_geometry, + Strategy const& strategy) { + typedef typename Strategy::disjoint_point_box_strategy_type d_pb_strategy_type; + typedef typename point_type<MultiPoint>::type point1_type; typedef typename point_type<SingleGeometry>::type point2_type; typedef model::box<point2_type> box2_type; @@ -270,7 +277,7 @@ public: for ( iterator it = boost::begin(multi_point) ; it != boost::end(multi_point) ; ++it ) { // The default strategy is enough for Point/Box - if (! detail::disjoint::disjoint_point_box(*it, box2) + if (! detail::disjoint::disjoint_point_box(*it, box2, d_pb_strategy_type()) && ! dispatch::disjoint<point1_type, SingleGeometry>::apply(*it, single_geometry, strategy)) { return false; @@ -310,23 +317,27 @@ private: } }; + template <typename DisjointPointBoxStrategy> struct overlaps_box_point { template <typename Box, typename Point> static inline bool apply(Box const& box, Point const& point) { // The default strategy is enough for Point/Box - return ! detail::disjoint::disjoint_point_box(point, box); + return ! detail::disjoint::disjoint_point_box(point, box, + DisjointPointBoxStrategy()); } }; + template <typename DisjointBoxBoxStrategy> struct overlaps_box_box_pair { template <typename Box, typename BoxPair> inline bool apply(Box const& box, BoxPair const& box_pair) const { // The default strategy is enough for Box/Box - return ! detail::disjoint::disjoint_box_box(box_pair.first, box); + return ! detail::disjoint::disjoint_box_box(box_pair.first, box, + DisjointBoxBoxStrategy()); } }; @@ -344,11 +355,13 @@ private: template <typename Point, typename BoxPair> inline bool apply(Point const& point, BoxPair const& box_pair) { + typedef typename PtSegStrategy::disjoint_point_box_strategy_type d_pb_strategy_type; + typedef typename boost::range_value<MultiGeometry>::type single_type; // The default strategy is enough for Point/Box if (! m_intersection_found - && ! detail::disjoint::disjoint_point_box(point, box_pair.first) + && ! detail::disjoint::disjoint_point_box(point, box_pair.first, d_pb_strategy_type()) && ! dispatch::disjoint<Point, single_type>::apply(point, range::at(m_multi_geometry, box_pair.second), m_strategy)) { m_intersection_found = true; @@ -390,14 +403,23 @@ public: item_visitor_type<Strategy> visitor(multi_geometry, strategy); + typedef overlaps_box_point + < + typename Strategy::disjoint_point_box_strategy_type + > overlaps_box_point_type; + typedef overlaps_box_box_pair + < + typename Strategy::disjoint_box_box_strategy_type + > overlaps_box_box_pair_type; + geometry::partition < box1_type >::apply(multi_point, boxes, visitor, expand_box_point(), - overlaps_box_point(), + overlaps_box_point_type(), expand_box_box_pair(), - overlaps_box_box_pair()); + overlaps_box_box_pair_type()); return ! visitor.intersection_found(); } diff --git a/boost/geometry/algorithms/detail/disjoint/point_box.hpp b/boost/geometry/algorithms/detail/disjoint/point_box.hpp index 2e6773d221..b4c4026467 100644 --- a/boost/geometry/algorithms/detail/disjoint/point_box.hpp +++ b/boost/geometry/algorithms/detail/disjoint/point_box.hpp @@ -5,8 +5,8 @@ // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // Copyright (c) 2013-2015 Adam Wulkiewicz, Lodz, Poland -// This file was modified by Oracle on 2013-2017. -// Modifications copyright (c) 2013-2017, Oracle and/or its affiliates. +// This file was modified by Oracle on 2013-2018. +// Modifications copyright (c) 2013-2018, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle @@ -41,16 +41,11 @@ namespace detail { namespace disjoint /*! \brief Internal utility function to detect if point/box are disjoint */ -template <typename Point, typename Box> -inline bool disjoint_point_box(Point const& point, Box const& box) +template <typename Point, typename Box, typename Strategy> +inline bool disjoint_point_box(Point const& point, Box const& box, Strategy const& ) { - typedef typename strategy::disjoint::services::default_strategy - < - Point, Box - >::type strategy_type; - // ! covered_by(point, box) - return ! strategy_type::apply(point, box); + return ! Strategy::apply(point, box); } diff --git a/boost/geometry/algorithms/detail/disjoint/point_point.hpp b/boost/geometry/algorithms/detail/disjoint/point_point.hpp index 13ac34d718..f91712934b 100644 --- a/boost/geometry/algorithms/detail/disjoint/point_point.hpp +++ b/boost/geometry/algorithms/detail/disjoint/point_point.hpp @@ -5,8 +5,8 @@ // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // Copyright (c) 2013-2015 Adam Wulkiewicz, Lodz, Poland -// This file was modified by Oracle on 2013, 2014, 2015, 2017. -// Modifications copyright (c) 2013-2017, Oracle and/or its affiliates. +// This file was modified by Oracle on 2013, 2014, 2015, 2017, 2018. +// Modifications copyright (c) 2013-2018, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle @@ -23,29 +23,15 @@ #include <cstddef> -#include <boost/type_traits/is_same.hpp> - -#include <boost/geometry/core/access.hpp> -#include <boost/geometry/core/radian_access.hpp> -#include <boost/geometry/core/coordinate_dimension.hpp> -#include <boost/geometry/core/coordinate_system.hpp> -#include <boost/geometry/core/coordinate_type.hpp> -#include <boost/geometry/core/cs.hpp> #include <boost/geometry/core/tags.hpp> -#include <boost/geometry/util/math.hpp> -#include <boost/geometry/util/select_most_precise.hpp> - -#include <boost/geometry/strategies/strategy_transform.hpp> - -#include <boost/geometry/geometries/helper_geometry.hpp> - -#include <boost/geometry/algorithms/transform.hpp> - -#include <boost/geometry/algorithms/detail/normalize.hpp> - #include <boost/geometry/algorithms/dispatch/disjoint.hpp> +// For backward compatibility +#include <boost/geometry/strategies/disjoint.hpp> +#include <boost/geometry/strategies/cartesian/point_in_point.hpp> +#include <boost/geometry/strategies/spherical/point_in_point.hpp> + namespace boost { namespace geometry { @@ -56,169 +42,15 @@ namespace detail { namespace disjoint { -template <std::size_t Dimension, std::size_t DimensionCount> -struct point_point_generic -{ - template <typename Point1, typename Point2, typename Strategy> - static inline bool apply(Point1 const& p1, Point2 const& p2, Strategy const& ) - { - return apply(p1, p2); - } - - template <typename Point1, typename Point2> - static inline bool apply(Point1 const& p1, Point2 const& p2) - { - if (! geometry::math::equals(get<Dimension>(p1), get<Dimension>(p2))) - { - return true; - } - return - point_point_generic<Dimension + 1, DimensionCount>::apply(p1, p2); - } -}; - -template <std::size_t DimensionCount> -struct point_point_generic<DimensionCount, DimensionCount> -{ - template <typename Point1, typename Point2> - static inline bool apply(Point1 const&, Point2 const& ) - { - return false; - } -}; - - -class point_point_on_spheroid -{ -private: - template <typename Point1, typename Point2, bool SameUnits> - struct are_same_points - { - static inline bool apply(Point1 const& point1, Point2 const& point2) - { - typedef typename helper_geometry<Point1>::type helper_point_type1; - typedef typename helper_geometry<Point2>::type helper_point_type2; - - helper_point_type1 point1_normalized - = return_normalized<helper_point_type1>(point1); - helper_point_type2 point2_normalized - = return_normalized<helper_point_type2>(point2); - - return point_point_generic - < - 0, dimension<Point1>::value - >::apply(point1_normalized, point2_normalized); - } - }; - - template <typename Point1, typename Point2> - struct are_same_points<Point1, Point2, false> // points have different units - { - static inline bool apply(Point1 const& point1, Point2 const& point2) - { - typedef typename geometry::select_most_precise - < - typename fp_coordinate_type<Point1>::type, - typename fp_coordinate_type<Point2>::type - >::type calculation_type; - - typename helper_geometry - < - Point1, calculation_type, radian - >::type helper_point1, helper_point2; - - Point1 point1_normalized = return_normalized<Point1>(point1); - Point2 point2_normalized = return_normalized<Point2>(point2); - - geometry::transform(point1_normalized, helper_point1); - geometry::transform(point2_normalized, helper_point2); - - return point_point_generic - < - 0, dimension<Point1>::value - >::apply(helper_point1, helper_point2); - } - }; - -public: - template <typename Point1, typename Point2, typename Strategy> - static inline bool apply(Point1 const& point1, Point2 const& point2, Strategy const& ) - { - return apply(point1, point2); - } - - template <typename Point1, typename Point2> - static inline bool apply(Point1 const& point1, Point2 const& point2) - { - return are_same_points - < - Point1, - Point2, - boost::is_same - < - typename coordinate_system<Point1>::type::units, - typename coordinate_system<Point2>::type::units - >::value - >::apply(point1, point2); - } -}; - - -template -< - typename Point1, typename Point2, - std::size_t Dimension, std::size_t DimensionCount, - typename CSTag1 = typename cs_tag<Point1>::type, - typename CSTag2 = CSTag1 -> -struct point_point - : point_point<Point1, Point2, Dimension, DimensionCount, cartesian_tag> -{}; - -template -< - typename Point1, typename Point2, - std::size_t Dimension, std::size_t DimensionCount -> -struct point_point - < - Point1, Point2, Dimension, DimensionCount, spherical_equatorial_tag - > : point_point_on_spheroid -{}; - -template -< - typename Point1, typename Point2, - std::size_t Dimension, std::size_t DimensionCount -> -struct point_point - < - Point1, Point2, Dimension, DimensionCount, geographic_tag - > : point_point_on_spheroid -{}; - -template -< - typename Point1, typename Point2, - std::size_t Dimension, std::size_t DimensionCount -> -struct point_point<Point1, Point2, Dimension, DimensionCount, cartesian_tag> - : point_point_generic<Dimension, DimensionCount> -{}; - - /*! \brief Internal utility function to detect of points are disjoint \note To avoid circular references */ -template <typename Point1, typename Point2> -inline bool disjoint_point_point(Point1 const& point1, Point2 const& point2) +template <typename Point1, typename Point2, typename Strategy> +inline bool disjoint_point_point(Point1 const& point1, Point2 const& point2, + Strategy const& ) { - return point_point - < - Point1, Point2, - 0, dimension<Point1>::type::value - >::apply(point1, point2); + return ! Strategy::apply(point1, point2); } @@ -226,8 +58,6 @@ inline bool disjoint_point_point(Point1 const& point1, Point2 const& point2) #endif // DOXYGEN_NO_DETAIL - - #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { @@ -235,8 +65,14 @@ namespace dispatch template <typename Point1, typename Point2, std::size_t DimensionCount> struct disjoint<Point1, Point2, DimensionCount, point_tag, point_tag, false> - : detail::disjoint::point_point<Point1, Point2, 0, DimensionCount> -{}; +{ + template <typename Strategy> + static inline bool apply(Point1 const& point1, Point2 const& point2, + Strategy const& ) + { + return ! Strategy::apply(point1, point2); + } +}; } // namespace dispatch diff --git a/boost/geometry/algorithms/detail/disjoint/segment_box.hpp b/boost/geometry/algorithms/detail/disjoint/segment_box.hpp index baa4cf83dd..ea51f6be7a 100644 --- a/boost/geometry/algorithms/detail/disjoint/segment_box.hpp +++ b/boost/geometry/algorithms/detail/disjoint/segment_box.hpp @@ -5,8 +5,8 @@ // Copyright (c) 2009-2014 Mateusz Loskot, London, UK. // Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland. -// This file was modified by Oracle on 2013-2017. -// Modifications copyright (c) 2013-2017, Oracle and/or its affiliates. +// This file was modified by Oracle on 2013-2019. +// Modifications copyright (c) 2013-2019, Oracle and/or its affiliates. // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle @@ -39,6 +39,9 @@ #include <boost/geometry/geometries/box.hpp> +// Temporary, for envelope_segment_impl +#include <boost/geometry/strategies/spherical/envelope_segment.hpp> + namespace boost { namespace geometry { @@ -50,21 +53,6 @@ namespace detail { namespace disjoint template <typename CS_Tag> struct disjoint_segment_box_sphere_or_spheroid { -private: - - template <typename CT> - static inline void swap(CT& lon1, - CT& lat1, - CT& lon2, - CT& lat2) - { - std::swap(lon1, lon2); - std::swap(lat1, lat2); - } - - -public: - struct disjoint_info { enum type @@ -82,26 +70,50 @@ public: operator T () const; }; - template <typename Segment, typename Box, typename Strategy> + template + < + typename Segment, typename Box, + typename AzimuthStrategy, + typename NormalizeStrategy, + typename DisjointPointBoxStrategy, + typename DisjointBoxBoxStrategy + > static inline bool apply(Segment const& segment, Box const& box, - Strategy const& azimuth_strategy) + AzimuthStrategy const& azimuth_strategy, + NormalizeStrategy const& normalize_strategy, + DisjointPointBoxStrategy const& disjoint_point_box_strategy, + DisjointBoxBoxStrategy const& disjoint_box_box_strategy) { typedef typename point_type<Segment>::type segment_point; segment_point vertex; - return (apply(segment, box, azimuth_strategy, vertex) != disjoint_info::intersect); + return apply(segment, box, vertex, + azimuth_strategy, + normalize_strategy, + disjoint_point_box_strategy, + disjoint_box_box_strategy) != disjoint_info::intersect; } - template <typename Segment, typename Box, typename Strategy, typename P> + template + < + typename Segment, typename Box, + typename P, + typename AzimuthStrategy, + typename NormalizeStrategy, + typename DisjointPointBoxStrategy, + typename DisjointBoxBoxStrategy + > static inline disjoint_info apply(Segment const& segment, Box const& box, - Strategy const& azimuth_strategy, - P& vertex) + P& vertex, + AzimuthStrategy const& azimuth_strategy, + NormalizeStrategy const& , + DisjointPointBoxStrategy const& disjoint_point_box_strategy, + DisjointBoxBoxStrategy const& disjoint_box_box_strategy) { assert_dimension_equal<Segment, Box>(); typedef typename point_type<Segment>::type segment_point_type; - typedef typename cs_tag<Segment>::type segment_cs_type; segment_point_type p0, p1; geometry::detail::assign_point_from_index<0>(segment, p0); @@ -113,7 +125,8 @@ public: // Simplest cases first // Case 1: if box contains one of segment's endpoints then they are not disjoint - if (! disjoint_point_box(p0, box) || ! disjoint_point_box(p1, box)) + if ( ! disjoint_point_box(p0, box, disjoint_point_box_strategy) + || ! disjoint_point_box(p1, box, disjoint_point_box_strategy) ) { return disjoint_info::intersect; } @@ -122,10 +135,10 @@ public: typedef typename coordinate_type<segment_point_type>::type CT; - segment_point_type p0_normalized = - geometry::detail::return_normalized<segment_point_type>(p0); - segment_point_type p1_normalized = - geometry::detail::return_normalized<segment_point_type>(p1); + segment_point_type p0_normalized; + NormalizeStrategy::apply(p0, p0_normalized); + segment_point_type p1_normalized; + NormalizeStrategy::apply(p1, p1_normalized); CT lon1 = geometry::get_as_radian<0>(p0_normalized); CT lat1 = geometry::get_as_radian<1>(p0_normalized); @@ -134,38 +147,35 @@ public: if (lon1 > lon2) { - swap(lon1, lat1, lon2, lat2); + std::swap(lon1, lon2); + std::swap(lat1, lat2); } - //Compute alp1 outside envelope and pass it to envelope_segment_impl - //in order for it to be used later in the algorithm - CT alp1; - - azimuth_strategy.apply(lon1, lat1, lon2, lat2, alp1); - geometry::model::box<segment_point_type> box_seg; - geometry::detail::envelope::envelope_segment_impl<segment_cs_type> - ::template apply<geometry::radian>(lon1, lat1, - lon2, lat2, - box_seg, - azimuth_strategy, - alp1); + strategy::envelope::detail::envelope_segment_impl + < + CS_Tag + >::template apply<geometry::radian>(lon1, lat1, + lon2, lat2, + box_seg, + azimuth_strategy); - if (disjoint_box_box(box, box_seg)) + if (disjoint_box_box(box, box_seg, disjoint_box_box_strategy)) { return disjoint_return_value; } // Case 3: test intersection by comparing angles - CT a_b0, a_b1, a_b2, a_b3; + CT alp1, a_b0, a_b1, a_b2, a_b3; CT b_lon_min = geometry::get_as_radian<geometry::min_corner, 0>(box); CT b_lat_min = geometry::get_as_radian<geometry::min_corner, 1>(box); CT b_lon_max = geometry::get_as_radian<geometry::max_corner, 0>(box); CT b_lat_max = geometry::get_as_radian<geometry::max_corner, 1>(box); + azimuth_strategy.apply(lon1, lat1, lon2, lat2, alp1); azimuth_strategy.apply(lon1, lat1, b_lon_min, b_lat_min, a_b0); azimuth_strategy.apply(lon1, lat1, b_lon_max, b_lat_min, a_b1); azimuth_strategy.apply(lon1, lat1, b_lon_min, b_lat_max, a_b2); diff --git a/boost/geometry/algorithms/detail/distance/interface.hpp b/boost/geometry/algorithms/detail/distance/interface.hpp index 4122ecfe17..2338abbeb5 100644 --- a/boost/geometry/algorithms/detail/distance/interface.hpp +++ b/boost/geometry/algorithms/detail/distance/interface.hpp @@ -95,9 +95,10 @@ struct distance namespace resolve_strategy { +template <typename Strategy> struct distance { - template <typename Geometry1, typename Geometry2, typename Strategy> + template <typename Geometry1, typename Geometry2> static inline typename distance_result<Geometry1, Geometry2, Strategy>::type apply(Geometry1 const& geometry1, Geometry2 const& geometry2, @@ -108,7 +109,11 @@ struct distance Geometry1, Geometry2, Strategy >::apply(geometry1, geometry2, strategy); } +}; +template <> +struct distance<default_strategy> +{ template <typename Geometry1, typename Geometry2> static inline typename distance_result<Geometry1, Geometry2, default_strategy>::type @@ -144,8 +149,10 @@ struct distance Geometry2 const& geometry2, Strategy const& strategy) { - return - resolve_strategy::distance::apply(geometry1, geometry2, strategy); + return resolve_strategy::distance + < + Strategy + >::apply(geometry1, geometry2, strategy); } }; diff --git a/boost/geometry/algorithms/detail/distance/point_to_geometry.hpp b/boost/geometry/algorithms/detail/distance/point_to_geometry.hpp index 9596799cb2..f41cf5c764 100644 --- a/boost/geometry/algorithms/detail/distance/point_to_geometry.hpp +++ b/boost/geometry/algorithms/detail/distance/point_to_geometry.hpp @@ -5,10 +5,11 @@ // Copyright (c) 2009-2014 Mateusz Loskot, London, UK. // Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland. -// This file was modified by Oracle on 2014. -// Modifications copyright (c) 2014, Oracle and/or its affiliates. +// This file was modified by Oracle on 2014, 2019. +// Modifications copyright (c) 2014-2019, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. @@ -39,13 +40,12 @@ #include <boost/geometry/strategies/tags.hpp> #include <boost/geometry/algorithms/assign.hpp> -#include <boost/geometry/algorithms/covered_by.hpp> -#include <boost/geometry/algorithms/within.hpp> #include <boost/geometry/algorithms/detail/closest_feature/geometry_to_range.hpp> #include <boost/geometry/algorithms/detail/closest_feature/point_to_range.hpp> #include <boost/geometry/algorithms/detail/distance/is_comparable.hpp> #include <boost/geometry/algorithms/detail/distance/iterator_selector.hpp> +#include <boost/geometry/algorithms/detail/within/point_in_geometry.hpp> #include <boost/geometry/algorithms/dispatch/distance.hpp> @@ -160,7 +160,8 @@ struct point_to_ring Ring const& ring, Strategy const& strategy) { - if (geometry::within(point, ring)) + // TODO: pass strategy + if (within::within_point_geometry(point, ring)) { return return_type(0); } @@ -204,7 +205,8 @@ private: { for (InteriorRingIterator it = first; it != last; ++it) { - if (geometry::within(point, *it)) + // TODO: pass strategy + if (within::within_point_geometry(point, *it)) { // the point is inside a polygon hole, so its distance // to the polygon its distance to the polygon's @@ -233,7 +235,8 @@ public: Polygon const& polygon, Strategy const& strategy) { - if (!geometry::covered_by(point, exterior_ring(polygon))) + // TODO: pass strategy + if (! within::covered_by_point_geometry(point, exterior_ring(polygon))) { // the point is outside the exterior ring, so its distance // to the polygon is its distance to the polygon's exterior ring @@ -330,7 +333,8 @@ struct point_to_multigeometry<Point, MultiPolygon, Strategy, true> MultiPolygon const& multipolygon, Strategy const& strategy) { - if (geometry::covered_by(point, multipolygon)) + // TODO: pass strategy + if (within::covered_by_point_geometry(point, multipolygon)) { return 0; } diff --git a/boost/geometry/algorithms/detail/distance/segment_to_box.hpp b/boost/geometry/algorithms/detail/distance/segment_to_box.hpp index bfe52c7b1b..d88a6699c8 100644 --- a/boost/geometry/algorithms/detail/distance/segment_to_box.hpp +++ b/boost/geometry/algorithms/detail/distance/segment_to_box.hpp @@ -1,15 +1,17 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014-2018 Oracle and/or its affiliates. +// Copyright (c) 2014-2019 Oracle and/or its affiliates. // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Licensed under the Boost Software License version 1.0. // http://www.boost.org/users/license.html #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_SEGMENT_TO_BOX_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_SEGMENT_TO_BOX_HPP + #include <cstddef> #include <functional> @@ -27,26 +29,27 @@ #include <boost/geometry/core/point_type.hpp> #include <boost/geometry/core/tags.hpp> +#include <boost/geometry/algorithms/detail/assign_box_corners.hpp> +#include <boost/geometry/algorithms/detail/assign_indexed_point.hpp> +#include <boost/geometry/algorithms/detail/closest_feature/point_to_range.hpp> +#include <boost/geometry/algorithms/detail/disjoint/segment_box.hpp> +#include <boost/geometry/algorithms/detail/distance/default_strategies.hpp> +#include <boost/geometry/algorithms/detail/distance/is_comparable.hpp> +#include <boost/geometry/algorithms/detail/equals/point_point.hpp> +#include <boost/geometry/algorithms/dispatch/distance.hpp> +#include <boost/geometry/algorithms/not_implemented.hpp> + +#include <boost/geometry/policies/compare.hpp> + #include <boost/geometry/util/calculation_type.hpp> #include <boost/geometry/util/condition.hpp> +#include <boost/geometry/util/has_nan_coordinate.hpp> #include <boost/geometry/util/math.hpp> +#include <boost/geometry/strategies/disjoint.hpp> #include <boost/geometry/strategies/distance.hpp> #include <boost/geometry/strategies/tags.hpp> -#include <boost/geometry/policies/compare.hpp> - -#include <boost/geometry/algorithms/equals.hpp> -#include <boost/geometry/algorithms/intersects.hpp> -#include <boost/geometry/algorithms/not_implemented.hpp> - -#include <boost/geometry/algorithms/detail/assign_box_corners.hpp> -#include <boost/geometry/algorithms/detail/assign_indexed_point.hpp> -#include <boost/geometry/algorithms/detail/distance/default_strategies.hpp> -#include <boost/geometry/algorithms/detail/distance/is_comparable.hpp> - -#include <boost/geometry/algorithms/dispatch/distance.hpp> - namespace boost { namespace geometry { @@ -57,6 +60,20 @@ namespace detail { namespace distance { +// TODO: Take strategy +template <typename Segment, typename Box> +inline bool intersects_segment_box(Segment const& segment, Box const& box) +{ + typedef typename strategy::disjoint::services::default_strategy + < + Segment, Box + >::type strategy_type; + + return ! detail::disjoint::disjoint_segment_box::apply(segment, box, + strategy_type()); +} + + template < typename Segment, @@ -99,7 +116,7 @@ public: Strategy const& strategy, bool check_intersection = true) { - if (check_intersection && geometry::intersects(segment, box)) + if (check_intersection && intersects_segment_box(segment, box)) { return 0; } @@ -214,7 +231,7 @@ public: Strategy const& strategy, bool check_intersection = true) { - if (check_intersection && geometry::intersects(segment, box)) + if (check_intersection && intersects_segment_box(segment, box)) { return 0; } @@ -753,7 +770,8 @@ public: detail::assign_point_from_index<0>(segment, p[0]); detail::assign_point_from_index<1>(segment, p[1]); - if (geometry::equals(p[0], p[1])) + if (detail::equals::equals_point_point(p[0], p[1], + sb_strategy.get_equals_point_point_strategy())) { typedef typename boost::mpl::if_ < diff --git a/boost/geometry/algorithms/detail/envelope/areal.hpp b/boost/geometry/algorithms/detail/envelope/areal.hpp index 034a98c0ae..3c9b5c576c 100644 --- a/boost/geometry/algorithms/detail/envelope/areal.hpp +++ b/boost/geometry/algorithms/detail/envelope/areal.hpp @@ -3,6 +3,7 @@ // Copyright (c) 2018 Oracle and/or its affiliates. // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at @@ -28,7 +29,6 @@ namespace boost { namespace geometry namespace detail { namespace envelope { -template <typename EnvelopePolicy> struct envelope_polygon { template <typename Polygon, typename Box, typename Strategy> @@ -42,13 +42,13 @@ struct envelope_polygon // if the exterior ring is empty, consider the interior rings envelope_multi_range < - EnvelopePolicy + envelope_range >::apply(interior_rings(polygon), mbr, strategy); } else { // otherwise, consider only the exterior ring - EnvelopePolicy::apply(ext_ring, mbr, strategy); + envelope_range::apply(ext_ring, mbr, strategy); } } }; @@ -62,77 +62,21 @@ namespace dispatch { -template <typename Ring, typename CS_Tag> -struct envelope<Ring, ring_tag, CS_Tag> - : detail::envelope::envelope_range -{}; - template <typename Ring> -struct envelope<Ring, ring_tag, spherical_equatorial_tag> - : detail::envelope::envelope_linestring_or_ring_on_spheroid -{}; - -template <typename Ring> -struct envelope<Ring, ring_tag, geographic_tag> - : detail::envelope::envelope_linestring_or_ring_on_spheroid -{}; - - -template <typename Polygon, typename CS_Tag> -struct envelope<Polygon, polygon_tag, CS_Tag> - : detail::envelope::envelope_polygon - < - detail::envelope::envelope_range - > -{}; - -template <typename Polygon> -struct envelope<Polygon, polygon_tag, spherical_equatorial_tag> - : detail::envelope::envelope_polygon - < - detail::envelope::envelope_linestring_or_ring_on_spheroid - > +struct envelope<Ring, ring_tag> + : detail::envelope::envelope_range {}; template <typename Polygon> -struct envelope<Polygon, polygon_tag, geographic_tag> +struct envelope<Polygon, polygon_tag> : detail::envelope::envelope_polygon - < - detail::envelope::envelope_linestring_or_ring_on_spheroid - > -{}; - - -template <typename MultiPolygon, typename CS_Tag> -struct envelope<MultiPolygon, multi_polygon_tag, CS_Tag> - : detail::envelope::envelope_multi_range - < - detail::envelope::envelope_polygon - < - detail::envelope::envelope_range - > - > -{}; - -template <typename MultiPolygon> -struct envelope<MultiPolygon, multi_polygon_tag, spherical_equatorial_tag> - : detail::envelope::envelope_multi_range - < - detail::envelope::envelope_polygon - < - detail::envelope::envelope_linestring_or_ring_on_spheroid - > - > {}; template <typename MultiPolygon> -struct envelope<MultiPolygon, multi_polygon_tag, geographic_tag> +struct envelope<MultiPolygon, multi_polygon_tag> : detail::envelope::envelope_multi_range < detail::envelope::envelope_polygon - < - detail::envelope::envelope_linestring_or_ring_on_spheroid - > > {}; diff --git a/boost/geometry/algorithms/detail/envelope/box.hpp b/boost/geometry/algorithms/detail/envelope/box.hpp index cf039a292a..b085a14b9d 100644 --- a/boost/geometry/algorithms/detail/envelope/box.hpp +++ b/boost/geometry/algorithms/detail/envelope/box.hpp @@ -18,164 +18,34 @@ #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_BOX_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_BOX_HPP -#include <cstddef> -#include <boost/geometry/core/cs.hpp> -#include <boost/geometry/core/coordinate_dimension.hpp> -#include <boost/geometry/core/coordinate_system.hpp> #include <boost/geometry/core/tags.hpp> -#include <boost/geometry/views/detail/indexed_point_view.hpp> - -#include <boost/geometry/algorithms/detail/convert_point_to_point.hpp> -#include <boost/geometry/algorithms/detail/normalize.hpp> -#include <boost/geometry/algorithms/detail/envelope/transform_units.hpp> - -#include <boost/geometry/algorithms/dispatch/envelope.hpp> +// For backward compatibility +#include <boost/geometry/strategies/cartesian/envelope_box.hpp> +#include <boost/geometry/strategies/spherical/envelope_box.hpp> namespace boost { namespace geometry { -#ifndef DOXYGEN_NO_DETAIL -namespace detail { namespace envelope -{ - - -template -< - std::size_t Index, - std::size_t Dimension, - std::size_t DimensionCount -> -struct envelope_indexed_box -{ - template <typename BoxIn, typename BoxOut> - static inline void apply(BoxIn const& box_in, BoxOut& mbr) - { - detail::indexed_point_view<BoxIn const, Index> box_in_corner(box_in); - detail::indexed_point_view<BoxOut, Index> mbr_corner(mbr); - - detail::conversion::point_to_point - < - detail::indexed_point_view<BoxIn const, Index>, - detail::indexed_point_view<BoxOut, Index>, - Dimension, - DimensionCount - >::apply(box_in_corner, mbr_corner); - } -}; -template -< - std::size_t Index, - std::size_t DimensionCount -> -struct envelope_indexed_box_on_spheroid +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch { - template <typename BoxIn, typename BoxOut> - static inline void apply(BoxIn const& box_in, BoxOut& mbr) - { - // transform() does not work with boxes of dimension higher - // than 2; to account for such boxes we transform the min/max - // points of the boxes using the indexed_point_view - detail::indexed_point_view<BoxIn const, Index> box_in_corner(box_in); - detail::indexed_point_view<BoxOut, Index> mbr_corner(mbr); - - // first transform the units - transform_units(box_in_corner, mbr_corner); - - // now transform the remaining coordinates - detail::conversion::point_to_point - < - detail::indexed_point_view<BoxIn const, Index>, - detail::indexed_point_view<BoxOut, Index>, - 2, - DimensionCount - >::apply(box_in_corner, mbr_corner); - } -}; -struct envelope_box +template <typename Box> +struct envelope<Box, box_tag> { template<typename BoxIn, typename BoxOut, typename Strategy> - static inline void apply(BoxIn const& box_in, - BoxOut& mbr, - Strategy const&) + static inline void apply(BoxIn const& box_in, BoxOut& mbr, Strategy const& ) { - envelope_indexed_box - < - min_corner, 0, dimension<BoxIn>::value - >::apply(box_in, mbr); - - envelope_indexed_box - < - max_corner, 0, dimension<BoxIn>::value - >::apply(box_in, mbr); + Strategy::apply(box_in, mbr); } }; -struct envelope_box_on_spheroid -{ - template <typename BoxIn, typename BoxOut, typename Strategy> - static inline void apply(BoxIn const& box_in, - BoxOut& mbr, - Strategy const&) - { - BoxIn box_in_normalized = box_in; - - if (!is_inverse_spheroidal_coordinates(box_in)) - { - box_in_normalized = detail::return_normalized<BoxIn>(box_in); - } - - envelope_indexed_box_on_spheroid - < - min_corner, dimension<BoxIn>::value - >::apply(box_in_normalized, mbr); - - envelope_indexed_box_on_spheroid - < - max_corner, dimension<BoxIn>::value - >::apply(box_in_normalized, mbr); - } -}; - - -}} // namespace detail::envelope -#endif // DOXYGEN_NO_DETAIL - -#ifndef DOXYGEN_NO_DISPATCH -namespace dispatch -{ - - -template <typename Box> -struct envelope<Box, box_tag, cartesian_tag> - : detail::envelope::envelope_box -{}; - - -template <typename Box> -struct envelope<Box, box_tag, spherical_polar_tag> - : detail::envelope::envelope_box_on_spheroid -{}; - - -template <typename Box> -struct envelope<Box, box_tag, spherical_equatorial_tag> - : detail::envelope::envelope_box_on_spheroid -{}; - - -template <typename Box> -struct envelope<Box, box_tag, geographic_tag> - : detail::envelope::envelope_box_on_spheroid -{}; - - } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH diff --git a/boost/geometry/algorithms/detail/envelope/interface.hpp b/boost/geometry/algorithms/detail/envelope/interface.hpp index 8e9c35b395..28c815f4c2 100644 --- a/boost/geometry/algorithms/detail/envelope/interface.hpp +++ b/boost/geometry/algorithms/detail/envelope/interface.hpp @@ -4,8 +4,8 @@ // Copyright (c) 2008-2015 Bruno Lalande, Paris, France. // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. -// This file was modified by Oracle on 2015, 2016, 2017. -// Modifications copyright (c) 2015-2017, Oracle and/or its affiliates. +// This file was modified by Oracle on 2015, 2016, 2017, 2018. +// Modifications copyright (c) 2015-2018, Oracle and/or its affiliates. // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle @@ -21,19 +21,24 @@ #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_INTERFACE_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_INTERFACE_HPP + #include <boost/variant/apply_visitor.hpp> #include <boost/variant/static_visitor.hpp> #include <boost/variant/variant_fwd.hpp> -#include <boost/geometry/geometries/concepts/check.hpp> - #include <boost/geometry/algorithms/dispatch/envelope.hpp> +#include <boost/geometry/core/coordinate_system.hpp> +#include <boost/geometry/core/tag.hpp> +#include <boost/geometry/core/tags.hpp> + +#include <boost/geometry/geometries/concepts/check.hpp> + #include <boost/geometry/strategies/default_strategy.hpp> #include <boost/geometry/strategies/envelope.hpp> -#include <boost/geometry/strategies/cartesian/envelope_segment.hpp> -#include <boost/geometry/strategies/spherical/envelope_segment.hpp> -#include <boost/geometry/strategies/geographic/envelope_segment.hpp> + +#include <boost/geometry/util/select_most_precise.hpp> + namespace boost { namespace geometry { @@ -57,13 +62,15 @@ struct envelope Box& box, default_strategy) { - typedef typename point_type<Geometry>::type point_type; - typedef typename coordinate_type<point_type>::type coordinate_type; - typedef typename strategy::envelope::services::default_strategy < - typename cs_tag<point_type>::type, - coordinate_type + typename tag<Geometry>::type, + typename cs_tag<Geometry>::type, + typename select_most_precise + < + typename coordinate_type<Geometry>::type, + typename coordinate_type<Box>::type + >::type >::type strategy_type; dispatch::envelope<Geometry>::apply(geometry, box, strategy_type()); diff --git a/boost/geometry/algorithms/detail/envelope/linear.hpp b/boost/geometry/algorithms/detail/envelope/linear.hpp index 7fa788b738..e2f05f2e3a 100644 --- a/boost/geometry/algorithms/detail/envelope/linear.hpp +++ b/boost/geometry/algorithms/detail/envelope/linear.hpp @@ -4,11 +4,12 @@ // Copyright (c) 2008-2015 Bruno Lalande, Paris, France. // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. -// This file was modified by Oracle on 2015, 2016. -// Modifications copyright (c) 2015-2016, Oracle and/or its affiliates. +// This file was modified by Oracle on 2015, 2016, 2018. +// Modifications copyright (c) 2015-2018, Oracle and/or its affiliates. // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at @@ -17,92 +18,40 @@ #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_LINEAR_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_LINEAR_HPP -#include <boost/geometry/core/cs.hpp> -#include <boost/geometry/core/tags.hpp> -#include <boost/geometry/iterators/segment_iterator.hpp> +#include <boost/geometry/core/tags.hpp> #include <boost/geometry/algorithms/detail/envelope/range.hpp> #include <boost/geometry/algorithms/dispatch/envelope.hpp> +// For backward compatibility +#include <boost/geometry/strategies/cartesian/envelope.hpp> +#include <boost/geometry/strategies/spherical/envelope.hpp> +#include <boost/geometry/strategies/geographic/envelope.hpp> namespace boost { namespace geometry { -#ifndef DOXYGEN_NO_DETAIL -namespace detail { namespace envelope -{ - -struct envelope_linestring_or_ring_on_spheroid -{ - template <typename LinestringRing, typename Box, typename Strategy> - static inline void apply(LinestringRing const& linestring_or_ring, - Box& mbr, - Strategy const& strategy) - { - envelope_range::apply(geometry::segments_begin(linestring_or_ring), - geometry::segments_end(linestring_or_ring), - mbr, - strategy); - } -}; - - -}} // namespace detail::envelope -#endif // DOXYGEN_NO_DETAIL - - #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { -template <typename Linestring, typename CS_Tag> -struct envelope<Linestring, linestring_tag, CS_Tag> - : detail::envelope::envelope_range -{}; - -template <typename Linestring> -struct envelope<Linestring, linestring_tag, spherical_equatorial_tag> - : detail::envelope::envelope_linestring_or_ring_on_spheroid -{}; - template <typename Linestring> -struct envelope<Linestring, linestring_tag, geographic_tag> - : detail::envelope::envelope_linestring_or_ring_on_spheroid +struct envelope<Linestring, linestring_tag> + : detail::envelope::envelope_range {}; -template <typename MultiLinestring, typename CS_Tag> -struct envelope - < - MultiLinestring, multi_linestring_tag, CS_Tag - > : detail::envelope::envelope_multi_range - < - detail::envelope::envelope_range - > -{}; - template <typename MultiLinestring> -struct envelope - < - MultiLinestring, multi_linestring_tag, spherical_equatorial_tag - > : detail::envelope::envelope_multi_range_on_spheroid +struct envelope<MultiLinestring, multi_linestring_tag> + : detail::envelope::envelope_multi_range < - detail::envelope::envelope_linestring_or_ring_on_spheroid + detail::envelope::envelope_range > {}; -template <typename MultiLinestring> -struct envelope - < - MultiLinestring, multi_linestring_tag, geographic_tag - > : detail::envelope::envelope_multi_range_on_spheroid - < - detail::envelope::envelope_linestring_or_ring_on_spheroid - > -{}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH diff --git a/boost/geometry/algorithms/detail/envelope/multipoint.hpp b/boost/geometry/algorithms/detail/envelope/multipoint.hpp index eef7563796..ce112e4d78 100644 --- a/boost/geometry/algorithms/detail/envelope/multipoint.hpp +++ b/boost/geometry/algorithms/detail/envelope/multipoint.hpp @@ -1,6 +1,6 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2015-2017, Oracle and/or its affiliates. +// Copyright (c) 2015-2018, Oracle and/or its affiliates. // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle @@ -13,361 +13,32 @@ #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_MULTIPOINT_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_MULTIPOINT_HPP -#include <cstddef> -#include <algorithm> -#include <utility> -#include <vector> - -#include <boost/algorithm/minmax_element.hpp> -#include <boost/range.hpp> - -#include <boost/geometry/core/access.hpp> -#include <boost/geometry/core/assert.hpp> -#include <boost/geometry/core/coordinate_system.hpp> -#include <boost/geometry/core/coordinate_type.hpp> #include <boost/geometry/core/tags.hpp> -#include <boost/geometry/util/math.hpp> -#include <boost/geometry/util/range.hpp> - -#include <boost/geometry/geometries/helper_geometry.hpp> - -#include <boost/geometry/algorithms/detail/normalize.hpp> - -#include <boost/geometry/algorithms/detail/envelope/box.hpp> -#include <boost/geometry/algorithms/detail/envelope/initialize.hpp> -#include <boost/geometry/algorithms/detail/envelope/range.hpp> -#include <boost/geometry/algorithms/detail/expand/point.hpp> - #include <boost/geometry/algorithms/dispatch/envelope.hpp> +// For backward compatibility +#include <boost/geometry/strategies/cartesian/envelope_multipoint.hpp> +#include <boost/geometry/strategies/spherical/envelope_multipoint.hpp> namespace boost { namespace geometry { -#ifndef DOXYGEN_NO_DETAIL -namespace detail { namespace envelope -{ - - -class envelope_multipoint_on_spheroid -{ -private: - template <std::size_t Dim> - struct coordinate_less - { - template <typename Point> - inline bool operator()(Point const& point1, Point const& point2) const - { - return math::smaller(geometry::get<Dim>(point1), - geometry::get<Dim>(point2)); - } - }; - - template <typename Constants, typename MultiPoint, typename OutputIterator> - static inline void analyze_point_coordinates(MultiPoint const& multipoint, - bool& has_south_pole, - bool& has_north_pole, - OutputIterator oit) - { - typedef typename boost::range_value<MultiPoint>::type point_type; - typedef typename boost::range_iterator - < - MultiPoint const - >::type iterator_type; - - // analyze point coordinates: - // (1) normalize point coordinates - // (2) check if any point is the north or the south pole - // (3) put all non-pole points in a container - // - // notice that at this point in the algorithm, we have at - // least two points on the spheroid - has_south_pole = false; - has_north_pole = false; - - for (iterator_type it = boost::begin(multipoint); - it != boost::end(multipoint); - ++it) - { - point_type point = detail::return_normalized<point_type>(*it); - - if (math::equals(geometry::get<1>(point), - Constants::min_latitude())) - { - has_south_pole = true; - } - else if (math::equals(geometry::get<1>(point), - Constants::max_latitude())) - { - has_north_pole = true; - } - else - { - *oit++ = point; - } - } - } - - template <typename SortedRange, typename Value> - static inline Value maximum_gap(SortedRange const& sorted_range, - Value& max_gap_left, - Value& max_gap_right) - { - typedef typename boost::range_iterator - < - SortedRange const - >::type iterator_type; - - iterator_type it1 = boost::begin(sorted_range), it2 = it1; - ++it2; - max_gap_left = geometry::get<0>(*it1); - max_gap_right = geometry::get<0>(*it2); - - Value max_gap = max_gap_right - max_gap_left; - for (++it1, ++it2; it2 != boost::end(sorted_range); ++it1, ++it2) - { - Value gap = geometry::get<0>(*it2) - geometry::get<0>(*it1); - if (math::larger(gap, max_gap)) - { - max_gap_left = geometry::get<0>(*it1); - max_gap_right = geometry::get<0>(*it2); - max_gap = gap; - } - } - - return max_gap; - } - - template - < - typename Constants, - typename PointRange, - typename LongitudeLess, - typename CoordinateType - > - static inline void get_min_max_longitudes(PointRange& range, - LongitudeLess const& lon_less, - CoordinateType& lon_min, - CoordinateType& lon_max) - { - typedef typename boost::range_iterator - < - PointRange const - >::type iterator_type; - - // compute min and max longitude values - std::pair<iterator_type, iterator_type> min_max_longitudes - = boost::minmax_element(boost::begin(range), - boost::end(range), - lon_less); - - lon_min = geometry::get<0>(*min_max_longitudes.first); - lon_max = geometry::get<0>(*min_max_longitudes.second); - - // if the longitude span is "large" compute the true maximum gap - if (math::larger(lon_max - lon_min, Constants::half_period())) - { - std::sort(boost::begin(range), boost::end(range), lon_less); - - CoordinateType max_gap_left = 0, max_gap_right = 0; - CoordinateType max_gap - = maximum_gap(range, max_gap_left, max_gap_right); - - CoordinateType complement_gap - = Constants::period() + lon_min - lon_max; - - if (math::larger(max_gap, complement_gap)) - { - lon_min = max_gap_right; - lon_max = max_gap_left + Constants::period(); - } - } - } - - template - < - typename Constants, - typename Iterator, - typename LatitudeLess, - typename CoordinateType - > - static inline void get_min_max_latitudes(Iterator const first, - Iterator const last, - LatitudeLess const& lat_less, - bool has_south_pole, - bool has_north_pole, - CoordinateType& lat_min, - CoordinateType& lat_max) - { - if (has_south_pole && has_north_pole) - { - lat_min = Constants::min_latitude(); - lat_max = Constants::max_latitude(); - } - else if (has_south_pole) - { - lat_min = Constants::min_latitude(); - lat_max - = geometry::get<1>(*std::max_element(first, last, lat_less)); - } - else if (has_north_pole) - { - lat_min - = geometry::get<1>(*std::min_element(first, last, lat_less)); - lat_max = Constants::max_latitude(); - } - else - { - std::pair<Iterator, Iterator> min_max_latitudes - = boost::minmax_element(first, last, lat_less); - - lat_min = geometry::get<1>(*min_max_latitudes.first); - lat_max = geometry::get<1>(*min_max_latitudes.second); - } - } - -public: - template <typename MultiPoint, typename Box, typename Strategy> - static inline void apply(MultiPoint const& multipoint, Box& mbr, Strategy const& strategy) - { - typedef typename point_type<MultiPoint>::type point_type; - typedef typename coordinate_type<MultiPoint>::type coordinate_type; - typedef typename boost::range_iterator - < - MultiPoint const - >::type iterator_type; - - typedef math::detail::constants_on_spheroid - < - coordinate_type, - typename coordinate_system<MultiPoint>::type::units - > constants; - - if (boost::empty(multipoint)) - { - initialize<Box, 0, dimension<Box>::value>::apply(mbr); - return; - } - - initialize<Box, 0, 2>::apply(mbr); - - if (boost::size(multipoint) == 1) - { - return dispatch::envelope - < - typename boost::range_value<MultiPoint>::type - >::apply(range::front(multipoint), mbr, strategy); - } - - // analyze the points and put the non-pole ones in the - // points vector - std::vector<point_type> points; - bool has_north_pole = false, has_south_pole = false; - - analyze_point_coordinates<constants>(multipoint, - has_south_pole, has_north_pole, - std::back_inserter(points)); - - coordinate_type lon_min, lat_min, lon_max, lat_max; - if (points.size() == 1) - { - // we have one non-pole point and at least one pole point - lon_min = geometry::get<0>(range::front(points)); - lon_max = geometry::get<0>(range::front(points)); - lat_min = has_south_pole - ? constants::min_latitude() - : constants::max_latitude(); - lat_max = has_north_pole - ? constants::max_latitude() - : constants::min_latitude(); - } - else if (points.empty()) - { - // all points are pole points - BOOST_GEOMETRY_ASSERT(has_south_pole || has_north_pole); - lon_min = coordinate_type(0); - lon_max = coordinate_type(0); - lat_min = has_south_pole - ? constants::min_latitude() - : constants::max_latitude(); - lat_max = (has_north_pole) - ? constants::max_latitude() - : constants::min_latitude(); - } - else - { - get_min_max_longitudes<constants>(points, - coordinate_less<0>(), - lon_min, - lon_max); - - get_min_max_latitudes<constants>(points.begin(), - points.end(), - coordinate_less<1>(), - has_south_pole, - has_north_pole, - lat_min, - lat_max); - } - - typedef typename helper_geometry - < - Box, - coordinate_type, - typename coordinate_system<MultiPoint>::type::units - >::type helper_box_type; - - helper_box_type helper_mbr; - - geometry::set<min_corner, 0>(helper_mbr, lon_min); - geometry::set<min_corner, 1>(helper_mbr, lat_min); - geometry::set<max_corner, 0>(helper_mbr, lon_max); - geometry::set<max_corner, 1>(helper_mbr, lat_max); - - // now transform to output MBR (per index) - envelope_indexed_box_on_spheroid<min_corner, 2>::apply(helper_mbr, mbr); - envelope_indexed_box_on_spheroid<max_corner, 2>::apply(helper_mbr, mbr); - - // compute envelope for higher coordinates - iterator_type it = boost::begin(multipoint); - envelope_one_point<2, dimension<Box>::value>::apply(*it, mbr, strategy); - - for (++it; it != boost::end(multipoint); ++it) - { - detail::expand::point_loop - < - 2, dimension<Box>::value - >::apply(mbr, *it, strategy); - } - } -}; - - -}} // namespace detail::envelope -#endif // DOXYGEN_NO_DETAIL - - #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { -template <typename MultiPoint, typename CSTag> -struct envelope<MultiPoint, multi_point_tag, CSTag> - : detail::envelope::envelope_range -{}; - -template <typename MultiPoint> -struct envelope<MultiPoint, multi_point_tag, spherical_equatorial_tag> - : detail::envelope::envelope_multipoint_on_spheroid -{}; - template <typename MultiPoint> -struct envelope<MultiPoint, multi_point_tag, geographic_tag> - : detail::envelope::envelope_multipoint_on_spheroid -{}; +struct envelope<MultiPoint, multi_point_tag> +{ + template <typename Box, typename Strategy> + static inline void apply(MultiPoint const& multipoint, Box& mbr, Strategy const& ) + { + Strategy::apply(multipoint, mbr); + } +}; } // namespace dispatch diff --git a/boost/geometry/algorithms/detail/envelope/point.hpp b/boost/geometry/algorithms/detail/envelope/point.hpp index 86e73f3aa3..164274a280 100644 --- a/boost/geometry/algorithms/detail/envelope/point.hpp +++ b/boost/geometry/algorithms/detail/envelope/point.hpp @@ -4,8 +4,8 @@ // Copyright (c) 2008-2015 Bruno Lalande, Paris, France. // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. -// This file was modified by Oracle on 2015, 2016, 2017. -// Modifications copyright (c) 2015-2016, Oracle and/or its affiliates. +// This file was modified by Oracle on 2015, 2016, 2017, 2018. +// Modifications copyright (c) 2015-2018, Oracle and/or its affiliates. // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle @@ -18,23 +18,14 @@ #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_POINT_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_POINT_HPP -#include <cstddef> - -#include <boost/geometry/core/access.hpp> -#include <boost/geometry/core/cs.hpp> -#include <boost/geometry/core/coordinate_dimension.hpp> -#include <boost/geometry/core/coordinate_system.hpp> #include <boost/geometry/core/tags.hpp> -#include <boost/geometry/views/detail/indexed_point_view.hpp> - -#include <boost/geometry/algorithms/detail/convert_point_to_point.hpp> -#include <boost/geometry/algorithms/detail/normalize.hpp> - -#include <boost/geometry/algorithms/detail/envelope/transform_units.hpp> - #include <boost/geometry/algorithms/dispatch/envelope.hpp> +// For backward compatibility +#include <boost/geometry/strategies/cartesian/envelope_point.hpp> +#include <boost/geometry/strategies/spherical/envelope_point.hpp> + namespace boost { namespace geometry { @@ -44,53 +35,12 @@ namespace detail { namespace envelope { -template <std::size_t Dimension, std::size_t DimensionCount> -struct envelope_one_point +struct envelope_point { - template <std::size_t Index, typename Point, typename Box> - static inline void apply(Point const& point, Box& mbr) - { - detail::indexed_point_view<Box, Index> box_corner(mbr); - detail::conversion::point_to_point - < - Point, - detail::indexed_point_view<Box, Index>, - Dimension, - DimensionCount - >::apply(point, box_corner); - } - template <typename Point, typename Box, typename Strategy> - static inline void apply(Point const& point, Box& mbr, Strategy const&) + static inline void apply(Point const& point, Box& mbr, Strategy const& ) { - apply<min_corner>(point, mbr); - apply<max_corner>(point, mbr); - } -}; - - -struct envelope_point_on_spheroid -{ - template<typename Point, typename Box, typename Strategy> - static inline void apply(Point const& point, Box& mbr, Strategy const& strategy) - { - Point normalized_point = detail::return_normalized<Point>(point); - - typename point_type<Box>::type box_point; - - // transform units of input point to units of a box point - transform_units(normalized_point, box_point); - - geometry::set<min_corner, 0>(mbr, geometry::get<0>(box_point)); - geometry::set<min_corner, 1>(mbr, geometry::get<1>(box_point)); - - geometry::set<max_corner, 0>(mbr, geometry::get<0>(box_point)); - geometry::set<max_corner, 1>(mbr, geometry::get<1>(box_point)); - - envelope_one_point - < - 2, dimension<Point>::value - >::apply(normalized_point, mbr, strategy); + Strategy::apply(point, mbr); } }; @@ -104,26 +54,8 @@ namespace dispatch template <typename Point> -struct envelope<Point, point_tag, cartesian_tag> - : detail::envelope::envelope_one_point<0, dimension<Point>::value> -{}; - - -template <typename Point> -struct envelope<Point, point_tag, spherical_polar_tag> - : detail::envelope::envelope_point_on_spheroid -{}; - - -template <typename Point> -struct envelope<Point, point_tag, spherical_equatorial_tag> - : detail::envelope::envelope_point_on_spheroid -{}; - - -template <typename Point> -struct envelope<Point, point_tag, geographic_tag> - : detail::envelope::envelope_point_on_spheroid +struct envelope<Point, point_tag> + : detail::envelope::envelope_point {}; diff --git a/boost/geometry/algorithms/detail/envelope/range.hpp b/boost/geometry/algorithms/detail/envelope/range.hpp index b5591f61ab..2d33600d0f 100644 --- a/boost/geometry/algorithms/detail/envelope/range.hpp +++ b/boost/geometry/algorithms/detail/envelope/range.hpp @@ -4,11 +4,12 @@ // Copyright (c) 2008-2015 Bruno Lalande, Paris, France. // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. -// This file was modified by Oracle on 2015, 2016. -// Modifications copyright (c) 2015-2016, Oracle and/or its affiliates. +// This file was modified by Oracle on 2015, 2016, 2018. +// Modifications copyright (c) 2015-2018, Oracle and/or its affiliates. // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. @@ -23,23 +24,17 @@ #include <iterator> #include <vector> -#include <boost/range.hpp> - -#include <boost/geometry/core/coordinate_dimension.hpp> - -#include <boost/geometry/util/range.hpp> +#include <boost/range/begin.hpp> +#include <boost/range/end.hpp> #include <boost/geometry/algorithms/is_empty.hpp> #include <boost/geometry/algorithms/detail/envelope/initialize.hpp> -#include <boost/geometry/algorithms/detail/envelope/range_of_boxes.hpp> - #include <boost/geometry/algorithms/detail/expand/box.hpp> #include <boost/geometry/algorithms/detail/expand/point.hpp> #include <boost/geometry/algorithms/detail/expand/segment.hpp> -#include <boost/geometry/algorithms/dispatch/envelope.hpp> - +#include <boost/geometry/core/coordinate_dimension.hpp> namespace boost { namespace geometry { @@ -53,7 +48,7 @@ namespace detail { namespace envelope struct envelope_range { template <typename Iterator, typename Box, typename Strategy> - static inline void apply(Iterator first, + static inline void apply(Iterator it, Iterator last, Box& mbr, Strategy const& strategy) @@ -63,16 +58,21 @@ struct envelope_range // initialize MBR initialize<Box, 0, dimension<Box>::value>::apply(mbr); - Iterator it = first; if (it != last) { // initialize box with first element in range - dispatch::envelope<value_type>::apply(*it, mbr, strategy); + dispatch::envelope + < + value_type + >::apply(*it, mbr, strategy.get_element_envelope_strategy()); // consider now the remaining elements in the range (if any) for (++it; it != last; ++it) { - dispatch::expand<Box, value_type>::apply(mbr, *it, strategy); + dispatch::expand + < + Box, value_type + >::apply(mbr, *it, strategy.get_element_expand_strategy()); } } } @@ -80,7 +80,7 @@ struct envelope_range template <typename Range, typename Box, typename Strategy> static inline void apply(Range const& range, Box& mbr, Strategy const& strategy) { - return apply(boost::begin(range), boost::end(range), mbr, strategy); + return apply(Strategy::begin(range), Strategy::end(range), mbr, strategy); } }; @@ -94,86 +94,26 @@ struct envelope_multi_range Box& mbr, Strategy const& strategy) { - typedef typename boost::range_iterator - < - MultiRange const - >::type iterator_type; - - bool initialized = false; - for (iterator_type it = boost::begin(multirange); - it != boost::end(multirange); - ++it) - { - if (! geometry::is_empty(*it)) - { - if (initialized) - { - Box helper_mbr; - EnvelopePolicy::apply(*it, helper_mbr, strategy); - - dispatch::expand<Box, Box>::apply(mbr, helper_mbr, strategy); - } - else - { - // compute the initial envelope - EnvelopePolicy::apply(*it, mbr, strategy); - initialized = true; - } - } - } - - if (! initialized) - { - // if not already initialized, initialize MBR - initialize<Box, 0, dimension<Box>::value>::apply(mbr); - } + apply(boost::begin(multirange), boost::end(multirange), mbr, strategy); } -}; - -// implementation for multi-range on a spheroid (longitude is periodic) -template <typename EnvelopePolicy> -struct envelope_multi_range_on_spheroid -{ - template <typename MultiRange, typename Box, typename Strategy> - static inline void apply(MultiRange const& multirange, + template <typename Iter, typename Box, typename Strategy> + static inline void apply(Iter it, + Iter last, Box& mbr, Strategy const& strategy) { - typedef typename boost::range_iterator - < - MultiRange const - >::type iterator_type; - - // due to the periodicity of longitudes we need to compute the boxes - // of all the single geometries and keep them in a container - std::vector<Box> boxes; - for (iterator_type it = boost::begin(multirange); - it != boost::end(multirange); - ++it) + typename Strategy::template multi_state<Box> state; + for (; it != last; ++it) { if (! geometry::is_empty(*it)) { - Box helper_box; - EnvelopePolicy::apply(*it, helper_box, strategy); - boxes.push_back(helper_box); + Box helper_mbr; + EnvelopePolicy::apply(*it, helper_mbr, strategy); + state.apply(helper_mbr); } } - - // now we need to compute the envelope of the range of boxes - // (cannot be done in an incremental fashion as in the - // Cartesian coordinate system) - // if all single geometries are empty no boxes have been found - // and the MBR is simply initialized - if (! boxes.empty()) - { - envelope_range_of_boxes::apply(boxes, mbr, strategy); - } - else - { - initialize<Box, 0, dimension<Box>::value>::apply(mbr); - } - + state.result(mbr); } }; diff --git a/boost/geometry/algorithms/detail/envelope/range_of_boxes.hpp b/boost/geometry/algorithms/detail/envelope/range_of_boxes.hpp index 92d1fe3959..28e76c4458 100644 --- a/boost/geometry/algorithms/detail/envelope/range_of_boxes.hpp +++ b/boost/geometry/algorithms/detail/envelope/range_of_boxes.hpp @@ -20,17 +20,20 @@ #include <boost/range.hpp> +#include <boost/geometry/algorithms/detail/convert_point_to_point.hpp> +#include <boost/geometry/algorithms/detail/max_interval_gap.hpp> +#include <boost/geometry/algorithms/detail/expand/indexed.hpp> + #include <boost/geometry/core/access.hpp> #include <boost/geometry/core/assert.hpp> #include <boost/geometry/core/coordinate_system.hpp> #include <boost/geometry/core/coordinate_type.hpp> #include <boost/geometry/util/math.hpp> +#include <boost/geometry/util/normalize_spheroidal_coordinates.hpp> #include <boost/geometry/util/range.hpp> -#include <boost/geometry/algorithms/detail/convert_point_to_point.hpp> -#include <boost/geometry/algorithms/detail/max_interval_gap.hpp> -#include <boost/geometry/algorithms/detail/expand/indexed.hpp> +#include <boost/geometry/views/detail/indexed_point_view.hpp> namespace boost { namespace geometry @@ -151,10 +154,8 @@ struct envelope_range_of_longitudes template <std::size_t Dimension, std::size_t DimensionCount> struct envelope_range_of_boxes_by_expansion { - template <typename RangeOfBoxes, typename Box, typename Strategy> - static inline void apply(RangeOfBoxes const& range_of_boxes, - Box& mbr, - Strategy const& strategy) + template <typename RangeOfBoxes, typename Box> + static inline void apply(RangeOfBoxes const& range_of_boxes, Box& mbr) { typedef typename boost::range_value<RangeOfBoxes>::type box_type; @@ -198,14 +199,14 @@ struct envelope_range_of_boxes_by_expansion min_corner, Dimension, DimensionCount - >::apply(mbr, *it, strategy); + >::apply(mbr, *it); detail::expand::indexed_loop < max_corner, Dimension, DimensionCount - >::apply(mbr, *it, strategy); + >::apply(mbr, *it); } } @@ -225,16 +226,14 @@ struct envelope_range_of_boxes } }; - template <typename RangeOfBoxes, typename Box, typename Strategy> - static inline void apply(RangeOfBoxes const& range_of_boxes, - Box& mbr, - Strategy const& strategy) + template <typename RangeOfBoxes, typename Box> + static inline void apply(RangeOfBoxes const& range_of_boxes, Box& mbr) { // boxes in the range are assumed to be normalized already typedef typename boost::range_value<RangeOfBoxes>::type box_type; typedef typename coordinate_type<box_type>::type coordinate_type; - typedef typename coordinate_system<box_type>::type::units units_type; + typedef typename detail::cs_angular_units<box_type>::type units_type; typedef typename boost::range_iterator < RangeOfBoxes const @@ -326,7 +325,7 @@ struct envelope_range_of_boxes envelope_range_of_boxes_by_expansion < 2, dimension<Box>::value - >::apply(range_of_boxes, mbr, strategy); + >::apply(range_of_boxes, mbr); } }; diff --git a/boost/geometry/algorithms/detail/envelope/segment.hpp b/boost/geometry/algorithms/detail/envelope/segment.hpp index cfa139a087..af79f34508 100644 --- a/boost/geometry/algorithms/detail/envelope/segment.hpp +++ b/boost/geometry/algorithms/detail/envelope/segment.hpp @@ -19,33 +19,17 @@ #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_SEGMENT_HPP #include <cstddef> -#include <utility> -#include <boost/core/ignore_unused.hpp> -#include <boost/numeric/conversion/cast.hpp> - -#include <boost/geometry/core/assert.hpp> -#include <boost/geometry/core/coordinate_system.hpp> -#include <boost/geometry/core/coordinate_type.hpp> -#include <boost/geometry/core/cs.hpp> -#include <boost/geometry/core/point_type.hpp> -#include <boost/geometry/core/radian_access.hpp> #include <boost/geometry/core/tags.hpp> -#include <boost/geometry/util/math.hpp> - -#include <boost/geometry/geometries/helper_geometry.hpp> - -#include <boost/geometry/formulas/meridian_segment.hpp> -#include <boost/geometry/formulas/vertex_latitude.hpp> - #include <boost/geometry/algorithms/detail/assign_indexed_point.hpp> -#include <boost/geometry/algorithms/detail/envelope/point.hpp> -#include <boost/geometry/algorithms/detail/envelope/transform_units.hpp> -#include <boost/geometry/algorithms/detail/expand/point.hpp> - #include <boost/geometry/algorithms/dispatch/envelope.hpp> +// For backward compatibility +#include <boost/geometry/strategies/cartesian/envelope_segment.hpp> +#include <boost/geometry/strategies/spherical/envelope_segment.hpp> +#include <boost/geometry/strategies/geographic/envelope_segment.hpp> + namespace boost { namespace geometry { @@ -53,385 +37,6 @@ namespace boost { namespace geometry namespace detail { namespace envelope { -template <typename CalculationType, typename CS_Tag> -struct envelope_segment_call_vertex_latitude -{ - template <typename T1, typename T2, typename Strategy> - static inline CalculationType apply(T1 const& lat1, - T2 const& alp1, - Strategy const& ) - { - return geometry::formula::vertex_latitude<CalculationType, CS_Tag> - ::apply(lat1, alp1); - } -}; - -template <typename CalculationType> -struct envelope_segment_call_vertex_latitude<CalculationType, geographic_tag> -{ - template <typename T1, typename T2, typename Strategy> - static inline CalculationType apply(T1 const& lat1, - T2 const& alp1, - Strategy const& strategy) - { - return geometry::formula::vertex_latitude<CalculationType, geographic_tag> - ::apply(lat1, alp1, strategy.model()); - } -}; - -template <typename Units, typename CS_Tag> -struct envelope_segment_convert_polar -{ - template <typename T> - static inline void pre(T & , T & ) {} - - template <typename T> - static inline void post(T & , T & ) {} -}; - -template <typename Units> -struct envelope_segment_convert_polar<Units, spherical_polar_tag> -{ - template <typename T> - static inline void pre(T & lat1, T & lat2) - { - lat1 = math::latitude_convert_ep<Units>(lat1); - lat2 = math::latitude_convert_ep<Units>(lat2); - } - - template <typename T> - static inline void post(T & lat1, T & lat2) - { - lat1 = math::latitude_convert_ep<Units>(lat1); - lat2 = math::latitude_convert_ep<Units>(lat2); - std::swap(lat1, lat2); - } -}; - -template <typename CS_Tag> -class envelope_segment_impl -{ -private: - - // degrees or radians - template <typename CalculationType> - static inline void swap(CalculationType& lon1, - CalculationType& lat1, - CalculationType& lon2, - CalculationType& lat2) - { - std::swap(lon1, lon2); - std::swap(lat1, lat2); - } - - // radians - template <typename CalculationType> - static inline bool contains_pi_half(CalculationType const& a1, - CalculationType const& a2) - { - // azimuths a1 and a2 are assumed to be in radians - BOOST_GEOMETRY_ASSERT(! math::equals(a1, a2)); - - static CalculationType const pi_half = math::half_pi<CalculationType>(); - - return (a1 < a2) - ? (a1 < pi_half && pi_half < a2) - : (a1 > pi_half && pi_half > a2); - } - - // radians or degrees - template <typename Units, typename CoordinateType> - static inline bool crosses_antimeridian(CoordinateType const& lon1, - CoordinateType const& lon2) - { - typedef math::detail::constants_on_spheroid - < - CoordinateType, Units - > constants; - - return math::abs(lon1 - lon2) > constants::half_period(); // > pi - } - - // degrees or radians - template <typename Units, typename CalculationType, typename Strategy> - static inline void compute_box_corners(CalculationType& lon1, - CalculationType& lat1, - CalculationType& lon2, - CalculationType& lat2, - CalculationType a1, - CalculationType a2, - Strategy const& strategy) - { - // coordinates are assumed to be in radians - BOOST_GEOMETRY_ASSERT(lon1 <= lon2); - boost::ignore_unused(lon1, lon2); - - CalculationType lat1_rad = math::as_radian<Units>(lat1); - CalculationType lat2_rad = math::as_radian<Units>(lat2); - - if (math::equals(a1, a2)) - { - // the segment must lie on the equator or is very short or is meridian - return; - } - - if (lat1 > lat2) - { - std::swap(lat1, lat2); - std::swap(lat1_rad, lat2_rad); - std::swap(a1, a2); - } - - if (contains_pi_half(a1, a2)) - { - CalculationType p_max = envelope_segment_call_vertex_latitude - <CalculationType, CS_Tag>::apply(lat1_rad, a1, strategy); - - CalculationType const mid_lat = lat1 + lat2; - if (mid_lat < 0) - { - // update using min latitude - CalculationType const lat_min_rad = -p_max; - CalculationType const lat_min - = math::from_radian<Units>(lat_min_rad); - - if (lat1 > lat_min) - { - lat1 = lat_min; - } - } - else - { - // update using max latitude - CalculationType const lat_max_rad = p_max; - CalculationType const lat_max - = math::from_radian<Units>(lat_max_rad); - - if (lat2 < lat_max) - { - lat2 = lat_max; - } - } - } - } - - template <typename Units, typename CalculationType> - static inline void special_cases(CalculationType& lon1, - CalculationType& lat1, - CalculationType& lon2, - CalculationType& lat2) - { - typedef math::detail::constants_on_spheroid - < - CalculationType, Units - > constants; - - bool is_pole1 = math::equals(math::abs(lat1), constants::max_latitude()); - bool is_pole2 = math::equals(math::abs(lat2), constants::max_latitude()); - - if (is_pole1 && is_pole2) - { - // both points are poles; nothing more to do: - // longitudes are already normalized to 0 - // but just in case - lon1 = 0; - lon2 = 0; - } - else if (is_pole1 && !is_pole2) - { - // first point is a pole, second point is not: - // make the longitude of the first point the same as that - // of the second point - lon1 = lon2; - } - else if (!is_pole1 && is_pole2) - { - // second point is a pole, first point is not: - // make the longitude of the second point the same as that - // of the first point - lon2 = lon1; - } - - if (lon1 == lon2) - { - // segment lies on a meridian - if (lat1 > lat2) - { - std::swap(lat1, lat2); - } - return; - } - - BOOST_GEOMETRY_ASSERT(!is_pole1 && !is_pole2); - - if (lon1 > lon2) - { - swap(lon1, lat1, lon2, lat2); - } - - if (crosses_antimeridian<Units>(lon1, lon2)) - { - lon1 += constants::period(); - swap(lon1, lat1, lon2, lat2); - } - } - - template - < - typename Units, - typename CalculationType, - typename Box - > - static inline void create_box(CalculationType lon1, - CalculationType lat1, - CalculationType lon2, - CalculationType lat2, - Box& mbr) - { - typedef typename coordinate_type<Box>::type box_coordinate_type; - - typedef typename helper_geometry - < - Box, box_coordinate_type, Units - >::type helper_box_type; - - helper_box_type helper_mbr; - - geometry::set - < - min_corner, 0 - >(helper_mbr, boost::numeric_cast<box_coordinate_type>(lon1)); - - geometry::set - < - min_corner, 1 - >(helper_mbr, boost::numeric_cast<box_coordinate_type>(lat1)); - - geometry::set - < - max_corner, 0 - >(helper_mbr, boost::numeric_cast<box_coordinate_type>(lon2)); - - geometry::set - < - max_corner, 1 - >(helper_mbr, boost::numeric_cast<box_coordinate_type>(lat2)); - - transform_units(helper_mbr, mbr); - } - - - template <typename Units, typename CalculationType, typename Strategy> - static inline void apply(CalculationType& lon1, - CalculationType& lat1, - CalculationType& lon2, - CalculationType& lat2, - Strategy const& strategy) - { - special_cases<Units>(lon1, lat1, lon2, lat2); - - CalculationType lon1_rad = math::as_radian<Units>(lon1); - CalculationType lat1_rad = math::as_radian<Units>(lat1); - CalculationType lon2_rad = math::as_radian<Units>(lon2); - CalculationType lat2_rad = math::as_radian<Units>(lat2); - CalculationType alp1, alp2; - strategy.apply(lon1_rad, lat1_rad, lon2_rad, lat2_rad, alp1, alp2); - - compute_box_corners<Units>(lon1, lat1, lon2, lat2, alp1, alp2, strategy); - } - - template <typename Units, typename CalculationType, typename Strategy> - static inline void apply(CalculationType& lon1, - CalculationType& lat1, - CalculationType& lon2, - CalculationType& lat2, - Strategy const& strategy, - CalculationType alp1) - { - special_cases<Units>(lon1, lat1, lon2, lat2); - - CalculationType lon1_rad = math::as_radian<Units>(lon1); - CalculationType lat1_rad = math::as_radian<Units>(lat1); - CalculationType lon2_rad = math::as_radian<Units>(lon2); - CalculationType lat2_rad = math::as_radian<Units>(lat2); - CalculationType alp2; - strategy.apply_reverse(lon1_rad, lat1_rad, lon2_rad, lat2_rad, alp2); - - compute_box_corners<Units>(lon1, lat1, lon2, lat2, alp1, alp2, strategy); - } - -public: - template - < - typename Units, - typename CalculationType, - typename Box, - typename Strategy - > - static inline void apply(CalculationType lon1, - CalculationType lat1, - CalculationType lon2, - CalculationType lat2, - Box& mbr, - Strategy const& strategy) - { - typedef envelope_segment_convert_polar<Units, typename cs_tag<Box>::type> convert_polar; - - convert_polar::pre(lat1, lat2); - - apply<Units>(lon1, lat1, lon2, lat2, strategy); - - convert_polar::post(lat1, lat2); - - create_box<Units>(lon1, lat1, lon2, lat2, mbr); - } - - template - < - typename Units, - typename CalculationType, - typename Box, - typename Strategy - > - static inline void apply(CalculationType lon1, - CalculationType lat1, - CalculationType lon2, - CalculationType lat2, - Box& mbr, - Strategy const& strategy, - CalculationType alp1) - { - typedef envelope_segment_convert_polar<Units, typename cs_tag<Box>::type> convert_polar; - - convert_polar::pre(lat1, lat2); - - apply<Units>(lon1, lat1, lon2, lat2, strategy, alp1); - - convert_polar::post(lat1, lat2); - - create_box<Units>(lon1, lat1, lon2, lat2, mbr); - } -}; - -template <std::size_t Dimension, std::size_t DimensionCount> -struct envelope_one_segment -{ - template<typename Point, typename Box, typename Strategy> - static inline void apply(Point const& p1, - Point const& p2, - Box& mbr, - Strategy const& strategy) - { - envelope_one_point<Dimension, DimensionCount>::apply(p1, mbr, strategy); - detail::expand::point_loop - < - Dimension, - DimensionCount - >::apply(mbr, p2, strategy); - } -}; - - template <std::size_t DimensionCount> struct envelope_segment { @@ -441,12 +46,7 @@ struct envelope_segment Box& mbr, Strategy const& strategy) { - // first compute the envelope range for the first two coordinates strategy.apply(p1, p2, mbr); - - // now compute the envelope range for coordinates of - // dimension 2 and higher - envelope_one_segment<2, DimensionCount>::apply(p1, p2, mbr, strategy); } template <typename Segment, typename Box, typename Strategy> diff --git a/boost/geometry/algorithms/detail/equals/implementation.hpp b/boost/geometry/algorithms/detail/equals/implementation.hpp index 310059a427..f39ae0b8b7 100644 --- a/boost/geometry/algorithms/detail/equals/implementation.hpp +++ b/boost/geometry/algorithms/detail/equals/implementation.hpp @@ -5,8 +5,8 @@ // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // Copyright (c) 2014-2015 Adam Wulkiewicz, Lodz, Poland. -// This file was modified by Oracle on 2014, 2015, 2016, 2017. -// Modifications copyright (c) 2014-2017 Oracle and/or its affiliates. +// This file was modified by Oracle on 2014, 2015, 2016, 2017, 2018. +// Modifications copyright (c) 2014-2018 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle @@ -64,13 +64,9 @@ template struct point_point { template <typename Point1, typename Point2, typename Strategy> - static inline bool apply(Point1 const& point1, Point2 const& point2, Strategy const& strategy) + static inline bool apply(Point1 const& point1, Point2 const& point2, Strategy const& ) { - return ! detail::disjoint::point_point - < - Point1, Point2, - Dimension, DimensionCount - >::apply(point1, point2, strategy); + return Strategy::apply(point1, point2); } }; @@ -108,20 +104,28 @@ struct box_box<DimensionCount, DimensionCount> struct segment_segment { template <typename Segment1, typename Segment2, typename Strategy> - static inline bool apply(Segment1 const& segment1, Segment2 const& segment2, Strategy const& ) + static inline bool apply(Segment1 const& segment1, Segment2 const& segment2, + Strategy const& strategy) { + typename Strategy::point_in_point_strategy_type const& + pt_pt_strategy = strategy.get_point_in_point_strategy(); + return equals::equals_point_point( indexed_point_view<Segment1 const, 0>(segment1), - indexed_point_view<Segment2 const, 0>(segment2) ) + indexed_point_view<Segment2 const, 0>(segment2), + pt_pt_strategy) ? equals::equals_point_point( indexed_point_view<Segment1 const, 1>(segment1), - indexed_point_view<Segment2 const, 1>(segment2) ) + indexed_point_view<Segment2 const, 1>(segment2), + pt_pt_strategy) : ( equals::equals_point_point( indexed_point_view<Segment1 const, 0>(segment1), - indexed_point_view<Segment2 const, 1>(segment2) ) + indexed_point_view<Segment2 const, 1>(segment2), + pt_pt_strategy) && equals::equals_point_point( indexed_point_view<Segment1 const, 1>(segment1), - indexed_point_view<Segment2 const, 0>(segment2) ) + indexed_point_view<Segment2 const, 0>(segment2), + pt_pt_strategy) ); } }; diff --git a/boost/geometry/algorithms/detail/equals/point_point.hpp b/boost/geometry/algorithms/detail/equals/point_point.hpp index 12daa85e9d..06a784284e 100644 --- a/boost/geometry/algorithms/detail/equals/point_point.hpp +++ b/boost/geometry/algorithms/detail/equals/point_point.hpp @@ -5,8 +5,8 @@ // Copyright (c) 2009-2014 Mateusz Loskot, London, UK. // Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland -// This file was modified by Oracle on 2013-2014. -// Modifications copyright (c) 2013-2014, Oracle and/or its affiliates. +// This file was modified by Oracle on 2013-2018. +// Modifications copyright (c) 2013-2018, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle @@ -21,13 +21,10 @@ #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_EQUALS_POINT_POINT_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_EQUALS_POINT_POINT_HPP -#include <boost/geometry/algorithms/detail/disjoint/point_point.hpp> - namespace boost { namespace geometry { - #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace equals { @@ -36,17 +33,16 @@ namespace detail { namespace equals \brief Internal utility function to detect of points are disjoint \note To avoid circular references */ -template <typename Point1, typename Point2> -inline bool equals_point_point(Point1 const& point1, Point2 const& point2) +template <typename Point1, typename Point2, typename Strategy> +inline bool equals_point_point(Point1 const& point1, Point2 const& point2, + Strategy const& ) { - return ! detail::disjoint::disjoint_point_point(point1, point2); + return Strategy::apply(point1, point2); } - }} // namespace detail::equals #endif // DOXYGEN_NO_DETAIL - }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_EQUALS_POINT_POINT_HPP diff --git a/boost/geometry/algorithms/detail/expand/box.hpp b/boost/geometry/algorithms/detail/expand/box.hpp index 485f4d25e6..41571dba6a 100644 --- a/boost/geometry/algorithms/detail/expand/box.hpp +++ b/boost/geometry/algorithms/detail/expand/box.hpp @@ -5,8 +5,8 @@ // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // Copyright (c) 2014-2015 Samuel Debionne, Grenoble, France. -// This file was modified by Oracle on 2015, 2016, 2017. -// Modifications copyright (c) 2015-2017, Oracle and/or its affiliates. +// This file was modified by Oracle on 2015, 2016, 2017, 2018. +// Modifications copyright (c) 2015-2018, Oracle and/or its affiliates. // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle @@ -19,52 +19,19 @@ #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXPAND_BOX_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXPAND_BOX_HPP -#include <cstddef> -#include <algorithm> -#include <boost/mpl/assert.hpp> -#include <boost/type_traits/is_same.hpp> +#include <boost/geometry/algorithms/dispatch/expand.hpp> -#include <boost/geometry/core/coordinate_dimension.hpp> #include <boost/geometry/core/tags.hpp> -#include <boost/geometry/algorithms/detail/envelope/box.hpp> -#include <boost/geometry/algorithms/detail/envelope/range_of_boxes.hpp> - -#include <boost/geometry/algorithms/detail/expand/indexed.hpp> - -#include <boost/geometry/algorithms/dispatch/expand.hpp> +// For backward compatibility +#include <boost/geometry/strategies/cartesian/expand_box.hpp> +#include <boost/geometry/strategies/spherical/expand_box.hpp> namespace boost { namespace geometry { -#ifndef DOXYGEN_NO_DETAIL -namespace detail { namespace expand -{ - - -struct box_on_spheroid -{ - template <typename BoxOut, typename BoxIn, typename Strategy> - static inline void apply(BoxOut& box_out, - BoxIn const& box_in, - Strategy const& strategy) - { - // normalize both boxes and convert box-in to be of type of box-out - BoxOut mbrs[2]; - detail::envelope::envelope_box_on_spheroid::apply(box_in, mbrs[0], strategy); - detail::envelope::envelope_box_on_spheroid::apply(box_out, mbrs[1], strategy); - - // compute the envelope of the two boxes - detail::envelope::envelope_range_of_boxes::apply(mbrs, box_out, strategy); - } -}; - - -}} // namespace detail::expand -#endif // DOXYGEN_NO_DETAIL - #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { @@ -73,59 +40,23 @@ namespace dispatch // Box + box -> new box containing two input boxes template < - typename BoxOut, typename BoxIn, - typename CSTagOut, typename CSTag + typename BoxOut, typename BoxIn > struct expand < BoxOut, BoxIn, - box_tag, box_tag, - CSTagOut, CSTag + box_tag, box_tag > { - BOOST_MPL_ASSERT_MSG((false), - NOT_IMPLEMENTED_FOR_THESE_COORDINATE_SYSTEMS, - (types<CSTagOut, CSTag>())); + template <typename Strategy> + static inline void apply(BoxOut& box_out, + BoxIn const& box_in, + Strategy const& ) + { + Strategy::apply(box_out, box_in); + } }; -template <typename BoxOut, typename BoxIn> -struct expand - < - BoxOut, BoxIn, - box_tag, box_tag, - cartesian_tag, cartesian_tag - > : detail::expand::expand_indexed - < - 0, dimension<BoxIn>::value - > -{}; - -template <typename BoxOut, typename BoxIn> -struct expand - < - BoxOut, BoxIn, - box_tag, box_tag, - spherical_equatorial_tag, spherical_equatorial_tag - > : detail::expand::box_on_spheroid -{}; - -template <typename BoxOut, typename BoxIn> -struct expand - < - BoxOut, BoxIn, - box_tag, box_tag, - spherical_polar_tag, spherical_polar_tag - > : detail::expand::box_on_spheroid -{}; - -template <typename BoxOut, typename BoxIn> -struct expand - < - BoxOut, BoxIn, - box_tag, box_tag, - geographic_tag, geographic_tag - > : detail::expand::box_on_spheroid -{}; } // namespace dispatch diff --git a/boost/geometry/algorithms/detail/expand/indexed.hpp b/boost/geometry/algorithms/detail/expand/indexed.hpp index fe7ee4f781..08463689de 100644 --- a/boost/geometry/algorithms/detail/expand/indexed.hpp +++ b/boost/geometry/algorithms/detail/expand/indexed.hpp @@ -5,8 +5,8 @@ // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // Copyright (c) 2014-2015 Samuel Debionne, Grenoble, France. -// This file was modified by Oracle on 2015, 2016, 2017. -// Modifications copyright (c) 2015-2017, Oracle and/or its affiliates. +// This file was modified by Oracle on 2015, 2016, 2017, 2018. +// Modifications copyright (c) 2015-2018, Oracle and/or its affiliates. // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle @@ -48,8 +48,8 @@ template > struct indexed_loop { - template <typename Box, typename Geometry, typename Strategy> - static inline void apply(Box& box, Geometry const& source, Strategy const& strategy) + template <typename Box, typename Geometry> + static inline void apply(Box& box, Geometry const& source) { typedef typename select_coordinate_type < @@ -75,7 +75,7 @@ struct indexed_loop indexed_loop < Index, Dimension + 1, DimensionCount - >::apply(box, source, strategy); + >::apply(box, source); } }; @@ -86,8 +86,8 @@ struct indexed_loop Index, DimensionCount, DimensionCount > { - template <typename Box, typename Geometry, typename Strategy> - static inline void apply(Box&, Geometry const&, Strategy const&) {} + template <typename Box, typename Geometry> + static inline void apply(Box&, Geometry const&) {} }; @@ -96,20 +96,18 @@ struct indexed_loop template <std::size_t Dimension, std::size_t DimensionCount> struct expand_indexed { - template <typename Box, typename Geometry, typename Strategy> - static inline void apply(Box& box, - Geometry const& geometry, - Strategy const& strategy) + template <typename Box, typename Geometry> + static inline void apply(Box& box, Geometry const& geometry) { indexed_loop < 0, Dimension, DimensionCount - >::apply(box, geometry, strategy); + >::apply(box, geometry); indexed_loop < 1, Dimension, DimensionCount - >::apply(box, geometry, strategy); + >::apply(box, geometry); } }; diff --git a/boost/geometry/algorithms/detail/expand/interface.hpp b/boost/geometry/algorithms/detail/expand/interface.hpp index 5aacd8e72a..28241b379b 100644 --- a/boost/geometry/algorithms/detail/expand/interface.hpp +++ b/boost/geometry/algorithms/detail/expand/interface.hpp @@ -5,11 +5,12 @@ // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // Copyright (c) 2014-2015 Samuel Debionne, Grenoble, France. -// This file was modified by Oracle on 2015, 2016. -// Modifications copyright (c) 2015-2016, Oracle and/or its affiliates. +// This file was modified by Oracle on 2015, 2016, 2018. +// Modifications copyright (c) 2015-2018, Oracle and/or its affiliates. // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. @@ -25,16 +26,17 @@ #include <boost/variant/static_visitor.hpp> #include <boost/variant/variant_fwd.hpp> +#include <boost/geometry/core/coordinate_system.hpp> +#include <boost/geometry/core/tag.hpp> +#include <boost/geometry/core/tags.hpp> + #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/algorithms/dispatch/expand.hpp> #include <boost/geometry/strategies/default_strategy.hpp> +#include <boost/geometry/strategies/expand.hpp> -#include <boost/geometry/strategies/envelope.hpp> -#include <boost/geometry/strategies/cartesian/envelope_segment.hpp> -#include <boost/geometry/strategies/spherical/envelope_segment.hpp> -#include <boost/geometry/strategies/geographic/envelope_segment.hpp> namespace boost { namespace geometry { @@ -58,14 +60,11 @@ struct expand Geometry const& geometry, default_strategy) { - typedef typename point_type<Geometry>::type point_type; - typedef typename coordinate_type<point_type>::type coordinate_type; - - typedef typename strategy::envelope::services::default_strategy - < - typename cs_tag<point_type>::type, - coordinate_type - >::type strategy_type; + typedef typename strategy::expand::services::default_strategy + < + typename tag<Geometry>::type, + typename cs_tag<Geometry>::type + >::type strategy_type; dispatch::expand<Box, Geometry>::apply(box, geometry, strategy_type()); } diff --git a/boost/geometry/algorithms/detail/expand/point.hpp b/boost/geometry/algorithms/detail/expand/point.hpp index 88ebe75db7..d4a9097cb3 100644 --- a/boost/geometry/algorithms/detail/expand/point.hpp +++ b/boost/geometry/algorithms/detail/expand/point.hpp @@ -22,202 +22,19 @@ #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXPAND_POINT_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXPAND_POINT_HPP -#include <cstddef> -#include <algorithm> -#include <functional> -#include <boost/mpl/assert.hpp> -#include <boost/type_traits/is_same.hpp> +#include <boost/geometry/algorithms/dispatch/expand.hpp> -#include <boost/geometry/core/access.hpp> -#include <boost/geometry/core/coordinate_dimension.hpp> -#include <boost/geometry/core/coordinate_system.hpp> -#include <boost/geometry/core/coordinate_type.hpp> #include <boost/geometry/core/tags.hpp> -#include <boost/geometry/util/is_inverse_spheroidal_coordinates.hpp> -#include <boost/geometry/util/math.hpp> -#include <boost/geometry/util/select_coordinate_type.hpp> - -#include <boost/geometry/algorithms/detail/normalize.hpp> -#include <boost/geometry/algorithms/detail/envelope/transform_units.hpp> +// For backward compatibility +#include <boost/geometry/strategies/cartesian/expand_point.hpp> +#include <boost/geometry/strategies/spherical/expand_point.hpp> -#include <boost/geometry/algorithms/dispatch/expand.hpp> namespace boost { namespace geometry { -#ifndef DOXYGEN_NO_DETAIL -namespace detail { namespace expand -{ - - -template <std::size_t Dimension, std::size_t DimensionCount> -struct point_loop -{ - template <typename Box, typename Point, typename Strategy> - static inline void apply(Box& box, Point const& source, Strategy const& strategy) - { - typedef typename select_coordinate_type - < - Point, Box - >::type coordinate_type; - - std::less<coordinate_type> less; - std::greater<coordinate_type> greater; - - coordinate_type const coord = get<Dimension>(source); - - if (less(coord, get<min_corner, Dimension>(box))) - { - set<min_corner, Dimension>(box, coord); - } - - if (greater(coord, get<max_corner, Dimension>(box))) - { - set<max_corner, Dimension>(box, coord); - } - - point_loop<Dimension + 1, DimensionCount>::apply(box, source, strategy); - } -}; - - -template <std::size_t DimensionCount> -struct point_loop<DimensionCount, DimensionCount> -{ - template <typename Box, typename Point, typename Strategy> - static inline void apply(Box&, Point const&, Strategy const&) {} -}; - - -// implementation for the spherical and geographic coordinate systems -template <std::size_t DimensionCount, bool IsEquatorial = true> -struct point_loop_on_spheroid -{ - template <typename Box, typename Point, typename Strategy> - static inline void apply(Box& box, - Point const& point, - Strategy const& strategy) - { - typedef typename point_type<Box>::type box_point_type; - typedef typename coordinate_type<Box>::type box_coordinate_type; - typedef typename coordinate_system<Box>::type::units units_type; - - typedef math::detail::constants_on_spheroid - < - box_coordinate_type, - units_type - > constants; - - // normalize input point and input box - Point p_normalized = detail::return_normalized<Point>(point); - - // transform input point to be of the same type as the box point - box_point_type box_point; - detail::envelope::transform_units(p_normalized, box_point); - - if (is_inverse_spheroidal_coordinates(box)) - { - geometry::set_from_radian<min_corner, 0>(box, geometry::get_as_radian<0>(p_normalized)); - geometry::set_from_radian<min_corner, 1>(box, geometry::get_as_radian<1>(p_normalized)); - geometry::set_from_radian<max_corner, 0>(box, geometry::get_as_radian<0>(p_normalized)); - geometry::set_from_radian<max_corner, 1>(box, geometry::get_as_radian<1>(p_normalized)); - - } else { - - detail::normalize(box, box); - - box_coordinate_type p_lon = geometry::get<0>(box_point); - box_coordinate_type p_lat = geometry::get<1>(box_point); - - typename coordinate_type<Box>::type - b_lon_min = geometry::get<min_corner, 0>(box), - b_lat_min = geometry::get<min_corner, 1>(box), - b_lon_max = geometry::get<max_corner, 0>(box), - b_lat_max = geometry::get<max_corner, 1>(box); - - if (math::is_latitude_pole<units_type, IsEquatorial>(p_lat)) - { - // the point of expansion is the either the north or the - // south pole; the only important coordinate here is the - // pole's latitude, as the longitude can be anything; - // we, thus, take into account the point's latitude only and return - geometry::set<min_corner, 1>(box, (std::min)(p_lat, b_lat_min)); - geometry::set<max_corner, 1>(box, (std::max)(p_lat, b_lat_max)); - return; - } - - if (math::equals(b_lat_min, b_lat_max) - && math::is_latitude_pole<units_type, IsEquatorial>(b_lat_min)) - { - // the box degenerates to either the north or the south pole; - // the only important coordinate here is the pole's latitude, - // as the longitude can be anything; - // we thus take into account the box's latitude only and return - geometry::set<min_corner, 0>(box, p_lon); - geometry::set<min_corner, 1>(box, (std::min)(p_lat, b_lat_min)); - geometry::set<max_corner, 0>(box, p_lon); - geometry::set<max_corner, 1>(box, (std::max)(p_lat, b_lat_max)); - return; - } - - // update latitudes - b_lat_min = (std::min)(b_lat_min, p_lat); - b_lat_max = (std::max)(b_lat_max, p_lat); - - // update longitudes - if (math::smaller(p_lon, b_lon_min)) - { - box_coordinate_type p_lon_shifted = p_lon + constants::period(); - - if (math::larger(p_lon_shifted, b_lon_max)) - { - // here we could check using: ! math::larger(.., ..) - if (math::smaller(b_lon_min - p_lon, p_lon_shifted - b_lon_max)) - { - b_lon_min = p_lon; - } - else - { - b_lon_max = p_lon_shifted; - } - } - } - else if (math::larger(p_lon, b_lon_max)) - { - // in this case, and since p_lon is normalized in the range - // (-180, 180], we must have that b_lon_max <= 180 - if (b_lon_min < 0 - && math::larger(p_lon - b_lon_max, - constants::period() - p_lon + b_lon_min)) - { - b_lon_min = p_lon; - b_lon_max += constants::period(); - } - else - { - b_lon_max = p_lon; - } - } - - geometry::set<min_corner, 0>(box, b_lon_min); - geometry::set<min_corner, 1>(box, b_lat_min); - geometry::set<max_corner, 0>(box, b_lon_max); - geometry::set<max_corner, 1>(box, b_lat_max); - } - - point_loop - < - 2, DimensionCount - >::apply(box, point, strategy); - } -}; - - -}} // namespace detail::expand -#endif // DOXYGEN_NO_DETAIL - #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { @@ -226,74 +43,24 @@ namespace dispatch // Box + point -> new box containing also point template < - typename BoxOut, typename Point, - typename CSTagOut, typename CSTag + typename BoxOut, typename Point > struct expand < BoxOut, Point, - box_tag, point_tag, - CSTagOut, CSTag + box_tag, point_tag > { - BOOST_MPL_ASSERT_MSG((false), - NOT_IMPLEMENTED_FOR_THESE_COORDINATE_SYSTEMS, - (types<CSTagOut, CSTag>())); + template <typename Strategy> + static inline void apply(BoxOut& box, + Point const& point, + Strategy const& ) + { + Strategy::apply(box, point); + } }; -template <typename BoxOut, typename Point> -struct expand - < - BoxOut, Point, - box_tag, point_tag, - cartesian_tag, cartesian_tag - > : detail::expand::point_loop - < - 0, dimension<Point>::value - > -{}; - -template <typename BoxOut, typename Point> -struct expand - < - BoxOut, Point, - box_tag, point_tag, - spherical_equatorial_tag, spherical_equatorial_tag - > : detail::expand::point_loop_on_spheroid - < - dimension<Point>::value - > -{}; - -template <typename BoxOut, typename Point> -struct expand - < - BoxOut, Point, - box_tag, point_tag, - spherical_polar_tag, spherical_polar_tag - > : detail::expand::point_loop_on_spheroid - < - dimension<Point>::value, - false - > -{}; - -template -< - typename BoxOut, typename Point -> -struct expand - < - BoxOut, Point, - box_tag, point_tag, - geographic_tag, geographic_tag - > : detail::expand::point_loop_on_spheroid - < - dimension<Point>::value - > -{}; - } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH diff --git a/boost/geometry/algorithms/detail/expand/segment.hpp b/boost/geometry/algorithms/detail/expand/segment.hpp index dddd3d2c7a..3f6f196026 100644 --- a/boost/geometry/algorithms/detail/expand/segment.hpp +++ b/boost/geometry/algorithms/detail/expand/segment.hpp @@ -5,8 +5,8 @@ // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // Copyright (c) 2014-2015 Samuel Debionne, Grenoble, France. -// This file was modified by Oracle on 2015, 2016, 2017. -// Modifications copyright (c) 2015-2017, Oracle and/or its affiliates. +// This file was modified by Oracle on 2015, 2016, 2017, 2018. +// Modifications copyright (c) 2015-2018, Oracle and/or its affiliates. // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle @@ -19,57 +19,21 @@ #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXPAND_SEGMENT_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXPAND_SEGMENT_HPP -#include <boost/mpl/assert.hpp> -#include <boost/type_traits/is_same.hpp> -#include <boost/geometry/core/coordinate_dimension.hpp> -#include <boost/geometry/core/tags.hpp> - -#include <boost/geometry/algorithms/detail/envelope/box.hpp> -#include <boost/geometry/algorithms/detail/envelope/range_of_boxes.hpp> -#include <boost/geometry/algorithms/detail/envelope/segment.hpp> - -#include <boost/geometry/algorithms/detail/expand/indexed.hpp> +#include <boost/core/ignore_unused.hpp> #include <boost/geometry/algorithms/dispatch/expand.hpp> +#include <boost/geometry/core/tags.hpp> -namespace boost { namespace geometry -{ +// For backward compatibility +#include <boost/geometry/strategies/cartesian/expand_segment.hpp> +#include <boost/geometry/strategies/geographic/expand_segment.hpp> +#include <boost/geometry/strategies/spherical/expand_segment.hpp> -#ifndef DOXYGEN_NO_DETAIL -namespace detail { namespace expand -{ -struct segment +namespace boost { namespace geometry { - template <typename Box, typename Segment, typename Strategy> - static inline void apply(Box& box, - Segment const& segment, - Strategy const& strategy) - { - Box mbrs[2]; - - // compute the envelope of the segment - typename point_type<Segment>::type p[2]; - detail::assign_point_from_index<0>(segment, p[0]); - detail::assign_point_from_index<1>(segment, p[1]); - detail::envelope::envelope_segment - < - dimension<Segment>::value - >::apply(p[0], p[1], mbrs[0], strategy); - - // normalize the box - detail::envelope::envelope_box_on_spheroid::apply(box, mbrs[1], strategy); - - // compute the envelope of the two boxes - detail::envelope::envelope_range_of_boxes::apply(mbrs, box, strategy); - } -}; - - -}} // namespace detail::expand -#endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch @@ -77,62 +41,24 @@ namespace dispatch template < - typename Box, typename Segment, - typename CSTagOut, typename CSTag + typename Box, typename Segment > struct expand < Box, Segment, - box_tag, segment_tag, - CSTagOut, CSTag + box_tag, segment_tag > { - BOOST_MPL_ASSERT_MSG((false), - NOT_IMPLEMENTED_FOR_THESE_COORDINATE_SYSTEMS, - (types<CSTagOut, CSTag>())); + template <typename Strategy> + static inline void apply(Box& box, + Segment const& segment, + Strategy const& strategy) + { + boost::ignore_unused(strategy); + strategy.apply(box, segment); + } }; -template -< - typename Box, typename Segment -> -struct expand - < - Box, Segment, - box_tag, segment_tag, - cartesian_tag, cartesian_tag - > : detail::expand::expand_indexed - < - 0, dimension<Segment>::value - > -{}; - -template <typename Box, typename Segment> -struct expand - < - Box, Segment, - box_tag, segment_tag, - spherical_polar_tag, spherical_polar_tag - > : detail::expand::segment -{}; - -template <typename Box, typename Segment> -struct expand - < - Box, Segment, - box_tag, segment_tag, - spherical_equatorial_tag, spherical_equatorial_tag - > : detail::expand::segment -{}; - -template <typename Box, typename Segment> -struct expand - < - Box, Segment, - box_tag, segment_tag, - geographic_tag, geographic_tag - > : detail::expand::segment -{}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH diff --git a/boost/geometry/algorithms/detail/extreme_points.hpp b/boost/geometry/algorithms/detail/extreme_points.hpp index 607997813c..842c441f41 100644 --- a/boost/geometry/algorithms/detail/extreme_points.hpp +++ b/boost/geometry/algorithms/detail/extreme_points.hpp @@ -5,8 +5,8 @@ // Copyright (c) 2009-2013 Mateusz Loskot, London, UK. // Copyright (c) 2013-2017 Adam Wulkiewicz, Lodz, Poland. -// This file was modified by Oracle on 2017. -// Modifications copyright (c) 2017 Oracle and/or its affiliates. +// This file was modified by Oracle on 2017, 2018. +// Modifications copyright (c) 2017-2018 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -25,6 +25,7 @@ #include <boost/geometry/algorithms/detail/interior_iterator.hpp> #include <boost/geometry/core/cs.hpp> +#include <boost/geometry/core/point_order.hpp> #include <boost/geometry/core/point_type.hpp> #include <boost/geometry/core/ring_type.hpp> #include <boost/geometry/core/tags.hpp> diff --git a/boost/geometry/algorithms/detail/get_left_turns.hpp b/boost/geometry/algorithms/detail/get_left_turns.hpp index e9f6a50859..1fec47a01f 100644 --- a/boost/geometry/algorithms/detail/get_left_turns.hpp +++ b/boost/geometry/algorithms/detail/get_left_turns.hpp @@ -2,8 +2,8 @@ // Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands. -// This file was modified by Oracle on 2017. -// Modifications copyright (c) 2017, Oracle and/or its affiliates. +// This file was modified by Oracle on 2017, 2018. +// Modifications copyright (c) 2017-2018, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -14,11 +14,14 @@ #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_GET_LEFT_TURNS_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_GET_LEFT_TURNS_HPP +#include <set> +#include <vector> + #include <boost/geometry/core/assert.hpp> -#include <boost/geometry/arithmetic/arithmetic.hpp> #include <boost/geometry/algorithms/detail/overlay/segment_identifier.hpp> #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp> +#include <boost/geometry/arithmetic/arithmetic.hpp> #include <boost/geometry/iterators/closing_iterator.hpp> #include <boost/geometry/iterators/ever_circling_iterator.hpp> #include <boost/geometry/strategies/side.hpp> diff --git a/boost/geometry/algorithms/detail/get_max_size.hpp b/boost/geometry/algorithms/detail/get_max_size.hpp index 8ac43e78b8..f4741824a7 100644 --- a/boost/geometry/algorithms/detail/get_max_size.hpp +++ b/boost/geometry/algorithms/detail/get_max_size.hpp @@ -5,6 +5,11 @@ // Copyright (c) 2014 Mateusz Loskot, London, UK. // Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland. +// This file was modified by Oracle on 2018. +// Modifications copyright (c) 2018, Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + // 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) @@ -12,10 +17,10 @@ #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_GET_MAX_SIZE_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_GET_MAX_SIZE_HPP - #include <cstddef> #include <boost/geometry/core/access.hpp> +#include <boost/geometry/core/coordinate_dimension.hpp> #include <boost/geometry/util/math.hpp> namespace boost { namespace geometry diff --git a/boost/geometry/algorithms/detail/is_valid/complement_graph.hpp b/boost/geometry/algorithms/detail/is_valid/complement_graph.hpp index f08e70242c..1d3bda191a 100644 --- a/boost/geometry/algorithms/detail/is_valid/complement_graph.hpp +++ b/boost/geometry/algorithms/detail/is_valid/complement_graph.hpp @@ -1,8 +1,9 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014, Oracle and/or its affiliates. +// Copyright (c) 2014, 2018, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Licensed under the Boost Software License version 1.0. // http://www.boost.org/users/license.html @@ -19,6 +20,7 @@ #include <boost/core/addressof.hpp> +#include <boost/geometry/algorithms/detail/signed_size_type.hpp> #include <boost/geometry/core/assert.hpp> #include <boost/geometry/policies/compare.hpp> @@ -221,9 +223,11 @@ public: return false; } +#ifdef BOOST_GEOMETRY_TEST_DEBUG template <typename OStream, typename TP> friend inline void debug_print_complement_graph(OStream&, complement_graph<TP> const&); +#endif // BOOST_GEOMETRY_TEST_DEBUG private: std::size_t m_num_rings, m_num_turns; diff --git a/boost/geometry/algorithms/detail/is_valid/debug_complement_graph.hpp b/boost/geometry/algorithms/detail/is_valid/debug_complement_graph.hpp index 60f597e296..749dd3fc25 100644 --- a/boost/geometry/algorithms/detail/is_valid/debug_complement_graph.hpp +++ b/boost/geometry/algorithms/detail/is_valid/debug_complement_graph.hpp @@ -1,8 +1,9 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014, Oracle and/or its affiliates. +// Copyright (c) 2014, 2018, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Licensed under the Boost Software License version 1.0. // http://www.boost.org/users/license.html @@ -14,6 +15,8 @@ #include <iostream> #endif +#include <boost/geometry/algorithms/detail/is_valid/complement_graph.hpp> + namespace boost { namespace geometry { diff --git a/boost/geometry/algorithms/detail/is_valid/debug_validity_phase.hpp b/boost/geometry/algorithms/detail/is_valid/debug_validity_phase.hpp index a10e0fe596..b072f7ad43 100644 --- a/boost/geometry/algorithms/detail/is_valid/debug_validity_phase.hpp +++ b/boost/geometry/algorithms/detail/is_valid/debug_validity_phase.hpp @@ -1,8 +1,9 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014, Oracle and/or its affiliates. +// Copyright (c) 2014, 2018, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Licensed under the Boost Software License version 1.0. // http://www.boost.org/users/license.html @@ -12,11 +13,10 @@ #ifdef GEOMETRY_TEST_DEBUG #include <iostream> +#endif #include <boost/geometry/core/tag.hpp> #include <boost/geometry/core/tags.hpp> -#endif - namespace boost { namespace geometry { diff --git a/boost/geometry/algorithms/detail/is_valid/has_invalid_coordinate.hpp b/boost/geometry/algorithms/detail/is_valid/has_invalid_coordinate.hpp index 6e6823d62f..cf3a41069a 100644 --- a/boost/geometry/algorithms/detail/is_valid/has_invalid_coordinate.hpp +++ b/boost/geometry/algorithms/detail/is_valid/has_invalid_coordinate.hpp @@ -1,6 +1,6 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014-2015, Oracle and/or its affiliates. +// Copyright (c) 2014-2018, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -15,15 +15,17 @@ #include <boost/type_traits/is_floating_point.hpp> +#include <boost/geometry/algorithms/detail/check_iterator_range.hpp> +#include <boost/geometry/algorithms/validity_failure_type.hpp> + #include <boost/geometry/core/coordinate_type.hpp> #include <boost/geometry/core/point_type.hpp> -#include <boost/geometry/util/has_non_finite_coordinate.hpp> - #include <boost/geometry/iterators/point_iterator.hpp> + #include <boost/geometry/views/detail/indexed_point_view.hpp> -#include <boost/geometry/algorithms/detail/check_iterator_range.hpp> +#include <boost/geometry/util/has_non_finite_coordinate.hpp> namespace boost { namespace geometry { diff --git a/boost/geometry/algorithms/detail/is_valid/has_valid_self_turns.hpp b/boost/geometry/algorithms/detail/is_valid/has_valid_self_turns.hpp index b36e9f38b7..82818b0990 100644 --- a/boost/geometry/algorithms/detail/is_valid/has_valid_self_turns.hpp +++ b/boost/geometry/algorithms/detail/is_valid/has_valid_self_turns.hpp @@ -1,6 +1,6 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014-2017, Oracle and/or its affiliates. +// Copyright (c) 2014-2018, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -16,6 +16,12 @@ #include <boost/core/ignore_unused.hpp> #include <boost/range.hpp> +#include <boost/geometry/algorithms/detail/is_valid/is_acceptable_turn.hpp> +#include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp> +#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp> +#include <boost/geometry/algorithms/detail/overlay/self_turn_points.hpp> +#include <boost/geometry/algorithms/validity_failure_type.hpp> + #include <boost/geometry/core/assert.hpp> #include <boost/geometry/core/point_type.hpp> @@ -23,12 +29,6 @@ #include <boost/geometry/policies/robustness/segment_ratio_type.hpp> #include <boost/geometry/policies/robustness/get_rescale_policy.hpp> -#include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp> -#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp> -#include <boost/geometry/algorithms/detail/overlay/self_turn_points.hpp> - -#include <boost/geometry/algorithms/detail/is_valid/is_acceptable_turn.hpp> - namespace boost { namespace geometry { diff --git a/boost/geometry/algorithms/detail/is_valid/multipolygon.hpp b/boost/geometry/algorithms/detail/is_valid/multipolygon.hpp index ed24b13810..8fe5803323 100644 --- a/boost/geometry/algorithms/detail/is_valid/multipolygon.hpp +++ b/boost/geometry/algorithms/detail/is_valid/multipolygon.hpp @@ -116,19 +116,12 @@ private: } // prepare strategies - typedef typename std::iterator_traits<PolygonIterator>::value_type polygon_type; - typedef typename Strategy::template point_in_geometry_strategy - < - polygon_type, polygon_type - >::type within_strategy_type; - within_strategy_type const within_strategy - = strategy.template get_point_in_geometry_strategy<polygon_type, polygon_type>(); typedef typename Strategy::envelope_strategy_type envelope_strategy_type; envelope_strategy_type const envelope_strategy = strategy.get_envelope_strategy(); // call partition to check if polygons are disjoint from each other - typename base::template item_visitor_type<within_strategy_type> item_visitor(within_strategy); + typename base::template item_visitor_type<Strategy> item_visitor(strategy); geometry::partition < diff --git a/boost/geometry/algorithms/detail/is_valid/polygon.hpp b/boost/geometry/algorithms/detail/is_valid/polygon.hpp index 5c6229b793..834ce5af2c 100644 --- a/boost/geometry/algorithms/detail/is_valid/polygon.hpp +++ b/boost/geometry/algorithms/detail/is_valid/polygon.hpp @@ -2,7 +2,7 @@ // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland. -// Copyright (c) 2014-2017, Oracle and/or its affiliates. +// Copyright (c) 2014-2018, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -217,26 +217,19 @@ protected: , m_strategy(strategy) {} - template <typename Item> - inline bool is_within(Item const& first, Item const& second) - { - typename point_type<Polygon>::type point; - typedef detail::point_on_border::point_on_range<true> pob; - - // TODO: this should check for a point on the interior, instead - // of on border. Or it should check using the overlap function. - - return pob::apply(point, points_begin(first), points_end(first)) - && geometry::within(point, second, m_strategy); - } - template <typename Iterator, typename Box> inline bool apply(partition_item<Iterator, Box> const& item1, partition_item<Iterator, Box> const& item2) { - if (! items_overlap - && (is_within(*item1.get(), *item2.get()) - || is_within(*item2.get(), *item1.get()))) + typedef boost::mpl::vector + < + geometry::de9im::static_mask<'T'>, + geometry::de9im::static_mask<'*', 'T'>, + geometry::de9im::static_mask<'*', '*', '*', 'T'> + > relate_mask_t; + + if ( ! items_overlap + && geometry::relate(*item1.get(), *item2.get(), relate_mask_t(), m_strategy) ) { items_overlap = true; return false; // interrupt @@ -326,19 +319,13 @@ protected: } // prepare strategies - typedef typename Strategy::template point_in_geometry_strategy - < - inter_ring_type, inter_ring_type - >::type in_interior_strategy_type; - in_interior_strategy_type const in_interior_strategy - = strategy.template get_point_in_geometry_strategy<inter_ring_type, inter_ring_type>(); typedef typename Strategy::envelope_strategy_type envelope_strategy_type; envelope_strategy_type const envelope_strategy = strategy.get_envelope_strategy(); // call partition to check if interior rings are disjoint from // each other - item_visitor_type<in_interior_strategy_type> item_visitor(in_interior_strategy); + item_visitor_type<Strategy> item_visitor(strategy); geometry::partition < diff --git a/boost/geometry/algorithms/detail/is_valid/ring.hpp b/boost/geometry/algorithms/detail/is_valid/ring.hpp index 40698155b5..5a55d998e4 100644 --- a/boost/geometry/algorithms/detail/is_valid/ring.hpp +++ b/boost/geometry/algorithms/detail/is_valid/ring.hpp @@ -2,7 +2,7 @@ // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland. -// Copyright (c) 2014-2017, Oracle and/or its affiliates. +// Copyright (c) 2014-2018, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -20,6 +20,7 @@ #include <boost/geometry/core/closure.hpp> #include <boost/geometry/core/cs.hpp> #include <boost/geometry/core/point_order.hpp> +#include <boost/geometry/core/tags.hpp> #include <boost/geometry/util/order_as_direction.hpp> #include <boost/geometry/util/range.hpp> @@ -36,6 +37,7 @@ #include <boost/geometry/algorithms/detail/is_valid/has_invalid_coordinate.hpp> #include <boost/geometry/algorithms/detail/is_valid/has_spikes.hpp> #include <boost/geometry/algorithms/detail/is_valid/has_valid_self_turns.hpp> +#include <boost/geometry/algorithms/dispatch/is_valid.hpp> #include <boost/geometry/strategies/area.hpp> diff --git a/boost/geometry/algorithms/detail/normalize.hpp b/boost/geometry/algorithms/detail/normalize.hpp index 7a761d42bb..b53243f08f 100644 --- a/boost/geometry/algorithms/detail/normalize.hpp +++ b/boost/geometry/algorithms/detail/normalize.hpp @@ -1,6 +1,6 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2015-2017, Oracle and/or its affiliates. +// Copyright (c) 2015-2018, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -11,298 +11,31 @@ #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_NORMALIZE_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_NORMALIZE_HPP -#include <cstddef> -#include <boost/numeric/conversion/cast.hpp> - -#include <boost/geometry/core/access.hpp> -#include <boost/geometry/core/coordinate_system.hpp> -#include <boost/geometry/core/coordinate_type.hpp> -#include <boost/geometry/core/cs.hpp> -#include <boost/geometry/core/tag.hpp> -#include <boost/geometry/core/tags.hpp> - -#include <boost/geometry/util/normalize_spheroidal_coordinates.hpp> -#include <boost/geometry/util/normalize_spheroidal_box_coordinates.hpp> - -#include <boost/geometry/views/detail/indexed_point_view.hpp> +// For backward compatibility +#include <boost/geometry/strategies/normalize.hpp> namespace boost { namespace geometry { -#ifndef DOXYGEN_NO_DETAIL -namespace detail { namespace normalization -{ - - -struct do_nothing -{ - template <typename GeometryIn, typename GeometryOut> - static inline void apply(GeometryIn const&, GeometryOut&) - { - } -}; - - -template <std::size_t Dimension, std::size_t DimensionCount> -struct assign_loop -{ - template <typename CoordinateType, typename PointIn, typename PointOut> - static inline void apply(CoordinateType const& longitude, - CoordinateType const& latitude, - PointIn const& point_in, - PointOut& point_out) - { - geometry::set<Dimension>(point_out, boost::numeric_cast - < - typename coordinate_type<PointOut>::type - >(geometry::get<Dimension>(point_in))); - - assign_loop - < - Dimension + 1, DimensionCount - >::apply(longitude, latitude, point_in, point_out); - } -}; - -template <std::size_t DimensionCount> -struct assign_loop<DimensionCount, DimensionCount> -{ - template <typename CoordinateType, typename PointIn, typename PointOut> - static inline void apply(CoordinateType const&, - CoordinateType const&, - PointIn const&, - PointOut&) - { - } -}; - -template <std::size_t DimensionCount> -struct assign_loop<0, DimensionCount> -{ - template <typename CoordinateType, typename PointIn, typename PointOut> - static inline void apply(CoordinateType const& longitude, - CoordinateType const& latitude, - PointIn const& point_in, - PointOut& point_out) - { - geometry::set<0>(point_out, boost::numeric_cast - < - typename coordinate_type<PointOut>::type - >(longitude)); - - assign_loop - < - 1, DimensionCount - >::apply(longitude, latitude, point_in, point_out); - } -}; - -template <std::size_t DimensionCount> -struct assign_loop<1, DimensionCount> -{ - template <typename CoordinateType, typename PointIn, typename PointOut> - static inline void apply(CoordinateType const& longitude, - CoordinateType const& latitude, - PointIn const& point_in, - PointOut& point_out) - { - geometry::set<1>(point_out, boost::numeric_cast - < - typename coordinate_type<PointOut>::type - >(latitude)); - - assign_loop - < - 2, DimensionCount - >::apply(longitude, latitude, point_in, point_out); - } -}; - - -template <typename PointIn, typename PointOut, bool IsEquatorial = true> -struct normalize_point -{ - static inline void apply(PointIn const& point_in, PointOut& point_out) - { - typedef typename coordinate_type<PointIn>::type in_coordinate_type; - - in_coordinate_type longitude = geometry::get<0>(point_in); - in_coordinate_type latitude = geometry::get<1>(point_in); - - math::normalize_spheroidal_coordinates - < - typename coordinate_system<PointIn>::type::units, - IsEquatorial, - in_coordinate_type - >(longitude, latitude); - - assign_loop - < - 0, dimension<PointIn>::value - >::apply(longitude, latitude, point_in, point_out); - } -}; - - -template <typename BoxIn, typename BoxOut, bool IsEquatorial = true> -class normalize_box -{ - template <typename UnitsIn, typename UnitsOut, typename CoordinateInType> - static inline void apply_to_coordinates(CoordinateInType& lon_min, - CoordinateInType& lat_min, - CoordinateInType& lon_max, - CoordinateInType& lat_max, - BoxIn const& box_in, - BoxOut& box_out) - { - detail::indexed_point_view<BoxOut, min_corner> p_min_out(box_out); - assign_loop - < - 0, dimension<BoxIn>::value - >::apply(lon_min, - lat_min, - detail::indexed_point_view - < - BoxIn const, min_corner - >(box_in), - p_min_out); - - detail::indexed_point_view<BoxOut, max_corner> p_max_out(box_out); - assign_loop - < - 0, dimension<BoxIn>::value - >::apply(lon_max, - lat_max, - detail::indexed_point_view - < - BoxIn const, max_corner - >(box_in), - p_max_out); - } - -public: - static inline void apply(BoxIn const& box_in, BoxOut& box_out) - { - typedef typename coordinate_type<BoxIn>::type in_coordinate_type; - - in_coordinate_type lon_min = geometry::get<min_corner, 0>(box_in); - in_coordinate_type lat_min = geometry::get<min_corner, 1>(box_in); - in_coordinate_type lon_max = geometry::get<max_corner, 0>(box_in); - in_coordinate_type lat_max = geometry::get<max_corner, 1>(box_in); - - math::normalize_spheroidal_box_coordinates - < - typename coordinate_system<BoxIn>::type::units, - IsEquatorial, - in_coordinate_type - >(lon_min, lat_min, lon_max, lat_max); - - apply_to_coordinates - < - typename coordinate_system<BoxIn>::type::units, - typename coordinate_system<BoxOut>::type::units - >(lon_min, lat_min, lon_max, lat_max, box_in, box_out); - } -}; - - -}} // namespace detail::normalization -#endif // DOXYGEN_NO_DETAIL - -#ifndef DOXYGEN_NO_DISPATCH -namespace dispatch -{ - -template -< - typename GeometryIn, - typename GeometryOut, - typename TagIn = typename tag<GeometryIn>::type, - typename TagOut = typename tag<GeometryOut>::type, - typename CSTagIn = typename cs_tag<GeometryIn>::type, - typename CSTagOut = typename cs_tag<GeometryOut>::type -> -struct normalize : detail::normalization::do_nothing -{}; - - -template <typename PointIn, typename PointOut> -struct normalize - < - PointIn, PointOut, point_tag, point_tag, - spherical_equatorial_tag, spherical_equatorial_tag - > : detail::normalization::normalize_point<PointIn, PointOut> -{}; - - -template <typename PointIn, typename PointOut> -struct normalize - < - PointIn, PointOut, point_tag, point_tag, - spherical_polar_tag, spherical_polar_tag - > : detail::normalization::normalize_point<PointIn, PointOut, false> -{}; - - -template <typename PointIn, typename PointOut> -struct normalize - < - PointIn, PointOut, point_tag, point_tag, geographic_tag, geographic_tag - > : detail::normalization::normalize_point<PointIn, PointOut> -{}; - - -template <typename BoxIn, typename BoxOut> -struct normalize - < - BoxIn, BoxOut, box_tag, box_tag, - spherical_equatorial_tag, spherical_equatorial_tag - > : detail::normalization::normalize_box<BoxIn, BoxOut> -{}; - - -template <typename BoxIn, typename BoxOut> -struct normalize - < - BoxIn, BoxOut, box_tag, box_tag, - spherical_polar_tag, spherical_polar_tag - > : detail::normalization::normalize_box<BoxIn, BoxOut, false> -{}; - - -template <typename BoxIn, typename BoxOut> -struct normalize - < - BoxIn, BoxOut, box_tag, box_tag, geographic_tag, geographic_tag - > : detail::normalization::normalize_box<BoxIn, BoxOut> -{}; - - -} // namespace dispatch -#endif // DOXYGEN_NO_DISPATCH - #ifndef DOXYGEN_NO_DETAIL namespace detail { -template <typename GeometryIn, typename GeometryOut> -inline void normalize(GeometryIn const& geometry_in, GeometryOut& geometry_out) +template <typename GeometryIn, typename GeometryOut, typename Strategy> +inline void normalize(GeometryIn const& geometry_in, GeometryOut& geometry_out, Strategy const& ) { - dispatch::normalize - < - GeometryIn, GeometryOut - >::apply(geometry_in, geometry_out); + Strategy::apply(geometry_in, geometry_out); } -template <typename GeometryOut, typename GeometryIn> -inline GeometryOut return_normalized(GeometryIn const& geometry_in) +template <typename GeometryOut, typename GeometryIn, typename Strategy> +inline GeometryOut return_normalized(GeometryIn const& geometry_in, Strategy const& strategy) { GeometryOut geometry_out; - detail::normalize(geometry_in, geometry_out); + detail::normalize(geometry_in, geometry_out, strategy); return geometry_out; } diff --git a/boost/geometry/algorithms/detail/overlay/append_no_duplicates.hpp b/boost/geometry/algorithms/detail/overlay/append_no_duplicates.hpp index 0fd1fe4de9..34e9fc79c7 100644 --- a/boost/geometry/algorithms/detail/overlay/append_no_duplicates.hpp +++ b/boost/geometry/algorithms/detail/overlay/append_no_duplicates.hpp @@ -2,6 +2,11 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// This file was modified by Oracle on 2018. +// Modifications copyright (c) 2018 Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + // 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) @@ -10,11 +15,10 @@ #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_APPEND_NO_DUPLICATES_HPP -#include <boost/range.hpp> - #include <boost/geometry/algorithms/append.hpp> #include <boost/geometry/algorithms/detail/equals/point_point.hpp> +#include <boost/geometry/util/range.hpp> namespace boost { namespace geometry @@ -26,11 +30,24 @@ namespace detail { namespace overlay { template <typename Range, typename Point> -inline void append_no_duplicates(Range& range, Point const& point, bool force = false) +inline void append_with_duplicates(Range& range, Point const& point) +{ +#ifdef BOOST_GEOMETRY_DEBUG_INTERSECTION + std::cout << " add: (" + << geometry::get<0>(point) << ", " << geometry::get<1>(point) << ")" + << std::endl; +#endif + geometry::append(range, point); +} + +template <typename Range, typename Point, typename EqPPStrategy> +inline void append_no_duplicates(Range& range, Point const& point, + EqPPStrategy const& strategy) { - if (boost::size(range) == 0 - || force - || ! geometry::detail::equals::equals_point_point(*(boost::end(range)-1), point)) + if ( boost::empty(range) + || ! geometry::detail::equals::equals_point_point(geometry::range::back(range), + point, + strategy) ) { #ifdef BOOST_GEOMETRY_DEBUG_INTERSECTION std::cout << " add: (" diff --git a/boost/geometry/algorithms/detail/overlay/append_no_dups_or_spikes.hpp b/boost/geometry/algorithms/detail/overlay/append_no_dups_or_spikes.hpp index 724996ae33..aac39df141 100644 --- a/boost/geometry/algorithms/detail/overlay/append_no_dups_or_spikes.hpp +++ b/boost/geometry/algorithms/detail/overlay/append_no_dups_or_spikes.hpp @@ -2,8 +2,8 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. -// This file was modified by Oracle on 2014, 2017. -// Modifications copyright (c) 2014-2017 Oracle and/or its affiliates. +// This file was modified by Oracle on 2014, 2017, 2018. +// Modifications copyright (c) 2014-2018 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -15,11 +15,14 @@ #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_APPEND_NO_DUPS_OR_SPIKES_HPP #include <boost/range.hpp> +#include <boost/static_assert.hpp> #include <boost/geometry/algorithms/append.hpp> #include <boost/geometry/algorithms/detail/point_is_spike_or_equal.hpp> #include <boost/geometry/algorithms/detail/equals/point_point.hpp> +#include <boost/geometry/core/closure.hpp> + #include <boost/geometry/util/condition.hpp> #include <boost/geometry/util/range.hpp> @@ -33,12 +36,13 @@ namespace detail { namespace overlay { // TODO: move this / rename this -template <typename Point1, typename Point2, typename RobustPolicy> +template <typename Point1, typename Point2, typename EqualsStrategy, typename RobustPolicy> inline bool points_equal_or_close(Point1 const& point1, Point2 const& point2, + EqualsStrategy const& strategy, RobustPolicy const& robust_policy) { - if (detail::equals::equals_point_point(point1, point2)) + if (detail::equals::equals_point_point(point1, point2, strategy)) { return true; } @@ -59,7 +63,14 @@ inline bool points_equal_or_close(Point1 const& point1, geometry::recalculate(point1_rob, point1, robust_policy); geometry::recalculate(point2_rob, point2, robust_policy); - return detail::equals::equals_point_point(point1_rob, point2_rob); + // Only if this is the case the same strategy can be used. + BOOST_STATIC_ASSERT((boost::is_same + < + typename geometry::cs_tag<Point1>::type, + typename geometry::cs_tag<robust_point_type>::type + >::value)); + + return detail::equals::equals_point_point(point1_rob, point2_rob, strategy); } @@ -76,8 +87,10 @@ inline void append_no_dups_or_spikes(Range& range, Point const& point, // The code below this condition checks all spikes/dups // for geometries >= 3 points. // So we have to check the first potential duplicate differently - if (boost::size(range) == 1 - && points_equal_or_close(*(boost::begin(range)), point, robust_policy)) + if ( boost::size(range) == 1 + && points_equal_or_close(*(boost::begin(range)), point, + strategy.get_equals_point_point_strategy(), + robust_policy) ) { return; } @@ -113,8 +126,10 @@ inline void append_no_collinear(Range& range, Point const& point, // The code below this condition checks all spikes/dups // for geometries >= 3 points. // So we have to check the first potential duplicate differently - if (boost::size(range) == 1 - && points_equal_or_close(*(boost::begin(range)), point, robust_policy)) + if ( boost::size(range) == 1 + && points_equal_or_close(*(boost::begin(range)), point, + strategy.get_equals_point_point_strategy(), + robust_policy) ) { return; } diff --git a/boost/geometry/algorithms/detail/overlay/assign_parents.hpp b/boost/geometry/algorithms/detail/overlay/assign_parents.hpp index 3be5393486..6d3c602ff2 100644 --- a/boost/geometry/algorithms/detail/overlay/assign_parents.hpp +++ b/boost/geometry/algorithms/detail/overlay/assign_parents.hpp @@ -3,8 +3,8 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland. -// This file was modified by Oracle on 2017. -// Modifications copyright (c) 2017 Oracle and/or its affiliates. +// This file was modified by Oracle on 2017, 2018. +// Modifications copyright (c) 2017-2018 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, @@ -16,7 +16,6 @@ #include <boost/range.hpp> -#include <boost/geometry/algorithms/area.hpp> #include <boost/geometry/algorithms/envelope.hpp> #include <boost/geometry/algorithms/expand.hpp> #include <boost/geometry/algorithms/detail/partition.hpp> @@ -135,12 +134,14 @@ struct ring_info_helper_get_box } }; +template <typename DisjointBoxBoxStrategy> struct ring_info_helper_ovelaps_box { template <typename Box, typename InputItem> static inline bool apply(Box const& box, InputItem const& item) { - return ! geometry::detail::disjoint::disjoint_box_box(box, item.envelope); + return ! geometry::detail::disjoint::disjoint_box_box( + box, item.envelope, DisjointBoxBoxStrategy()); } }; @@ -328,11 +329,16 @@ inline void assign_parents(Geometry1 const& geometry1, Strategy > visitor(geometry1, geometry2, collection, ring_map, strategy, check_for_orientation); + typedef ring_info_helper_ovelaps_box + < + typename Strategy::disjoint_box_box_strategy_type + > overlaps_box_type; + geometry::partition < box_type >::apply(vector, visitor, ring_info_helper_get_box(), - ring_info_helper_ovelaps_box()); + overlaps_box_type()); } if (check_for_orientation) diff --git a/boost/geometry/algorithms/detail/overlay/check_enrich.hpp b/boost/geometry/algorithms/detail/overlay/check_enrich.hpp index 25e442982b..e07e056c33 100644 --- a/boost/geometry/algorithms/detail/overlay/check_enrich.hpp +++ b/boost/geometry/algorithms/detail/overlay/check_enrich.hpp @@ -2,6 +2,11 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// This file was modified by Oracle on 2018. +// Modifications copyright (c) 2018 Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + // 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) @@ -9,11 +14,18 @@ #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CHECK_ENRICH_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CHECK_ENRICH_HPP +#ifdef BOOST_GEOMETRY_DEBUG_ENRICH +#include <iostream> +#endif // BOOST_GEOMETRY_DEBUG_ENRICH #include <cstddef> +#include <vector> -#include <boost/range.hpp> +#include <boost/range/begin.hpp> +#include <boost/range/end.hpp> +#include <boost/range/value_type.hpp> +#include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp> #include <boost/geometry/algorithms/detail/ring_identifier.hpp> @@ -42,7 +54,7 @@ struct meta_turn template <typename MetaTurn> -inline void display(MetaTurn const& meta_turn, std::string const& reason = "") +inline void display(MetaTurn const& meta_turn, const char* reason = "") { #ifdef BOOST_GEOMETRY_DEBUG_ENRICH std::cout << meta_turn.index diff --git a/boost/geometry/algorithms/detail/overlay/clip_linestring.hpp b/boost/geometry/algorithms/detail/overlay/clip_linestring.hpp index 8cb37d6954..ead9e7014a 100644 --- a/boost/geometry/algorithms/detail/overlay/clip_linestring.hpp +++ b/boost/geometry/algorithms/detail/overlay/clip_linestring.hpp @@ -2,10 +2,11 @@ // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. -// This file was modified by Oracle on 2015. -// Modifications copyright (c) 2015 Oracle and/or its affiliates. +// This file was modified by Oracle on 2015, 2018. +// Modifications copyright (c) 2015-2018 Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at @@ -24,6 +25,8 @@ #include <boost/geometry/util/select_coordinate_type.hpp> #include <boost/geometry/geometries/segment.hpp> +#include <boost/geometry/strategies/cartesian/point_in_point.hpp> + namespace boost { namespace geometry { @@ -83,6 +86,15 @@ private: public: +// TODO: Temporary, this strategy should be moved, it is cartesian-only + + typedef strategy::within::cartesian_point_point equals_point_point_strategy_type; + + static inline equals_point_point_strategy_type get_equals_point_point_strategy() + { + return equals_point_point_strategy_type(); + } + inline bool clip_segment(Box const& b, segment_type& s, bool& sp1_clipped, bool& sp2_clipped) const { typedef typename select_coordinate_type<Box, Point>::type coordinate_type; @@ -224,9 +236,10 @@ OutputIterator clip_range_with_box(Box const& b, Range const& range, // b. Add p1 only if it is the first point, then add p2 if (boost::empty(line_out)) { - detail::overlay::append_no_duplicates(line_out, p1, true); + detail::overlay::append_with_duplicates(line_out, p1); } - detail::overlay::append_no_duplicates(line_out, p2); + detail::overlay::append_no_duplicates(line_out, p2, + strategy.get_equals_point_point_strategy()); // c. If c2 is clipped, finish the line if (c2) diff --git a/boost/geometry/algorithms/detail/overlay/convert_ring.hpp b/boost/geometry/algorithms/detail/overlay/convert_ring.hpp index 51955b515d..e2b3cfe069 100644 --- a/boost/geometry/algorithms/detail/overlay/convert_ring.hpp +++ b/boost/geometry/algorithms/detail/overlay/convert_ring.hpp @@ -2,6 +2,11 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// This file was modified by Oracle on 2018. +// Modifications copyright (c) 2018, Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + // 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) @@ -9,18 +14,16 @@ #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CONVERT_RING_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CONVERT_RING_HPP - #include <boost/mpl/assert.hpp> -#include <boost/range.hpp> #include <boost/range/algorithm/reverse.hpp> +#include <boost/geometry/algorithms/convert.hpp> +#include <boost/geometry/algorithms/detail/ring_identifier.hpp> +#include <boost/geometry/algorithms/num_points.hpp> + #include <boost/geometry/core/tags.hpp> #include <boost/geometry/core/exterior_ring.hpp> #include <boost/geometry/core/interior_rings.hpp> -#include <boost/geometry/algorithms/detail/ring_identifier.hpp> - -#include <boost/geometry/algorithms/convert.hpp> - namespace boost { namespace geometry { diff --git a/boost/geometry/algorithms/detail/overlay/copy_segments.hpp b/boost/geometry/algorithms/detail/overlay/copy_segments.hpp index c6f540a978..d5bdf7eb82 100644 --- a/boost/geometry/algorithms/detail/overlay/copy_segments.hpp +++ b/boost/geometry/algorithms/detail/overlay/copy_segments.hpp @@ -2,8 +2,8 @@ // Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. -// This file was modified by Oracle on 2014, 2017. -// Modifications copyright (c) 2014-2017 Oracle and/or its affiliates. +// This file was modified by Oracle on 2014, 2017, 2018. +// Modifications copyright (c) 2014-2018 Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -23,23 +23,27 @@ #include <boost/range.hpp> #include <boost/type_traits/integral_constant.hpp> +#include <boost/geometry/algorithms/detail/assign_box_corners.hpp> +#include <boost/geometry/algorithms/detail/signed_size_type.hpp> +#include <boost/geometry/algorithms/detail/overlay/append_no_duplicates.hpp> +#include <boost/geometry/algorithms/detail/overlay/append_no_dups_or_spikes.hpp> +#include <boost/geometry/algorithms/not_implemented.hpp> + #include <boost/geometry/core/assert.hpp> #include <boost/geometry/core/exterior_ring.hpp> #include <boost/geometry/core/interior_rings.hpp> #include <boost/geometry/core/ring_type.hpp> #include <boost/geometry/core/tags.hpp> -#include <boost/geometry/algorithms/not_implemented.hpp> + #include <boost/geometry/geometries/concepts/check.hpp> -#include <boost/geometry/iterators/ever_circling_iterator.hpp> -#include <boost/geometry/views/closeable_view.hpp> -#include <boost/geometry/views/reversible_view.hpp> -#include <boost/geometry/algorithms/detail/overlay/append_no_duplicates.hpp> -#include <boost/geometry/algorithms/detail/overlay/append_no_dups_or_spikes.hpp> -#include <boost/geometry/algorithms/detail/signed_size_type.hpp> +#include <boost/geometry/iterators/ever_circling_iterator.hpp> #include <boost/geometry/util/range.hpp> +#include <boost/geometry/views/closeable_view.hpp> +#include <boost/geometry/views/reversible_view.hpp> + namespace boost { namespace geometry { @@ -137,11 +141,11 @@ private: template <typename RangeOut, typename Point, typename SideStrategy, typename RobustPolicy> static inline void append_to_output(RangeOut& current_output, Point const& point, - SideStrategy const&, + SideStrategy const& strategy, RobustPolicy const&, boost::false_type const&) { - detail::overlay::append_no_duplicates(current_output, point); + detail::overlay::append_no_duplicates(current_output, point, strategy.get_equals_point_point_strategy()); } public: diff --git a/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp b/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp index a35be052a0..287a06b081 100644 --- a/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp +++ b/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp @@ -441,18 +441,21 @@ inline void enrich_intersection_points(Turns& turns, if (turn.both(detail::overlay::operation_none) || turn.both(opposite_operation) + || turn.both(detail::overlay::operation_blocked) || (detail::overlay::is_self_turn<OverlayType>(turn) && ! turn.is_clustered() && ! turn.both(target_operation))) { + // For all operations, discard xx and none/none // For intersections, remove uu to avoid the need to travel // a union (during intersection) in uu/cc clusters (e.g. #31,#32,#33) + // The ux is necessary to indicate impossible paths + // (especially if rescaling is removed) - // Similarly, for union, discard ii + // Similarly, for union, discard ii and ix - // Only keep self-uu-turns or self-ii-turns + // For self-turns, only keep uu / ii - // Blocked (or combination with blocked is still needed for difference) turn.discarded = true; turn.cluster_id = -1; continue; diff --git a/boost/geometry/algorithms/detail/overlay/follow.hpp b/boost/geometry/algorithms/detail/overlay/follow.hpp index d948c4f670..5d62e0c476 100644 --- a/boost/geometry/algorithms/detail/overlay/follow.hpp +++ b/boost/geometry/algorithms/detail/overlay/follow.hpp @@ -3,8 +3,8 @@ // Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland. -// This file was modified by Oracle on 2014, 2017. -// Modifications copyright (c) 2014-2017 Oracle and/or its affiliates. +// This file was modified by Oracle on 2014, 2017, 2018. +// Modifications copyright (c) 2014-2018 Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -159,7 +159,7 @@ struct action_selector<overlay_intersection, RemoveSpikes> typename LineString, typename Point, typename Operation, - typename SideStrategy, + typename Strategy, typename RobustPolicy > static inline void enter(LineStringOut& current_piece, @@ -167,13 +167,13 @@ struct action_selector<overlay_intersection, RemoveSpikes> segment_identifier& segment_id, signed_size_type , Point const& point, Operation const& operation, - SideStrategy const& , + Strategy const& strategy, RobustPolicy const& , OutputIterator& ) { // On enter, append the intersection point and remember starting point // TODO: we don't check on spikes for linestrings (?). Consider this. - detail::overlay::append_no_duplicates(current_piece, point); + detail::overlay::append_no_duplicates(current_piece, point, strategy.get_equals_point_point_strategy()); segment_id = operation.seg_id; } @@ -184,7 +184,7 @@ struct action_selector<overlay_intersection, RemoveSpikes> typename LineString, typename Point, typename Operation, - typename SideStrategy, + typename Strategy, typename RobustPolicy > static inline void leave(LineStringOut& current_piece, @@ -192,7 +192,7 @@ struct action_selector<overlay_intersection, RemoveSpikes> segment_identifier& segment_id, signed_size_type index, Point const& point, Operation const& , - SideStrategy const& strategy, + Strategy const& strategy, RobustPolicy const& robust_policy, OutputIterator& out) { @@ -202,7 +202,7 @@ struct action_selector<overlay_intersection, RemoveSpikes> < false, RemoveSpikes >::apply(linestring, segment_id, index, strategy, robust_policy, current_piece); - detail::overlay::append_no_duplicates(current_piece, point); + detail::overlay::append_no_duplicates(current_piece, point, strategy.get_equals_point_point_strategy()); if (::boost::size(current_piece) > 1) { *out++ = current_piece; @@ -260,7 +260,7 @@ struct action_selector<overlay_difference, RemoveSpikes> typename LineString, typename Point, typename Operation, - typename SideStrategy, + typename Strategy, typename RobustPolicy > static inline void enter(LineStringOut& current_piece, @@ -268,7 +268,7 @@ struct action_selector<overlay_difference, RemoveSpikes> segment_identifier& segment_id, signed_size_type index, Point const& point, Operation const& operation, - SideStrategy const& strategy, + Strategy const& strategy, RobustPolicy const& robust_policy, OutputIterator& out) { @@ -283,7 +283,7 @@ struct action_selector<overlay_difference, RemoveSpikes> typename LineString, typename Point, typename Operation, - typename SideStrategy, + typename Strategy, typename RobustPolicy > static inline void leave(LineStringOut& current_piece, @@ -291,7 +291,7 @@ struct action_selector<overlay_difference, RemoveSpikes> segment_identifier& segment_id, signed_size_type index, Point const& point, Operation const& operation, - SideStrategy const& strategy, + Strategy const& strategy, RobustPolicy const& robust_policy, OutputIterator& out) { diff --git a/boost/geometry/algorithms/detail/overlay/get_intersection_points.hpp b/boost/geometry/algorithms/detail/overlay/get_intersection_points.hpp index 94667d0ed0..5a3360375a 100644 --- a/boost/geometry/algorithms/detail/overlay/get_intersection_points.hpp +++ b/boost/geometry/algorithms/detail/overlay/get_intersection_points.hpp @@ -44,12 +44,16 @@ template > struct get_turn_without_info { - template <typename Strategy, typename RobustPolicy, typename OutputIterator> - static inline OutputIterator apply( - Point1 const& pi, Point1 const& pj, Point1 const& /*pk*/, - Point2 const& qi, Point2 const& qj, Point2 const& /*qk*/, - bool /*is_p_first*/, bool /*is_p_last*/, - bool /*is_q_first*/, bool /*is_q_last*/, + template + < + typename UniqueSubRange1, + typename UniqueSubRange2, + typename Strategy, + typename RobustPolicy, + typename OutputIterator + > + static inline OutputIterator apply(UniqueSubRange1 const& range_p, + UniqueSubRange2 const& range_q, TurnInfo const& , Strategy const& strategy, RobustPolicy const& robust_policy, @@ -71,6 +75,10 @@ struct get_turn_without_info typedef model::referring_segment<Point1 const> segment_type1; typedef model::referring_segment<Point2 const> segment_type2; + Point1 const& pi = range_p.at(0); + Point1 const& pj = range_p.at(1); + Point2 const& qi = range_q.at(0); + Point2 const& qj = range_q.at(1); segment_type1 p1(pi, pj); segment_type2 q1(qi, qj); diff --git a/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp b/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp index 895952c8fc..6d92b1bd3c 100644 --- a/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp +++ b/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp @@ -3,8 +3,8 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland. -// This file was modified by Oracle on 2015, 2017. -// Modifications copyright (c) 2015-2017 Oracle and/or its affiliates. +// This file was modified by Oracle on 2015, 2017, 2018, 2019. +// Modifications copyright (c) 2015-2019 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -21,6 +21,7 @@ #include <boost/geometry/core/access.hpp> #include <boost/geometry/core/assert.hpp> +#include <boost/geometry/core/exception.hpp> #include <boost/geometry/algorithms/convert.hpp> #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp> @@ -84,7 +85,7 @@ struct base_turn_handler return side1 * side2 == 1; } - // Both continue + // Both get the same operation template <typename TurnInfo> static inline void both(TurnInfo& ti, operation_type const op) { @@ -130,6 +131,17 @@ struct base_turn_handler ? 1 : 0; } + template <typename Point1, typename Point2> + static inline typename geometry::coordinate_type<Point1>::type + distance_measure(Point1 const& a, Point2 const& b) + { + // TODO: use comparable distance for point-point instead - but that + // causes currently cycling include problems + typedef typename geometry::coordinate_type<Point1>::type ctype; + ctype const dx = get<0>(a) - get<0>(b); + ctype const dy = get<1>(a) - get<1>(b); + return dx * dx + dy * dy; + } }; @@ -143,15 +155,14 @@ struct touch_interior : public base_turn_handler template < unsigned int Index, - typename Point1, - typename Point2, + typename UniqueSubRange1, + typename UniqueSubRange2, typename IntersectionInfo, typename DirInfo, typename SidePolicy > - static inline void apply( - Point1 const& , Point1 const& , Point1 const& , - Point2 const& , Point2 const& , Point2 const& , + static inline void apply(UniqueSubRange1 const& range_p, + UniqueSubRange2 const& range_q, TurnInfo& ti, IntersectionInfo const& intersection_info, DirInfo const& dir_info, @@ -169,8 +180,10 @@ struct touch_interior : public base_turn_handler static unsigned int const index_p = Index; static unsigned int const index_q = 1 - Index; + bool const has_pk = ! range_p.is_last_segment(); + bool const has_qk = ! range_q.is_last_segment(); int const side_qi_p = dir_info.sides.template get<index_q, 0>(); - int const side_qk_p = side.qk_wrt_p1(); + int const side_qk_p = has_qk ? side.qk_wrt_p1() : 0; if (side_qi_p == -side_qk_p) { @@ -183,7 +196,10 @@ struct touch_interior : public base_turn_handler return; } - int const side_qk_q = side.qk_wrt_q1(); + int const side_qk_q = has_qk ? side.qk_wrt_q1() : 0; + + // Only necessary if rescaling is turned off: + int const side_pj_q2 = has_qk ? side.pj_wrt_q2() : 0; if (side_qi_p == -1 && side_qk_p == -1 && side_qk_q == 1) { @@ -194,10 +210,21 @@ struct touch_interior : public base_turn_handler } else if (side_qi_p == 1 && side_qk_p == 1 && side_qk_q == -1) { - // Q turns right on the left side of P (test "ML3") - // Union: take both operation - // Intersection: skip - both(ti, operation_union); + if (has_qk && side_pj_q2 == -1) + { + // Q turns right on the left side of P (test "ML3") + // Union: take both operations + // Intersection: skip + both(ti, operation_union); + } + else + { + // q2 is collinear with p1, so it does not turn back. This + // can happen in floating point precision. In this case, + // block one of the operations to avoid taking that path. + ti.operations[index_p].operation = operation_union; + ti.operations[index_q].operation = operation_blocked; + } ti.touch_only = true; } else if (side_qi_p == side_qk_p && side_qi_p == side_qk_q) @@ -207,6 +234,29 @@ struct touch_interior : public base_turn_handler // Union: take left turn (Q if Q turns left, P if Q turns right) // Intersection: other turn unsigned int index = side_qk_q == 1 ? index_q : index_p; + if (has_qk && side_pj_q2 == 0) + { + // Even though sides xk w.r.t. 1 are distinct, pj is collinear + // with q. Therefore swap the path + index = 1 - index; + } + + if (has_pk && has_qk && opposite(side_pj_q2, side_qi_p)) + { + // Without rescaling, floating point requires extra measures + int const side_qj_p1 = side.qj_wrt_p1(); + int const side_qj_p2 = side.qj_wrt_p2(); + + if (same(side_qj_p1, side_qj_p2)) + { + int const side_pj_q1 = side.pj_wrt_q1(); + if (opposite(side_pj_q1, side_pj_q2)) + { + index = 1 - index; + } + } + } + ti.operations[index].operation = operation_union; ti.operations[1 - index].operation = operation_intersection; ti.touch_only = true; @@ -219,10 +269,16 @@ struct touch_interior : public base_turn_handler // Collinearly in the same direction // (Q comes from left of P and turns left, // OR Q comes from right of P and turns right) - // Omit intersection point. + // Omit second intersection point. // Union: just continue // Intersection: just continue both(ti, operation_continue); + + // Calculate remaining distance. + // Q arrives at p, at point qj, so use qk for q + // and use pj for p + ti.operations[index_p].remaining_distance = distance_measure(ti.point, range_p.at(1)); + ti.operations[index_q].remaining_distance = distance_measure(ti.point, range_q.at(2)); } else { @@ -266,15 +322,14 @@ struct touch : public base_turn_handler template < - typename Point1, - typename Point2, + typename UniqueSubRange1, + typename UniqueSubRange2, typename IntersectionInfo, typename DirInfo, typename SidePolicy > - static inline void apply( - Point1 const& , Point1 const& , Point1 const& , - Point2 const& , Point2 const& , Point2 const& , + static inline void apply(UniqueSubRange1 const& range_p, + UniqueSubRange2 const& range_q, TurnInfo& ti, IntersectionInfo const& intersection_info, DirInfo const& dir_info, @@ -282,17 +337,20 @@ struct touch : public base_turn_handler { assign_point(ti, method_touch, intersection_info, 0); + bool const has_pk = ! range_p.is_last_segment(); + bool const has_qk = ! range_q.is_last_segment(); + int const side_qi_p1 = dir_info.sides.template get<1, 0>(); - int const side_qk_p1 = side.qk_wrt_p1(); + int const side_qk_p1 = has_qk ? side.qk_wrt_p1() : 0; // If Qi and Qk are both at same side of Pi-Pj, // or collinear (so: not opposite sides) if (! opposite(side_qi_p1, side_qk_p1)) { - int const side_pk_q2 = side.pk_wrt_q2(); - int const side_pk_p = side.pk_wrt_p1(); - int const side_qk_q = side.qk_wrt_q1(); + int const side_pk_q2 = has_pk && has_qk ? side.pk_wrt_q2() : 0; + int const side_pk_p = has_pk ? side.pk_wrt_p1() : 0; + int const side_qk_q = has_qk ? side.qk_wrt_q1() : 0; bool const q_turns_left = side_qk_q == 1; bool const block_q = side_qk_p1 == 0 @@ -315,7 +373,7 @@ struct touch : public base_turn_handler return; } - int const side_pk_q1 = side.pk_wrt_q1(); + int const side_pk_q1 = has_pk && has_qk ? side.pk_wrt_q1() : 0; // Collinear opposite case -> block P @@ -392,13 +450,13 @@ struct touch : public base_turn_handler else { // From left to right or from right to left - int const side_pk_p = side.pk_wrt_p1(); + int const side_pk_p = has_pk ? side.pk_wrt_p1() : 0; bool const right_to_left = side_qk_p1 == 1; // If p turns into direction of qi (1,2) if (side_pk_p == side_qi_p1) { - int const side_pk_q1 = side.pk_wrt_q1(); + int const side_pk_q1 = has_pk ? side.pk_wrt_q1() : 0; // Collinear opposite case -> block P if (side_pk_q1 == 0) @@ -420,7 +478,7 @@ struct touch : public base_turn_handler // If p turns into direction of qk (4,5) if (side_pk_p == side_qk_p1) { - int const side_pk_q2 = side.pk_wrt_q2(); + int const side_pk_q2 = has_pk ? side.pk_wrt_q2() : 0; // Collinear case -> lines join, continue if (side_pk_q2 == 0) @@ -439,21 +497,6 @@ struct touch : public base_turn_handler ui_else_iu(! right_to_left, ti); return; } - -#ifdef BOOST_GEOMETRY_DEBUG_GET_TURNS - // Normally a robustness issue. - // TODO: more research if still occuring - std::cout << "Not yet handled" << std::endl - << "pi " << get<0>(pi) << " , " << get<1>(pi) - << " pj " << get<0>(pj) << " , " << get<1>(pj) - << " pk " << get<0>(pk) << " , " << get<1>(pk) - << std::endl - << "qi " << get<0>(qi) << " , " << get<1>(qi) - << " qj " << get<0>(qj) << " , " << get<1>(qj) - << " qk " << get<0>(qk) << " , " << get<1>(qk) - << std::endl; -#endif - } }; @@ -466,15 +509,14 @@ struct equal : public base_turn_handler { template < - typename Point1, - typename Point2, + typename UniqueSubRange1, + typename UniqueSubRange2, typename IntersectionInfo, typename DirInfo, typename SidePolicy > - static inline void apply( - Point1 const& , Point1 const& , Point1 const& , - Point2 const& , Point2 const& , Point2 const& , + static inline void apply(UniqueSubRange1 const& range_p, + UniqueSubRange2 const& range_q, TurnInfo& ti, IntersectionInfo const& info, DirInfo const& , @@ -483,10 +525,12 @@ struct equal : public base_turn_handler // Copy the intersection point in TO direction assign_point(ti, method_equal, info, non_opposite_to_index(info)); - int const side_pk_q2 = side.pk_wrt_q2(); - int const side_pk_p = side.pk_wrt_p1(); - int const side_qk_p = side.qk_wrt_p1(); + bool const has_pk = ! range_p.is_last_segment(); + bool const has_qk = ! range_q.is_last_segment(); + int const side_pk_q2 = has_pk && has_qk ? side.pk_wrt_q2() : 0; + int const side_pk_p = has_pk ? side.pk_wrt_p1() : 0; + int const side_qk_p = has_qk ? side.qk_wrt_p1() : 0; // If pk is collinear with qj-qk, they continue collinearly. // This can be on either side of p1 (== q1), or collinear @@ -525,12 +569,14 @@ struct equal_opposite : public base_turn_handler { template < - typename Point1, - typename Point2, + typename UniqueSubRange1, + typename UniqueSubRange2, typename OutputIterator, typename IntersectionInfo > - static inline void apply(Point1 const& pi, Point2 const& qi, + static inline void apply( + UniqueSubRange1 const& /*range_p*/, + UniqueSubRange2 const& /*range_q*/, /* by value: */ TurnInfo tp, OutputIterator& out, IntersectionInfo const& intersection_info) @@ -546,7 +592,6 @@ struct equal_opposite : public base_turn_handler for (unsigned int i = 0; i < intersection_info.i_info().count; i++) { assign_point(tp, method_none, intersection_info.i_info(), i); - AssignPolicy::apply(tp, pi, qi, intersection_info); *out++ = tp; } } @@ -593,15 +638,15 @@ struct collinear : public base_turn_handler */ template < - typename Point1, - typename Point2, + typename UniqueSubRange1, + typename UniqueSubRange2, typename IntersectionInfo, typename DirInfo, typename SidePolicy > static inline void apply( - Point1 const& , Point1 const& pj, Point1 const& pk, - Point2 const& , Point2 const& qj, Point2 const& qk, + UniqueSubRange1 const& range_p, + UniqueSubRange2 const& range_q, TurnInfo& ti, IntersectionInfo const& info, DirInfo const& dir_info, @@ -614,8 +659,10 @@ struct collinear : public base_turn_handler // Should not be 0, this is checked before BOOST_GEOMETRY_ASSERT(arrival != 0); - int const side_p = side.pk_wrt_p1(); - int const side_q = side.qk_wrt_q1(); + bool const has_pk = ! range_p.is_last_segment(); + bool const has_qk = ! range_q.is_last_segment(); + int const side_p = has_pk ? side.pk_wrt_p1() : 0; + int const side_q = has_qk ? side.qk_wrt_q1() : 0; // If p arrives, use p, else use q int const side_p_or_q = arrival == 1 @@ -642,25 +689,13 @@ struct collinear : public base_turn_handler // Calculate remaining distance. If it continues collinearly it is // measured until the end of the next segment ti.operations[0].remaining_distance - = side_p == 0 - ? distance_measure(ti.point, pk) - : distance_measure(ti.point, pj); + = side_p == 0 && has_pk + ? distance_measure(ti.point, range_p.at(2)) + : distance_measure(ti.point, range_p.at(1)); ti.operations[1].remaining_distance - = side_q == 0 - ? distance_measure(ti.point, qk) - : distance_measure(ti.point, qj); - } - - template <typename Point1, typename Point2> - static inline typename geometry::coordinate_type<Point1>::type - distance_measure(Point1 const& a, Point2 const& b) - { - // TODO: use comparable distance for point-point instead - but that - // causes currently cycling include problems - typedef typename geometry::coordinate_type<Point1>::type ctype; - ctype const dx = get<0>(a) - get<0>(b); - ctype const dy = get<1>(a) - get<1>(b); - return dx * dx + dy * dy; + = side_q == 0 && has_qk + ? distance_measure(ti.point, range_q.at(2)) + : distance_measure(ti.point, range_q.at(1)); } }; @@ -699,13 +734,10 @@ private : template < unsigned int Index, - typename Point1, - typename Point2, typename IntersectionInfo > - static inline bool set_tp(Point1 const& , Point1 const& , Point1 const& , int side_rk_r, - bool const handle_robustness, - Point2 const& , Point2 const& , int side_rk_s, + static inline bool set_tp(int side_rk_r, bool handle_robustness, + int side_rk_s, TurnInfo& tp, IntersectionInfo const& intersection_info) { BOOST_STATIC_ASSERT(Index <= 1); @@ -757,15 +789,15 @@ public: template < - typename Point1, - typename Point2, + typename UniqueSubRange1, + typename UniqueSubRange2, typename OutputIterator, typename IntersectionInfo, typename SidePolicy > static inline void apply( - Point1 const& pi, Point1 const& pj, Point1 const& pk, - Point2 const& qi, Point2 const& qj, Point2 const& qk, + UniqueSubRange1 const& range_p, + UniqueSubRange2 const& range_q, // Opposite collinear can deliver 2 intersection points, TurnInfo const& tp_model, @@ -774,22 +806,24 @@ public: IntersectionInfo const& intersection_info, SidePolicy const& side) { - apply(pi, pj, pk, qi, qj, qk, tp_model, out, intersection_info, side, empty_transformer); + apply(range_p, range_q, + tp_model, out, intersection_info, side, empty_transformer); } public: + template < - typename Point1, - typename Point2, + typename UniqueSubRange1, + typename UniqueSubRange2, typename OutputIterator, typename IntersectionInfo, typename SidePolicy, typename TurnTransformer > static inline void apply( - Point1 const& pi, Point1 const& pj, Point1 const& pk, - Point2 const& qi, Point2 const& qj, Point2 const& qk, + UniqueSubRange1 const& range_p, + UniqueSubRange2 const& range_q, // Opposite collinear can deliver 2 intersection points, TurnInfo const& tp_model, @@ -797,8 +831,7 @@ public: IntersectionInfo const& info, SidePolicy const& side, - TurnTransformer turn_transformer, - bool const is_pk_valid = true, bool const is_qk_valid = true) + TurnTransformer turn_transformer) { TurnInfo tp = tp_model; @@ -807,23 +840,21 @@ public: // If P arrives within Q, there is a turn dependent on P if ( p_arrival == 1 - && is_pk_valid - && set_tp<0>(pi, pj, pk, side.pk_wrt_p1(), true, qi, qj, side.pk_wrt_q1(), tp, info.i_info()) ) + && ! range_p.is_last_segment() + && set_tp<0>(side.pk_wrt_p1(), true, side.pk_wrt_q1(), tp, info.i_info()) ) { turn_transformer(tp); - AssignPolicy::apply(tp, pi, qi, info); *out++ = tp; } // If Q arrives within P, there is a turn dependent on Q if ( q_arrival == 1 - && is_qk_valid - && set_tp<1>(qi, qj, qk, side.qk_wrt_q1(), false, pi, pj, side.qk_wrt_p1(), tp, info.i_info()) ) + && ! range_q.is_last_segment() + && set_tp<1>(side.qk_wrt_q1(), false, side.qk_wrt_p1(), tp, info.i_info()) ) { turn_transformer(tp); - AssignPolicy::apply(tp, pi, qi, info); *out++ = tp; } @@ -840,7 +871,6 @@ public: for (unsigned int i = 0; i < info.i_info().count; i++) { assign_point(tp, method_collinear, info.i_info(), i); - AssignPolicy::apply(tp, pi, qi, info); *out++ = tp; } } @@ -856,23 +886,14 @@ template > struct crosses : public base_turn_handler { - template - < - typename Point1, - typename Point2, - typename IntersectionInfo, - typename DirInfo - > - static inline void apply( - Point1 const& , Point1 const& , Point1 const& , - Point2 const& , Point2 const& , Point2 const& , - TurnInfo& ti, + template <typename IntersectionInfo, typename DirInfo> + static inline void apply(TurnInfo& ti, IntersectionInfo const& intersection_info, DirInfo const& dir_info) { assign_point(ti, method_crosses, intersection_info, 0); - // In all casees: + // In all cases: // If Q crosses P from left to right // Union: take P // Intersection: take Q @@ -897,37 +918,21 @@ struct only_convert : public base_turn_handler /*! \brief Policy doing nothing -\details get_turn_info can have an optional policy to get/assign some - extra information. By default it does not, and this class - is that default. +\details get_turn_info can have an optional policy include extra + truns. By default it does not, and this class is that default. */ struct assign_null_policy { static bool const include_no_turn = false; static bool const include_degenerate = false; static bool const include_opposite = false; - - template - < - typename Info, - typename Point1, - typename Point2, - typename IntersectionInfo - > - static inline void apply(Info& , Point1 const& , Point2 const&, IntersectionInfo const&) - {} - }; - /*! \brief Turn information: intersection point, method, and turn information \details Information necessary for traversal phase (a phase of the overlay process). The information is gathered during the get_turns (segment intersection) phase. - \tparam Point1 point type of first segment - \tparam Point2 point type of second segment - \tparam TurnInfo type of class getting intersection and turn info \tparam AssignPolicy policy to assign extra info, e.g. to calculate distance from segment's first points to intersection points. @@ -937,23 +942,21 @@ struct assign_null_policy template<typename AssignPolicy> struct get_turn_info { - // Intersect pi-pj with qi-qj - // The points pk and qk are used do determine more information - // about the turn (turn left/right) + // Intersect a segment p with a segment q + // Both p and q are modelled as sub_ranges to provide more points + // to be able to give more information about the turn (left/right) template < - typename Point1, - typename Point2, + typename UniqueSubRange1, + typename UniqueSubRange2, typename TurnInfo, typename IntersectionStrategy, typename RobustPolicy, typename OutputIterator > static inline OutputIterator apply( - Point1 const& pi, Point1 const& pj, Point1 const& pk, - Point2 const& qi, Point2 const& qj, Point2 const& qk, - bool /*is_p_first*/, bool /*is_p_last*/, - bool /*is_q_first*/, bool /*is_q_last*/, + UniqueSubRange1 const& range_p, + UniqueSubRange2 const& range_q, TurnInfo const& tp_model, IntersectionStrategy const& intersection_strategy, RobustPolicy const& robust_policy, @@ -961,13 +964,14 @@ struct get_turn_info { typedef intersection_info < - Point1, Point2, + UniqueSubRange1, UniqueSubRange2, typename TurnInfo::point_type, IntersectionStrategy, RobustPolicy > inters_info; - inters_info inters(pi, pj, pk, qi, qj, qk, intersection_strategy, robust_policy); + inters_info inters(range_p, range_q, + intersection_strategy, robust_policy); char const method = inters.d_info().how; @@ -984,7 +988,6 @@ struct get_turn_info && inters.i_info().count > 0) { only_convert::apply(tp, inters.i_info()); - AssignPolicy::apply(tp, pi, qi, inters); *out++ = tp; } break; @@ -1002,45 +1005,28 @@ struct get_turn_info // If Q (1) arrives (1) if ( inters.d_info().arrival[1] == 1 ) { - policy::template apply<0>(pi, pj, pk, qi, qj, qk, - tp, inters.i_info(), inters.d_info(), + policy::template apply<0>(range_p, range_q, tp, inters.i_info(), inters.d_info(), inters.sides()); } else { // Swap p/q - side_calculator - < - typename inters_info::cs_tag, - typename inters_info::robust_point2_type, - typename inters_info::robust_point1_type, - typename inters_info::side_strategy_type - > swapped_side_calc(inters.rqi(), inters.rqj(), inters.rqk(), - inters.rpi(), inters.rpj(), inters.rpk(), - inters.get_side_strategy()); - - policy::template apply<1>(qi, qj, qk, pi, pj, pk, - tp, inters.i_info(), inters.d_info(), - swapped_side_calc); + policy::template apply<1>(range_q, range_p, tp, inters.i_info(), inters.d_info(), + inters.get_swapped_sides()); } - AssignPolicy::apply(tp, pi, qi, inters); *out++ = tp; } break; case 'i' : { - crosses<TurnInfo>::apply(pi, pj, pk, qi, qj, qk, - tp, inters.i_info(), inters.d_info()); - AssignPolicy::apply(tp, pi, qi, inters); + crosses<TurnInfo>::apply(tp, inters.i_info(), inters.d_info()); *out++ = tp; } break; case 't' : { // Both touch (both arrive there) - touch<TurnInfo>::apply(pi, pj, pk, qi, qj, qk, - tp, inters.i_info(), inters.d_info(), inters.sides()); - AssignPolicy::apply(tp, pi, qi, inters); + touch<TurnInfo>::apply(range_p, range_q, tp, inters.i_info(), inters.d_info(), inters.sides()); *out++ = tp; } break; @@ -1050,9 +1036,7 @@ struct get_turn_info { // Both equal // or collinear-and-ending at intersection point - equal<TurnInfo>::apply(pi, pj, pk, qi, qj, qk, - tp, inters.i_info(), inters.d_info(), inters.sides()); - AssignPolicy::apply(tp, pi, qi, inters); + equal<TurnInfo>::apply(range_p, range_q, tp, inters.i_info(), inters.d_info(), inters.sides()); *out++ = tp; } else @@ -1061,8 +1045,7 @@ struct get_turn_info < TurnInfo, AssignPolicy - >::apply(pi, qi, - tp, out, inters); + >::apply(range_p, range_q, tp, out, inters); } } break; @@ -1075,19 +1058,18 @@ struct get_turn_info if ( inters.d_info().arrival[0] == 0 ) { // Collinear, but similar thus handled as equal - equal<TurnInfo>::apply(pi, pj, pk, qi, qj, qk, - tp, inters.i_info(), inters.d_info(), inters.sides()); + equal<TurnInfo>::apply(range_p, range_q, tp, + inters.i_info(), inters.d_info(), inters.sides()); // override assigned method tp.method = method_collinear; } else { - collinear<TurnInfo>::apply(pi, pj, pk, qi, qj, qk, - tp, inters.i_info(), inters.d_info(), inters.sides()); + collinear<TurnInfo>::apply(range_p, range_q, tp, + inters.i_info(), inters.d_info(), inters.sides()); } - AssignPolicy::apply(tp, pi, qi, inters); *out++ = tp; } else @@ -1096,7 +1078,7 @@ struct get_turn_info < TurnInfo, AssignPolicy - >::apply(pi, pj, pk, qi, qj, qk, + >::apply(range_p, range_q, tp, out, inters, inters.sides()); } } @@ -1107,7 +1089,6 @@ struct get_turn_info if (AssignPolicy::include_degenerate) { only_convert::apply(tp, inters.i_info()); - AssignPolicy::apply(tp, pi, qi, inters); *out++ = tp; } } diff --git a/boost/geometry/algorithms/detail/overlay/get_turn_info_for_endpoint.hpp b/boost/geometry/algorithms/detail/overlay/get_turn_info_for_endpoint.hpp index f9b4dee2cd..521744df88 100644 --- a/boost/geometry/algorithms/detail/overlay/get_turn_info_for_endpoint.hpp +++ b/boost/geometry/algorithms/detail/overlay/get_turn_info_for_endpoint.hpp @@ -2,8 +2,8 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. -// This file was modified by Oracle on 2013, 2014, 2017. -// Modifications copyright (c) 2013-2017 Oracle and/or its affiliates. +// This file was modified by Oracle on 2013, 2014, 2017, 2018. +// Modifications copyright (c) 2013-2018 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -15,8 +15,10 @@ #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_FOR_ENDPOINT_HPP #include <boost/core/ignore_unused.hpp> -#include <boost/geometry/core/assert.hpp> + +#include <boost/geometry/algorithms/detail/equals/point_point.hpp> #include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp> +#include <boost/geometry/core/assert.hpp> #include <boost/geometry/policies/robustness/no_rescale_policy.hpp> namespace boost { namespace geometry { @@ -109,11 +111,12 @@ namespace detail { namespace overlay { class linear_intersections { public: - template <typename Point1, typename Point2, typename IntersectionResult> + template <typename Point1, typename Point2, typename IntersectionResult, typename EqPPStrategy> linear_intersections(Point1 const& pi, Point2 const& qi, IntersectionResult const& result, - bool is_p_last, bool is_q_last) + bool is_p_last, bool is_q_last, + EqPPStrategy const& strategy) { int arrival_a = result.template get<1>().arrival[0]; int arrival_b = result.template get<1>().arrival[1]; @@ -133,10 +136,10 @@ public: ips[0].is_pi = equals::equals_point_point( - pi, result.template get<0>().intersections[0]); + pi, result.template get<0>().intersections[0], strategy); ips[0].is_qi = equals::equals_point_point( - qi, result.template get<0>().intersections[0]); + qi, result.template get<0>().intersections[0], strategy); ips[1].is_pj = arrival_a != -1; ips[1].is_qj = arrival_b != -1; } @@ -222,39 +225,53 @@ private: ip_info ips[2]; }; -template <typename AssignPolicy, bool EnableFirst, bool EnableLast> +template <bool EnableFirst, bool EnableLast> struct get_turn_info_for_endpoint { + typedef std::pair<operation_type, operation_type> operations_pair; + BOOST_STATIC_ASSERT(EnableFirst || EnableLast); - template<typename Point1, - typename Point2, + template<typename UniqueSubRange1, + typename UniqueSubRange2, typename TurnInfo, typename IntersectionInfo, - typename OutputIterator + typename OutputIterator, + typename EqPPStrategy > - static inline bool apply(Point1 const& pi, Point1 const& pj, Point1 const& pk, - Point2 const& qi, Point2 const& qj, Point2 const& qk, - bool is_p_first, bool is_p_last, - bool is_q_first, bool is_q_last, + static inline bool apply(UniqueSubRange1 const& range_p, + UniqueSubRange2 const& range_q, TurnInfo const& tp_model, IntersectionInfo const& inters, method_type /*method*/, - OutputIterator out) + OutputIterator out, + EqPPStrategy const& strategy) { std::size_t ip_count = inters.i_info().count; // no intersection points - if ( ip_count == 0 ) + if (ip_count == 0) + { return false; + } - if ( !is_p_first && !is_p_last && !is_q_first && !is_q_last ) + if (! range_p.is_first_segment() + && ! range_q.is_first_segment() + && ! range_p.is_last_segment() + && ! range_q.is_last_segment()) + { + // Not an end-point from segment p or q return false; + } - linear_intersections intersections(pi, qi, inters.result(), is_p_last, is_q_last); + linear_intersections intersections(range_p.at(0), + range_q.at(0), + inters.result(), + range_p.is_last_segment(), + range_q.is_last_segment(), + strategy); bool append0_last - = analyse_segment_and_assign_ip(pi, pj, pk, qi, qj, qk, - is_p_first, is_p_last, is_q_first, is_q_last, + = analyse_segment_and_assign_ip(range_p, range_q, intersections.template get<0>(), tp_model, inters, 0, out); @@ -268,8 +285,7 @@ struct get_turn_info_for_endpoint return result_ignore_ip0; bool append1_last - = analyse_segment_and_assign_ip(pi, pj, pk, qi, qj, qk, - is_p_first, is_p_last, is_q_first, is_q_last, + = analyse_segment_and_assign_ip(range_p, range_q, intersections.template get<1>(), tp_model, inters, 1, out); @@ -279,37 +295,25 @@ struct get_turn_info_for_endpoint return result_ignore_ip0 || result_ignore_ip1; } - template <typename Point1, - typename Point2, + template <typename UniqueSubRange1, + typename UniqueSubRange2, typename TurnInfo, typename IntersectionInfo, typename OutputIterator> static inline - bool analyse_segment_and_assign_ip(Point1 const& pi, Point1 const& pj, Point1 const& pk, - Point2 const& qi, Point2 const& qj, Point2 const& qk, - bool is_p_first, bool is_p_last, - bool is_q_first, bool is_q_last, + bool analyse_segment_and_assign_ip(UniqueSubRange1 const& range_p, + UniqueSubRange2 const& range_q, linear_intersections::ip_info const& ip_info, TurnInfo const& tp_model, IntersectionInfo const& inters, unsigned int ip_index, OutputIterator out) { -#ifdef BOOST_GEOMETRY_DEBUG_GET_TURNS_LINEAR_LINEAR - // may this give false positives for INTs? - typename IntersectionResult::point_type const& - inters_pt = result.template get<0>().intersections[ip_index]; - BOOST_GEOMETRY_ASSERT(ip_info.is_pi == equals::equals_point_point(pi, inters_pt)); - BOOST_GEOMETRY_ASSERT(ip_info.is_qi == equals::equals_point_point(qi, inters_pt)); - BOOST_GEOMETRY_ASSERT(ip_info.is_pj == equals::equals_point_point(pj, inters_pt)); - BOOST_GEOMETRY_ASSERT(ip_info.is_qj == equals::equals_point_point(qj, inters_pt)); -#endif - // TODO - calculate first/last only if needed - bool is_p_first_ip = is_p_first && ip_info.is_pi; - bool is_p_last_ip = is_p_last && ip_info.is_pj; - bool is_q_first_ip = is_q_first && ip_info.is_qi; - bool is_q_last_ip = is_q_last && ip_info.is_qj; + bool is_p_first_ip = range_p.is_first_segment() && ip_info.is_pi; + bool is_p_last_ip = range_p.is_last_segment() && ip_info.is_pj; + bool is_q_first_ip = range_q.is_first_segment() && ip_info.is_qi; + bool is_q_last_ip = range_q.is_last_segment() && ip_info.is_qj; bool append_first = EnableFirst && (is_p_first_ip || is_q_first_ip); bool append_last = EnableLast && (is_p_last_ip || is_q_last_ip); @@ -318,9 +322,7 @@ struct get_turn_info_for_endpoint if ( append_first || append_last ) { - bool handled = handle_internal<0>(pi, pj, pk, qi, qj, qk, - inters.rpi(), inters.rpj(), inters.rpk(), - inters.rqi(), inters.rqj(), inters.rqk(), + bool handled = handle_internal<0>(range_p, range_q, is_p_first_ip, is_p_last_ip, is_q_first_ip, is_q_last_ip, ip_info.is_qi, ip_info.is_qj, @@ -328,9 +330,8 @@ struct get_turn_info_for_endpoint p_operation, q_operation); if ( !handled ) { - handle_internal<1>(qi, qj, qk, pi, pj, pk, - inters.rqi(), inters.rqj(), inters.rqk(), - inters.rpi(), inters.rpj(), inters.rpk(), + // Reverse p/q + handle_internal<1>(range_q, range_p, is_q_first_ip, is_q_last_ip, is_p_first_ip, is_p_last_ip, ip_info.is_pi, ip_info.is_pj, @@ -348,31 +349,29 @@ struct get_turn_info_for_endpoint // handle spikes // P is spike and should be handled - if ( !is_p_last - && ip_info.is_pj // this check is redundant (also in is_spike_p) but faster + if (ip_info.is_pj // this check is redundant (also in is_spike_p) but faster && inters.i_info().count == 2 && inters.is_spike_p() ) { - assign(pi, qi, inters.result(), ip_index, method, operation_blocked, q_operation, + assign(inters.result(), ip_index, method, operation_blocked, q_operation, p_pos, q_pos, is_p_first_ip, is_q_first_ip, true, false, tp_model, out); - assign(pi, qi, inters.result(), ip_index, method, operation_intersection, q_operation, + assign(inters.result(), ip_index, method, operation_intersection, q_operation, p_pos, q_pos, is_p_first_ip, is_q_first_ip, true, false, tp_model, out); } // Q is spike and should be handled - else if ( !is_q_last - && ip_info.is_qj // this check is redundant (also in is_spike_q) but faster + else if (ip_info.is_qj // this check is redundant (also in is_spike_q) but faster && inters.i_info().count == 2 && inters.is_spike_q() ) { - assign(pi, qi, inters.result(), ip_index, method, p_operation, operation_blocked, + assign(inters.result(), ip_index, method, p_operation, operation_blocked, p_pos, q_pos, is_p_first_ip, is_q_first_ip, false, true, tp_model, out); - assign(pi, qi, inters.result(), ip_index, method, p_operation, operation_intersection, + assign(inters.result(), ip_index, method, p_operation, operation_intersection, p_pos, q_pos, is_p_first_ip, is_q_first_ip, false, true, tp_model, out); } // no spikes else { - assign(pi, qi, inters.result(), ip_index, method, p_operation, q_operation, + assign(inters.result(), ip_index, method, p_operation, q_operation, p_pos, q_pos, is_p_first_ip, is_q_first_ip, false, false, tp_model, out); } } @@ -385,25 +384,22 @@ struct get_turn_info_for_endpoint // however now it's lazily calculated and then it would be always calculated template<std::size_t G1Index, - typename Point1, - typename Point2, - typename RobustPoint1, - typename RobustPoint2, + typename UniqueRange1, + typename UniqueRange2, typename TurnInfo, typename IntersectionInfo > - static inline bool handle_internal(Point1 const& /*i1*/, Point1 const& /*j1*/, Point1 const& /*k1*/, - Point2 const& i2, Point2 const& j2, Point2 const& /*k2*/, - RobustPoint1 const& ri1, RobustPoint1 const& rj1, RobustPoint1 const& /*rk1*/, - RobustPoint2 const& ri2, RobustPoint2 const& rj2, RobustPoint2 const& rk2, + static inline bool handle_internal(UniqueRange1 const& range1, + UniqueRange2 const& range2, bool first1, bool last1, bool first2, bool last2, bool ip_i2, bool ip_j2, TurnInfo const& tp_model, IntersectionInfo const& inters, unsigned int ip_index, operation_type & op1, operation_type & op2) { - typedef typename cs_tag<typename TurnInfo::point_type>::type cs_tag; + boost::ignore_unused(ip_index, tp_model); - boost::ignore_unused(i2, j2, ip_index, tp_model); + typename IntersectionInfo::side_strategy_type const& sides + = inters.get_side_strategy(); if ( !first2 && !last2 ) { @@ -425,14 +421,11 @@ struct get_turn_info_for_endpoint } else if ( ip_j2 ) { - side_calculator<cs_tag, - RobustPoint1, RobustPoint2, - typename IntersectionInfo::side_strategy_type, - RobustPoint2> - side_calc(ri2, ri1, rj1, ri2, rj2, rk2, inters.get_side_strategy()); + int const side_pj_q2 = sides.apply(range2.at(1), range2.at(2), range1.at(1)); + int const side_pj_q1 = sides.apply(range2.at(0), range2.at(1), range1.at(1)); + int const side_qk_q1 = sides.apply(range2.at(0), range2.at(1), range2.at(2)); - std::pair<operation_type, operation_type> - operations = operations_of_equal(side_calc); + operations_pair operations = operations_of_equal(side_pj_q2, side_pj_q1, side_qk_q1); // TODO: must the above be calculated? // wouldn't it be enough to check if segments are collinear? @@ -479,13 +472,11 @@ struct get_turn_info_for_endpoint } else if ( ip_j2 ) { - side_calculator<cs_tag, RobustPoint1, RobustPoint2, - typename IntersectionInfo::side_strategy_type, - RobustPoint2> - side_calc(ri2, rj1, ri1, ri2, rj2, rk2, inters.get_side_strategy()); - - std::pair<operation_type, operation_type> - operations = operations_of_equal(side_calc); + int const side_pi_q2 = sides.apply(range2.at(1), range2.at(2), range1.at(0)); + int const side_pi_q1 = sides.apply(range2.at(0), range2.at(1), range1.at(0)); + int const side_qk_q1 = sides.apply(range2.at(0), range2.at(1), range2.at(2)); + + operations_pair operations = operations_of_equal(side_pi_q2, side_pi_q1, side_qk_q1); // TODO: must the above be calculated? // wouldn't it be enough to check if segments are collinear? @@ -534,13 +525,10 @@ struct get_turn_info_for_endpoint ( is_ip_last_j ? position_back : position_middle ); } - template <typename Point1, - typename Point2, - typename IntersectionResult, + template <typename IntersectionResult, typename TurnInfo, typename OutputIterator> - static inline void assign(Point1 const& pi, Point2 const& qi, - IntersectionResult const& result, + static inline void assign(IntersectionResult const& result, unsigned int ip_index, method_type method, operation_type op0, operation_type op1, @@ -591,33 +579,27 @@ struct get_turn_info_for_endpoint } } - // TODO: this should get an intersection_info, which is unavailable here - // Because the assign_null policy accepts any structure, we pass the result instead for now - AssignPolicy::apply(tp, pi, qi, result); *out++ = tp; } - template <typename SidePolicy> - static inline std::pair<operation_type, operation_type> operations_of_equal(SidePolicy const& side) + static inline operations_pair operations_of_equal(int side_px_q2, + int side_px_q1, + int side_qk_q1) { - int const side_pk_q2 = side.pk_wrt_q2(); - int const side_pk_p = side.pk_wrt_p1(); - int const side_qk_p = side.qk_wrt_p1(); - - // If pk is collinear with qj-qk, they continue collinearly. - // This can be on either side of p1 (== q1), or collinear + // If px (pi or pj) is collinear with qj-qk (q2), they continue collinearly. + // This can be on either side of q1, or collinear // The second condition checks if they do not continue // oppositely - if ( side_pk_q2 == 0 && side_pk_p == side_qk_p ) + if (side_px_q2 == 0 && side_px_q1 == side_qk_q1) { return std::make_pair(operation_continue, operation_continue); } // If they turn to same side (not opposite sides) - if ( ! base_turn_handler::opposite(side_pk_p, side_qk_p) ) + if ( ! base_turn_handler::opposite(side_px_q1, side_qk_q1) ) { - // If pk is left of q2 or collinear: p: union, q: intersection - if ( side_pk_q2 != -1 ) + // If px is left of q2 or collinear: p: union, q: intersection + if (side_px_q2 != -1 ) { return std::make_pair(operation_union, operation_intersection); } @@ -630,7 +612,7 @@ struct get_turn_info_for_endpoint { // They turn opposite sides. If p turns left (or collinear), // p: union, q: intersection - if ( side_pk_p != -1 ) + if (side_px_q1 != -1 ) { return std::make_pair(operation_union, operation_intersection); } @@ -641,16 +623,15 @@ struct get_turn_info_for_endpoint } } - static inline bool operations_both( - std::pair<operation_type, operation_type> const& operations, - operation_type const op) + static inline bool operations_both(operations_pair const& operations, + operation_type const op) { return operations.first == op && operations.second == op; } - static inline bool operations_combination( - std::pair<operation_type, operation_type> const& operations, - operation_type const op1, operation_type const op2) + static inline bool operations_combination(operations_pair const& operations, + operation_type const op1, + operation_type const op2) { return ( operations.first == op1 && operations.second == op2 ) || ( operations.first == op2 && operations.second == op1 ); diff --git a/boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp b/boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp index f8247cd240..087ca80602 100644 --- a/boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp +++ b/boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp @@ -2,8 +2,8 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. -// This file was modified by Oracle on 2013, 2014, 2015, 2017. -// Modifications copyright (c) 2013-2017 Oracle and/or its affiliates. +// This file was modified by Oracle on 2013, 2014, 2015, 2017, 2018. +// Modifications copyright (c) 2013-2018 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -14,7 +14,16 @@ #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_HELPERS_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_HELPERS_HPP +#include <boost/geometry/algorithms/detail/direction_code.hpp> +#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp> +#include <boost/geometry/algorithms/detail/recalculate.hpp> +#include <boost/geometry/core/assert.hpp> +#include <boost/geometry/geometries/segment.hpp> // referring_segment +#include <boost/geometry/policies/relate/direction.hpp> +#include <boost/geometry/policies/relate/intersection_points.hpp> +#include <boost/geometry/policies/relate/tupled.hpp> #include <boost/geometry/policies/robustness/no_rescale_policy.hpp> +#include <boost/geometry/strategies/intersection_result.hpp> namespace boost { namespace geometry { @@ -36,183 +45,324 @@ struct turn_operation_linear bool is_collinear; // valid only for Linear geometry }; -template <typename TurnPointCSTag, typename PointP, typename PointQ, - typename SideStrategy, - typename Pi = PointP, typename Pj = PointP, typename Pk = PointP, - typename Qi = PointQ, typename Qj = PointQ, typename Qk = PointQ +template +< + typename TurnPointCSTag, + typename UniqueSubRange1, + typename UniqueSubRange2, + typename SideStrategy > struct side_calculator { - inline side_calculator(Pi const& pi, Pj const& pj, Pk const& pk, - Qi const& qi, Qj const& qj, Qk const& qk, + typedef typename UniqueSubRange1::point_type point1_type; + typedef typename UniqueSubRange2::point_type point2_type; + + inline side_calculator(UniqueSubRange1 const& range_p, + UniqueSubRange2 const& range_q, SideStrategy const& side_strategy) - : m_pi(pi), m_pj(pj), m_pk(pk) - , m_qi(qi), m_qj(qj), m_qk(qk) - , m_side_strategy(side_strategy) + : m_side_strategy(side_strategy) + , m_range_p(range_p) + , m_range_q(range_q) {} - inline int pk_wrt_p1() const { return m_side_strategy.apply(m_pi, m_pj, m_pk); } - inline int pk_wrt_q1() const { return m_side_strategy.apply(m_qi, m_qj, m_pk); } - inline int qk_wrt_p1() const { return m_side_strategy.apply(m_pi, m_pj, m_qk); } - inline int qk_wrt_q1() const { return m_side_strategy.apply(m_qi, m_qj, m_qk); } + inline int pk_wrt_p1() const { return m_side_strategy.apply(get_pi(), get_pj(), get_pk()); } + inline int pk_wrt_q1() const { return m_side_strategy.apply(get_qi(), get_qj(), get_pk()); } + inline int qk_wrt_p1() const { return m_side_strategy.apply(get_pi(), get_pj(), get_qk()); } + inline int qk_wrt_q1() const { return m_side_strategy.apply(get_qi(), get_qj(), get_qk()); } - inline int pk_wrt_q2() const { return m_side_strategy.apply(m_qj, m_qk, m_pk); } - inline int qk_wrt_p2() const { return m_side_strategy.apply(m_pj, m_pk, m_qk); } + inline int pk_wrt_q2() const { return m_side_strategy.apply(get_qj(), get_qk(), get_pk()); } + inline int qk_wrt_p2() const { return m_side_strategy.apply(get_pj(), get_pk(), get_qk()); } - Pi const& m_pi; - Pj const& m_pj; - Pk const& m_pk; - Qi const& m_qi; - Qj const& m_qj; - Qk const& m_qk; + // Necessary when rescaling turns off: + inline int qj_wrt_p1() const { return m_side_strategy.apply(get_pi(), get_pj(), get_qj()); } + inline int qj_wrt_p2() const { return m_side_strategy.apply(get_pj(), get_pk(), get_qj()); } + inline int pj_wrt_q1() const { return m_side_strategy.apply(get_qi(), get_qj(), get_pj()); } + inline int pj_wrt_q2() const { return m_side_strategy.apply(get_qj(), get_qk(), get_pj()); } + inline point1_type const& get_pi() const { return m_range_p.at(0); } + inline point1_type const& get_pj() const { return m_range_p.at(1); } + inline point1_type const& get_pk() const { return m_range_p.at(2); } + + inline point2_type const& get_qi() const { return m_range_q.at(0); } + inline point2_type const& get_qj() const { return m_range_q.at(1); } + inline point2_type const& get_qk() const { return m_range_q.at(2); } + + // Used side-strategy, owned by the calculator, + // created from .get_side_strategy() SideStrategy m_side_strategy; + + // Used ranges - owned by get_turns or (for robust points) by intersection_info_base + UniqueSubRange1 const& m_range_p; + UniqueSubRange2 const& m_range_q; }; -template <typename Point1, typename Point2, typename RobustPolicy> +template<typename Point, typename UniqueSubRange, typename RobustPolicy> +struct robust_subrange_adapter +{ + typedef Point point_type; + + robust_subrange_adapter(UniqueSubRange const& unique_sub_range, + Point const& robust_point_i, Point const& robust_point_j, + RobustPolicy const& robust_policy) + + : m_unique_sub_range(unique_sub_range) + , m_robust_policy(robust_policy) + , m_robust_point_i(robust_point_i) + , m_robust_point_j(robust_point_j) + , m_k_retrieved(false) + {} + + std::size_t size() const { return m_unique_sub_range.size(); } + + //! Get precalculated point + Point const& at(std::size_t index) const + { + BOOST_GEOMETRY_ASSERT(index < size()); + switch (index) + { + case 0 : return m_robust_point_i; + case 1 : return m_robust_point_j; + case 2 : return get_point_k(); + default : return m_robust_point_i; + } + } + +private : + Point const& get_point_k() const + { + if (! m_k_retrieved) + { + geometry::recalculate(m_robust_point_k, m_unique_sub_range.at(2), m_robust_policy); + m_k_retrieved = true; + } + return m_robust_point_k; + } + + UniqueSubRange const& m_unique_sub_range; + RobustPolicy const& m_robust_policy; + + Point const& m_robust_point_i; + Point const& m_robust_point_j; + mutable Point m_robust_point_k; + + mutable bool m_k_retrieved; +}; + +template +< + typename UniqueSubRange1, typename UniqueSubRange2, + typename RobustPolicy +> struct robust_points { typedef typename geometry::robust_point_type < - Point1, RobustPolicy + typename UniqueSubRange1::point_type, RobustPolicy >::type robust_point1_type; - // TODO: define robust_point2_type using Point2? typedef robust_point1_type robust_point2_type; - inline robust_points(Point1 const& pi, Point1 const& pj, Point1 const& pk, - Point2 const& qi, Point2 const& qj, Point2 const& qk, + inline robust_points(UniqueSubRange1 const& range_p, + UniqueSubRange2 const& range_q, RobustPolicy const& robust_policy) + : m_robust_policy(robust_policy) + , m_range_p(range_p) + , m_range_q(range_q) + , m_pk_retrieved(false) + , m_qk_retrieved(false) + { + // Calculate pi,pj and qi,qj which are almost always necessary + // But don't calculate pk/qk yet, which is retrieved (taking + // more time) and not always necessary. + geometry::recalculate(m_rpi, range_p.at(0), robust_policy); + geometry::recalculate(m_rpj, range_p.at(1), robust_policy); + geometry::recalculate(m_rqi, range_q.at(0), robust_policy); + geometry::recalculate(m_rqj, range_q.at(1), robust_policy); + } + + inline robust_point1_type const& get_rpk() const { - geometry::recalculate(m_rpi, pi, robust_policy); - geometry::recalculate(m_rpj, pj, robust_policy); - geometry::recalculate(m_rpk, pk, robust_policy); - geometry::recalculate(m_rqi, qi, robust_policy); - geometry::recalculate(m_rqj, qj, robust_policy); - geometry::recalculate(m_rqk, qk, robust_policy); + if (! m_pk_retrieved) + { + geometry::recalculate(m_rpk, m_range_p.at(2), m_robust_policy); + m_pk_retrieved = true; + } + return m_rpk; } + inline robust_point2_type const& get_rqk() const + { + if (! m_qk_retrieved) + { + geometry::recalculate(m_rqk, m_range_q.at(2), m_robust_policy); + m_qk_retrieved = true; + } + return m_rqk; + } + + robust_point1_type m_rpi, m_rpj; + robust_point2_type m_rqi, m_rqj; - robust_point1_type m_rpi, m_rpj, m_rpk; - robust_point2_type m_rqi, m_rqj, m_rqk; +private : + RobustPolicy const& m_robust_policy; + UniqueSubRange1 const& m_range_p; + UniqueSubRange2 const& m_range_q; + + // On retrieval + mutable robust_point1_type m_rpk; + mutable robust_point2_type m_rqk; + mutable bool m_pk_retrieved; + mutable bool m_qk_retrieved; }; -template <typename Point1, typename Point2, typename TurnPoint, typename IntersectionStrategy, typename RobustPolicy> +template +< + typename UniqueSubRange1, typename UniqueSubRange2, + typename TurnPoint, typename IntersectionStrategy, typename RobustPolicy> class intersection_info_base - : private robust_points<Point1, Point2, RobustPolicy> + : private robust_points<UniqueSubRange1, UniqueSubRange2, RobustPolicy> { - typedef robust_points<Point1, Point2, RobustPolicy> base; + typedef robust_points<UniqueSubRange1, UniqueSubRange2, RobustPolicy> base; public: - typedef Point1 point1_type; - typedef Point2 point2_type; - typedef typename base::robust_point1_type robust_point1_type; typedef typename base::robust_point2_type robust_point2_type; + typedef robust_subrange_adapter<robust_point1_type, UniqueSubRange1, RobustPolicy> robust_subrange1; + typedef robust_subrange_adapter<robust_point2_type, UniqueSubRange2, RobustPolicy> robust_subrange2; + typedef typename cs_tag<TurnPoint>::type cs_tag; typedef typename IntersectionStrategy::side_strategy_type side_strategy_type; - typedef side_calculator<cs_tag, robust_point1_type, robust_point2_type, side_strategy_type> side_calculator_type; - - intersection_info_base(Point1 const& pi, Point1 const& pj, Point1 const& pk, - Point2 const& qi, Point2 const& qj, Point2 const& qk, + typedef side_calculator<cs_tag, robust_subrange1, robust_subrange2, + side_strategy_type> side_calculator_type; + + typedef side_calculator + < + cs_tag, robust_subrange2, robust_subrange1, + side_strategy_type + > robust_swapped_side_calculator_type; + + intersection_info_base(UniqueSubRange1 const& range_p, + UniqueSubRange2 const& range_q, IntersectionStrategy const& intersection_strategy, RobustPolicy const& robust_policy) - : base(pi, pj, pk, qi, qj, qk, robust_policy) - , m_side_calc(base::m_rpi, base::m_rpj, base::m_rpk, - base::m_rqi, base::m_rqj, base::m_rqk, + : base(range_p, range_q, robust_policy) + , m_range_p(range_p) + , m_range_q(range_q) + , m_robust_range_p(range_p, base::m_rpi, base::m_rpj, robust_policy) + , m_robust_range_q(range_q, base::m_rqi, base::m_rqj, robust_policy) + , m_side_calc(m_robust_range_p, m_robust_range_q, intersection_strategy.get_side_strategy()) - , m_pi(pi), m_pj(pj), m_pk(pk) - , m_qi(qi), m_qj(qj), m_qk(qk) {} - inline Point1 const& pi() const { return m_pi; } - inline Point1 const& pj() const { return m_pj; } - inline Point1 const& pk() const { return m_pk; } - - inline Point2 const& qi() const { return m_qi; } - inline Point2 const& qj() const { return m_qj; } - inline Point2 const& qk() const { return m_qk; } + inline typename UniqueSubRange1::point_type const& pi() const { return m_range_p.at(0); } + inline typename UniqueSubRange2::point_type const& qi() const { return m_range_q.at(0); } inline robust_point1_type const& rpi() const { return base::m_rpi; } inline robust_point1_type const& rpj() const { return base::m_rpj; } - inline robust_point1_type const& rpk() const { return base::m_rpk; } + inline robust_point1_type const& rpk() const { return base::get_rpk(); } inline robust_point2_type const& rqi() const { return base::m_rqi; } inline robust_point2_type const& rqj() const { return base::m_rqj; } - inline robust_point2_type const& rqk() const { return base::m_rqk; } + inline robust_point2_type const& rqk() const { return base::get_rqk(); } inline side_calculator_type const& sides() const { return m_side_calc; } -private: - side_calculator_type m_side_calc; + robust_swapped_side_calculator_type get_swapped_sides() const + { + robust_swapped_side_calculator_type result( + m_robust_range_q, m_robust_range_p, + m_side_calc.m_side_strategy); + return result; + } - point1_type const& m_pi; - point1_type const& m_pj; - point1_type const& m_pk; - point2_type const& m_qi; - point2_type const& m_qj; - point2_type const& m_qk; + // Owned by get_turns + UniqueSubRange1 const& m_range_p; + UniqueSubRange2 const& m_range_q; +private : + // Owned by this class + robust_subrange1 m_robust_range_p; + robust_subrange2 m_robust_range_q; + side_calculator_type m_side_calc; }; -template <typename Point1, typename Point2, typename TurnPoint, typename IntersectionStrategy> -class intersection_info_base<Point1, Point2, TurnPoint, IntersectionStrategy, detail::no_rescale_policy> +template +< + typename UniqueSubRange1, typename UniqueSubRange2, + typename TurnPoint, typename IntersectionStrategy +> +class intersection_info_base<UniqueSubRange1, UniqueSubRange2, + TurnPoint, IntersectionStrategy, detail::no_rescale_policy> { public: - typedef Point1 point1_type; - typedef Point2 point2_type; + typedef typename UniqueSubRange1::point_type point1_type; + typedef typename UniqueSubRange2::point_type point2_type; - typedef Point1 robust_point1_type; - typedef Point2 robust_point2_type; + typedef typename UniqueSubRange1::point_type robust_point1_type; + typedef typename UniqueSubRange2::point_type robust_point2_type; typedef typename cs_tag<TurnPoint>::type cs_tag; typedef typename IntersectionStrategy::side_strategy_type side_strategy_type; - typedef side_calculator<cs_tag, Point1, Point2, side_strategy_type> side_calculator_type; + typedef side_calculator<cs_tag, UniqueSubRange1, UniqueSubRange2, side_strategy_type> side_calculator_type; + + typedef side_calculator + < + cs_tag, UniqueSubRange2, UniqueSubRange1, + side_strategy_type + > swapped_side_calculator_type; - intersection_info_base(Point1 const& pi, Point1 const& pj, Point1 const& pk, - Point2 const& qi, Point2 const& qj, Point2 const& qk, + intersection_info_base(UniqueSubRange1 const& range_p, + UniqueSubRange2 const& range_q, IntersectionStrategy const& intersection_strategy, no_rescale_policy const& /*robust_policy*/) - : m_side_calc(pi, pj, pk, qi, qj, qk, + : m_range_p(range_p) + , m_range_q(range_q) + , m_side_calc(range_p, range_q, intersection_strategy.get_side_strategy()) {} - inline Point1 const& pi() const { return m_side_calc.m_pi; } - inline Point1 const& pj() const { return m_side_calc.m_pj; } - inline Point1 const& pk() const { return m_side_calc.m_pk; } + inline point1_type const& rpi() const { return m_side_calc.get_pi(); } + inline point1_type const& rpj() const { return m_side_calc.get_pj(); } + inline point1_type const& rpk() const { return m_side_calc.get_pk(); } - inline Point2 const& qi() const { return m_side_calc.m_qi; } - inline Point2 const& qj() const { return m_side_calc.m_qj; } - inline Point2 const& qk() const { return m_side_calc.m_qk; } + inline point2_type const& rqi() const { return m_side_calc.get_qi(); } + inline point2_type const& rqj() const { return m_side_calc.get_qj(); } + inline point2_type const& rqk() const { return m_side_calc.get_qk(); } - inline Point1 const& rpi() const { return pi(); } - inline Point1 const& rpj() const { return pj(); } - inline Point1 const& rpk() const { return pk(); } + inline side_calculator_type const& sides() const { return m_side_calc; } - inline Point2 const& rqi() const { return qi(); } - inline Point2 const& rqj() const { return qj(); } - inline Point2 const& rqk() const { return qk(); } + swapped_side_calculator_type get_swapped_sides() const + { + swapped_side_calculator_type result( + m_range_q, m_range_p, + m_side_calc.m_side_strategy); + return result; + } - inline side_calculator_type const& sides() const { return m_side_calc; } - -private: +protected : + // Owned by get_turns + UniqueSubRange1 const& m_range_p; + UniqueSubRange2 const& m_range_q; +private : + // Owned here, passed by .get_side_strategy() side_calculator_type m_side_calc; }; template < - typename Point1, - typename Point2, + typename UniqueSubRange1, typename UniqueSubRange2, typename TurnPoint, typename IntersectionStrategy, typename RobustPolicy > class intersection_info - : public intersection_info_base<Point1, Point2, TurnPoint, IntersectionStrategy, RobustPolicy> + : public intersection_info_base<UniqueSubRange1, UniqueSubRange2, + TurnPoint, IntersectionStrategy, RobustPolicy> { - typedef intersection_info_base<Point1, Point2, TurnPoint, IntersectionStrategy, RobustPolicy> base; + typedef intersection_info_base<UniqueSubRange1, UniqueSubRange2, + TurnPoint, IntersectionStrategy, RobustPolicy> base; public: typedef segment_intersection_points @@ -224,6 +374,9 @@ public: >::type > intersection_point_type; + typedef typename UniqueSubRange1::point_type point1_type; + typedef typename UniqueSubRange2::point_type point2_type; + // NOTE: formerly defined in intersection_strategies typedef policies::relate::segments_tupled < @@ -237,22 +390,23 @@ public: typedef IntersectionStrategy intersection_strategy_type; typedef typename IntersectionStrategy::side_strategy_type side_strategy_type; - typedef model::referring_segment<Point1 const> segment_type1; - typedef model::referring_segment<Point2 const> segment_type2; + typedef model::referring_segment<point1_type const> segment_type1; + typedef model::referring_segment<point2_type const> segment_type2; typedef typename base::side_calculator_type side_calculator_type; typedef typename intersection_policy_type::return_type result_type; typedef typename boost::tuples::element<0, result_type>::type i_info_type; // intersection_info typedef typename boost::tuples::element<1, result_type>::type d_info_type; // dir_info - intersection_info(Point1 const& pi, Point1 const& pj, Point1 const& pk, - Point2 const& qi, Point2 const& qj, Point2 const& qk, + intersection_info(UniqueSubRange1 const& range_p, + UniqueSubRange2 const& range_q, IntersectionStrategy const& intersection_strategy, RobustPolicy const& robust_policy) - : base(pi, pj, pk, qi, qj, qk, intersection_strategy, robust_policy) + : base(range_p, range_q, + intersection_strategy, robust_policy) , m_result(intersection_strategy.apply( - segment_type1(pi, pj), - segment_type2(qi, qj), + segment_type1(range_p.at(0), range_p.at(1)), + segment_type2(range_q.at(0), range_q.at(1)), intersection_policy_type(), robust_policy, base::rpi(), base::rpj(), @@ -265,11 +419,6 @@ public: inline i_info_type const& i_info() const { return m_result.template get<0>(); } inline d_info_type const& d_info() const { return m_result.template get<1>(); } - inline intersection_strategy_type const& get_intersection_strategy() const - { - return m_intersection_strategy; - } - inline side_strategy_type get_side_strategy() const { return m_intersection_strategy.get_side_strategy(); @@ -278,24 +427,36 @@ public: // TODO: it's more like is_spike_ip_p inline bool is_spike_p() const { + if (base::m_range_p.is_last_segment()) + { + return false; + } if (base::sides().pk_wrt_p1() == 0) { + // p: pi--------pj--------pk + // or: pi----pk==pj + if (! is_ip_j<0>()) { return false; } - int const qk_p1 = base::sides().qk_wrt_p1(); - int const qk_p2 = base::sides().qk_wrt_p2(); - + // TODO: why is q used to determine spike property in p? + bool const has_qk = ! base::m_range_q.is_last_segment(); + int const qk_p1 = has_qk ? base::sides().qk_wrt_p1() : 0; + int const qk_p2 = has_qk ? base::sides().qk_wrt_p2() : 0; + if (qk_p1 == -qk_p2) { if (qk_p1 == 0) { - return is_spike_of_collinear(base::pi(), base::pj(), - base::pk()); + // qk is collinear with both p1 and p2, + // verify if pk goes backwards w.r.t. pi/pj + return direction_code(base::rpi(), base::rpj(), base::rpk()) == -1; } - + + // qk is at opposite side of p1/p2, therefore + // p1/p2 (collinear) are opposite and form a spike return true; } } @@ -303,9 +464,14 @@ public: return false; } - // TODO: it's more like is_spike_ip_q inline bool is_spike_q() const { + if (base::m_range_q.is_last_segment()) + { + return false; + } + + // See comments at is_spike_p if (base::sides().qk_wrt_q1() == 0) { if (! is_ip_j<1>()) @@ -313,15 +479,16 @@ public: return false; } - int const pk_q1 = base::sides().pk_wrt_q1(); - int const pk_q2 = base::sides().pk_wrt_q2(); + // TODO: why is p used to determine spike property in q? + bool const has_pk = ! base::m_range_p.is_last_segment(); + int const pk_q1 = has_pk ? base::sides().pk_wrt_q1() : 0; + int const pk_q2 = has_pk ? base::sides().pk_wrt_q2() : 0; if (pk_q1 == -pk_q2) { if (pk_q1 == 0) { - return is_spike_of_collinear(base::qi(), base::qj(), - base::qk()); + return direction_code(base::rqi(), base::rqj(), base::rqk()) == -1; } return true; @@ -332,26 +499,6 @@ public: } private: - template <typename Point> - inline bool is_spike_of_collinear(Point const& i, Point const& j, - Point const& k) const - { - typedef model::referring_segment<Point const> seg; - - // no need to calcualte direction info - typedef policies::relate::segments_intersection_points - < - intersection_point_type - > policy_type; - - typename policy_type::return_type const result - = m_intersection_strategy.apply(seg(i, j), seg(j, k), - policy_type(), - m_robust_policy); - - return result.count == 2; - } - template <std::size_t OpId> bool is_ip_j() const { diff --git a/boost/geometry/algorithms/detail/overlay/get_turn_info_la.hpp b/boost/geometry/algorithms/detail/overlay/get_turn_info_la.hpp index 46c1305cd7..f8272794bd 100644 --- a/boost/geometry/algorithms/detail/overlay/get_turn_info_la.hpp +++ b/boost/geometry/algorithms/detail/overlay/get_turn_info_la.hpp @@ -3,8 +3,8 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland. -// This file was modified by Oracle on 2013, 2014, 2015, 2017. -// Modifications copyright (c) 2013-2017 Oracle and/or its affiliates. +// This file was modified by Oracle on 2013, 2014, 2015, 2017, 2018. +// Modifications copyright (c) 2013-2018 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -41,32 +41,30 @@ struct get_turn_info_linear_areal template < - typename Point1, - typename Point2, + typename UniqueSubRange1, + typename UniqueSubRange2, typename TurnInfo, typename IntersectionStrategy, typename RobustPolicy, typename OutputIterator > static inline OutputIterator apply( - Point1 const& pi, Point1 const& pj, Point1 const& pk, - Point2 const& qi, Point2 const& qj, Point2 const& qk, - bool is_p_first, bool is_p_last, - bool is_q_first, bool is_q_last, + UniqueSubRange1 const& range_p, + UniqueSubRange2 const& range_q, TurnInfo const& tp_model, - IntersectionStrategy const& intersection_strategy, + IntersectionStrategy const& strategy, RobustPolicy const& robust_policy, OutputIterator out) { typedef intersection_info < - Point1, Point2, + UniqueSubRange1, UniqueSubRange2, typename TurnInfo::point_type, IntersectionStrategy, RobustPolicy > inters_info; - inters_info inters(pi, pj, pk, qi, qj, qk, intersection_strategy, robust_policy); + inters_info inters(range_p, range_q, strategy, robust_policy); char const method = inters.d_info().how; @@ -79,10 +77,9 @@ struct get_turn_info_linear_areal case 'a' : // collinear, "at" case 'f' : // collinear, "from" case 's' : // starts from the middle - get_turn_info_for_endpoint<true, true>( - pi, pj, pk, qi, qj, qk, - is_p_first, is_p_last, is_q_first, is_q_last, - tp_model, inters, method_none, out); + get_turn_info_for_endpoint<true, true>(range_p, range_q, + tp_model, inters, method_none, out, + strategy.get_point_in_point_strategy()); break; case 'd' : // disjoint: never do anything @@ -90,10 +87,9 @@ struct get_turn_info_linear_areal case 'm' : { - if ( get_turn_info_for_endpoint<false, true>( - pi, pj, pk, qi, qj, qk, - is_p_first, is_p_last, is_q_first, is_q_last, - tp_model, inters, method_touch_interior, out) ) + if ( get_turn_info_for_endpoint<false, true>(range_p, range_q, + tp_model, inters, method_touch_interior, out, + strategy.get_point_in_point_strategy()) ) { // do nothing } @@ -107,25 +103,16 @@ struct get_turn_info_linear_areal // If Q (1) arrives (1) if ( inters.d_info().arrival[1] == 1 ) { - policy::template apply<0>(pi, pj, pk, qi, qj, qk, - tp, inters.i_info(), inters.d_info(), + policy::template apply<0>(range_p, range_q, tp, + inters.i_info(), inters.d_info(), inters.sides()); } else { // Swap p/q - side_calculator - < - typename inters_info::cs_tag, - typename inters_info::robust_point2_type, - typename inters_info::robust_point1_type, - typename inters_info::side_strategy_type - > swapped_side_calc(inters.rqi(), inters.rqj(), inters.rqk(), - inters.rpi(), inters.rpj(), inters.rpk(), - inters.get_side_strategy()); - policy::template apply<1>(qi, qj, qk, pi, pj, pk, + policy::template apply<1>(range_q, range_p, tp, inters.i_info(), inters.d_info(), - swapped_side_calc); + inters.get_swapped_sides()); } if ( tp.operations[1].operation == operation_blocked ) @@ -139,39 +126,35 @@ struct get_turn_info_linear_areal // this function assumes that 'u' must be set for a spike calculate_spike_operation(tp.operations[0].operation, - inters, is_p_last); + inters, + strategy.get_point_in_point_strategy()); - AssignPolicy::apply(tp, pi, qi, inters); - *out++ = tp; } } break; case 'i' : { - crosses<TurnInfo>::apply(pi, pj, pk, qi, qj, qk, - tp, inters.i_info(), inters.d_info()); + crosses<TurnInfo>::apply(tp, inters.i_info(), inters.d_info()); replace_operations_i(tp.operations[0].operation, tp.operations[1].operation); - AssignPolicy::apply(tp, pi, qi, inters); *out++ = tp; } break; case 't' : { // Both touch (both arrive there) - if ( get_turn_info_for_endpoint<false, true>( - pi, pj, pk, qi, qj, qk, - is_p_first, is_p_last, is_q_first, is_q_last, - tp_model, inters, method_touch, out) ) + if ( get_turn_info_for_endpoint<false, true>(range_p, range_q, + tp_model, inters, method_touch, out, + strategy.get_point_in_point_strategy()) ) { // do nothing } else { - touch<TurnInfo>::apply(pi, pj, pk, qi, qj, qk, - tp, inters.i_info(), inters.d_info(), inters.sides()); + touch<TurnInfo>::apply(range_p, range_q, tp, + inters.i_info(), inters.d_info(), inters.sides()); if ( tp.operations[1].operation == operation_blocked ) { @@ -236,15 +219,13 @@ struct get_turn_info_linear_areal bool ignore_spike = calculate_spike_operation(tp.operations[0].operation, - inters, is_p_last); - -// TODO: move this into the append_xxx and call for each turn? - AssignPolicy::apply(tp, pi, qi, inters); + inters, + strategy.get_point_in_point_strategy()); if ( ! BOOST_GEOMETRY_CONDITION(handle_spikes) || ignore_spike || ! append_opposite_spikes<append_touches>( // for 'i' or 'c' i??? - tp, inters, is_p_last, is_q_last, out) ) + tp, inters, out) ) { *out++ = tp; } @@ -253,10 +234,9 @@ struct get_turn_info_linear_areal break; case 'e': { - if ( get_turn_info_for_endpoint<true, true>( - pi, pj, pk, qi, qj, qk, - is_p_first, is_p_last, is_q_first, is_q_last, - tp_model, inters, method_equal, out) ) + if ( get_turn_info_for_endpoint<true, true>(range_p, range_q, + tp_model, inters, method_equal, out, + strategy.get_point_in_point_strategy()) ) { // do nothing } @@ -268,18 +248,15 @@ struct get_turn_info_linear_areal { // Both equal // or collinear-and-ending at intersection point - equal<TurnInfo>::apply(pi, pj, pk, qi, qj, qk, - tp, inters.i_info(), inters.d_info(), inters.sides()); + equal<TurnInfo>::apply(range_p, range_q, tp, + inters.i_info(), inters.d_info(), inters.sides()); turn_transformer_ec<false> transformer(method_touch); transformer(tp); - -// TODO: move this into the append_xxx and call for each turn? - AssignPolicy::apply(tp, pi, qi, inters); - + // conditionally handle spikes if ( ! BOOST_GEOMETRY_CONDITION(handle_spikes) - || ! append_collinear_spikes(tp, inters, is_p_last, is_q_last, + || ! append_collinear_spikes(tp, inters, method_touch, append_equal, out) ) { *out++ = tp; // no spikes @@ -291,7 +268,7 @@ struct get_turn_info_linear_areal < TurnInfo, AssignPolicy - >::apply(pi, qi, + >::apply(range_p, range_q, tp, out, inters); } } @@ -301,9 +278,9 @@ struct get_turn_info_linear_areal { // Collinear if ( get_turn_info_for_endpoint<true, true>( - pi, pj, pk, qi, qj, qk, - is_p_first, is_p_last, is_q_first, is_q_last, - tp_model, inters, method_collinear, out) ) + range_p, range_q, + tp_model, inters, method_collinear, out, + strategy.get_point_in_point_strategy()) ) { // do nothing } @@ -319,16 +296,16 @@ struct get_turn_info_linear_areal if ( inters.d_info().arrival[0] == 0 ) { // Collinear, but similar thus handled as equal - equal<TurnInfo>::apply(pi, pj, pk, qi, qj, qk, - tp, inters.i_info(), inters.d_info(), inters.sides()); + equal<TurnInfo>::apply(range_p, range_q, tp, + inters.i_info(), inters.d_info(), inters.sides()); method_replace = method_touch; version = append_equal; } else { - collinear<TurnInfo>::apply(pi, pj, pk, qi, qj, qk, - tp, inters.i_info(), inters.d_info(), inters.sides()); + collinear<TurnInfo>::apply(range_p, range_q, tp, + inters.i_info(), inters.d_info(), inters.sides()); //method_replace = method_touch_interior; //version = append_collinear; @@ -337,12 +314,9 @@ struct get_turn_info_linear_areal turn_transformer_ec<false> transformer(method_replace); transformer(tp); -// TODO: move this into the append_xxx and call for each turn? - AssignPolicy::apply(tp, pi, qi, inters); - // conditionally handle spikes if ( ! BOOST_GEOMETRY_CONDITION(handle_spikes) - || ! append_collinear_spikes(tp, inters, is_p_last, is_q_last, + || ! append_collinear_spikes(tp, inters, method_replace, version, out) ) { // no spikes @@ -358,7 +332,7 @@ struct get_turn_info_linear_areal if ( BOOST_GEOMETRY_CONDITION(handle_spikes) ) { append_opposite_spikes<append_collinear_opposite>( - tp, inters, is_p_last, is_q_last, out); + tp, inters, out); } // TODO: ignore for spikes? @@ -369,10 +343,9 @@ struct get_turn_info_linear_areal < TurnInfo, AssignPolicy - >::apply(pi, pj, pk, qi, qj, qk, + >::apply(range_p, range_q, tp, out, inters, - inters.sides(), transformer, - !is_p_last, true); // qk is always valid + inters.sides(), transformer); } } } @@ -384,19 +357,20 @@ struct get_turn_info_linear_areal { only_convert::apply(tp, inters.i_info()); - if ( is_p_first - && equals::equals_point_point(pi, tp.point) ) + if ( range_p.is_first_segment() + && equals::equals_point_point(range_p.at(0), tp.point, + strategy.get_point_in_point_strategy()) ) { tp.operations[0].position = position_front; } - else if ( is_p_last - && equals::equals_point_point(pj, tp.point) ) + else if ( range_p.is_last_segment() + && equals::equals_point_point(range_p.at(1), tp.point, + strategy.get_point_in_point_strategy()) ) { tp.operations[0].position = position_back; } // tp.operations[1].position = position_middle; - AssignPolicy::apply(tp, pi, qi, inters); *out++ = tp; } } @@ -417,13 +391,13 @@ struct get_turn_info_linear_areal } template <typename Operation, - typename IntersectionInfo> + typename IntersectionInfo, + typename EqPPStrategy> static inline bool calculate_spike_operation(Operation & op, IntersectionInfo const& inters, - bool is_p_last) + EqPPStrategy const& strategy) { bool is_p_spike = ( op == operation_union || op == operation_intersection ) - && ! is_p_last && inters.is_spike_p(); if ( is_p_spike ) @@ -441,7 +415,7 @@ struct get_turn_info_linear_areal // spike on the edge point // if it's already known that the spike is going out this musn't be checked if ( ! going_out - && equals::equals_point_point(inters.rpj(), inters.rqj()) ) + && detail::equals::equals_point_point(inters.rpj(), inters.rqj(), strategy) ) { int const pk_q2 = inters.sides().pk_wrt_q2(); going_in = pk_q1 < 0 && pk_q2 < 0; // Pk on the right of both @@ -453,7 +427,7 @@ struct get_turn_info_linear_areal // spike on the edge point // if it's already known that the spike is going in this musn't be checked if ( ! going_in - && equals::equals_point_point(inters.rpj(), inters.rqj()) ) + && detail::equals::equals_point_point(inters.rpj(), inters.rqj(), strategy) ) { int const pk_q2 = inters.sides().pk_wrt_q2(); going_in = pk_q1 < 0 || pk_q2 < 0; // Pk on the right of one of them @@ -483,7 +457,6 @@ struct get_turn_info_linear_areal typename OutIt> static inline bool append_collinear_spikes(TurnInfo & tp, IntersectionInfo const& inters, - bool is_p_last, bool /*is_q_last*/, method_type method, append_version_c version, OutIt out) { @@ -494,7 +467,6 @@ struct get_turn_info_linear_areal ( tp.operations[0].operation == operation_union || tp.operations[0].operation == operation_intersection ) : tp.operations[0].operation == operation_continue ) - && ! is_p_last && inters.is_spike_p(); // TODO: throw an exception for spike in Areal? @@ -543,7 +515,6 @@ struct get_turn_info_linear_areal typename OutIt> static inline bool append_opposite_spikes(TurnInfo & tp, IntersectionInfo const& inters, - bool is_p_last, bool /*is_q_last*/, OutIt out) { static const bool is_version_touches = (Version == append_touches); @@ -552,7 +523,6 @@ struct get_turn_info_linear_areal ( tp.operations[0].operation == operation_continue || tp.operations[0].operation == operation_intersection ) : // i ??? true ) - && ! is_p_last && inters.is_spike_p(); // TODO: throw an exception for spike in Areal? @@ -586,8 +556,6 @@ struct get_turn_info_linear_areal BOOST_GEOMETRY_ASSERT(inters.i_info().count > 1); base_turn_handler::assign_point(tp, method_touch_interior, inters.i_info(), 1); - - AssignPolicy::apply(tp, inters.pi(), inters.qi(), inters); } tp.operations[0].operation = operation_blocked; @@ -706,35 +674,46 @@ struct get_turn_info_linear_areal template <bool EnableFirst, bool EnableLast, - typename Point1, - typename Point2, + typename UniqueSubRange1, + typename UniqueSubRange2, typename TurnInfo, typename IntersectionInfo, - typename OutputIterator> + typename OutputIterator, + typename EqPPStrategy> static inline bool get_turn_info_for_endpoint( - Point1 const& pi, Point1 const& /*pj*/, Point1 const& /*pk*/, - Point2 const& qi, Point2 const& /*qj*/, Point2 const& /*qk*/, - bool is_p_first, bool is_p_last, - bool /*is_q_first*/, bool is_q_last, + UniqueSubRange1 const& range_p, + UniqueSubRange2 const& range_q, TurnInfo const& tp_model, IntersectionInfo const& inters, method_type /*method*/, - OutputIterator out) + OutputIterator out, + EqPPStrategy const& strategy) { namespace ov = overlay; - typedef ov::get_turn_info_for_endpoint<AssignPolicy, EnableFirst, EnableLast> get_info_e; + typedef ov::get_turn_info_for_endpoint<EnableFirst, EnableLast> get_info_e; const std::size_t ip_count = inters.i_info().count; // no intersection points - if ( ip_count == 0 ) + if (ip_count == 0) + { return false; + } - if ( !is_p_first && !is_p_last ) + if (! range_p.is_first_segment() && ! range_p.is_last_segment()) + { + // P sub-range has no end-points return false; + } -// TODO: is_q_last could probably be replaced by false and removed from parameters + typename IntersectionInfo::side_strategy_type const& sides + = inters.get_side_strategy(); - linear_intersections intersections(pi, qi, inters.result(), is_p_last, is_q_last); + linear_intersections intersections(range_p.at(0), + range_q.at(0), + inters.result(), + range_p.is_last_segment(), + range_q.is_last_segment(), + strategy); linear_intersections::ip_info const& ip0 = intersections.template get<0>(); linear_intersections::ip_info const& ip1 = intersections.template get<1>(); @@ -745,7 +724,7 @@ struct get_turn_info_linear_areal // IP on the first point of Linear Geometry bool was_first_point_handled = false; if ( BOOST_GEOMETRY_CONDITION(EnableFirst) - && is_p_first && ip0.is_pi && !ip0.is_qi ) // !q0i prevents duplication + && range_p.is_first_segment() && ip0.is_pi && !ip0.is_qi ) // !q0i prevents duplication { TurnInfo tp = tp_model; tp.operations[0].position = position_front; @@ -759,51 +738,40 @@ struct get_turn_info_linear_areal } else { - typedef typename IntersectionInfo::robust_point1_type rp1_type; - typedef typename IntersectionInfo::robust_point2_type rp2_type; - - method_type replaced_method = method_touch_interior; - + // pi is the intersection point at qj or in the middle of q1 + // so consider segments + // 1. pi at qj: qi-qj-pj and qi-qj-qk + // x: qi-qj, y: qj-qk, qz: qk + // 2. pi in the middle of q1: qi-pi-pj and qi-pi-qj + // x: qi-pi, y: pi-qj, qz: qj + // qi-pi, side the same as WRT q1 + // pi-qj, side the same as WRT q1 + // qj WRT q1 is 0 + method_type replaced_method = method_none; + int side_pj_y = 0, side_pj_x = 0, side_qz_x = 0; + // 1. ip0 or pi at qj if ( ip0.is_qj ) { - side_calculator - < - typename IntersectionInfo::cs_tag, - rp1_type, rp2_type, - typename IntersectionInfo::side_strategy_type, - rp2_type - > side_calc(inters.rqi(), inters.rpi(), inters.rpj(), - inters.rqi(), inters.rqj(), inters.rqk(), - inters.get_side_strategy()); - - std::pair<operation_type, operation_type> - operations = get_info_e::operations_of_equal(side_calc); - - tp.operations[0].operation = operations.first; - tp.operations[1].operation = operations.second; - replaced_method = method_touch; + side_pj_y = sides.apply(range_q.at(1), range_q.at(2), range_p.at(1)); // pj wrt q2 + side_pj_x = sides.apply(range_q.at(0), range_q.at(1), range_p.at(1)); // pj wrt q1 + side_qz_x = sides.apply(range_q.at(0), range_q.at(1), range_q.at(2)); // qk wrt q1 } + // 2. ip0 or pi in the middle of q1 else { - side_calculator - < - typename IntersectionInfo::cs_tag, - rp1_type, rp2_type, - typename IntersectionInfo::side_strategy_type, - rp2_type, rp1_type, rp1_type, - rp2_type, rp1_type, rp2_type - > side_calc(inters.rqi(), inters.rpi(), inters.rpj(), - inters.rqi(), inters.rpi(), inters.rqj(), - inters.get_side_strategy()); - - std::pair<operation_type, operation_type> - operations = get_info_e::operations_of_equal(side_calc); - - tp.operations[0].operation = operations.first; - tp.operations[1].operation = operations.second; + replaced_method = method_touch_interior; + side_pj_y = sides.apply(range_q.at(0), range_q.at(1), range_p.at(1)); // pj wrt q1 + side_pj_x = side_pj_y; // pj wrt q1 + side_qz_x = 0; // qj wrt q1 } + std::pair<operation_type, operation_type> operations + = get_info_e::operations_of_equal(side_pj_y, side_pj_x, side_qz_x); + + tp.operations[0].operation = operations.first; + tp.operations[1].operation = operations.second; + turn_transformer_ec<true> transformer(replaced_method); transformer(tp); } @@ -817,7 +785,6 @@ struct get_turn_info_linear_areal // here is_p_first_ip == true tp.operations[0].is_collinear = false; - AssignPolicy::apply(tp, pi, qi, inters); *out++ = tp; was_first_point_handled = true; @@ -827,7 +794,7 @@ struct get_turn_info_linear_areal // IP on the last point of Linear Geometry if ( BOOST_GEOMETRY_CONDITION(EnableLast) - && is_p_last + && range_p.is_last_segment() && ( ip_count > 1 ? (ip1.is_pj && !ip1.is_qi) : (ip0.is_pj && !ip0.is_qi) ) ) // prevents duplication { TurnInfo tp = tp_model; @@ -840,19 +807,33 @@ struct get_turn_info_linear_areal } else //if ( result.template get<0>().count == 1 ) { - side_calculator - < - typename IntersectionInfo::cs_tag, - typename IntersectionInfo::robust_point1_type, - typename IntersectionInfo::robust_point2_type, - typename IntersectionInfo::side_strategy_type, - typename IntersectionInfo::robust_point2_type - > side_calc(inters.rqi(), inters.rpj(), inters.rpi(), - inters.rqi(), inters.rqj(), inters.rqk(), - inters.get_side_strategy()); - - std::pair<operation_type, operation_type> - operations = get_info_e::operations_of_equal(side_calc); + // pj is the intersection point at qj or in the middle of q1 + // so consider segments + // 1. pj at qj: qi-qj-pi and qi-qj-qk + // x: qi-qj, y: qj-qk, qz: qk + // 2. pj in the middle of q1: qi-pj-pi and qi-pj-qj + // x: qi-pj, y: pj-qj, qz: qj + // qi-pj, the side is the same as WRT q1 + // pj-qj, the side is the same as WRT q1 + // side of qj WRT q1 is 0 + int side_pi_y = 0, side_pi_x = 0, side_qz_x = 0; + // 1. ip0 or pj at qj + if ( ip0.is_qj ) + { + side_pi_y = sides.apply(range_q.at(1), range_q.at(2), range_p.at(0)); // pi wrt q2 + side_pi_x = sides.apply(range_q.at(0), range_q.at(1), range_p.at(0)); // pi wrt q1 + side_qz_x = sides.apply(range_q.at(0), range_q.at(1), range_q.at(2)); // qk wrt q1 + } + // 2. ip0 or pj in the middle of q1 + else + { + side_pi_y = sides.apply(range_q.at(0), range_q.at(1), range_p.at(0)); // pi wrt q1 + side_pi_x = side_pi_y; // pi wrt q1 + side_qz_x = 0; // qj wrt q1 + } + + std::pair<operation_type, operation_type> operations + = get_info_e::operations_of_equal(side_pi_y, side_pi_x, side_qz_x); tp.operations[0].operation = operations.first; tp.operations[1].operation = operations.second; @@ -873,7 +854,6 @@ struct get_turn_info_linear_areal unsigned int ip_index = ip_count > 1 ? 1 : 0; base_turn_handler::assign_point(tp, tp.method, inters.i_info(), ip_index); - AssignPolicy::apply(tp, pi, qi, inters); *out++ = tp; // don't ignore the first IP if the segment is opposite @@ -883,6 +863,14 @@ struct get_turn_info_linear_areal // don't ignore anything for now return false; } + + template <typename Point1, typename Point2, typename IntersectionStrategy> + static inline bool equals_point_point(Point1 const& point1, Point2 const& point2, + IntersectionStrategy const& strategy) + { + return detail::equals::equals_point_point(point1, point2, + strategy.get_point_in_point_strategy()); + } }; }} // namespace detail::overlay diff --git a/boost/geometry/algorithms/detail/overlay/get_turn_info_ll.hpp b/boost/geometry/algorithms/detail/overlay/get_turn_info_ll.hpp index 58fd4bb5c7..217f4a340b 100644 --- a/boost/geometry/algorithms/detail/overlay/get_turn_info_ll.hpp +++ b/boost/geometry/algorithms/detail/overlay/get_turn_info_ll.hpp @@ -3,8 +3,8 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland. -// This file was modified by Oracle on 2013, 2014, 2015, 2017. -// Modifications copyright (c) 2013-2017 Oracle and/or its affiliates. +// This file was modified by Oracle on 2013, 2014, 2015, 2017, 2018. +// Modifications copyright (c) 2013-2018 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -36,18 +36,16 @@ struct get_turn_info_linear_linear template < - typename Point1, - typename Point2, + typename UniqueSubRange1, + typename UniqueSubRange2, typename TurnInfo, typename IntersectionStrategy, typename RobustPolicy, typename OutputIterator > static inline OutputIterator apply( - Point1 const& pi, Point1 const& pj, Point1 const& pk, - Point2 const& qi, Point2 const& qj, Point2 const& qk, - bool is_p_first, bool is_p_last, - bool is_q_first, bool is_q_last, + UniqueSubRange1 const& range_p, + UniqueSubRange2 const& range_q, TurnInfo const& tp_model, IntersectionStrategy const& strategy, RobustPolicy const& robust_policy, @@ -55,13 +53,13 @@ struct get_turn_info_linear_linear { typedef intersection_info < - Point1, Point2, + UniqueSubRange1, UniqueSubRange2, typename TurnInfo::point_type, IntersectionStrategy, RobustPolicy > inters_info; - inters_info inters(pi, pj, pk, qi, qj, qk, strategy, robust_policy); + inters_info inters(range_p, range_q, strategy, robust_policy); char const method = inters.d_info().how; @@ -74,10 +72,10 @@ struct get_turn_info_linear_linear case 'a' : // collinear, "at" case 'f' : // collinear, "from" case 's' : // starts from the middle - get_turn_info_for_endpoint<AssignPolicy, true, true> - ::apply(pi, pj, pk, qi, qj, qk, - is_p_first, is_p_last, is_q_first, is_q_last, - tp_model, inters, method_none, out); + get_turn_info_for_endpoint<true, true> + ::apply(range_p, range_q, + tp_model, inters, method_none, out, + strategy.get_point_in_point_strategy()); break; case 'd' : // disjoint: never do anything @@ -85,10 +83,10 @@ struct get_turn_info_linear_linear case 'm' : { - if ( get_turn_info_for_endpoint<AssignPolicy, false, true> - ::apply(pi, pj, pk, qi, qj, qk, - is_p_first, is_p_last, is_q_first, is_q_last, - tp_model, inters, method_touch_interior, out) ) + if ( get_turn_info_for_endpoint<false, true> + ::apply(range_p, range_q, + tp_model, inters, method_touch_interior, out, + strategy.get_point_in_point_strategy()) ) { // do nothing } @@ -102,26 +100,16 @@ struct get_turn_info_linear_linear // If Q (1) arrives (1) if ( inters.d_info().arrival[1] == 1) { - policy::template apply<0>(pi, pj, pk, qi, qj, qk, - tp, inters.i_info(), inters.d_info(), + policy::template apply<0>(range_p, range_q, tp, + inters.i_info(), inters.d_info(), inters.sides()); } else { // Swap p/q - side_calculator - < - typename inters_info::cs_tag, - typename inters_info::robust_point2_type, - typename inters_info::robust_point1_type, - typename inters_info::side_strategy_type - > swapped_side_calc(inters.rqi(), inters.rqj(), inters.rqk(), - inters.rpi(), inters.rpj(), inters.rpk(), - inters.get_side_strategy()); - - policy::template apply<1>(qi, qj, qk, pi, pj, pk, - tp, inters.i_info(), inters.d_info(), - swapped_side_calc); + policy::template apply<1>(range_q, range_p, tp, + inters.i_info(), inters.d_info(), + inters.get_swapped_sides()); } if ( tp.operations[0].operation == operation_blocked ) @@ -137,36 +125,33 @@ struct get_turn_info_linear_linear tp.operations[0].operation, tp.operations[1].operation); - AssignPolicy::apply(tp, pi, qi, inters); *out++ = tp; } } break; case 'i' : { - crosses<TurnInfo>::apply(pi, pj, pk, qi, qj, qk, - tp, inters.i_info(), inters.d_info()); + crosses<TurnInfo>::apply(tp, inters.i_info(), inters.d_info()); replace_operations_i(tp.operations[0].operation, tp.operations[1].operation); - AssignPolicy::apply(tp, pi, qi, inters); *out++ = tp; } break; case 't' : { // Both touch (both arrive there) - if ( get_turn_info_for_endpoint<AssignPolicy, false, true> - ::apply(pi, pj, pk, qi, qj, qk, - is_p_first, is_p_last, is_q_first, is_q_last, - tp_model, inters, method_touch, out) ) + if ( get_turn_info_for_endpoint<false, true> + ::apply(range_p, range_q, + tp_model, inters, method_touch, out, + strategy.get_point_in_point_strategy()) ) { // do nothing } else { - touch<TurnInfo>::apply(pi, pj, pk, qi, qj, qk, - tp, inters.i_info(), inters.d_info(), inters.sides()); + touch<TurnInfo>::apply(range_p, range_q, tp, + inters.i_info(), inters.d_info(), inters.sides()); // workarounds for touch<> not taking spikes into account starts here // those was discovered empirically @@ -276,13 +261,8 @@ struct get_turn_info_linear_linear tp.operations[0].operation, tp.operations[1].operation); -// TODO: move this into the append_xxx and call for each turn? - AssignPolicy::apply(tp, pi, qi, inters); - if ( ! BOOST_GEOMETRY_CONDITION(handle_spikes) - || ! append_opposite_spikes<append_touches>(tp, inters, - is_p_last, is_q_last, - out) ) + || ! append_opposite_spikes<append_touches>(tp, inters, out) ) { *out++ = tp; } @@ -291,10 +271,10 @@ struct get_turn_info_linear_linear break; case 'e': { - if ( get_turn_info_for_endpoint<AssignPolicy, true, true> - ::apply(pi, pj, pk, qi, qj, qk, - is_p_first, is_p_last, is_q_first, is_q_last, - tp_model, inters, method_equal, out) ) + if ( get_turn_info_for_endpoint<true, true> + ::apply(range_p, range_q, + tp_model, inters, method_equal, out, + strategy.get_point_in_point_strategy()) ) { // do nothing } @@ -307,8 +287,8 @@ struct get_turn_info_linear_linear { // Both equal // or collinear-and-ending at intersection point - equal<TurnInfo>::apply(pi, pj, pk, qi, qj, qk, - tp, inters.i_info(), inters.d_info(), inters.sides()); + equal<TurnInfo>::apply(range_p, range_q, tp, + inters.i_info(), inters.d_info(), inters.sides()); operation_type spike_op = ( tp.operations[0].operation != operation_continue @@ -320,13 +300,9 @@ struct get_turn_info_linear_linear turn_transformer_ec transformer(method_touch); transformer(tp); -// TODO: move this into the append_xxx and call for each turn? - AssignPolicy::apply(tp, pi, qi, inters); - // conditionally handle spikes if ( ! BOOST_GEOMETRY_CONDITION(handle_spikes) || ! append_collinear_spikes(tp, inters, - is_p_last, is_q_last, method_touch, spike_op, out) ) { @@ -341,7 +317,7 @@ struct get_turn_info_linear_linear < TurnInfo, AssignPolicy - >::apply(pi, qi, tp, out, inters); + >::apply(range_p, range_q, tp, out, inters); } } } @@ -349,10 +325,10 @@ struct get_turn_info_linear_linear case 'c' : { // Collinear - if ( get_turn_info_for_endpoint<AssignPolicy, true, true> - ::apply(pi, pj, pk, qi, qj, qk, - is_p_first, is_p_last, is_q_first, is_q_last, - tp_model, inters, method_collinear, out) ) + if ( get_turn_info_for_endpoint<true, true> + ::apply(range_p, range_q, + tp_model, inters, method_collinear, out, + strategy.get_point_in_point_strategy()) ) { // do nothing } @@ -370,8 +346,8 @@ struct get_turn_info_linear_linear if ( inters.d_info().arrival[0] == 0 ) { // Collinear, but similar thus handled as equal - equal<TurnInfo>::apply(pi, pj, pk, qi, qj, qk, - tp, inters.i_info(), inters.d_info(), inters.sides()); + equal<TurnInfo>::apply(range_p, range_q, tp, + inters.i_info(), inters.d_info(), inters.sides()); method_replace = method_touch; if ( tp.operations[0].operation != operation_continue @@ -382,7 +358,7 @@ struct get_turn_info_linear_linear } else { - collinear<TurnInfo>::apply(pi, pj, pk, qi, qj, qk, + collinear<TurnInfo>::apply(range_p, range_q, tp, inters.i_info(), inters.d_info(), inters.sides()); //method_replace = method_touch_interior; @@ -393,13 +369,9 @@ struct get_turn_info_linear_linear turn_transformer_ec transformer(method_replace); transformer(tp); -// TODO: move this into the append_xxx and call for each turn? - AssignPolicy::apply(tp, pi, qi, inters); - // conditionally handle spikes if ( ! BOOST_GEOMETRY_CONDITION(handle_spikes) || ! append_collinear_spikes(tp, inters, - is_p_last, is_q_last, method_replace, spike_op, out) ) { @@ -415,9 +387,7 @@ struct get_turn_info_linear_linear // conditionally handle spikes if ( BOOST_GEOMETRY_CONDITION(handle_spikes) ) { - append_opposite_spikes<append_collinear_opposite>(tp, inters, - is_p_last, is_q_last, - out); + append_opposite_spikes<append_collinear_opposite>(tp, inters, out); } // TODO: ignore for spikes? @@ -428,9 +398,9 @@ struct get_turn_info_linear_linear < TurnInfo, AssignPolicy - >::apply(pi, pj, pk, qi, qj, qk, + >::apply(range_p, range_q, tp, out, inters, inters.sides(), - transformer, !is_p_last, !is_q_last); + transformer); } } } @@ -440,31 +410,33 @@ struct get_turn_info_linear_linear // degenerate points if ( BOOST_GEOMETRY_CONDITION(AssignPolicy::include_degenerate) ) { + typedef typename IntersectionStrategy::point_in_point_strategy_type + equals_strategy_type; + only_convert::apply(tp, inters.i_info()); // if any, only one of those should be true - if ( is_p_first - && equals::equals_point_point(pi, tp.point) ) + if ( range_p.is_first_segment() + && equals::equals_point_point(range_p.at(0), tp.point, equals_strategy_type()) ) { tp.operations[0].position = position_front; } - else if ( is_p_last - && equals::equals_point_point(pj, tp.point) ) + else if ( range_p.is_last_segment() + && equals::equals_point_point(range_p.at(1), tp.point, equals_strategy_type()) ) { tp.operations[0].position = position_back; } - else if ( is_q_first - && equals::equals_point_point(qi, tp.point) ) + else if ( range_q.is_first_segment() + && equals::equals_point_point(range_q.at(0), tp.point, equals_strategy_type()) ) { tp.operations[1].position = position_front; } - else if ( is_q_last - && equals::equals_point_point(qj, tp.point) ) + else if ( range_q.is_last_segment() + && equals::equals_point_point(range_q.at(1), tp.point, equals_strategy_type()) ) { tp.operations[1].position = position_back; } - AssignPolicy::apply(tp, pi, qi, inters); *out++ = tp; } } @@ -489,7 +461,6 @@ struct get_turn_info_linear_linear typename OutIt> static inline bool append_collinear_spikes(TurnInfo & tp, IntersectionInfo const& inters_info, - bool is_p_last, bool is_q_last, method_type method, operation_type spike_op, OutIt out) { @@ -497,10 +468,8 @@ struct get_turn_info_linear_linear // both position == middle bool is_p_spike = tp.operations[0].operation == spike_op - && ! is_p_last && inters_info.is_spike_p(); bool is_q_spike = tp.operations[1].operation == spike_op - && ! is_q_last && inters_info.is_spike_q(); if ( is_p_spike && is_q_spike ) @@ -559,7 +528,6 @@ struct get_turn_info_linear_linear typename OutIt> static inline bool append_opposite_spikes(TurnInfo & tp, IntersectionInfo const& inters, - bool is_p_last, bool is_q_last, OutIt out) { static const bool is_version_touches = (Version == append_touches); @@ -568,13 +536,11 @@ struct get_turn_info_linear_linear ( tp.operations[0].operation == operation_continue || tp.operations[0].operation == operation_intersection ) : true ) - && ! is_p_last && inters.is_spike_p(); bool is_q_spike = ( is_version_touches ? ( tp.operations[1].operation == operation_continue || tp.operations[1].operation == operation_intersection ) : true ) - && ! is_q_last && inters.is_spike_q(); bool res = false; @@ -598,8 +564,6 @@ struct get_turn_info_linear_linear base_turn_handler::assign_point(tp, method_touch_interior, inters.i_info(), 1); - - AssignPolicy::apply(tp, inters.pi(), inters.qi(), inters); } tp.operations[0].operation = operation_blocked; @@ -630,8 +594,6 @@ struct get_turn_info_linear_linear BOOST_GEOMETRY_ASSERT(inters.i_info().count > 0); base_turn_handler::assign_point(tp, method_touch_interior, inters.i_info(), 0); - - AssignPolicy::apply(tp, inters.pi(), inters.qi(), inters); } tp.operations[0].operation = operation_intersection; diff --git a/boost/geometry/algorithms/detail/overlay/get_turns.hpp b/boost/geometry/algorithms/detail/overlay/get_turns.hpp index 042e65b4e1..886f8b683f 100644 --- a/boost/geometry/algorithms/detail/overlay/get_turns.hpp +++ b/boost/geometry/algorithms/detail/overlay/get_turns.hpp @@ -3,8 +3,8 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2014-2017 Adam Wulkiewicz, Lodz, Poland. -// This file was modified by Oracle on 2014, 2016, 2017. -// Modifications copyright (c) 2014-2017 Oracle and/or its affiliates. +// This file was modified by Oracle on 2014, 2016, 2017, 2018. +// Modifications copyright (c) 2014-2018 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -27,6 +27,7 @@ #include <boost/range.hpp> #include <boost/geometry/core/access.hpp> +#include <boost/geometry/core/assert.hpp> #include <boost/geometry/core/coordinate_dimension.hpp> #include <boost/geometry/core/exterior_ring.hpp> #include <boost/geometry/core/interior_rings.hpp> @@ -101,6 +102,113 @@ struct no_interrupt_policy } }; +template +< + bool IsAreal, + typename Section, + typename Point, + typename CircularIterator, + typename IntersectionStrategy, + typename RobustPolicy +> +struct unique_sub_range_from_section +{ + typedef Point point_type; + + unique_sub_range_from_section(Section const& section, signed_size_type index, + CircularIterator circular_iterator, + Point const& previous, Point const& current, + RobustPolicy const& robust_policy) + : m_section(section) + , m_index(index) + , m_previous_point(previous) + , m_current_point(current) + , m_circular_iterator(circular_iterator) + , m_point_retrieved(false) + , m_robust_policy(robust_policy) + { + } + + inline bool is_first_segment() const + { + return !IsAreal && m_section.is_non_duplicate_first && m_index == m_section.begin_index; + } + inline bool is_last_segment() const + { + return size() == 2u; + } + + inline std::size_t size() const + { + return IsAreal ? 3 + : m_section.is_non_duplicate_last && m_index + 1 >= m_section.end_index ? 2 : 3; + } + + inline Point const& at(std::size_t index) const + { + BOOST_GEOMETRY_ASSERT(index < size()); + switch (index) + { + case 0 : return m_previous_point; + case 1 : return m_current_point; + case 2 : return get_next_point(); + default : return m_previous_point; + } + } + +private : + inline Point const& get_next_point() const + { + if (! m_point_retrieved) + { + advance_to_non_duplicate_next(m_current_point, m_circular_iterator); + m_point = *m_circular_iterator; + m_point_retrieved = true; + } + return m_point; + } + + inline void advance_to_non_duplicate_next(Point const& current, CircularIterator& circular_iterator) const + { + typedef typename IntersectionStrategy::point_in_point_strategy_type disjoint_strategy_type; + typedef typename robust_point_type<Point, RobustPolicy>::type robust_point_type; + robust_point_type current_robust_point; + robust_point_type next_robust_point; + geometry::recalculate(current_robust_point, current, m_robust_policy); + geometry::recalculate(next_robust_point, *circular_iterator, m_robust_policy); + + // To see where the next segments bend to, in case of touch/intersections + // on end points, we need (in case of degenerate/duplicate points) an extra + // iterator which moves to the REAL next point, so non duplicate. + // This needs an extra comparison (disjoint). + // (Note that within sections, non duplicate points are already asserted, + // by the sectionalize process). + + // So advance to the "non duplicate next" + // (the check is defensive, to avoid endless loops) + std::size_t check = 0; + while(! detail::disjoint::disjoint_point_point + ( + current_robust_point, next_robust_point, + disjoint_strategy_type() + ) + && check++ < m_section.range_count) + { + circular_iterator++; + geometry::recalculate(next_robust_point, *circular_iterator, m_robust_policy); + } + } + + Section const& m_section; + signed_size_type m_index; + Point const& m_previous_point; + Point const& m_current_point; + mutable CircularIterator m_circular_iterator; + mutable Point m_point; + mutable bool m_point_retrieved; + RobustPolicy m_robust_policy; +}; + template < @@ -143,6 +251,8 @@ class get_turns_in_sections view_type2 const >::type range2_iterator; + typedef ever_circling_iterator<range1_iterator> circular1_iterator; + typedef ever_circling_iterator<range2_iterator> circular2_iterator; template <typename Geometry, typename Section> static inline bool adjacent(Section const& section, @@ -187,6 +297,18 @@ public : { boost::ignore_unused(interrupt_policy); + static bool const areal1 = boost::is_same + < + typename tag_cast<typename tag<Geometry1>::type, areal_tag>::type, + areal_tag + >::type::value; + static bool const areal2 = boost::is_same + < + typename tag_cast<typename tag<Geometry2>::type, areal_tag>::type, + areal_tag + >::type::value; + + if ((sec1.duplicate && (sec1.count + 1) < sec1.range_count) || (sec2.duplicate && (sec2.count + 1) < sec2.range_count)) { @@ -230,9 +352,14 @@ public : it1 != end1 && ! detail::section::exceeding<0>(dir1, *prev1, sec1.bounding_box, sec2.bounding_box, robust_policy); ++prev1, ++it1, ++index1, ++next1, ++ndi1) { - ever_circling_iterator<range1_iterator> nd_next1( - begin_range_1, end_range_1, next1, true); - advance_to_non_duplicate_next(nd_next1, it1, sec1, robust_policy); + unique_sub_range_from_section + < + areal1, Section1, point1_type, circular1_iterator, + IntersectionStrategy, RobustPolicy + > unique_sub_range1(sec1, index1, + circular1_iterator(begin_range_1, end_range_1, next1, true), + *prev1, *it1, + robust_policy); signed_size_type index2 = sec2.begin_index; signed_size_type ndi2 = sec2.non_duplicate_index; @@ -278,10 +405,14 @@ public : if (! skip) { - // Move to the "non duplicate next" - ever_circling_iterator<range2_iterator> nd_next2( - begin_range_2, end_range_2, next2, true); - advance_to_non_duplicate_next(nd_next2, it2, sec2, robust_policy); + unique_sub_range_from_section + < + areal2, Section2, point2_type, circular2_iterator, + IntersectionStrategy, RobustPolicy + > unique_sub_range2(sec2, index2, + circular2_iterator(begin_range_2, end_range_2, next2), + *prev2, *it2, + robust_policy); typedef typename boost::range_value<Turns>::type turn_info; @@ -295,13 +426,7 @@ public : std::size_t const size_before = boost::size(turns); - bool const is_1_first = sec1.is_non_duplicate_first && index1 == sec1.begin_index; - bool const is_1_last = sec1.is_non_duplicate_last && index1+1 >= sec1.end_index; - bool const is_2_first = sec2.is_non_duplicate_first && index2 == sec2.begin_index; - bool const is_2_last = sec2.is_non_duplicate_last && index2+1 >= sec2.end_index; - - TurnPolicy::apply(*prev1, *it1, *nd_next1, *prev2, *it2, *nd_next2, - is_1_first, is_1_last, is_2_first, is_2_last, + TurnPolicy::apply(unique_sub_range1, unique_sub_range2, ti, intersection_strategy, robust_policy, std::back_inserter(turns)); @@ -327,37 +452,6 @@ private : typedef typename model::referring_segment<point1_type const> segment1_type; typedef typename model::referring_segment<point2_type const> segment2_type; - template <typename Iterator, typename RangeIterator, typename Section, typename RobustPolicy> - static inline void advance_to_non_duplicate_next(Iterator& next, - RangeIterator const& it, Section const& section, RobustPolicy const& robust_policy) - { - typedef typename robust_point_type<point1_type, RobustPolicy>::type robust_point_type; - robust_point_type robust_point_from_it; - robust_point_type robust_point_from_next; - geometry::recalculate(robust_point_from_it, *it, robust_policy); - geometry::recalculate(robust_point_from_next, *next, robust_policy); - - // To see where the next segments bend to, in case of touch/intersections - // on end points, we need (in case of degenerate/duplicate points) an extra - // iterator which moves to the REAL next point, so non duplicate. - // This needs an extra comparison (disjoint). - // (Note that within sections, non duplicate points are already asserted, - // by the sectionalize process). - - // So advance to the "non duplicate next" - // (the check is defensive, to avoid endless loops) - std::size_t check = 0; - while(! detail::disjoint::disjoint_point_point - ( - robust_point_from_it, robust_point_from_next - ) - && check++ < section.range_count) - { - next++; - geometry::recalculate(robust_point_from_next, *next, robust_policy); - } - } - // It is NOT possible to have section-iterators here // because of the logistics of "index" (the section-iterator automatically // skips to the begin-point, we loose the index or have to recalculate it) @@ -423,7 +517,9 @@ struct section_visitor template <typename Section> inline bool apply(Section const& sec1, Section const& sec2) { - if (! detail::disjoint::disjoint_box_box(sec1.bounding_box, sec2.bounding_box)) + if (! detail::disjoint::disjoint_box_box(sec1.bounding_box, + sec2.bounding_box, + m_intersection_strategy.get_disjoint_box_box_strategy())) { // false if interrupted return get_turns_in_sections @@ -482,11 +578,13 @@ public: typename IntersectionStrategy::envelope_strategy_type const envelope_strategy = intersection_strategy.get_envelope_strategy(); + typename IntersectionStrategy::expand_strategy_type const + expand_strategy = intersection_strategy.get_expand_strategy(); geometry::sectionalize<Reverse1, dimensions>(geometry1, robust_policy, - sec1, envelope_strategy, 0); + sec1, envelope_strategy, expand_strategy, 0); geometry::sectionalize<Reverse2, dimensions>(geometry2, robust_policy, - sec2, envelope_strategy, 1); + sec2, envelope_strategy, expand_strategy, 1); // ... and then partition them, intersecting overlapping sections in visitor method section_visitor @@ -500,12 +598,21 @@ public: intersection_strategy, robust_policy, turns, interrupt_policy); + typedef detail::section::get_section_box + < + typename IntersectionStrategy::expand_box_strategy_type + > get_section_box_type; + typedef detail::section::overlaps_section_box + < + typename IntersectionStrategy::disjoint_box_box_strategy_type + > overlaps_section_box_type; + geometry::partition < box_type >::apply(sec1, sec2, visitor, - detail::section::get_section_box(), - detail::section::overlaps_section_box()); + get_section_box_type(), + overlaps_section_box_type()); } }; @@ -519,8 +626,9 @@ template > struct get_turns_cs { - typedef typename geometry::point_type<Range>::type point_type; + typedef typename geometry::point_type<Range>::type range_point_type; typedef typename geometry::point_type<Box>::type box_point_type; + typedef boost::array<box_point_type, 4> box_array; typedef typename closeable_view < @@ -539,6 +647,70 @@ struct get_turns_cs view_type const >::type iterator_type; + struct unique_sub_range_from_box_policy + { + typedef box_point_type point_type; + + unique_sub_range_from_box_policy(box_array const& box) + : m_box(box) + , m_index(0) + {} + + static inline bool is_first_segment() { return false; } + static inline bool is_last_segment() { return false; } + static inline std::size_t size() { return 4; } + + inline box_point_type const& at(std::size_t index) const + { + BOOST_GEOMETRY_ASSERT(index < size()); + return m_box[(m_index + index) % 4]; + } + + inline void next() + { + m_index++; + } + + private : + box_array const& m_box; + std::size_t m_index; + }; + + struct unique_sub_range_from_view_policy + { + typedef range_point_type point_type; + + unique_sub_range_from_view_policy(view_type const& view, point_type const& pi, point_type const& pj, iterator_type it) + : m_view(view) + , m_pi(pi) + , m_pj(pj) + , m_circular_iterator(boost::begin(view), boost::end(view), it, true) + { + ++m_circular_iterator; + } + + static inline bool is_first_segment() { return false; } + static inline bool is_last_segment() { return false; } + static inline std::size_t size() { return 3; } + + inline point_type const& at(std::size_t index) const + { + BOOST_GEOMETRY_ASSERT(index < size()); + switch (index) + { + case 0 : return m_pi; + case 1 : return m_pj; + case 2 : return *m_circular_iterator; + default : return m_pi; + } + } + + private : + view_type const& m_view; + point_type const& m_pi; + point_type const& m_pj; + ever_circling_iterator<iterator_type> m_circular_iterator; + }; template <typename IntersectionStrategy, typename RobustPolicy, typename Turns, typename InterruptPolicy> static inline void apply( @@ -556,22 +728,16 @@ struct get_turns_cs return; } - boost::array<box_point_type,4> bp; - assign_box_corners_oriented<ReverseBox>(box, bp); + box_array box_points; + assign_box_corners_oriented<ReverseBox>(box, box_points); cview_type cview(range); view_type view(cview); - typedef typename boost::range_size<view_type>::type size_type; - size_type segments_count1 = boost::size(view) - 1; - + // TODO: in this code, possible duplicate points are not yet taken + // into account (not in the iterator, nor in the retrieve policy) iterator_type it = boost::begin(view); - ever_circling_iterator<iterator_type> next( - boost::begin(view), boost::end(view), it, true); - next++; - next++; - //bool first = true; //char previous_side[2] = {0, 0}; @@ -580,11 +746,13 @@ struct get_turns_cs for (iterator_type prev = it++; it != boost::end(view); - prev = it++, next++, index++) + prev = it++, index++) { segment_identifier seg_id(source_id1, multi_index, ring_index, index); + unique_sub_range_from_view_policy view_unique_sub_range(view, *prev, *it, it); + /*if (first) { previous_side[0] = get_side<0>(box, *prev); @@ -611,11 +779,8 @@ struct get_turns_cs if (true) { get_turns_with_box(seg_id, source_id2, - *prev, *it, *next, - bp[0], bp[1], bp[2], bp[3], - // NOTE: some dummy values could be passed below since this would be called only for Polygons and Boxes - index == 0, - size_type(index) == segments_count1, + view_unique_sub_range, + box_points, intersection_strategy, robust_policy, turns, @@ -647,19 +812,16 @@ private: else return 0; } - template <typename IntersectionStrategy, typename RobustPolicy, typename Turns, typename InterruptPolicy> + template + < + typename IntersectionStrategy, + typename Turns, + typename InterruptPolicy, + typename RobustPolicy + > static inline void get_turns_with_box(segment_identifier const& seg_id, int source_id2, - // Points from a range: - point_type const& rp0, - point_type const& rp1, - point_type const& rp2, - // Points from the box - box_point_type const& bp0, - box_point_type const& bp1, - box_point_type const& bp2, - box_point_type const& bp3, - bool const is_range_first, - bool const is_range_last, + unique_sub_range_from_view_policy const& range_unique_sub_range, + box_array const& box, IntersectionStrategy const& intersection_strategy, RobustPolicy const& robust_policy, // Output @@ -675,31 +837,27 @@ private: turn_info ti; ti.operations[0].seg_id = seg_id; + unique_sub_range_from_box_policy box_unique_sub_range(box); ti.operations[1].seg_id = segment_identifier(source_id2, -1, -1, 0); - TurnPolicy::apply(rp0, rp1, rp2, bp0, bp1, bp2, - is_range_first, is_range_last, - true, false, + TurnPolicy::apply(range_unique_sub_range, box_unique_sub_range, ti, intersection_strategy, robust_policy, std::back_inserter(turns)); ti.operations[1].seg_id = segment_identifier(source_id2, -1, -1, 1); - TurnPolicy::apply(rp0, rp1, rp2, bp1, bp2, bp3, - is_range_first, is_range_last, - false, false, + box_unique_sub_range.next(); + TurnPolicy::apply(range_unique_sub_range, box_unique_sub_range, ti, intersection_strategy, robust_policy, std::back_inserter(turns)); ti.operations[1].seg_id = segment_identifier(source_id2, -1, -1, 2); - TurnPolicy::apply(rp0, rp1, rp2, bp2, bp3, bp0, - is_range_first, is_range_last, - false, false, + box_unique_sub_range.next(); + TurnPolicy::apply(range_unique_sub_range, box_unique_sub_range, ti, intersection_strategy, robust_policy, std::back_inserter(turns)); ti.operations[1].seg_id = segment_identifier(source_id2, -1, -1, 3); - TurnPolicy::apply(rp0, rp1, rp2, bp3, bp0, bp1, - is_range_first, is_range_last, - false, true, + box_unique_sub_range.next(); + TurnPolicy::apply(range_unique_sub_range, box_unique_sub_range, ti, intersection_strategy, robust_policy, std::back_inserter(turns)); diff --git a/boost/geometry/algorithms/detail/overlay/linear_linear.hpp b/boost/geometry/algorithms/detail/overlay/linear_linear.hpp index 21d079d95c..f0a7d6a7a8 100644 --- a/boost/geometry/algorithms/detail/overlay/linear_linear.hpp +++ b/boost/geometry/algorithms/detail/overlay/linear_linear.hpp @@ -139,18 +139,6 @@ protected: static bool const include_no_turn = false; static bool const include_degenerate = EnableDegenerateTurns; static bool const include_opposite = false; - - template - < - typename Info, - typename Point1, - typename Point2, - typename IntersectionInfo - > - static inline void apply(Info& , Point1 const& , Point2 const& , - IntersectionInfo const& ) - { - } }; diff --git a/boost/geometry/algorithms/detail/overlay/overlay.hpp b/boost/geometry/algorithms/detail/overlay/overlay.hpp index 5094c6c96c..8a8561c136 100644 --- a/boost/geometry/algorithms/detail/overlay/overlay.hpp +++ b/boost/geometry/algorithms/detail/overlay/overlay.hpp @@ -125,6 +125,12 @@ inline void get_ring_turn_info(TurnInfoMap& turn_info_map, Turns const& turns, C bool cluster_checked = false; bool has_blocked = false; + if (is_self_turn<OverlayType>(turn) && turn.discarded) + { + // Discarded self-turns don't count as traversed + continue; + } + for (typename boost::range_iterator<container_type const>::type op_it = boost::begin(turn.operations); op_it != boost::end(turn.operations); diff --git a/boost/geometry/algorithms/detail/overlay/pointlike_pointlike.hpp b/boost/geometry/algorithms/detail/overlay/pointlike_pointlike.hpp index 88aedecf86..afe8f680be 100644 --- a/boost/geometry/algorithms/detail/overlay/pointlike_pointlike.hpp +++ b/boost/geometry/algorithms/detail/overlay/pointlike_pointlike.hpp @@ -1,6 +1,6 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014-2017, Oracle and/or its affiliates. +// Copyright (c) 2014-2018, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -148,13 +148,13 @@ struct point_point_point Point2 const& point2, RobustPolicy const& , OutputIterator oit, - Strategy const&) + Strategy const& strategy) { action_selector_pl_pl < PointOut, OverlayType >::apply(point1, - detail::equals::equals_point_point(point1, point2), + detail::equals::equals_point_point(point1, point2, strategy), oit); return oit; @@ -182,7 +182,7 @@ struct multipoint_point_point Point const& point, RobustPolicy const& , OutputIterator oit, - Strategy const&) + Strategy const& strategy) { BOOST_GEOMETRY_ASSERT( OverlayType == overlay_difference ); @@ -194,7 +194,7 @@ struct multipoint_point_point < PointOut, OverlayType >::apply(*it, - detail::equals::equals_point_point(*it, point), + detail::equals::equals_point_point(*it, point, strategy), oit); } @@ -218,7 +218,7 @@ struct point_multipoint_point MultiPoint const& multipoint, RobustPolicy const& , OutputIterator oit, - Strategy const&) + Strategy const& strategy) { typedef action_selector_pl_pl<PointOut, OverlayType> action; @@ -226,7 +226,7 @@ struct point_multipoint_point it = boost::begin(multipoint); it != boost::end(multipoint); ++it) { - if ( detail::equals::equals_point_point(*it, point) ) + if ( detail::equals::equals_point_point(*it, point, strategy) ) { action::apply(point, true, oit); return oit; diff --git a/boost/geometry/algorithms/detail/overlay/select_rings.hpp b/boost/geometry/algorithms/detail/overlay/select_rings.hpp index 262ba748ab..9b88ddf8b4 100644 --- a/boost/geometry/algorithms/detail/overlay/select_rings.hpp +++ b/boost/geometry/algorithms/detail/overlay/select_rings.hpp @@ -21,7 +21,6 @@ #include <boost/geometry/core/tags.hpp> -#include <boost/geometry/algorithms/area.hpp> #include <boost/geometry/algorithms/covered_by.hpp> #include <boost/geometry/algorithms/detail/interior_iterator.hpp> #include <boost/geometry/algorithms/detail/ring_identifier.hpp> diff --git a/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp b/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp index 3cc98d3b7e..261d2c4b03 100644 --- a/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp +++ b/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp @@ -3,8 +3,8 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland. -// This file was modified by Oracle on 2017. -// Modifications copyright (c) 2017 Oracle and/or its affiliates. +// This file was modified by Oracle on 2017, 2018. +// Modifications copyright (c) 2017-2018 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -99,7 +99,9 @@ struct self_section_visitor template <typename Section> inline bool apply(Section const& sec1, Section const& sec2) { - if (! detail::disjoint::disjoint_box_box(sec1.bounding_box, sec2.bounding_box) + if (! detail::disjoint::disjoint_box_box(sec1.bounding_box, + sec2.bounding_box, + m_intersection_strategy.get_disjoint_box_box_strategy()) && ! sec1.duplicate && ! sec2.duplicate) { @@ -154,7 +156,8 @@ struct get_turns sections_type sec; geometry::sectionalize<Reverse, dimensions>(geometry, robust_policy, sec, - intersection_strategy.get_envelope_strategy()); + intersection_strategy.get_envelope_strategy(), + intersection_strategy.get_expand_strategy()); self_section_visitor < @@ -162,13 +165,22 @@ struct get_turns Turns, TurnPolicy, IntersectionStrategy, RobustPolicy, InterruptPolicy > visitor(geometry, intersection_strategy, robust_policy, turns, interrupt_policy, source_index, skip_adjacent); + typedef detail::section::get_section_box + < + typename IntersectionStrategy::expand_box_strategy_type + > get_section_box_type; + typedef detail::section::overlaps_section_box + < + typename IntersectionStrategy::disjoint_box_box_strategy_type + > overlaps_section_box_type; + // false if interrupted geometry::partition < box_type >::apply(sec, visitor, - detail::section::get_section_box(), - detail::section::overlaps_section_box()); + get_section_box_type(), + overlaps_section_box_type()); return ! interrupt_policy.has_intersections; } @@ -324,6 +336,8 @@ inline void self_turns(Geometry const& geometry, \param turns container which will contain intersection points \param interrupt_policy policy determining if process is stopped when intersection is found + \param source_index source index for generated turns + \param skip_adjacent indicates if adjacent turns should be skipped */ template < diff --git a/boost/geometry/algorithms/detail/overlay/stream_info.hpp b/boost/geometry/algorithms/detail/overlay/stream_info.hpp index 51fd1b3dca..307d9ff805 100644 --- a/boost/geometry/algorithms/detail/overlay/stream_info.hpp +++ b/boost/geometry/algorithms/detail/overlay/stream_info.hpp @@ -2,6 +2,11 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// This file was modified by Oracle on 2018. +// Modifications copyright (c) 2018 Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + // 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) @@ -12,7 +17,7 @@ #include <string> -#include <boost/array.hpp> +#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp> namespace boost { namespace geometry @@ -32,8 +37,8 @@ namespace detail { namespace overlay return h == 0 ? "-" : (h == 1 ? "A" : "D"); } - template <typename P> - std::ostream& operator<<(std::ostream &os, turn_info<P> const& info) + template <typename P, typename SR, typename O, typename C> + std::ostream& operator<<(std::ostream &os, turn_info<P, SR, O, C> const& info) { os << "\t" << " src " << info.seg_id.source_index @@ -46,10 +51,10 @@ namespace detail { namespace overlay << (info.opposite ? " o" : "") << "]" << " sd " - << dir(info.sides.get<0,0>()) - << dir(info.sides.get<0,1>()) - << dir(info.sides.get<1,0>()) - << dir(info.sides.get<1,1>()) + << dir(info.sides.template get<0,0>()) + << dir(info.sides.template get<0,1>()) + << dir(info.sides.template get<1,0>()) + << dir(info.sides.template get<1,1>()) << " nxt seg " << info.travels_to_vertex_index << " , ip " << info.travels_to_ip_index << " , or " << info.next_ip_index diff --git a/boost/geometry/algorithms/detail/overlay/traversal.hpp b/boost/geometry/algorithms/detail/overlay/traversal.hpp index 90ee240138..3a7d82ce0a 100644 --- a/boost/geometry/algorithms/detail/overlay/traversal.hpp +++ b/boost/geometry/algorithms/detail/overlay/traversal.hpp @@ -2,8 +2,8 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. -// This file was modified by Oracle on 2017. -// Modifications copyright (c) 2017 Oracle and/or its affiliates. +// This file was modified by Oracle on 2017, 2018. +// Modifications copyright (c) 2017-2018 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -15,9 +15,11 @@ #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TRAVERSAL_HPP #include <cstddef> +#include <set> #include <boost/range.hpp> +#include <boost/geometry/algorithms/detail/overlay/cluster_info.hpp> #include <boost/geometry/algorithms/detail/overlay/is_self_turn.hpp> #include <boost/geometry/algorithms/detail/overlay/sort_by_side.hpp> #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp> @@ -103,6 +105,23 @@ template > struct traversal { +private : + struct linked_turn_op_info + { + explicit linked_turn_op_info(signed_size_type ti = -1, int oi = -1, + signed_size_type nti = -1) + : turn_index(ti) + , op_index(oi) + , next_turn_index(nti) + , rank_index(-1) + {} + + signed_size_type turn_index; + int op_index; + signed_size_type next_turn_index; + signed_size_type rank_index; + }; + static const operation_type target_operation = operation_from_overlay<OverlayType>::value; typedef typename side_compare<target_operation>::type side_compare_type; @@ -116,6 +135,7 @@ struct traversal point_type, SideStrategy, side_compare_type > sbs_type; +public : inline traversal(Geometry1 const& geometry1, Geometry2 const& geometry2, Turns& turns, Clusters const& clusters, RobustPolicy const& robust_policy, SideStrategy const& strategy, @@ -352,35 +372,72 @@ struct traversal // If both are valid candidates, take the one with minimal remaining // distance (important for #mysql_23023665 in buffer). - // Initialize with 0, automatically assigned on first result + signed_size_type next[2] = {0}; + bool possible[2] = {0}; + bool close[2] = {0}; + + for (int i = 0; i < 2; i++) + { + next[i] = turn.operations[i].enriched.get_next_turn_index(); + possible[i] = traverse_possible(next[i]); + close[i] = possible[i] && next[i] == start_turn_index; + } + + if (close[0] != close[1]) + { + // One of the operations will finish the ring. Take that one. + selected_op_index = close[0] ? 0 : 1; + debug_traverse(turn, turn.operations[selected_op_index], "Candidate cc closing"); + return true; + } + + if (OverlayType == overlay_buffer && possible[0] && possible[1]) + { + // Buffers sometimes have multiple overlapping pieces, where remaining + // distance could lead to the wrong choice. Take the matching operation. + + bool is_target[2] = {0}; + for (int i = 0; i < 2; i++) + { + turn_operation_type const& next_op = m_turns[next[i]].operations[i]; + is_target[i] = next_op.operation == target_operation; + } + + if (is_target[0] != is_target[1]) + { + // Take the matching operation + selected_op_index = is_target[0] ? 0 : 1; + debug_traverse(turn, turn.operations[selected_op_index], "Candidate cc target"); + return true; + } + } + + static bool const is_union = target_operation == operation_union; + typename turn_operation_type::comparable_distance_type - min_remaining_distance = 0; + best_remaining_distance = 0; bool result = false; for (int i = 0; i < 2; i++) { - turn_operation_type const& op = turn.operations[i]; - - signed_size_type const next_turn_index = op.enriched.get_next_turn_index(); - - if (! traverse_possible(next_turn_index)) + if (!possible[i]) { continue; } + turn_operation_type const& op = turn.operations[i]; + if (! result - || next_turn_index == start_turn_index - || op.remaining_distance < min_remaining_distance) + || (is_union && op.remaining_distance > best_remaining_distance) + || (!is_union && op.remaining_distance < best_remaining_distance)) { debug_traverse(turn, op, "First candidate cc", ! result); - debug_traverse(turn, op, "Candidate cc override (start)", - result && next_turn_index == start_turn_index); debug_traverse(turn, op, "Candidate cc override (remaining)", - result && op.remaining_distance < min_remaining_distance); + result && op.remaining_distance < best_remaining_distance); selected_op_index = i; - min_remaining_distance = op.remaining_distance; + best_remaining_distance = op.remaining_distance; result = true; } } @@ -710,24 +767,163 @@ struct traversal return false; } - inline bool select_turn_from_cluster(signed_size_type& turn_index, + inline signed_size_type get_rank(sbs_type const& sbs, + linked_turn_op_info const& info) const + { + for (std::size_t i = 0; i < sbs.m_ranked_points.size(); i++) + { + typename sbs_type::rp const& rp = sbs.m_ranked_points[i]; + if (rp.turn_index == info.turn_index + && rp.operation_index == info.op_index + && rp.direction == sort_by_side::dir_to) + { + return rp.rank; + } + } + return -1; + } + + // Function checks simple cases, such as a cluster with two turns, + // arriving at the first turn, first turn points to second turn, + // second turn points further. + inline bool select_turn_from_cluster_linked(signed_size_type& turn_index, int& op_index, - signed_size_type start_turn_index, int start_op_index, + std::set<signed_size_type> const& ids, segment_identifier const& previous_seg_id) const { - bool const is_union = target_operation == operation_union; + typedef typename std::set<signed_size_type>::const_iterator sit_type; - turn_type const& turn = m_turns[turn_index]; - BOOST_ASSERT(turn.is_clustered()); + std::vector<linked_turn_op_info> possibilities; + std::vector<linked_turn_op_info> blocked; + for (sit_type it = ids.begin(); it != ids.end(); ++it) + { + signed_size_type cluster_turn_index = *it; + turn_type const& cluster_turn = m_turns[cluster_turn_index]; + if (cluster_turn.discarded) + { + continue; + } + if (is_self_turn<OverlayType>(cluster_turn) + || cluster_turn.both(target_operation)) + { + // Not (yet) supported, can be cluster of u/u turns + return false; + } + for (int i = 0; i < 2; i++) + { + turn_operation_type const& op = cluster_turn.operations[i]; + turn_operation_type const& other_op = cluster_turn.operations[1 - i]; + signed_size_type const ni = op.enriched.get_next_turn_index(); + if (op.operation == target_operation + || op.operation == operation_continue) + { + if (ni == cluster_turn_index) + { + // Not (yet) supported, traveling to itself, can be + // hole + return false; + } + possibilities.push_back( + linked_turn_op_info(cluster_turn_index, i, ni)); + } + else if (op.operation == operation_blocked + && ! (ni == other_op.enriched.get_next_turn_index()) + && ids.count(ni) == 0) + { + // Points to turn, not part of this cluster, + // and that way is blocked. But if the other operation + // points at the same turn, it is still fine. + blocked.push_back( + linked_turn_op_info(cluster_turn_index, i, ni)); + } + } + } - typename Clusters::const_iterator mit = m_clusters.find(turn.cluster_id); - BOOST_ASSERT(mit != m_clusters.end()); + typedef typename std::vector<linked_turn_op_info>::const_iterator const_it_type; - cluster_info const& cinfo = mit->second; - std::set<signed_size_type> const& ids = cinfo.turn_indices; + if (! blocked.empty()) + { + sbs_type sbs(m_strategy); - sbs_type sbs(m_strategy); + if (! fill_sbs(sbs, turn_index, ids, previous_seg_id)) + { + return false; + } + + for (typename std::vector<linked_turn_op_info>::iterator it = possibilities.begin(); + it != possibilities.end(); ++it) + { + linked_turn_op_info& info = *it; + info.rank_index = get_rank(sbs, info); + } + for (typename std::vector<linked_turn_op_info>::iterator it = blocked.begin(); + it != blocked.end(); ++it) + { + linked_turn_op_info& info = *it; + info.rank_index = get_rank(sbs, info); + } + + + for (const_it_type it = possibilities.begin(); + it != possibilities.end(); ++it) + { + linked_turn_op_info const& lti = *it; + for (const_it_type bit = blocked.begin(); + bit != blocked.end(); ++bit) + { + linked_turn_op_info const& blti = *bit; + if (blti.next_turn_index == lti.next_turn_index + && blti.rank_index == lti.rank_index) + { + return false; + } + } + } + } + + // Traversal can either enter the cluster in the first turn, + // or it can start halfway. + // If there is one (and only one) possibility pointing outside + // the cluster, take that one. + linked_turn_op_info target; + for (const_it_type it = possibilities.begin(); + it != possibilities.end(); ++it) + { + linked_turn_op_info const& lti = *it; + if (ids.count(lti.next_turn_index) == 0) + { + if (target.turn_index >= 0 + && target.next_turn_index != lti.next_turn_index) + { + // Points to different target + return false; + } + if (OverlayType == overlay_buffer && target.turn_index > 0) + { + // Target already assigned, so there are more targets + // or more ways to the same target + return false; + } + + target = lti; + } + } + if (target.turn_index < 0) + { + return false; + } + + turn_index = target.turn_index; + op_index = target.op_index; + return true; + } + + inline bool fill_sbs(sbs_type& sbs, + signed_size_type turn_index, + std::set<signed_size_type> const& ids, + segment_identifier const& previous_seg_id) const + { for (typename std::set<signed_size_type>::const_iterator sit = ids.begin(); sit != ids.end(); ++sit) { @@ -753,7 +949,39 @@ struct traversal { return false; } + turn_type const& turn = m_turns[turn_index]; sbs.apply(turn.point); + return true; + } + + + inline bool select_turn_from_cluster(signed_size_type& turn_index, + int& op_index, + signed_size_type start_turn_index, int start_op_index, + segment_identifier const& previous_seg_id) const + { + bool const is_union = target_operation == operation_union; + + turn_type const& turn = m_turns[turn_index]; + BOOST_ASSERT(turn.is_clustered()); + + typename Clusters::const_iterator mit = m_clusters.find(turn.cluster_id); + BOOST_ASSERT(mit != m_clusters.end()); + + cluster_info const& cinfo = mit->second; + std::set<signed_size_type> const& ids = cinfo.turn_indices; + + if (select_turn_from_cluster_linked(turn_index, op_index, ids, previous_seg_id)) + { + return true; + } + + sbs_type sbs(m_strategy); + + if (! fill_sbs(sbs, turn_index, ids, previous_seg_id)) + { + return false; + } bool result = false; diff --git a/boost/geometry/algorithms/detail/overlay/traversal_ring_creator.hpp b/boost/geometry/algorithms/detail/overlay/traversal_ring_creator.hpp index 7f80c8313a..99b2834f15 100644 --- a/boost/geometry/algorithms/detail/overlay/traversal_ring_creator.hpp +++ b/boost/geometry/algorithms/detail/overlay/traversal_ring_creator.hpp @@ -2,8 +2,8 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. -// This file was modified by Oracle on 2017. -// Modifications copyright (c) 2017, Oracle and/or its affiliates. +// This file was modified by Oracle on 2017, 2018. +// Modifications copyright (c) 2017-2018, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, @@ -17,6 +17,7 @@ #include <boost/range.hpp> +#include <boost/geometry/algorithms/detail/overlay/backtrack_check_si.hpp> #include <boost/geometry/algorithms/detail/overlay/copy_segments.hpp> #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp> #include <boost/geometry/algorithms/detail/overlay/traversal.hpp> @@ -208,10 +209,11 @@ struct traversal_ring_creator if (start_turn.is_clustered()) { - turn_type const& turn = m_turns[current_turn_index]; - if (turn.cluster_id == start_turn.cluster_id) + turn_type& turn = m_turns[current_turn_index]; + turn_operation_type& op = turn.operations[current_op_index]; + if (turn.cluster_id == start_turn.cluster_id + && op.enriched.get_next_turn_index() == start_turn_index) { - turn_operation_type& op = m_turns[start_turn_index].operations[current_op_index]; op.visited.set_finished(); m_visitor.visit_traverse(m_turns, m_turns[current_turn_index], start_op, "Early finish (cluster)"); return traverse_error_none; @@ -306,6 +308,23 @@ struct traversal_ring_creator } } + int get_operation_index(turn_type const& turn) const + { + // When starting with a continue operation, the one + // with the smallest (for intersection) or largest (for union) + // remaining distance (#8310b) + // Also to avoid skipping a turn in between, which can happen + // in rare cases (e.g. #130) + static const bool is_union + = operation_from_overlay<OverlayType>::value == operation_union; + + turn_operation_type const& op0 = turn.operations[0]; + turn_operation_type const& op1 = turn.operations[1]; + return op0.remaining_distance <= op1.remaining_distance + ? (is_union ? 1 : 0) + : (is_union ? 0 : 1); + } + template <typename Rings> void iterate(Rings& rings, std::size_t& finalized_ring_size, typename Backtrack::state_type& state) @@ -322,15 +341,8 @@ struct traversal_ring_creator if (turn.both(operation_continue)) { - // Traverse only one turn, the one with the SMALLEST remaining distance - // to avoid skipping a turn in between, which can happen in rare cases - // (e.g. #130) - turn_operation_type const& op0 = turn.operations[0]; - turn_operation_type const& op1 = turn.operations[1]; - int const op_index - = op0.remaining_distance <= op1.remaining_distance ? 0 : 1; - - traverse_with_operation(turn, turn_index, op_index, + traverse_with_operation(turn, turn_index, + get_operation_index(turn), rings, finalized_ring_size, state); } else @@ -373,13 +385,8 @@ struct traversal_ring_creator if (turn.both(operation_continue)) { - // Traverse only one turn, the one with the SMALLEST remaining distance - // to avoid skipping a turn in between, which can happen in rare cases - // (e.g. #130) - int const op_index - = op0.remaining_distance <= op1.remaining_distance ? 0 : 1; - - traverse_with_operation(turn, turn_index, op_index, + traverse_with_operation(turn, turn_index, + get_operation_index(turn), rings, finalized_ring_size, state); } else diff --git a/boost/geometry/algorithms/detail/overlay/traversal_switch_detector.hpp b/boost/geometry/algorithms/detail/overlay/traversal_switch_detector.hpp index 8bdb03df5d..2732531324 100644 --- a/boost/geometry/algorithms/detail/overlay/traversal_switch_detector.hpp +++ b/boost/geometry/algorithms/detail/overlay/traversal_switch_detector.hpp @@ -2,6 +2,11 @@ // Copyright (c) 2015-2016 Barend Gehrels, Amsterdam, the Netherlands. +// This file was modified by Oracle on 2018. +// Modifications copyright (c) 2018 Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + // 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) @@ -10,6 +15,7 @@ #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TRAVERSAL_SWITCH_DETECTOR_HPP #include <cstddef> +#include <map> #include <boost/range.hpp> diff --git a/boost/geometry/algorithms/detail/point_on_border.hpp b/boost/geometry/algorithms/detail/point_on_border.hpp index 831081aa69..b3e14fecbd 100644 --- a/boost/geometry/algorithms/detail/point_on_border.hpp +++ b/boost/geometry/algorithms/detail/point_on_border.hpp @@ -4,8 +4,8 @@ // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. -// This file was modified by Oracle on 2017. -// Modifications copyright (c) 2017 Oracle and/or its affiliates. +// This file was modified by Oracle on 2017, 2018. +// Modifications copyright (c) 2017-2018 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library @@ -56,117 +56,47 @@ struct get_point } }; -template<typename Point, std::size_t Dimension, std::size_t DimensionCount> -struct midpoint_helper -{ - template <typename InputPoint> - static inline bool apply(Point& p, InputPoint const& p1, InputPoint const& p2) - { - typename coordinate_type<Point>::type const two = 2; - set<Dimension>(p, - (get<Dimension>(p1) + get<Dimension>(p2)) / two); - return midpoint_helper<Point, Dimension + 1, DimensionCount>::apply(p, p1, p2); - } -}; - -template <typename Point, std::size_t DimensionCount> -struct midpoint_helper<Point, DimensionCount, DimensionCount> -{ - template <typename InputPoint> - static inline bool apply(Point& , InputPoint const& , InputPoint const& ) - { - return true; - } -}; - - -template <bool Midpoint> struct point_on_range { // Version with iterator template<typename Point, typename Iterator> static inline bool apply(Point& point, Iterator begin, Iterator end) { - Iterator it = begin; - if (it == end) + if (begin == end) { return false; } - if (! Midpoint) - { - geometry::detail::conversion::convert_point_to_point(*it, point); - return true; - } - - Iterator prev = it++; - - // Go to next non-duplicate point - while (it != end - && detail::equals::equals_point_point(*it, *prev)) - { - prev = it++; - } - if (it != end) - { - return midpoint_helper - < - Point, - 0, dimension<Point>::value - >::apply(point, *prev, *it); - } - return false; + geometry::detail::conversion::convert_point_to_point(*begin, point); + return true; } // Version with range template<typename Point, typename Range> static inline bool apply(Point& point, Range const& range) { - typedef typename geometry::cs_tag<Point>::type cs_tag; - BOOST_STATIC_ASSERT((! Midpoint || boost::is_same<cs_tag, cartesian_tag>::value)); - return apply(point, boost::begin(range), boost::end(range)); } }; -template <bool Midpoint> struct point_on_polygon { template<typename Point, typename Polygon> static inline bool apply(Point& point, Polygon const& polygon) { - return point_on_range - < - Midpoint - >::apply(point, exterior_ring(polygon)); + return point_on_range::apply(point, exterior_ring(polygon)); } }; -template <bool Midpoint> struct point_on_box { template<typename Point, typename Box> static inline bool apply(Point& point, Box const& box) { - if (BOOST_GEOMETRY_CONDITION(Midpoint)) - { - Point p1, p2; - detail::assign::assign_box_2d_corner<min_corner, min_corner>(box, p1); - detail::assign::assign_box_2d_corner<max_corner, min_corner>(box, p2); - midpoint_helper - < - Point, - 0, dimension<Point>::value - >::apply(point, p1, p2); - } - else - { - detail::assign::assign_box_2d_corner<min_corner, min_corner>(box, point); - } - + detail::assign::assign_box_2d_corner<min_corner, min_corner>(box, point); return true; } }; @@ -206,60 +136,50 @@ namespace dispatch { -template -< - typename GeometryTag, - bool Midpoint - -> +template <typename GeometryTag> struct point_on_border {}; - -template <bool Midpoint> -struct point_on_border<point_tag, Midpoint> +template <> +struct point_on_border<point_tag> : detail::point_on_border::get_point {}; - -template <bool Midpoint> -struct point_on_border<linestring_tag, Midpoint> - : detail::point_on_border::point_on_range<Midpoint> +template <> +struct point_on_border<linestring_tag> + : detail::point_on_border::point_on_range {}; - -template <bool Midpoint> -struct point_on_border<ring_tag, Midpoint> - : detail::point_on_border::point_on_range<Midpoint> +template <> +struct point_on_border<ring_tag> + : detail::point_on_border::point_on_range {}; - -template <bool Midpoint> -struct point_on_border<polygon_tag, Midpoint> - : detail::point_on_border::point_on_polygon<Midpoint> +template <> +struct point_on_border<polygon_tag> + : detail::point_on_border::point_on_polygon {}; - -template <bool Midpoint> -struct point_on_border<box_tag, Midpoint> - : detail::point_on_border::point_on_box<Midpoint> +template <> +struct point_on_border<box_tag> + : detail::point_on_border::point_on_box {}; -template <bool Midpoint> -struct point_on_border<multi_polygon_tag, Midpoint> +template <> +struct point_on_border<multi_polygon_tag> : detail::point_on_border::point_on_multi < - detail::point_on_border::point_on_polygon<Midpoint> + detail::point_on_border::point_on_polygon > {}; -template <bool Midpoint> -struct point_on_border<multi_linestring_tag, Midpoint> +template <> +struct point_on_border<multi_linestring_tag> : detail::point_on_border::point_on_multi < - detail::point_on_border::point_on_range<Midpoint> + detail::point_on_border::point_on_range > {}; @@ -286,33 +206,11 @@ inline bool point_on_border(Point& point, Geometry const& geometry) return dispatch::point_on_border < - typename tag<Geometry>::type, - false + typename tag<Geometry>::type >::apply(point, geometry); } -/*! -\tparam Midpoint boolean flag, true if the point should not be a vertex, but some point - in between of two vertices -\note for Midpoint, it is not taken from two consecutive duplicate vertices, - (unless there are no other). - */ -/* -template <bool Midpoint, typename Point, typename Geometry> -inline bool point_on_border(Point& point, Geometry const& geometry) -{ - concepts::check<Point>(); - concepts::check<Geometry const>(); - - return dispatch::point_on_border - < - typename tag<Geometry>::type, - Midpoint - >::apply(point, geometry); -} -*/ - }} // namespace boost::geometry diff --git a/boost/geometry/algorithms/detail/relate/areal_areal.hpp b/boost/geometry/algorithms/detail/relate/areal_areal.hpp index 800fbb2e96..fa0ab1ea0f 100644 --- a/boost/geometry/algorithms/detail/relate/areal_areal.hpp +++ b/boost/geometry/algorithms/detail/relate/areal_areal.hpp @@ -2,8 +2,8 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. -// This file was modified by Oracle on 2013, 2014, 2015, 2017. -// Modifications copyright (c) 2013-2017 Oracle and/or its affiliates. +// This file was modified by Oracle on 2013, 2014, 2015, 2017, 2018. +// Modifications copyright (c) 2013-2018 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -277,7 +277,8 @@ struct areal_areal { // analyse sorted turns turns_analyser<turn_type, 0> analyser; - analyse_each_turn(result, analyser, turns.begin(), turns.end()); + analyse_each_turn(result, analyser, turns.begin(), turns.end(), + point_in_areal_strategy12.get_equals_point_point_strategy()); if ( BOOST_GEOMETRY_CONDITION(result.interrupt) ) return; @@ -317,7 +318,8 @@ struct areal_areal { // analyse sorted turns turns_analyser<turn_type, 1> analyser; - analyse_each_turn(result, analyser, turns.begin(), turns.end()); + analyse_each_turn(result, analyser, turns.begin(), turns.end(), + point_in_areal_strategy21.get_equals_point_point_strategy()); if ( BOOST_GEOMETRY_CONDITION(result.interrupt) ) return; @@ -441,9 +443,8 @@ struct areal_areal , m_exit_detected(false) {} - template <typename Result, - typename TurnIt> - void apply(Result & result, TurnIt it) + template <typename Result, typename TurnIt, typename EqPPStrategy> + void apply(Result & result, TurnIt it, EqPPStrategy const& strategy) { //BOOST_GEOMETRY_ASSERT( it != last ); @@ -468,7 +469,7 @@ struct areal_areal { // real exit point - may be multiple if ( first_in_range - || ! turn_on_the_same_ip<op_id>(*m_previous_turn_ptr, *it) ) + || ! turn_on_the_same_ip<op_id>(*m_previous_turn_ptr, *it, strategy) ) { update_exit(result); m_exit_detected = false; @@ -484,7 +485,7 @@ struct areal_areal { // real entry point if ( first_in_range - || ! turn_on_the_same_ip<op_id>(*m_previous_turn_ptr, *it) ) + || ! turn_on_the_same_ip<op_id>(*m_previous_turn_ptr, *it, strategy) ) { update_enter(result); m_enter_detected = false; @@ -581,19 +582,24 @@ struct areal_areal // call analyser.apply() for each turn in range // IMPORTANT! The analyser is also called for the end iterator - last - template <typename Result, - typename Analyser, - typename TurnIt> + template + < + typename Result, + typename Analyser, + typename TurnIt, + typename EqPPStrategy + > static inline void analyse_each_turn(Result & res, Analyser & analyser, - TurnIt first, TurnIt last) + TurnIt first, TurnIt last, + EqPPStrategy const& strategy) { if ( first == last ) return; for ( TurnIt it = first ; it != last ; ++it ) { - analyser.apply(res, it); + analyser.apply(res, it, strategy); if ( BOOST_GEOMETRY_CONDITION(res.interrupt) ) return; diff --git a/boost/geometry/algorithms/detail/relate/boundary_checker.hpp b/boost/geometry/algorithms/detail/relate/boundary_checker.hpp index 99385e06f9..dc927d9026 100644 --- a/boost/geometry/algorithms/detail/relate/boundary_checker.hpp +++ b/boost/geometry/algorithms/detail/relate/boundary_checker.hpp @@ -1,24 +1,26 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014 Oracle and/or its affiliates. +// Copyright (c) 2014-2018 Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // 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) -// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle - #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_BOUNDARY_CHECKER_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_BOUNDARY_CHECKER_HPP #include <boost/core/ignore_unused.hpp> -#include <boost/geometry/util/range.hpp> -#include <boost/geometry/algorithms/num_points.hpp> -#include <boost/geometry/algorithms/detail/sub_range.hpp> #include <boost/geometry/algorithms/detail/equals/point_point.hpp> +#include <boost/geometry/algorithms/detail/sub_range.hpp> +#include <boost/geometry/algorithms/num_points.hpp> + +#include <boost/geometry/policies/compare.hpp> #include <boost/geometry/util/has_nan_coordinate.hpp> +#include <boost/geometry/util/range.hpp> namespace boost { namespace geometry { @@ -29,19 +31,26 @@ namespace detail { namespace relate { enum boundary_query { boundary_front, boundary_back, boundary_any }; template <typename Geometry, + typename WithinStrategy, // Point/Point equals (within) strategy typename Tag = typename geometry::tag<Geometry>::type> class boundary_checker {}; -template <typename Geometry> -class boundary_checker<Geometry, linestring_tag> +template <typename Geometry, typename WithinStrategy> +class boundary_checker<Geometry, WithinStrategy, linestring_tag> { typedef typename point_type<Geometry>::type point_type; public: + typedef WithinStrategy equals_strategy_type; + boundary_checker(Geometry const& g) : has_boundary( boost::size(g) >= 2 - && !detail::equals::equals_point_point(range::front(g), range::back(g)) ) + && !detail::equals::equals_point_point(range::front(g), + range::back(g), + equals_strategy_type()) ) +#ifdef BOOST_GEOMETRY_DEBUG_RELATE_BOUNDARY_CHECKER , geometry(g) +#endif {} template <boundary_query BoundaryQuery> @@ -51,24 +60,28 @@ public: #ifdef BOOST_GEOMETRY_DEBUG_RELATE_BOUNDARY_CHECKER // may give false positives for INT BOOST_GEOMETRY_ASSERT( (BoundaryQuery == boundary_front || BoundaryQuery == boundary_any) - && detail::equals::equals_point_point(pt, range::front(geometry)) + && detail::equals::equals_point_point(pt, range::front(geometry), WithinStrategy()) || (BoundaryQuery == boundary_back || BoundaryQuery == boundary_any) - && detail::equals::equals_point_point(pt, range::back(geometry)) ); + && detail::equals::equals_point_point(pt, range::back(geometry), WithinStrategy()) ); #endif return has_boundary; } private: bool has_boundary; +#ifdef BOOST_GEOMETRY_DEBUG_RELATE_BOUNDARY_CHECKER Geometry const& geometry; +#endif }; -template <typename Geometry> -class boundary_checker<Geometry, multi_linestring_tag> +template <typename Geometry, typename WithinStrategy> +class boundary_checker<Geometry, WithinStrategy, multi_linestring_tag> { typedef typename point_type<Geometry>::type point_type; public: + typedef WithinStrategy equals_strategy_type; + boundary_checker(Geometry const& g) : is_filled(false), geometry(g) {} @@ -111,7 +124,7 @@ public: point_reference back_pt = range::back(ls); // linear ring or point - no boundary - if (! equals::equals_point_point(front_pt, back_pt)) + if (! equals::equals_point_point(front_pt, back_pt, equals_strategy_type())) { // do not add points containing NaN coordinates // because they cannot be reasonably compared, e.g. with MSVC diff --git a/boost/geometry/algorithms/detail/relate/follow_helpers.hpp b/boost/geometry/algorithms/detail/relate/follow_helpers.hpp index 11e95a0b35..139664cc7c 100644 --- a/boost/geometry/algorithms/detail/relate/follow_helpers.hpp +++ b/boost/geometry/algorithms/detail/relate/follow_helpers.hpp @@ -2,25 +2,33 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. -// This file was modified by Oracle on 2013, 2014. -// Modifications copyright (c) 2013-2014 Oracle and/or its affiliates. +// This file was modified by Oracle on 2013, 2014, 2018. +// Modifications copyright (c) 2013-2018 Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // 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) -// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_FOLLOW_HELPERS_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_FOLLOW_HELPERS_HPP +#include <vector> + #include <boost/core/ignore_unused.hpp> +#include <boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp> +#include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp> +#include <boost/geometry/algorithms/detail/overlay/segment_identifier.hpp> +#include <boost/geometry/algorithms/detail/relate/boundary_checker.hpp> +#include <boost/geometry/algorithms/not_implemented.hpp> + #include <boost/geometry/core/assert.hpp> #include <boost/geometry/util/condition.hpp> #include <boost/geometry/util/range.hpp> -//#include <boost/geometry/algorithms/detail/sub_range.hpp> namespace boost { namespace geometry { @@ -333,8 +341,9 @@ private: std::vector<point_info> m_other_entry_points; // TODO: use map here or sorted vector? }; -template <std::size_t OpId, typename Turn> -inline bool turn_on_the_same_ip(Turn const& prev_turn, Turn const& curr_turn) +template <std::size_t OpId, typename Turn, typename EqPPStrategy> +inline bool turn_on_the_same_ip(Turn const& prev_turn, Turn const& curr_turn, + EqPPStrategy const& strategy) { segment_identifier const& prev_seg_id = prev_turn.operations[OpId].seg_id; segment_identifier const& curr_seg_id = curr_turn.operations[OpId].seg_id; @@ -354,7 +363,7 @@ inline bool turn_on_the_same_ip(Turn const& prev_turn, Turn const& curr_turn) return false; } - return detail::equals::equals_point_point(prev_turn.point, curr_turn.point); + return detail::equals::equals_point_point(prev_turn.point, curr_turn.point, strategy); } template <boundary_query BoundaryQuery, diff --git a/boost/geometry/algorithms/detail/relate/linear_areal.hpp b/boost/geometry/algorithms/detail/relate/linear_areal.hpp index ddbd7d615a..81fc9e5b3b 100644 --- a/boost/geometry/algorithms/detail/relate/linear_areal.hpp +++ b/boost/geometry/algorithms/detail/relate/linear_areal.hpp @@ -2,8 +2,8 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. -// This file was modified by Oracle on 2013, 2014, 2015, 2017. -// Modifications copyright (c) 2013-2017 Oracle and/or its affiliates. +// This file was modified by Oracle on 2013, 2014, 2015, 2017, 2018. +// Modifications copyright (c) 2013-2018 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -262,13 +262,22 @@ struct linear_areal typedef typename IntersectionStrategy::template point_in_geometry_strategy<Geometry1, Geometry2>::type within_strategy_type; within_strategy_type const within_strategy = intersection_strategy.template get_point_in_geometry_strategy<Geometry1, Geometry2>(); - boundary_checker<Geometry1> boundary_checker1(geometry1); + + typedef typename within_strategy_type::equals_point_point_strategy_type eq_pp_strategy_type; + + typedef boundary_checker + < + Geometry1, + eq_pp_strategy_type + > boundary_checker1_type; + boundary_checker1_type boundary_checker1(geometry1); + no_turns_la_linestring_pred < Geometry2, Result, within_strategy_type, - boundary_checker<Geometry1>, + boundary_checker1_type, TransposeResult > pred1(geometry2, result, @@ -393,12 +402,14 @@ struct linear_areal typedef turns::less<1, turns::less_op_areal_linear<1> > less; std::sort(it, next, less()); + eq_pp_strategy_type const eq_pp_strategy = within_strategy.get_equals_point_point_strategy(); + // analyse areal_boundary_analyser<turn_type> analyser; for ( turn_iterator rit = it ; rit != next ; ++rit ) { // if the analyser requests, break the search - if ( !analyser.apply(it, rit, next) ) + if ( !analyser.apply(it, rit, next, eq_pp_strategy) ) break; } @@ -621,6 +632,37 @@ struct linear_areal static const std::size_t op_id = 0; static const std::size_t other_op_id = 1; + template <typename TurnPointCSTag, typename PointP, typename PointQ, + typename SideStrategy, + typename Pi = PointP, typename Pj = PointP, typename Pk = PointP, + typename Qi = PointQ, typename Qj = PointQ, typename Qk = PointQ + > + struct la_side_calculator + { + inline la_side_calculator(Pi const& pi, Pj const& pj, Pk const& pk, + Qi const& qi, Qj const& qj, Qk const& qk, + SideStrategy const& side_strategy) + : m_pi(pi), m_pj(pj), m_pk(pk) + , m_qi(qi), m_qj(qj), m_qk(qk) + , m_side_strategy(side_strategy) + {} + + inline int pk_wrt_p1() const { return m_side_strategy.apply(m_pi, m_pj, m_pk); } + inline int qk_wrt_p1() const { return m_side_strategy.apply(m_pi, m_pj, m_qk); } + inline int pk_wrt_q2() const { return m_side_strategy.apply(m_qj, m_qk, m_pk); } + + private : + Pi const& m_pi; + Pj const& m_pj; + Pk const& m_pk; + Qi const& m_qi; + Qj const& m_qj; + Qk const& m_qk; + + SideStrategy m_side_strategy; + }; + + public: turns_analyser() : m_previous_turn_ptr(NULL) @@ -670,7 +712,8 @@ struct linear_areal { // real exit point - may be multiple // we know that we entered and now we exit - if ( ! turn_on_the_same_ip<op_id>(m_exit_watcher.get_exit_turn(), *it) ) + if ( ! turn_on_the_same_ip<op_id>(m_exit_watcher.get_exit_turn(), *it, + side_strategy.get_equals_point_point_strategy()) ) { m_exit_watcher.reset_detected_exit(); @@ -712,7 +755,8 @@ struct linear_areal if ( ( op == overlay::operation_intersection || op == overlay::operation_continue ) - && turn_on_the_same_ip<op_id>(m_exit_watcher.get_exit_turn(), *it) ) + && turn_on_the_same_ip<op_id>(m_exit_watcher.get_exit_turn(), *it, + side_strategy.get_equals_point_point_strategy()) ) { fake_enter_detected = true; } @@ -732,7 +776,8 @@ struct linear_areal && ( op != overlay::operation_blocked // operation different than block || seg_id.multi_index != m_previous_turn_ptr->operations[op_id].seg_id.multi_index ) ) // or the next single-geometry || ( m_previous_operation == overlay::operation_union - && ! turn_on_the_same_ip<op_id>(*m_previous_turn_ptr, *it) ) + && ! turn_on_the_same_ip<op_id>(*m_previous_turn_ptr, *it, + side_strategy.get_equals_point_point_strategy()) ) ) { update<interior, exterior, '1', TransposeResult>(res); @@ -764,7 +809,8 @@ struct linear_areal BOOST_GEOMETRY_ASSERT_MSG(m_previous_turn_ptr, "non-NULL ptr expected"); // real interior overlap - if ( ! turn_on_the_same_ip<op_id>(*m_previous_turn_ptr, *it) ) + if ( ! turn_on_the_same_ip<op_id>(*m_previous_turn_ptr, *it, + side_strategy.get_equals_point_point_strategy()) ) { update<interior, interior, '1', TransposeResult>(res); m_interior_detected = false; @@ -1203,7 +1249,7 @@ struct linear_areal point2_type const& qj = range::at(range2, q_seg_ij + 1); point1_type qi_conv; geometry::convert(qi, qi_conv); - bool const is_ip_qj = equals::equals_point_point(turn.point, qj); + bool const is_ip_qj = equals::equals_point_point(turn.point, qj, side_strategy.get_equals_point_point_strategy()); // TODO: test this! // BOOST_GEOMETRY_ASSERT(!equals::equals_point_point(turn.point, pi)); // BOOST_GEOMETRY_ASSERT(!equals::equals_point_point(turn.point, qi)); @@ -1217,10 +1263,11 @@ struct linear_areal // It would be good to replace it with some O(1) mechanism range2_iterator qk_it = find_next_non_duplicated(boost::begin(range2), range::pos(range2, q_seg_jk), - boost::end(range2)); + boost::end(range2), + side_strategy.get_equals_point_point_strategy()); // Will this sequence of points be always correct? - overlay::side_calculator<cs_tag, point1_type, point2_type, SideStrategy> + la_side_calculator<cs_tag, point1_type, point2_type, SideStrategy> side_calc(qi_conv, new_pj, pi, qi, qj, *qk_it, side_strategy); return calculate_from_inside_sides(side_calc); @@ -1230,15 +1277,16 @@ struct linear_areal point2_type new_qj; geometry::convert(turn.point, new_qj); - overlay::side_calculator<cs_tag, point1_type, point2_type, SideStrategy> + la_side_calculator<cs_tag, point1_type, point2_type, SideStrategy> side_calc(qi_conv, new_pj, pi, qi, new_qj, qj, side_strategy); return calculate_from_inside_sides(side_calc); } } - template <typename It> - static inline It find_next_non_duplicated(It first, It current, It last) + template <typename It, typename EqPPStrategy> + static inline It find_next_non_duplicated(It first, It current, It last, + EqPPStrategy const& strategy) { BOOST_GEOMETRY_ASSERT( current != last ); @@ -1246,14 +1294,14 @@ struct linear_areal for ( ++it ; it != last ; ++it ) { - if ( !equals::equals_point_point(*current, *it) ) + if ( !equals::equals_point_point(*current, *it, strategy) ) return it; } // if not found start from the beginning for ( it = first ; it != current ; ++it ) { - if ( !equals::equals_point_point(*current, *it) ) + if ( !equals::equals_point_point(*current, *it, strategy) ) return it; } @@ -1396,8 +1444,9 @@ struct linear_areal , m_previous_turn_ptr(NULL) {} - template <typename TurnIt> - bool apply(TurnIt /*first*/, TurnIt it, TurnIt last) + template <typename TurnIt, typename EqPPStrategy> + bool apply(TurnIt /*first*/, TurnIt it, TurnIt last, + EqPPStrategy const& strategy) { overlay::operation_type op = it->operations[1].operation; @@ -1412,7 +1461,7 @@ struct linear_areal if ( is_union_detected ) { BOOST_GEOMETRY_ASSERT(m_previous_turn_ptr != NULL); - if ( !detail::equals::equals_point_point(it->point, m_previous_turn_ptr->point) ) + if ( !detail::equals::equals_point_point(it->point, m_previous_turn_ptr->point, strategy) ) { // break return false; diff --git a/boost/geometry/algorithms/detail/relate/linear_linear.hpp b/boost/geometry/algorithms/detail/relate/linear_linear.hpp index 520f2bd775..6c5d82fdea 100644 --- a/boost/geometry/algorithms/detail/relate/linear_linear.hpp +++ b/boost/geometry/algorithms/detail/relate/linear_linear.hpp @@ -2,8 +2,8 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. -// This file was modified by Oracle on 2013, 2014, 2015, 2017. -// Modifications copyright (c) 2013-2017 Oracle and/or its affiliates. +// This file was modified by Oracle on 2013, 2014, 2015, 2017, 2018. +// Modifications copyright (c) 2013-2018 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -42,6 +42,8 @@ namespace detail { namespace relate { template <typename Result, typename BoundaryChecker, bool TransposeResult> class disjoint_linestring_pred { + typedef typename BoundaryChecker::equals_strategy_type equals_strategy_type; + public: disjoint_linestring_pred(Result & res, BoundaryChecker const& boundary_checker) @@ -80,7 +82,8 @@ public: // point-like linestring if ( count == 2 && equals::equals_point_point(range::front(linestring), - range::back(linestring)) ) + range::back(linestring), + equals_strategy_type()) ) { update<interior, exterior, '0', TransposeResult>(m_result); } @@ -145,14 +148,24 @@ struct linear_linear if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) ) return; - boundary_checker<Geometry1> boundary_checker1(geometry1); - disjoint_linestring_pred<Result, boundary_checker<Geometry1>, false> pred1(result, boundary_checker1); + typedef boundary_checker + < + Geometry1, + typename IntersectionStrategy::point_in_point_strategy_type + > boundary_checker1_type; + boundary_checker1_type boundary_checker1(geometry1); + disjoint_linestring_pred<Result, boundary_checker1_type, false> pred1(result, boundary_checker1); for_each_disjoint_geometry_if<0, Geometry1>::apply(turns.begin(), turns.end(), geometry1, pred1); if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) ) return; - boundary_checker<Geometry2> boundary_checker2(geometry2); - disjoint_linestring_pred<Result, boundary_checker<Geometry2>, true> pred2(result, boundary_checker2); + typedef boundary_checker + < + Geometry2, + typename IntersectionStrategy::point_in_point_strategy_type + > boundary_checker2_type; + boundary_checker2_type boundary_checker2(geometry2); + disjoint_linestring_pred<Result, boundary_checker2_type, true> pred2(result, boundary_checker2); for_each_disjoint_geometry_if<1, Geometry2>::apply(turns.begin(), turns.end(), geometry2, pred2); if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) ) return; @@ -274,6 +287,8 @@ struct linear_linear BoundaryChecker const& boundary_checker, OtherBoundaryChecker const& other_boundary_checker) { + typedef typename BoundaryChecker::equals_strategy_type equals_strategy_type; + overlay::operation_type const op = it->operations[op_id].operation; segment_identifier const& seg_id = it->operations[op_id].seg_id; @@ -323,7 +338,9 @@ struct linear_linear { // real exit point - may be multiple // we know that we entered and now we exit - if ( ! turn_on_the_same_ip<op_id>(m_exit_watcher.get_exit_turn(), *it) ) + if ( ! turn_on_the_same_ip<op_id>(m_exit_watcher.get_exit_turn(), + *it, + equals_strategy_type()) ) { m_exit_watcher.reset_detected_exit(); @@ -344,7 +361,9 @@ struct linear_linear return; if ( op == overlay::operation_intersection - && turn_on_the_same_ip<op_id>(m_exit_watcher.get_exit_turn(), *it) ) + && turn_on_the_same_ip<op_id>(m_exit_watcher.get_exit_turn(), + *it, + equals_strategy_type()) ) { fake_enter_detected = true; } @@ -647,6 +666,11 @@ struct linear_linear OtherBoundaryChecker const& /*other_boundary_checker*/, bool first_in_range) { + typedef typename BoundaryChecker::equals_strategy_type + equals_strategy1_type; + typedef typename OtherBoundaryChecker::equals_strategy_type + equals_strategy2_type; + typename detail::single_geometry_return_type<Geometry const>::type ls1_ref = detail::single_geometry(geometry, turn.operations[op_id].seg_id); typename detail::single_geometry_return_type<OtherGeometry const>::type @@ -714,9 +738,13 @@ struct linear_linear // here we don't know which one is degenerated bool const is_point1 = boost::size(ls1_ref) == 2 - && equals::equals_point_point(range::front(ls1_ref), range::back(ls1_ref)); + && equals::equals_point_point(range::front(ls1_ref), + range::back(ls1_ref), + equals_strategy1_type()); bool const is_point2 = boost::size(ls2_ref) == 2 - && equals::equals_point_point(range::front(ls2_ref), range::back(ls2_ref)); + && equals::equals_point_point(range::front(ls2_ref), + range::back(ls2_ref), + equals_strategy2_type()); // if the second one is degenerated if ( !is_point1 && is_point2 ) diff --git a/boost/geometry/algorithms/detail/relate/multi_point_geometry.hpp b/boost/geometry/algorithms/detail/relate/multi_point_geometry.hpp index 8d5f21555c..8dec5ccdaf 100644 --- a/boost/geometry/algorithms/detail/relate/multi_point_geometry.hpp +++ b/boost/geometry/algorithms/detail/relate/multi_point_geometry.hpp @@ -1,6 +1,6 @@ // Boost.Geometry -// Copyright (c) 2017 Oracle and/or its affiliates. +// Copyright (c) 2017-2018 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -17,6 +17,7 @@ #include <boost/geometry/algorithms/detail/disjoint/box_box.hpp> #include <boost/geometry/algorithms/detail/disjoint/point_box.hpp> #include <boost/geometry/algorithms/detail/expand_by_epsilon.hpp> +#include <boost/geometry/algorithms/detail/partition.hpp> #include <boost/geometry/algorithms/detail/relate/result.hpp> #include <boost/geometry/algorithms/detail/relate/topology_check.hpp> #include <boost/geometry/algorithms/detail/within/point_in_geometry.hpp> @@ -40,20 +41,21 @@ namespace detail { namespace relate template < typename Geometry, + typename EqPPStrategy, typename Tag = typename tag<Geometry>::type > struct multi_point_geometry_eb { template <typename MultiPoint> static inline bool apply(MultiPoint const& , - detail::relate::topology_check<Geometry> const& ) + detail::relate::topology_check<Geometry, EqPPStrategy> const& ) { return true; } }; -template <typename Geometry> -struct multi_point_geometry_eb<Geometry, linestring_tag> +template <typename Geometry, typename EqPPStrategy> +struct multi_point_geometry_eb<Geometry, EqPPStrategy, linestring_tag> { template <typename Points> struct boundary_visitor @@ -73,7 +75,7 @@ struct multi_point_geometry_eb<Geometry, linestring_tag> template <typename Pt> bool operator()(Pt const& pt) const { - return detail::equals::equals_point_point(pt, m_point); + return detail::equals::equals_point_point(pt, m_point, EqPPStrategy()); } Point const& m_point; @@ -99,7 +101,7 @@ struct multi_point_geometry_eb<Geometry, linestring_tag> template <typename MultiPoint> static inline bool apply(MultiPoint const& multi_point, - detail::relate::topology_check<Geometry> const& tc) + detail::relate::topology_check<Geometry, EqPPStrategy> const& tc) { boundary_visitor<MultiPoint> visitor(multi_point); tc.for_each_boundary_point(visitor); @@ -107,9 +109,12 @@ struct multi_point_geometry_eb<Geometry, linestring_tag> } }; -template <typename Geometry> -struct multi_point_geometry_eb<Geometry, multi_linestring_tag> +template <typename Geometry, typename EqPPStrategy> +struct multi_point_geometry_eb<Geometry, EqPPStrategy, multi_linestring_tag> { + // TODO: CS-specific less compare strategy derived from EqPPStrategy + typedef geometry::less<> less_type; + template <typename Points> struct boundary_visitor { @@ -121,7 +126,7 @@ struct multi_point_geometry_eb<Geometry, multi_linestring_tag> template <typename Point> bool apply(Point const& boundary_point) { - if (! std::binary_search(m_points.begin(), m_points.end(), boundary_point, geometry::less<>())) + if (! std::binary_search(m_points.begin(), m_points.end(), boundary_point, less_type())) { m_boundary_found = true; return false; @@ -138,12 +143,12 @@ struct multi_point_geometry_eb<Geometry, multi_linestring_tag> template <typename MultiPoint> static inline bool apply(MultiPoint const& multi_point, - detail::relate::topology_check<Geometry> const& tc) + detail::relate::topology_check<Geometry, EqPPStrategy> const& tc) { typedef typename boost::range_value<MultiPoint>::type point_type; typedef std::vector<point_type> points_type; points_type points(boost::begin(multi_point), boost::end(multi_point)); - std::sort(points.begin(), points.end(), geometry::less<>()); + std::sort(points.begin(), points.end(), less_type()); boundary_visitor<points_type> visitor(points); tc.for_each_boundary_point(visitor); @@ -165,6 +170,8 @@ struct multi_point_single_geometry { typedef typename point_type<SingleGeometry>::type point2_type; typedef model::box<point2_type> box2_type; + typedef typename Strategy::equals_point_point_strategy_type eq_pp_strategy_type; + typedef typename Strategy::disjoint_point_box_strategy_type d_pb_strategy_type; box2_type box2; geometry::envelope(single_geometry, box2, strategy.get_envelope_strategy()); @@ -181,7 +188,7 @@ struct multi_point_single_geometry } // The default strategy is enough for Point/Box - if (detail::disjoint::disjoint_point_box(*it, box2)) + if (detail::disjoint::disjoint_point_box(*it, box2, d_pb_strategy_type())) { relate::set<interior, exterior, '0', Transpose>(result); } @@ -209,7 +216,10 @@ struct multi_point_single_geometry } } - typedef detail::relate::topology_check<SingleGeometry> tc_t; + typedef detail::relate::topology_check + < + SingleGeometry, eq_pp_strategy_type + > tc_t; if ( relate::may_update<exterior, interior, tc_t::interior, Transpose>(result) || relate::may_update<exterior, boundary, tc_t::boundary, Transpose>(result) ) { @@ -226,8 +236,13 @@ struct multi_point_single_geometry if ( relate::may_update<exterior, boundary, tc_t::boundary, Transpose>(result) && tc.has_boundary() ) { - if (multi_point_geometry_eb<SingleGeometry>::apply(multi_point, tc)) + if (multi_point_geometry_eb + < + SingleGeometry, eq_pp_strategy_type + >::apply(multi_point, tc)) + { relate::set<exterior, boundary, tc_t::boundary, Transpose>(result); + } } } @@ -260,32 +275,40 @@ class multi_point_multi_geometry_ii_ib } }; + template <typename DisjointPointBoxStrategy> struct overlaps_box_point { template <typename Box, typename Point> static inline bool apply(Box const& box, Point const& point) { // The default strategy is enough for Point/Box - return ! detail::disjoint::disjoint_point_box(point, box); + return ! detail::disjoint::disjoint_point_box(point, box, + DisjointPointBoxStrategy()); } }; + template <typename DisjointBoxBoxStrategy> struct overlaps_box_box_pair { template <typename Box, typename BoxPair> static inline bool apply(Box const& box, BoxPair const& box_pair) { // The default strategy is enough for Box/Box - return ! detail::disjoint::disjoint_box_box(box_pair.first, box); + return ! detail::disjoint::disjoint_box_box(box_pair.first, box, + DisjointBoxBoxStrategy()); } }; template <typename Result, typename PtSegStrategy> class item_visitor_type { + typedef typename PtSegStrategy::equals_point_point_strategy_type pp_strategy_type; + typedef typename PtSegStrategy::disjoint_point_box_strategy_type d_pp_strategy_type; + typedef detail::relate::topology_check<MultiGeometry, pp_strategy_type> topology_check_type; + public: item_visitor_type(MultiGeometry const& multi_geometry, - detail::relate::topology_check<MultiGeometry> const& tc, + topology_check_type const& tc, Result & result, PtSegStrategy const& strategy) : m_multi_geometry(multi_geometry) @@ -298,7 +321,7 @@ class multi_point_multi_geometry_ii_ib inline bool apply(Point const& point, BoxPair const& box_pair) { // The default strategy is enough for Point/Box - if (! detail::disjoint::disjoint_point_box(point, box_pair.first)) + if (! detail::disjoint::disjoint_point_box(point, box_pair.first, d_pp_strategy_type())) { typename boost::range_value<MultiGeometry>::type const& single = range::at(m_multi_geometry, box_pair.second); @@ -335,7 +358,7 @@ class multi_point_multi_geometry_ii_ib private: MultiGeometry const& m_multi_geometry; - detail::relate::topology_check<MultiGeometry> const& m_tc; + topology_check_type const& m_tc; Result & m_result; PtSegStrategy const& m_strategy; }; @@ -351,20 +374,33 @@ public: static inline void apply(MultiPoint const& multi_point, MultiGeometry const& multi_geometry, std::vector<box_pair_type> const& boxes, - detail::relate::topology_check<MultiGeometry> const& tc, + detail::relate::topology_check + < + MultiGeometry, + typename Strategy::equals_point_point_strategy_type + > const& tc, Result & result, Strategy const& strategy) { item_visitor_type<Result, Strategy> visitor(multi_geometry, tc, result, strategy); + typedef overlaps_box_point + < + typename Strategy::disjoint_point_box_strategy_type + > overlaps_box_point_type; + typedef overlaps_box_box_pair + < + typename Strategy::disjoint_box_box_strategy_type + > overlaps_box_box_pair_type; + geometry::partition < box1_type >::apply(multi_point, boxes, visitor, expand_box_point(), - overlaps_box_point(), + overlaps_box_point_type(), expand_box_box_pair(), - overlaps_box_box_pair()); + overlaps_box_box_pair_type()); } }; @@ -387,7 +423,11 @@ struct multi_point_multi_geometry_ii_ib_ie static inline void apply(MultiPoint const& multi_point, MultiGeometry const& multi_geometry, std::vector<box_pair_type> const& boxes, - detail::relate::topology_check<MultiGeometry> const& tc, + detail::relate::topology_check + < + MultiGeometry, + typename Strategy::equals_point_point_strategy_type + > const& tc, Result & result, Strategy const& strategy) { @@ -461,6 +501,8 @@ struct multi_point_multi_geometry typedef model::box<point2_type> box2_type; typedef std::pair<box2_type, std::size_t> box_pair_type; + typedef typename Strategy::equals_point_point_strategy_type eq_pp_strategy_type; + typename Strategy::envelope_strategy_type const envelope_strategy = strategy.get_envelope_strategy(); @@ -473,7 +515,7 @@ struct multi_point_multi_geometry boxes[i].second = i; } - typedef detail::relate::topology_check<MultiGeometry> tc_t; + typedef detail::relate::topology_check<MultiGeometry, eq_pp_strategy_type> tc_t; tc_t tc(multi_geometry); if ( relate::may_update<interior, interior, '0', Transpose>(result) @@ -512,8 +554,13 @@ struct multi_point_multi_geometry if ( relate::may_update<exterior, boundary, tc_t::boundary, Transpose>(result) && tc.has_boundary() ) { - if (multi_point_geometry_eb<MultiGeometry>::apply(multi_point, tc)) + if (multi_point_geometry_eb + < + MultiGeometry, eq_pp_strategy_type + >::apply(multi_point, tc)) + { relate::set<exterior, boundary, tc_t::boundary, Transpose>(result); + } } } diff --git a/boost/geometry/algorithms/detail/relate/point_geometry.hpp b/boost/geometry/algorithms/detail/relate/point_geometry.hpp index e78a404b21..7b1726abeb 100644 --- a/boost/geometry/algorithms/detail/relate/point_geometry.hpp +++ b/boost/geometry/algorithms/detail/relate/point_geometry.hpp @@ -2,8 +2,8 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. -// This file was modified by Oracle on 2013, 2014, 2015, 2017. -// Modifications copyright (c) 2013-2017 Oracle and/or its affiliates. +// This file was modified by Oracle on 2013, 2014, 2015, 2017, 2018. +// Modifications copyright (c) 2013-2018 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -60,7 +60,11 @@ struct point_geometry if ( BOOST_GEOMETRY_CONDITION(result.interrupt) ) return; - typedef detail::relate::topology_check<Geometry> tc_t; + typedef detail::relate::topology_check + < + Geometry, + typename Strategy::equals_point_point_strategy_type + > tc_t; if ( relate::may_update<exterior, interior, tc_t::interior, Transpose>(result) || relate::may_update<exterior, boundary, tc_t::boundary, Transpose>(result) ) { diff --git a/boost/geometry/algorithms/detail/relate/point_point.hpp b/boost/geometry/algorithms/detail/relate/point_point.hpp index e0bed72ba3..d2a373f3c1 100644 --- a/boost/geometry/algorithms/detail/relate/point_point.hpp +++ b/boost/geometry/algorithms/detail/relate/point_point.hpp @@ -2,8 +2,8 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. -// This file was modified by Oracle on 2013, 2014, 2017. -// Modifications copyright (c) 2013-2017, Oracle and/or its affiliates. +// This file was modified by Oracle on 2013, 2014, 2017, 2018. +// Modifications copyright (c) 2013-2018, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -39,9 +39,9 @@ struct point_point template <typename Result, typename Strategy> static inline void apply(Point1 const& point1, Point2 const& point2, Result & result, - Strategy const& /*strategy*/) + Strategy const& strategy) { - bool equal = detail::equals::equals_point_point(point1, point2); + bool equal = detail::equals::equals_point_point(point1, point2, strategy); if ( equal ) { relate::set<interior, interior, '0'>(result); @@ -56,8 +56,10 @@ struct point_point } }; -template <typename Point, typename MultiPoint> -std::pair<bool, bool> point_multipoint_check(Point const& point, MultiPoint const& multi_point) +template <typename Point, typename MultiPoint, typename EqPPStrategy> +std::pair<bool, bool> point_multipoint_check(Point const& point, + MultiPoint const& multi_point, + EqPPStrategy const& strategy) { bool found_inside = false; bool found_outside = false; @@ -70,7 +72,7 @@ std::pair<bool, bool> point_multipoint_check(Point const& point, MultiPoint cons iterator last = boost::end(multi_point); for ( ; it != last ; ++it ) { - bool ii = detail::equals::equals_point_point(point, *it); + bool ii = detail::equals::equals_point_point(point, *it, strategy); if ( ii ) found_inside = true; @@ -92,7 +94,7 @@ struct point_multipoint template <typename Result, typename Strategy> static inline void apply(Point const& point, MultiPoint const& multi_point, Result & result, - Strategy const& /*strategy*/) + Strategy const& strategy) { if ( boost::empty(multi_point) ) { @@ -101,7 +103,7 @@ struct point_multipoint return; } - std::pair<bool, bool> rel = point_multipoint_check(point, multi_point); + std::pair<bool, bool> rel = point_multipoint_check(point, multi_point, strategy); if ( rel.first ) // some point of MP is equal to P { diff --git a/boost/geometry/algorithms/detail/relate/result.hpp b/boost/geometry/algorithms/detail/relate/result.hpp index 92bc160a6c..43592b9815 100644 --- a/boost/geometry/algorithms/detail/relate/result.hpp +++ b/boost/geometry/algorithms/detail/relate/result.hpp @@ -3,8 +3,8 @@ // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland. -// This file was modified by Oracle on 2013-2016. -// Modifications copyright (c) 2013-2016 Oracle and/or its affiliates. +// This file was modified by Oracle on 2013-2018. +// Modifications copyright (c) 2013-2018 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -25,6 +25,7 @@ #include <boost/mpl/end.hpp> #include <boost/mpl/is_sequence.hpp> #include <boost/mpl/next.hpp> +#include <boost/mpl/size.hpp> #include <boost/static_assert.hpp> #include <boost/throw_exception.hpp> #include <boost/tuple/tuple.hpp> diff --git a/boost/geometry/algorithms/detail/relate/topology_check.hpp b/boost/geometry/algorithms/detail/relate/topology_check.hpp index 810466ec05..a12acaf42b 100644 --- a/boost/geometry/algorithms/detail/relate/topology_check.hpp +++ b/boost/geometry/algorithms/detail/relate/topology_check.hpp @@ -1,6 +1,6 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014-2017, Oracle and/or its affiliates. +// Copyright (c) 2014-2018, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -13,6 +13,7 @@ #include <boost/geometry/algorithms/detail/equals/point_point.hpp> +#include <boost/geometry/algorithms/not_implemented.hpp> #include <boost/geometry/policies/compare.hpp> @@ -28,6 +29,7 @@ namespace detail { namespace relate { // TODO: change the name for e.g. something with the word "exterior" template <typename Geometry, + typename EqPPStrategy, typename Tag = typename geometry::tag<Geometry>::type> struct topology_check : not_implemented<Tag> @@ -47,8 +49,8 @@ struct topology_check // topology_check(Point const&, IgnoreBoundaryPoint const&) {} //}; -template <typename Linestring> -struct topology_check<Linestring, linestring_tag> +template <typename Linestring, typename EqPPStrategy> +struct topology_check<Linestring, EqPPStrategy, linestring_tag> { static const char interior = '1'; static const char boundary = '0'; @@ -100,7 +102,9 @@ private: m_has_interior = count > 0; // NOTE: Linestring with all points equal is treated as 1d linear ring m_has_boundary = count > 1 - && ! detail::equals::equals_point_point(range::front(m_ls), range::back(m_ls)); + && ! detail::equals::equals_point_point(range::front(m_ls), + range::back(m_ls), + EqPPStrategy()); m_is_initialized = true; } @@ -112,8 +116,8 @@ private: mutable bool m_has_boundary; }; -template <typename MultiLinestring> -struct topology_check<MultiLinestring, multi_linestring_tag> +template <typename MultiLinestring, typename EqPPStrategy> +struct topology_check<MultiLinestring, EqPPStrategy, multi_linestring_tag> { static const char interior = '1'; static const char boundary = '0'; @@ -159,6 +163,9 @@ struct topology_check<MultiLinestring, multi_linestring_tag> } private: +// TODO: CS-specific less derived from EqPPStrategy + typedef geometry::less<> less_type; + void init() const { if (m_is_initialized) @@ -192,7 +199,7 @@ private: point_reference back_pt = range::back(ls); // don't store boundaries of linear rings, this doesn't change anything - if (! equals::equals_point_point(front_pt, back_pt)) + if (! equals::equals_point_point(front_pt, back_pt, EqPPStrategy())) { // do not add points containing NaN coordinates // because they cannot be reasonably compared, e.g. with MSVC @@ -215,7 +222,7 @@ private: if (! m_endpoints.empty() ) { - std::sort(m_endpoints.begin(), m_endpoints.end(), geometry::less<>()); + std::sort(m_endpoints.begin(), m_endpoints.end(), less_type()); m_has_boundary = find_odd_count(m_endpoints.begin(), m_endpoints.end()); } @@ -225,7 +232,7 @@ private: template <typename It, typename Point> static inline std::size_t count_equal(It first, It last, Point const& point) { - std::pair<It, It> rng = std::equal_range(first, last, point, geometry::less<>()); + std::pair<It, It> rng = std::equal_range(first, last, point, less_type()); return (std::size_t)std::distance(rng.first, rng.second); } @@ -261,7 +268,7 @@ private: for ( ; first != last ; ++first, ++prev ) { // the end of the equal points subrange - if ( ! equals::equals_point_point(*first, *prev) ) + if ( ! equals::equals_point_point(*first, *prev, EqPPStrategy()) ) { // odd count -> boundary if ( count % 2 != 0 ) @@ -298,40 +305,35 @@ private: mutable std::vector<point_type> m_endpoints; }; -template <typename Ring> -struct topology_check<Ring, ring_tag> +struct topology_check_areal { static const char interior = '2'; static const char boundary = '1'; - topology_check(Ring const&) {} - static bool has_interior() { return true; } static bool has_boundary() { return true; } }; -template <typename Polygon> -struct topology_check<Polygon, polygon_tag> +template <typename Ring, typename EqPPStrategy> +struct topology_check<Ring, EqPPStrategy, ring_tag> + : topology_check_areal { - static const char interior = '2'; - static const char boundary = '1'; - - topology_check(Polygon const&) {} + topology_check(Ring const&) {} +}; - static bool has_interior() { return true; } - static bool has_boundary() { return true; } +template <typename Polygon, typename EqPPStrategy> +struct topology_check<Polygon, EqPPStrategy, polygon_tag> + : topology_check_areal +{ + topology_check(Polygon const&) {} }; -template <typename MultiPolygon> -struct topology_check<MultiPolygon, multi_polygon_tag> +template <typename MultiPolygon, typename EqPPStrategy> +struct topology_check<MultiPolygon, EqPPStrategy, multi_polygon_tag> + : topology_check_areal { - static const char interior = '2'; - static const char boundary = '1'; - topology_check(MultiPolygon const&) {} - - static bool has_interior() { return true; } - static bool has_boundary() { return true; } + template <typename Point> static bool check_boundary_point(Point const& ) { return true; } }; diff --git a/boost/geometry/algorithms/detail/relate/turns.hpp b/boost/geometry/algorithms/detail/relate/turns.hpp index 6fa05eaf21..01c4304fa4 100644 --- a/boost/geometry/algorithms/detail/relate/turns.hpp +++ b/boost/geometry/algorithms/detail/relate/turns.hpp @@ -48,7 +48,11 @@ template < Geometry1, Geometry2, assign_policy<> >, - typename RobustPolicy = detail::no_rescale_policy + typename RobustPolicy = typename geometry::rescale_overlay_policy_type + < + Geometry1, + Geometry2 + >::type > struct get_turns { diff --git a/boost/geometry/algorithms/detail/sections/section_box_policies.hpp b/boost/geometry/algorithms/detail/sections/section_box_policies.hpp index cf06700306..e6342ff709 100644 --- a/boost/geometry/algorithms/detail/sections/section_box_policies.hpp +++ b/boost/geometry/algorithms/detail/sections/section_box_policies.hpp @@ -2,6 +2,10 @@ // Copyright (c) 2015 Barend Gehrels, Amsterdam, the Netherlands. +// This file was modified by Oracle on 2018. +// Modifications copyright (c) 2018, Oracle and/or its affiliates. +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + // 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) @@ -21,21 +25,25 @@ namespace boost { namespace geometry namespace detail { namespace section { +template <typename ExpandBoxStrategy> struct get_section_box { template <typename Box, typename Section> static inline void apply(Box& total, Section const& section) { - geometry::expand(total, section.bounding_box); + geometry::expand(total, section.bounding_box, + ExpandBoxStrategy()); } }; +template <typename DisjointBoxBoxStrategy> struct overlaps_section_box { template <typename Box, typename Section> static inline bool apply(Box const& box, Section const& section) { - return ! detail::disjoint::disjoint_box_box(box, section.bounding_box); + return ! detail::disjoint::disjoint_box_box(box, section.bounding_box, + DisjointBoxBoxStrategy()); } }; diff --git a/boost/geometry/algorithms/detail/sections/section_functions.hpp b/boost/geometry/algorithms/detail/sections/section_functions.hpp index d283784e2c..bd72ff48a0 100644 --- a/boost/geometry/algorithms/detail/sections/section_functions.hpp +++ b/boost/geometry/algorithms/detail/sections/section_functions.hpp @@ -2,8 +2,8 @@ // Copyright (c) 2015 Barend Gehrels, Amsterdam, the Netherlands. -// This file was modified by Oracle on 2015, 2017. -// Modifications copyright (c) 2015-2017, Oracle and/or its affiliates. +// This file was modified by Oracle on 2015, 2017, 2018. +// Modifications copyright (c) 2015-2018, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -22,6 +22,8 @@ // For spherical/geographic longitudes covered_by point/box #include <boost/geometry/strategies/cartesian/point_in_box.hpp> +#include <boost/geometry/util/select_coordinate_type.hpp> + namespace boost { namespace geometry { @@ -30,6 +32,8 @@ namespace boost { namespace geometry namespace detail { namespace section { +// TODO: This code is CS-specific, should be moved to strategies + template < std::size_t Dimension, @@ -68,7 +72,7 @@ struct preceding_check<0, Geometry, spherical_tag> calc_t const other_min = get<min_corner, 0>(other_box); calc_t const other_max = get<max_corner, 0>(other_box); - bool const pt_covered = strategy::within::covered_by_range + bool const pt_covered = strategy::within::detail::covered_by_range < Point, 0, spherical_tag >::apply(value, diff --git a/boost/geometry/algorithms/detail/sections/sectionalize.hpp b/boost/geometry/algorithms/detail/sections/sectionalize.hpp index 7a8638f5c8..6ece756cd4 100644 --- a/boost/geometry/algorithms/detail/sections/sectionalize.hpp +++ b/boost/geometry/algorithms/detail/sections/sectionalize.hpp @@ -5,8 +5,8 @@ // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // Copyright (c) 2014-2015 Adam Wulkiewicz, Lodz, Poland. -// This file was modified by Oracle on 2013, 2014, 2015, 2017. -// Modifications copyright (c) 2013-2017 Oracle and/or its affiliates. +// This file was modified by Oracle on 2013, 2014, 2015, 2017, 2018. +// Modifications copyright (c) 2013-2018 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle @@ -58,6 +58,7 @@ #include <boost/geometry/algorithms/detail/expand_by_epsilon.hpp> #include <boost/geometry/strategies/envelope.hpp> +#include <boost/geometry/strategies/expand.hpp> namespace boost { namespace geometry { @@ -330,9 +331,9 @@ struct assign_loop<T, Count, Count> template <typename CSTag> struct box_first_in_section { - template <typename Box, typename Point, typename Strategy> + template <typename Box, typename Point, typename EnvelopeStrategy> static inline void apply(Box & box, Point const& prev, Point const& curr, - Strategy const& strategy) + EnvelopeStrategy const& strategy) { geometry::model::referring_segment<Point const> seg(prev, curr); geometry::envelope(seg, box, strategy); @@ -342,9 +343,9 @@ struct box_first_in_section template <> struct box_first_in_section<cartesian_tag> { - template <typename Box, typename Point, typename Strategy> + template <typename Box, typename Point, typename ExpandStrategy> static inline void apply(Box & box, Point const& prev, Point const& curr, - Strategy const& ) + ExpandStrategy const& ) { geometry::envelope(prev, box); geometry::expand(box, curr); @@ -399,11 +400,20 @@ struct sectionalize_part { typedef typename strategy::envelope::services::default_strategy < + segment_tag, typename cs_tag<typename Sections::box_type>::type >::type envelope_strategy_type; + typedef typename strategy::expand::services::default_strategy + < + segment_tag, + typename cs_tag<typename Sections::box_type>::type + >::type expand_strategy_type; + apply(sections, begin, end, - robust_policy, envelope_strategy_type(), + robust_policy, + envelope_strategy_type(), + expand_strategy_type(), ring_id, max_count); } @@ -412,12 +422,14 @@ struct sectionalize_part typename Iterator, typename RobustPolicy, typename Sections, - typename EnvelopeStrategy + typename EnvelopeStrategy, + typename ExpandStrategy > static inline void apply(Sections& sections, Iterator begin, Iterator end, RobustPolicy const& robust_policy, - EnvelopeStrategy const& strategy, + EnvelopeStrategy const& envelope_strategy, + ExpandStrategy const& expand_strategy, ring_identifier ring_id, std::size_t max_count) { @@ -535,14 +547,14 @@ struct sectionalize_part // In cartesian this is envelope of previous point expanded with current point // in non-cartesian this is envelope of a segment box_first_in_section<typename cs_tag<robust_point_type>::type> - ::apply(section.bounding_box, previous_robust_point, current_robust_point, strategy); + ::apply(section.bounding_box, previous_robust_point, current_robust_point, envelope_strategy); } else { // In cartesian this is expand with current point // in non-cartesian this is expand with a segment box_next_in_section<typename cs_tag<robust_point_type>::type> - ::apply(section.bounding_box, previous_robust_point, current_robust_point, strategy); + ::apply(section.bounding_box, previous_robust_point, current_robust_point, expand_strategy); } section.end_index = index + 1; @@ -588,12 +600,14 @@ struct sectionalize_range typename Range, typename RobustPolicy, typename Sections, - typename EnvelopeStrategy + typename EnvelopeStrategy, + typename ExpandStrategy > static inline void apply(Range const& range, RobustPolicy const& robust_policy, Sections& sections, - EnvelopeStrategy const& strategy, + EnvelopeStrategy const& envelope_strategy, + ExpandStrategy const& expand_strategy, ring_identifier ring_id, std::size_t max_count) { @@ -622,7 +636,8 @@ struct sectionalize_range sectionalize_part<Point, DimensionVector>::apply(sections, boost::begin(view), boost::end(view), - robust_policy, strategy, ring_id, max_count); + robust_policy, envelope_strategy, expand_strategy, + ring_id, max_count); } }; @@ -638,12 +653,14 @@ struct sectionalize_polygon typename Polygon, typename RobustPolicy, typename Sections, - typename EnvelopeStrategy + typename EnvelopeStrategy, + typename ExpandStrategy > static inline void apply(Polygon const& poly, RobustPolicy const& robust_policy, Sections& sections, - EnvelopeStrategy const& strategy, + EnvelopeStrategy const& envelope_strategy, + ExpandStrategy const& expand_strategy, ring_identifier ring_id, std::size_t max_count) { @@ -655,7 +672,8 @@ struct sectionalize_polygon > per_range; ring_id.ring_index = -1; - per_range::apply(exterior_ring(poly), robust_policy, sections, strategy, ring_id, max_count); + per_range::apply(exterior_ring(poly), robust_policy, sections, + envelope_strategy, expand_strategy, ring_id, max_count); ring_id.ring_index++; typename interior_return_type<Polygon const>::type @@ -663,7 +681,8 @@ struct sectionalize_polygon for (typename detail::interior_iterator<Polygon const>::type it = boost::begin(rings); it != boost::end(rings); ++it, ++ring_id.ring_index) { - per_range::apply(*it, robust_policy, sections, strategy, ring_id, max_count); + per_range::apply(*it, robust_policy, sections, + envelope_strategy, expand_strategy, ring_id, max_count); } } }; @@ -676,12 +695,14 @@ struct sectionalize_box typename Box, typename RobustPolicy, typename Sections, - typename EnvelopeStrategy + typename EnvelopeStrategy, + typename ExpandStrategy > static inline void apply(Box const& box, RobustPolicy const& robust_policy, Sections& sections, - EnvelopeStrategy const& , + EnvelopeStrategy const& envelope_strategy, + ExpandStrategy const& expand_strategy, ring_identifier const& ring_id, std::size_t max_count) { typedef typename point_type<Box>::type point_type; @@ -714,7 +735,7 @@ struct sectionalize_box point_type, DimensionVector >::apply(points, robust_policy, sections, - strategy::envelope::cartesian_segment<>(), + envelope_strategy, expand_strategy, ring_id, max_count); } }; @@ -727,12 +748,14 @@ struct sectionalize_multi typename MultiGeometry, typename RobustPolicy, typename Sections, - typename EnvelopeStrategy + typename EnvelopeStrategy, + typename ExpandStrategy > static inline void apply(MultiGeometry const& multi, RobustPolicy const& robust_policy, Sections& sections, - EnvelopeStrategy const& strategy, + EnvelopeStrategy const& envelope_strategy, + ExpandStrategy const& expand_strategy, ring_identifier ring_id, std::size_t max_count) { @@ -742,7 +765,9 @@ struct sectionalize_multi it != boost::end(multi); ++it, ++ring_id.multi_index) { - Policy::apply(*it, robust_policy, sections, strategy, ring_id, max_count); + Policy::apply(*it, robust_policy, sections, + envelope_strategy, expand_strategy, + ring_id, max_count); } } }; @@ -903,6 +928,8 @@ struct sectionalize<multi_linestring_tag, MultiLinestring, Reverse, DimensionVec \param geometry geometry to create sections from \param robust_policy policy to handle robustness issues \param sections structure with sections + \param envelope_strategy strategy for envelope calculation + \param expand_strategy strategy for partitions \param source_index index to assign to the ring_identifiers \param max_count maximal number of points per section (defaults to 10, this seems to give the fastest results) @@ -915,12 +942,14 @@ template typename Geometry, typename Sections, typename RobustPolicy, - typename EnvelopeStrategy + typename EnvelopeStrategy, + typename ExpandStrategy > inline void sectionalize(Geometry const& geometry, RobustPolicy const& robust_policy, Sections& sections, - EnvelopeStrategy const& strategy, + EnvelopeStrategy const& envelope_strategy, + ExpandStrategy const& expand_strategy, int source_index = 0, std::size_t max_count = 10) { @@ -959,7 +988,9 @@ inline void sectionalize(Geometry const& geometry, Geometry, Reverse, DimensionVector - >::apply(geometry, robust_policy, sections, strategy, ring_id, max_count); + >::apply(geometry, robust_policy, sections, + envelope_strategy, expand_strategy, + ring_id, max_count); detail::sectionalize::enlarge_sections(sections); } @@ -981,14 +1012,27 @@ inline void sectionalize(Geometry const& geometry, { typedef typename strategy::envelope::services::default_strategy < + typename tag<Geometry>::type, typename cs_tag<Geometry>::type >::type envelope_strategy_type; + typedef typename strategy::expand::services::default_strategy + < + typename boost::mpl::if_c + < + boost::is_same<typename tag<Geometry>::type, box_tag>::value, + box_tag, + segment_tag + >::type, + typename cs_tag<Geometry>::type + >::type expand_strategy_type; + boost::geometry::sectionalize < Reverse, DimensionVector >(geometry, robust_policy, sections, envelope_strategy_type(), + expand_strategy_type(), source_index, max_count); } diff --git a/boost/geometry/algorithms/detail/sub_range.hpp b/boost/geometry/algorithms/detail/sub_range.hpp index 29edc94e6c..099de426ab 100644 --- a/boost/geometry/algorithms/detail/sub_range.hpp +++ b/boost/geometry/algorithms/detail/sub_range.hpp @@ -2,21 +2,29 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. -// This file was modified by Oracle on 2013, 2014. -// Modifications copyright (c) 2013-2014, Oracle and/or its affiliates. +// This file was modified by Oracle on 2013, 2014, 2018. +// Modifications copyright (c) 2013-2018, Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // 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) -// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle - #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_SUB_RANGE_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_SUB_RANGE_HPP #include <boost/mpl/if.hpp> +#include <boost/type_traits/is_base_of.hpp> + +#include <boost/geometry/algorithms/not_implemented.hpp> #include <boost/geometry/core/assert.hpp> +#include <boost/geometry/core/exterior_ring.hpp> +#include <boost/geometry/core/interior_rings.hpp> +#include <boost/geometry/core/tag.hpp> +#include <boost/geometry/core/tags.hpp> + #include <boost/geometry/util/range.hpp> namespace boost { namespace geometry { diff --git a/boost/geometry/algorithms/detail/within/implementation.hpp b/boost/geometry/algorithms/detail/within/implementation.hpp index a1fae421e5..163092b2cb 100644 --- a/boost/geometry/algorithms/detail/within/implementation.hpp +++ b/boost/geometry/algorithms/detail/within/implementation.hpp @@ -4,8 +4,8 @@ // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. -// This file was modified by Oracle on 2013, 2014, 2017. -// Modifications copyright (c) 2013-2017 Oracle and/or its affiliates. +// This file was modified by Oracle on 2013, 2014, 2017, 2019. +// Modifications copyright (c) 2013-2019 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -61,7 +61,7 @@ struct use_point_in_geometry template <typename Geometry1, typename Geometry2, typename Strategy> static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { - return detail::within::point_in_geometry(geometry1, geometry2, strategy) == 1; + return detail::within::within_point_geometry(geometry1, geometry2, strategy); } }; diff --git a/boost/geometry/algorithms/detail/within/interface.hpp b/boost/geometry/algorithms/detail/within/interface.hpp index 23263604c2..048cc01f7a 100644 --- a/boost/geometry/algorithms/detail/within/interface.hpp +++ b/boost/geometry/algorithms/detail/within/interface.hpp @@ -4,8 +4,8 @@ // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. -// This file was modified by Oracle on 2013, 2014, 2017. -// Modifications copyright (c) 2013-2017 Oracle and/or its affiliates. +// This file was modified by Oracle on 2013, 2014, 2017, 2018. +// Modifications copyright (c) 2013-2018 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -70,13 +70,7 @@ struct within Geometry2 const& geometry2, Strategy const& strategy) { - concepts::within::check - < - typename tag<Geometry1>::type, - typename tag<Geometry2>::type, - typename tag_cast<typename tag<Geometry2>::type, areal_tag>::type, - Strategy - >(); + concepts::within::check<Geometry1, Geometry2, Strategy>(); return dispatch::within<Geometry1, Geometry2>::apply(geometry1, geometry2, strategy); } diff --git a/boost/geometry/algorithms/detail/within/point_in_geometry.hpp b/boost/geometry/algorithms/detail/within/point_in_geometry.hpp index a24f4d21e2..45449eb194 100644 --- a/boost/geometry/algorithms/detail/within/point_in_geometry.hpp +++ b/boost/geometry/algorithms/detail/within/point_in_geometry.hpp @@ -5,8 +5,8 @@ // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. // Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland. -// This file was modified by Oracle on 2013, 2014, 2015, 2017. -// Modifications copyright (c) 2013-2017, Oracle and/or its affiliates. +// This file was modified by Oracle on 2013, 2014, 2015, 2017, 2018, 2019. +// Modifications copyright (c) 2013-2019, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -45,6 +45,11 @@ namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace within { +template <typename Point1, typename Point2, typename Strategy> +inline bool equals_point_point(Point1 const& p1, Point2 const& p2, Strategy const& strategy) +{ + return equals::equals_point_point(p1, p2, strategy.get_equals_point_point_strategy()); +} // TODO: is this needed? inline int check_result_type(int result) @@ -139,8 +144,8 @@ struct point_in_geometry<Segment, segment_tag> return -1; // exterior // if the point is equal to the one of the terminal points - if ( detail::equals::equals_point_point(point, p0) - || detail::equals::equals_point_point(point, p1) ) + if ( detail::within::equals_point_point(point, p0, strategy) + || detail::within::equals_point_point(point, p1, strategy) ) return 0; // boundary else return 1; // interior @@ -161,11 +166,11 @@ struct point_in_geometry<Linestring, linestring_tag> return -1; // exterior // if the linestring doesn't have a boundary - if (detail::equals::equals_point_point(range::front(linestring), range::back(linestring))) + if (detail::within::equals_point_point(range::front(linestring), range::back(linestring), strategy)) return 1; // interior // else if the point is equal to the one of the terminal points - else if (detail::equals::equals_point_point(point, range::front(linestring)) - || detail::equals::equals_point_point(point, range::back(linestring))) + else if (detail::within::equals_point_point(point, range::front(linestring), strategy) + || detail::within::equals_point_point(point, range::back(linestring), strategy)) return 0; // boundary else return 1; // interior @@ -304,12 +309,12 @@ struct point_in_geometry<Geometry, multi_linestring_tag> point_type const& back = range::back(*it); // is closed_ring - no boundary - if ( detail::equals::equals_point_point(front, back) ) + if ( detail::within::equals_point_point(front, back, strategy) ) continue; // is point on boundary - if ( detail::equals::equals_point_point(point, front) - || detail::equals::equals_point_point(point, back) ) + if ( detail::within::equals_point_point(point, front, strategy) + || detail::within::equals_point_point(point, back, strategy) ) { ++boundaries; } @@ -361,13 +366,7 @@ namespace detail { namespace within { template <typename Point, typename Geometry, typename Strategy> inline int point_in_geometry(Point const& point, Geometry const& geometry, Strategy const& strategy) { - concepts::within::check - < - typename tag<Point>::type, - typename tag<Geometry>::type, - typename tag_cast<typename tag<Geometry>::type, areal_tag>::type, - Strategy - >(); + concepts::within::check<Point, Geometry, Strategy>(); return detail_dispatch::within::point_in_geometry<Geometry>::apply(point, geometry, strategy); } @@ -383,6 +382,30 @@ inline int point_in_geometry(Point const& point, Geometry const& geometry) return point_in_geometry(point, geometry, strategy_type()); } +template <typename Point, typename Geometry, typename Strategy> +inline bool within_point_geometry(Point const& point, Geometry const& geometry, Strategy const& strategy) +{ + return point_in_geometry(point, geometry, strategy) > 0; +} + +template <typename Point, typename Geometry> +inline bool within_point_geometry(Point const& point, Geometry const& geometry) +{ + return point_in_geometry(point, geometry) > 0; +} + +template <typename Point, typename Geometry, typename Strategy> +inline bool covered_by_point_geometry(Point const& point, Geometry const& geometry, Strategy const& strategy) +{ + return point_in_geometry(point, geometry, strategy) >= 0; +} + +template <typename Point, typename Geometry> +inline bool covered_by_point_geometry(Point const& point, Geometry const& geometry) +{ + return point_in_geometry(point, geometry) >= 0; +} + }} // namespace detail::within #endif // DOXYGEN_NO_DETAIL |