diff options
Diffstat (limited to 'boost/geometry/algorithms/detail')
178 files changed, 9045 insertions, 5071 deletions
diff --git a/boost/geometry/algorithms/detail/as_range.hpp b/boost/geometry/algorithms/detail/as_range.hpp deleted file mode 100644 index fe2016be5e..0000000000 --- a/boost/geometry/algorithms/detail/as_range.hpp +++ /dev/null @@ -1,91 +0,0 @@ -// Boost.Geometry (aka GGL, Generic Geometry Library) - -// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. -// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. -// Copyright (c) 2009-2012 Mateusz Loskot, London, UK. - -// This file was modified by Oracle on 2020-2021. -// Modifications copyright (c) 2020-2021 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 -// (geolib/GGL), copyright (c) 1995-2010 Geodan, 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_AS_RANGE_HPP -#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_AS_RANGE_HPP - - -#include <boost/geometry/algorithms/not_implemented.hpp> - -#include <boost/geometry/core/exterior_ring.hpp> -#include <boost/geometry/core/ring_type.hpp> -#include <boost/geometry/core/tag.hpp> -#include <boost/geometry/core/tags.hpp> - - -namespace boost { namespace geometry -{ - - -#ifndef DOXYGEN_NO_DISPATCH -namespace dispatch -{ - - -template <typename Geometry, typename Tag = typename tag<Geometry>::type> -struct as_range : not_implemented<Geometry, Tag> -{}; - -template <typename Geometry> -struct as_range<Geometry, linestring_tag> -{ - static inline typename ring_return_type<Geometry>::type get(Geometry& geometry) - { - return geometry; - } -}; - -template <typename Geometry> -struct as_range<Geometry, ring_tag> - : as_range<Geometry, linestring_tag> -{}; - -template <typename Geometry> -struct as_range<Geometry, polygon_tag> -{ - static inline typename ring_return_type<Geometry>::type get(Geometry& geometry) - { - return exterior_ring(geometry); - } -}; - - -} // namespace dispatch -#endif // DOXYGEN_NO_DISPATCH - -// Will probably be replaced by the more generic "view_as", therefore in detail -namespace detail -{ - -/*! -\brief Function getting either the range (ring, linestring) itself -or the outer ring (polygon) -\details Utility to handle polygon's outer ring as a range -\ingroup utility -*/ -template <typename Geometry> -inline typename ring_return_type<Geometry>::type as_range(Geometry& geometry) -{ - return dispatch::as_range<Geometry>::get(geometry); -} - -} - -}} // namespace boost::geometry - - -#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_AS_RANGE_HPP diff --git a/boost/geometry/algorithms/detail/buffer/buffer_box.hpp b/boost/geometry/algorithms/detail/buffer/buffer_box.hpp index f19a91d6ba..f19a91d6ba 100755..100644 --- a/boost/geometry/algorithms/detail/buffer/buffer_box.hpp +++ b/boost/geometry/algorithms/detail/buffer/buffer_box.hpp diff --git a/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp b/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp index cc5c41d11b..5e8635c3d7 100644 --- a/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp +++ b/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp @@ -1,9 +1,10 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2012-2020 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2022-2023 Adam Wulkiewicz, Lodz, Poland. -// This file was modified by Oracle on 2017-2021. -// Modifications copyright (c) 2017-2021 Oracle and/or its affiliates. +// This file was modified by Oracle on 2017-2022. +// Modifications copyright (c) 2017-2022 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, @@ -37,10 +38,13 @@ #include <boost/geometry/core/exterior_ring.hpp> #include <boost/geometry/core/interior_rings.hpp> +#include <boost/geometry/geometries/linestring.hpp> +#include <boost/geometry/geometries/ring.hpp> + #include <boost/geometry/strategies/buffer.hpp> #include <boost/geometry/strategies/side.hpp> -#include <boost/geometry/util/condition.hpp> +#include <boost/geometry/util/constexpr.hpp> #include <boost/geometry/util/math.hpp> #include <boost/geometry/util/type_traits.hpp> @@ -54,11 +58,11 @@ namespace boost { namespace geometry namespace detail { namespace buffer { -template <typename Range, typename DistanceStrategy, typename Strategies> -inline void simplify_input(Range const& range, - DistanceStrategy const& distance, - Range& simplified, - Strategies const& strategies) +template <typename RangeIn, typename DistanceStrategy, typename RangeOut, typename Strategies> +inline void simplify_input(RangeIn const& range, + DistanceStrategy const& distance, + RangeOut& simplified, + Strategies const& strategies) { // We have to simplify the ring before to avoid very small-scaled // features in the original (convex/concave/convex) being enlarged @@ -291,7 +295,7 @@ struct buffer_range robust_policy, strategies); } - collection.add_side_piece(*prev, *it, generated_side, first); + collection.add_side_piece(*prev, *it, generated_side, first, distance_strategy.empty(side)); if (first && mark_flat) { @@ -350,10 +354,7 @@ struct buffer_multi RobustPolicy const& robust_policy, Strategies const& strategies) { - for (typename boost::range_iterator<Multi const>::type - it = boost::begin(multi); - it != boost::end(multi); - ++it) + for (auto it = boost::begin(multi); it != boost::end(multi); ++it) { Policy::apply(*it, collection, distance_strategy, segment_strategy, @@ -453,7 +454,7 @@ template > struct buffer_inserter_ring { - typedef typename point_type<RingOutput>::type output_point_type; + using output_point_type = typename point_type<RingOutput>::type; template < @@ -524,7 +525,14 @@ struct buffer_inserter_ring RobustPolicy const& robust_policy, Strategies const& strategies) { - RingInput simplified; + // Use helper geometry to support non-mutable input Rings + using simplified_ring_t = model::ring + < + output_point_type, + point_order<RingInput>::value != counterclockwise, + closure<RingInput>::value != open + >; + simplified_ring_t simplified; detail::buffer::simplify_input(ring, distance, simplified, strategies); geometry::strategy::buffer::result_code code = geometry::strategy::buffer::result_no_output; @@ -532,12 +540,12 @@ struct buffer_inserter_ring std::size_t n = boost::size(simplified); std::size_t const min_points = core_detail::closure::minimum_ring_size < - geometry::closure<RingInput>::value + geometry::closure<simplified_ring_t>::value >::value; if (n >= min_points) { - detail::closed_clockwise_view<RingInput const> view(simplified); + detail::closed_clockwise_view<simplified_ring_t const> view(simplified); if (distance.negative()) { // Walk backwards (rings will be reversed afterwards) @@ -615,9 +623,8 @@ template > struct buffer_inserter<linestring_tag, Linestring, Polygon> { - typedef typename ring_type<Polygon>::type output_ring_type; - typedef typename point_type<output_ring_type>::type output_point_type; - typedef typename point_type<Linestring>::type input_point_type; + using output_ring_type = typename ring_type<Polygon>::type; + using output_point_type = typename point_type<output_ring_type>::type; template < @@ -641,8 +648,8 @@ struct buffer_inserter<linestring_tag, Linestring, Polygon> Strategies const& strategies, output_point_type& first_p1) { - input_point_type const& ultimate_point = *(end - 1); - input_point_type const& penultimate_point = *(end - 2); + output_point_type const& ultimate_point = *(end - 1); + output_point_type const& penultimate_point = *(end - 2); // For the end-cap, we need to have the last perpendicular point on the // other side of the linestring. If it is the second pass (right), @@ -708,7 +715,8 @@ struct buffer_inserter<linestring_tag, Linestring, Polygon> RobustPolicy const& robust_policy, Strategies const& strategies) { - Linestring simplified; + // Use helper geometry to support non-mutable input Linestrings + model::linestring<output_point_type> simplified; detail::buffer::simplify_input(linestring, distance, simplified, strategies); geometry::strategy::buffer::result_code code = geometry::strategy::buffer::result_no_output; @@ -934,17 +942,17 @@ inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator { boost::ignore_unused(visit_pieces_policy); - typedef detail::buffer::buffered_piece_collection - < - typename geometry::ring_type<GeometryOutput>::type, - Strategies, - DistanceStrategy, - RobustPolicy - > collection_type; + using collection_type = detail::buffer::buffered_piece_collection + < + typename geometry::ring_type<GeometryOutput>::type, + Strategies, + DistanceStrategy, + RobustPolicy + >; collection_type collection(strategies, distance_strategy, robust_policy); collection_type const& const_collection = collection; - bool const areal = util::is_areal<GeometryInput>::value; + static constexpr bool areal = util::is_areal<GeometryInput>::value; dispatch::buffer_inserter < @@ -961,7 +969,7 @@ inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator robust_policy, strategies); collection.get_turns(); - if (BOOST_GEOMETRY_CONDITION(areal)) + if BOOST_GEOMETRY_CONSTEXPR (areal) { collection.check_turn_in_original(); } @@ -981,7 +989,7 @@ inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator // phase 1: turns (after enrichment/clustering) visit_pieces_policy.apply(const_collection, 1); - if (BOOST_GEOMETRY_CONDITION(areal)) + if BOOST_GEOMETRY_CONSTEXPR (areal) { collection.deflate_check_turns(); } @@ -993,8 +1001,7 @@ inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator // - the output is counter clockwise // and avoid reversing twice bool reverse = distance_strategy.negative() && areal; - if (BOOST_GEOMETRY_CONDITION( - geometry::point_order<GeometryOutput>::value == counterclockwise)) + if BOOST_GEOMETRY_CONSTEXPR (geometry::point_order<GeometryOutput>::value == counterclockwise) { reverse = ! reverse; } @@ -1003,9 +1010,12 @@ inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator collection.reverse(); } - if (BOOST_GEOMETRY_CONDITION(distance_strategy.negative() && areal)) + if BOOST_GEOMETRY_CONSTEXPR (areal) { - collection.discard_nonintersecting_deflated_rings(); + if (distance_strategy.negative()) + { + collection.discard_nonintersecting_deflated_rings(); + } } collection.template assign<GeometryOutput>(out); diff --git a/boost/geometry/algorithms/detail/buffer/buffer_policies.hpp b/boost/geometry/algorithms/detail/buffer/buffer_policies.hpp index 05d5c6fdac..e75532c3f3 100644 --- a/boost/geometry/algorithms/detail/buffer/buffer_policies.hpp +++ b/boost/geometry/algorithms/detail/buffer/buffer_policies.hpp @@ -158,7 +158,6 @@ struct buffer_turn_info // or (for deflate) if there are not enough points to traverse it. bool is_turn_traversable; - bool close_to_offset; bool is_linear_end_point; bool within_original; signed_size_type count_in_original; // increased by +1 for in ext.ring, -1 for int.ring @@ -166,7 +165,6 @@ struct buffer_turn_info inline buffer_turn_info() : turn_index(0) , is_turn_traversable(true) - , close_to_offset(false) , is_linear_end_point(false) , within_original(false) , count_in_original(0) diff --git a/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp b/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp index 65571c9211..8aa9493420 100644 --- a/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp +++ b/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp @@ -1,10 +1,10 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands. -// Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland. +// Copyright (c) 2017-2023 Adam Wulkiewicz, Lodz, Poland. -// This file was modified by Oracle on 2016-2021. -// Modifications copyright (c) 2016-2021 Oracle and/or its affiliates. +// This file was modified by Oracle on 2016-2022. +// Modifications copyright (c) 2016-2022 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, @@ -59,6 +59,7 @@ #include <boost/geometry/algorithms/detail/sections/section_box_policies.hpp> #include <boost/geometry/views/detail/closed_clockwise_view.hpp> +#include <boost/geometry/util/for_each_with_index.hpp> #include <boost/geometry/util/range.hpp> @@ -289,77 +290,15 @@ struct buffered_piece_collection , m_robust_policy(robust_policy) {} - inline bool is_following(buffer_turn_info_type const& turn, - buffer_turn_operation_type const& op) - { - return turn.operations[0].seg_id.segment_index == op.seg_id.segment_index - || turn.operations[1].seg_id.segment_index == op.seg_id.segment_index; - } - - // Verify if turns which are classified as OK (outside or on border of - // offsetted ring) do not traverse through other turns which are classified - // as WITHIN (inside a piece). This can happen if turns are nearly colocated - // and due to floating point precision just classified as within, while - // they should not be within. - // In those cases the turns are fine to travel through (and should), - // but they are not made startable. - template <typename Vector> - inline void pretraverse(Vector const& indexed_operations) - { - // Verify if the turns which are OK don't skip segments - typedef typename boost::range_value<Vector>::type indexed_type; - buffer_turn_operation_type last_traversable_operation; - buffer_turn_info_type last_traversable_turn; - bool first = true; - for (std::size_t i = 0; i < indexed_operations.size(); i++) - { - indexed_type const & itop = indexed_operations[i]; - buffer_turn_info_type const& turn = m_turns[itop.turn_index]; - - if (turn.is_turn_traversable && ! first) - { - // Check previous and next turns. The first is handled - BOOST_GEOMETRY_ASSERT(i > 0); - indexed_type const& previous_itop = indexed_operations[i - 1]; - std::size_t const next_index = i + 1 < indexed_operations.size() ? i + 1 : 0; - indexed_type const& next_itop = indexed_operations[next_index]; - - buffer_turn_info_type& previous_turn = m_turns[previous_itop.turn_index]; - buffer_turn_info_type& next_turn = m_turns[next_itop.turn_index]; - - if (previous_turn.close_to_offset - && is_following(previous_turn, last_traversable_operation)) - { - previous_turn.is_turn_traversable = true; - } - else if (next_turn.close_to_offset - && is_following(next_turn, last_traversable_operation)) - { - next_turn.is_turn_traversable = true; - } - } - - if (turn.is_turn_traversable) - { - first = false; - last_traversable_operation = *itop.subject; - last_traversable_turn = turn; - } - } - } - inline void check_linear_endpoints(buffer_turn_info_type& turn) const { // TODO this is quadratic. But the #endpoints, expected, is low, // and only applicable for linear features // (in a multi linestring with many short lines, the #endpoints can be // much higher) - for (typename boost::range_iterator<std::vector<point_type> const>::type it - = boost::begin(m_linear_end_points); - it != boost::end(m_linear_end_points); - ++it) + for (auto const& p : m_linear_end_points) { - if (detail::equals::equals_point_point(turn.point, *it, m_strategy)) + if (detail::equals::equals_point_point(turn.point, p, m_strategy)) { turn.is_linear_end_point = true; } @@ -383,20 +322,9 @@ struct buffered_piece_collection enriched_map_buffer_include_policy()); // Sort turns over offsetted ring(s) - for (typename mapped_vector_type::iterator mit - = mapped_vector.begin(); - mit != mapped_vector.end(); - ++mit) - { - std::sort(mit->second.begin(), mit->second.end(), buffer_less()); - } - - for (typename mapped_vector_type::iterator mit - = mapped_vector.begin(); - mit != mapped_vector.end(); - ++mit) + for (auto& pair : mapped_vector) { - pretraverse(mit->second); + std::sort(pair.second.begin(), pair.second.end(), buffer_less()); } } @@ -409,17 +337,14 @@ struct buffered_piece_collection // Deflated rings may not travel to themselves, there should at least // be three turns (which cannot be checked here - TODO: add to traverse) - for (typename boost::range_iterator<turn_vector_type>::type it = - boost::begin(m_turns); it != boost::end(m_turns); ++it) + for (auto& turn : m_turns) { - buffer_turn_info_type& turn = *it; if (! turn.is_turn_traversable) { continue; } - for (int i = 0; i < 2; i++) + for (auto& op : turn.operations) { - buffer_turn_operation_type& op = turn.operations[i]; if (op.enriched.get_next_turn_index() == static_cast<signed_size_type>(turn.turn_index) && m_pieces[op.seg_id.piece_index].is_deflated) { @@ -452,10 +377,8 @@ struct buffered_piece_collection bool const deflate = m_distance_strategy.negative(); - for (typename boost::range_iterator<turn_vector_type>::type it = - boost::begin(m_turns); it != boost::end(m_turns); ++it) + for (auto& turn : m_turns) { - buffer_turn_info_type& turn = *it; if (turn.is_turn_traversable) { if (deflate && turn.count_in_original <= 0) @@ -475,21 +398,16 @@ struct buffered_piece_collection inline void update_turn_administration() { - std::size_t index = 0; - for (typename boost::range_iterator<turn_vector_type>::type it = - boost::begin(m_turns); it != boost::end(m_turns); ++it, ++index) + for_each_with_index(m_turns, [this](std::size_t index, auto& turn) { - buffer_turn_info_type& turn = *it; - - // Update member used turn.turn_index = index; // Verify if a turn is a linear endpoint if (! turn.is_linear_end_point) { - check_linear_endpoints(turn); + this->check_linear_endpoints(turn); } - } + }); } // Calculate properties of piece borders which are not influenced @@ -501,11 +419,8 @@ struct buffered_piece_collection // - (if pieces are reversed) inline void update_piece_administration() { - for (typename piece_vector_type::iterator it = boost::begin(m_pieces); - it != boost::end(m_pieces); - ++it) + for (auto& pc : m_pieces) { - piece& pc = *it; piece_border_type& border = pc.m_piece_border; buffered_ring<Ring> const& ring = offsetted_rings[pc.first_seg_id.multi_index]; @@ -561,8 +476,8 @@ struct buffered_piece_collection turn_in_piece_visitor < typename geometry::cs_tag<point_type>::type, - turn_vector_type, piece_vector_type, DistanceStrategy - > visitor(m_turns, m_pieces, m_distance_strategy); + turn_vector_type, piece_vector_type, DistanceStrategy, Strategy + > visitor(m_turns, m_pieces, m_distance_strategy, m_strategy); geometry::partition < @@ -694,7 +609,7 @@ struct buffered_piece_collection return; } - if (! input_ring.empty()) + if (! boost::empty(input_ring)) { // Assign the ring to the original_ring collection // For rescaling, it is recalculated. Without rescaling, it @@ -705,8 +620,7 @@ struct buffered_piece_collection using view_type = detail::closed_clockwise_view<InputRing const>; view_type const view(input_ring); - for (typename boost::range_iterator<view_type const>::type it = - boost::begin(view); it != boost::end(view); ++it) + for (auto it = boost::begin(view); it != boost::end(view); ++it) { clockwise_ring.push_back(*it); } @@ -798,11 +712,10 @@ struct buffered_piece_collection inline void sectionalize(piece const& pc, buffered_ring<Ring> const& ring) { - typedef geometry::detail::sectionalize::sectionalize_part + using sectionalizer = geometry::detail::sectionalize::sectionalize_part < - point_type, std::integer_sequence<std::size_t, 0, 1> // x,y dimension - > sectionalizer; + >; // Create a ring-identifier. The source-index is the piece index // The multi_index is as in this collection (the ring), but not used here @@ -860,7 +773,7 @@ struct buffered_piece_collection { BOOST_GEOMETRY_ASSERT(boost::size(range) != 0u); - typename Range::const_iterator it = boost::begin(range); + auto it = boost::begin(range); // If it follows a non-join (so basically the same piece-type) point b1 should be added. // There should be two intersections later and it should be discarded. @@ -918,12 +831,16 @@ struct buffered_piece_collection template <typename Range> inline void add_side_piece(point_type const& original_point1, point_type const& original_point2, - Range const& range, bool first) + Range const& range, bool is_first, bool is_empty) { BOOST_GEOMETRY_ASSERT(boost::size(range) >= 2u); - piece& pc = create_piece(strategy::buffer::buffered_segment, ! first); - add_range_to_piece(pc, range, first); + auto const piece_type = is_empty + ? strategy::buffer::buffered_empty_side + : strategy::buffer::buffered_segment; + + piece& pc = create_piece(piece_type, ! is_first); + add_range_to_piece(pc, range, is_first); // Add the four points of the side, starting with the last point of the // range, and reversing the order of the originals to keep it clockwise @@ -993,18 +910,17 @@ struct buffered_piece_collection // Those can never be traversed and should not be part of the output. inline void discard_rings() { - for (typename boost::range_iterator<turn_vector_type const>::type it = - boost::begin(m_turns); it != boost::end(m_turns); ++it) + for (auto const& turn : m_turns) { - if (it->is_turn_traversable) + if (turn.is_turn_traversable) { - offsetted_rings[it->operations[0].seg_id.multi_index].has_accepted_intersections = true; - offsetted_rings[it->operations[1].seg_id.multi_index].has_accepted_intersections = true; + offsetted_rings[turn.operations[0].seg_id.multi_index].has_accepted_intersections = true; + offsetted_rings[turn.operations[1].seg_id.multi_index].has_accepted_intersections = true; } else { - offsetted_rings[it->operations[0].seg_id.multi_index].has_discarded_intersections = true; - offsetted_rings[it->operations[1].seg_id.multi_index].has_discarded_intersections = true; + offsetted_rings[turn.operations[0].seg_id.multi_index].has_discarded_intersections = true; + offsetted_rings[turn.operations[1].seg_id.multi_index].has_discarded_intersections = true; } } } @@ -1017,12 +933,8 @@ struct buffered_piece_collection // any of the robust original rings // This can go quadratic if the input has many rings, and there // are many untouched deflated rings around - for (typename std::vector<original_ring>::const_iterator it - = original_rings.begin(); - it != original_rings.end(); - ++it) + for (auto const& original : original_rings) { - original_ring const& original = *it; if (original.m_ring.empty()) { continue; @@ -1064,12 +976,8 @@ struct buffered_piece_collection // be discarded inline void discard_nonintersecting_deflated_rings() { - for(typename buffered_ring_collection<buffered_ring<Ring> >::iterator it - = boost::begin(offsetted_rings); - it != boost::end(offsetted_rings); - ++it) + for (auto& ring : offsetted_rings) { - buffered_ring<Ring>& ring = *it; if (! ring.has_intersections() && boost::size(ring) > 0u && geometry::area(ring, m_strategy) < 0) @@ -1084,10 +992,8 @@ struct buffered_piece_collection inline void block_turns() { - for (typename boost::range_iterator<turn_vector_type>::type it = - boost::begin(m_turns); it != boost::end(m_turns); ++it) + for (auto& turn : m_turns) { - buffer_turn_info_type& turn = *it; if (! turn.is_turn_traversable) { // Discard this turn (don't set it to blocked to avoid colocated @@ -1120,21 +1026,16 @@ struct buffered_piece_collection inline void reverse() { - for(typename buffered_ring_collection<buffered_ring<Ring> >::iterator it = boost::begin(offsetted_rings); - it != boost::end(offsetted_rings); - ++it) + for (auto& ring : offsetted_rings) { - if (! it->has_intersections()) + if (! ring.has_intersections()) { - std::reverse(it->begin(), it->end()); + std::reverse(ring.begin(), ring.end()); } } - for (typename boost::range_iterator<buffered_ring_collection<Ring> >::type - it = boost::begin(traversed_rings); - it != boost::end(traversed_rings); - ++it) + for (auto& ring : traversed_rings) { - std::reverse(it->begin(), it->end()); + std::reverse(ring.begin(), ring.end()); } } @@ -1156,37 +1057,30 @@ struct buffered_piece_collection // Inner rings, for deflate, which do not have intersections, and // which are outside originals, are skipped // (other ones should be traversed) - signed_size_type index = 0; - for(typename buffered_ring_collection<buffered_ring<Ring> >::const_iterator it = boost::begin(offsetted_rings); - it != boost::end(offsetted_rings); - ++it, ++index) - { - if (! it->has_intersections() - && ! it->is_untouched_outside_original) + for_each_with_index(offsetted_rings, [&](std::size_t index, auto const& ring) { - properties p = properties(*it, m_strategy); - if (p.valid) + if (! ring.has_intersections() + && ! ring.is_untouched_outside_original) { - ring_identifier id(0, index, -1); - selected[id] = p; + properties p = properties(ring, m_strategy); + if (p.valid) + { + ring_identifier id(0, index, -1); + selected[id] = p; + } } - } - } + }); // Select all created rings - index = 0; - for (typename boost::range_iterator<buffered_ring_collection<Ring> const>::type - it = boost::begin(traversed_rings); - it != boost::end(traversed_rings); - ++it, ++index) - { - properties p = properties(*it, m_strategy); - if (p.valid) + for_each_with_index(traversed_rings, [&](std::size_t index, auto const& ring) { - ring_identifier id(2, index, -1); - selected[id] = p; - } - } + properties p = properties(ring, m_strategy); + if (p.valid) + { + ring_identifier id(2, index, -1); + selected[id] = p; + } + }); detail::overlay::assign_parents<overlay_buffer>(offsetted_rings, traversed_rings, selected, m_strategy); diff --git a/boost/geometry/algorithms/detail/buffer/get_piece_turns.hpp b/boost/geometry/algorithms/detail/buffer/get_piece_turns.hpp index 09fef75185..c5b0aedc75 100644 --- a/boost/geometry/algorithms/detail/buffer/get_piece_turns.hpp +++ b/boost/geometry/algorithms/detail/buffer/get_piece_turns.hpp @@ -194,7 +194,6 @@ class piece_turn_visitor { typedef typename boost::range_value<Rings const>::type ring_type; typedef typename boost::range_value<Turns const>::type turn_type; - typedef typename boost::range_iterator<ring_type const>::type iterator; signed_size_type const piece1_first_index = piece1.first_seg_id.segment_index; signed_size_type const piece2_first_index = piece2.first_seg_id.segment_index; @@ -213,12 +212,12 @@ class piece_turn_visitor // get geometry and iterators over these sections ring_type const& ring1 = m_rings[piece1.first_seg_id.multi_index]; - iterator it1_first = boost::begin(ring1) + sec1_first_index; - iterator it1_beyond = boost::begin(ring1) + sec1_last_index + 1; + auto it1_first = boost::begin(ring1) + sec1_first_index; + auto it1_beyond = boost::begin(ring1) + sec1_last_index + 1; ring_type const& ring2 = m_rings[piece2.first_seg_id.multi_index]; - iterator it2_first = boost::begin(ring2) + sec2_first_index; - iterator it2_beyond = boost::begin(ring2) + sec2_last_index + 1; + auto it2_first = boost::begin(ring2) + sec2_first_index; + auto it2_beyond = boost::begin(ring2) + sec2_last_index + 1; // Set begin/end of monotonic ranges, in both x/y directions signed_size_type index1 = sec1_first_index; @@ -246,8 +245,8 @@ class piece_turn_visitor the_model.operations[0].seg_id = piece1.first_seg_id; the_model.operations[0].seg_id.segment_index = index1; // override - iterator it1 = it1_first; - for (iterator prev1 = it1++; + auto it1 = it1_first; + for (auto prev1 = it1++; it1 != it1_beyond; prev1 = it1++, the_model.operations[0].seg_id.segment_index++) { @@ -257,8 +256,8 @@ class piece_turn_visitor unique_sub_range_from_piece<ring_type> unique_sub_range1(ring1, prev1, it1); - iterator it2 = it2_first; - for (iterator prev2 = it2++; + auto it2 = it2_first; + for (auto prev2 = it2++; it2 != it2_beyond; prev2 = it2++, the_model.operations[1].seg_id.segment_index++) { diff --git a/boost/geometry/algorithms/detail/buffer/implementation.hpp b/boost/geometry/algorithms/detail/buffer/implementation.hpp new file mode 100644 index 0000000000..8b820e8f71 --- /dev/null +++ b/boost/geometry/algorithms/detail/buffer/implementation.hpp @@ -0,0 +1,214 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 Mateusz Loskot, London, UK. + +// This file was modified by Oracle on 2017-2022. +// Modifications copyright (c) 2017-2022 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 +// (geolib/GGL), copyright (c) 1995-2010 Geodan, 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_IMPLEMENTATION_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_IMPLEMENTATION_HPP + +#include <boost/range/value_type.hpp> + +#include <boost/geometry/algorithms/detail/buffer/buffer_box.hpp> +#include <boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp> +#include <boost/geometry/algorithms/detail/buffer/interface.hpp> +#include <boost/geometry/algorithms/detail/visit.hpp> // for GC +#include <boost/geometry/algorithms/envelope.hpp> +#include <boost/geometry/algorithms/is_empty.hpp> +#include <boost/geometry/algorithms/union.hpp> // for GC +#include <boost/geometry/arithmetic/arithmetic.hpp> +#include <boost/geometry/geometries/box.hpp> +#include <boost/geometry/strategies/buffer/cartesian.hpp> +#include <boost/geometry/strategies/buffer/geographic.hpp> +#include <boost/geometry/strategies/buffer/spherical.hpp> +#include <boost/geometry/util/math.hpp> +#include <boost/geometry/util/range.hpp> + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + +template <typename BoxIn, typename BoxOut> +struct buffer_dc<BoxIn, BoxOut, box_tag, box_tag> +{ + template <typename Distance> + static inline void apply(BoxIn const& box_in, BoxOut& box_out, + Distance const& distance, Distance const& ) + { + detail::buffer::buffer_box(box_in, distance, box_out); + } +}; + + +template <typename Input, typename Output, typename TagIn> +struct buffer_all<Input, Output, TagIn, multi_polygon_tag> +{ + template + < + typename DistanceStrategy, + typename SideStrategy, + typename JoinStrategy, + typename EndStrategy, + typename PointStrategy, + typename Strategies + > + static inline void apply(Input const& geometry_in, + Output& geometry_out, + DistanceStrategy const& distance_strategy, + SideStrategy const& side_strategy, + JoinStrategy const& join_strategy, + EndStrategy const& end_strategy, + PointStrategy const& point_strategy, + Strategies const& strategies) + { + typedef typename boost::range_value<Output>::type polygon_type; + + typedef typename point_type<Input>::type point_type; + typedef typename rescale_policy_type + < + point_type, + typename geometry::cs_tag<point_type>::type + >::type rescale_policy_type; + + if (geometry::is_empty(geometry_in)) + { + // Then output geometry is kept empty as well + return; + } + + model::box<point_type> box; + geometry::envelope(geometry_in, box); + geometry::buffer(box, box, distance_strategy.max_distance(join_strategy, end_strategy)); + + rescale_policy_type rescale_policy + = boost::geometry::get_rescale_policy<rescale_policy_type>( + box, strategies); + + detail::buffer::buffer_inserter<polygon_type>(geometry_in, + range::back_inserter(geometry_out), + distance_strategy, + side_strategy, + join_strategy, + end_strategy, + point_strategy, + strategies, + rescale_policy); + } +}; + + +template <typename Input, typename Output> +struct buffer_all<Input, Output, geometry_collection_tag, multi_polygon_tag> +{ + template + < + typename DistanceStrategy, + typename SideStrategy, + typename JoinStrategy, + typename EndStrategy, + typename PointStrategy, + typename Strategies + > + static inline void apply(Input const& geometry_in, + Output& geometry_out, + DistanceStrategy const& distance_strategy, + SideStrategy const& side_strategy, + JoinStrategy const& join_strategy, + EndStrategy const& end_strategy, + PointStrategy const& point_strategy, + Strategies const& strategies) + { + // NOTE: The buffer normally calculates everything at once (by pieces) and traverses all + // of them to apply the union operation. Not even by merging elements. But that is + // complex and has led to issues as well. Here intermediate results are calculated + // with buffer and the results are merged afterwards. + // NOTE: This algorithm merges partial results iteratively. + // We could first gather all of the results and after that + // use some more optimal method like merge_elements(). + detail::visit_breadth_first([&](auto const& g) + { + Output buffer_result; + buffer_all + < + util::remove_cref_t<decltype(g)>, Output + >::apply(g, buffer_result, distance_strategy, side_strategy, + join_strategy, end_strategy, point_strategy, strategies); + + if (! geometry::is_empty(buffer_result)) + { + Output union_result; + geometry::union_(geometry_out, buffer_result, union_result, strategies); + geometry_out = std::move(union_result); + } + + return true; + }, geometry_in); + } +}; + +template <typename Input, typename Output> +struct buffer_all<Input, Output, geometry_collection_tag, geometry_collection_tag> +{ + template + < + typename DistanceStrategy, + typename SideStrategy, + typename JoinStrategy, + typename EndStrategy, + typename PointStrategy, + typename Strategies + > + static inline void apply(Input const& geometry_in, + Output& geometry_out, + DistanceStrategy const& distance_strategy, + SideStrategy const& side_strategy, + JoinStrategy const& join_strategy, + EndStrategy const& end_strategy, + PointStrategy const& point_strategy, + Strategies const& strategies) + { + // NOTE: We could also allow returning GC containing only polygons. + // We'd have to wrap them in model::multi_polygon and then + // iteratively emplace_back() into the GC. + using mpo_t = typename util::sequence_find_if + < + typename traits::geometry_types<Output>::type, + util::is_multi_polygon + >::type; + mpo_t result; + buffer_all + < + Input, mpo_t + >::apply(geometry_in, result, distance_strategy, side_strategy, + join_strategy, end_strategy, point_strategy, strategies); + range::emplace_back(geometry_out, std::move(result)); + } +}; + +template <typename Input, typename Output, typename TagIn> +struct buffer_all<Input, Output, TagIn, geometry_collection_tag> + : buffer_all<Input, Output, geometry_collection_tag, geometry_collection_tag> +{}; + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_IMPLEMENTATION_HPP diff --git a/boost/geometry/algorithms/detail/buffer/interface.hpp b/boost/geometry/algorithms/detail/buffer/interface.hpp new file mode 100644 index 0000000000..d19abd6efe --- /dev/null +++ b/boost/geometry/algorithms/detail/buffer/interface.hpp @@ -0,0 +1,279 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 Mateusz Loskot, London, UK. + +// This file was modified by Oracle on 2017-2022. +// Modifications copyright (c) 2017-2022 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 +// (geolib/GGL), copyright (c) 1995-2010 Geodan, 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_INTERFACE_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_INTERFACE_HPP + +#include <boost/geometry/algorithms/clear.hpp> +#include <boost/geometry/algorithms/not_implemented.hpp> +#include <boost/geometry/core/visit.hpp> +#include <boost/geometry/core/tag.hpp> +#include <boost/geometry/geometries/adapted/boost_variant.hpp> +#include <boost/geometry/geometries/concepts/check.hpp> +#include <boost/geometry/strategies/buffer/services.hpp> +#include <boost/geometry/util/type_traits_std.hpp> + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + +template +< + typename Input, + typename Output, + typename TagIn = typename tag<Input>::type, + typename TagOut = typename tag<Output>::type +> +struct buffer_dc : not_implemented<TagIn, TagOut> +{}; + +template +< + typename Input, + typename Output, + typename TagIn = typename tag<Input>::type, + typename TagOut = typename tag<Output>::type +> +struct buffer_all : not_implemented<TagIn, TagOut> +{}; + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +namespace resolve_dynamic +{ + +template +< + typename Input, + typename TagIn = typename geometry::tag<Input>::type +> +struct buffer_dc +{ + template <typename Output, typename Distance> + static inline void apply(Input const& geometry_in, + Output& geometry_out, + Distance const& distance, + Distance const& chord_length) + { + dispatch::buffer_dc<Input, Output>::apply(geometry_in, geometry_out, distance, chord_length); + } +}; + +template <typename Input> +struct buffer_dc<Input, dynamic_geometry_tag> +{ + template <typename Output, typename Distance> + static inline void apply(Input const& geometry_in, + Output& geometry_out, + Distance const& distance, + Distance const& chord_length) + { + traits::visit<Input>::apply([&](auto const& g) + { + dispatch::buffer_dc + < + util::remove_cref_t<decltype(g)>, Output + >::apply(g, geometry_out, distance, chord_length); + }, geometry_in); + } +}; + + +template +< + typename Input, + typename TagIn = typename geometry::tag<Input>::type +> +struct buffer_all +{ + template + < + typename Output, + typename DistanceStrategy, + typename SideStrategy, + typename JoinStrategy, + typename EndStrategy, + typename PointStrategy + > + static inline void apply(Input const& geometry_in, + Output& geometry_out, + DistanceStrategy const& distance_strategy, + SideStrategy const& side_strategy, + JoinStrategy const& join_strategy, + EndStrategy const& end_strategy, + PointStrategy const& point_strategy) + { + typename strategies::buffer::services::default_strategy + < + Input + >::type strategies; + + dispatch::buffer_all + < + Input, Output + >::apply(geometry_in, geometry_out, distance_strategy, side_strategy, + join_strategy, end_strategy, point_strategy, strategies); + } +}; + +template <typename Input> +struct buffer_all<Input, dynamic_geometry_tag> +{ + template + < + typename Output, + typename DistanceStrategy, + typename SideStrategy, + typename JoinStrategy, + typename EndStrategy, + typename PointStrategy + > + static inline void apply(Input const& geometry_in, + Output& geometry_out, + DistanceStrategy const& distance_strategy, + SideStrategy const& side_strategy, + JoinStrategy const& join_strategy, + EndStrategy const& end_strategy, + PointStrategy const& point_strategy) + { + traits::visit<Input>::apply([&](auto const& g) + { + buffer_all + < + util::remove_cref_t<decltype(g)> + >::apply(g, geometry_out, distance_strategy, side_strategy, + join_strategy, end_strategy, point_strategy); + }, geometry_in); + } +}; + +} // namespace resolve_dynamic + + +/*! +\brief \brief_calc{buffer} +\ingroup buffer +\details \details_calc{buffer, \det_buffer}. +\tparam Input \tparam_geometry +\tparam Output \tparam_geometry +\tparam Distance \tparam_numeric +\param geometry_in \param_geometry +\param geometry_out \param_geometry +\param distance The distance to be used for the buffer +\param chord_length (optional) The length of the chord's in the generated arcs around points or bends + +\qbk{[include reference/algorithms/buffer.qbk]} + */ +template <typename Input, typename Output, typename Distance> +inline void buffer(Input const& geometry_in, Output& geometry_out, + Distance const& distance, Distance const& chord_length = -1) +{ + concepts::check<Input const>(); + concepts::check<Output>(); + + resolve_dynamic::buffer_dc<Input>::apply(geometry_in, geometry_out, distance, chord_length); +} + +/*! +\brief \brief_calc{buffer} +\ingroup buffer +\details \details_calc{return_buffer, \det_buffer}. \details_return{buffer}. +\tparam Input \tparam_geometry +\tparam Output \tparam_geometry +\tparam Distance \tparam_numeric +\param geometry \param_geometry +\param distance The distance to be used for the buffer +\param chord_length (optional) The length of the chord's in the generated arcs + around points or bends (RESERVED, NOT YET USED) +\return \return_calc{buffer} + */ +template <typename Output, typename Input, typename Distance> +inline Output return_buffer(Input const& geometry, Distance const& distance, + Distance const& chord_length = -1) +{ + concepts::check<Input const>(); + concepts::check<Output>(); + + Output geometry_out; + + resolve_dynamic::buffer_dc<Input>::apply(geometry, geometry_out, distance, chord_length); + + return geometry_out; +} + +/*! +\brief \brief_calc{buffer} +\ingroup buffer +\details \details_calc{buffer, \det_buffer}. +\tparam GeometryIn \tparam_geometry +\tparam GeometryOut \tparam_geometry{GeometryOut} +\tparam DistanceStrategy A strategy defining distance (or radius) +\tparam SideStrategy A strategy defining creation along sides +\tparam JoinStrategy A strategy defining creation around convex corners +\tparam EndStrategy A strategy defining creation at linestring ends +\tparam PointStrategy A strategy defining creation around points +\param geometry_in \param_geometry +\param geometry_out output geometry, e.g. multi polygon, + will contain a buffered version of the input geometry +\param distance_strategy The distance strategy to be used +\param side_strategy The side strategy to be used +\param join_strategy The join strategy to be used +\param end_strategy The end strategy to be used +\param point_strategy The point strategy to be used + +\qbk{distinguish,with strategies} +\qbk{[include reference/algorithms/buffer_with_strategies.qbk]} + */ +template +< + typename GeometryIn, + typename GeometryOut, + typename DistanceStrategy, + typename SideStrategy, + typename JoinStrategy, + typename EndStrategy, + typename PointStrategy +> +inline void buffer(GeometryIn const& geometry_in, + GeometryOut& geometry_out, + DistanceStrategy const& distance_strategy, + SideStrategy const& side_strategy, + JoinStrategy const& join_strategy, + EndStrategy const& end_strategy, + PointStrategy const& point_strategy) +{ + concepts::check<GeometryIn const>(); + concepts::check<GeometryOut>(); + + geometry::clear(geometry_out); + + resolve_dynamic::buffer_all + < + GeometryIn, GeometryOut + >::apply(geometry_in, geometry_out, distance_strategy, side_strategy, + join_strategy, end_strategy, point_strategy); +} + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_INTERFACE_HPP diff --git a/boost/geometry/algorithms/detail/buffer/piece_border.hpp b/boost/geometry/algorithms/detail/buffer/piece_border.hpp index ecd03d9c82..d773d32c36 100644 --- a/boost/geometry/algorithms/detail/buffer/piece_border.hpp +++ b/boost/geometry/algorithms/detail/buffer/piece_border.hpp @@ -1,9 +1,10 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2020 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2020-2021 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2023 Adam Wulkiewicz, Lodz, Poland. -// This file was modified by Oracle on 2020. -// Modifications copyright (c) 2020, Oracle and/or its affiliates. +// This file was modified by Oracle on 2020-2022. +// Modifications copyright (c) 2020-2022, 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, @@ -14,7 +15,8 @@ #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_PIECE_BORDER_HPP -#include <boost/array.hpp> +#include <array> + #include <boost/core/addressof.hpp> #include <boost/geometry/core/assert.hpp> @@ -24,7 +26,6 @@ #include <boost/geometry/algorithms/comparable_distance.hpp> #include <boost/geometry/algorithms/equals.hpp> #include <boost/geometry/algorithms/expand.hpp> -#include <boost/geometry/algorithms/detail/buffer/buffer_box.hpp> #include <boost/geometry/algorithms/detail/buffer/buffer_policies.hpp> #include <boost/geometry/algorithms/detail/expand_by_epsilon.hpp> #include <boost/geometry/strategies/cartesian/turn_in_ring_winding.hpp> @@ -116,7 +117,7 @@ struct piece_border // Points from the original (one or two, depending on piece shape) // Note, if there are 2 points, they are REVERSED w.r.t. the original // Therefore here we can walk in its order. - boost::array<Point, 2> m_originals; + std::array<Point, 2> m_originals; std::size_t m_original_size; geometry::model::box<Point> m_envelope; @@ -262,16 +263,21 @@ struct piece_border if (m_original_size == 1) { // One point. Walk from last offsetted to point, and from point to first offsetted - continue_processing = step(point, offsetted_back, m_originals[0], tir, por_from_offsetted, state) - && step(point, m_originals[0], offsetted_front, tir, por_to_offsetted, state); + continue_processing = step(point, offsetted_back, m_originals[0], + tir, por_from_offsetted, state) + && step(point, m_originals[0], offsetted_front, + tir, por_to_offsetted, state); } else if (m_original_size == 2) { // Two original points. Walk from last offsetted point to first original point, // then along original, then from second oginal to first offsetted point - continue_processing = step(point, offsetted_back, m_originals[0], tir, por_from_offsetted, state) - && step(point, m_originals[0], m_originals[1], tir, por_original, state) - && step(point, m_originals[1], offsetted_front, tir, por_to_offsetted, state); + continue_processing = step(point, offsetted_back, m_originals[0], + tir, por_from_offsetted, state) + && step(point, m_originals[0], m_originals[1], + tir, por_original, state) + && step(point, m_originals[1], offsetted_front, + tir, por_to_offsetted, state); } if (continue_processing) @@ -302,8 +308,15 @@ private : : target; } - template <typename TurnPoint, typename Iterator, typename Strategy, typename State> - bool walk_offsetted(TurnPoint const& point, Iterator begin, Iterator end, Strategy const & strategy, State& state) const + template + < + typename TurnPoint, typename Iterator, + typename TiRStrategy, + typename State + > + bool walk_offsetted(TurnPoint const& point, Iterator begin, Iterator end, + TiRStrategy const & strategy, + State& state) const { Iterator it = begin; Iterator beyond = end; @@ -327,7 +340,7 @@ private : for (Iterator previous = it++ ; it != beyond ; ++previous, ++it ) { if (! step(point, *previous, *it, strategy, - geometry::strategy::buffer::place_on_ring_offsetted, state)) + geometry::strategy::buffer::place_on_ring_offsetted, state)) { return false; } @@ -336,27 +349,11 @@ private : } template <typename TurnPoint, typename TiRStrategy, typename State> - bool step(TurnPoint const& point, Point const& p1, Point const& p2, TiRStrategy const & strategy, + bool step(TurnPoint const& point, Point const& p1, Point const& p2, + TiRStrategy const& strategy, geometry::strategy::buffer::place_on_ring_type place_on_ring, State& state) const { - // A step between original/offsetted ring is always convex - // (unless the join strategy generates points left of it - - // future: convexity might be added to the buffer-join-strategy) - // Therefore, if the state count > 0, it means the point is left of it, - // and because it is convex, we can stop - - typedef typename geometry::coordinate_type<Point>::type coordinate_type; - typedef geometry::detail::distance_measure<coordinate_type> dm_type; - dm_type const dm = geometry::detail::get_distance_measure(point, p1, p2); - if (m_is_convex && dm.measure > 0) - { - // The point is left of this segment of a convex piece - state.m_count = 0; - return false; - } - // Call strategy, and if it is on the border, return false - // to stop further processing. - return strategy.apply(point, p1, p2, dm, place_on_ring, state); + return strategy.apply(point, p1, p2, place_on_ring, m_is_convex, state); } template <typename It, typename Box, typename Strategy> 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 b1930dc0c4..daa59b618b 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,9 @@ // Copyright (c) 2014 Barend Gehrels, Amsterdam, the Netherlands. -// This file was modified by Oracle on 2016-2020. -// Modifications copyright (c) 2016-2020 Oracle and/or its affiliates. +// This file was modified by Oracle on 2016-2023. +// Modifications copyright (c) 2016-2023 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, @@ -18,6 +19,7 @@ #include <boost/geometry/core/coordinate_type.hpp> #include <boost/geometry/algorithms/detail/buffer/buffer_policies.hpp> +#include <boost/geometry/algorithms/detail/disjoint/interface.hpp> #include <boost/geometry/algorithms/expand.hpp> #include <boost/geometry/strategies/agnostic/point_in_poly_winding.hpp> #include <boost/geometry/strategies/buffer.hpp> @@ -32,7 +34,7 @@ namespace detail { namespace buffer { -template <typename Strategy> +template <typename Strategy> struct original_get_box { explicit original_get_box(Strategy const& strategy) @@ -190,20 +192,11 @@ inline int point_in_original(Point const& point, Original const& original, return strategy.result(state); } - typedef typename Original::sections_type sections_type; - typedef typename boost::range_iterator<sections_type const>::type iterator_type; - typedef typename boost::range_value<sections_type const>::type section_type; - typedef typename geometry::coordinate_type<Point>::type coordinate_type; - - coordinate_type const point_x = geometry::get<0>(point); + auto const point_x = geometry::get<0>(point); // Walk through all monotonic sections of this original - for (iterator_type it = boost::begin(original.m_sections); - it != boost::end(original.m_sections); - ++it) + for (auto const& section : original.m_sections) { - section_type const& section = *it; - if (! section.duplicate && section.begin_index < section.end_index && point_x >= geometry::get<min_corner, 0>(section.bounding_box) 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 f51bd29007..bb7019c089 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-2020 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland. -// This file was modified by Oracle on 2016, 2018. -// Modifications copyright (c) 2016-2018 Oracle and/or its affiliates. +// This file was modified by Oracle on 2016-2022. +// Modifications copyright (c) 2016-2022 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, @@ -21,6 +21,7 @@ #include <boost/geometry/algorithms/covered_by.hpp> #include <boost/geometry/algorithms/detail/disjoint/point_box.hpp> #include <boost/geometry/algorithms/detail/disjoint/box_box.hpp> +#include <boost/geometry/algorithms/detail/dummy_geometries.hpp> #include <boost/geometry/algorithms/detail/buffer/buffer_policies.hpp> #include <boost/geometry/geometries/box.hpp> @@ -38,7 +39,8 @@ template typename CsTag, typename Turns, typename Pieces, - typename DistanceStrategy + typename DistanceStrategy, + typename UmbrellaStrategy > class turn_in_piece_visitor @@ -46,6 +48,7 @@ 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 DistanceStrategy const& m_distance_strategy; // to check if point is on original or one_sided + UmbrellaStrategy const& m_umbrella_strategy; template <typename Operation, typename Piece> inline bool skip(Operation const& op, Piece const& piece) const @@ -94,10 +97,12 @@ class turn_in_piece_visitor public: inline turn_in_piece_visitor(Turns& turns, Pieces const& pieces, - DistanceStrategy const& distance_strategy) + DistanceStrategy const& distance_strategy, + UmbrellaStrategy const& umbrella_strategy) : m_turns(turns) , m_pieces(pieces) , m_distance_strategy(distance_strategy) + , m_umbrella_strategy(umbrella_strategy) {} template <typename Turn, typename Piece> @@ -127,20 +132,24 @@ public: template <typename Turn, typename Piece, typename Border> inline bool apply(Turn const& turn, Piece const& piece, Border const& border) { - if (! geometry::covered_by(turn.point, border.m_envelope)) + if (! geometry::covered_by(turn.point, border.m_envelope, m_umbrella_strategy)) { // Easy check: if turn is not in the (expanded) envelope return true; } + if (piece.type == geometry::strategy::buffer::buffered_empty_side) + { + return false; + } + if (piece.type == geometry::strategy::buffer::buffered_point) { // Optimization for a buffer around points: if distance from center // is not between min/max radius, it is either inside or outside, // and more expensive checks are not necessary. - typedef typename Border::radius_type radius_type; - - radius_type const d = geometry::comparable_distance(piece.m_center, turn.point); + auto const d = geometry::comparable_distance(piece.m_center, turn.point, + m_umbrella_strategy); if (d < border.m_min_comparable_radius) { @@ -155,38 +164,20 @@ public: } // Check if buffer is one-sided (at this point), because then a point - // on the original is not considered as within. + // on the original border is not considered as within. bool const one_sided = has_zero_distance_at(turn.point); typename Border::state_type state; - if (! border.point_on_piece(turn.point, one_sided, turn.is_linear_end_point, state)) + if (! border.point_on_piece(turn.point, one_sided, + turn.is_linear_end_point, state)) { return true; } - if (state.code() == 1) + if (state.is_inside() && ! state.is_on_boundary()) { - // It is WITHIN a piece, or on the piece border, but not - // on the offsetted part of it. - - // TODO - at further removing rescaling, this threshold can be - // adapted, or ideally, go. - // This threshold is minimized to the point where fragile - // unit tests of hard cases start to fail (5 in multi_polygon) - // But it is acknowlegded that such a threshold depends on the - // scale of the input. - if (state.m_min_distance > 1.0e-5 || ! state.m_close_to_offset) - { - Turn& mutable_turn = m_turns[turn.turn_index]; - mutable_turn.is_turn_traversable = false; - - // Keep track of the information if this turn was close - // to an offset (without threshold). Because if it was, - // it might have been classified incorrectly and in the - // pretraversal step, it can in hindsight be classified - // as "outside". - mutable_turn.close_to_offset = state.m_close_to_offset; - } + Turn& mutable_turn = m_turns[turn.turn_index]; + mutable_turn.is_turn_traversable = false; } return true; diff --git a/boost/geometry/algorithms/detail/calculate_point_order.hpp b/boost/geometry/algorithms/detail/calculate_point_order.hpp index a9362b3613..191f71f3d8 100644 --- a/boost/geometry/algorithms/detail/calculate_point_order.hpp +++ b/boost/geometry/algorithms/detail/calculate_point_order.hpp @@ -1,7 +1,8 @@ // Boost.Geometry -// Copyright (c) 2019-2021, Oracle and/or its affiliates. +// Copyright (c) 2023 Adam Wulkiewicz, Lodz, Poland. +// Copyright (c) 2019-2021, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Licensed under the Boost Software License version 1.0. @@ -36,7 +37,7 @@ struct clean_point , m_is_azi_valid(false), m_is_azi_diff_valid(false) {} - typename boost::iterators::iterator_reference<Iter>::type ref() const + decltype(auto) ref() const { return *m_iter; } @@ -108,8 +109,6 @@ struct calculate_point_order_by_azimuth typedef typename boost::range_iterator<Ring const>::type iter_t; typedef typename Strategy::template result_type<Ring>::type calc_t; typedef clean_point<iter_t, calc_t> clean_point_t; - typedef std::vector<clean_point_t> cleaned_container_t; - typedef typename cleaned_container_t::iterator cleaned_iter_t; calc_t const zero = 0; calc_t const pi = math::pi<calc_t>(); @@ -121,21 +120,21 @@ struct calculate_point_order_by_azimuth } // non-duplicated, non-spike points - cleaned_container_t cleaned; + std::vector<clean_point_t> cleaned; cleaned.reserve(count); for (iter_t it = boost::begin(ring); it != boost::end(ring); ++it) { // Add point cleaned.push_back(clean_point_t(it)); - + while (cleaned.size() >= 3) { - cleaned_iter_t it0 = cleaned.end() - 3; - cleaned_iter_t it1 = cleaned.end() - 2; - cleaned_iter_t it2 = cleaned.end() - 1; + auto it0 = cleaned.end() - 3; + auto it1 = cleaned.end() - 2; + auto it2 = cleaned.end() - 1; - calc_t diff; + calc_t diff; if (get_or_calculate_azimuths_difference(*it0, *it1, *it2, diff, strategy) && ! math::equals(math::abs(diff), pi)) { @@ -148,7 +147,7 @@ struct calculate_point_order_by_azimuth // TODO: angles have to be invalidated only if spike is detected // for duplicates it'd be ok to leave them it0->set_azimuth_invalid(); - it0->set_azimuth_difference_invalid(); + it0->set_azimuth_difference_invalid(); it2->set_azimuth_difference_invalid(); cleaned.erase(it1); } @@ -156,8 +155,8 @@ struct calculate_point_order_by_azimuth } // filter-out duplicates and spikes at the front and back of cleaned - cleaned_iter_t cleaned_b = cleaned.begin(); - cleaned_iter_t cleaned_e = cleaned.end(); + auto cleaned_b = cleaned.begin(); + auto cleaned_e = cleaned.end(); std::size_t cleaned_count = cleaned.size(); bool found = false; do @@ -165,10 +164,10 @@ struct calculate_point_order_by_azimuth found = false; while(cleaned_count >= 3) { - cleaned_iter_t it0 = cleaned_e - 2; - cleaned_iter_t it1 = cleaned_e - 1; - cleaned_iter_t it2 = cleaned_b; - cleaned_iter_t it3 = cleaned_b + 1; + auto it0 = cleaned_e - 2; + auto it1 = cleaned_e - 1; + auto it2 = cleaned_b; + auto it3 = cleaned_b + 1; calc_t diff = 0; if (! get_or_calculate_azimuths_difference(*it0, *it1, *it2, diff, strategy) @@ -212,10 +211,10 @@ struct calculate_point_order_by_azimuth // calculate the sum of external angles calc_t angles_sum = zero; - for (cleaned_iter_t it = cleaned_b; it != cleaned_e; ++it) + for (auto it = cleaned_b; it != cleaned_e; ++it) { - cleaned_iter_t it0 = (it == cleaned_b ? cleaned_e - 1 : it - 1); - cleaned_iter_t it2 = (it == cleaned_e - 1 ? cleaned_b : it + 1); + auto it0 = (it == cleaned_b ? cleaned_e - 1 : it - 1); + auto it2 = (it == cleaned_e - 1 ? cleaned_b : it + 1); calc_t diff = 0; get_or_calculate_azimuths_difference(*it0, *it, *it2, diff, strategy); @@ -269,7 +268,7 @@ private: razi = p0.reverse_azimuth(); return true; } - + if (strategy.apply(p0.ref(), p1.ref(), azi, razi)) { p0.set_azimuths(azi, razi); @@ -336,7 +335,7 @@ namespace detail template <typename Ring, typename Strategy> inline geometry::order_selector calculate_point_order(Ring const& ring, Strategy const& strategy) { - concepts::check<Ring>(); + concepts::check<Ring const>(); return dispatch::calculate_point_order<Strategy>::apply(ring, strategy); } @@ -349,7 +348,7 @@ inline geometry::order_selector calculate_point_order(Ring const& ring) typename geometry::cs_tag<Ring>::type >::type strategy_type; - concepts::check<Ring>(); + concepts::check<Ring const>(); return dispatch::calculate_point_order<strategy_type>::apply(ring, strategy_type()); } diff --git a/boost/geometry/algorithms/detail/calculate_sum.hpp b/boost/geometry/algorithms/detail/calculate_sum.hpp index 4af986fb62..4296d88e61 100644 --- a/boost/geometry/algorithms/detail/calculate_sum.hpp +++ b/boost/geometry/algorithms/detail/calculate_sum.hpp @@ -37,8 +37,7 @@ class calculate_polygon_sum static inline ReturnType sum_interior_rings(Rings const& rings, Strategy const& strategy) { ReturnType sum = ReturnType(0); - for (typename boost::range_iterator<Rings const>::type - it = boost::begin(rings); it != boost::end(rings); ++it) + for (auto it = boost::begin(rings); it != boost::end(rings); ++it) { sum += Policy::apply(*it, strategy); } diff --git a/boost/geometry/algorithms/detail/centroid/translating_transformer.hpp b/boost/geometry/algorithms/detail/centroid/translating_transformer.hpp index 56a7e3ec91..042891e6e2 100644 --- a/boost/geometry/algorithms/detail/centroid/translating_transformer.hpp +++ b/boost/geometry/algorithms/detail/centroid/translating_transformer.hpp @@ -75,7 +75,7 @@ struct translating_transformer<Geometry, areal_tag, cartesian_tag> { typedef typename geometry::point_type<Geometry>::type point_type; typedef point_type result_type; - + explicit translating_transformer(Geometry const& geom) : m_origin(NULL) { diff --git a/boost/geometry/algorithms/detail/check_iterator_range.hpp b/boost/geometry/algorithms/detail/check_iterator_range.hpp deleted file mode 100644 index 9bd1d7ae27..0000000000 --- a/boost/geometry/algorithms/detail/check_iterator_range.hpp +++ /dev/null @@ -1,71 +0,0 @@ -// Boost.Geometry (aka GGL, Generic Geometry Library) - -// Copyright (c) 2014, Oracle and/or its affiliates. - -// Contributed and/or modified by Menelaos Karavelas, 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_CHECK_ITERATOR_RANGE_HPP -#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CHECK_ITERATOR_RANGE_HPP - -#include <boost/core/ignore_unused.hpp> - - -namespace boost { namespace geometry -{ - -#ifndef DOXYGEN_NO_DETAIL -namespace detail -{ - -// Check whether (each element of) an iterator range satisfies a given -// predicate. -// The predicate must be implemented as having a static apply unary -// method that returns a bool. -// By default an empty range is accepted -template <typename Predicate, bool AllowEmptyRange = true> -struct check_iterator_range -{ - template <typename InputIterator> - static inline bool apply(InputIterator first, InputIterator beyond) - { - for (InputIterator it = first; it != beyond; ++it) - { - if (! Predicate::apply(*it)) - { - return false; - } - } - return AllowEmptyRange || first != beyond; - } - - - // version where we can pass a predicate object - template <typename InputIterator> - static inline bool apply(InputIterator first, - InputIterator beyond, - Predicate const& predicate) - { - // in case predicate's apply method is static, MSVC will - // complain that predicate is not used - boost::ignore_unused(predicate); - - for (InputIterator it = first; it != beyond; ++it) - { - if (! predicate.apply(*it)) - { - return false; - } - } - return AllowEmptyRange || first != beyond; - } -}; - -} // namespace detail -#endif // DOXYGEN_NO_DETAIL - -}} // namespace boost::geometry - -#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_CHECK_ITERATOR_RANGE_HPP diff --git a/boost/geometry/algorithms/detail/closest_feature/geometry_to_range.hpp b/boost/geometry/algorithms/detail/closest_feature/geometry_to_range.hpp index 4ac5ac6976..c5d331aaf3 100644 --- a/boost/geometry/algorithms/detail/closest_feature/geometry_to_range.hpp +++ b/boost/geometry/algorithms/detail/closest_feature/geometry_to_range.hpp @@ -92,7 +92,7 @@ public: typename RangeIterator, typename Strategy, typename Distance - > + > static inline RangeIterator apply(Geometry const& geometry, RangeIterator first, RangeIterator last, @@ -111,7 +111,7 @@ public: typename Geometry, typename RangeIterator, typename Strategy - > + > static inline RangeIterator apply(Geometry const& geometry, RangeIterator first, RangeIterator last, diff --git a/boost/geometry/algorithms/detail/closest_feature/point_to_range.hpp b/boost/geometry/algorithms/detail/closest_feature/point_to_range.hpp index 8ca0b3a7b9..ed2efd6fce 100644 --- a/boost/geometry/algorithms/detail/closest_feature/point_to_range.hpp +++ b/boost/geometry/algorithms/detail/closest_feature/point_to_range.hpp @@ -189,7 +189,7 @@ private: it_min1 = it_back; it_min2 = first; } - } + } public: typedef typename std::pair<iterator_type, iterator_type> return_type; diff --git a/boost/geometry/algorithms/detail/closest_feature/range_to_range.hpp b/boost/geometry/algorithms/detail/closest_feature/range_to_range.hpp index 52b2495d12..be1729a86f 100644 --- a/boost/geometry/algorithms/detail/closest_feature/range_to_range.hpp +++ b/boost/geometry/algorithms/detail/closest_feature/range_to_range.hpp @@ -150,7 +150,7 @@ public: apply(rtree_first, rtree_last, queries_first, queries_last, strategy, rtree_min, qit_min, dist_min); - return std::make_pair(rtree_min, qit_min); + return std::make_pair(rtree_min, qit_min); } diff --git a/boost/geometry/algorithms/detail/closest_points/implementation.hpp b/boost/geometry/algorithms/detail/closest_points/implementation.hpp new file mode 100644 index 0000000000..4accfa21b1 --- /dev/null +++ b/boost/geometry/algorithms/detail/closest_points/implementation.hpp @@ -0,0 +1,28 @@ +// Boost.Geometry + +// Copyright (c) 2021, Oracle and/or its affiliates. + +// Contributed and/or modified by Vissarion Fysikopoulos, 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_CLOSEST_POINTS_IMPLEMENTATION_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_POINTS_IMPLEMENTATION_HPP + +#include <boost/geometry/algorithms/detail/distance/implementation.hpp> +#include <boost/geometry/algorithms/detail/closest_points/point_to_geometry.hpp> +#include <boost/geometry/algorithms/detail/closest_points/multipoint_to_geometry.hpp> +#include <boost/geometry/algorithms/detail/closest_points/linear_to_linear.hpp> +#include <boost/geometry/algorithms/detail/closest_points/linear_or_areal_to_areal.hpp> +//#include <boost/geometry/algorithms/detail/closest_points/linear_to_box.hpp> +//#include <boost/geometry/algorithms/detail/closest_points/geometry_to_segment_or_box.hpp> +#include <boost/geometry/algorithms/detail/closest_points/segment_to_segment.hpp> +//#include <boost/geometry/algorithms/detail/closest_points/segment_to_box.hpp> +//#include <boost/geometry/algorithms/detail/closest_points/box_to_box.hpp> + +#include <boost/geometry/strategies/closest_points/cartesian.hpp> +#include <boost/geometry/strategies/closest_points/geographic.hpp> +#include <boost/geometry/strategies/closest_points/spherical.hpp> + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_POINTS_IMPLEMENTATION_HPP diff --git a/boost/geometry/algorithms/detail/closest_points/interface.hpp b/boost/geometry/algorithms/detail/closest_points/interface.hpp new file mode 100644 index 0000000000..622c47ba7f --- /dev/null +++ b/boost/geometry/algorithms/detail/closest_points/interface.hpp @@ -0,0 +1,225 @@ +// Boost.Geometry + +// Copyright (c) 2021, Oracle and/or its affiliates. + +// Contributed and/or modified by Vissarion Fysikopoulos, 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_CLOSEST_POINTS_INTERFACE_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_POINTS_INTERFACE_HPP + +#include <boost/concept_check.hpp> + +#include <boost/geometry/algorithms/detail/throw_on_empty_input.hpp> +#include <boost/geometry/algorithms/detail/closest_points/utilities.hpp> + +#include <boost/geometry/algorithms/dispatch/closest_points.hpp> + +#include <boost/geometry/algorithms/detail/distance/interface.hpp> + +#include <boost/geometry/core/point_type.hpp> + +#include <boost/geometry/geometries/adapted/boost_variant.hpp> // For backward compatibility +#include <boost/geometry/geometries/concepts/check.hpp> + +#include <boost/geometry/strategies/default_strategy.hpp> +#include <boost/geometry/strategies/detail.hpp> +#include <boost/geometry/strategies/closest_points/services.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +// If reversal is needed, perform it + +template +< + typename Geometry1, + typename Geometry2, + typename Tag1, + typename Tag2 +> +struct closest_points +< + Geometry1, Geometry2, + Tag1, Tag2, true +> + : closest_points<Geometry2, Geometry1, Tag2, Tag1, false> +{ + template <typename Segment, typename Strategy> + static inline void apply(Geometry1 const& g1, Geometry2 const& g2, + Segment& shortest_seg, Strategy const& strategy) + { + closest_points + < + Geometry2, Geometry1, Tag2, Tag1, false + >::apply(g2, g1, shortest_seg, strategy); + + detail::closest_points::swap_segment_points::apply(shortest_seg); + } +}; + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +namespace resolve_strategy +{ + +template<typename Strategy> +struct closest_points +{ + template <typename Geometry1, typename Geometry2, typename Segment> + static inline void apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Segment& shortest_seg, + Strategy const& strategy) + { + dispatch::closest_points + < + Geometry1, Geometry2 + >::apply(geometry1, geometry2, shortest_seg, strategy); + } +}; + +template <> +struct closest_points<default_strategy> +{ + template <typename Geometry1, typename Geometry2, typename Segment> + static inline void + apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Segment& shortest_seg, + default_strategy) + { + using strategy_type = typename strategies::closest_points::services::default_strategy + < + Geometry1, Geometry2 + >::type; + + dispatch::closest_points + < + Geometry1, Geometry2 + >::apply(geometry1, geometry2, shortest_seg, strategy_type()); + } +}; + +} // namespace resolve_strategy + + +namespace resolve_variant +{ + + +template <typename Geometry1, typename Geometry2> +struct closest_points +{ + template <typename Segment, typename Strategy> + static inline void apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Segment& shortest_seg, + Strategy const& strategy) + { + resolve_strategy::closest_points + < + Strategy + >::apply(geometry1, geometry2, shortest_seg, strategy); + } +}; + +//TODO: Add support for DG/GC + +} // namespace resolve_variant + + +/*! +\brief Calculate the closest points between two geometries \brief_strategy +\ingroup closest_points +\details +\details The free function closest_points calculates the distance between two geometries \brief_strategy. \details_strategy_reasons +\tparam Geometry1 \tparam_geometry +\tparam Geometry2 \tparam_geometry +\tparam Segment Any type fulfilling a Segment Concept +\tparam Strategy \tparam_strategy{Closest Points} +\param geometry1 \param_geometry +\param geometry2 \param_geometry +\param shortest_seg Output segment containing the closest points +\param strategy \param_strategy{closest_points} +\note The strategy can be a point-point strategy. In case of distance point-line/point-polygon + it may also be a point-segment strategy. + +\qbk{distinguish,with strategy} + +\qbk{ + +[heading Example] +[closest_points_strategy] +[closest_points_strategy_output] + +[heading See also] +\* [link geometry.reference.algorithms.distance distance] +} +*/ + +template <typename Geometry1, typename Geometry2, typename Segment, typename Strategy> +inline void closest_points(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Segment& shortest_seg, + Strategy const& strategy) +{ + concepts::check<Geometry1 const>(); + concepts::check<Geometry2 const>(); + + detail::throw_on_empty_input(geometry1); + detail::throw_on_empty_input(geometry2); + + resolve_variant::closest_points + < + Geometry1, + Geometry2 + >::apply(geometry1, geometry2, shortest_seg, strategy); +} + + +/*! +\brief Compute the closest points between two geometries. +\ingroup closest_points +\details The free function closest_points calculates the closest points between two geometries. \details_default_strategy +\tparam Geometry1 \tparam_geometry +\tparam Geometry2 \tparam_geometry +\tparam Segment Any type fulfilling a Segment Concept +\param geometry1 \param_geometry +\param geometry2 \param_geometry +\param shortest_seg Output segment containing the closest points + +\qbk{ + +[heading Example] +[closest_points] +[closest_points_output] + +[heading See also] +\* [link geometry.reference.algorithms.distance distance] +} +*/ + +template <typename Geometry1, typename Geometry2, typename Segment> +inline void closest_points(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Segment& shortest_seg) +{ + closest_points(geometry1, geometry2, shortest_seg, default_strategy()); +} + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_POINTS_INTERFACE_HPP diff --git a/boost/geometry/algorithms/detail/closest_points/linear_or_areal_to_areal.hpp b/boost/geometry/algorithms/detail/closest_points/linear_or_areal_to_areal.hpp new file mode 100644 index 0000000000..6d643e1aca --- /dev/null +++ b/boost/geometry/algorithms/detail/closest_points/linear_or_areal_to_areal.hpp @@ -0,0 +1,261 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2021, Oracle and/or its affiliates. + +// Contributed and/or modified by Vissarion Fysikopoulos, 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_CLOSEST_POINTS_LINEAR_OR_AREAL_TO_AREAL_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_POINTS_LINEAR_OR_AREAL_TO_AREAL_HPP + +#include <boost/geometry/algorithms/detail/closest_points/linear_to_linear.hpp> +#include <boost/geometry/algorithms/detail/closest_points/utilities.hpp> + +#include <boost/geometry/algorithms/intersection.hpp> + +#include <boost/geometry/core/point_type.hpp> + +#include <boost/geometry/geometries/geometries.hpp> + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace closest_points +{ + +struct linear_to_areal +{ + template <typename Linear, typename Areal, typename Segment, typename Strategies> + static inline void apply(Linear const& linear, + Areal const& areal, + Segment& shortest_seg, + Strategies const& strategies) + { + using most_precise_type = typename select_coordinate_type<Linear, Areal>::type; + + using point_type = typename std::conditional + < + std::is_same<typename coordinate_type<Linear>::type, most_precise_type>::value, + typename point_type<Linear>::type, + typename point_type<Areal>::type + >::type; + + using linestring_type = geometry::model::linestring<point_type>; + + /* TODO: currently intersection does not support some cases of tupled input + * such as linestring - multipolygon + * this could be implemented directly with dynamic geometries + using polygon_type = geometry::model::polygon<point_type>; + std::tuple + < + geometry::model::multi_point<point_type>, + geometry::model::multi_linestring<linestring_type>, + geometry::model::multi_polygon<polygon_type> + > tp; + bool intersect_tp = geometry::intersection(linear, areal, tp, strategies); + */ + + geometry::model::multi_point<point_type> mp_out; + geometry::intersection(linear, areal, mp_out, strategies); + + if (! boost::empty(mp_out)) + { + set_segment_from_points::apply(*boost::begin(mp_out), + *boost::begin(mp_out), + shortest_seg); + return; + } + + // if there are no intersection points then check if the linear geometry + // (or part of it) is inside the areal and return any point of this part + geometry::model::multi_linestring<linestring_type> ln_out; + geometry::intersection(linear, areal, ln_out, strategies); + + if (! boost::empty(ln_out)) + { + set_segment_from_points::apply(*boost::begin(*boost::begin(ln_out)), + *boost::begin(*boost::begin(ln_out)), + shortest_seg); + return; + } + + linear_to_linear::apply(linear, areal, shortest_seg, strategies, false); + } +}; + +struct areal_to_linear +{ + template <typename Linear, typename Areal, typename Segment, typename Strategies> + static inline void apply(Areal const& areal, + Linear const& linear, + Segment& shortest_seg, + Strategies const& strategies) + { + linear_to_areal::apply(linear, areal, shortest_seg, strategies); + detail::closest_points::swap_segment_points::apply(shortest_seg); + } +}; + +struct segment_to_areal +{ + template <typename Segment, typename Areal, typename OutSegment, typename Strategies> + static inline void apply(Segment const& segment, + Areal const& areal, + OutSegment& shortest_seg, + Strategies const& strategies, + bool = false) + { + using linestring_type = geometry::model::linestring<typename point_type<Segment>::type>; + linestring_type linestring; + convert(segment, linestring); + linear_to_areal::apply(linestring, areal, shortest_seg, strategies); + } +}; + +struct areal_to_segment +{ + template <typename Areal, typename Segment, typename OutSegment, typename Strategies> + static inline void apply(Areal const& areal, + Segment const& segment, + OutSegment& shortest_seg, + Strategies const& strategies, + bool = false) + { + segment_to_areal::apply(segment, areal, shortest_seg, strategies); + detail::closest_points::swap_segment_points::apply(shortest_seg); + } +}; + +struct areal_to_areal +{ + template <typename Areal1, typename Areal2, typename Segment, typename Strategies> + static inline void apply(Areal1 const& areal1, + Areal2 const& areal2, + Segment& shortest_seg, + Strategies const& strategies) + { + using most_precise_type = typename select_coordinate_type<Areal1, Areal2>::type; + + using point_type = typename std::conditional + < + std::is_same<typename coordinate_type<Areal1>::type, most_precise_type>::value, + typename point_type<Areal1>::type, + typename point_type<Areal2>::type + >::type; + + using linestring_type = geometry::model::linestring<point_type>; + using polygon_type = geometry::model::polygon<point_type>; + + /* TODO: currently intersection does not support tupled input + * this should be implemented directly with dynamic geometries + */ + + geometry::model::multi_point<point_type> mp_out; + geometry::intersection(areal1, areal2, mp_out, strategies); + + if (! boost::empty(mp_out)) + { + set_segment_from_points::apply(*boost::begin(mp_out), + *boost::begin(mp_out), + shortest_seg); + return; + } + + // if there are no intersection points then the linear geometry (or part of it) + // is inside the areal; return any point of this part + geometry::model::multi_linestring<linestring_type> ln_out; + geometry::intersection(areal1, areal2, ln_out, strategies); + + if (! boost::empty(ln_out)) + { + set_segment_from_points::apply(*boost::begin(*boost::begin(ln_out)), + *boost::begin(*boost::begin(ln_out)), + shortest_seg); + return; + } + + geometry::model::multi_polygon<polygon_type> pl_out; + geometry::intersection(areal1, areal2, pl_out, strategies); + + if (! boost::empty(pl_out)) + { + set_segment_from_points::apply( + *boost::begin(boost::geometry::exterior_ring(*boost::begin(pl_out))), + *boost::begin(boost::geometry::exterior_ring(*boost::begin(pl_out))), + shortest_seg); + return; + } + + linear_to_linear::apply(areal1, areal2, shortest_seg, strategies, false); + } +}; + + +}} // namespace detail::closest_points +#endif // DOXYGEN_NO_DETAIL + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + +template <typename Linear, typename Areal> +struct closest_points + < + Linear, Areal, + linear_tag, areal_tag, + false + > + : detail::closest_points::linear_to_areal +{}; + +template <typename Areal, typename Linear> +struct closest_points + < + Areal, Linear, + areal_tag, linear_tag, + false + > + : detail::closest_points::areal_to_linear +{}; + +template <typename Segment, typename Areal> +struct closest_points + < + Segment, Areal, + segment_tag, areal_tag, + false + > + : detail::closest_points::segment_to_areal +{}; + +template <typename Areal, typename Segment> +struct closest_points + < + Areal, Segment, + areal_tag, segment_tag, + false + > + : detail::closest_points::areal_to_segment +{}; + +template <typename Areal1, typename Areal2> +struct closest_points + < + Areal1, Areal2, + areal_tag, areal_tag, + false + > + : detail::closest_points::areal_to_areal +{}; + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_POINTS_LINEAR_OR_AREAL_TO_AREAL_HPP diff --git a/boost/geometry/algorithms/detail/closest_points/linear_to_linear.hpp b/boost/geometry/algorithms/detail/closest_points/linear_to_linear.hpp new file mode 100644 index 0000000000..d2927a6d39 --- /dev/null +++ b/boost/geometry/algorithms/detail/closest_points/linear_to_linear.hpp @@ -0,0 +1,155 @@ +// Boost.Geometry + +// Copyright (c) 2021, Oracle and/or its affiliates. + +// Contributed and/or modified by Vissarion Fysikopoulos, 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_CLOSEST_POINTS_LINEAR_TO_LINEAR_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_POINTS_LINEAR_TO_LINEAR_HPP + +#include <boost/geometry/algorithms/detail/closest_points/range_to_geometry_rtree.hpp> +#include <boost/geometry/algorithms/detail/closest_points/utilities.hpp> + +#include <boost/geometry/algorithms/num_points.hpp> +#include <boost/geometry/algorithms/num_segments.hpp> + +#include <boost/geometry/core/point_type.hpp> + +#include <boost/geometry/iterators/point_iterator.hpp> +#include <boost/geometry/iterators/segment_iterator.hpp> + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace closest_points +{ + + +struct linear_to_linear +{ + template <typename Linear1, typename Linear2, typename Segment, typename Strategies> + static inline void apply(Linear1 const& linear1, + Linear2 const& linear2, + Segment& shortest_seg, + Strategies const& strategies, + bool = false) + { + if (geometry::num_points(linear1) == 1) + { + dispatch::closest_points + < + typename point_type<Linear1>::type, + Linear2 + >::apply(*points_begin(linear1), linear2, shortest_seg, strategies); + return; + } + + if (geometry::num_points(linear2) == 1) + { + dispatch::closest_points + < + typename point_type<Linear2>::type, + Linear1 + >::apply(*points_begin(linear2), linear1, shortest_seg, strategies); + detail::closest_points::swap_segment_points::apply(shortest_seg); + return; + } + + if (geometry::num_segments(linear1) < geometry::num_segments(linear2)) + { + point_or_segment_range_to_geometry_rtree::apply( + geometry::segments_begin(linear2), + geometry::segments_end(linear2), + linear1, + shortest_seg, + strategies); + detail::closest_points::swap_segment_points::apply(shortest_seg); + return; + } + + point_or_segment_range_to_geometry_rtree::apply( + geometry::segments_begin(linear1), + geometry::segments_end(linear1), + linear2, + shortest_seg, + strategies); + } +}; + +struct segment_to_linear +{ + template <typename Segment, typename Linear, typename OutSegment, typename Strategies> + static inline void apply(Segment const& segment, + Linear const& linear, + OutSegment& shortest_seg, + Strategies const& strategies, + bool = false) + { + using linestring_type = geometry::model::linestring + <typename point_type<Segment>::type>; + linestring_type linestring; + convert(segment, linestring); + linear_to_linear::apply(linestring, linear, shortest_seg, strategies); + } +}; + +struct linear_to_segment +{ + template <typename Linear, typename Segment, typename OutSegment, typename Strategies> + static inline void apply(Linear const& linear, + Segment const& segment, + OutSegment& shortest_seg, + Strategies const& strategies, + bool = false) + { + segment_to_linear::apply(segment, linear, shortest_seg, strategies); + detail::closest_points::swap_segment_points::apply(shortest_seg); + } +}; + +}} // namespace detail::closest_points +#endif // DOXYGEN_NO_DETAIL + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + +template <typename Linear1, typename Linear2> +struct closest_points + < + Linear1, Linear2, + linear_tag, linear_tag, + false + > : detail::closest_points::linear_to_linear +{}; + +template <typename Segment, typename Linear> +struct closest_points + < + Segment, Linear, + segment_tag, linear_tag, + false + > : detail::closest_points::segment_to_linear +{}; + +template <typename Linear, typename Segment> +struct closest_points + < + Linear, Segment, + linear_tag, segment_tag, + false + > : detail::closest_points::linear_to_segment +{}; + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_POINTS_LINEAR_TO_LINEAR_HPP diff --git a/boost/geometry/algorithms/detail/closest_points/multipoint_to_geometry.hpp b/boost/geometry/algorithms/detail/closest_points/multipoint_to_geometry.hpp new file mode 100644 index 0000000000..f59c85a9b5 --- /dev/null +++ b/boost/geometry/algorithms/detail/closest_points/multipoint_to_geometry.hpp @@ -0,0 +1,325 @@ +// Boost.Geometry + +// Copyright (c) 2021, Oracle and/or its affiliates. + +// Contributed and/or modified by Vissarion Fysikopoulos, 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_CLOSEST_POINTS_MULTIPOINT_TO_GEOMETRY_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_POINTS_MULTIPOINT_TO_GEOMETRY_HPP + +#include <iterator> + +#include <boost/geometry/algorithms/covered_by.hpp> +#include <boost/geometry/algorithms/detail/closest_points/range_to_geometry_rtree.hpp> +#include <boost/geometry/algorithms/detail/closest_points/utilities.hpp> +#include <boost/geometry/algorithms/dispatch/closest_points.hpp> + +#include <boost/geometry/core/point_type.hpp> +#include <boost/geometry/core/tags.hpp> + +#include <boost/geometry/geometries/linestring.hpp> + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace closest_points +{ + + +struct multipoint_to_multipoint +{ + template + < + typename MultiPoint1, + typename MultiPoint2, + typename Segment, + typename Strategies + > + static inline void apply(MultiPoint1 const& multipoint1, + MultiPoint2 const& multipoint2, + Segment& shortest_seg, + Strategies const& strategies) + { + if (boost::size(multipoint1) < boost::size(multipoint2)) + { + point_or_segment_range_to_geometry_rtree::apply( + boost::begin(multipoint2), + boost::end(multipoint2), + multipoint1, + shortest_seg, + strategies); + detail::closest_points::swap_segment_points::apply(shortest_seg); + return; + } + point_or_segment_range_to_geometry_rtree::apply( + boost::begin(multipoint1), + boost::end(multipoint1), + multipoint2, + shortest_seg, + strategies); + } +}; + +struct multipoint_to_linear +{ + template + < + typename MultiPoint, + typename Linear, + typename Segment, + typename Strategies + > + static inline void apply(MultiPoint const& multipoint, + Linear const& linear, + Segment& shortest_seg, + Strategies const& strategies) + { + point_or_segment_range_to_geometry_rtree::apply( + boost::begin(multipoint), + boost::end(multipoint), + linear, + shortest_seg, + strategies); + } +}; + +struct linear_to_multipoint +{ + template + < + typename Linear, + typename MultiPoint, + typename Segment, + typename Strategies + > + static inline void apply(Linear const& linear, + MultiPoint const& multipoint, + Segment& shortest_seg, + Strategies const& strategies) + { + multipoint_to_linear::apply(multipoint, linear, shortest_seg, strategies); + detail::closest_points::swap_segment_points::apply(shortest_seg); + } +}; + +struct segment_to_multipoint +{ + template + < + typename Segment, + typename MultiPoint, + typename OutSegment, + typename Strategies + > + static inline void apply(Segment const& segment, + MultiPoint const& multipoint, + OutSegment& shortest_seg, + Strategies const& strategies) + { + using linestring_type = geometry::model::linestring + < + typename point_type<Segment>::type + >; + linestring_type linestring; + convert(segment, linestring); + multipoint_to_linear::apply(multipoint, linestring, shortest_seg, strategies); + detail::closest_points::swap_segment_points::apply(shortest_seg); + } +}; + +struct multipoint_to_segment +{ + template + < + typename MultiPoint, + typename Segment, + typename OutSegment, + typename Strategies + > + static inline void apply(MultiPoint const& multipoint, + Segment const& segment, + OutSegment& shortest_seg, + Strategies const& strategies) + { + using linestring_type = geometry::model::linestring + < + typename point_type<Segment>::type + >; + linestring_type linestring; + convert(segment, linestring); + multipoint_to_linear::apply(multipoint, linestring, shortest_seg, + strategies); + } +}; + + +struct multipoint_to_areal +{ + +private: + + template <typename Areal, typename Strategies> + struct covered_by_areal + { + covered_by_areal(Areal const& areal, Strategies const& strategy) + : m_areal(areal), m_strategy(strategy) + {} + + template <typename Point> + inline bool operator()(Point const& point) const + { + return geometry::covered_by(point, m_areal, m_strategy); + } + + Areal const& m_areal; + Strategies const& m_strategy; + }; + +public: + + template + < + typename MultiPoint, + typename Areal, + typename Segment, + typename Strategies + > + static inline void apply(MultiPoint const& multipoint, + Areal const& areal, + Segment& shortest_seg, + Strategies const& strategies) + { + covered_by_areal<Areal, Strategies> predicate(areal, strategies); + + auto it = std::find_if( + boost::begin(multipoint), + boost::end(multipoint), + predicate); + + if (it != boost::end(multipoint)) + { + return set_segment_from_points::apply(*it, *it, shortest_seg); + + } + + point_or_segment_range_to_geometry_rtree::apply( + boost::begin(multipoint), + boost::end(multipoint), + areal, + shortest_seg, + strategies); + } +}; + +struct areal_to_multipoint +{ + template + < + typename Areal, + typename MultiPoint, + typename Segment, + typename Strategies + > + static inline void apply(Areal const& areal, + MultiPoint const& multipoint, + Segment& shortest_seg, + Strategies const& strategies) + { + multipoint_to_areal::apply(multipoint, areal, shortest_seg, strategies); + detail::closest_points::swap_segment_points::apply(shortest_seg); + } +}; + +}} // namespace detail::closest_points +#endif // DOXYGEN_NO_DETAIL + + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +template <typename MultiPoint1, typename MultiPoint2> +struct closest_points + < + MultiPoint1, MultiPoint2, + multi_point_tag, multi_point_tag, + false + > : detail::closest_points::multipoint_to_multipoint +{}; + + +template <typename MultiPoint, typename Linear> +struct closest_points + < + MultiPoint, Linear, + multi_point_tag, linear_tag, + false + > : detail::closest_points::multipoint_to_linear +{}; + + +template <typename Linear, typename MultiPoint> +struct closest_points + < + Linear, MultiPoint, + linear_tag, multi_point_tag, + false + > : detail::closest_points::linear_to_multipoint +{}; + + +template <typename MultiPoint, typename Segment> +struct closest_points + < + MultiPoint, Segment, + multi_point_tag, segment_tag, + false + > : detail::closest_points::multipoint_to_segment +{}; + + +template <typename Segment, typename MultiPoint> +struct closest_points + < + Segment, MultiPoint, + segment_tag, multi_point_tag, + false + > : detail::closest_points::segment_to_multipoint +{}; + + +template <typename MultiPoint, typename Areal> +struct closest_points + < + MultiPoint, Areal, + multi_point_tag, areal_tag, + false + > : detail::closest_points::multipoint_to_areal +{}; + + +template <typename Areal, typename MultiPoint> +struct closest_points + < + Areal, MultiPoint, + areal_tag, multi_point_tag, + false + > : detail::closest_points::areal_to_multipoint +{}; + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_POINTS_MULTIPOINT_TO_GEOMETRY_HPP diff --git a/boost/geometry/algorithms/detail/closest_points/point_to_geometry.hpp b/boost/geometry/algorithms/detail/closest_points/point_to_geometry.hpp new file mode 100644 index 0000000000..5771858518 --- /dev/null +++ b/boost/geometry/algorithms/detail/closest_points/point_to_geometry.hpp @@ -0,0 +1,456 @@ +// Boost.Geometry + +// Copyright (c) 2021-2023, Oracle and/or its affiliates. + +// Contributed and/or modified by Vissarion Fysikopoulos, 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_CLOSEST_POINTS_POINT_TO_GEOMETRY_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_POINTS_POINT_TO_GEOMETRY_HPP + +#include <iterator> +#include <type_traits> + +#include <boost/core/ignore_unused.hpp> +#include <boost/range/begin.hpp> +#include <boost/range/end.hpp> +#include <boost/range/size.hpp> +#include <boost/range/value_type.hpp> + +#include <boost/geometry/algorithms/assign.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/closest_points/utilities.hpp> +#include <boost/geometry/algorithms/detail/distance/is_comparable.hpp> +#include <boost/geometry/algorithms/detail/distance/iterator_selector.hpp> +#include <boost/geometry/algorithms/detail/distance/strategy_utils.hpp> +#include <boost/geometry/algorithms/detail/within/point_in_geometry.hpp> +#include <boost/geometry/algorithms/dispatch/closest_points.hpp> +#include <boost/geometry/algorithms/dispatch/distance.hpp> + +#include <boost/geometry/core/closure.hpp> +#include <boost/geometry/core/point_type.hpp> +#include <boost/geometry/core/exterior_ring.hpp> +#include <boost/geometry/core/interior_rings.hpp> +#include <boost/geometry/core/radian_access.hpp> +#include <boost/geometry/core/tag.hpp> +#include <boost/geometry/core/tags.hpp> + +#include <boost/geometry/strategies/distance.hpp> +#include <boost/geometry/strategies/relate/services.hpp> +#include <boost/geometry/strategies/tags.hpp> + +#include <boost/geometry/util/math.hpp> + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace closest_points +{ + +struct point_to_point +{ + template <typename P1, typename P2, typename Segment, typename Strategies> + static inline void apply(P1 const& p1, P2 const& p2, + Segment& shortest_seg, Strategies const&) + { + set_segment_from_points::apply(p1, p2, shortest_seg); + } +}; + +struct point_to_segment +{ + template <typename Point, typename Segment, typename OutputSegment, typename Strategies> + static inline void apply(Point const& point, Segment const& segment, + OutputSegment& shortest_seg, Strategies const& strategies) + { + typename point_type<Segment>::type p[2]; + geometry::detail::assign_point_from_index<0>(segment, p[0]); + geometry::detail::assign_point_from_index<1>(segment, p[1]); + + boost::ignore_unused(strategies); + + auto closest_point = strategies.closest_points(point, segment) + .apply(point, p[0], p[1]); + + set_segment_from_points::apply(point, closest_point, shortest_seg); + } +}; + +/* +struct point_to_box +{ + template<typename Point, typename Box, typename Strategies> +static inline auto apply(Point const& point, Box const& box, + Strategies const& strategies) + { + boost::ignore_unused(strategies); + return strategies.closest_points(point, box).apply(point, box); + } +}; +*/ + +template <closure_selector Closure> +class point_to_range +{ +public: + + template <typename Point, typename Range, typename Segment, typename Strategies> + static inline void apply(Point const& point, Range const& range, + Segment& shortest_seg, + Strategies const& strategies) + { + using point_to_point_range = detail::closest_feature::point_to_point_range + < + Point, Range, Closure + >; + + if (boost::size(range) == 0) + { + set_segment_from_points::apply(point, point, shortest_seg); + return; + } + + closest_points::creturn_t<Point, Range, Strategies> cd_min; + + auto comparable_distance = strategy::distance::services::get_comparable + < + decltype(strategies.distance(point, range)) + >::apply(strategies.distance(point, range)); + + auto closest_segment = point_to_point_range::apply(point, + boost::begin(range), + boost::end(range), + comparable_distance, + cd_min); + + auto closest_point = strategies.closest_points(point, range) + .apply(point, *closest_segment.first, *closest_segment.second); + + set_segment_from_points::apply(point, closest_point, shortest_seg); + } +}; + + +template<closure_selector Closure> +struct point_to_ring +{ + template <typename Point, typename Ring, typename Segment, typename Strategies> + static inline auto apply(Point const& point, + Ring const& ring, + Segment& shortest_seg, + Strategies const& strategies) + { + if (within::within_point_geometry(point, ring, strategies)) + { + set_segment_from_points::apply(point, point, shortest_seg); + } + else + { + point_to_range + < + closure<Ring>::value + >::apply(point, ring, shortest_seg, strategies); + } + + } +}; + + +template <closure_selector Closure> +class point_to_polygon +{ + template <typename Polygon> + struct distance_to_interior_rings + { + template + < + typename Point, + typename InteriorRingIterator, + typename Segment, + typename Strategies + > + static inline void apply(Point const& point, + InteriorRingIterator first, + InteriorRingIterator last, + Segment& shortest_seg, + Strategies const& strategies) + { + using per_ring = point_to_range<Closure>; + + for (InteriorRingIterator it = first; it != last; ++it) + { + if (within::within_point_geometry(point, *it, strategies)) + { + // the point is inside a polygon hole, so its distance + // to the polygon is its distance to the polygon's + // hole boundary + per_ring::apply(point, *it, shortest_seg, strategies); + return; + } + } + set_segment_from_points::apply(point, point, shortest_seg); + } + + template + < + typename Point, + typename InteriorRings, + typename Segment, + typename Strategies + > + static inline void apply(Point const& point, InteriorRings const& interior_rings, + Segment& shortest_seg, Strategies const& strategies) + { + apply(point, + boost::begin(interior_rings), + boost::end(interior_rings), + shortest_seg, + strategies); + } + }; + + +public: + template + < + typename Point, + typename Polygon, + typename Segment, + typename Strategies + > + static inline void apply(Point const& point, + Polygon const& polygon, + Segment& shortest_seg, + Strategies const& strategies) + { + using per_ring = point_to_range<Closure>; + + if (! within::covered_by_point_geometry(point, exterior_ring(polygon), + strategies)) + { + // the point is outside the exterior ring, so its distance + // to the polygon is its distance to the polygon's exterior ring + per_ring::apply(point, exterior_ring(polygon), shortest_seg, strategies); + return; + } + + // Check interior rings + distance_to_interior_rings<Polygon>::apply(point, + interior_rings(polygon), + shortest_seg, + strategies); + } +}; + + +template +< + typename MultiGeometry, + bool CheckCoveredBy = std::is_same + < + typename tag<MultiGeometry>::type, multi_polygon_tag + >::value +> +class point_to_multigeometry +{ +private: + using geometry_to_range = detail::closest_feature::geometry_to_range; + +public: + + template + < + typename Point, + typename Segment, + typename Strategies + > + static inline void apply(Point const& point, + MultiGeometry const& multigeometry, + Segment& shortest_seg, + Strategies const& strategies) + { + using selector_type = distance::iterator_selector<MultiGeometry const>; + + closest_points::creturn_t<Point, MultiGeometry, Strategies> cd; + + auto comparable_distance = strategy::distance::services::get_comparable + < + decltype(strategies.distance(point, multigeometry)) + >::apply(strategies.distance(point, multigeometry)); + + typename selector_type::iterator_type it_min + = geometry_to_range::apply(point, + selector_type::begin(multigeometry), + selector_type::end(multigeometry), + comparable_distance, + cd); + + dispatch::closest_points + < + Point, + typename std::iterator_traits + < + typename selector_type::iterator_type + >::value_type + >::apply(point, *it_min, shortest_seg, strategies); + } +}; + + +// this is called only for multipolygons, hence the change in the +// template parameter name MultiGeometry to MultiPolygon +template <typename MultiPolygon> +struct point_to_multigeometry<MultiPolygon, true> +{ + template + < + typename Point, + typename Segment, + typename Strategies + > + static inline void apply(Point const& point, + MultiPolygon const& multipolygon, + Segment& shortest_seg, + Strategies const& strategies) + { + if (within::covered_by_point_geometry(point, multipolygon, strategies)) + { + set_segment_from_points::apply(point, point, shortest_seg); + return; + } + + return point_to_multigeometry + < + MultiPolygon, false + >::apply(point, multipolygon, shortest_seg, strategies); + } +}; + + +}} // namespace detail::closest_points +#endif // DOXYGEN_NO_DETAIL + + + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +template <typename P1, typename P2> +struct closest_points + < + P1, P2, point_tag, point_tag, false + > : detail::closest_points::point_to_point +{}; + + +template <typename Point, typename Linestring> +struct closest_points + < + Point, Linestring, point_tag, linestring_tag, false + > : detail::closest_points::point_to_range<closed> +{}; + + +template <typename Point, typename Ring> +struct closest_points + < + Point, Ring, point_tag, ring_tag, false + > : detail::closest_points::point_to_ring + < + closure<Ring>::value + > +{}; + + +template <typename Point, typename Polygon> +struct closest_points + < + Point, Polygon, point_tag, polygon_tag, false + > : detail::closest_points::point_to_polygon + < + closure<Polygon>::value + > +{}; + + +template <typename Point, typename Segment> +struct closest_points + < + Point, Segment, point_tag, segment_tag, false + > : detail::closest_points::point_to_segment +{}; + +/* +template <typename Point, typename Box> +struct closest_points + < + Point, Box, point_tag, box_tag, + strategy_tag_distance_point_box, false + > : detail::closest_points::point_to_box<Point, Box> +{}; +*/ + +template<typename Point, typename MultiPoint> +struct closest_points + < + Point, MultiPoint, point_tag, multi_point_tag, false + > : detail::closest_points::point_to_multigeometry<MultiPoint> +{}; + + +template<typename Point, typename MultiLinestring> +struct closest_points + < + Point, MultiLinestring, point_tag, multi_linestring_tag, false + > : detail::closest_points::point_to_multigeometry<MultiLinestring> +{}; + + +template<typename Point, typename MultiPolygon> +struct closest_points + < + Point, MultiPolygon, point_tag, multi_polygon_tag, false + > : detail::closest_points::point_to_multigeometry<MultiPolygon> +{}; + + +template <typename Point, typename Linear> +struct closest_points + < + Point, Linear, point_tag, linear_tag, false + > : closest_points + < + Point, Linear, + point_tag, typename tag<Linear>::type, false + > +{}; + + +template <typename Point, typename Areal> +struct closest_points + < + Point, Areal, point_tag, areal_tag, false + > : closest_points + < + Point, Areal, + point_tag, typename tag<Areal>::type, false + > +{}; + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_POINTS_POINT_TO_GEOMETRY_HPP diff --git a/boost/geometry/algorithms/detail/closest_points/range_to_geometry_rtree.hpp b/boost/geometry/algorithms/detail/closest_points/range_to_geometry_rtree.hpp new file mode 100644 index 0000000000..1bb44b53cd --- /dev/null +++ b/boost/geometry/algorithms/detail/closest_points/range_to_geometry_rtree.hpp @@ -0,0 +1,110 @@ +// Boost.Geometry + +// Copyright (c) 2021-2023, Oracle and/or its affiliates. + +// Contributed and/or modified by Vissarion Fysikopoulos, 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_CLOSEST_POINTS_RANGE_TO_GEOMETRY_RTREE_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_POINTS_RANGE_TO_GEOMETRY_RTREE_HPP + +#include <iterator> +#include <utility> + +#include <boost/geometry/algorithms/detail/closest_feature/range_to_range.hpp> +#include <boost/geometry/algorithms/detail/closest_points/utilities.hpp> +#include <boost/geometry/algorithms/detail/distance/is_comparable.hpp> +#include <boost/geometry/algorithms/detail/distance/iterator_selector.hpp> +#include <boost/geometry/algorithms/detail/distance/strategy_utils.hpp> +#include <boost/geometry/algorithms/dispatch/closest_points.hpp> + +#include <boost/geometry/core/assert.hpp> +#include <boost/geometry/core/point_type.hpp> + +#include <boost/geometry/iterators/detail/has_one_element.hpp> + +#include <boost/geometry/strategies/distance.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace closest_points +{ + +class point_or_segment_range_to_geometry_rtree +{ +public: + + template + < + typename PointOrSegmentIterator, + typename Geometry, + typename Segment, + typename Strategies + > + static inline void apply(PointOrSegmentIterator first, + PointOrSegmentIterator last, + Geometry const& geometry, + Segment& shortest_seg, + Strategies const& strategies) + { + typedef typename std::iterator_traits + < + PointOrSegmentIterator + >::value_type point_or_segment_type; + + typedef distance::iterator_selector<Geometry const> selector_type; + + typedef detail::closest_feature::range_to_range_rtree range_to_range; + + BOOST_GEOMETRY_ASSERT( first != last ); + + //TODO: Is this special case needed? + //if ( detail::has_one_element(first, last) ) + //{ + // dispatch::closest_points + // < + // point_or_segment_type, Geometry + // >::apply(*first, geometry, shortest_seg, strategies); + //} + + closest_points::creturn_t<point_or_segment_type, Geometry, Strategies> cd; + + std::pair + < + point_or_segment_type, + typename selector_type::iterator_type + > closest_features + = range_to_range::apply(first, + last, + selector_type::begin(geometry), + selector_type::end(geometry), + strategies, + cd); + dispatch::closest_points + < + point_or_segment_type, + typename std::iterator_traits + < + typename selector_type::iterator_type + >::value_type + >::apply(closest_features.first, + *closest_features.second, + shortest_seg, + strategies); + } +}; + + +}} // namespace detail::closest_points +#endif // DOXYGEN_NO_DETAIL + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_POINTS_RANGE_TO_GEOMETRY_RTREE_HPP diff --git a/boost/geometry/algorithms/detail/closest_points/segment_to_segment.hpp b/boost/geometry/algorithms/detail/closest_points/segment_to_segment.hpp new file mode 100644 index 0000000000..15d28cd690 --- /dev/null +++ b/boost/geometry/algorithms/detail/closest_points/segment_to_segment.hpp @@ -0,0 +1,145 @@ +// Boost.Geometry + +// Copyright (c) 2021-2023, Oracle and/or its affiliates. + +// Contributed and/or modified by Vissarion Fysikopoulos, 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_CLOSEST_POINTS_SEGMENT_TO_SEGMENT_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_POINTS_SEGMENT_TO_SEGMENT_HPP + +#include <algorithm> +#include <iterator> + +#include <boost/core/addressof.hpp> + +#include <boost/geometry/algorithms/assign.hpp> +#include <boost/geometry/algorithms/detail/closest_points/utilities.hpp> +#include <boost/geometry/algorithms/detail/distance/is_comparable.hpp> +#include <boost/geometry/algorithms/detail/distance/strategy_utils.hpp> +#include <boost/geometry/algorithms/dispatch/closest_points.hpp> +#include <boost/geometry/algorithms/dispatch/distance.hpp> +#include <boost/geometry/algorithms/intersects.hpp> + +#include <boost/geometry/core/point_type.hpp> +#include <boost/geometry/core/tags.hpp> + +#include <boost/geometry/strategies/distance.hpp> +#include <boost/geometry/strategies/tags.hpp> + +#include <boost/geometry/util/condition.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace closest_points +{ + + + +// compute segment-segment closest-points +class segment_to_segment +{ +public: + + template <typename Segment1, typename Segment2, typename OutputSegment, typename Strategies> + static inline void apply(Segment1 const& segment1, Segment2 const& segment2, + OutputSegment& shortest_seg, + Strategies const& strategies) + { + using intersection_return_type = segment_intersection_points + < + typename point_type<Segment1>::type + >; + + using intersection_policy = policies::relate::segments_intersection_points + < + intersection_return_type + >; + + detail::segment_as_subrange<Segment1> sub_range1(segment1); + detail::segment_as_subrange<Segment2> sub_range2(segment2); + auto is = strategies.relate().apply(sub_range1, sub_range2, + intersection_policy()); + if (is.count > 0) + { + set_segment_from_points::apply(is.intersections[0], + is.intersections[0], + shortest_seg); + return; + } + + typename point_type<Segment1>::type p[2]; + detail::assign_point_from_index<0>(segment1, p[0]); + detail::assign_point_from_index<1>(segment1, p[1]); + + typename point_type<Segment2>::type q[2]; + detail::assign_point_from_index<0>(segment2, q[0]); + detail::assign_point_from_index<1>(segment2, q[1]); + + auto cp0 = strategies.closest_points(q[0], segment1).apply(q[0], p[0], p[1]); + auto cp1 = strategies.closest_points(q[1], segment1).apply(q[1], p[0], p[1]); + auto cp2 = strategies.closest_points(p[0], segment2).apply(p[0], q[0], q[1]); + auto cp3 = strategies.closest_points(p[1], segment2).apply(p[1], q[0], q[1]); + + closest_points::creturn_t<Segment1, Segment2, Strategies> d[4]; + + auto const cds = strategies::distance::detail::make_comparable(strategies) + .distance(detail::dummy_point(), detail::dummy_point()); + + d[0] = cds.apply(cp0, q[0]); + d[1] = cds.apply(cp1, q[1]); + d[2] = cds.apply(p[0], cp2); + d[3] = cds.apply(p[1], cp3); + + std::size_t imin = std::distance(boost::addressof(d[0]), std::min_element(d, d + 4)); + + switch (imin) + { + case 0: + set_segment_from_points::apply(cp0, q[0], shortest_seg); + return; + case 1: + set_segment_from_points::apply(cp1, q[1], shortest_seg); + return; + case 2: + set_segment_from_points::apply(p[0], cp2, shortest_seg); + return; + default: + set_segment_from_points::apply(p[1], cp3, shortest_seg); + return; + } + } +}; + + +}} // namespace detail::closest_points +#endif // DOXYGEN_NO_DETAIL + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +// segment-segment +template <typename Segment1, typename Segment2> +struct closest_points + < + Segment1, Segment2, segment_tag, segment_tag, false + > : detail::closest_points::segment_to_segment +{}; + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_POINTS_SEGMENT_TO_SEGMENT_HPP diff --git a/boost/geometry/algorithms/detail/closest_points/utilities.hpp b/boost/geometry/algorithms/detail/closest_points/utilities.hpp new file mode 100644 index 0000000000..858c86efb8 --- /dev/null +++ b/boost/geometry/algorithms/detail/closest_points/utilities.hpp @@ -0,0 +1,69 @@ +// Boost.Geometry + +// Copyright (c) 2021-2023, Oracle and/or its affiliates. + +// Contributed and/or modified by Vissarion Fysikopoulos, 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_CLOSEST_POINTS_UTILITIES_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_POINTS_UTILITIES_HPP + +#include <boost/geometry/algorithms/detail/assign_indexed_point.hpp> +#include <boost/geometry/util/algorithm.hpp> + +#include <boost/geometry/strategies/distance.hpp> + +namespace boost { namespace geometry +{ + +namespace detail { namespace closest_points +{ + +struct set_segment_from_points +{ + template <typename Point1, typename Point2, typename Segment> + static inline void apply(Point1 const& p1, Point2 const& p2, Segment& segment) + { + assign_point_to_index<0>(p1, segment); + assign_point_to_index<1>(p2, segment); + } +}; + + +struct swap_segment_points +{ + template <typename Segment> + static inline void apply(Segment& segment) + { + geometry::detail::for_each_dimension<Segment>([&](auto index) + { + auto temp = get<0,index>(segment); + set<0,index>(segment, get<1,index>(segment)); + set<1,index>(segment, temp); + }); + } +}; + +template <typename Geometry1, typename Geometry2, typename Strategies> +using distance_strategy_t = decltype( + std::declval<Strategies>().distance(std::declval<Geometry1>(), std::declval<Geometry2>())); + +template <typename Geometry1, typename Geometry2, typename Strategies> +using creturn_t = typename strategy::distance::services::return_type + < + typename strategy::distance::services::comparable_type + < + distance_strategy_t<Geometry1, Geometry2, Strategies> + >::type, + typename point_type<Geometry1>::type, + typename point_type<Geometry2>::type + >::type; + + +}} // namespace detail::closest_points + +}} // namespace boost::geometry + +#endif //BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_POINTS_UTILITIES_HPP diff --git a/boost/geometry/algorithms/detail/comparable_distance/interface.hpp b/boost/geometry/algorithms/detail/comparable_distance/interface.hpp index 14e2940d3b..d582dc9254 100644 --- a/boost/geometry/algorithms/detail/comparable_distance/interface.hpp +++ b/boost/geometry/algorithms/detail/comparable_distance/interface.hpp @@ -3,6 +3,7 @@ // Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2014 Bruno Lalande, Paris, France. // Copyright (c) 2009-2014 Mateusz Loskot, London, UK. +// Copyright (c) 2023 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2014-2021. // Modifications copyright (c) 2014-2021, Oracle and/or its affiliates. @@ -50,11 +51,9 @@ template struct comparable_distance { template <typename Geometry1, typename Geometry2> - static inline - typename comparable_distance_result<Geometry1, Geometry2, Strategies>::type - apply(Geometry1 const& geometry1, - Geometry2 const& geometry2, - Strategies const& strategies) + static inline auto apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Strategies const& strategies) { return dispatch::distance < @@ -70,21 +69,17 @@ template <typename Strategy> struct comparable_distance<Strategy, false> { template <typename Geometry1, typename Geometry2> - static inline - typename comparable_distance_result<Geometry1, Geometry2, Strategy>::type - apply(Geometry1 const& geometry1, - Geometry2 const& geometry2, - Strategy const& strategy) + static inline auto apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Strategy const& strategy) { using strategies::distance::services::strategy_converter; - typedef decltype(strategy_converter<Strategy>::get(strategy)) - strategies_type; - typedef strategies::distance::detail::comparable + using comparable_strategies_type = strategies::distance::detail::comparable < - strategies_type - > comparable_strategies_type; - + decltype(strategy_converter<Strategy>::get(strategy)) + >; + return dispatch::distance < Geometry1, Geometry2, @@ -100,21 +95,17 @@ template <> struct comparable_distance<default_strategy, false> { template <typename Geometry1, typename Geometry2> - static inline typename comparable_distance_result - < - Geometry1, Geometry2, default_strategy - >::type - apply(Geometry1 const& geometry1, - Geometry2 const& geometry2, - default_strategy) + static inline auto apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + default_strategy) { - typedef strategies::distance::detail::comparable + using comparable_strategy_type = strategies::distance::detail::comparable < typename strategies::distance::services::default_strategy < Geometry1, Geometry2 >::type - > comparable_strategy_type; + >; return dispatch::distance < @@ -126,19 +117,22 @@ struct comparable_distance<default_strategy, false> } // namespace resolve_strategy -namespace resolve_variant +namespace resolve_dynamic { -template <typename Geometry1, typename Geometry2> +template +< + typename Geometry1, typename Geometry2, + typename Tag1 = typename geometry::tag<Geometry1>::type, + typename Tag2 = typename geometry::tag<Geometry2>::type +> struct comparable_distance { template <typename Strategy> - static inline - typename comparable_distance_result<Geometry1, Geometry2, Strategy>::type - apply(Geometry1 const& geometry1, - Geometry2 const& geometry2, - Strategy const& strategy) + static inline auto apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Strategy const& strategy) { return resolve_strategy::comparable_distance < @@ -148,190 +142,85 @@ struct comparable_distance }; -template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2> -struct comparable_distance - < - boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, - Geometry2 - > +template <typename DynamicGeometry1, typename Geometry2, typename Tag2> +struct comparable_distance<DynamicGeometry1, Geometry2, dynamic_geometry_tag, Tag2> { template <typename Strategy> - struct visitor: static_visitor - < - typename comparable_distance_result - < - boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, - Geometry2, - Strategy - >::type - > + static inline auto apply(DynamicGeometry1 const& geometry1, + Geometry2 const& geometry2, + Strategy const& strategy) { - Geometry2 const& m_geometry2; - Strategy const& m_strategy; - - visitor(Geometry2 const& geometry2, - Strategy const& strategy) - : m_geometry2(geometry2), - m_strategy(strategy) - {} - - template <typename Geometry1> - typename comparable_distance_result + using result_t = typename geometry::comparable_distance_result < - Geometry1, Geometry2, Strategy - >::type - operator()(Geometry1 const& geometry1) const + DynamicGeometry1, Geometry2, Strategy + >::type; + result_t result = 0; + traits::visit<DynamicGeometry1>::apply([&](auto const& g1) { - return comparable_distance - < - Geometry1, - Geometry2 - >::template apply - < - Strategy - >(geometry1, m_geometry2, m_strategy); - } - }; - - template <typename Strategy> - static inline typename comparable_distance_result - < - boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, - Geometry2, - Strategy - >::type - apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1, - Geometry2 const& geometry2, - Strategy const& strategy) - { - return boost::apply_visitor(visitor<Strategy>(geometry2, strategy), geometry1); + result = resolve_strategy::comparable_distance + < + Strategy + >::apply(g1, geometry2, strategy); + }, geometry1); + return result; } }; -template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)> -struct comparable_distance - < - Geometry1, - boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> - > +template <typename Geometry1, typename DynamicGeometry2, typename Tag1> +struct comparable_distance<Geometry1, DynamicGeometry2, Tag1, dynamic_geometry_tag> { template <typename Strategy> - struct visitor: static_visitor - < - typename comparable_distance_result - < - Geometry1, - boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, - Strategy - >::type - > + static inline auto apply(Geometry1 const& geometry1, + DynamicGeometry2 const& geometry2, + Strategy const& strategy) { - Geometry1 const& m_geometry1; - Strategy const& m_strategy; - - visitor(Geometry1 const& geometry1, - Strategy const& strategy) - : m_geometry1(geometry1), - m_strategy(strategy) - {} - - template <typename Geometry2> - typename comparable_distance_result + using result_t = typename geometry::comparable_distance_result < - Geometry1, Geometry2, Strategy - >::type - operator()(Geometry2 const& geometry2) const + Geometry1, DynamicGeometry2, Strategy + >::type; + result_t result = 0; + traits::visit<DynamicGeometry2>::apply([&](auto const& g2) { - return comparable_distance - < - Geometry1, - Geometry2 - >::template apply - < - Strategy - >(m_geometry1, geometry2, m_strategy); - } - }; - - template <typename Strategy> - static inline typename comparable_distance_result - < - Geometry1, - boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, - Strategy - >::type - apply(Geometry1 const& geometry1, - boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2, - Strategy const& strategy) - { - return boost::apply_visitor(visitor<Strategy>(geometry1, strategy), geometry2); + result = resolve_strategy::comparable_distance + < + Strategy + >::apply(geometry1, g2, strategy); + }, geometry2); + return result; } }; -template -< - BOOST_VARIANT_ENUM_PARAMS(typename T1), - BOOST_VARIANT_ENUM_PARAMS(typename T2) -> +template <typename DynamicGeometry1, typename DynamicGeometry2> struct comparable_distance < - boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>, - boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> + DynamicGeometry1, DynamicGeometry2, + dynamic_geometry_tag, dynamic_geometry_tag > { template <typename Strategy> - struct visitor: static_visitor - < - typename comparable_distance_result - < - boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>, - boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)>, - Strategy - >::type - > + static inline auto apply(DynamicGeometry1 const& geometry1, + DynamicGeometry2 const& geometry2, + Strategy const& strategy) { - Strategy const& m_strategy; - - visitor(Strategy const& strategy) - : m_strategy(strategy) - {} - - template <typename Geometry1, typename Geometry2> - typename comparable_distance_result + using result_t = typename geometry::comparable_distance_result < - Geometry1, Geometry2, Strategy - >::type - operator()(Geometry1 const& geometry1, Geometry2 const& geometry2) const + DynamicGeometry1, DynamicGeometry2, Strategy + >::type; + result_t result = 0; + traits::visit<DynamicGeometry1, DynamicGeometry2>::apply([&](auto const& g1, auto const& g2) { - return comparable_distance - < - Geometry1, - Geometry2 - >::template apply - < - Strategy - >(geometry1, geometry2, m_strategy); - } - }; - - template <typename Strategy> - static inline typename comparable_distance_result - < - boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>, - boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)>, - Strategy - >::type - apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1, - boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2, - Strategy const& strategy) - { - return boost::apply_visitor(visitor<Strategy>(strategy), geometry1, geometry2); + result = resolve_strategy::comparable_distance + < + Strategy + >::apply(g1, g2, strategy); + }, geometry1, geometry2); + return result; } }; -} // namespace resolve_variant +} // namespace resolve_dynamic @@ -354,14 +243,14 @@ struct comparable_distance \qbk{distinguish,with strategy} */ template <typename Geometry1, typename Geometry2, typename Strategy> -inline typename comparable_distance_result<Geometry1, Geometry2, Strategy>::type -comparable_distance(Geometry1 const& geometry1, Geometry2 const& geometry2, - Strategy const& strategy) +inline auto comparable_distance(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Strategy const& strategy) { concepts::check<Geometry1 const>(); concepts::check<Geometry2 const>(); - return resolve_variant::comparable_distance + return resolve_dynamic::comparable_distance < Geometry1, Geometry2 @@ -387,12 +276,9 @@ comparable_distance(Geometry1 const& geometry1, Geometry2 const& geometry2, \qbk{[include reference/algorithms/comparable_distance.qbk]} */ template <typename Geometry1, typename Geometry2> -inline typename default_comparable_distance_result<Geometry1, Geometry2>::type -comparable_distance(Geometry1 const& geometry1, Geometry2 const& geometry2) +inline auto comparable_distance(Geometry1 const& geometry1, + Geometry2 const& geometry2) { - concepts::check<Geometry1 const>(); - concepts::check<Geometry2 const>(); - return geometry::comparable_distance(geometry1, geometry2, default_strategy()); } diff --git a/boost/geometry/algorithms/detail/convert_point_to_point.hpp b/boost/geometry/algorithms/detail/convert_point_to_point.hpp index c7d37b6ca4..8762cd6687 100644 --- a/boost/geometry/algorithms/detail/convert_point_to_point.hpp +++ b/boost/geometry/algorithms/detail/convert_point_to_point.hpp @@ -32,6 +32,12 @@ namespace detail { namespace conversion { +// TODO: Use assignment if possible. +// WARNING: This utility is called in various places for a subset of dimensions. +// In such cases only some of the coordinates should be copied. Alternatively +// there should be a different utility for that called differently than +// convert_xxx, e.g. set_coordinates. + template <typename Source, typename Destination, std::size_t Dimension, std::size_t DimensionCount> struct point_to_point { diff --git a/boost/geometry/algorithms/detail/convex_hull/graham_andrew.hpp b/boost/geometry/algorithms/detail/convex_hull/graham_andrew.hpp index 9584f6a2f1..64d81054e8 100644 --- a/boost/geometry/algorithms/detail/convex_hull/graham_andrew.hpp +++ b/boost/geometry/algorithms/detail/convex_hull/graham_andrew.hpp @@ -2,8 +2,8 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. -// This file was modified by Oracle on 2014-2021. -// Modifications copyright (c) 2014-2021 Oracle and/or its affiliates. +// This file was modified by Oracle on 2014-2023. +// Modifications copyright (c) 2014-2023 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 @@ -23,20 +23,19 @@ #include <algorithm> #include <vector> -#include <boost/range/begin.hpp> -#include <boost/range/empty.hpp> -#include <boost/range/end.hpp> -#include <boost/range/size.hpp> - #include <boost/geometry/algorithms/detail/for_each_range.hpp> #include <boost/geometry/core/assert.hpp> +#include <boost/geometry/core/closure.hpp> #include <boost/geometry/core/cs.hpp> #include <boost/geometry/core/point_type.hpp> +#include <boost/geometry/core/point_order.hpp> #include <boost/geometry/policies/compare.hpp> #include <boost/geometry/strategies/convex_hull/cartesian.hpp> #include <boost/geometry/strategies/convex_hull/geographic.hpp> #include <boost/geometry/strategies/convex_hull/spherical.hpp> +#include <boost/geometry/util/range.hpp> + namespace boost { namespace geometry { @@ -45,13 +44,15 @@ namespace boost { namespace geometry namespace detail { namespace convex_hull { -template <typename Geometry, typename Point, typename Less> -inline void get_extremes(Geometry const& geometry, +// TODO: All of the copies could be avoided if this function stored pointers to points. +// But would it be possible considering that a range can return proxy reference? +template <typename InputProxy, typename Point, typename Less> +inline void get_extremes(InputProxy const& in_proxy, Point& left, Point& right, Less const& less) { bool first = true; - geometry::detail::for_each_range(geometry, [&](auto const& range) + in_proxy.for_each_range([&](auto const& range) { if (boost::empty(range)) { @@ -107,19 +108,13 @@ inline void get_extremes(Geometry const& geometry, } -template -< - typename Geometry, - typename Point, - typename Container, - typename SideStrategy -> -inline void assign_ranges(Geometry const& geometry, +template <typename InputProxy, typename Point, typename Container, typename SideStrategy> +inline void assign_ranges(InputProxy const& in_proxy, Point const& most_left, Point const& most_right, Container& lower_points, Container& upper_points, SideStrategy const& side) { - geometry::detail::for_each_range(geometry, [&](auto const& range) + in_proxy.for_each_range([&](auto const& range) { // Put points in one of the two output sequences for (auto it = boost::begin(range); it != boost::end(range); ++it) @@ -145,33 +140,14 @@ inline void assign_ranges(Geometry const& geometry, } -template <typename Range, typename Less> -inline void sort(Range& range, Less const& less) -{ - std::sort(boost::begin(range), boost::end(range), less); -} - -} // namespace convex_hull - - /*! \brief Graham scan algorithm to calculate convex hull */ -template <typename InputGeometry, typename OutputPoint> +template <typename InputPoint> class graham_andrew { -public : - typedef OutputPoint point_type; - typedef InputGeometry geometry_type; - -private: - - typedef typename cs_tag<point_type>::type cs_tag; - + typedef InputPoint point_type; typedef typename std::vector<point_type> container_type; - typedef typename std::vector<point_type>::const_iterator iterator; - typedef typename std::vector<point_type>::const_reverse_iterator rev_iterator; - class partitions { @@ -182,14 +158,23 @@ private: container_type m_copied_input; }; - public: - typedef partitions state_type; + template <typename InputProxy, typename OutputRing, typename Strategy> + static void apply(InputProxy const& in_proxy, OutputRing & out_ring, Strategy& strategy) + { + partitions state; + + apply(in_proxy, state, strategy); - template <typename Strategy> - inline void apply(InputGeometry const& geometry, - partitions& state, - Strategy& strategy) const + result(state, + range::back_inserter(out_ring), + geometry::point_order<OutputRing>::value == clockwise, + geometry::closure<OutputRing>::value != open); + } + +private: + template <typename InputProxy, typename Strategy> + static void apply(InputProxy const& in_proxy, partitions& state, Strategy& strategy) { // First pass. // Get min/max (in most cases left / right) points @@ -203,14 +188,11 @@ public: // For symmetry and to get often more balanced lower/upper halves // we keep it. - typedef typename geometry::point_type<InputGeometry>::type point_type; - point_type most_left, most_right; - // TODO: User-defined CS-specific less-compare - geometry::less<point_type> less; + geometry::less_exact<point_type, -1, Strategy> less; - detail::convex_hull::get_extremes(geometry, most_left, most_right, less); + detail::convex_hull::get_extremes(in_proxy, most_left, most_right, less); container_type lower_points, upper_points; @@ -219,13 +201,13 @@ public: // Bounding left/right points // Second pass, now that extremes are found, assign all points // in either lower, either upper - detail::convex_hull::assign_ranges(geometry, most_left, most_right, + detail::convex_hull::assign_ranges(in_proxy, most_left, most_right, lower_points, upper_points, side_strategy); // Sort both collections, first on x(, then on y) - detail::convex_hull::sort(lower_points, less); - detail::convex_hull::sort(upper_points, less); + std::sort(boost::begin(lower_points), boost::end(lower_points), less); + std::sort(boost::begin(upper_points), boost::end(upper_points), less); // And decide which point should be in the final hull build_half_hull<-1>(lower_points, state.m_lower_hull, @@ -236,26 +218,6 @@ public: side_strategy); } - - template <typename OutputIterator> - inline void result(partitions const& state, - OutputIterator out, - bool clockwise, - bool closed) const - { - if (clockwise) - { - output_ranges(state.m_upper_hull, state.m_lower_hull, out, closed); - } - else - { - output_ranges(state.m_lower_hull, state.m_upper_hull, out, closed); - } - } - - -private: - template <int Factor, typename SideStrategy> static inline void build_half_hull(container_type const& input, container_type& output, @@ -263,9 +225,9 @@ private: SideStrategy const& side) { output.push_back(left); - for(iterator it = input.begin(); it != input.end(); ++it) + for (auto const& i : input) { - add_to_hull<Factor>(*it, output, side); + add_to_hull<Factor>(i, output, side); } add_to_hull<Factor>(right, output, side); } @@ -279,7 +241,7 @@ private: std::size_t output_size = output.size(); while (output_size >= 3) { - rev_iterator rit = output.rbegin(); + auto rit = output.rbegin(); point_type const last = *rit++; point_type const& last2 = *rit++; @@ -301,6 +263,19 @@ private: template <typename OutputIterator> + static void result(partitions const& state, OutputIterator out, bool clockwise, bool closed) + { + if (clockwise) + { + output_ranges(state.m_upper_hull, state.m_lower_hull, out, closed); + } + else + { + output_ranges(state.m_lower_hull, state.m_upper_hull, out, closed); + } + } + + template <typename OutputIterator> static inline void output_ranges(container_type const& first, container_type const& second, OutputIterator out, @@ -327,7 +302,7 @@ private: }; -} // namespace detail +}} // namespace detail::convex_hull #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry diff --git a/boost/geometry/algorithms/detail/convex_hull/interface.hpp b/boost/geometry/algorithms/detail/convex_hull/interface.hpp index ce61c99802..b820cc4bf4 100644 --- a/boost/geometry/algorithms/detail/convex_hull/interface.hpp +++ b/boost/geometry/algorithms/detail/convex_hull/interface.hpp @@ -3,6 +3,7 @@ // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2015 Bruno Lalande, Paris, France. // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. +// Copyright (c) 2023 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2014-2021. // Modifications copyright (c) 2014-2021 Oracle and/or its affiliates. @@ -21,86 +22,171 @@ #ifndef BOOST_GEOMETRY_ALGORITHMS_CONVEX_HULL_INTERFACE_HPP #define BOOST_GEOMETRY_ALGORITHMS_CONVEX_HULL_INTERFACE_HPP -#include <boost/array.hpp> +#include <array> -#include <boost/variant/apply_visitor.hpp> -#include <boost/variant/static_visitor.hpp> -#include <boost/variant/variant_fwd.hpp> - -#include <boost/geometry/algorithms/detail/as_range.hpp> #include <boost/geometry/algorithms/detail/assign_box_corners.hpp> #include <boost/geometry/algorithms/detail/convex_hull/graham_andrew.hpp> +#include <boost/geometry/algorithms/detail/equals/point_point.hpp> +#include <boost/geometry/algorithms/detail/for_each_range.hpp> +#include <boost/geometry/algorithms/detail/select_geometry_type.hpp> +#include <boost/geometry/algorithms/detail/visit.hpp> #include <boost/geometry/algorithms/is_empty.hpp> #include <boost/geometry/core/closure.hpp> #include <boost/geometry/core/cs.hpp> #include <boost/geometry/core/exterior_ring.hpp> +#include <boost/geometry/core/geometry_types.hpp> #include <boost/geometry/core/point_order.hpp> #include <boost/geometry/core/ring_type.hpp> +#include <boost/geometry/core/tag.hpp> +#include <boost/geometry/core/tags.hpp> +#include <boost/geometry/core/visit.hpp> +#include <boost/geometry/geometries/adapted/boost_variant.hpp> // For backward compatibility #include <boost/geometry/geometries/concepts/check.hpp> +#include <boost/geometry/geometries/ring.hpp> -#include <boost/geometry/strategies/convex_hull/services.hpp> +#include <boost/geometry/strategies/convex_hull/cartesian.hpp> +#include <boost/geometry/strategies/convex_hull/geographic.hpp> +#include <boost/geometry/strategies/convex_hull/spherical.hpp> #include <boost/geometry/strategies/default_strategy.hpp> #include <boost/geometry/util/condition.hpp> +#include <boost/geometry/util/range.hpp> +#include <boost/geometry/util/sequence.hpp> +#include <boost/geometry/util/type_traits.hpp> namespace boost { namespace geometry { +// TODO: This file is named interface.hpp but the code below is not the interface. +// It's the implementation of the algorithm. #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace convex_hull { -template <order_selector Order, closure_selector Closure> -struct hull_insert +// Abstraction representing ranges/rings of a geometry +template <typename Geometry> +struct input_geometry_proxy { - // Member template function (to avoid inconvenient declaration - // of output-iterator-type, from hull_to_geometry) - template <typename Geometry, typename OutputIterator, typename Strategy> - static inline OutputIterator apply(Geometry const& geometry, - OutputIterator out, - Strategy const& strategy) + input_geometry_proxy(Geometry const& geometry) + : m_geometry(geometry) + {} + + template <typename UnaryFunction> + inline void for_each_range(UnaryFunction fun) const { - typedef graham_andrew - < - Geometry, - typename point_type<Geometry>::type - > ConvexHullAlgorithm; + geometry::detail::for_each_range(m_geometry, fun); + } - ConvexHullAlgorithm algorithm; - typename ConvexHullAlgorithm::state_type state; + Geometry const& m_geometry; +}; - algorithm.apply(geometry, state, strategy); - algorithm.result(state, out, Order == clockwise, Closure != open); +// Abstraction representing ranges/rings of subgeometries of geometry collection +// with boxes converted to rings +template <typename Geometry, typename BoxRings> +struct input_geometry_collection_proxy +{ + input_geometry_collection_proxy(Geometry const& geometry, BoxRings const& box_rings) + : m_geometry(geometry) + , m_box_rings(box_rings) + {} + + template <typename UnaryFunction> + inline void for_each_range(UnaryFunction fun) const + { + detail::visit_breadth_first([&](auto const& g) + { + input_geometry_collection_proxy::call_for_non_boxes(g, fun); + return true; + }, m_geometry); - return out; + for (auto const& r : m_box_rings) + { + geometry::detail::for_each_range(r, fun); + } } -}; -struct hull_to_geometry -{ - template <typename Geometry, typename OutputGeometry, typename Strategy> - static inline void apply(Geometry const& geometry, OutputGeometry& out, - Strategy const& strategy) +private: + template <typename G, typename F, std::enable_if_t<! util::is_box<G>::value, int> = 0> + static inline void call_for_non_boxes(G const& g, F & f) { - // TODO: Why not handle multi-polygon here? - // TODO: detail::as_range() is only used in this place in the whole library - // it should probably be located here. - // NOTE: A variable is created here because this can be a proxy range - // and back_insert_iterator<> can store a pointer to it. - // Handle linestring, ring and polygon the same: - auto&& range = detail::as_range(out); - hull_insert - < - geometry::point_order<OutputGeometry>::value, - geometry::closure<OutputGeometry>::value - >::apply(geometry, range::back_inserter(range), strategy); + geometry::detail::for_each_range(g, f); } + template <typename G, typename F, std::enable_if_t<util::is_box<G>::value, int> = 0> + static inline void call_for_non_boxes(G const&, F &) + {} + + Geometry const& m_geometry; + BoxRings const& m_box_rings; +}; + + +// TODO: Or just implement point_type<> for GeometryCollection +// and enforce the same point_type used in the whole sequence in check(). +template <typename Geometry, typename Tag = typename tag<Geometry>::type> +struct default_strategy +{ + using type = typename strategies::convex_hull::services::default_strategy + < + Geometry + >::type; +}; + +template <typename Geometry> +struct default_strategy<Geometry, geometry_collection_tag> + : default_strategy<typename detail::first_geometry_type<Geometry>::type> +{}; + + +// Utilities for output GC and DG +template <typename G1, typename G2> +struct output_polygonal_less +{ + template <typename G> + using priority = std::integral_constant + < + int, + (util::is_ring<G>::value ? 0 : + util::is_polygon<G>::value ? 1 : + util::is_multi_polygon<G>::value ? 2 : 3) + >; + + static const bool value = priority<G1>::value < priority<G2>::value; }; +template <typename G1, typename G2> +struct output_linear_less +{ + template <typename G> + using priority = std::integral_constant + < + int, + (util::is_segment<G>::value ? 0 : + util::is_linestring<G>::value ? 1 : + util::is_multi_linestring<G>::value ? 2 : 3) + >; + + static const bool value = priority<G1>::value < priority<G2>::value; +}; + +template <typename G1, typename G2> +struct output_pointlike_less +{ + template <typename G> + using priority = std::integral_constant + < + int, + (util::is_point<G>::value ? 0 : + util::is_multi_point<G>::value ? 1 : 2) + >; + + static const bool value = priority<G1>::value < priority<G2>::value; +}; + + }} // namespace detail::convex_hull #endif // DOXYGEN_NO_DETAIL @@ -116,10 +202,23 @@ template typename Tag = typename tag<Geometry>::type > struct convex_hull - : detail::convex_hull::hull_to_geometry -{}; +{ + template <typename OutputGeometry, typename Strategy> + static inline void apply(Geometry const& geometry, + OutputGeometry& out, + Strategy const& strategy) + { + detail::convex_hull::input_geometry_proxy<Geometry> in_proxy(geometry); + detail::convex_hull::graham_andrew + < + typename point_type<Geometry>::type + >::apply(in_proxy, out, strategy); + } +}; -// TODO: This is not correct in spherical and geographic CS + +// A hull for boxes is trivial. Any strategy is (currently) skipped. +// TODO: This is not correct in spherical and geographic CS. template <typename Box> struct convex_hull<Box, box_tag> { @@ -133,185 +232,337 @@ struct convex_hull<Box, box_tag> static bool const Reverse = geometry::point_order<OutputGeometry>::value == counterclockwise; - // A hull for boxes is trivial. Any strategy is (currently) skipped. - boost::array<typename point_type<Box>::type, 4> range; - geometry::detail::assign_box_corners_oriented<Reverse>(box, range); - geometry::append(out, range); + std::array<typename point_type<OutputGeometry>::type, 4> arr; + // TODO: This assigns only 2d cooridnates! + // And it is also used in box_view<>! + geometry::detail::assign_box_corners_oriented<Reverse>(box, arr); + + std::move(arr.begin(), arr.end(), range::back_inserter(out)); if (BOOST_GEOMETRY_CONDITION(Close)) { - geometry::append(out, *boost::begin(range)); + range::push_back(out, range::front(out)); } } }; +template <typename GeometryCollection> +struct convex_hull<GeometryCollection, geometry_collection_tag> +{ + template <typename OutputGeometry, typename Strategy> + static inline void apply(GeometryCollection const& geometry, + OutputGeometry& out, + Strategy const& strategy) + { + // Assuming that single point_type is used by the GeometryCollection + using subgeometry_type = typename detail::first_geometry_type<GeometryCollection>::type; + using point_type = typename geometry::point_type<subgeometry_type>::type; + using ring_type = model::ring<point_type, true, false>; + + // Calculate box rings once + std::vector<ring_type> box_rings; + detail::visit_breadth_first([&](auto const& g) + { + convex_hull::add_ring_for_box(box_rings, g, strategy); + return true; + }, geometry); -template <order_selector Order, closure_selector Closure> -struct convex_hull_insert - : detail::convex_hull::hull_insert<Order, Closure> -{}; + detail::convex_hull::input_geometry_collection_proxy + < + GeometryCollection, std::vector<ring_type> + > in_proxy(geometry, box_rings); + detail::convex_hull::graham_andrew + < + point_type + >::apply(in_proxy, out, strategy); + } -} // namespace dispatch -#endif // DOXYGEN_NO_DISPATCH +private: + template + < + typename Ring, typename SubGeometry, typename Strategy, + std::enable_if_t<util::is_box<SubGeometry>::value, int> = 0 + > + static inline void add_ring_for_box(std::vector<Ring> & rings, SubGeometry const& box, + Strategy const& strategy) + { + Ring ring; + convex_hull<SubGeometry>::apply(box, ring, strategy); + rings.push_back(std::move(ring)); + } + template + < + typename Ring, typename SubGeometry, typename Strategy, + std::enable_if_t<! util::is_box<SubGeometry>::value, int> = 0 + > + static inline void add_ring_for_box(std::vector<Ring> & , SubGeometry const& , + Strategy const& ) + {} +}; -namespace resolve_strategy { +template <typename OutputGeometry, typename Tag = typename tag<OutputGeometry>::type> +struct convex_hull_out +{ + BOOST_GEOMETRY_STATIC_ASSERT_FALSE("This OutputGeometry is not supported.", OutputGeometry, Tag); +}; -struct convex_hull +template <typename OutputGeometry> +struct convex_hull_out<OutputGeometry, ring_tag> { - template <typename Geometry, typename OutputGeometry, typename Strategy> + template <typename Geometry, typename Strategies> static inline void apply(Geometry const& geometry, OutputGeometry& out, - Strategy const& strategy) + Strategies const& strategies) { - //BOOST_CONCEPT_ASSERT( (geometry::concepts::ConvexHullStrategy<Strategy>) ); - dispatch::convex_hull<Geometry>::apply(geometry, out, strategy); + dispatch::convex_hull<Geometry>::apply(geometry, out, strategies); } +}; - template <typename Geometry, typename OutputGeometry> +template <typename OutputGeometry> +struct convex_hull_out<OutputGeometry, polygon_tag> +{ + template <typename Geometry, typename Strategies> static inline void apply(Geometry const& geometry, OutputGeometry& out, - default_strategy) + Strategies const& strategies) { - typedef typename strategies::convex_hull::services::default_strategy - < - Geometry - >::type strategy_type; + auto&& ring = exterior_ring(out); + dispatch::convex_hull<Geometry>::apply(geometry, ring, strategies); + } +}; - apply(geometry, out, strategy_type()); +template <typename OutputGeometry> +struct convex_hull_out<OutputGeometry, multi_polygon_tag> +{ + template <typename Geometry, typename Strategies> + static inline void apply(Geometry const& geometry, + OutputGeometry& out, + Strategies const& strategies) + { + typename boost::range_value<OutputGeometry>::type polygon; + auto&& ring = exterior_ring(polygon); + dispatch::convex_hull<Geometry>::apply(geometry, ring, strategies); + // Empty input is checked so the output shouldn't be empty + range::push_back(out, std::move(polygon)); } }; -struct convex_hull_insert +template <typename OutputGeometry> +struct convex_hull_out<OutputGeometry, geometry_collection_tag> { - template <typename Geometry, typename OutputIterator, typename Strategy> - static inline OutputIterator apply(Geometry const& geometry, - OutputIterator& out, - Strategy const& strategy) + using polygonal_t = typename util::sequence_min_element + < + typename traits::geometry_types<OutputGeometry>::type, + detail::convex_hull::output_polygonal_less + >::type; + using linear_t = typename util::sequence_min_element + < + typename traits::geometry_types<OutputGeometry>::type, + detail::convex_hull::output_linear_less + >::type; + using pointlike_t = typename util::sequence_min_element + < + typename traits::geometry_types<OutputGeometry>::type, + detail::convex_hull::output_pointlike_less + >::type; + + // select_element may define different kind of geometry than the one that is desired + BOOST_GEOMETRY_STATIC_ASSERT(util::is_polygonal<polygonal_t>::value, + "It must be possible to store polygonal geometry in OutputGeometry.", polygonal_t); + BOOST_GEOMETRY_STATIC_ASSERT(util::is_linear<linear_t>::value, + "It must be possible to store linear geometry in OutputGeometry.", linear_t); + BOOST_GEOMETRY_STATIC_ASSERT(util::is_pointlike<pointlike_t>::value, + "It must be possible to store pointlike geometry in OutputGeometry.", pointlike_t); + + template <typename Geometry, typename Strategies> + static inline void apply(Geometry const& geometry, + OutputGeometry& out, + Strategies const& strategies) { - //BOOST_CONCEPT_ASSERT( (geometry::concepts::ConvexHullStrategy<Strategy>) ); + polygonal_t polygonal; + convex_hull_out<polygonal_t>::apply(geometry, polygonal, strategies); + // Empty input is checked so the output shouldn't be empty + auto&& out_ring = ring(polygonal); + + if (boost::size(out_ring) == detail::minimum_ring_size<polygonal_t>::value) + { + using detail::equals::equals_point_point; + if (equals_point_point(range::front(out_ring), range::at(out_ring, 1), strategies)) + { + pointlike_t pointlike; + move_to_pointlike(out_ring, pointlike); + move_to_out(pointlike, out); + return; + } + if (equals_point_point(range::front(out_ring), range::at(out_ring, 2), strategies)) + { + linear_t linear; + move_to_linear(out_ring, linear); + move_to_out(linear, out); + return; + } + } - return dispatch::convex_hull_insert< - geometry::point_order<Geometry>::value, - geometry::closure<Geometry>::value - >::apply(geometry, out, strategy); + move_to_out(polygonal, out); } - template <typename Geometry, typename OutputIterator> - static inline OutputIterator apply(Geometry const& geometry, - OutputIterator& out, - default_strategy) +private: + template <typename Polygonal, util::enable_if_ring_t<Polygonal, int> = 0> + static decltype(auto) ring(Polygonal const& polygonal) { - typedef typename strategies::convex_hull::services::default_strategy - < - Geometry - >::type strategy_type; + return polygonal; + } + template <typename Polygonal, util::enable_if_polygon_t<Polygonal, int> = 0> + static decltype(auto) ring(Polygonal const& polygonal) + { + return exterior_ring(polygonal); + } + template <typename Polygonal, util::enable_if_multi_polygon_t<Polygonal, int> = 0> + static decltype(auto) ring(Polygonal const& polygonal) + { + return exterior_ring(range::front(polygonal)); + } - return apply(geometry, out, strategy_type()); + template <typename Range, typename Linear, util::enable_if_segment_t<Linear, int> = 0> + static void move_to_linear(Range & out_range, Linear & seg) + { + detail::assign_point_to_index<0>(range::front(out_range), seg); + detail::assign_point_to_index<1>(range::at(out_range, 1), seg); + } + template <typename Range, typename Linear, util::enable_if_linestring_t<Linear, int> = 0> + static void move_to_linear(Range & out_range, Linear & ls) + { + std::move(boost::begin(out_range), boost::begin(out_range) + 2, range::back_inserter(ls)); + } + template <typename Range, typename Linear, util::enable_if_multi_linestring_t<Linear, int> = 0> + static void move_to_linear(Range & out_range, Linear & mls) + { + typename boost::range_value<Linear>::type ls; + std::move(boost::begin(out_range), boost::begin(out_range) + 2, range::back_inserter(ls)); + range::push_back(mls, std::move(ls)); + } + + template <typename Range, typename PointLike, util::enable_if_point_t<PointLike, int> = 0> + static void move_to_pointlike(Range & out_range, PointLike & pt) + { + pt = range::front(out_range); + } + template <typename Range, typename PointLike, util::enable_if_multi_point_t<PointLike, int> = 0> + static void move_to_pointlike(Range & out_range, PointLike & mpt) + { + range::push_back(mpt, std::move(range::front(out_range))); + } + + template + < + typename Geometry, typename OutputGeometry_, + util::enable_if_geometry_collection_t<OutputGeometry_, int> = 0 + > + static void move_to_out(Geometry & g, OutputGeometry_ & out) + { + range::emplace_back(out, std::move(g)); + } + template + < + typename Geometry, typename OutputGeometry_, + util::enable_if_dynamic_geometry_t<OutputGeometry_, int> = 0 + > + static void move_to_out(Geometry & g, OutputGeometry_ & out) + { + out = std::move(g); } }; -} // namespace resolve_strategy +template <typename OutputGeometry> +struct convex_hull_out<OutputGeometry, dynamic_geometry_tag> + : convex_hull_out<OutputGeometry, geometry_collection_tag> +{}; -namespace resolve_variant { +// For backward compatibility +template <typename OutputGeometry> +struct convex_hull_out<OutputGeometry, linestring_tag> + : convex_hull_out<OutputGeometry, ring_tag> +{}; -template <typename Geometry> + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +namespace resolve_strategy { + +template <typename Strategies> struct convex_hull { - template <typename OutputGeometry, typename Strategy> + template <typename Geometry, typename OutputGeometry> static inline void apply(Geometry const& geometry, OutputGeometry& out, - Strategy const& strategy) + Strategies const& strategies) { - concepts::check_concepts_and_equal_dimensions< - const Geometry, - OutputGeometry - >(); - - resolve_strategy::convex_hull::apply(geometry, out, strategy); + dispatch::convex_hull_out<OutputGeometry>::apply(geometry, out, strategies); } }; -template <BOOST_VARIANT_ENUM_PARAMS(typename T)> -struct convex_hull<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > +template <> +struct convex_hull<default_strategy> { - template <typename OutputGeometry, typename Strategy> - struct visitor: boost::static_visitor<void> + template <typename Geometry, typename OutputGeometry> + static inline void apply(Geometry const& geometry, + OutputGeometry& out, + default_strategy const&) { - OutputGeometry& m_out; - Strategy const& m_strategy; - - visitor(OutputGeometry& out, Strategy const& strategy) - : m_out(out), m_strategy(strategy) - {} - - template <typename Geometry> - void operator()(Geometry const& geometry) const - { - convex_hull<Geometry>::apply(geometry, m_out, m_strategy); - } - }; + using strategy_type = typename detail::convex_hull::default_strategy + < + Geometry + >::type; - template <typename OutputGeometry, typename Strategy> - static inline void - apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry, - OutputGeometry& out, - Strategy const& strategy) - { - boost::apply_visitor(visitor<OutputGeometry, Strategy>(out, strategy), - geometry); + dispatch::convex_hull_out<OutputGeometry>::apply(geometry, out, strategy_type()); } }; -template <typename Geometry> -struct convex_hull_insert + +} // namespace resolve_strategy + + +namespace resolve_dynamic { + +template <typename Geometry, typename Tag = typename tag<Geometry>::type> +struct convex_hull { - template <typename OutputIterator, typename Strategy> - static inline OutputIterator apply(Geometry const& geometry, - OutputIterator& out, - Strategy const& strategy) + template <typename OutputGeometry, typename Strategy> + static inline void apply(Geometry const& geometry, + OutputGeometry& out, + Strategy const& strategy) { - // Concept: output point type = point type of input geometry - concepts::check<Geometry const>(); - concepts::check<typename point_type<Geometry>::type>(); + concepts::check_concepts_and_equal_dimensions< + const Geometry, + OutputGeometry + >(); - return resolve_strategy::convex_hull_insert::apply(geometry, out, strategy); + resolve_strategy::convex_hull<Strategy>::apply(geometry, out, strategy); } }; -template <BOOST_VARIANT_ENUM_PARAMS(typename T)> -struct convex_hull_insert<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > +template <typename Geometry> +struct convex_hull<Geometry, dynamic_geometry_tag> { - template <typename OutputIterator, typename Strategy> - struct visitor: boost::static_visitor<OutputIterator> + template <typename OutputGeometry, typename Strategy> + static inline void apply(Geometry const& geometry, + OutputGeometry& out, + Strategy const& strategy) { - OutputIterator& m_out; - Strategy const& m_strategy; - - visitor(OutputIterator& out, Strategy const& strategy) - : m_out(out), m_strategy(strategy) - {} - - template <typename Geometry> - OutputIterator operator()(Geometry const& geometry) const + traits::visit<Geometry>::apply([&](auto const& g) { - return convex_hull_insert<Geometry>::apply(geometry, m_out, m_strategy); - } - }; - - template <typename OutputIterator, typename Strategy> - static inline OutputIterator - apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry, - OutputIterator& out, - Strategy const& strategy) - { - return boost::apply_visitor(visitor<OutputIterator, Strategy>(out, strategy), geometry); + convex_hull<util::remove_cref_t<decltype(g)>>::apply(g, out, strategy); + }, geometry); } }; -} // namespace resolve_variant + +} // namespace resolve_dynamic /*! @@ -330,8 +581,7 @@ struct convex_hull_insert<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > \qbk{[include reference/algorithms/convex_hull.qbk]} */ template<typename Geometry, typename OutputGeometry, typename Strategy> -inline void convex_hull(Geometry const& geometry, - OutputGeometry& out, Strategy const& strategy) +inline void convex_hull(Geometry const& geometry, OutputGeometry& out, Strategy const& strategy) { if (geometry::is_empty(geometry)) { @@ -339,7 +589,7 @@ inline void convex_hull(Geometry const& geometry, return; } - resolve_variant::convex_hull<Geometry>::apply(geometry, out, strategy); + resolve_dynamic::convex_hull<Geometry>::apply(geometry, out, strategy); } @@ -355,52 +605,11 @@ inline void convex_hull(Geometry const& geometry, \qbk{[include reference/algorithms/convex_hull.qbk]} */ template<typename Geometry, typename OutputGeometry> -inline void convex_hull(Geometry const& geometry, - OutputGeometry& hull) +inline void convex_hull(Geometry const& geometry, OutputGeometry& hull) { geometry::convex_hull(geometry, hull, default_strategy()); } -#ifndef DOXYGEN_NO_DETAIL -namespace detail { namespace convex_hull -{ - - -template<typename Geometry, typename OutputIterator, typename Strategy> -inline OutputIterator convex_hull_insert(Geometry const& geometry, - OutputIterator out, Strategy const& strategy) -{ - return resolve_variant::convex_hull_insert - < - Geometry - >::apply(geometry, out, strategy); -} - - -/*! -\brief Calculate the convex hull of a geometry, output-iterator version -\ingroup convex_hull -\tparam Geometry the input geometry type -\tparam OutputIterator: an output-iterator -\param geometry the geometry to calculate convex hull from -\param out an output iterator outputing points of the convex hull -\note This overloaded version outputs to an output iterator. -In this case, nothing is known about its point-type or - about its clockwise order. Therefore, the input point-type - and order are copied - - */ -template<typename Geometry, typename OutputIterator> -inline OutputIterator convex_hull_insert(Geometry const& geometry, - OutputIterator out) -{ - return convex_hull_insert(geometry, out, default_strategy()); -} - - -}} // namespace detail::convex_hull -#endif // DOXYGEN_NO_DETAIL - }} // namespace boost::geometry diff --git a/boost/geometry/algorithms/detail/counting.hpp b/boost/geometry/algorithms/detail/counting.hpp index 3580740b31..0199ec0b9a 100644 --- a/boost/geometry/algorithms/detail/counting.hpp +++ b/boost/geometry/algorithms/detail/counting.hpp @@ -30,8 +30,6 @@ #include <boost/geometry/util/range.hpp> -#include <boost/geometry/algorithms/detail/interior_iterator.hpp> - namespace boost { namespace geometry { @@ -67,10 +65,8 @@ struct polygon_count { std::size_t n = RangeCount::apply(exterior_ring(poly)); - typename interior_return_type<Polygon const>::type - rings = interior_rings(poly); - for (typename detail::interior_iterator<Polygon const>::type - it = boost::begin(rings); it != boost::end(rings); ++it) + auto const& rings = interior_rings(poly); + for (auto it = boost::begin(rings); it != boost::end(rings); ++it) { n += RangeCount::apply(*it); } @@ -84,13 +80,10 @@ template <typename SingleCount> struct multi_count { template <typename MultiGeometry> - static inline std::size_t apply(MultiGeometry const& geometry) + static inline std::size_t apply(MultiGeometry const& multi) { std::size_t n = 0; - for (typename boost::range_iterator<MultiGeometry const>::type - it = boost::begin(geometry); - it != boost::end(geometry); - ++it) + for (auto it = boost::begin(multi); it != boost::end(multi); ++it) { n += SingleCount::apply(*it); } diff --git a/boost/geometry/algorithms/detail/covered_by/implementation.hpp b/boost/geometry/algorithms/detail/covered_by/implementation.hpp index ca4e557caa..13626871aa 100644 --- a/boost/geometry/algorithms/detail/covered_by/implementation.hpp +++ b/boost/geometry/algorithms/detail/covered_by/implementation.hpp @@ -4,9 +4,10 @@ // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. -// This file was modified by Oracle on 2013-2021. -// Modifications copyright (c) 2013-2021 Oracle and/or its affiliates. +// This file was modified by Oracle on 2013-2022. +// Modifications copyright (c) 2013-2022 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 // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library @@ -37,7 +38,8 @@ namespace detail { namespace covered_by { 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) + static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, + Strategy const& strategy) { return detail::within::covered_by_point_geometry(geometry1, geometry2, strategy); } @@ -46,44 +48,41 @@ struct use_point_in_geometry struct use_relate { template <typename Geometry1, typename Geometry2, typename Strategy> - static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) + static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, + Strategy const& strategy) { - typedef typename detail::de9im::static_mask_covered_by_type + return detail::relate::relate_impl < - Geometry1, Geometry2 - >::type covered_by_mask; - return geometry::relate(geometry1, geometry2, covered_by_mask(), strategy); + detail::de9im::static_mask_covered_by_type, + Geometry1, + Geometry2 + >::apply(geometry1, geometry2, strategy); } }; -}} // namespace detail::covered_by -#endif // DOXYGEN_NO_DETAIL - -#ifndef DOXYGEN_NO_DISPATCH -namespace dispatch -{ - -template <typename Point, typename Box> -struct covered_by<Point, Box, point_tag, box_tag> +struct geometry_covered_by_box { - template <typename Strategy> - static inline bool apply(Point const& point, Box const& box, Strategy const& strategy) + template <typename Geometry, typename Box, typename Strategy> + static inline bool apply(Geometry const& geometry, Box const& box, Strategy const& strategy) { - return strategy.covered_by(point, box).apply(point, box); + using point_type = typename point_type<Geometry>::type; + using mutable_point_type = typename helper_geometry<point_type>::type; + using box_type = model::box<mutable_point_type>; + + // TODO: this is not optimal since the process should be able to terminate if a point is found + // outside of the box without computing the whole envelope + box_type box_areal; + geometry::envelope(geometry, box_areal, strategy); + return strategy.covered_by(box_areal, box).apply(box_areal, box); } }; -template <typename Box1, typename Box2> -struct covered_by<Box1, Box2, box_tag, box_tag> -{ - template <typename Strategy> - static inline bool apply(Box1 const& box1, Box2 const& box2, Strategy const& strategy) - { - assert_dimension_equal<Box1, Box2>(); - return strategy.covered_by(box1, box2).apply(box1, box2); - } -}; +}} // namespace detail::covered_by +#endif // DOXYGEN_NO_DETAIL +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ // P/P @@ -272,6 +271,76 @@ struct covered_by<MultiPolygon1, MultiPolygon2, multi_polygon_tag, multi_polygon : public detail::covered_by::use_relate {}; +// B/A + +template <typename Box, typename Polygon> +struct covered_by<Box, Polygon, box_tag, ring_tag> + : public detail::covered_by::use_relate +{}; + +template <typename Box, typename Polygon> +struct covered_by<Box, Polygon, box_tag, polygon_tag> + : public detail::covered_by::use_relate +{}; + +template <typename Box, typename Polygon> +struct covered_by<Box, Polygon, box_tag, multi_polygon_tag> + : public detail::covered_by::use_relate +{}; + +// Geometry/Box + +template <typename Point, typename Box> +struct covered_by<Point, Box, point_tag, box_tag> +{ + template <typename Strategy> + static inline bool apply(Point const& point, Box const& box, Strategy const& strategy) + { + return strategy.covered_by(point, box).apply(point, box); + } +}; + +template <typename MultiPoint, typename Box> +struct covered_by<MultiPoint, Box, multi_point_tag, box_tag> + : public detail::covered_by::geometry_covered_by_box +{}; + +template <typename Linestring, typename Box> +struct covered_by<Linestring, Box, linestring_tag, box_tag> + : public detail::covered_by::geometry_covered_by_box +{}; + +template <typename MultiLinestring, typename Box> +struct covered_by<MultiLinestring, Box, multi_linestring_tag, box_tag> + : public detail::covered_by::geometry_covered_by_box +{}; + +template <typename Ring, typename Box> +struct covered_by<Ring, Box, ring_tag, box_tag> + : public detail::covered_by::geometry_covered_by_box +{}; + +template <typename Polygon, typename Box> +struct covered_by<Polygon, Box, polygon_tag, box_tag> + : public detail::covered_by::geometry_covered_by_box +{}; + +template <typename MultiPolygon, typename Box> +struct covered_by<MultiPolygon, Box, multi_polygon_tag, box_tag> + : public detail::covered_by::geometry_covered_by_box +{}; + +template <typename Box1, typename Box2> +struct covered_by<Box1, Box2, box_tag, box_tag> +{ + template <typename Strategy> + static inline bool apply(Box1 const& box1, Box2 const& box2, Strategy const& strategy) + { + assert_dimension_equal<Box1, Box2>(); + return strategy.covered_by(box1, box2).apply(box1, box2); + } +}; + } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH diff --git a/boost/geometry/algorithms/detail/covered_by/implementation_gc.hpp b/boost/geometry/algorithms/detail/covered_by/implementation_gc.hpp new file mode 100644 index 0000000000..cd0a44bc8f --- /dev/null +++ b/boost/geometry/algorithms/detail/covered_by/implementation_gc.hpp @@ -0,0 +1,46 @@ +// Boost.Geometry + +// Copyright (c) 2022 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) + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_COVERED_BY_IMPLEMENTATION_GC_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_COVERED_BY_IMPLEMENTATION_GC_HPP + + +#include <boost/geometry/algorithms/detail/covered_by/implementation.hpp> +#include <boost/geometry/algorithms/detail/relate/implementation_gc.hpp> + + +namespace boost { namespace geometry { + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch { + +template <typename Geometry1, typename Geometry2> +struct covered_by<Geometry1, Geometry2, geometry_collection_tag, geometry_collection_tag> + : detail::covered_by::use_relate +{}; + +template <typename Geometry1, typename Geometry2, typename Tag1> +struct covered_by<Geometry1, Geometry2, Tag1, geometry_collection_tag> + : detail::covered_by::use_relate +{}; + +template <typename Geometry1, typename Geometry2, typename Tag2> +struct covered_by<Geometry1, Geometry2, geometry_collection_tag, Tag2> + : detail::covered_by::use_relate +{}; + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_COVERED_BY_IMPLEMENTATION_GC_HPP diff --git a/boost/geometry/algorithms/detail/covered_by/interface.hpp b/boost/geometry/algorithms/detail/covered_by/interface.hpp index 20b22ff600..0488034381 100644 --- a/boost/geometry/algorithms/detail/covered_by/interface.hpp +++ b/boost/geometry/algorithms/detail/covered_by/interface.hpp @@ -19,10 +19,6 @@ #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_COVERED_BY_INTERFACE_HPP -#include <boost/variant/apply_visitor.hpp> -#include <boost/variant/static_visitor.hpp> -#include <boost/variant/variant_fwd.hpp> - #include <boost/geometry/algorithms/detail/within/interface.hpp> #include <boost/geometry/algorithms/not_implemented.hpp> @@ -121,9 +117,14 @@ struct covered_by<default_strategy, false> } // namespace resolve_strategy -namespace resolve_variant { +namespace resolve_dynamic { -template <typename Geometry1, typename Geometry2> +template +< + typename Geometry1, typename Geometry2, + typename Tag1 = typename geometry::tag<Geometry1>::type, + typename Tag2 = typename geometry::tag<Geometry2>::type +> struct covered_by { template <typename Strategy> @@ -131,107 +132,74 @@ struct covered_by Geometry2 const& geometry2, Strategy const& strategy) { - return resolve_strategy::covered_by<Strategy> - ::apply(geometry1, geometry2, strategy); + return resolve_strategy::covered_by + < + Strategy + >::apply(geometry1, geometry2, strategy); } }; -template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2> -struct covered_by<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2> +template <typename Geometry1, typename Geometry2, typename Tag2> +struct covered_by<Geometry1, Geometry2, dynamic_geometry_tag, Tag2> { template <typename Strategy> - struct visitor: boost::static_visitor<bool> + static inline bool apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Strategy const& strategy) { - Geometry2 const& m_geometry2; - Strategy const& m_strategy; - - visitor(Geometry2 const& geometry2, Strategy const& strategy) - : m_geometry2(geometry2), m_strategy(strategy) {} - - template <typename Geometry1> - bool operator()(Geometry1 const& geometry1) const + bool result = false; + traits::visit<Geometry1>::apply([&](auto const& g1) { - return covered_by<Geometry1, Geometry2> - ::apply(geometry1, m_geometry2, m_strategy); - } - }; - - template <typename Strategy> - static inline bool - apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1, - Geometry2 const& geometry2, - Strategy const& strategy) - { - return boost::apply_visitor(visitor<Strategy>(geometry2, strategy), geometry1); + result = resolve_strategy::covered_by + < + Strategy + >::apply(g1, geometry2, strategy); + }, geometry1); + return result; } }; -template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)> -struct covered_by<Geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > +template <typename Geometry1, typename Geometry2, typename Tag1> +struct covered_by<Geometry1, Geometry2, Tag1, dynamic_geometry_tag> { template <typename Strategy> - struct visitor: boost::static_visitor<bool> + static inline bool apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Strategy const& strategy) { - Geometry1 const& m_geometry1; - Strategy const& m_strategy; - - visitor(Geometry1 const& geometry1, Strategy const& strategy) - : m_geometry1(geometry1), m_strategy(strategy) {} - - template <typename Geometry2> - bool operator()(Geometry2 const& geometry2) const + bool result = false; + traits::visit<Geometry2>::apply([&](auto const& g2) { - return covered_by<Geometry1, Geometry2> - ::apply(m_geometry1, geometry2, m_strategy); - } - }; - - template <typename Strategy> - static inline bool - apply(Geometry1 const& geometry1, - boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2, - Strategy const& strategy) - { - return boost::apply_visitor(visitor<Strategy>(geometry1, strategy), geometry2); + result = resolve_strategy::covered_by + < + Strategy + >::apply(geometry1, g2, strategy); + }, geometry2); + return result; } }; -template < - BOOST_VARIANT_ENUM_PARAMS(typename T1), - BOOST_VARIANT_ENUM_PARAMS(typename T2) -> -struct covered_by< - boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>, - boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> -> +template <typename Geometry1, typename Geometry2> +struct covered_by<Geometry1, Geometry2, dynamic_geometry_tag, dynamic_geometry_tag> { template <typename Strategy> - struct visitor: boost::static_visitor<bool> + static inline bool apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Strategy const& strategy) { - Strategy const& m_strategy; - - visitor(Strategy const& strategy): m_strategy(strategy) {} - - template <typename Geometry1, typename Geometry2> - bool operator()(Geometry1 const& geometry1, - Geometry2 const& geometry2) const + bool result = false; + traits::visit<Geometry1, Geometry2>::apply([&](auto const& g1, auto const& g2) { - return covered_by<Geometry1, Geometry2> - ::apply(geometry1, geometry2, m_strategy); - } - }; - - template <typename Strategy> - static inline bool - apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1, - boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2, - Strategy const& strategy) - { - return boost::apply_visitor(visitor<Strategy>(strategy), geometry1, geometry2); + result = resolve_strategy::covered_by + < + Strategy + >::apply(g1, g2, strategy); + }, geometry1, geometry2); + return result; } }; -} // namespace resolve_variant +} // namespace resolve_dynamic /*! @@ -256,8 +224,10 @@ struct covered_by< template<typename Geometry1, typename Geometry2> inline bool covered_by(Geometry1 const& geometry1, Geometry2 const& geometry2) { - return resolve_variant::covered_by<Geometry1, Geometry2> - ::apply(geometry1, geometry2, default_strategy()); + return resolve_dynamic::covered_by + < + Geometry1, Geometry2 + >::apply(geometry1, geometry2, default_strategy()); } /*! @@ -280,8 +250,10 @@ template<typename Geometry1, typename Geometry2, typename Strategy> inline bool covered_by(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { - return resolve_variant::covered_by<Geometry1, Geometry2> - ::apply(geometry1, geometry2, strategy); + return resolve_dynamic::covered_by + < + Geometry1, Geometry2 + >::apply(geometry1, geometry2, strategy); } }} // namespace boost::geometry diff --git a/boost/geometry/algorithms/detail/direction_code.hpp b/boost/geometry/algorithms/detail/direction_code.hpp index 269e9b476f..ece34f15b4 100644 --- a/boost/geometry/algorithms/detail/direction_code.hpp +++ b/boost/geometry/algorithms/detail/direction_code.hpp @@ -46,16 +46,16 @@ struct direction_code_impl template <> struct direction_code_impl<cartesian_tag> { - template <typename Point1, typename Point2> - static inline int apply(Point1 const& segment_a, Point1 const& segment_b, + template <typename PointSegmentA, typename PointSegmentB, typename Point2> + static inline int apply(PointSegmentA const& segment_a, PointSegmentB const& segment_b, Point2 const& point) { - typedef typename geometry::select_coordinate_type + using calc_t = typename geometry::select_coordinate_type < - Point1, Point2 - >::type calc_t; + PointSegmentA, PointSegmentB, Point2 + >::type; - typedef model::infinite_line<calc_t> line_type; + using line_type = model::infinite_line<calc_t>; // Situation and construction of perpendicular line // @@ -79,49 +79,67 @@ struct direction_code_impl<cartesian_tag> } calc_t const sv = arithmetic::side_value(line, point); - return sv == 0 ? 0 : sv > 0 ? 1 : -1; + static calc_t const zero = 0; + return sv == zero ? 0 : sv > zero ? 1 : -1; } }; template <> struct direction_code_impl<spherical_equatorial_tag> { - template <typename Point1, typename Point2> - static inline int apply(Point1 const& segment_a, Point1 const& segment_b, + template <typename PointSegmentA, typename PointSegmentB, typename Point2> + static inline int apply(PointSegmentA const& segment_a, PointSegmentB const& segment_b, Point2 const& p) { - typedef typename coordinate_type<Point1>::type coord1_t; - typedef typename coordinate_type<Point2>::type coord2_t; - typedef typename cs_angular_units<Point1>::type units_t; - typedef typename cs_angular_units<Point2>::type units2_t; - BOOST_GEOMETRY_STATIC_ASSERT( - (std::is_same<units_t, units2_t>::value), - "Not implemented for different units.", - units_t, units2_t); - - typedef typename geometry::select_coordinate_type <Point1, Point2>::type calc_t; - typedef math::detail::constants_on_spheroid<coord1_t, units_t> constants1; - typedef math::detail::constants_on_spheroid<coord2_t, units_t> constants2; - static coord1_t const pi_half1 = constants1::max_latitude(); - static coord2_t const pi_half2 = constants2::max_latitude(); + { + using units_sa_t = typename cs_angular_units<PointSegmentA>::type; + using units_sb_t = typename cs_angular_units<PointSegmentB>::type; + using units_p_t = typename cs_angular_units<Point2>::type; + BOOST_GEOMETRY_STATIC_ASSERT( + (std::is_same<units_sa_t, units_sb_t>::value), + "Not implemented for different units.", + units_sa_t, units_sb_t); + BOOST_GEOMETRY_STATIC_ASSERT( + (std::is_same<units_sa_t, units_p_t>::value), + "Not implemented for different units.", + units_sa_t, units_p_t); + } + + using coor_sa_t = typename coordinate_type<PointSegmentA>::type; + using coor_sb_t = typename coordinate_type<PointSegmentB>::type; + using coor_p_t = typename coordinate_type<Point2>::type; + + // Declare unit type (equal for all types) and calc type (coerced to most precise) + using units_t = typename cs_angular_units<Point2>::type; + using calc_t = typename geometry::select_coordinate_type + < + PointSegmentA, PointSegmentB, Point2 + >::type; + using constants_sa_t = math::detail::constants_on_spheroid<coor_sa_t, units_t>; + using constants_sb_t = math::detail::constants_on_spheroid<coor_sb_t, units_t>; + using constants_p_t = math::detail::constants_on_spheroid<coor_p_t, units_t>; + + static coor_sa_t const pi_half_sa = constants_sa_t::max_latitude(); + static coor_sb_t const pi_half_sb = constants_sb_t::max_latitude(); + static coor_p_t const pi_half_p = constants_p_t::max_latitude(); static calc_t const c0 = 0; - coord1_t const a0 = geometry::get<0>(segment_a); - coord1_t const a1 = geometry::get<1>(segment_a); - coord1_t const b0 = geometry::get<0>(segment_b); - coord1_t const b1 = geometry::get<1>(segment_b); - coord2_t const p0 = geometry::get<0>(p); - coord2_t const p1 = geometry::get<1>(p); - + coor_sa_t const a0 = geometry::get<0>(segment_a); + coor_sa_t const a1 = geometry::get<1>(segment_a); + coor_sb_t const b0 = geometry::get<0>(segment_b); + coor_sb_t const b1 = geometry::get<1>(segment_b); + coor_p_t const p0 = geometry::get<0>(p); + coor_p_t const p1 = geometry::get<1>(p); + if ( (math::equals(b0, a0) && math::equals(b1, a1)) || (math::equals(b0, p0) && math::equals(b1, p1)) ) { return 0; } - bool const is_a_pole = math::equals(pi_half1, math::abs(a1)); - bool const is_b_pole = math::equals(pi_half1, math::abs(b1)); - bool const is_p_pole = math::equals(pi_half2, math::abs(p1)); + bool const is_a_pole = math::equals(pi_half_sa, math::abs(a1)); + bool const is_b_pole = math::equals(pi_half_sb, math::abs(b1)); + bool const is_p_pole = math::equals(pi_half_p, math::abs(p1)); if ( is_b_pole && ((is_a_pole && math::sign(b1) == math::sign(a1)) || (is_p_pole && math::sign(b1) == math::sign(p1))) ) @@ -139,12 +157,12 @@ struct direction_code_impl<spherical_equatorial_tag> calc_t const dlat1 = latitude_distance_signed<units_t, calc_t>(b1, a1, dlon1, is_antilon1); calc_t const dlat2 = latitude_distance_signed<units_t, calc_t>(b1, p1, dlon2, is_antilon2); - calc_t mx = is_a_pole || is_b_pole || is_p_pole ? - c0 : - (std::min)(is_antilon1 ? c0 : math::abs(dlon1), - is_antilon2 ? c0 : math::abs(dlon2)); - calc_t my = (std::min)(math::abs(dlat1), - math::abs(dlat2)); + calc_t const mx = is_a_pole || is_b_pole || is_p_pole + ? c0 + : (std::min)(is_antilon1 ? c0 : math::abs(dlon1), + is_antilon2 ? c0 : math::abs(dlon2)); + calc_t const my = (std::min)(math::abs(dlat1), + math::abs(dlat2)); int s1 = 0, s2 = 0; if (mx >= my) @@ -164,7 +182,7 @@ struct direction_code_impl<spherical_equatorial_tag> template <typename Units, typename T> static inline T latitude_distance_signed(T const& lat1, T const& lat2, T const& lon_ds, bool & is_antilon) { - typedef math::detail::constants_on_spheroid<T, Units> constants; + using constants = math::detail::constants_on_spheroid<T, Units>; static T const pi = constants::half_period(); static T const c0 = 0; @@ -187,27 +205,27 @@ struct direction_code_impl<spherical_equatorial_tag> template <> struct direction_code_impl<spherical_polar_tag> { - template <typename Point1, typename Point2> - static inline int apply(Point1 segment_a, Point1 segment_b, + template <typename PointSegmentA, typename PointSegmentB, typename Point2> + static inline int apply(PointSegmentA segment_a, PointSegmentB segment_b, Point2 p) { - typedef math::detail::constants_on_spheroid + using constants_sa_t = math::detail::constants_on_spheroid < - typename coordinate_type<Point1>::type, - typename cs_angular_units<Point1>::type - > constants1; - typedef math::detail::constants_on_spheroid + typename coordinate_type<PointSegmentA>::type, + typename cs_angular_units<PointSegmentA>::type + >; + using constants_p_t = math::detail::constants_on_spheroid < typename coordinate_type<Point2>::type, typename cs_angular_units<Point2>::type - > constants2; + >; geometry::set<1>(segment_a, - constants1::max_latitude() - geometry::get<1>(segment_a)); + constants_sa_t::max_latitude() - geometry::get<1>(segment_a)); geometry::set<1>(segment_b, - constants1::max_latitude() - geometry::get<1>(segment_b)); + constants_sa_t::max_latitude() - geometry::get<1>(segment_b)); geometry::set<1>(p, - constants2::max_latitude() - geometry::get<1>(p)); + constants_p_t::max_latitude() - geometry::get<1>(p)); return direction_code_impl < @@ -216,13 +234,13 @@ struct direction_code_impl<spherical_polar_tag> } }; -// if spherical_tag is passed then pick cs_tag based on Point1 type +// if spherical_tag is passed then pick cs_tag based on PointSegmentA type // with spherical_equatorial_tag as the default template <> struct direction_code_impl<spherical_tag> { - template <typename Point1, typename Point2> - static inline int apply(Point1 segment_a, Point1 segment_b, + template <typename PointSegmentA, typename PointSegmentB, typename Point2> + static inline int apply(PointSegmentA segment_a, PointSegmentB segment_b, Point2 p) { return direction_code_impl @@ -231,7 +249,7 @@ struct direction_code_impl<spherical_tag> < std::is_same < - typename geometry::cs_tag<Point1>::type, + typename geometry::cs_tag<PointSegmentA>::type, spherical_polar_tag >::value, spherical_polar_tag, @@ -251,8 +269,10 @@ struct direction_code_impl<geographic_tag> // Returns 1 if p goes forward, so extends (a,b) // Returns 0 if p is equal with b, or if (a,b) is degenerate // Note that it does not do any collinearity test, that should be done before -template <typename CSTag, typename Point1, typename Point2> -inline int direction_code(Point1 const& segment_a, Point1 const& segment_b, +// In some cases the "segment" consists of different source points, and therefore +// their types might differ. +template <typename CSTag, typename PointSegmentA, typename PointSegmentB, typename Point2> +inline int direction_code(PointSegmentA const& segment_a, PointSegmentB const& segment_b, Point2 const& p) { return direction_code_impl<CSTag>::apply(segment_a, segment_b, p); diff --git a/boost/geometry/algorithms/detail/disjoint/areal_areal.hpp b/boost/geometry/algorithms/detail/disjoint/areal_areal.hpp index 934f90c875..880e503785 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-2020. -// Modifications copyright (c) 2013-2020, Oracle and/or its affiliates. +// This file was modified by Oracle on 2013-2022. +// Modifications copyright (c) 2013-2022, 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,13 +23,15 @@ #include <boost/geometry/core/point_type.hpp> -#include <boost/geometry/algorithms/covered_by.hpp> +#include <boost/geometry/algorithms/detail/covered_by/implementation.hpp> #include <boost/geometry/algorithms/detail/for_each_range.hpp> #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/geometries/helper_geometry.hpp> + #include <boost/geometry/algorithms/for_each.hpp> @@ -46,7 +48,8 @@ inline bool point_on_border_covered_by(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { - typename geometry::point_type<Geometry1>::type pt; + using point_type = typename geometry::point_type<Geometry1>::type; + typename helper_geometry<point_type>::type pt; return geometry::point_on_border(pt, geometry1) && geometry::covered_by(pt, geometry2, strategy); } diff --git a/boost/geometry/algorithms/detail/disjoint/linear_areal.hpp b/boost/geometry/algorithms/detail/disjoint/linear_areal.hpp index 0a1513fbed..8d71dd2e34 100644 --- a/boost/geometry/algorithms/detail/disjoint/linear_areal.hpp +++ b/boost/geometry/algorithms/detail/disjoint/linear_areal.hpp @@ -5,11 +5,12 @@ // Copyright (c) 2009-2014 Mateusz Loskot, London, UK. // Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland. -// This file was modified by Oracle on 2013-2021. -// Modifications copyright (c) 2013-2021, Oracle and/or its affiliates. +// This file was modified by Oracle on 2013-2022. +// Modifications copyright (c) 2013-2022, Oracle and/or its affiliates. -// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle +// 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. @@ -36,11 +37,10 @@ #include <boost/geometry/core/tag_cast.hpp> #include <boost/geometry/core/tags.hpp> -#include <boost/geometry/algorithms/covered_by.hpp> +#include <boost/geometry/algorithms/detail/covered_by/implementation.hpp> #include <boost/geometry/algorithms/not_implemented.hpp> #include <boost/geometry/algorithms/detail/assign_indexed_point.hpp> -#include <boost/geometry/algorithms/detail/check_iterator_range.hpp> #include <boost/geometry/algorithms/detail/point_on_border.hpp> #include <boost/geometry/algorithms/detail/disjoint/linear_linear.hpp> @@ -51,6 +51,7 @@ #include <boost/geometry/algorithms/dispatch/disjoint.hpp> +#include <boost/geometry/geometries/helper_geometry.hpp> namespace boost { namespace geometry { @@ -70,8 +71,8 @@ struct disjoint_no_intersections_policy template <typename Strategy> static inline bool apply(Geometry1 const& g1, Geometry2 const& g2, Strategy const& strategy) { - typedef typename point_type<Geometry1>::type point1_type; - point1_type p; + using point_type = typename point_type<Geometry1>::type; + typename helper_geometry<point_type>::type p; geometry::point_on_border(p, g1); return ! geometry::covered_by(p, g2, strategy); @@ -88,12 +89,11 @@ struct disjoint_no_intersections_policy<Geometry1, Geometry2, Tag1, multi_tag> static inline bool apply(Geometry1 const& g1, Geometry2 const& g2, Strategy const& strategy) { // TODO: use partition or rtree on g2 - typedef typename boost::range_iterator<Geometry1 const>::type iterator; - for ( iterator it = boost::begin(g1) ; it != boost::end(g1) ; ++it ) + for (auto it = boost::begin(g1); it != boost::end(g1); ++it) { typedef typename boost::range_value<Geometry1 const>::type value_type; - if ( ! disjoint_no_intersections_policy<value_type const, Geometry2> - ::apply(*it, g2, strategy) ) + if (! disjoint_no_intersections_policy<value_type const, Geometry2> + ::apply(*it, g2, strategy)) { return false; } @@ -141,28 +141,25 @@ struct disjoint_segment_areal template <typename Segment, typename Polygon> class disjoint_segment_areal<Segment, Polygon, polygon_tag> { -private: + template <typename InteriorRings, typename Strategy> static inline bool check_interior_rings(InteriorRings const& interior_rings, Segment const& segment, Strategy const& strategy) { - typedef typename boost::range_value<InteriorRings>::type ring_type; + using ring_type = typename boost::range_value<InteriorRings>::type; - typedef unary_disjoint_geometry_to_query_geometry + using unary_predicate_type = unary_disjoint_geometry_to_query_geometry < Segment, Strategy, disjoint_range_segment_or_box<ring_type, Segment> - > unary_predicate_type; - - return check_iterator_range - < - unary_predicate_type - >::apply(boost::begin(interior_rings), - boost::end(interior_rings), - unary_predicate_type(segment, strategy)); + >; + + return std::all_of(boost::begin(interior_rings), + boost::end(interior_rings), + unary_predicate_type(segment, strategy)); } diff --git a/boost/geometry/algorithms/detail/disjoint/linear_linear.hpp b/boost/geometry/algorithms/detail/disjoint/linear_linear.hpp index fc8e6a3511..00a6bff82d 100644 --- a/boost/geometry/algorithms/detail/disjoint/linear_linear.hpp +++ b/boost/geometry/algorithms/detail/disjoint/linear_linear.hpp @@ -33,6 +33,8 @@ #include <boost/geometry/algorithms/detail/overlay/do_reverse.hpp> #include <boost/geometry/algorithms/detail/overlay/segment_as_subrange.hpp> +#include <boost/geometry/geometries/helper_geometry.hpp> + #include <boost/geometry/policies/disjoint_interrupt_policy.hpp> #include <boost/geometry/policies/robustness/no_rescale_policy.hpp> @@ -91,20 +93,21 @@ struct disjoint_linear Geometry2 const& geometry2, Strategy const& strategy) { - typedef typename geometry::point_type<Geometry1>::type point_type; - typedef geometry::segment_ratio + using point_type = typename geometry::point_type<Geometry1>::type; + using mutable_point_type = typename helper_geometry<point_type>::type; + using ratio_type = geometry::segment_ratio < typename coordinate_type<point_type>::type - > ratio_type; - typedef overlay::turn_info + > ; + using turn_info_type = overlay::turn_info < - point_type, + mutable_point_type, ratio_type, typename detail::get_turns::turn_operation_type < - Geometry1, Geometry2, ratio_type + Geometry1, Geometry2, mutable_point_type, ratio_type >::type - > turn_info_type; + >; std::deque<turn_info_type> turns; diff --git a/boost/geometry/algorithms/detail/disjoint/multipoint_geometry.hpp b/boost/geometry/algorithms/detail/disjoint/multipoint_geometry.hpp index 9e3a57a29e..535c9006b5 100644 --- a/boost/geometry/algorithms/detail/disjoint/multipoint_geometry.hpp +++ b/boost/geometry/algorithms/detail/disjoint/multipoint_geometry.hpp @@ -2,7 +2,9 @@ // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland. -// Copyright (c) 2014-2020, Oracle and/or its affiliates. +// Copyright (c) 2014-2023, 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 @@ -31,7 +33,6 @@ #include <boost/geometry/algorithms/envelope.hpp> #include <boost/geometry/algorithms/expand.hpp> -#include <boost/geometry/algorithms/detail/check_iterator_range.hpp> #include <boost/geometry/algorithms/detail/partition.hpp> #include <boost/geometry/algorithms/detail/disjoint/box_box.hpp> #include <boost/geometry/algorithms/detail/disjoint/multirange_geometry.hpp> @@ -62,25 +63,25 @@ namespace detail { namespace disjoint class multipoint_multipoint { private: - template <typename Iterator, typename CSTag> - class unary_disjoint_predicate - : geometry::less<void, -1, CSTag> + template <typename Iterator, typename Strategy> + class unary_not_disjoint_predicate + : geometry::less<void, -1, Strategy> { private: - typedef geometry::less<void, -1, CSTag> base_type; + using less_type = geometry::less<void, -1, Strategy>; public: - unary_disjoint_predicate(Iterator first, Iterator last) - : base_type(), m_first(first), m_last(last) + unary_not_disjoint_predicate(Iterator first, Iterator last) + : less_type(), m_first(first), m_last(last) {} template <typename Point> - inline bool apply(Point const& point) const + inline bool operator()(Point const& point) const { - return !std::binary_search(m_first, - m_last, - point, - static_cast<base_type const&>(*this)); + return std::binary_search(m_first, + m_last, + point, + static_cast<less_type const&>(*this)); } private: @@ -93,30 +94,25 @@ public: MultiPoint2 const& multipoint2, Strategy const&) { - typedef typename Strategy::cs_tag cs_tag; - typedef geometry::less<void, -1, cs_tag> less_type; - BOOST_GEOMETRY_ASSERT( boost::size(multipoint1) <= boost::size(multipoint2) ); - typedef typename boost::range_value<MultiPoint1>::type point1_type; + using less_type = geometry::less<void, -1, Strategy>; + using point1_type = typename boost::range_value<MultiPoint1>::type; std::vector<point1_type> points1(boost::begin(multipoint1), boost::end(multipoint1)); std::sort(points1.begin(), points1.end(), less_type()); - typedef unary_disjoint_predicate + using predicate_type = unary_not_disjoint_predicate < typename std::vector<point1_type>::const_iterator, - cs_tag - > predicate_type; + Strategy + >; - return check_iterator_range - < - predicate_type - >::apply(boost::begin(multipoint2), - boost::end(multipoint2), - predicate_type(points1.begin(), points1.end())); + return none_of(boost::begin(multipoint2), + boost::end(multipoint2), + predicate_type(points1.begin(), points1.end())); } }; @@ -289,13 +285,12 @@ public: typedef typename point_type<MultiPoint>::type point1_type; typedef typename point_type<SingleGeometry>::type point2_type; typedef model::box<point2_type> box2_type; - + box2_type box2; geometry::envelope(single_geometry, box2, strategy); geometry::detail::expand_by_epsilon(box2); - typedef typename boost::range_const_iterator<MultiPoint>::type iterator; - for ( iterator it = boost::begin(multi_point) ; it != boost::end(multi_point) ; ++it ) + for (auto 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, strategy) @@ -434,7 +429,7 @@ public: typedef model::box<point1_type> box1_type; typedef model::box<point2_type> box2_type; typedef std::pair<box2_type, std::size_t> box_pair_type; - + std::size_t count2 = boost::size(multi_geometry); std::vector<box_pair_type> boxes(count2); for (std::size_t i = 0 ; i < count2 ; ++i) @@ -533,7 +528,7 @@ struct disjoint { return detail::disjoint::multipoint_multipoint ::apply(multipoint2, multipoint1, strategy); - } + } return detail::disjoint::multipoint_multipoint ::apply(multipoint1, multipoint2, strategy); diff --git a/boost/geometry/algorithms/detail/disjoint/multirange_geometry.hpp b/boost/geometry/algorithms/detail/disjoint/multirange_geometry.hpp index 51945551bb..2dccbae934 100644 --- a/boost/geometry/algorithms/detail/disjoint/multirange_geometry.hpp +++ b/boost/geometry/algorithms/detail/disjoint/multirange_geometry.hpp @@ -1,7 +1,8 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014-2020, Oracle and/or its affiliates. +// Copyright (c) 2014-2023, 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 @@ -11,12 +12,12 @@ #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_MULTIRANGE_GEOMETRY_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_MULTIRANGE_GEOMETRY_HPP +#include <algorithm> #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/range/value_type.hpp> -#include <boost/geometry/algorithms/detail/check_iterator_range.hpp> #include <boost/geometry/algorithms/dispatch/disjoint.hpp> @@ -34,13 +35,13 @@ class unary_disjoint_geometry_to_query_geometry { public: unary_disjoint_geometry_to_query_geometry(Geometry const& geometry, - Strategy const& strategy) + Strategy const& strategy) : m_geometry(geometry) , m_strategy(strategy) {} template <typename QueryGeometry> - inline bool apply(QueryGeometry const& query_geometry) const + inline bool operator()(QueryGeometry const& query_geometry) const { return BinaryPredicate::apply(query_geometry, m_geometry, m_strategy); } @@ -59,7 +60,7 @@ struct multirange_constant_size_geometry ConstantSizeGeometry const& constant_size_geometry, Strategy const& strategy) { - typedef unary_disjoint_geometry_to_query_geometry + using disjoint = unary_disjoint_geometry_to_query_geometry < ConstantSizeGeometry, Strategy, @@ -68,13 +69,11 @@ struct multirange_constant_size_geometry typename boost::range_value<MultiRange>::type, ConstantSizeGeometry > - > unary_predicate_type; + >; - return detail::check_iterator_range - < - unary_predicate_type - >::apply(boost::begin(multirange), boost::end(multirange), - unary_predicate_type(constant_size_geometry, strategy)); + return std::all_of(boost::begin(multirange), + boost::end(multirange), + disjoint(constant_size_geometry, strategy)); } template <typename Strategy> diff --git a/boost/geometry/algorithms/detail/disjoint/point_geometry.hpp b/boost/geometry/algorithms/detail/disjoint/point_geometry.hpp index 66bd7c26ce..4e22ac3a00 100644 --- a/boost/geometry/algorithms/detail/disjoint/point_geometry.hpp +++ b/boost/geometry/algorithms/detail/disjoint/point_geometry.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. -// Modifications copyright (c) 2013-2015, Oracle and/or its affiliates. +// This file was modified by Oracle on 2013-2022. +// Modifications copyright (c) 2013-2022, 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,7 +21,7 @@ #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_POINT_GEOMETRY_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_POINT_GEOMETRY_HPP -#include <boost/geometry/algorithms/covered_by.hpp> +#include <boost/geometry/algorithms/detail/covered_by/implementation.hpp> #include <boost/geometry/algorithms/detail/disjoint/linear_linear.hpp> diff --git a/boost/geometry/algorithms/detail/disjoint/segment_box.hpp b/boost/geometry/algorithms/detail/disjoint/segment_box.hpp index f6ba272690..1f2d669e53 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-2020. -// Modifications copyright (c) 2013-2020, Oracle and/or its affiliates. +// This file was modified by Oracle on 2013-2021. +// Modifications copyright (c) 2013-2021, 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 @@ -33,7 +33,6 @@ #include <boost/geometry/algorithms/detail/envelope/segment.hpp> #include <boost/geometry/algorithms/detail/normalize.hpp> #include <boost/geometry/algorithms/dispatch/disjoint.hpp> -#include <boost/geometry/algorithms/envelope.hpp> #include <boost/geometry/formulas/vertex_longitude.hpp> diff --git a/boost/geometry/algorithms/detail/distance/geometry_collection.hpp b/boost/geometry/algorithms/detail/distance/geometry_collection.hpp new file mode 100644 index 0000000000..f230958437 --- /dev/null +++ b/boost/geometry/algorithms/detail/distance/geometry_collection.hpp @@ -0,0 +1,237 @@ +// Boost.Geometry + +// Copyright (c) 2021 Oracle and/or its affiliates. +// 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_GEOMETRY_COLLECTION_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_GEOMETRY_COLLECTION_HPP + + +#include <vector> + +#include <boost/geometry/algorithms/dispatch/distance.hpp> +#include <boost/geometry/algorithms/detail/visit.hpp> +#include <boost/geometry/core/assert.hpp> +#include <boost/geometry/core/point_type.hpp> +#include <boost/geometry/index/rtree.hpp> +#include <boost/geometry/strategies/distance.hpp> +#include <boost/geometry/strategies/distance_result.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace distance +{ + + +template <typename Geometry, typename GeometryCollection, typename Strategies> +inline auto geometry_to_collection(Geometry const& geometry, + GeometryCollection const& collection, + Strategies const& strategies) +{ + using result_t = typename geometry::distance_result<Geometry, GeometryCollection, Strategies>::type; + result_t result = 0; + bool is_first = true; + detail::visit_breadth_first([&](auto const& g) + { + result_t r = dispatch::distance + < + Geometry, util::remove_cref_t<decltype(g)>, Strategies + >::apply(geometry, g, strategies); + if (is_first) + { + result = r; + is_first = false; + } + else if (r < result) + { + result = r; + } + return result > result_t(0); + }, collection); + + return result; +} + +template <typename GeometryCollection1, typename GeometryCollection2, typename Strategies> +inline auto collection_to_collection(GeometryCollection1 const& collection1, + GeometryCollection2 const& collection2, + Strategies const& strategies) +{ + using result_t = typename geometry::distance_result<GeometryCollection1, GeometryCollection2, Strategies>::type; + + using point1_t = typename geometry::point_type<GeometryCollection1>::type; + using box1_t = model::box<point1_t>; + using point2_t = typename geometry::point_type<GeometryCollection2>::type; + using box2_t = model::box<point2_t>; + + using rtree_value_t = std::pair<box1_t, typename boost::range_iterator<GeometryCollection1 const>::type>; + using rtree_params_t = index::parameters<index::rstar<4>, Strategies>; + using rtree_t = index::rtree<rtree_value_t, rtree_params_t>; + + rtree_params_t rtree_params(index::rstar<4>(), strategies); + rtree_t rtree(rtree_params); + + // Build rtree of boxes and iterators of elements of GC1 + // TODO: replace this with visit_breadth_first_iterator to avoid creating an unnecessary container? + { + std::vector<rtree_value_t> values; + visit_breadth_first_impl<true>::apply([&](auto & g1, auto it) + { + box1_t b1 = geometry::return_envelope<box1_t>(g1, strategies); + geometry::detail::expand_by_epsilon(b1); + values.emplace_back(b1, it); + return true; + }, collection1); + rtree_t rt(values.begin(), values.end(), rtree_params); + rtree = std::move(rt); + } + + result_t const zero = 0; + auto const rtree_qend = rtree.qend(); + + result_t result = 0; + bool is_first = true; + visit_breadth_first([&](auto const& g2) + { + box2_t b2 = geometry::return_envelope<box2_t>(g2, strategies); + geometry::detail::expand_by_epsilon(b2); + + for (auto it = rtree.qbegin(index::nearest(b2, rtree.size())) ; it != rtree_qend ; ++it) + { + // If the distance between boxes is greater than or equal to previously found + // distance between geometries then stop processing the current b2 because no + // closer b1 will be found + if (! is_first) + { + result_t const bd = dispatch::distance + < + box1_t, box2_t, Strategies + >::apply(it->first, b2, strategies); + if (bd >= result) + { + break; + } + } + + // Boxes are closer than the previously found distance (or it's the first time), + // calculate the new distance between geometries and check if it's closer (or assign it). + traits::iter_visit<GeometryCollection1>::apply([&](auto const& g1) + { + result_t const d = dispatch::distance + < + util::remove_cref_t<decltype(g1)>, util::remove_cref_t<decltype(g2)>, + Strategies + >::apply(g1, g2, strategies); + if (is_first) + { + result = d; + is_first = false; + } + else if (d < result) + { + result = d; + } + }, it->second); + + // The smallest possible distance found, end searching. + if (! is_first && result <= zero) + { + return false; + } + } + + // Just in case + return is_first || result > zero; + }, collection2); + + return result; +} + + +}} // namespace detail::distance +#endif // DOXYGEN_NO_DETAIL + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +template +< + typename Geometry, typename GeometryCollection, typename Strategies, typename Tag1 +> +struct distance + < + Geometry, GeometryCollection, Strategies, + Tag1, geometry_collection_tag, void, false + > +{ + static inline auto apply(Geometry const& geometry, + GeometryCollection const& collection, + Strategies const& strategies) + { + assert_dimension_equal<Geometry, GeometryCollection>(); + + return detail::distance::geometry_to_collection(geometry, collection, strategies); + } +}; + +template +< + typename GeometryCollection, typename Geometry, typename Strategies, typename Tag2 +> +struct distance + < + GeometryCollection, Geometry, Strategies, + geometry_collection_tag, Tag2, void, false + > +{ + static inline auto apply(GeometryCollection const& collection, + Geometry const& geometry, + Strategies const& strategies) + { + assert_dimension_equal<Geometry, GeometryCollection>(); + + return detail::distance::geometry_to_collection(geometry, collection, strategies); + } +}; + +template +< + typename GeometryCollection1, typename GeometryCollection2, typename Strategies +> +struct distance + < + GeometryCollection1, GeometryCollection2, Strategies, + geometry_collection_tag, geometry_collection_tag, void, false + > +{ + static inline auto apply(GeometryCollection1 const& collection1, + GeometryCollection2 const& collection2, + Strategies const& strategies) + { + assert_dimension_equal<GeometryCollection1, GeometryCollection2>(); + + // Build the rtree for the smaller GC (ignoring recursive GCs) + return boost::size(collection1) <= boost::size(collection2) + ? detail::distance::collection_to_collection(collection1, collection2, strategies) + : detail::distance::collection_to_collection(collection2, collection1, strategies); + } +}; + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_SEGMENT_TO_BOX_HPP diff --git a/boost/geometry/algorithms/detail/distance/geometry_to_segment_or_box.hpp b/boost/geometry/algorithms/detail/distance/geometry_to_segment_or_box.hpp index 6a852ec43f..5af854f901 100644 --- a/boost/geometry/algorithms/detail/distance/geometry_to_segment_or_box.hpp +++ b/boost/geometry/algorithms/detail/distance/geometry_to_segment_or_box.hpp @@ -54,7 +54,7 @@ template > struct segment_or_box_point_range_closure : not_implemented<SegmentOrBox> -{}; +{}; template <typename Segment> struct segment_or_box_point_range_closure<Segment, segment_tag> @@ -163,17 +163,11 @@ public: Strategies const& strategies, bool check_intersection = true) { - typedef geometry::point_iterator<Geometry const> point_iterator_type; typedef geometry::segment_iterator < Geometry const > segment_iterator_type; - typedef typename boost::range_const_iterator - < - std::vector<segment_or_box_point> - >::type seg_or_box_const_iterator; - typedef assign_new_min_iterator<SegmentOrBox> assign_new_value; @@ -196,32 +190,27 @@ public: assign_segment_or_box_points < - SegmentOrBox, + SegmentOrBox, std::vector<segment_or_box_point> >::apply(segment_or_box, seg_or_box_points); // consider all distances of the points in the geometry to the // segment or box comparable_return_type cd_min1(0); - point_iterator_type pit_min; - seg_or_box_const_iterator it_min1 = boost::const_begin(seg_or_box_points); - seg_or_box_const_iterator it_min2 = it_min1; - ++it_min2; + auto pit_min = points_begin(geometry); + auto it_min1 = boost::const_begin(seg_or_box_points); + auto it_min2 = it_min1 + 1; bool first = true; - for (point_iterator_type pit = points_begin(geometry); + for (auto pit = pit_min; pit != points_end(geometry); ++pit, first = false) { comparable_return_type cd; - std::pair - < - seg_or_box_const_iterator, seg_or_box_const_iterator - > it_pair - = point_to_point_range::apply(*pit, - boost::const_begin(seg_or_box_points), - boost::const_end(seg_or_box_points), - cstrategy, - cd); + auto it_pair = point_to_point_range::apply(*pit, + boost::const_begin(seg_or_box_points), + boost::const_end(seg_or_box_points), + cstrategy, + cd); if (first || cd < cd_min1) { @@ -236,10 +225,10 @@ public: // segments of the geometry comparable_return_type cd_min2(0); segment_iterator_type sit_min; - seg_or_box_const_iterator it_min; + auto it_min = boost::const_begin(seg_or_box_points); first = true; - for (seg_or_box_const_iterator it = boost::const_begin(seg_or_box_points); + for (auto it = boost::const_begin(seg_or_box_points); it != boost::const_end(seg_or_box_points); ++it, first = false) { comparable_return_type cd; @@ -282,7 +271,7 @@ public: } - static inline return_type apply(SegmentOrBox const& segment_or_box, Geometry const& geometry, + static inline return_type apply(SegmentOrBox const& segment_or_box, Geometry const& geometry, Strategies const& strategies, bool check_intersection = true) { return apply(geometry, segment_or_box, strategies, check_intersection); @@ -299,14 +288,7 @@ class geometry_to_segment_or_box { private: typedef detail::closest_feature::geometry_to_range base_type; - - typedef typename boost::range_iterator - < - MultiPoint const - >::type iterator_type; - typedef detail::closest_feature::geometry_to_range geometry_to_range; - typedef distance::strategy_t<MultiPoint, SegmentOrBox, Strategies> strategy_type; public: @@ -318,7 +300,7 @@ public: { distance::creturn_t<MultiPoint, SegmentOrBox, Strategies> cd_min; - iterator_type it_min + auto const it_min = geometry_to_range::apply(segment_or_box, boost::begin(multipoint), boost::end(multipoint), diff --git a/boost/geometry/algorithms/detail/distance/implementation.hpp b/boost/geometry/algorithms/detail/distance/implementation.hpp index 91b1d817b3..8dfe4fec7e 100644 --- a/boost/geometry/algorithms/detail/distance/implementation.hpp +++ b/boost/geometry/algorithms/detail/distance/implementation.hpp @@ -7,9 +7,9 @@ // This file was modified by Oracle on 2014-2021. // Modifications copyright (c) 2014-2021, 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. @@ -27,6 +27,7 @@ #include <boost/geometry/algorithms/detail/distance/linear_to_linear.hpp> #include <boost/geometry/algorithms/detail/distance/linear_or_areal_to_areal.hpp> #include <boost/geometry/algorithms/detail/distance/linear_to_box.hpp> +#include <boost/geometry/algorithms/detail/distance/geometry_collection.hpp> #include <boost/geometry/algorithms/detail/distance/geometry_to_segment_or_box.hpp> #include <boost/geometry/algorithms/detail/distance/segment_to_segment.hpp> #include <boost/geometry/algorithms/detail/distance/segment_to_box.hpp> diff --git a/boost/geometry/algorithms/detail/distance/interface.hpp b/boost/geometry/algorithms/detail/distance/interface.hpp index f39f505544..5fdb66beaf 100644 --- a/boost/geometry/algorithms/detail/distance/interface.hpp +++ b/boost/geometry/algorithms/detail/distance/interface.hpp @@ -8,7 +8,6 @@ // This file was modified by Oracle on 2014-2021. // Modifications copyright (c) 2014-2021, 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 @@ -28,6 +27,7 @@ #include <boost/geometry/algorithms/dispatch/distance.hpp> #include <boost/geometry/core/point_type.hpp> +#include <boost/geometry/core/visit.hpp> #include <boost/geometry/geometries/adapted/boost_variant.hpp> // For backward compatibility #include <boost/geometry/geometries/concepts/check.hpp> @@ -92,10 +92,9 @@ template struct distance { template <typename Geometry1, typename Geometry2> - static inline typename distance_result<Geometry1, Geometry2, Strategy>::type - apply(Geometry1 const& geometry1, - Geometry2 const& geometry2, - Strategy const& strategy) + static inline auto apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Strategy const& strategy) { return dispatch::distance < @@ -123,11 +122,9 @@ struct distance<Strategy, false> typename Geometry1, typename Geometry2, typename S, std::enable_if_t<is_strategy_converter_specialized<S>::value, int> = 0 > - static inline - typename distance_result<Geometry1, Geometry2, S>::type - apply(Geometry1 const& geometry1, - Geometry2 const& geometry2, - S const& strategy) + static inline auto apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + S const& strategy) { typedef strategies::distance::services::strategy_converter<Strategy> converter; typedef decltype(converter::get(strategy)) strategy_type; @@ -143,11 +140,9 @@ struct distance<Strategy, false> typename Geometry1, typename Geometry2, typename S, std::enable_if_t<! is_strategy_converter_specialized<S>::value, int> = 0 > - static inline - typename distance_result<Geometry1, Geometry2, S>::type - apply(Geometry1 const& geometry1, - Geometry2 const& geometry2, - S const& strategy) + static inline auto apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + S const& strategy) { typedef strategies::distance::services::custom_strategy_converter < @@ -166,11 +161,9 @@ template <> struct distance<default_strategy, false> { template <typename Geometry1, typename Geometry2> - static inline - typename distance_result<Geometry1, Geometry2, default_strategy>::type - apply(Geometry1 const& geometry1, - Geometry2 const& geometry2, - default_strategy) + static inline auto apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + default_strategy) { typedef typename strategies::distance::services::default_strategy < @@ -187,18 +180,22 @@ struct distance<default_strategy, false> } // namespace resolve_strategy -namespace resolve_variant +namespace resolve_dynamic { -template <typename Geometry1, typename Geometry2> +template +< + typename Geometry1, typename Geometry2, + typename Tag1 = typename geometry::tag<Geometry1>::type, + typename Tag2 = typename geometry::tag<Geometry2>::type +> struct distance { template <typename Strategy> - static inline typename distance_result<Geometry1, Geometry2, Strategy>::type - apply(Geometry1 const& geometry1, - Geometry2 const& geometry2, - Strategy const& strategy) + static inline auto apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Strategy const& strategy) { return resolve_strategy::distance < @@ -208,174 +205,72 @@ struct distance }; -template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2> -struct distance<variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2> +template <typename DynamicGeometry1, typename Geometry2, typename Tag2> +struct distance<DynamicGeometry1, Geometry2, dynamic_geometry_tag, Tag2> { template <typename Strategy> - struct visitor: static_visitor - < - typename distance_result - < - variant<BOOST_VARIANT_ENUM_PARAMS(T)>, - Geometry2, - Strategy - >::type - > + static inline auto apply(DynamicGeometry1 const& geometry1, + Geometry2 const& geometry2, + Strategy const& strategy) { - Geometry2 const& m_geometry2; - Strategy const& m_strategy; - - visitor(Geometry2 const& geometry2, - Strategy const& strategy) - : m_geometry2(geometry2), - m_strategy(strategy) - {} - - template <typename Geometry1> - typename distance_result<Geometry1, Geometry2, Strategy>::type - operator()(Geometry1 const& geometry1) const + using result_t = typename geometry::distance_result<DynamicGeometry1, Geometry2, Strategy>::type; + result_t result = 0; + traits::visit<DynamicGeometry1>::apply([&](auto const& g1) { - return distance - < - Geometry1, - Geometry2 - >::template apply - < - Strategy - >(geometry1, m_geometry2, m_strategy); - } - }; - - template <typename Strategy> - static inline typename distance_result - < - variant<BOOST_VARIANT_ENUM_PARAMS(T)>, - Geometry2, - Strategy - >::type - apply(variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1, - Geometry2 const& geometry2, - Strategy const& strategy) - { - return boost::apply_visitor(visitor<Strategy>(geometry2, strategy), geometry1); + result = resolve_strategy::distance + < + Strategy + >::apply(g1, geometry2, strategy); + }, geometry1); + return result; } }; -template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)> -struct distance<Geometry1, variant<BOOST_VARIANT_ENUM_PARAMS(T)> > +template <typename Geometry1, typename DynamicGeometry2, typename Tag1> +struct distance<Geometry1, DynamicGeometry2, Tag1, dynamic_geometry_tag> { template <typename Strategy> - struct visitor: static_visitor - < - typename distance_result - < - Geometry1, - variant<BOOST_VARIANT_ENUM_PARAMS(T)>, - Strategy - >::type - > + static inline auto apply(Geometry1 const& geometry1, + DynamicGeometry2 const& geometry2, + Strategy const& strategy) { - Geometry1 const& m_geometry1; - Strategy const& m_strategy; - - visitor(Geometry1 const& geometry1, - Strategy const& strategy) - : m_geometry1(geometry1), - m_strategy(strategy) - {} - - template <typename Geometry2> - typename distance_result<Geometry1, Geometry2, Strategy>::type - operator()(Geometry2 const& geometry2) const + using result_t = typename geometry::distance_result<Geometry1, DynamicGeometry2, Strategy>::type; + result_t result = 0; + traits::visit<DynamicGeometry2>::apply([&](auto const& g2) { - return distance - < - Geometry1, - Geometry2 - >::template apply - < - Strategy - >(m_geometry1, geometry2, m_strategy); - } - }; - - template <typename Strategy> - static inline typename distance_result - < - Geometry1, - variant<BOOST_VARIANT_ENUM_PARAMS(T)>, - Strategy - >::type - apply( - Geometry1 const& geometry1, - const variant<BOOST_VARIANT_ENUM_PARAMS(T)>& geometry2, - Strategy const& strategy) - { - return boost::apply_visitor(visitor<Strategy>(geometry1, strategy), geometry2); + result = resolve_strategy::distance + < + Strategy + >::apply(geometry1, g2, strategy); + }, geometry2); + return result; } }; -template -< - BOOST_VARIANT_ENUM_PARAMS(typename T1), - BOOST_VARIANT_ENUM_PARAMS(typename T2) -> -struct distance - < - boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>, - boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> - > +template <typename DynamicGeometry1, typename DynamicGeometry2> +struct distance<DynamicGeometry1, DynamicGeometry2, dynamic_geometry_tag, dynamic_geometry_tag> { template <typename Strategy> - struct visitor: static_visitor - < - typename distance_result - < - boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>, - boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)>, - Strategy - >::type - > + static inline auto apply(DynamicGeometry1 const& geometry1, + DynamicGeometry2 const& geometry2, + Strategy const& strategy) { - Strategy const& m_strategy; - - visitor(Strategy const& strategy) - : m_strategy(strategy) - {} - - template <typename Geometry1, typename Geometry2> - typename distance_result<Geometry1, Geometry2, Strategy>::type - operator()(Geometry1 const& geometry1, Geometry2 const& geometry2) const + using result_t = typename geometry::distance_result<DynamicGeometry1, DynamicGeometry2, Strategy>::type; + result_t result = 0; + traits::visit<DynamicGeometry1, DynamicGeometry2>::apply([&](auto const& g1, auto const& g2) { - return distance - < - Geometry1, - Geometry2 - >::template apply - < - Strategy - >(geometry1, geometry2, m_strategy); - } - }; - - template <typename Strategy> - static inline typename distance_result - < - boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>, - boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)>, - Strategy - >::type - apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1, - boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2, - Strategy const& strategy) - { - return boost::apply_visitor(visitor<Strategy>(strategy), geometry1, geometry2); + result = resolve_strategy::distance + < + Strategy + >::apply(g1, g2, strategy); + }, geometry1, geometry2); + return result; } }; -} // namespace resolve_variant +} // namespace resolve_dynamic /*! @@ -415,10 +310,9 @@ for distance, it is probably so that there is no specialization for return_type<...> for your strategy. */ template <typename Geometry1, typename Geometry2, typename Strategy> -inline typename distance_result<Geometry1, Geometry2, Strategy>::type -distance(Geometry1 const& geometry1, - Geometry2 const& geometry2, - Strategy const& strategy) +inline auto distance(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Strategy const& strategy) { concepts::check<Geometry1 const>(); concepts::check<Geometry2 const>(); @@ -426,7 +320,7 @@ distance(Geometry1 const& geometry1, detail::throw_on_empty_input(geometry1); detail::throw_on_empty_input(geometry2); - return resolve_variant::distance + return resolve_dynamic::distance < Geometry1, Geometry2 @@ -448,13 +342,9 @@ distance(Geometry1 const& geometry1, \qbk{[include reference/algorithms/distance.qbk]} */ template <typename Geometry1, typename Geometry2> -inline typename default_distance_result<Geometry1, Geometry2>::type -distance(Geometry1 const& geometry1, - Geometry2 const& geometry2) +inline auto distance(Geometry1 const& geometry1, + Geometry2 const& geometry2) { - concepts::check<Geometry1 const>(); - concepts::check<Geometry2 const>(); - return geometry::distance(geometry1, geometry2, default_strategy()); } diff --git a/boost/geometry/algorithms/detail/distance/linear_or_areal_to_areal.hpp b/boost/geometry/algorithms/detail/distance/linear_or_areal_to_areal.hpp index e4cb41a358..dc1f4786b5 100644 --- a/boost/geometry/algorithms/detail/distance/linear_or_areal_to_areal.hpp +++ b/boost/geometry/algorithms/detail/distance/linear_or_areal_to_areal.hpp @@ -91,7 +91,7 @@ template <typename Linear, typename Areal, typename Strategy> struct distance < Linear, Areal, Strategy, - linear_tag, areal_tag, + linear_tag, areal_tag, strategy_tag_distance_point_segment, false > : detail::distance::linear_to_areal @@ -104,7 +104,7 @@ template <typename Areal, typename Linear, typename Strategy> struct distance < Areal, Linear, Strategy, - areal_tag, linear_tag, + areal_tag, linear_tag, strategy_tag_distance_point_segment, false > : detail::distance::linear_to_areal @@ -118,7 +118,7 @@ template <typename Areal1, typename Areal2, typename Strategy> struct distance < Areal1, Areal2, Strategy, - areal_tag, areal_tag, + areal_tag, areal_tag, strategy_tag_distance_point_segment, false > : detail::distance::areal_to_areal diff --git a/boost/geometry/algorithms/detail/distance/linear_to_linear.hpp b/boost/geometry/algorithms/detail/distance/linear_to_linear.hpp index eb81133f61..0c3e68051b 100644 --- a/boost/geometry/algorithms/detail/distance/linear_to_linear.hpp +++ b/boost/geometry/algorithms/detail/distance/linear_to_linear.hpp @@ -102,7 +102,7 @@ template <typename Linear1, typename Linear2, typename Strategy, typename Strate struct distance < Linear1, Linear2, Strategy, - linear_tag, linear_tag, + linear_tag, linear_tag, StrategyTag, false > : detail::distance::linear_to_linear < diff --git a/boost/geometry/algorithms/detail/distance/multipoint_to_geometry.hpp b/boost/geometry/algorithms/detail/distance/multipoint_to_geometry.hpp index eabc9528db..58a9d5b283 100644 --- a/boost/geometry/algorithms/detail/distance/multipoint_to_geometry.hpp +++ b/boost/geometry/algorithms/detail/distance/multipoint_to_geometry.hpp @@ -1,7 +1,8 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014-2021 Oracle and/or its affiliates. +// Copyright (c) 2014-2021, 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 @@ -16,7 +17,6 @@ #include <boost/range/size.hpp> #include <boost/geometry/algorithms/covered_by.hpp> -#include <boost/geometry/algorithms/detail/check_iterator_range.hpp> #include <boost/geometry/algorithms/detail/distance/range_to_geometry_rtree.hpp> #include <boost/geometry/algorithms/detail/distance/strategy_utils.hpp> #include <boost/geometry/algorithms/dispatch/distance.hpp> @@ -46,7 +46,6 @@ struct multipoint_to_multipoint Strategies const& strategies) { if (boost::size(multipoint2) < boost::size(multipoint1)) - { return point_or_segment_range_to_geometry_rtree < @@ -103,16 +102,16 @@ template <typename MultiPoint, typename Areal, typename Strategies> class multipoint_to_areal { private: - struct not_covered_by_areal + struct covered_by_areal { - not_covered_by_areal(Areal const& areal, Strategies const& strategy) + covered_by_areal(Areal const& areal, Strategies const& strategy) : m_areal(areal), m_strategy(strategy) {} template <typename Point> - inline bool apply(Point const& point) const + inline bool operator()(Point const& point) const { - return !geometry::covered_by(point, m_areal, m_strategy); + return geometry::covered_by(point, m_areal, m_strategy); } Areal const& m_areal; @@ -126,14 +125,10 @@ public: Areal const& areal, Strategies const& strategies) { - not_covered_by_areal predicate(areal, strategies); + covered_by_areal predicate(areal, strategies); - if (check_iterator_range - < - not_covered_by_areal, false - >::apply(boost::begin(multipoint), - boost::end(multipoint), - predicate)) + if (! boost::empty(multipoint) && + std::none_of(boost::begin(multipoint), boost::end(multipoint), predicate)) { return detail::distance::point_or_segment_range_to_geometry_rtree < diff --git a/boost/geometry/algorithms/detail/distance/range_to_geometry_rtree.hpp b/boost/geometry/algorithms/detail/distance/range_to_geometry_rtree.hpp index b76955cb63..cd7c46ce71 100644 --- a/boost/geometry/algorithms/detail/distance/range_to_geometry_rtree.hpp +++ b/boost/geometry/algorithms/detail/distance/range_to_geometry_rtree.hpp @@ -95,7 +95,7 @@ public: : dispatch::distance < - point_or_segment_type, + point_or_segment_type, typename std::iterator_traits < typename selector_type::iterator_type diff --git a/boost/geometry/algorithms/detail/distance/segment_to_box.hpp b/boost/geometry/algorithms/detail/distance/segment_to_box.hpp index 354d42bd01..09f3cc4f61 100644 --- a/boost/geometry/algorithms/detail/distance/segment_to_box.hpp +++ b/boost/geometry/algorithms/detail/distance/segment_to_box.hpp @@ -1,6 +1,6 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014-2021 Oracle and/or its affiliates. +// Copyright (c) 2014-2023 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 @@ -91,7 +91,7 @@ private: std::vector<box_point>, open > point_to_point_range; - + public: // TODO: Or should the return type be defined by sb_strategy_type? typedef distance::return_t<box_point, Segment, Strategies> return_type; @@ -114,7 +114,7 @@ public: // get box points std::vector<box_point> box_points(4); detail::assign_box_corners_oriented<true>(box, box_points); - + ps_strategy_type const strategy = strategies.distance(dummy_point(), dummy_segment()); auto const cstrategy = strategy::distance::services::get_comparable @@ -192,7 +192,7 @@ private: public: // TODO: Or should the return type be defined by sb_strategy_type? typedef distance::return_t<box_point, Segment, Strategies> return_type; - + static inline return_type apply(Segment const& segment, Box const& box, Strategies const& strategies, @@ -658,7 +658,7 @@ public: BoxPoint const& bottom_right, Strategies const& strategies) { - BOOST_GEOMETRY_ASSERT( (geometry::less<SegmentPoint, -1, typename Strategies::cs_tag>()(p0, p1)) + BOOST_GEOMETRY_ASSERT( (geometry::less<SegmentPoint, -1, Strategies>()(p0, p1)) || geometry::has_nan_coordinate(p0) || geometry::has_nan_coordinate(p1) ); @@ -753,7 +753,7 @@ public: bottom_left, bottom_right, top_left, top_right); - typedef geometry::less<segment_point, -1, typename Strategies::cs_tag> less_type; + typedef geometry::less<segment_point, -1, Strategies> less_type; if (less_type()(p[0], p[1])) { return segment_to_box_2D diff --git a/boost/geometry/algorithms/detail/envelope/areal.hpp b/boost/geometry/algorithms/detail/envelope/areal.hpp index 3c9b5c576c..ece4d3d144 100644 --- a/boost/geometry/algorithms/detail/envelope/areal.hpp +++ b/boost/geometry/algorithms/detail/envelope/areal.hpp @@ -1,6 +1,6 @@ // Boost.Geometry -// Copyright (c) 2018 Oracle and/or its affiliates. +// Copyright (c) 2018-2021 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 @@ -22,6 +22,8 @@ #include <boost/geometry/algorithms/dispatch/envelope.hpp> +#include <boost/geometry/views/reversible_view.hpp> + namespace boost { namespace geometry { @@ -29,6 +31,24 @@ namespace boost { namespace geometry namespace detail { namespace envelope { + +struct envelope_hole +{ + template <typename Range, typename Box, typename Strategies> + static inline void apply(Range const& range, Box& mbr, Strategies const& strategies) + { + // Reverse holes to avoid calculating the envelope for the outside + // in spherical and geographic coordinate systems + detail::clockwise_view + < + Range const, + geometry::point_order<Range>::value == counterclockwise + ? clockwise : counterclockwise + > view(range); + strategies.envelope(range, mbr).apply(view, mbr); + } +}; + struct envelope_polygon { template <typename Polygon, typename Box, typename Strategy> @@ -39,11 +59,14 @@ struct envelope_polygon if (geometry::is_empty(ext_ring)) { + // use dummy multi polygon to get the strategy because there is no multi ring concept + using strategy_t = decltype(strategy.envelope(detail::dummy_multi_polygon(), + detail::dummy_box())); // if the exterior ring is empty, consider the interior rings envelope_multi_range < - envelope_range - >::apply(interior_rings(polygon), mbr, strategy); + envelope_hole + >::template apply<strategy_t>(interior_rings(polygon), mbr, strategy); } else { diff --git a/boost/geometry/algorithms/detail/envelope/geometry_collection.hpp b/boost/geometry/algorithms/detail/envelope/geometry_collection.hpp new file mode 100644 index 0000000000..979513da7e --- /dev/null +++ b/boost/geometry/algorithms/detail/envelope/geometry_collection.hpp @@ -0,0 +1,62 @@ +// Boost.Geometry + +// Copyright (c) 2021, Oracle and/or its affiliates. +// 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 +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_GEOMETRY_COLLECTION_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_GEOMETRY_COLLECTION_HPP + + +#include <boost/geometry/algorithms/detail/visit.hpp> +#include <boost/geometry/algorithms/dispatch/envelope.hpp> +#include <boost/geometry/algorithms/is_empty.hpp> + +#include <boost/geometry/core/tags.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +template <typename Collection> +struct envelope<Collection, geometry_collection_tag> +{ + template <typename Geometry, typename Box, typename Strategies> + static inline void apply(Geometry const& geometry, + Box& mbr, + Strategies const& strategies) + { + using strategy_t = decltype(strategies.envelope(geometry, mbr)); + + typename strategy_t::template state<Box> state; + detail::visit_breadth_first([&](auto const& g) + { + if (! geometry::is_empty(g)) + { + Box b; + envelope<util::remove_cref_t<decltype(g)>>::apply(g, b, strategies); + strategy_t::apply(state, b); + } + return true; + }, geometry); + strategy_t::result(state, mbr); + } +}; + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_GEOMETRY_COLLECTION_HPP diff --git a/boost/geometry/algorithms/detail/envelope/implementation.hpp b/boost/geometry/algorithms/detail/envelope/implementation.hpp index 569c77b036..cb4108d163 100644 --- a/boost/geometry/algorithms/detail/envelope/implementation.hpp +++ b/boost/geometry/algorithms/detail/envelope/implementation.hpp @@ -6,9 +6,9 @@ // This file was modified by Oracle on 2015-2021. // Modifications copyright (c) 2015-2021, 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. @@ -28,6 +28,7 @@ #include <boost/geometry/algorithms/detail/envelope/areal.hpp> #include <boost/geometry/algorithms/detail/envelope/box.hpp> +#include <boost/geometry/algorithms/detail/envelope/geometry_collection.hpp> #include <boost/geometry/algorithms/detail/envelope/linear.hpp> #include <boost/geometry/algorithms/detail/envelope/multipoint.hpp> #include <boost/geometry/algorithms/detail/envelope/point.hpp> diff --git a/boost/geometry/algorithms/detail/envelope/interface.hpp b/boost/geometry/algorithms/detail/envelope/interface.hpp index 3f6dece384..70679dd918 100644 --- a/boost/geometry/algorithms/detail/envelope/interface.hpp +++ b/boost/geometry/algorithms/detail/envelope/interface.hpp @@ -22,16 +22,14 @@ #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/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/core/visit.hpp> +#include <boost/geometry/geometries/adapted/boost_variant.hpp> // For backward compatibility #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/strategies/default_strategy.hpp> @@ -39,6 +37,7 @@ #include <boost/geometry/strategies/envelope/services.hpp> #include <boost/geometry/util/select_most_precise.hpp> +#include <boost/geometry/util/type_traits_std.hpp> namespace boost { namespace geometry @@ -98,10 +97,10 @@ struct envelope<default_strategy, false> } // namespace resolve_strategy -namespace resolve_variant +namespace resolve_dynamic { -template <typename Geometry> +template <typename Geometry, typename Tag = typename tag<Geometry>::type> struct envelope { template <typename Box, typename Strategy> @@ -117,38 +116,22 @@ struct envelope }; -template <BOOST_VARIANT_ENUM_PARAMS(typename T)> -struct envelope<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > +template <typename Geometry> +struct envelope<Geometry, dynamic_geometry_tag> { template <typename Box, typename Strategy> - struct visitor: boost::static_visitor<void> + static inline void apply(Geometry const& geometry, + Box& box, + Strategy const& strategy) { - Box& m_box; - Strategy const& m_strategy; - - visitor(Box& box, Strategy const& strategy) - : m_box(box) - , m_strategy(strategy) - {} - - template <typename Geometry> - void operator()(Geometry const& geometry) const + traits::visit<Geometry>::apply([&](auto const& g) { - envelope<Geometry>::apply(geometry, m_box, m_strategy); - } - }; - - template <typename Box, typename Strategy> - static inline void - apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry, - Box& box, - Strategy const& strategy) - { - boost::apply_visitor(visitor<Box, Strategy>(box, strategy), geometry); + envelope<util::remove_cref_t<decltype(g)>>::apply(g, box, strategy); + }, geometry); } }; -} // namespace resolve_variant +} // namespace resolve_dynamic /*! @@ -172,7 +155,7 @@ struct envelope<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > template<typename Geometry, typename Box, typename Strategy> inline void envelope(Geometry const& geometry, Box& mbr, Strategy const& strategy) { - resolve_variant::envelope<Geometry>::apply(geometry, mbr, strategy); + resolve_dynamic::envelope<Geometry>::apply(geometry, mbr, strategy); } /*! @@ -193,7 +176,7 @@ inline void envelope(Geometry const& geometry, Box& mbr, Strategy const& strateg template<typename Geometry, typename Box> inline void envelope(Geometry const& geometry, Box& mbr) { - resolve_variant::envelope<Geometry>::apply(geometry, mbr, default_strategy()); + resolve_dynamic::envelope<Geometry>::apply(geometry, mbr, default_strategy()); } @@ -219,7 +202,7 @@ template<typename Box, typename Geometry, typename Strategy> inline Box return_envelope(Geometry const& geometry, Strategy const& strategy) { Box mbr; - resolve_variant::envelope<Geometry>::apply(geometry, mbr, strategy); + resolve_dynamic::envelope<Geometry>::apply(geometry, mbr, strategy); return mbr; } @@ -242,7 +225,7 @@ template<typename Box, typename Geometry> inline Box return_envelope(Geometry const& geometry) { Box mbr; - resolve_variant::envelope<Geometry>::apply(geometry, mbr, default_strategy()); + resolve_dynamic::envelope<Geometry>::apply(geometry, mbr, default_strategy()); return mbr; } diff --git a/boost/geometry/algorithms/detail/envelope/intersects_antimeridian.hpp b/boost/geometry/algorithms/detail/envelope/intersects_antimeridian.hpp index 47937bf740..05127e0d23 100644 --- a/boost/geometry/algorithms/detail/envelope/intersects_antimeridian.hpp +++ b/boost/geometry/algorithms/detail/envelope/intersects_antimeridian.hpp @@ -19,7 +19,7 @@ #include <boost/geometry/algorithms/detail/normalize.hpp> -namespace boost { namespace geometry +namespace boost { namespace geometry { namespace detail { namespace envelope @@ -38,7 +38,7 @@ struct intersects_antimeridian < CoordinateType, Units > constants; - + return math::equals(math::abs(lat1), constants::max_latitude()) || diff --git a/boost/geometry/algorithms/detail/envelope/range.hpp b/boost/geometry/algorithms/detail/envelope/range.hpp index 068685b0ef..4692341e06 100644 --- a/boost/geometry/algorithms/detail/envelope/range.hpp +++ b/boost/geometry/algorithms/detail/envelope/range.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-2020. -// Modifications copyright (c) 2015-2020, Oracle and/or its affiliates. +// This file was modified by Oracle on 2015-2021. +// Modifications copyright (c) 2015-2021, 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 @@ -28,7 +28,7 @@ #include <boost/range/end.hpp> #include <boost/geometry/algorithms/is_empty.hpp> - +#include <boost/geometry/algorithms/detail/dummy_geometries.hpp> #include <boost/geometry/algorithms/detail/envelope/initialize.hpp> #include <boost/geometry/algorithms/detail/expand/box.hpp> #include <boost/geometry/algorithms/detail/expand/point.hpp> @@ -47,42 +47,10 @@ namespace detail { namespace envelope // implementation for simple ranges struct envelope_range { - template <typename Iterator, typename Box, typename Strategy> - static inline void apply(Iterator it, - Iterator last, - Box& mbr, - Strategy const& strategy) - { - typedef typename std::iterator_traits<Iterator>::value_type value_type; - - // initialize MBR - initialize<Box, 0, dimension<Box>::value>::apply(mbr); - - if (it != last) - { - // initialize box with first element in range - dispatch::envelope - < - value_type - >::apply(*it, mbr, 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); - } - } - } - - template <typename Range, typename Box, typename Strategy> - static inline void apply(Range const& range, Box& mbr, Strategy const& strategy) + template <typename Range, typename Box, typename Strategies> + static inline void apply(Range const& range, Box& mbr, Strategies const& strategies) { - using strategy_t = decltype(strategy.envelope(range, mbr)); - return apply(strategy_t::begin(range), strategy_t::end(range), - mbr, strategy); + strategies.envelope(range, mbr).apply(range, mbr); } }; @@ -91,35 +59,32 @@ struct envelope_range template <typename EnvelopePolicy> struct envelope_multi_range { - template <typename MultiRange, typename Box, typename Strategy> + template <typename MultiRange, typename Box, typename Strategies> static inline void apply(MultiRange const& multirange, Box& mbr, - Strategy const& strategy) + Strategies const& strategies) { - using range_t = typename boost::range_value<MultiRange>::type; - using strategy_t = decltype(strategy.envelope(std::declval<range_t>(), mbr)); - using state_t = typename strategy_t::template multi_state<Box>; - apply<state_t>(boost::begin(multirange), boost::end(multirange), mbr, strategy); + using strategy_t = decltype(strategies.envelope(multirange, mbr)); + apply<strategy_t>(multirange, mbr, strategies); } -private: - template <typename State, typename Iter, typename Box, typename Strategy> - static inline void apply(Iter it, - Iter last, + template <typename Strategy, typename MultiRange, typename Box, typename Strategies> + static inline void apply(MultiRange const& multirange, Box& mbr, - Strategy const& strategy) + Strategies const& strategies) { - State state; - for (; it != last; ++it) + typename Strategy::template state<Box> state; + auto const end = boost::end(multirange); + for (auto it = boost::begin(multirange); it != end; ++it) { if (! geometry::is_empty(*it)) { Box helper_mbr; - EnvelopePolicy::apply(*it, helper_mbr, strategy); - state.apply(helper_mbr); + EnvelopePolicy::apply(*it, helper_mbr, strategies); + Strategy::apply(state, helper_mbr); } } - state.result(mbr); + Strategy::result(state, mbr); } }; diff --git a/boost/geometry/algorithms/detail/envelope/range_of_boxes.hpp b/boost/geometry/algorithms/detail/envelope/range_of_boxes.hpp index c55be03435..04032c6237 100644 --- a/boost/geometry/algorithms/detail/envelope/range_of_boxes.hpp +++ b/boost/geometry/algorithms/detail/envelope/range_of_boxes.hpp @@ -59,7 +59,7 @@ public: longitude_interval(T const& left, T const& right) { m_end[0] = left; - m_end[1] = right; + m_end[1] = right; } template <std::size_t Index> @@ -162,11 +162,6 @@ struct envelope_range_of_boxes_by_expansion { typedef typename boost::range_value<RangeOfBoxes>::type box_type; - typedef typename boost::range_iterator - < - RangeOfBoxes const - >::type iterator_type; - // first initialize MBR detail::indexed_point_view<Box, min_corner> mbr_min(mbr); detail::indexed_point_view<Box, max_corner> mbr_max(mbr); @@ -194,7 +189,7 @@ struct envelope_range_of_boxes_by_expansion >::apply(first_box_max, mbr_max); // now expand using the remaining boxes - iterator_type it = boost::begin(range_of_boxes); + auto it = boost::begin(range_of_boxes); for (++it; it != boost::end(range_of_boxes); ++it) { detail::expand::indexed_loop @@ -237,10 +232,6 @@ struct envelope_range_of_boxes typedef typename boost::range_value<RangeOfBoxes>::type box_type; typedef typename coordinate_type<box_type>::type coordinate_type; typedef typename detail::cs_angular_units<box_type>::type units_type; - typedef typename boost::range_iterator - < - RangeOfBoxes const - >::type iterator_type; static const bool is_equatorial = ! std::is_same < @@ -258,39 +249,40 @@ struct envelope_range_of_boxes BOOST_GEOMETRY_ASSERT(! boost::empty(range_of_boxes)); - iterator_type it_min = std::min_element(boost::begin(range_of_boxes), - boost::end(range_of_boxes), - latitude_less<min_corner>()); - iterator_type it_max = std::max_element(boost::begin(range_of_boxes), - boost::end(range_of_boxes), - latitude_less<max_corner>()); + auto const it_min = std::min_element(boost::begin(range_of_boxes), + boost::end(range_of_boxes), + latitude_less<min_corner>()); + auto const it_max = std::max_element(boost::begin(range_of_boxes), + boost::end(range_of_boxes), + latitude_less<max_corner>()); coordinate_type const min_longitude = constants::min_longitude(); coordinate_type const max_longitude = constants::max_longitude(); coordinate_type const period = constants::period(); interval_range_type intervals; - for (iterator_type it = boost::begin(range_of_boxes); + for (auto it = boost::begin(range_of_boxes); it != boost::end(range_of_boxes); ++it) { - if (is_inverse_spheroidal_coordinates(*it)) + auto const& box = *it; + if (is_inverse_spheroidal_coordinates(box)) { continue; } - coordinate_type lat_min = geometry::get<min_corner, 1>(*it); - coordinate_type lat_max = geometry::get<max_corner, 1>(*it); + coordinate_type lat_min = geometry::get<min_corner, 1>(box); + coordinate_type lat_max = geometry::get<max_corner, 1>(box); if (math::equals(lat_min, constants::max_latitude()) || math::equals(lat_max, constants::min_latitude())) { // if the box degenerates to the south or north pole // just ignore it continue; - } + } - coordinate_type lon_left = geometry::get<min_corner, 0>(*it); - coordinate_type lon_right = geometry::get<max_corner, 0>(*it); + coordinate_type lon_left = geometry::get<min_corner, 0>(box); + coordinate_type lon_right = geometry::get<max_corner, 0>(box); if (math::larger(lon_right, max_longitude)) { diff --git a/boost/geometry/algorithms/detail/equals/collect_vectors.hpp b/boost/geometry/algorithms/detail/equals/collect_vectors.hpp index f2e1c7eb49..b908c3e535 100644 --- a/boost/geometry/algorithms/detail/equals/collect_vectors.hpp +++ b/boost/geometry/algorithms/detail/equals/collect_vectors.hpp @@ -22,7 +22,6 @@ #include <boost/numeric/conversion/cast.hpp> -#include <boost/geometry/algorithms/detail/interior_iterator.hpp> #include <boost/geometry/algorithms/detail/normalize.hpp> #include <boost/geometry/algorithms/not_implemented.hpp> @@ -39,7 +38,6 @@ #include <boost/geometry/views/detail/closed_clockwise_view.hpp> -#include <boost/geometry/strategies/cartesian/side_by_triangle.hpp> #include <boost/geometry/strategies/spherical/ssf.hpp> #include <boost/geometry/strategies/normalize.hpp> @@ -47,34 +45,17 @@ namespace boost { namespace geometry { -// Since these vectors (though ray would be a better name) are used in the -// implementation of equals() for Areal geometries the internal representation -// should be consistent with the side strategy. -template -< - typename T, - typename Geometry, - typename SideStrategy, - typename CSTag = typename cs_tag<Geometry>::type -> -struct collected_vector - : nyi::not_implemented_tag -{}; -// compatible with side_by_triangle cartesian strategy -template <typename T, typename Geometry, typename CT, typename CSTag> -struct collected_vector - < - T, Geometry, strategy::side::side_by_triangle<CT>, CSTag - > +template <typename T> +struct collected_vector_cartesian { typedef T type; - - inline collected_vector() + + inline collected_vector_cartesian() {} - inline collected_vector(T const& px, T const& py, - T const& pdx, T const& pdy) + inline collected_vector_cartesian(T const& px, T const& py, + T const& pdx, T const& pdy) : x(px) , y(py) , dx(pdx) @@ -84,7 +65,7 @@ struct collected_vector {} template <typename Point> - inline collected_vector(Point const& p1, Point const& p2) + inline collected_vector_cartesian(Point const& p1, Point const& p2) : x(get<0>(p1)) , y(get<1>(p1)) , dx(get<0>(p2) - x) @@ -95,8 +76,7 @@ struct collected_vector bool normalize() { - T magnitude = math::sqrt( - boost::numeric_cast<T>(dx * dx + dy * dy)); + T magnitude = math::sqrt(boost::numeric_cast<T>(dx * dx + dy * dy)); // NOTE: shouldn't here math::equals() be called? if (magnitude > 0) @@ -110,7 +90,7 @@ struct collected_vector } // For sorting - inline bool operator<(collected_vector const& other) const + inline bool operator<(collected_vector_cartesian const& other) const { if (math::equals(x, other.x)) { @@ -127,13 +107,13 @@ struct collected_vector return x < other.x; } - inline bool next_is_collinear(collected_vector const& other) const + inline bool next_is_collinear(collected_vector_cartesian const& other) const { return same_direction(other); } // For std::equals - inline bool operator==(collected_vector const& other) const + inline bool operator==(collected_vector_cartesian const& other) const { return math::equals(x, other.x) && math::equals(y, other.y) @@ -141,7 +121,7 @@ struct collected_vector } private: - inline bool same_direction(collected_vector const& other) const + inline bool same_direction(collected_vector_cartesian const& other) const { // For high precision arithmetic, we have to be // more relaxed then using == @@ -159,38 +139,32 @@ private: // Compatible with spherical_side_formula which currently // is the default spherical_equatorial and geographic strategy // so CSTag is spherical_equatorial_tag or geographic_tag -template <typename T, typename Geometry, typename CT, typename CSTag> -struct collected_vector - < - T, Geometry, strategy::side::spherical_side_formula<CT>, CSTag - > +template <typename T, typename Point> +struct collected_vector_spherical { typedef T type; - - typedef typename geometry::detail::cs_angular_units<Geometry>::type units_type; - typedef model::point<T, 2, cs::spherical_equatorial<units_type> > point_type; + typedef model::point<T, 3, cs::cartesian> vector_type; - collected_vector() + collected_vector_spherical() {} - template <typename Point> - collected_vector(Point const& p1, Point const& p2) + collected_vector_spherical(Point const& p1, Point const& p2) : origin(get<0>(p1), get<1>(p1)) { - origin = detail::return_normalized<point_type>( + origin = detail::return_normalized<Point>( origin, strategy::normalize::spherical_point()); using namespace geometry::formula; prev = sph_to_cart3d<vector_type>(p1); next = sph_to_cart3d<vector_type>(p2); - direction = cross_product(prev, next); + cross = direction = cross_product(prev, next); } bool normalize() { - T magnitude_sqr = dot_product(direction, direction); + T const magnitude_sqr = dot_product(direction, direction); // NOTE: shouldn't here math::equals() be called? if (magnitude_sqr > 0) @@ -202,7 +176,7 @@ struct collected_vector return false; } - bool operator<(collected_vector const& other) const + bool operator<(collected_vector_spherical const& other) const { if (math::equals(get<0>(origin), get<0>(other.origin))) { @@ -226,13 +200,13 @@ struct collected_vector // For consistency with side and intersection strategies used by relops // IMPORTANT: this method should be called for previous vector // and next vector should be passed as parameter - bool next_is_collinear(collected_vector const& other) const + bool next_is_collinear(collected_vector_spherical const& other) const { - return formula::sph_side_value(direction, other.next) == 0; + return formula::sph_side_value(cross, other.next) == 0; } // For std::equals - bool operator==(collected_vector const& other) const + bool operator==(collected_vector_spherical const& other) const { return math::equals(get<0>(origin), get<0>(other.origin)) && math::equals(get<1>(origin), get<1>(other.origin)) @@ -241,76 +215,57 @@ struct collected_vector private: // For consistency with side and intersection strategies used by relops - bool is_collinear(collected_vector const& other) const + // NOTE: alternative would be to equal-compare direction's coordinates + // or to check if dot product of directions is equal to 1. + bool is_collinear(collected_vector_spherical const& other) const { - return formula::sph_side_value(direction, other.prev) == 0 - && formula::sph_side_value(direction, other.next) == 0; + return formula::sph_side_value(cross, other.prev) == 0 + && formula::sph_side_value(cross, other.next) == 0; } - - /*bool same_direction(collected_vector const& other) const - { - return math::equals_with_epsilon(get<0>(direction), get<0>(other.direction)) - && math::equals_with_epsilon(get<1>(direction), get<1>(other.direction)) - && math::equals_with_epsilon(get<2>(direction), get<2>(other.direction)); - }*/ - point_type origin; // used for sorting and equality check + Point origin; // used for sorting and equality check vector_type direction; // used for sorting, only in operator< + vector_type cross; // used for sorting, used for collinearity check vector_type prev; // used for collinearity check, only in operator== vector_type next; // used for collinearity check }; -// Specialization for spherical polar -template <typename T, typename Geometry, typename CT> -struct collected_vector - < - T, Geometry, - strategy::side::spherical_side_formula<CT>, - spherical_polar_tag - > - : public collected_vector - < - T, Geometry, - strategy::side::spherical_side_formula<CT>, - spherical_equatorial_tag - > +// Version for spherical polar +template <typename T, typename Point> +struct collected_vector_polar + : public collected_vector_spherical<T, Point> { - typedef collected_vector - < - T, Geometry, - strategy::side::spherical_side_formula<CT>, - spherical_equatorial_tag - > base_type; + using type = T; + using base_point_type + = model::point<T, 2, cs::spherical_equatorial<geometry::degree>>; + using base_type = collected_vector_spherical<T, base_point_type>; - collected_vector() {} + collected_vector_polar() {} - template <typename Point> - collected_vector(Point const& p1, Point const& p2) + collected_vector_polar(Point const& p1, Point const& p2) : base_type(to_equatorial(p1), to_equatorial(p2)) {} private: - template <typename Point> - Point to_equatorial(Point const& p) + static base_point_type to_equatorial(Point const& p) { - typedef typename coordinate_type<Point>::type coord_type; - - typedef math::detail::constants_on_spheroid + using coord_type = typename coordinate_type<Point>::type; + using constants = math::detail::constants_on_spheroid < coord_type, typename coordinate_system<Point>::type::units - > constants; + > ; - coord_type const pi_2 = constants::half_period() / 2; + constexpr coord_type pi_2 = constants::half_period() / 2; - Point res = p; + base_point_type res; + set<0>(res, get<0>(p)); set<1>(res, pi_2 - get<1>(p)); return res; } }; - -// TODO: specialize collected_vector for geographic_tag +// TODO: implement collected_vector type for geographic #ifndef DOXYGEN_NO_DETAIL @@ -339,15 +294,11 @@ private: return; } - typedef typename boost::range_size<Collection>::type collection_size_t; - collection_size_t c_old_size = boost::size(collection); - - typedef typename boost::range_iterator<ClosedClockwiseRange const>::type iterator; - + auto c_old_size = boost::size(collection); bool is_first = true; - iterator it = boost::begin(range); + auto it = boost::begin(range); - for (iterator prev = it++; it != boost::end(range); prev = it++) + for (auto prev = it++; it != boost::end(range); prev = it++) { typename boost::range_value<Collection>::type v(*prev, *it); @@ -366,13 +317,10 @@ private: } // If first one has same direction as last one, remove first one - collection_size_t collected_count = boost::size(collection) - c_old_size; - if ( collected_count > 1 ) + if (boost::size(collection) > c_old_size + 1) { - typedef typename boost::range_iterator<Collection>::type c_iterator; - c_iterator first = range::pos(collection, c_old_size); - - if (collection.back().next_is_collinear(*first) ) + auto first = range::pos(collection, c_old_size); + if (collection.back().next_is_collinear(*first)) { //collection.erase(first); // O(1) instead of O(N) @@ -451,10 +399,8 @@ struct polygon_collect_vectors typedef range_collect_vectors<ring_type, Collection> per_range; per_range::apply(collection, exterior_ring(polygon)); - typename interior_return_type<Polygon const>::type - rings = interior_rings(polygon); - for (typename detail::interior_iterator<Polygon const>::type - it = boost::begin(rings); it != boost::end(rings); ++it) + auto const& rings = interior_rings(polygon); + for (auto it = boost::begin(rings); it != boost::end(rings); ++it) { per_range::apply(collection, *it); } @@ -467,10 +413,7 @@ struct multi_collect_vectors { static inline void apply(Collection& collection, MultiGeometry const& multi) { - for (typename boost::range_iterator<MultiGeometry const>::type - it = boost::begin(multi); - it != boost::end(multi); - ++it) + for (auto it = boost::begin(multi); it != boost::end(multi); ++it) { SinglePolicy::apply(collection, *it); } diff --git a/boost/geometry/algorithms/detail/equals/implementation.hpp b/boost/geometry/algorithms/detail/equals/implementation.hpp index e66a8a77ac..2f803f3658 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-2021. -// Modifications copyright (c) 2014-2021 Oracle and/or its affiliates. +// This file was modified by Oracle on 2014-2022. +// Modifications copyright (c) 2014-2022 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 @@ -36,8 +36,8 @@ #include <boost/geometry/algorithms/detail/equals/point_point.hpp> #include <boost/geometry/algorithms/detail/equals/collect_vectors.hpp> #include <boost/geometry/algorithms/detail/equals/interface.hpp> +#include <boost/geometry/algorithms/detail/relate/implementation.hpp> #include <boost/geometry/algorithms/detail/relate/relate_impl.hpp> -#include <boost/geometry/algorithms/relate.hpp> #include <boost/geometry/strategies/relate/cartesian.hpp> #include <boost/geometry/strategies/relate/geographic.hpp> @@ -160,26 +160,32 @@ struct length_check */ -template <typename Geometry1, typename Geometry2, typename Strategy> -struct collected_vector +// Small helper structure do decide to use collect_vectors, or not +template <typename Strategy, typename CsTag> +struct use_collect_vectors { - typedef typename geometry::select_most_precise - < - typename select_coordinate_type - < - Geometry1, Geometry2 - >::type, - double - >::type calculation_type; + static constexpr bool value = false; +}; - typedef geometry::collected_vector - < - calculation_type, - Geometry1, - decltype(std::declval<Strategy>().side()) - > type; +template <typename Strategy> +struct use_collect_vectors<Strategy, cartesian_tag> +{ + static constexpr bool value = true; + + template <typename T, typename Point> + using type = collected_vector_cartesian<T>; }; +template <typename CV> +struct use_collect_vectors<strategy::side::spherical_side_formula<CV>, spherical_tag> +{ + static constexpr bool value = true; + + template <typename T, typename Point> + using type = collected_vector_spherical<T, Point>; +}; + + template <typename TrivialCheck> struct equals_by_collection { @@ -193,10 +199,24 @@ struct equals_by_collection return false; } - typedef typename collected_vector + using calculation_type = typename geometry::select_most_precise + < + typename select_coordinate_type + < + Geometry1, Geometry2 + >::type, + double + >::type; + + using collected_vector_type = typename use_collect_vectors < - Geometry1, Geometry2, Strategy - >::type collected_vector_type; + decltype(std::declval<Strategy>().side()), + typename Strategy::cs_tag + >::template type + < + calculation_type, + typename geometry::point_type<Geometry1>::type + >; std::vector<collected_vector_type> c1, c2; @@ -211,7 +231,7 @@ struct equals_by_collection std::sort(c1.begin(), c1.end()); std::sort(c2.begin(), c2.end()); - // Just check if these vectors are equal. + // Check if these vectors are equal. return std::equal(c1.begin(), c1.end(), c2.begin()); } }; @@ -226,47 +246,40 @@ struct equals_by_relate > {}; -// If collect_vectors which is a SideStrategy-dispatched optimization -// is implemented in a way consistent with the Intersection/Side Strategy -// then collect_vectors is used, otherwise relate is used. +// Use either collect_vectors or relate // NOTE: the result could be conceptually different for invalid // geometries in different coordinate systems because collect_vectors // and relate treat invalid geometries differently. template<typename TrivialCheck> struct equals_by_collection_or_relate { - template <typename Geometry1, typename Geometry2, typename Strategy> - static inline bool apply(Geometry1 const& geometry1, - Geometry2 const& geometry2, - Strategy const& strategy) - { - typedef std::is_base_of - < - nyi::not_implemented_tag, - typename collected_vector - < - Geometry1, Geometry2, Strategy - >::type - > enable_relate_type; - - return apply(geometry1, geometry2, strategy, enable_relate_type()); - } + template <typename Strategy> + using use_vectors = use_collect_vectors + < + decltype(std::declval<Strategy>().side()), + typename Strategy::cs_tag + >; -private: - template <typename Geometry1, typename Geometry2, typename Strategy> + template + < + typename Geometry1, typename Geometry2, typename Strategy, + std::enable_if_t<use_vectors<Strategy>::value, int> = 0 + > static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, - Strategy const& strategy, - std::false_type /*enable_relate*/) + Strategy const& strategy) { return equals_by_collection<TrivialCheck>::apply(geometry1, geometry2, strategy); } - template <typename Geometry1, typename Geometry2, typename Strategy> + template + < + typename Geometry1, typename Geometry2, typename Strategy, + std::enable_if_t<! use_vectors<Strategy>::value, int> = 0 + > static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, - Strategy const& strategy, - std::true_type /*enable_relate*/) + Strategy const& strategy) { return equals_by_relate<Geometry1, Geometry2>::apply(geometry1, geometry2, strategy); } @@ -376,7 +389,7 @@ struct equals < MultiPolygon1, MultiPolygon2, multi_polygon_tag, multi_polygon_tag, - areal_tag, areal_tag, + areal_tag, areal_tag, 2, Reverse > @@ -389,7 +402,7 @@ struct equals < Polygon, MultiPolygon, polygon_tag, multi_polygon_tag, - areal_tag, areal_tag, + areal_tag, areal_tag, 2, Reverse > @@ -401,7 +414,7 @@ struct equals < MultiPolygon, Ring, multi_polygon_tag, ring_tag, - areal_tag, areal_tag, + areal_tag, areal_tag, 2, Reverse > diff --git a/boost/geometry/algorithms/detail/equals/implementation_gc.hpp b/boost/geometry/algorithms/detail/equals/implementation_gc.hpp new file mode 100644 index 0000000000..81424e0468 --- /dev/null +++ b/boost/geometry/algorithms/detail/equals/implementation_gc.hpp @@ -0,0 +1,114 @@ +// Boost.Geometry + +// Copyright (c) 2022 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) + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_EQUALS_IMPLEMENTATION_GC_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_EQUALS_IMPLEMENTATION_GC_HPP + + +#include <boost/geometry/algorithms/detail/equals/implementation.hpp> +#include <boost/geometry/algorithms/detail/relate/implementation_gc.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +template <typename Geometry1, typename Geometry2, std::size_t DimensionCount> +struct equals + < + Geometry1, Geometry2, + geometry_collection_tag, geometry_collection_tag, + geometry_collection_tag, geometry_collection_tag, + DimensionCount, false + > +{ + template <typename Strategy> + static inline bool apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Strategy const& strategy) + { + return detail::relate::relate_impl + < + detail::de9im::static_mask_equals_type, + Geometry1, + Geometry2 + >::apply(geometry1, geometry2, strategy); + } +}; + + +template +< + typename Geometry1, typename Geometry2, + typename Tag1, typename CastedTag1, + std::size_t DimensionCount +> +struct equals + < + Geometry1, Geometry2, + Tag1, geometry_collection_tag, + CastedTag1, geometry_collection_tag, + DimensionCount, false + > +{ + template <typename Strategy> + static inline bool apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Strategy const& strategy) + { + using gc1_view_t = detail::geometry_collection_view<Geometry1>; + return equals + < + gc1_view_t, Geometry2 + >::apply(gc1_view_t(geometry1), geometry2, strategy); + } +}; + + +template +< + typename Geometry1, typename Geometry2, + typename Tag2, typename CastedTag2, + std::size_t DimensionCount +> +struct equals + < + Geometry1, Geometry2, + geometry_collection_tag, Tag2, + geometry_collection_tag, CastedTag2, + DimensionCount, false + > +{ + template <typename Strategy> + static inline bool apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Strategy const& strategy) + { + using gc2_view_t = detail::geometry_collection_view<Geometry2>; + return equals + < + Geometry1, gc2_view_t + >::apply(geometry1, gc2_view_t(geometry2), strategy); + } +}; + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_EQUALS_IMPLEMENTATION_GC_HPP diff --git a/boost/geometry/algorithms/detail/equals/interface.hpp b/boost/geometry/algorithms/detail/equals/interface.hpp index bd31e8c2c4..f0c4438430 100644 --- a/boost/geometry/algorithms/detail/equals/interface.hpp +++ b/boost/geometry/algorithms/detail/equals/interface.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-2021. -// Modifications copyright (c) 2014-2021 Oracle and/or its affiliates. +// This file was modified by Oracle on 2014-2022. +// Modifications copyright (c) 2014-2022 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,15 +23,12 @@ #include <cstddef> -#include <boost/variant/apply_visitor.hpp> -#include <boost/variant/static_visitor.hpp> -#include <boost/variant/variant_fwd.hpp> - #include <boost/geometry/core/coordinate_dimension.hpp> #include <boost/geometry/core/reverse_dispatch.hpp> #include <boost/geometry/core/tag.hpp> #include <boost/geometry/core/tag_cast.hpp> +#include <boost/geometry/geometries/adapted/boost_variant.hpp> #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/algorithms/not_implemented.hpp> @@ -157,9 +154,14 @@ struct equals<default_strategy, false> } // namespace resolve_strategy -namespace resolve_variant { +namespace resolve_dynamic { -template <typename Geometry1, typename Geometry2> +template +< + typename Geometry1, typename Geometry2, + typename Tag1 = typename geometry::tag<Geometry1>::type, + typename Tag2 = typename geometry::tag<Geometry2>::type +> struct equals { template <typename Strategy> @@ -180,114 +182,67 @@ struct equals } }; -template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2> -struct equals<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2> +template <typename Geometry1, typename Geometry2, typename Tag2> +struct equals<Geometry1, Geometry2, dynamic_geometry_tag, Tag2> { template <typename Strategy> - struct visitor: static_visitor<bool> + static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, + Strategy const& strategy) { - Geometry2 const& m_geometry2; - Strategy const& m_strategy; - - visitor(Geometry2 const& geometry2, Strategy const& strategy) - : m_geometry2(geometry2) - , m_strategy(strategy) - {} - - template <typename Geometry1> - inline bool operator()(Geometry1 const& geometry1) const + bool result = false; + traits::visit<Geometry1>::apply([&](auto const& g1) { - return equals<Geometry1, Geometry2> - ::apply(geometry1, m_geometry2, m_strategy); - } - - }; - - template <typename Strategy> - static inline bool apply( - boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1, - Geometry2 const& geometry2, - Strategy const& strategy - ) - { - return boost::apply_visitor(visitor<Strategy>(geometry2, strategy), geometry1); + result = equals + < + util::remove_cref_t<decltype(g1)>, + Geometry2 + >::apply(g1, geometry2, strategy); + }, geometry1); + return result; } }; -template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)> -struct equals<Geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > +template <typename Geometry1, typename Geometry2, typename Tag1> +struct equals<Geometry1, Geometry2, Tag1, dynamic_geometry_tag> { template <typename Strategy> - struct visitor: static_visitor<bool> + static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, + Strategy const& strategy) { - Geometry1 const& m_geometry1; - Strategy const& m_strategy; - - visitor(Geometry1 const& geometry1, Strategy const& strategy) - : m_geometry1(geometry1) - , m_strategy(strategy) - {} - - template <typename Geometry2> - inline bool operator()(Geometry2 const& geometry2) const + bool result = false; + traits::visit<Geometry2>::apply([&](auto const& g2) { - return equals<Geometry1, Geometry2> - ::apply(m_geometry1, geometry2, m_strategy); - } - - }; - - template <typename Strategy> - static inline bool apply( - Geometry1 const& geometry1, - boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2, - Strategy const& strategy - ) - { - return boost::apply_visitor(visitor<Strategy>(geometry1, strategy), geometry2); + result = equals + < + Geometry1, + util::remove_cref_t<decltype(g2)> + >::apply(geometry1, g2, strategy); + }, geometry2); + return result; } }; -template < - BOOST_VARIANT_ENUM_PARAMS(typename T1), - BOOST_VARIANT_ENUM_PARAMS(typename T2) -> -struct equals< - boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>, - boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> -> +template <typename Geometry1, typename Geometry2> +struct equals<Geometry1, Geometry2, dynamic_geometry_tag, dynamic_geometry_tag> { template <typename Strategy> - struct visitor: static_visitor<bool> + static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, + Strategy const& strategy) { - Strategy const& m_strategy; - - visitor(Strategy const& strategy) - : m_strategy(strategy) - {} - - template <typename Geometry1, typename Geometry2> - inline bool operator()(Geometry1 const& geometry1, - Geometry2 const& geometry2) const + bool result = false; + traits::visit<Geometry1, Geometry2>::apply([&](auto const& g1, auto const& g2) { - return equals<Geometry1, Geometry2> - ::apply(geometry1, geometry2, m_strategy); - } - - }; - - template <typename Strategy> - static inline bool apply( - boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1, - boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2, - Strategy const& strategy - ) - { - return boost::apply_visitor(visitor<Strategy>(strategy), geometry1, geometry2); + result = equals + < + util::remove_cref_t<decltype(g1)>, + util::remove_cref_t<decltype(g2)> + >::apply(g1, g2, strategy); + }, geometry1, geometry2); + return result; } }; -} // namespace resolve_variant +} // namespace resolve_dynamic /*! @@ -314,10 +269,10 @@ inline bool equals(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { - return resolve_variant::equals - < - Geometry1, Geometry2 - >::apply(geometry1, geometry2, strategy); + return resolve_dynamic::equals + < + Geometry1, Geometry2 + >::apply(geometry1, geometry2, strategy); } @@ -340,8 +295,10 @@ inline bool equals(Geometry1 const& geometry1, template <typename Geometry1, typename Geometry2> inline bool equals(Geometry1 const& geometry1, Geometry2 const& geometry2) { - return resolve_variant::equals<Geometry1, Geometry2> - ::apply(geometry1, geometry2, default_strategy()); + return resolve_dynamic::equals + < + Geometry1, Geometry2 + >::apply(geometry1, geometry2, default_strategy()); } diff --git a/boost/geometry/algorithms/detail/expand/indexed.hpp b/boost/geometry/algorithms/detail/expand/indexed.hpp index 08463689de..92d701d16e 100644 --- a/boost/geometry/algorithms/detail/expand/indexed.hpp +++ b/boost/geometry/algorithms/detail/expand/indexed.hpp @@ -61,7 +61,7 @@ struct indexed_loop std::less<coordinate_type> less; std::greater<coordinate_type> greater; - + if (less(coord, get<min_corner, Dimension>(box))) { set<min_corner, Dimension>(box, coord); diff --git a/boost/geometry/algorithms/detail/expand/interface.hpp b/boost/geometry/algorithms/detail/expand/interface.hpp index 442a4e011f..6552c266e4 100644 --- a/boost/geometry/algorithms/detail/expand/interface.hpp +++ b/boost/geometry/algorithms/detail/expand/interface.hpp @@ -22,22 +22,23 @@ #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXPAND_INTERFACE_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXPAND_INTERFACE_HPP -#include <boost/variant/apply_visitor.hpp> -#include <boost/variant/static_visitor.hpp> -#include <boost/variant/variant_fwd.hpp> #include <boost/geometry/algorithms/dispatch/expand.hpp> #include <boost/geometry/core/coordinate_system.hpp> #include <boost/geometry/core/tag.hpp> #include <boost/geometry/core/tags.hpp> +#include <boost/geometry/core/visit.hpp> +#include <boost/geometry/geometries/adapted/boost_variant.hpp> // For backward compatibility #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/strategies/default_strategy.hpp> #include <boost/geometry/strategies/detail.hpp> #include <boost/geometry/strategies/expand/services.hpp> +#include <boost/geometry/util/type_traits_std.hpp> + namespace boost { namespace geometry { @@ -97,10 +98,10 @@ struct expand<default_strategy, false> } //namespace resolve_strategy -namespace resolve_variant +namespace resolve_dynamic { - -template <typename Geometry> + +template <typename Geometry, typename Tag = typename tag<Geometry>::type> struct expand { template <typename Box, typename Strategy> @@ -111,72 +112,28 @@ struct expand concepts::check<Box>(); concepts::check<Geometry const>(); concepts::check_concepts_and_equal_dimensions<Box, Geometry const>(); - + resolve_strategy::expand<Strategy>::apply(box, geometry, strategy); } }; -template <BOOST_VARIANT_ENUM_PARAMS(typename T)> -struct expand<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > +template <typename Geometry> +struct expand<Geometry, dynamic_geometry_tag> { - template <typename Box, typename Strategy> - struct visitor: boost::static_visitor<void> - { - Box& m_box; - Strategy const& m_strategy; - - visitor(Box& box, Strategy const& strategy) - : m_box(box) - , m_strategy(strategy) - {} - - template <typename Geometry> - void operator()(Geometry const& geometry) const - { - return expand<Geometry>::apply(m_box, geometry, m_strategy); - } - }; - template <class Box, typename Strategy> - static inline void - apply(Box& box, - boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry, - Strategy const& strategy) + static inline void apply(Box& box, + Geometry const& geometry, + Strategy const& strategy) { - return boost::apply_visitor(visitor<Box, Strategy>(box, strategy), - geometry); + traits::visit<Geometry>::apply([&](auto const& g) + { + expand<util::remove_cref_t<decltype(g)>>::apply(box, g, strategy); + }, geometry); } }; - -} // namespace resolve_variant - - -/*** -*! -\brief Expands a box using the extend (envelope) of another geometry (box, point) -\ingroup expand -\tparam Box type of the box -\tparam Geometry of second geometry, to be expanded with the box -\param box box to expand another geometry with, might be changed -\param geometry other geometry -\param strategy_less -\param strategy_greater -\note Strategy is currently ignored - * -template -< - typename Box, typename Geometry, - typename StrategyLess, typename StrategyGreater -> -inline void expand(Box& box, Geometry const& geometry, - StrategyLess const& strategy_less, - StrategyGreater const& strategy_greater) -{ - concepts::check_concepts_and_equal_dimensions<Box, Geometry const>(); - dispatch::expand<Box, Geometry>::apply(box, geometry); -} -***/ +} // namespace resolve_dynamic + /*! \brief Expands (with strategy) @@ -195,7 +152,7 @@ will be added to the box template <typename Box, typename Geometry, typename Strategy> inline void expand(Box& box, Geometry const& geometry, Strategy const& strategy) { - resolve_variant::expand<Geometry>::apply(box, geometry, strategy); + resolve_dynamic::expand<Geometry>::apply(box, geometry, strategy); } /*! @@ -213,7 +170,7 @@ added to the box template <typename Box, typename Geometry> inline void expand(Box& box, Geometry const& geometry) { - resolve_variant::expand<Geometry>::apply(box, geometry, default_strategy()); + resolve_dynamic::expand<Geometry>::apply(box, geometry, default_strategy()); } }} // namespace boost::geometry diff --git a/boost/geometry/algorithms/detail/expand_by_epsilon.hpp b/boost/geometry/algorithms/detail/expand_by_epsilon.hpp index 3e41b71ff9..ae07f5bb0a 100644 --- a/boost/geometry/algorithms/detail/expand_by_epsilon.hpp +++ b/boost/geometry/algorithms/detail/expand_by_epsilon.hpp @@ -44,7 +44,7 @@ struct corner_by_epsilon typedef typename coordinate_type<Point>::type coord_type; coord_type const coord = get<I>(point); coord_type const seps = math::scaled_epsilon(coord); - + set<I>(point, PlusOrMinus<coord_type>()(coord, seps)); corner_by_epsilon<Point, PlusOrMinus, I+1>::apply(point); diff --git a/boost/geometry/algorithms/detail/extreme_points.hpp b/boost/geometry/algorithms/detail/extreme_points.hpp index a6605fd45d..2ac13fc1ed 100644 --- a/boost/geometry/algorithms/detail/extreme_points.hpp +++ b/boost/geometry/algorithms/detail/extreme_points.hpp @@ -26,7 +26,6 @@ #include <boost/range/value_type.hpp> #include <boost/geometry/algorithms/detail/assign_box_corners.hpp> -#include <boost/geometry/algorithms/detail/interior_iterator.hpp> #include <boost/geometry/arithmetic/arithmetic.hpp> @@ -124,7 +123,6 @@ struct extreme_points_on_ring { typedef typename geometry::coordinate_type<Ring>::type coordinate_type; - typedef typename boost::range_iterator<Ring const>::type range_iterator; typedef typename geometry::point_type<Ring>::type point_type; template <typename CirclingIterator, typename Points> @@ -288,8 +286,7 @@ struct extreme_points_on_ring template <typename Iterator, typename SideStrategy> static inline bool right_turn(Ring const& ring, Iterator it, SideStrategy const& strategy) { - typename std::iterator_traits<Iterator>::difference_type const index - = std::distance(boost::begin(ring), it); + auto const index = std::distance(boost::begin(ring), it); geometry::ever_circling_range_iterator<Ring const> left(ring); geometry::ever_circling_range_iterator<Ring const> right(ring); left += index; @@ -326,9 +323,9 @@ struct extreme_points_on_ring // Get all maxima, usually one. In case of self-tangencies, or self-crossings, // the max might be is not valid. A valid max should make a right turn - range_iterator max_it = boost::begin(ring); + auto max_it = boost::begin(ring); compare<Dimension> smaller; - for (range_iterator it = max_it + 1; it != boost::end(ring); ++it) + for (auto it = max_it + 1; it != boost::end(ring); ++it) { if (smaller(*max_it, *it) && right_turn(ring, it, strategy)) { @@ -341,8 +338,7 @@ struct extreme_points_on_ring return false; } - typename std::iterator_traits<range_iterator>::difference_type const - index = std::distance(boost::begin(ring), max_it); + auto const index = std::distance(boost::begin(ring), max_it); //std::cout << "Extreme point lies at " << index << " having " << geometry::wkt(*max_it) << std::endl; geometry::ever_circling_range_iterator<Ring const> left(ring); @@ -429,10 +425,8 @@ struct extreme_points<Polygon, Dimension, polygon_tag> } // For a polygon, its interior rings can contain intruders - typename interior_return_type<Polygon const>::type - rings = interior_rings(polygon); - for (typename detail::interior_iterator<Polygon const>::type - it = boost::begin(rings); it != boost::end(rings); ++it) + auto const& rings = interior_rings(polygon); + for (auto it = boost::begin(rings); it != boost::end(rings); ++it) { ring_implementation::get_intruders(*it, extremes, intruders, strategy); } diff --git a/boost/geometry/algorithms/detail/gc_group_elements.hpp b/boost/geometry/algorithms/detail/gc_group_elements.hpp new file mode 100644 index 0000000000..c1c26ec9c6 --- /dev/null +++ b/boost/geometry/algorithms/detail/gc_group_elements.hpp @@ -0,0 +1,196 @@ +// Boost.Geometry + +// Copyright (c) 2022, Oracle and/or its affiliates. +// 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_GC_GROUP_ELEMENTS_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_GC_GROUP_ELEMENTS_HPP + + +#include <array> +#include <deque> +#include <map> +#include <set> +#include <vector> + +#include <boost/range/begin.hpp> +#include <boost/range/size.hpp> + +#include <boost/geometry/algorithms/detail/gc_make_rtree.hpp> +#include <boost/geometry/algorithms/detail/visit.hpp> +#include <boost/geometry/algorithms/is_empty.hpp> +#include <boost/geometry/core/topological_dimension.hpp> +#include <boost/geometry/views/detail/random_access_view.hpp> + + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail +{ + + +struct gc_element_id +{ + gc_element_id(unsigned int source_id_, std::size_t gc_id_) + : source_id(source_id_), gc_id(gc_id_) + {} + + unsigned int source_id; + std::size_t gc_id; + + friend bool operator<(gc_element_id const& left, gc_element_id const& right) + { + return left.source_id < right.source_id + || (left.source_id == right.source_id && left.gc_id < right.gc_id); + } +}; + +template <typename GC1View, typename GC2View, typename Strategy, typename IntersectingFun, typename DisjointFun> +inline void gc_group_elements(GC1View const& gc1_view, GC2View const& gc2_view, Strategy const& strategy, + IntersectingFun&& intersecting_fun, + DisjointFun&& disjoint_fun, + bool const group_self = false) +{ + // NOTE: gc_make_rtree_indexes() already checks for random-access, + // non-recursive geometry collections. + + // NOTE: could be replaced with unordered_map and unordered_set + std::map<gc_element_id, std::set<gc_element_id>> adjacent; + + // Create adjacency list based on intersecting envelopes of GC elements + auto const rtree2 = gc_make_rtree_indexes(gc2_view, strategy); + if (! group_self) // group only elements from the other GC? + { + for (std::size_t i = 0; i < boost::size(gc1_view); ++i) + { + traits::iter_visit<GC1View>::apply([&](auto const& g1) + { + using g1_t = util::remove_cref_t<decltype(g1)>; + using box1_t = gc_make_rtree_box_t<g1_t>; + box1_t b1 = geometry::return_envelope<box1_t>(g1, strategy); + detail::expand_by_epsilon(b1); + + gc_element_id id1 = {0, i}; + for (auto qit = rtree2.qbegin(index::intersects(b1)); qit != rtree2.qend(); ++qit) + { + gc_element_id id2 = {1, qit->second}; + adjacent[id1].insert(id2); + adjacent[id2].insert(id1); + } + }, boost::begin(gc1_view) + i); + } + } + else // group elements from the same GCs and the other GC + { + auto const rtree1 = gc_make_rtree_indexes(gc1_view, strategy); + for (auto it1 = rtree1.begin() ; it1 != rtree1.end() ; ++it1) + { + auto const b1 = it1->first; + gc_element_id id1 = {0, it1->second}; + for (auto qit2 = rtree2.qbegin(index::intersects(b1)); qit2 != rtree2.qend(); ++qit2) + { + gc_element_id id2 = {1, qit2->second}; + adjacent[id1].insert(id2); + adjacent[id2].insert(id1); + } + for (auto qit1 = rtree1.qbegin(index::intersects(b1)); qit1 != rtree1.qend(); ++qit1) + { + if (id1.gc_id != qit1->second) + { + gc_element_id id11 = {0, qit1->second}; + adjacent[id1].insert(id11); + adjacent[id11].insert(id1); + } + } + } + for (auto it2 = rtree2.begin(); it2 != rtree2.end(); ++it2) + { + auto const b2 = it2->first; + gc_element_id id2 = {1, it2->second}; + for (auto qit2 = rtree2.qbegin(index::intersects(b2)); qit2 != rtree2.qend(); ++qit2) + { + if (id2.gc_id != qit2->second) + { + gc_element_id id22 = {1, qit2->second}; + adjacent[id2].insert(id22); + adjacent[id22].insert(id2); + } + } + } + } + + // Traverse the graph and build connected groups i.e. groups of intersecting envelopes + std::deque<gc_element_id> queue; + std::array<std::vector<bool>, 2> visited = { + std::vector<bool>(boost::size(gc1_view), false), + std::vector<bool>(boost::size(gc2_view), false) + }; + for (auto const& elem : adjacent) + { + std::vector<gc_element_id> group; + if (! visited[elem.first.source_id][elem.first.gc_id]) + { + queue.push_back(elem.first); + visited[elem.first.source_id][elem.first.gc_id] = true; + group.push_back(elem.first); + while (! queue.empty()) + { + gc_element_id e = queue.front(); + queue.pop_front(); + for (auto const& n : adjacent[e]) + { + if (! visited[n.source_id][n.gc_id]) + { + queue.push_back(n); + visited[n.source_id][n.gc_id] = true; + group.push_back(n); + } + } + } + } + if (! group.empty()) + { + if (! intersecting_fun(group)) + { + return; + } + } + } + + { + std::vector<gc_element_id> group; + for (std::size_t i = 0; i < visited[0].size(); ++i) + { + if (! visited[0][i]) + { + group.emplace_back(0, i); + } + } + for (std::size_t i = 0; i < visited[1].size(); ++i) + { + if (! visited[1][i]) + { + group.emplace_back(1, i); + } + } + if (! group.empty()) + { + disjoint_fun(group); + } + } +} + + +} // namespace detail +#endif // DOXYGEN_NO_DETAIL + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_GC_GROUP_ELEMENTS_HPP diff --git a/boost/geometry/algorithms/detail/gc_make_rtree.hpp b/boost/geometry/algorithms/detail/gc_make_rtree.hpp new file mode 100644 index 0000000000..c1c00d4692 --- /dev/null +++ b/boost/geometry/algorithms/detail/gc_make_rtree.hpp @@ -0,0 +1,118 @@ +// Boost.Geometry + +// Copyright (c) 2022, Oracle and/or its affiliates. + +// 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_GC_MAKE_RTREE_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_GC_MAKE_RTREE_HPP + +#include <vector> + +#include <boost/range/begin.hpp> +#include <boost/range/end.hpp> +#include <boost/range/size.hpp> + +#include <boost/geometry/algorithms/detail/expand_by_epsilon.hpp> +#include <boost/geometry/algorithms/detail/visit.hpp> +#include <boost/geometry/algorithms/envelope.hpp> +#include <boost/geometry/index/rtree.hpp> +#include <boost/geometry/strategies/index/services.hpp> +#include <boost/geometry/views/detail/random_access_view.hpp> + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail +{ + + +template <typename GC> +using gc_make_rtree_box_t = geometry::model::box + < + geometry::model::point + < + typename geometry::coordinate_type<GC>::type, + geometry::dimension<GC>::value, + typename geometry::coordinate_system<GC>::type + > + >; + + +template <typename GC, typename Strategy> +inline auto gc_make_rtree_iterators(GC& gc, Strategy const& strategy) +{ + using box_t = gc_make_rtree_box_t<GC>; + using iter_t = typename boost::range_iterator<GC>::type; + + using rtree_param_t = index::rstar<4>; + using rtree_parameters_t = index::parameters<rtree_param_t, Strategy>; + using value_t = std::pair<box_t, iter_t>; + using rtree_t = index::rtree<value_t, rtree_parameters_t>; + + // TODO: get rid of the temporary vector + auto const size = boost::size(gc); + std::vector<value_t> values; + values.reserve(size); + + visit_breadth_first_impl<true>::apply([&](auto const& g, auto iter) + { + box_t b = geometry::return_envelope<box_t>(g, strategy); + detail::expand_by_epsilon(b); + values.emplace_back(b, iter); + return true; + }, gc); + + return rtree_t(values.begin(), values.end(), rtree_parameters_t(rtree_param_t(), strategy)); +} + + +template <typename GCView, typename Strategy> +inline auto gc_make_rtree_indexes(GCView const& gc, Strategy const& strategy) +{ + // Alternatively only take random_access_view<GC> + static const bool is_random_access = is_random_access_range<GCView>::value; + static const bool is_not_recursive = ! is_geometry_collection_recursive<GCView>::value; + BOOST_GEOMETRY_STATIC_ASSERT((is_random_access && is_not_recursive), + "This algorithm requires random-access, non-recursive geometry collection or view.", + GCView); + + using box_t = gc_make_rtree_box_t<GCView>; + + using rtree_param_t = index::rstar<4>; + using rtree_parameters_t = index::parameters<rtree_param_t, Strategy>; + using value_t = std::pair<box_t, std::size_t>; + using rtree_t = index::rtree<value_t, rtree_parameters_t>; + + // TODO: get rid of the temporary vector + std::size_t const size = boost::size(gc); + std::vector<value_t> values; + values.reserve(size); + + auto const begin = boost::begin(gc); + for (std::size_t i = 0; i < size; ++i) + { + traits::iter_visit<GCView>::apply([&](auto const& g) + { + box_t b = geometry::return_envelope<box_t>(g, strategy); + detail::expand_by_epsilon(b); + values.emplace_back(b, i); + }, begin + i); + } + + return rtree_t(values.begin(), values.end(), rtree_parameters_t(rtree_param_t(), strategy)); +} + + +} // namespace detail +#endif // DOXYGEN_NO_DETAIL + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_GC_MAKE_RTREE_HPP diff --git a/boost/geometry/algorithms/detail/gc_topological_dimension.hpp b/boost/geometry/algorithms/detail/gc_topological_dimension.hpp new file mode 100644 index 0000000000..49f017945c --- /dev/null +++ b/boost/geometry/algorithms/detail/gc_topological_dimension.hpp @@ -0,0 +1,51 @@ +// Boost.Geometry + +// Copyright (c) 2022, Oracle and/or its affiliates. +// 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_GC_TOPOLOGICAL_DIMENSION_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_GC_TOPOLOGICAL_DIMENSION_HPP + + +#include <algorithm> + +#include <boost/geometry/algorithms/detail/visit.hpp> +#include <boost/geometry/algorithms/is_empty.hpp> +#include <boost/geometry/core/topological_dimension.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail +{ + + +template <typename GeometryCollection> +inline int gc_topological_dimension(GeometryCollection const& geometry) +{ + int result = -1; + detail::visit_breadth_first([&](auto const& g) + { + if (! geometry::is_empty(g)) + { + static const int d = geometry::topological_dimension<decltype(g)>::value; + result = (std::max)(result, d); + } + return result >= 2; + }, geometry); + return result; +} + + +} // namespace detail +#endif // DOXYGEN_NO_DETAIL + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_GC_TOPOLOGICAL_DIMENSION_HPP diff --git a/boost/geometry/algorithms/detail/has_self_intersections.hpp b/boost/geometry/algorithms/detail/has_self_intersections.hpp index 805ab6754a..0b13eb7bda 100644 --- a/boost/geometry/algorithms/detail/has_self_intersections.hpp +++ b/boost/geometry/algorithms/detail/has_self_intersections.hpp @@ -91,10 +91,8 @@ inline bool has_self_intersections(Geometry const& geometry, #ifdef BOOST_GEOMETRY_DEBUG_HAS_SELF_INTERSECTIONS bool first = true; #endif - for(typename std::deque<turn_info>::const_iterator it = boost::begin(turns); - it != boost::end(turns); ++it) + for (auto const& info : turns) { - turn_info const& info = *it; bool const both_union_turn = info.operations[0].operation == detail::overlay::operation_union && info.operations[1].operation == detail::overlay::operation_union; diff --git a/boost/geometry/algorithms/detail/interior_iterator.hpp b/boost/geometry/algorithms/detail/interior_iterator.hpp index 3582773c3d..1a9d4f1922 100644 --- a/boost/geometry/algorithms/detail/interior_iterator.hpp +++ b/boost/geometry/algorithms/detail/interior_iterator.hpp @@ -31,7 +31,7 @@ struct interior_iterator { typedef typename boost::range_iterator < - typename geometry::interior_type<Geometry>::type + typename geometry::interior_type<Geometry>::type >::type type; }; diff --git a/boost/geometry/algorithms/detail/intersection/areal_areal.hpp b/boost/geometry/algorithms/detail/intersection/areal_areal.hpp index 9faa1df55c..e657f825f2 100644 --- a/boost/geometry/algorithms/detail/intersection/areal_areal.hpp +++ b/boost/geometry/algorithms/detail/intersection/areal_areal.hpp @@ -155,7 +155,7 @@ struct intersection_areal_areal_<TupledOut, tupled_output_tag> pointlike::get(geometry_out), strategy); } - + return; } diff --git a/boost/geometry/algorithms/detail/intersection/gc.hpp b/boost/geometry/algorithms/detail/intersection/gc.hpp new file mode 100644 index 0000000000..fa492c0f34 --- /dev/null +++ b/boost/geometry/algorithms/detail/intersection/gc.hpp @@ -0,0 +1,329 @@ +// Boost.Geometry + +// Copyright (c) 2022, Oracle and/or its affiliates. +// 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_INTERSECTION_GC_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTION_GC_HPP + + +#include <tuple> + +#include <boost/geometry/algorithms/detail/gc_make_rtree.hpp> +#include <boost/geometry/algorithms/detail/intersection/interface.hpp> +#include <boost/geometry/views/detail/geometry_collection_view.hpp> + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace intersection +{ + + +template <typename GC, typename Multi> +struct gc_can_move_element +{ + template <typename G> + using is_same_as_single = std::is_same<G, typename boost::range_value<Multi>::type>; + using gc_types = typename traits::geometry_types<GC>::type; + using found_type = typename util::sequence_find_if<gc_types, is_same_as_single>::type; + static const bool value = ! std::is_void<found_type>::value; +}; + +template <typename GC, typename Multi> +struct gc_can_convert_element +{ + template <typename G> + using has_same_tag_as_single = std::is_same + < + typename geometry::tag<G>::type, + typename geometry::tag<typename boost::range_value<Multi>::type>::type + >; + using gc_types = typename traits::geometry_types<GC>::type; + using found_type = typename util::sequence_find_if<gc_types, has_same_tag_as_single>::type; + static const bool value = ! std::is_void<found_type>::value; +}; + +template +< + typename GC, typename Multi, + std::enable_if_t<gc_can_move_element<GC, Multi>::value, int> = 0 +> +inline void gc_move_one_elem_multi_back(GC& gc, Multi&& multi) +{ + range::emplace_back(gc, std::move(*boost::begin(multi))); +} + +template +< + typename GC, typename Multi, + std::enable_if_t<! gc_can_move_element<GC, Multi>::value && gc_can_convert_element<GC, Multi>::value, int> = 0 +> +inline void gc_move_one_elem_multi_back(GC& gc, Multi&& multi) +{ + typename gc_can_convert_element<GC, Multi>::found_type single_out; + geometry::convert(*boost::begin(multi), single_out); + range::emplace_back(gc, std::move(single_out)); +} + +template +< + typename GC, typename Multi, + std::enable_if_t<! gc_can_move_element<GC, Multi>::value && ! gc_can_convert_element<GC, Multi>::value, int> = 0 +> +inline void gc_move_one_elem_multi_back(GC& gc, Multi&& multi) +{ + range::emplace_back(gc, std::move(multi)); +} + +template <typename GC, typename Multi> +inline void gc_move_multi_back(GC& gc, Multi&& multi) +{ + if (! boost::empty(multi)) + { + if (boost::size(multi) == 1) + { + gc_move_one_elem_multi_back(gc, std::move(multi)); + } + else + { + range::emplace_back(gc, std::move(multi)); + } + } +} + + +}} // namespace detail::intersection +#endif // DOXYGEN_NO_DETAIL + + +namespace resolve_collection +{ + + +template +< + typename Geometry1, typename Geometry2, typename GeometryOut +> +struct intersection + < + Geometry1, Geometry2, GeometryOut, + geometry_collection_tag, geometry_collection_tag, geometry_collection_tag + > +{ + // NOTE: for now require all of the possible output types + // technically only a subset could be needed. + using multi_point_t = typename util::sequence_find_if + < + typename traits::geometry_types<GeometryOut>::type, + util::is_multi_point + >::type; + using multi_linestring_t = typename util::sequence_find_if + < + typename traits::geometry_types<GeometryOut>::type, + util::is_multi_linestring + >::type; + using multi_polygon_t = typename util::sequence_find_if + < + typename traits::geometry_types<GeometryOut>::type, + util::is_multi_polygon + >::type; + using tuple_out_t = boost::tuple<multi_point_t, multi_linestring_t, multi_polygon_t>; + + template <typename Strategy> + static inline bool apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + GeometryOut& geometry_out, + Strategy const& strategy) + { + bool result = false; + tuple_out_t out; + + auto const rtree2 = detail::gc_make_rtree_iterators(geometry2, strategy); + detail::visit_breadth_first([&](auto const& g1) + { + bool r = g1_prod_gc2(g1, rtree2, out, strategy); + result = result || r; + return true; + }, geometry1); + + detail::intersection::gc_move_multi_back(geometry_out, boost::get<0>(out)); + detail::intersection::gc_move_multi_back(geometry_out, boost::get<1>(out)); + detail::intersection::gc_move_multi_back(geometry_out, boost::get<2>(out)); + + return result; + } + +private: + // Implemented as separate function because msvc is unable to do nested lambda capture + template <typename G1, typename Rtree2, typename TupleOut, typename Strategy> + static bool g1_prod_gc2(G1 const& g1, Rtree2 const& rtree2, TupleOut& out, Strategy const& strategy) + { + bool result = false; + + using box1_t = detail::gc_make_rtree_box_t<G1>; + box1_t b1 = geometry::return_envelope<box1_t>(g1, strategy); + detail::expand_by_epsilon(b1); + + for (auto qit = rtree2.qbegin(index::intersects(b1)); qit != rtree2.qend(); ++qit) + { + traits::iter_visit<Geometry2>::apply([&](auto const& g2) + { + TupleOut inters_result; + using g2_t = util::remove_cref_t<decltype(g2)>; + intersection<G1, g2_t, TupleOut>::apply(g1, g2, inters_result, strategy); + + // TODO: If possible merge based on adjacency lists, i.e. merge + // only the intersections of elements that intersect each other + // as subgroups. So the result could contain merged intersections + // of several groups, not only one. + // TODO: It'd probably be better to gather all of the parts first + // and then merge them with merge_elements. + // NOTE: template explicitly called because gcc-6 doesn't compile it + // otherwise. + bool const r0 = intersection::template merge_result<0>(inters_result, out, strategy); + bool const r1 = intersection::template merge_result<1>(inters_result, out, strategy); + bool const r2 = intersection::template merge_result<2>(inters_result, out, strategy); + result = result || r0 || r1 || r2; + }, qit->second); + } + + return result; + } + + template <std::size_t Index, typename Out, typename Strategy> + static bool merge_result(Out const& inters_result, Out& out, Strategy const& strategy) + { + auto const& multi_result = boost::get<Index>(inters_result); + auto& multi_out = boost::get<Index>(out); + if (! boost::empty(multi_result)) + { + std::remove_reference_t<decltype(multi_out)> temp_result; + merge_two(multi_out, multi_result, temp_result, strategy); + multi_out = std::move(temp_result); + return true; + } + return false; + } + + template <typename Out, typename Strategy, std::enable_if_t<! util::is_pointlike<Out>::value, int> = 0> + static void merge_two(Out const& g1, Out const& g2, Out& out, Strategy const& strategy) + { + using rescale_policy_type = typename geometry::rescale_overlay_policy_type + < + Out, Out, typename Strategy::cs_tag + >::type; + + rescale_policy_type robust_policy + = geometry::get_rescale_policy<rescale_policy_type>( + g1, g2, strategy); + + geometry::dispatch::intersection_insert + < + Out, Out, typename boost::range_value<Out>::type, + overlay_union + >::apply(g1, + g2, + robust_policy, + geometry::range::back_inserter(out), + strategy); + } + + template <typename Out, typename Strategy, std::enable_if_t<util::is_pointlike<Out>::value, int> = 0> + static void merge_two(Out const& g1, Out const& g2, Out& out, Strategy const& strategy) + { + detail::overlay::union_pointlike_pointlike_point + < + Out, Out, typename boost::range_value<Out>::type + >::apply(g1, + g2, + 0, // dummy robust policy + geometry::range::back_inserter(out), + strategy); + } +}; + +template +< + typename Geometry1, typename Geometry2, typename GeometryOut, typename Tag1 +> +struct intersection + < + Geometry1, Geometry2, GeometryOut, + Tag1, geometry_collection_tag, geometry_collection_tag + > +{ + template <typename Strategy> + static inline bool apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + GeometryOut& geometry_out, + Strategy const& strategy) + { + using gc_view_t = geometry::detail::geometry_collection_view<Geometry1>; + return intersection + < + gc_view_t, Geometry2, GeometryOut + >::apply(gc_view_t(geometry1), geometry2, geometry_out, strategy); + } +}; + +template +< + typename Geometry1, typename Geometry2, typename GeometryOut, typename Tag2 +> +struct intersection + < + Geometry1, Geometry2, GeometryOut, + geometry_collection_tag, Tag2, geometry_collection_tag + > +{ + template <typename Strategy> + static inline bool apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + GeometryOut& geometry_out, + Strategy const& strategy) + { + using gc_view_t = geometry::detail::geometry_collection_view<Geometry2>; + return intersection + < + Geometry1, gc_view_t, GeometryOut + >::apply(geometry1, gc_view_t(geometry2), geometry_out, strategy); + } +}; + +template +< + typename Geometry1, typename Geometry2, typename GeometryOut, typename Tag1, typename Tag2 +> +struct intersection + < + Geometry1, Geometry2, GeometryOut, + Tag1, Tag2, geometry_collection_tag + > +{ + template <typename Strategy> + static inline bool apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + GeometryOut& geometry_out, + Strategy const& strategy) + { + using gc1_view_t = geometry::detail::geometry_collection_view<Geometry1>; + using gc2_view_t = geometry::detail::geometry_collection_view<Geometry2>; + return intersection + < + gc1_view_t, gc2_view_t, GeometryOut + >::apply(gc1_view_t(geometry1), gc2_view_t(geometry2), geometry_out, strategy); + } +}; + + +} // namespace resolve_collection + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTION_GC_HPP diff --git a/boost/geometry/algorithms/detail/intersection/implementation.hpp b/boost/geometry/algorithms/detail/intersection/implementation.hpp index eee3f25f91..199a05d015 100644 --- a/boost/geometry/algorithms/detail/intersection/implementation.hpp +++ b/boost/geometry/algorithms/detail/intersection/implementation.hpp @@ -2,8 +2,8 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. -// This file was modified by Oracle on 2014-2021. -// Modifications copyright (c) 2014-2021, Oracle and/or its affiliates. +// This file was modified by Oracle on 2014-2022. +// Modifications copyright (c) 2014-2022, 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/intersection/areal_areal.hpp> #include <boost/geometry/algorithms/detail/intersection/box_box.hpp> +#include <boost/geometry/algorithms/detail/intersection/gc.hpp> #include <boost/geometry/algorithms/detail/intersection/multi.hpp> #include <boost/geometry/strategies/relate/cartesian.hpp> diff --git a/boost/geometry/algorithms/detail/intersection/interface.hpp b/boost/geometry/algorithms/detail/intersection/interface.hpp index fcd7e959e7..84a9a57cc1 100644 --- a/boost/geometry/algorithms/detail/intersection/interface.hpp +++ b/boost/geometry/algorithms/detail/intersection/interface.hpp @@ -2,8 +2,8 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. -// This file was modified by Oracle on 2014-2020. -// Modifications copyright (c) 2014-2020, Oracle and/or its affiliates. +// This file was modified by Oracle on 2014-2022. +// Modifications copyright (c) 2014-2022, 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, @@ -14,17 +14,15 @@ #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTION_INTERFACE_HPP -#include <boost/variant/apply_visitor.hpp> -#include <boost/variant/static_visitor.hpp> -#include <boost/variant/variant_fwd.hpp> - #include <boost/geometry/algorithms/detail/overlay/intersection_insert.hpp> #include <boost/geometry/algorithms/detail/tupled_output.hpp> +#include <boost/geometry/geometries/adapted/boost_variant.hpp> #include <boost/geometry/policies/robustness/get_rescale_policy.hpp> #include <boost/geometry/strategies/default_strategy.hpp> #include <boost/geometry/strategies/detail.hpp> #include <boost/geometry/strategies/relate/services.hpp> #include <boost/geometry/util/range.hpp> +#include <boost/geometry/util/type_traits_std.hpp> namespace boost { namespace geometry @@ -107,25 +105,21 @@ struct intersection #endif // DOXYGEN_NO_DISPATCH -namespace resolve_strategy { +namespace resolve_collection +{ template < - typename Strategy, - bool IsUmbrella = strategies::detail::is_umbrella_strategy<Strategy>::value + typename Geometry1, typename Geometry2, typename GeometryOut, + typename Tag1 = typename geometry::tag<Geometry1>::type, + typename Tag2 = typename geometry::tag<Geometry2>::type, + typename TagOut = typename geometry::tag<GeometryOut>::type > struct intersection { - template - < - typename Geometry1, - typename Geometry2, - typename GeometryOut - > - static inline bool apply(Geometry1 const& geometry1, - Geometry2 const& geometry2, - GeometryOut & geometry_out, - Strategy const& strategy) + template <typename Strategy> + static bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, + GeometryOut & geometry_out, Strategy const& strategy) { typedef typename geometry::rescale_overlay_policy_type < @@ -133,7 +127,7 @@ struct intersection Geometry2, typename Strategy::cs_tag >::type rescale_policy_type; - + rescale_policy_type robust_policy = geometry::get_rescale_policy<rescale_policy_type>( geometry1, geometry2, strategy); @@ -147,6 +141,36 @@ struct intersection } }; +} // namespace resolve_collection + + +namespace resolve_strategy { + +template +< + typename Strategy, + bool IsUmbrella = strategies::detail::is_umbrella_strategy<Strategy>::value +> +struct intersection +{ + template + < + typename Geometry1, + typename Geometry2, + typename GeometryOut + > + static inline bool apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + GeometryOut & geometry_out, + Strategy const& strategy) + { + return resolve_collection::intersection + < + Geometry1, Geometry2, GeometryOut + >::apply(geometry1, geometry2, geometry_out, strategy); + } +}; + template <typename Strategy> struct intersection<Strategy, false> { @@ -199,21 +223,24 @@ struct intersection<default_strategy, false> } // resolve_strategy -namespace resolve_variant +namespace resolve_dynamic { - -template <typename Geometry1, typename Geometry2> + +template +< + typename Geometry1, typename Geometry2, + typename Tag1 = typename geometry::tag<Geometry1>::type, + typename Tag2 = typename geometry::tag<Geometry2>::type +> struct intersection { template <typename GeometryOut, typename Strategy> - static inline bool apply(Geometry1 const& geometry1, - Geometry2 const& geometry2, - GeometryOut& geometry_out, - Strategy const& strategy) + static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, + GeometryOut& geometry_out, Strategy const& strategy) { concepts::check<Geometry1 const>(); concepts::check<Geometry2 const>(); - + return resolve_strategy::intersection < Strategy @@ -222,135 +249,70 @@ struct intersection }; -template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2> -struct intersection<variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2> +template <typename DynamicGeometry1, typename Geometry2, typename Tag2> +struct intersection<DynamicGeometry1, Geometry2, dynamic_geometry_tag, Tag2> { template <typename GeometryOut, typename Strategy> - struct visitor: static_visitor<bool> + static inline bool apply(DynamicGeometry1 const& geometry1, Geometry2 const& geometry2, + GeometryOut& geometry_out, Strategy const& strategy) { - Geometry2 const& m_geometry2; - GeometryOut& m_geometry_out; - Strategy const& m_strategy; - - visitor(Geometry2 const& geometry2, - GeometryOut& geometry_out, - Strategy const& strategy) - : m_geometry2(geometry2) - , m_geometry_out(geometry_out) - , m_strategy(strategy) - {} - - template <typename Geometry1> - bool operator()(Geometry1 const& geometry1) const + bool result = false; + traits::visit<DynamicGeometry1>::apply([&](auto const& g1) { - return intersection + result = intersection < - Geometry1, + util::remove_cref_t<decltype(g1)>, Geometry2 - >::apply(geometry1, m_geometry2, m_geometry_out, m_strategy); - } - }; - - template <typename GeometryOut, typename Strategy> - static inline bool - apply(variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1, - Geometry2 const& geometry2, - GeometryOut& geometry_out, - Strategy const& strategy) - { - return boost::apply_visitor(visitor<GeometryOut, Strategy>(geometry2, - geometry_out, - strategy), - geometry1); + >::apply(g1, geometry2, geometry_out, strategy); + }, geometry1); + return result; } }; -template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)> -struct intersection<Geometry1, variant<BOOST_VARIANT_ENUM_PARAMS(T)> > +template <typename Geometry1, typename DynamicGeometry2, typename Tag1> +struct intersection<Geometry1, DynamicGeometry2, Tag1, dynamic_geometry_tag> { template <typename GeometryOut, typename Strategy> - struct visitor: static_visitor<bool> + static inline bool apply(Geometry1 const& geometry1, DynamicGeometry2 const& geometry2, + GeometryOut& geometry_out, Strategy const& strategy) { - Geometry1 const& m_geometry1; - GeometryOut& m_geometry_out; - Strategy const& m_strategy; - - visitor(Geometry1 const& geometry1, - GeometryOut& geometry_out, - Strategy const& strategy) - : m_geometry1(geometry1) - , m_geometry_out(geometry_out) - , m_strategy(strategy) - {} - - template <typename Geometry2> - bool operator()(Geometry2 const& geometry2) const + bool result = false; + traits::visit<DynamicGeometry2>::apply([&](auto const& g2) { - return intersection + result = intersection < Geometry1, - Geometry2 - >::apply(m_geometry1, geometry2, m_geometry_out, m_strategy); - } - }; - - template <typename GeometryOut, typename Strategy> - static inline bool - apply(Geometry1 const& geometry1, - variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2, - GeometryOut& geometry_out, - Strategy const& strategy) - { - return boost::apply_visitor(visitor<GeometryOut, Strategy>(geometry1, - geometry_out, - strategy), - geometry2); + util::remove_cref_t<decltype(g2)> + >::apply(geometry1, g2, geometry_out, strategy); + }, geometry2); + return result; } }; -template <BOOST_VARIANT_ENUM_PARAMS(typename T1), BOOST_VARIANT_ENUM_PARAMS(typename T2)> -struct intersection<variant<BOOST_VARIANT_ENUM_PARAMS(T1)>, variant<BOOST_VARIANT_ENUM_PARAMS(T2)> > +template <typename DynamicGeometry1, typename DynamicGeometry2> +struct intersection<DynamicGeometry1, DynamicGeometry2, dynamic_geometry_tag, dynamic_geometry_tag> { template <typename GeometryOut, typename Strategy> - struct visitor: static_visitor<bool> + static inline bool apply(DynamicGeometry1 const& geometry1, DynamicGeometry2 const& geometry2, + GeometryOut& geometry_out, Strategy const& strategy) { - GeometryOut& m_geometry_out; - Strategy const& m_strategy; - - visitor(GeometryOut& geometry_out, Strategy const& strategy) - : m_geometry_out(geometry_out) - , m_strategy(strategy) - {} - - template <typename Geometry1, typename Geometry2> - bool operator()(Geometry1 const& geometry1, - Geometry2 const& geometry2) const + bool result = false; + traits::visit<DynamicGeometry1, DynamicGeometry2>::apply([&](auto const& g1, auto const& g2) { - return intersection + result = intersection < - Geometry1, - Geometry2 - >::apply(geometry1, geometry2, m_geometry_out, m_strategy); - } - }; - - template <typename GeometryOut, typename Strategy> - static inline bool - apply(variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1, - variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2, - GeometryOut& geometry_out, - Strategy const& strategy) - { - return boost::apply_visitor(visitor<GeometryOut, Strategy>(geometry_out, - strategy), - geometry1, geometry2); + util::remove_cref_t<decltype(g1)>, + util::remove_cref_t<decltype(g2)> + >::apply(g1, g2, geometry_out, strategy); + }, geometry1, geometry2); + return result; } }; - -} // namespace resolve_variant - + +} // namespace resolve_dynamic + /*! \brief \brief_calc2{intersection} @@ -382,7 +344,7 @@ inline bool intersection(Geometry1 const& geometry1, GeometryOut& geometry_out, Strategy const& strategy) { - return resolve_variant::intersection + return resolve_dynamic::intersection < Geometry1, Geometry2 @@ -415,7 +377,7 @@ inline bool intersection(Geometry1 const& geometry1, Geometry2 const& geometry2, GeometryOut& geometry_out) { - return resolve_variant::intersection + return resolve_dynamic::intersection < Geometry1, Geometry2 diff --git a/boost/geometry/algorithms/detail/intersection/multi.hpp b/boost/geometry/algorithms/detail/intersection/multi.hpp index 42b9997fd0..7810abab50 100644 --- a/boost/geometry/algorithms/detail/intersection/multi.hpp +++ b/boost/geometry/algorithms/detail/intersection/multi.hpp @@ -2,8 +2,8 @@ // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. -// This file was modified by Oracle on 2014, 2020. -// Modifications copyright (c) 2014-2020, Oracle and/or its affiliates. +// This file was modified by Oracle on 2014-2022. +// Modifications copyright (c) 2014-2022, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -22,6 +22,8 @@ #include <boost/geometry/core/tags.hpp> #include <boost/geometry/geometries/concepts/check.hpp> +#include <boost/geometry/algorithms/detail/covered_by/implementation.hpp> + // TODO: those headers probably may be removed #include <boost/geometry/algorithms/detail/overlay/get_ring.hpp> #include <boost/geometry/algorithms/detail/overlay/get_turns.hpp> @@ -33,7 +35,6 @@ #include <boost/geometry/algorithms/detail/intersection/interface.hpp> -#include <boost/geometry/algorithms/covered_by.hpp> #include <boost/geometry/algorithms/envelope.hpp> #include <boost/geometry/algorithms/num_points.hpp> @@ -63,19 +64,9 @@ struct intersection_multi_linestring_multi_linestring_point { // Note, this loop is quadratic w.r.t. number of linestrings per input. // Future Enhancement: first do the sections of each, then intersect. - for (typename boost::range_iterator - < - MultiLinestring1 const - >::type it1 = boost::begin(ml1); - it1 != boost::end(ml1); - ++it1) + for (auto it1 = boost::begin(ml1); it1 != boost::end(ml1); ++it1) { - for (typename boost::range_iterator - < - MultiLinestring2 const - >::type it2 = boost::begin(ml2); - it2 != boost::end(ml2); - ++it2) + for (auto it2 = boost::begin(ml2); it2 != boost::end(ml2); ++it2) { out = intersection_linestring_linestring_point<PointOut> ::apply(*it1, *it2, robust_policy, out, strategy); @@ -102,12 +93,7 @@ struct intersection_linestring_multi_linestring_point OutputIterator out, Strategy const& strategy) { - for (typename boost::range_iterator - < - MultiLinestring const - >::type it = boost::begin(ml); - it != boost::end(ml); - ++it) + for (auto it = boost::begin(ml); it != boost::end(ml); ++it) { out = intersection_linestring_linestring_point<PointOut> ::apply(linestring, *it, robust_policy, out, strategy); @@ -140,12 +126,7 @@ struct intersection_of_multi_linestring_with_areal OutputIterator out, Strategy const& strategy) { - for (typename boost::range_iterator - < - MultiLinestring const - >::type it = boost::begin(ml); - it != boost::end(ml); - ++it) + for (auto it = boost::begin(ml); it != boost::end(ml); ++it) { out = intersection_of_linestring_with_areal < @@ -204,9 +185,7 @@ struct clip_multi_linestring { typedef typename point_type<LinestringOut>::type point_type; strategy::intersection::liang_barsky<Box, point_type> lb_strategy; - for (typename boost::range_iterator<MultiLinestring const>::type it - = boost::begin(multi_linestring); - it != boost::end(multi_linestring); ++it) + for (auto it = boost::begin(multi_linestring); it != boost::end(multi_linestring); ++it) { out = detail::intersection::clip_range_with_box <LinestringOut>(box, *it, robust_policy, out, lb_strategy); @@ -537,6 +516,40 @@ struct intersection_insert template < + typename Linestring, typename MultiPolygon, + typename TupledOut, + overlay_type OverlayType, + bool ReverseMultiLinestring, bool ReverseMultiPolygon +> +struct intersection_insert + < + Linestring, MultiPolygon, + TupledOut, + OverlayType, + ReverseMultiLinestring, ReverseMultiPolygon, + linestring_tag, multi_polygon_tag, detail::tupled_output_tag, + linear_tag, areal_tag, detail::tupled_output_tag + > : detail::intersection::intersection_of_linestring_with_areal + < + ReverseMultiPolygon, TupledOut, OverlayType, true + > + , detail::expect_output + < + Linestring, MultiPolygon, TupledOut, + // NOTE: points can be the result only in case of intersection. + // TODO: union should require L and A + std::conditional_t + < + (OverlayType == overlay_intersection), + point_tag, + void + >, + linestring_tag + > +{}; + +template +< typename MultiLinestring, typename MultiPolygon, typename TupledOut, overlay_type OverlayType, diff --git a/boost/geometry/algorithms/detail/is_simple/areal.hpp b/boost/geometry/algorithms/detail/is_simple/areal.hpp index 4fc3fa26e5..952aa4e549 100644 --- a/boost/geometry/algorithms/detail/is_simple/areal.hpp +++ b/boost/geometry/algorithms/detail/is_simple/areal.hpp @@ -49,12 +49,12 @@ template <typename InteriorRings, typename Strategy> inline bool are_simple_interior_rings(InteriorRings const& interior_rings, Strategy const& strategy) { - auto const end = boost::end(interior_rings); - return std::find_if(boost::begin(interior_rings), end, - [&](auto const& r) - { - return ! is_simple_ring(r, strategy); - }) == end; // non-simple ring not found + return std::all_of(boost::begin(interior_rings), + boost::end(interior_rings), + [&](auto const& r) + { + return is_simple_ring(r, strategy); + }); // non-simple ring not found // allow empty ring } @@ -116,12 +116,11 @@ struct is_simple<MultiPolygon, multi_polygon_tag> template <typename Strategy> static inline bool apply(MultiPolygon const& multipolygon, Strategy const& strategy) { - auto const end = boost::end(multipolygon); - return std::find_if(boost::begin(multipolygon), end, - [&](auto const& po) { - return ! detail::is_simple::is_simple_polygon(po, strategy); - }) == end; // non-simple polygon not found - // allow empty multi-polygon + return std::none_of(boost::begin(multipolygon), boost::end(multipolygon), + [&](auto const& po) { + return ! detail::is_simple::is_simple_polygon(po, strategy); + }); // non-simple polygon not found + // allow empty multi-polygon } }; diff --git a/boost/geometry/algorithms/detail/is_simple/debug_print_boundary_points.hpp b/boost/geometry/algorithms/detail/is_simple/debug_print_boundary_points.hpp index b336d44f67..7136e5167e 100644 --- a/boost/geometry/algorithms/detail/is_simple/debug_print_boundary_points.hpp +++ b/boost/geometry/algorithms/detail/is_simple/debug_print_boundary_points.hpp @@ -69,9 +69,7 @@ struct debug_boundary_points_printer<MultiLinestring, multi_linestring_tag> typedef std::vector<point_type> point_vector; point_vector boundary_points; - for (typename boost::range_iterator<MultiLinestring const>::type it - = boost::begin(multilinestring); - it != boost::end(multilinestring); ++it) + for (auto it = boost::begin(multilinestring); it != boost::end(multilinestring); ++it) { if ( boost::size(*it) > 1 && !geometry::equals(range::front(*it), range::back(*it)) ) @@ -85,11 +83,9 @@ struct debug_boundary_points_printer<MultiLinestring, multi_linestring_tag> geometry::less<point_type>()); std::cout << "boundary points: "; - for (typename point_vector::const_iterator - pit = boundary_points.begin(); - pit != boundary_points.end(); ++pit) + for (auto const& p : boundary_points) { - std::cout << " " << geometry::dsv(*pit); + std::cout << " " << geometry::dsv(p); } std::cout << std::endl << std::endl; } diff --git a/boost/geometry/algorithms/detail/is_simple/linear.hpp b/boost/geometry/algorithms/detail/is_simple/linear.hpp index 090824c25e..e2ac77ad56 100644 --- a/boost/geometry/algorithms/detail/is_simple/linear.hpp +++ b/boost/geometry/algorithms/detail/is_simple/linear.hpp @@ -2,6 +2,7 @@ // Copyright (c) 2014-2021, 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 @@ -36,7 +37,6 @@ #include <boost/geometry/algorithms/intersects.hpp> #include <boost/geometry/algorithms/not_implemented.hpp> -#include <boost/geometry/algorithms/detail/check_iterator_range.hpp> #include <boost/geometry/algorithms/detail/signed_size_type.hpp> #include <boost/geometry/algorithms/detail/disjoint/linear_linear.hpp> @@ -158,7 +158,7 @@ public: inline bool apply(Turn const& turn) const { typedef typename boost::range_value<MultiLinestring>::type linestring_type; - + linestring_type const& ls1 = range::at(m_multilinestring, turn.operations[0].seg_id.multi_index); @@ -261,16 +261,16 @@ struct is_simple_multilinestring { private: template <typename Strategy> - struct per_linestring + struct not_simple { - per_linestring(Strategy const& strategy) + not_simple(Strategy const& strategy) : m_strategy(strategy) {} template <typename Linestring> - inline bool apply(Linestring const& linestring) const + inline bool operator()(Linestring const& linestring) const { - return detail::is_simple::is_simple_linestring + return ! detail::is_simple::is_simple_linestring < Linestring, false // do not compute self-intersections @@ -285,19 +285,16 @@ public: static inline bool apply(MultiLinestring const& multilinestring, Strategy const& strategy) { - typedef per_linestring<Strategy> per_ls; - // check each of the linestrings for simplicity // but do not compute self-intersections yet; these will be // computed for the entire multilinestring - if ( ! detail::check_iterator_range - < - per_ls, // do not compute self-intersections - true // allow empty multilinestring - >::apply(boost::begin(multilinestring), - boost::end(multilinestring), - per_ls(strategy)) - ) + // return true for empty multilinestring + + using not_simple = not_simple<Strategy>; // do not compute self-intersections + + if (std::any_of(boost::begin(multilinestring), + boost::end(multilinestring), + not_simple(strategy))) { return false; } diff --git a/boost/geometry/algorithms/detail/is_simple/multipoint.hpp b/boost/geometry/algorithms/detail/is_simple/multipoint.hpp index 2d2e52130f..2eba68f97e 100644 --- a/boost/geometry/algorithms/detail/is_simple/multipoint.hpp +++ b/boost/geometry/algorithms/detail/is_simple/multipoint.hpp @@ -1,7 +1,8 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014-2021, Oracle and/or its affiliates. +// Copyright (c) 2014-2023, 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 @@ -44,12 +45,11 @@ struct is_simple_multipoint template <typename Strategy> static inline bool apply(MultiPoint const& multipoint, Strategy const& strategy) { - typedef typename Strategy::cs_tag cs_tag; typedef geometry::less < typename point_type<MultiPoint>::type, -1, - cs_tag + Strategy > less_type; if (boost::empty(multipoint)) diff --git a/boost/geometry/algorithms/detail/is_valid/complement_graph.hpp b/boost/geometry/algorithms/detail/is_valid/complement_graph.hpp index 67a94f1016..9a51d30eb4 100644 --- a/boost/geometry/algorithms/detail/is_valid/complement_graph.hpp +++ b/boost/geometry/algorithms/detail/is_valid/complement_graph.hpp @@ -1,7 +1,8 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014, 2018, 2019, Oracle and/or its affiliates. +// Copyright (c) 2014-2023, 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 @@ -32,7 +33,7 @@ namespace detail { namespace is_valid { -template <typename TurnPoint, typename CSTag> +template <typename TurnPoint, typename Strategy> class complement_graph_vertex { public: @@ -55,7 +56,7 @@ public: { return geometry::less < - TurnPoint, -1, CSTag + TurnPoint, -1, Strategy >()(*m_turn_point, *other.m_turn_point); } if ( m_turn_point == NULL && other.m_turn_point == NULL ) @@ -77,11 +78,11 @@ private: -template <typename TurnPoint, typename CSTag> +template <typename TurnPoint, typename Strategy> class complement_graph { private: - typedef complement_graph_vertex<TurnPoint, CSTag> vertex; + typedef complement_graph_vertex<TurnPoint, Strategy> vertex; typedef std::set<vertex> vertex_container; public: @@ -224,9 +225,10 @@ public: } #ifdef BOOST_GEOMETRY_TEST_DEBUG - template <typename OStream, typename TP> + template <typename OutputStream> friend inline - void debug_print_complement_graph(OStream&, complement_graph<TP> const&); + void debug_print_complement_graph(OutputStream&, + complement_graph<TurnPoint, Strategy> const&); #endif // BOOST_GEOMETRY_TEST_DEBUG private: 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 5d16e2ea3c..4e4b978b53 100644 --- a/boost/geometry/algorithms/detail/is_valid/debug_complement_graph.hpp +++ b/boost/geometry/algorithms/detail/is_valid/debug_complement_graph.hpp @@ -1,7 +1,8 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014, 2018, 2019, Oracle and/or its affiliates. +// Copyright (c) 2014-2023, 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 @@ -25,12 +26,12 @@ namespace detail { namespace is_valid #ifdef BOOST_GEOMETRY_TEST_DEBUG -template <typename OutputStream, typename TurnPoint, typename CSTag> +template <typename OutputStream, typename TurnPoint, typename Strategy> inline void debug_print_complement_graph(OutputStream& os, - complement_graph<TurnPoint, CSTag> const& graph) + complement_graph<TurnPoint, Strategy> const& graph) { - typedef typename complement_graph<TurnPoint>::vertex_handle vertex_handle; + typedef typename complement_graph<TurnPoint, Strategy>::vertex_handle vertex_handle; os << "num rings: " << graph.m_num_rings << std::endl; os << "vertex ids: {"; @@ -39,7 +40,7 @@ debug_print_complement_graph(OutputStream& os, { os << " " << it->id(); } - os << " }" << std::endl; + os << " }" << std::endl; for (vertex_handle it = graph.m_vertices.begin(); it != graph.m_vertices.end(); ++it) @@ -47,20 +48,20 @@ debug_print_complement_graph(OutputStream& os, os << "neighbors of " << it->id() << ": {"; for (typename complement_graph < - TurnPoint + TurnPoint, Strategy >::neighbor_container::const_iterator nit = graph.m_neighbors[it->id()].begin(); nit != graph.m_neighbors[it->id()].end(); ++nit) { os << " " << (*nit)->id(); } - os << "}" << std::endl; + os << "}" << std::endl; } } #else -template <typename OutputStream, typename TurnPoint, typename CSTag> +template <typename OutputStream, typename TurnPoint, typename Strategy> inline void debug_print_complement_graph(OutputStream&, - complement_graph<TurnPoint, CSTag> const&) + complement_graph<TurnPoint, Strategy> const&) { } #endif 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 ce0853d20c..82a1f5f4cd 100644 --- a/boost/geometry/algorithms/detail/is_valid/has_invalid_coordinate.hpp +++ b/boost/geometry/algorithms/detail/is_valid/has_invalid_coordinate.hpp @@ -1,7 +1,8 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014-2020, Oracle and/or its affiliates. +// Copyright (c) 2014-2021, 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 @@ -14,7 +15,6 @@ #include <cstddef> #include <type_traits> -#include <boost/geometry/algorithms/detail/check_iterator_range.hpp> #include <boost/geometry/algorithms/validity_failure_type.hpp> #include <boost/geometry/core/coordinate_type.hpp> @@ -28,7 +28,7 @@ namespace boost { namespace geometry { - + #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace is_valid { @@ -80,26 +80,19 @@ struct indexed_has_invalid_coordinate struct range_has_invalid_coordinate { - struct point_has_valid_coordinates - { - template <typename Point> - static inline bool apply(Point const& point) - { - return ! point_has_invalid_coordinate::apply(point); - } - }; - template <typename Geometry, typename VisitPolicy> static inline bool apply(Geometry const& geometry, VisitPolicy& visitor) { boost::ignore_unused(visitor); - bool const has_valid_coordinates = detail::check_iterator_range - < - point_has_valid_coordinates, - true // do not consider an empty range as problematic - >::apply(geometry::points_begin(geometry), - geometry::points_end(geometry)); + auto const points_end = geometry::points_end(geometry); + bool const has_valid_coordinates = std::none_of + ( + geometry::points_begin(geometry), points_end, + []( auto const& point ){ + return point_has_invalid_coordinate::apply(point); + } + ); return has_valid_coordinates ? diff --git a/boost/geometry/algorithms/detail/is_valid/has_spikes.hpp b/boost/geometry/algorithms/detail/is_valid/has_spikes.hpp index 6dbaa49bc7..08e9ab43d2 100644 --- a/boost/geometry/algorithms/detail/is_valid/has_spikes.hpp +++ b/boost/geometry/algorithms/detail/is_valid/has_spikes.hpp @@ -56,7 +56,9 @@ struct has_spikes Strategy const& strategy) { if (first == last) + { return last; + } auto const& front = *first; ++first; return std::find_if(first, last, [&](auto const& pt) { @@ -71,18 +73,12 @@ struct has_spikes { boost::ignore_unused(visitor); - typedef typename boost::range_iterator<View const>::type iterator; + auto cur = boost::begin(view); + auto prev = find_different_from_first(boost::rbegin(view), + boost::rend(view), + strategy); - iterator cur = boost::begin(view); - typename boost::range_reverse_iterator - < - View const - >::type prev = find_different_from_first(boost::rbegin(view), - boost::rend(view), - strategy); - - iterator next = find_different_from_first(cur, boost::end(view), - strategy); + auto next = find_different_from_first(cur, boost::end(view), strategy); if (detail::is_spike_or_equal(*next, *cur, *prev, strategy.side())) { return ! visitor.template apply<failure_spikes>(is_linear, *cur); @@ -131,8 +127,7 @@ struct has_spikes // also in geographic cases going over the pole if (detail::is_spike_or_equal(*next, *cur, *prev, strategy.side())) { - return - ! visitor.template apply<failure_spikes>(is_linestring, *cur); + return ! visitor.template apply<failure_spikes>(is_linestring, *cur); } prev = cur; cur = next; 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 6c33961b3b..b12c42c8e9 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-2020, Oracle and/or its affiliates. +// Copyright (c) 2014-2021, 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 @@ -54,11 +54,6 @@ private: CSTag >::type rescale_policy_type; - typedef detail::overlay::get_turn_info - < - detail::overlay::assign_null_policy - > turn_policy; - public: typedef detail::overlay::turn_info < @@ -88,12 +83,11 @@ public: > interrupt_policy; // Calculate self-turns, skipping adjacent segments - detail::self_get_turn_points::self_turns<false, turn_policy>(geometry, - strategy, - robust_policy, - turns, - interrupt_policy, - 0, true); + detail::self_get_turn_points::self_turns + < + false, detail::overlay::assign_null_policy + >(geometry, strategy, robust_policy, turns, interrupt_policy, + 0, true); if (interrupt_policy.has_intersections) { diff --git a/boost/geometry/algorithms/detail/is_valid/interface.hpp b/boost/geometry/algorithms/detail/is_valid/interface.hpp index 4f8d1f5435..53576d20cb 100644 --- a/boost/geometry/algorithms/detail/is_valid/interface.hpp +++ b/boost/geometry/algorithms/detail/is_valid/interface.hpp @@ -1,6 +1,6 @@ // Boost.Geometry -// Copyright (c) 2014-2020, Oracle and/or its affiliates. +// Copyright (c) 2014-2021, 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 @@ -14,12 +14,11 @@ #include <sstream> #include <string> -#include <boost/variant/apply_visitor.hpp> -#include <boost/variant/static_visitor.hpp> -#include <boost/variant/variant_fwd.hpp> - +#include <boost/geometry/algorithms/detail/visit.hpp> #include <boost/geometry/algorithms/dispatch/is_valid.hpp> #include <boost/geometry/core/cs.hpp> +#include <boost/geometry/core/visit.hpp> +#include <boost/geometry/geometries/adapted/boost_variant.hpp> // For backward compatibility #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/policies/is_valid/default_policy.hpp> #include <boost/geometry/policies/is_valid/failing_reason_policy.hpp> @@ -31,7 +30,7 @@ namespace boost { namespace geometry { - + namespace resolve_strategy { @@ -90,10 +89,10 @@ struct is_valid<default_strategy, false> } // namespace resolve_strategy -namespace resolve_variant +namespace resolve_dynamic { -template <typename Geometry> +template <typename Geometry, typename Tag = typename tag<Geometry>::type> struct is_valid { template <typename VisitPolicy, typename Strategy> @@ -110,39 +109,42 @@ struct is_valid } }; -template <BOOST_VARIANT_ENUM_PARAMS(typename T)> -struct is_valid<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > +template <typename Geometry> +struct is_valid<Geometry, dynamic_geometry_tag> { template <typename VisitPolicy, typename Strategy> - struct visitor : boost::static_visitor<bool> + static inline bool apply(Geometry const& geometry, + VisitPolicy& policy_visitor, + Strategy const& strategy) { - visitor(VisitPolicy& policy, Strategy const& strategy) - : m_policy(policy) - , m_strategy(strategy) - {} - - template <typename Geometry> - bool operator()(Geometry const& geometry) const + bool result = true; + traits::visit<Geometry>::apply([&](auto const& g) { - return is_valid<Geometry>::apply(geometry, m_policy, m_strategy); - } - - VisitPolicy& m_policy; - Strategy const& m_strategy; - }; + result = is_valid<util::remove_cref_t<decltype(g)>>::apply(g, policy_visitor, strategy); + }, geometry); + return result; + } +}; +template <typename Geometry> +struct is_valid<Geometry, geometry_collection_tag> +{ template <typename VisitPolicy, typename Strategy> - static inline bool - apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry, - VisitPolicy& policy_visitor, - Strategy const& strategy) + static inline bool apply(Geometry const& geometry, + VisitPolicy& policy_visitor, + Strategy const& strategy) { - return boost::apply_visitor(visitor<VisitPolicy, Strategy>(policy_visitor, strategy), - geometry); + bool result = true; + detail::visit_breadth_first([&](auto const& g) + { + result = is_valid<util::remove_cref_t<decltype(g)>>::apply(g, policy_visitor, strategy); + return result; + }, geometry); + return result; } }; -} // namespace resolve_variant +} // namespace resolve_dynamic // Undocumented for now @@ -151,7 +153,7 @@ inline bool is_valid(Geometry const& geometry, VisitPolicy& visitor, Strategy const& strategy) { - return resolve_variant::is_valid<Geometry>::apply(geometry, visitor, strategy); + return resolve_dynamic::is_valid<Geometry>::apply(geometry, visitor, strategy); } @@ -175,7 +177,7 @@ template <typename Geometry, typename Strategy> inline bool is_valid(Geometry const& geometry, Strategy const& strategy) { is_valid_default_policy<> visitor; - return resolve_variant::is_valid<Geometry>::apply(geometry, visitor, strategy); + return resolve_dynamic::is_valid<Geometry>::apply(geometry, visitor, strategy); } /*! @@ -220,7 +222,7 @@ template <typename Geometry, typename Strategy> inline bool is_valid(Geometry const& geometry, validity_failure_type& failure, Strategy const& strategy) { failure_type_policy<> visitor; - bool result = resolve_variant::is_valid<Geometry>::apply(geometry, visitor, strategy); + bool result = resolve_dynamic::is_valid<Geometry>::apply(geometry, visitor, strategy); failure = visitor.failure(); return result; } @@ -271,7 +273,7 @@ inline bool is_valid(Geometry const& geometry, std::string& message, Strategy co { std::ostringstream stream; failing_reason_policy<> visitor(stream); - bool result = resolve_variant::is_valid<Geometry>::apply(geometry, visitor, strategy); + bool result = resolve_dynamic::is_valid<Geometry>::apply(geometry, visitor, strategy); message = stream.str(); return result; } diff --git a/boost/geometry/algorithms/detail/is_valid/is_acceptable_turn.hpp b/boost/geometry/algorithms/detail/is_valid/is_acceptable_turn.hpp index 9ca82b1071..4aad18881d 100644 --- a/boost/geometry/algorithms/detail/is_valid/is_acceptable_turn.hpp +++ b/boost/geometry/algorithms/detail/is_valid/is_acceptable_turn.hpp @@ -151,7 +151,7 @@ public: || turn.method == method_touch_interior) && turn.touch_only; } -}; +}; }} // namespace detail::is_valid diff --git a/boost/geometry/algorithms/detail/is_valid/linear.hpp b/boost/geometry/algorithms/detail/is_valid/linear.hpp index 69cb76e5d5..3753c87a42 100644 --- a/boost/geometry/algorithms/detail/is_valid/linear.hpp +++ b/boost/geometry/algorithms/detail/is_valid/linear.hpp @@ -1,7 +1,9 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014-2021, Oracle and/or its affiliates. +// Copyright (c) 2023 Adam Wulkiewicz, Lodz, Poland. +// Copyright (c) 2014-2021, 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 @@ -20,7 +22,6 @@ #include <boost/geometry/algorithms/equals.hpp> #include <boost/geometry/algorithms/validity_failure_type.hpp> -#include <boost/geometry/algorithms/detail/check_iterator_range.hpp> #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/num_distinct_consecutive_points.hpp> @@ -31,7 +32,7 @@ #include <boost/geometry/core/point_type.hpp> #include <boost/geometry/core/tags.hpp> -#include <boost/geometry/util/condition.hpp> +#include <boost/geometry/util/constexpr.hpp> namespace boost { namespace geometry @@ -105,7 +106,7 @@ namespace dispatch // A curve is simple if it does not pass through the same point twice, // with the possible exception of its two endpoints // -// There is an option here as to whether spikes are allowed for linestrings; +// There is an option here as to whether spikes are allowed for linestrings; // here we pass this as an additional template parameter: allow_spikes // If allow_spikes is set to true, spikes are allowed, false otherwise. // By default, spikes are disallowed @@ -131,7 +132,6 @@ class is_valid MultiLinestring, multi_linestring_tag, AllowEmptyMultiGeometries > { -private: template <typename VisitPolicy, typename Strategy> struct per_linestring { @@ -141,7 +141,7 @@ private: {} template <typename Linestring> - inline bool apply(Linestring const& linestring) const + inline bool operator()(Linestring const& linestring) const { return detail::is_valid::is_valid_linestring < @@ -159,21 +159,19 @@ public: VisitPolicy& visitor, Strategy const& strategy) { - if (BOOST_GEOMETRY_CONDITION( - AllowEmptyMultiGeometries && boost::empty(multilinestring))) + if BOOST_GEOMETRY_CONSTEXPR (AllowEmptyMultiGeometries) { - return visitor.template apply<no_failure>(); + if (boost::empty(multilinestring)) + { + return visitor.template apply<no_failure>(); + } } - typedef per_linestring<VisitPolicy, Strategy> per_ls; + using per_ls = per_linestring<VisitPolicy, Strategy>; - return detail::check_iterator_range - < - per_ls, - false // do not check for empty multilinestring (done above) - >::apply(boost::begin(multilinestring), - boost::end(multilinestring), - per_ls(visitor, strategy)); + return std::all_of(boost::begin(multilinestring), + boost::end(multilinestring), + per_ls(visitor, strategy)); } }; diff --git a/boost/geometry/algorithms/detail/is_valid/multipolygon.hpp b/boost/geometry/algorithms/detail/is_valid/multipolygon.hpp index 0b3b4c4a74..5af933de85 100644 --- a/boost/geometry/algorithms/detail/is_valid/multipolygon.hpp +++ b/boost/geometry/algorithms/detail/is_valid/multipolygon.hpp @@ -1,7 +1,9 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014-2020, Oracle and/or its affiliates. +// Copyright (c) 2023 Adam Wulkiewicz, Lodz, Poland. +// Copyright (c) 2014-2021, 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 @@ -26,7 +28,7 @@ #include <boost/geometry/core/ring_type.hpp> #include <boost/geometry/core/tags.hpp> -#include <boost/geometry/util/condition.hpp> +#include <boost/geometry/util/constexpr.hpp> #include <boost/geometry/util/range.hpp> #include <boost/geometry/geometries/box.hpp> @@ -34,7 +36,6 @@ #include <boost/geometry/algorithms/validity_failure_type.hpp> #include <boost/geometry/algorithms/within.hpp> -#include <boost/geometry/algorithms/detail/check_iterator_range.hpp> #include <boost/geometry/algorithms/detail/partition.hpp> #include <boost/geometry/algorithms/detail/is_valid/has_valid_self_turns.hpp> @@ -257,55 +258,56 @@ private: template <typename VisitPolicy, typename Strategy> - struct per_polygon + struct is_invalid_polygon { - per_polygon(VisitPolicy& policy, Strategy const& strategy) + is_invalid_polygon(VisitPolicy& policy, Strategy const& strategy) : m_policy(policy) , m_strategy(strategy) {} template <typename Polygon> - inline bool apply(Polygon const& polygon) const + inline bool operator()(Polygon const& polygon) const { - return base::apply(polygon, m_policy, m_strategy); + return ! base::apply(polygon, m_policy, m_strategy); } VisitPolicy& m_policy; Strategy const& m_strategy; }; + public: template <typename VisitPolicy, typename Strategy> static inline bool apply(MultiPolygon const& multipolygon, VisitPolicy& visitor, Strategy const& strategy) { - typedef debug_validity_phase<MultiPolygon> debug_phase; + using debug_phase = debug_validity_phase<MultiPolygon>; - if (BOOST_GEOMETRY_CONDITION(AllowEmptyMultiGeometries) - && boost::empty(multipolygon)) + if BOOST_GEOMETRY_CONSTEXPR (AllowEmptyMultiGeometries) { - return visitor.template apply<no_failure>(); + if (boost::empty(multipolygon)) + { + return visitor.template apply<no_failure>(); + } } // check validity of all polygons ring debug_phase::apply(1); - if (! detail::check_iterator_range - < - per_polygon<VisitPolicy, Strategy>, - false // do not check for empty multipolygon (done above) - >::apply(boost::begin(multipolygon), - boost::end(multipolygon), - per_polygon<VisitPolicy, Strategy>(visitor, strategy))) + if (std::any_of(boost::begin(multipolygon), boost::end(multipolygon), + is_invalid_polygon<VisitPolicy, Strategy>(visitor, strategy))) { return false; } - // compute turns and check if all are acceptable debug_phase::apply(2); - typedef has_valid_self_turns<MultiPolygon, typename Strategy::cs_tag> has_valid_turns; + using has_valid_turns = has_valid_self_turns + < + MultiPolygon, + typename Strategy::cs_tag + >; std::deque<typename has_valid_turns::turn_type> turns; bool has_invalid_turns = diff --git a/boost/geometry/algorithms/detail/is_valid/polygon.hpp b/boost/geometry/algorithms/detail/is_valid/polygon.hpp index 72ae593f8e..39512ad154 100644 --- a/boost/geometry/algorithms/detail/is_valid/polygon.hpp +++ b/boost/geometry/algorithms/detail/is_valid/polygon.hpp @@ -1,9 +1,9 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland. - -// Copyright (c) 2014-2020, Oracle and/or its affiliates. +// Copyright (c) 2017-2023 Adam Wulkiewicz, Lodz, Poland. +// Copyright (c) 2014-2023, 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 @@ -34,7 +34,7 @@ #include <boost/geometry/core/ring_type.hpp> #include <boost/geometry/core/tags.hpp> -#include <boost/geometry/util/condition.hpp> +#include <boost/geometry/util/constexpr.hpp> #include <boost/geometry/util/range.hpp> #include <boost/geometry/util/sequence.hpp> @@ -50,7 +50,6 @@ #include <boost/geometry/algorithms/detail/point_on_border.hpp> #include <boost/geometry/algorithms/within.hpp> -#include <boost/geometry/algorithms/detail/check_iterator_range.hpp> #include <boost/geometry/algorithms/detail/partition.hpp> #include <boost/geometry/algorithms/detail/is_valid/complement_graph.hpp> @@ -86,17 +85,17 @@ class is_valid_polygon protected: template <typename VisitPolicy, typename Strategy> - struct per_ring + struct is_invalid_ring { - per_ring(VisitPolicy& policy, Strategy const& strategy) + is_invalid_ring(VisitPolicy& policy, Strategy const& strategy) : m_policy(policy) , m_strategy(strategy) {} template <typename Ring> - inline bool apply(Ring const& ring) const + inline bool operator()(Ring const& ring) const { - return detail::is_valid::is_valid_ring + return ! detail::is_valid::is_valid_ring < Ring, false, true >::apply(ring, m_policy, m_strategy); @@ -111,14 +110,9 @@ protected: VisitPolicy& visitor, Strategy const& strategy) { - return - detail::check_iterator_range - < - per_ring<VisitPolicy, Strategy>, - true // allow for empty interior ring range - >::apply(boost::begin(interior_rings), - boost::end(interior_rings), - per_ring<VisitPolicy, Strategy>(visitor, strategy)); + return std::none_of(boost::begin(interior_rings), + boost::end(interior_rings), + is_invalid_ring<VisitPolicy, Strategy>(visitor, strategy)); } struct has_valid_rings @@ -372,7 +366,7 @@ protected: } struct has_holes_inside - { + { template <typename TurnIterator, typename VisitPolicy, typename Strategy> static inline bool apply(Polygon const& polygon, TurnIterator first, @@ -410,7 +404,7 @@ protected: typedef complement_graph < typename turn_type::point_type, - typename Strategy::cs_tag + Strategy > graph; graph g(geometry::num_interior_rings(polygon) + 1); @@ -452,7 +446,7 @@ public: return false; } - if (BOOST_GEOMETRY_CONDITION(CheckRingValidityOnly)) + if BOOST_GEOMETRY_CONSTEXPR (CheckRingValidityOnly) { return true; } diff --git a/boost/geometry/algorithms/detail/make/make.hpp b/boost/geometry/algorithms/detail/make/make.hpp index 566936b86a..45aa6ed473 100644 --- a/boost/geometry/algorithms/detail/make/make.hpp +++ b/boost/geometry/algorithms/detail/make/make.hpp @@ -19,10 +19,10 @@ namespace boost { namespace geometry namespace detail { namespace make { -template <typename Type, typename Coordinate> +template <typename Type, typename Coordinate1, typename Coordinate2> inline -model::infinite_line<Type> make_infinite_line(Coordinate const& x1, - Coordinate const& y1, Coordinate const& x2, Coordinate const& y2) +model::infinite_line<Type> make_infinite_line(Coordinate1 const& x1, + Coordinate1 const& y1, Coordinate2 const& x2, Coordinate2 const& y2) { model::infinite_line<Type> result; result.a = y1 - y2; @@ -31,9 +31,9 @@ model::infinite_line<Type> make_infinite_line(Coordinate const& x1, return result; } -template <typename Type, typename Point> +template <typename Type, typename PointA, typename PointB> inline -model::infinite_line<Type> make_infinite_line(Point const& a, Point const& b) +model::infinite_line<Type> make_infinite_line(PointA const& a, PointB const& b) { return make_infinite_line<Type>(geometry::get<0>(a), geometry::get<1>(a), geometry::get<0>(b), geometry::get<1>(b)); @@ -49,9 +49,9 @@ model::infinite_line<Type> make_infinite_line(Segment const& segment) geometry::get<1, 1>(segment)); } -template <typename Type, typename Point> +template <typename Type, typename PointA, typename PointB, typename PointC> inline -model::infinite_line<Type> make_perpendicular_line(Point const& a, Point const& b, Point const& c) +model::infinite_line<Type> make_perpendicular_line(PointA const& a, PointB const& b, PointC const& c) { // https://www.math-only-math.com/equation-of-a-line-perpendicular-to-a-line.html model::infinite_line<Type> const line = make_infinite_line<Type>(a, b); diff --git a/boost/geometry/algorithms/detail/max_interval_gap.hpp b/boost/geometry/algorithms/detail/max_interval_gap.hpp index f71efc9aa6..905491ef36 100644 --- a/boost/geometry/algorithms/detail/max_interval_gap.hpp +++ b/boost/geometry/algorithms/detail/max_interval_gap.hpp @@ -225,7 +225,7 @@ maximum_gap(RangeOfIntervals const& range_of_intervals, std::priority_queue < event_type, - std::vector<event_type>, + std::vector<event_type>, detail::max_interval_gap::event_greater<event_type> > queue; diff --git a/boost/geometry/algorithms/detail/multi_modify.hpp b/boost/geometry/algorithms/detail/multi_modify.hpp index 9c2f180067..58597ed6f3 100644 --- a/boost/geometry/algorithms/detail/multi_modify.hpp +++ b/boost/geometry/algorithms/detail/multi_modify.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-2020. -// Modifications copyright (c) 2017-2020 Oracle and/or its affiliates. +// This file was modified by Oracle on 2017-2021. +// Modifications copyright (c) 2017-2021 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 @@ -32,27 +32,24 @@ namespace detail { -template <typename MultiGeometry, typename Policy> +template <typename Policy> struct multi_modify { + template <typename MultiGeometry> static inline void apply(MultiGeometry& multi) { - typedef typename boost::range_iterator<MultiGeometry>::type iterator_type; - for (iterator_type it = boost::begin(multi); - it != boost::end(multi); - ++it) + auto const end = boost::end(multi); + for (auto it = boost::begin(multi); it != end; ++it) { Policy::apply(*it); } } - template <typename Strategy> + template <typename MultiGeometry, typename Strategy> static inline void apply(MultiGeometry& multi, Strategy const& strategy) { - typedef typename boost::range_iterator<MultiGeometry>::type iterator_type; - for (iterator_type it = boost::begin(multi); - it != boost::end(multi); - ++it) + auto const end = boost::end(multi); + for (auto it = boost::begin(multi); it != end; ++it) { Policy::apply(*it, strategy); } diff --git a/boost/geometry/algorithms/detail/multi_modify_with_predicate.hpp b/boost/geometry/algorithms/detail/multi_modify_with_predicate.hpp index 4dcc919e98..8d0ec2cb51 100644 --- a/boost/geometry/algorithms/detail/multi_modify_with_predicate.hpp +++ b/boost/geometry/algorithms/detail/multi_modify_with_predicate.hpp @@ -36,10 +36,7 @@ struct multi_modify_with_predicate { static inline void apply(MultiGeometry& multi, Predicate const& predicate) { - typedef typename boost::range_iterator<MultiGeometry>::type iterator_type; - for (iterator_type it = boost::begin(multi); - it != boost::end(multi); - ++it) + for (auto it = boost::begin(multi); it != boost::end(multi); ++it) { Policy::apply(*it, predicate); } diff --git a/boost/geometry/algorithms/detail/multi_sum.hpp b/boost/geometry/algorithms/detail/multi_sum.hpp index d41a3689fd..1c5ad6bf51 100644 --- a/boost/geometry/algorithms/detail/multi_sum.hpp +++ b/boost/geometry/algorithms/detail/multi_sum.hpp @@ -31,15 +31,10 @@ namespace detail struct multi_sum { template <typename ReturnType, typename Policy, typename MultiGeometry, typename Strategy> - static inline ReturnType apply(MultiGeometry const& geometry, Strategy const& strategy) + static inline ReturnType apply(MultiGeometry const& multi, Strategy const& strategy) { ReturnType sum = ReturnType(); - for (typename boost::range_iterator - < - MultiGeometry const - >::type it = boost::begin(geometry); - it != boost::end(geometry); - ++it) + for (auto it = boost::begin(multi); it != boost::end(multi); ++it) { sum += Policy::apply(*it, strategy); } diff --git a/boost/geometry/algorithms/detail/num_distinct_consecutive_points.hpp b/boost/geometry/algorithms/detail/num_distinct_consecutive_points.hpp index 5acc531d32..4b94ed4c4f 100644 --- a/boost/geometry/algorithms/detail/num_distinct_consecutive_points.hpp +++ b/boost/geometry/algorithms/detail/num_distinct_consecutive_points.hpp @@ -1,7 +1,8 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014-2020, Oracle and/or its affiliates. +// Copyright (c) 2014-2023, 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 @@ -19,6 +20,8 @@ #include <boost/range/end.hpp> #include <boost/range/size.hpp> +#include <boost/geometry/algorithms/detail/equals/point_point.hpp> + namespace boost { namespace geometry { @@ -48,8 +51,6 @@ struct num_distinct_consecutive_points template <typename Strategy> static inline std::size_t apply(Range const& range, Strategy const& strategy) { - typedef typename boost::range_iterator<Range const>::type iterator; - std::size_t const size = boost::size(range); if ( size < 2u ) @@ -57,13 +58,13 @@ struct num_distinct_consecutive_points return (size < MaximumNumber) ? size : MaximumNumber; } - iterator current = boost::begin(range); - iterator const end = boost::end(range); + auto current = boost::begin(range); + auto const end = boost::end(range); std::size_t counter(0); do { ++counter; - iterator next = std::find_if(current, end, [&](auto const& pt) { + auto next = std::find_if(current, end, [&](auto const& pt) { return ! equals::equals_point_point(pt, *current, strategy); }); current = next; diff --git a/boost/geometry/algorithms/detail/overlaps/implementation.hpp b/boost/geometry/algorithms/detail/overlaps/implementation.hpp index e056cbbdaf..5ab1b6ba7b 100644 --- a/boost/geometry/algorithms/detail/overlaps/implementation.hpp +++ b/boost/geometry/algorithms/detail/overlaps/implementation.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 2014-2021. -// Modifications copyright (c) 2014-2021 Oracle and/or its affiliates. +// This file was modified by Oracle on 2014-2022. +// Modifications copyright (c) 2014-2022 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -24,9 +24,11 @@ #include <boost/geometry/core/access.hpp> +#include <boost/geometry/algorithms/detail/gc_topological_dimension.hpp> #include <boost/geometry/algorithms/detail/overlaps/interface.hpp> +#include <boost/geometry/algorithms/detail/relate/implementation.hpp> +#include <boost/geometry/algorithms/detail/relate/implementation_gc.hpp> #include <boost/geometry/algorithms/not_implemented.hpp> -#include <boost/geometry/algorithms/relate.hpp> #include <boost/geometry/geometries/concepts/check.hpp> @@ -34,6 +36,8 @@ #include <boost/geometry/strategies/relate/geographic.hpp> #include <boost/geometry/strategies/relate/spherical.hpp> +#include <boost/geometry/views/detail/geometry_collection_view.hpp> + namespace boost { namespace geometry { @@ -150,6 +154,74 @@ struct overlaps<Box1, Box2, box_tag, box_tag> : detail::overlaps::box_box {}; + +template <typename Geometry1, typename Geometry2> +struct overlaps<Geometry1, Geometry2, geometry_collection_tag, geometry_collection_tag> +{ + template <typename Strategy> + static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, + Strategy const& strategy) + { + int dimension1 = detail::gc_topological_dimension(geometry1); + int dimension2 = detail::gc_topological_dimension(geometry2); + + if (dimension1 >= 0 && dimension2 >= 0) + { + if (dimension1 == 1 && dimension2 == 1) + { + return detail::relate::relate_impl + < + detail::de9im::static_mask_overlaps_d1_1_d2_1_type, + Geometry1, + Geometry2 + >::apply(geometry1, geometry2, strategy); + } + else if (dimension1 == dimension2) + { + return detail::relate::relate_impl + < + detail::de9im::static_mask_overlaps_d1_eq_d2_type, + Geometry1, + Geometry2 + >::apply(geometry1, geometry2, strategy); + } + } + + return false; + } +}; + +template <typename Geometry1, typename Geometry2, typename Tag1> +struct overlaps<Geometry1, Geometry2, Tag1, geometry_collection_tag> +{ + template <typename Strategy> + static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, + Strategy const& strategy) + { + using gc1_view_t = detail::geometry_collection_view<Geometry1>; + return overlaps + < + gc1_view_t, Geometry2 + >::apply(gc1_view_t(geometry1), geometry2, strategy); + } +}; + +template <typename Geometry1, typename Geometry2, typename Tag2> +struct overlaps<Geometry1, Geometry2, geometry_collection_tag, Tag2> +{ + template <typename Strategy> + static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, + Strategy const& strategy) + { + using gc2_view_t = detail::geometry_collection_view<Geometry2>; + return overlaps + < + Geometry1, gc2_view_t + >::apply(geometry1, gc2_view_t(geometry2), strategy); + } +}; + + } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH diff --git a/boost/geometry/algorithms/detail/overlaps/interface.hpp b/boost/geometry/algorithms/detail/overlaps/interface.hpp index fbe0ffdae8..bc2cfb517b 100644 --- a/boost/geometry/algorithms/detail/overlaps/interface.hpp +++ b/boost/geometry/algorithms/detail/overlaps/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 2014-2021. -// Modifications copyright (c) 2014-2021 Oracle and/or its affiliates. +// This file was modified by Oracle on 2014-2022. +// Modifications copyright (c) 2014-2022 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -24,6 +24,7 @@ #include <boost/geometry/algorithms/not_implemented.hpp> +#include <boost/geometry/geometries/adapted/boost_variant.hpp> #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/algorithms/detail/relate/relate_impl.hpp> @@ -124,6 +125,96 @@ struct overlaps<default_strategy, false> } // namespace resolve_strategy +namespace resolve_dynamic +{ + +template +< + typename Geometry1, typename Geometry2, + typename Tag1 = typename geometry::tag<Geometry1>::type, + typename Tag2 = typename geometry::tag<Geometry2>::type +> +struct overlaps +{ + template <typename Strategy> + static inline bool apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Strategy const& strategy) + { + return resolve_strategy::overlaps + < + Strategy + >::apply(geometry1, geometry2, strategy); + } +}; + + +template <typename DynamicGeometry1, typename Geometry2, typename Tag2> +struct overlaps<DynamicGeometry1, Geometry2, dynamic_geometry_tag, Tag2> +{ + template <typename Strategy> + static inline bool apply(DynamicGeometry1 const& geometry1, + Geometry2 const& geometry2, + Strategy const& strategy) + { + bool result = false; + traits::visit<DynamicGeometry1>::apply([&](auto const& g1) + { + result = resolve_strategy::overlaps + < + Strategy + >::apply(g1, geometry2, strategy); + }, geometry1); + return result; + } +}; + + +template <typename Geometry1, typename DynamicGeometry2, typename Tag1> +struct overlaps<Geometry1, DynamicGeometry2, Tag1, dynamic_geometry_tag> +{ + template <typename Strategy> + static inline bool apply(Geometry1 const& geometry1, + DynamicGeometry2 const& geometry2, + Strategy const& strategy) + { + bool result = false; + traits::visit<DynamicGeometry2>::apply([&](auto const& g2) + { + result = resolve_strategy::overlaps + < + Strategy + >::apply(geometry1, g2, strategy); + }, geometry2); + return result; + } +}; + + +template <typename DynamicGeometry1, typename DynamicGeometry2> +struct overlaps<DynamicGeometry1, DynamicGeometry2, dynamic_geometry_tag, dynamic_geometry_tag> +{ + template <typename Strategy> + static inline bool apply(DynamicGeometry1 const& geometry1, + DynamicGeometry2 const& geometry2, + Strategy const& strategy) + { + bool result = false; + traits::visit<DynamicGeometry1, DynamicGeometry2>::apply([&](auto const& g1, auto const& g2) + { + result = resolve_strategy::overlaps + < + Strategy + >::apply(g1, g2, strategy); + }, geometry1, geometry2); + return result; + } +}; + + +} // namespace resolve_dynamic + + /*! \brief \brief_check2{overlap} \ingroup overlaps @@ -146,9 +237,9 @@ inline bool overlaps(Geometry1 const& geometry1, concepts::check<Geometry1 const>(); concepts::check<Geometry2 const>(); - return resolve_strategy::overlaps + return resolve_dynamic::overlaps < - Strategy + Geometry1, Geometry2 >::apply(geometry1, geometry2, strategy); } @@ -174,9 +265,9 @@ inline bool overlaps(Geometry1 const& geometry1, Geometry2 const& geometry2) concepts::check<Geometry1 const>(); concepts::check<Geometry2 const>(); - return resolve_strategy::overlaps + return resolve_dynamic::overlaps < - default_strategy + Geometry1, Geometry2 >::apply(geometry1, geometry2, default_strategy()); } diff --git a/boost/geometry/algorithms/detail/overlay/add_rings.hpp b/boost/geometry/algorithms/detail/overlay/add_rings.hpp index 45f2e7f12f..026906b496 100644 --- a/boost/geometry/algorithms/detail/overlay/add_rings.hpp +++ b/boost/geometry/algorithms/detail/overlay/add_rings.hpp @@ -96,8 +96,6 @@ inline OutputIterator add_rings(SelectionMap const& map, Strategy const& strategy, add_rings_error_handling error_handling = add_rings_ignore_unordered) { - typedef typename SelectionMap::const_iterator iterator; - std::size_t const min_num_points = core_detail::closure::minimum_ring_size < geometry::closure @@ -110,29 +108,23 @@ inline OutputIterator add_rings(SelectionMap const& map, >::value; - for (iterator it = boost::begin(map); - it != boost::end(map); - ++it) + for (auto const& pair : map) { - if (! it->second.discarded - && it->second.parent.source_index == -1) + if (! pair.second.discarded + && pair.second.parent.source_index == -1) { GeometryOut result; convert_and_add(result, geometry1, geometry2, collection, - it->first, it->second.reversed, false); + pair.first, pair.second.reversed, false); // Add children - for (typename std::vector<ring_identifier>::const_iterator child_it - = it->second.children.begin(); - child_it != it->second.children.end(); - ++child_it) + for (auto const& child : pair.second.children) { - iterator mit = map.find(*child_it); - if (mit != map.end() - && ! mit->second.discarded) + auto mit = map.find(child); + if (mit != map.end() && ! mit->second.discarded) { convert_and_add(result, geometry1, geometry2, collection, - *child_it, mit->second.reversed, true); + child, mit->second.reversed, true); } } 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 f304600c00..a21ee9832b 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 @@ -23,6 +23,7 @@ #include <boost/static_assert.hpp> #include <boost/geometry/algorithms/append.hpp> +#include <boost/geometry/algorithms/detail/convert_point_to_point.hpp> #include <boost/geometry/algorithms/detail/point_is_spike_or_equal.hpp> #include <boost/geometry/algorithms/detail/equals/point_point.hpp> @@ -99,7 +100,16 @@ inline void append_no_dups_or_spikes(Range& range, Point const& point, return; } - traits::push_back<Range>::apply(range, point); + auto append = [](auto& r, const auto& p) + { + using point_t = typename boost::range_value<Range>::type; + point_t rp; + geometry::detail::conversion::convert_point_to_point(p, rp); + traits::push_back<Range>::apply(r, std::move(rp)); + }; + + append(range, point); + // If a point is equal, or forming a spike, remove the pen-ultimate point // because this one caused the spike. @@ -115,7 +125,7 @@ inline void append_no_dups_or_spikes(Range& range, Point const& point, { // Use the Concept/traits, so resize and append again traits::resize<Range>::apply(range, boost::size(range) - 2); - traits::push_back<Range>::apply(range, point); + append(range, point); } } @@ -174,7 +184,6 @@ inline void clean_closing_dups_and_spikes(Range& range, return; } - typedef typename boost::range_iterator<Range>::type iterator_type; static bool const closed = geometry::closure<Range>::value == geometry::closed; // TODO: the following algorithm could be rewritten to first look for spikes @@ -184,9 +193,9 @@ inline void clean_closing_dups_and_spikes(Range& range, do { found = false; - iterator_type first = boost::begin(range); - iterator_type second = first + 1; - iterator_type ultimate = boost::end(range) - 1; + auto first = boost::begin(range); + auto second = first + 1; + auto ultimate = boost::end(range) - 1; if (BOOST_GEOMETRY_CONDITION(closed)) { ultimate--; diff --git a/boost/geometry/algorithms/detail/overlay/approximately_equals.hpp b/boost/geometry/algorithms/detail/overlay/approximately_equals.hpp index d28a04ee8f..1f41085dc1 100644 --- a/boost/geometry/algorithms/detail/overlay/approximately_equals.hpp +++ b/boost/geometry/algorithms/detail/overlay/approximately_equals.hpp @@ -23,7 +23,7 @@ namespace detail { namespace overlay template <typename Point1, typename Point2, typename E> inline bool approximately_equals(Point1 const& a, Point2 const& b, - E const& multiplier) + E const& epsilon_multiplier) { using coor_t = typename select_coordinate_type<Point1, Point2>::type; using calc_t = typename geometry::select_most_precise<coor_t, E>::type; @@ -34,7 +34,7 @@ inline bool approximately_equals(Point1 const& a, Point2 const& b, calc_t const& b1 = geometry::get<1>(b); math::detail::equals_factor_policy<calc_t> policy(a0, b0, a1, b1); - policy.factor *= multiplier; + policy.multiply_epsilon(epsilon_multiplier); return math::detail::equals_by_policy(a0, b0, policy) && math::detail::equals_by_policy(a1, b1, policy); diff --git a/boost/geometry/algorithms/detail/overlay/assign_parents.hpp b/boost/geometry/algorithms/detail/overlay/assign_parents.hpp index a4cfac4dc1..fb3ee1bef2 100644 --- a/boost/geometry/algorithms/detail/overlay/assign_parents.hpp +++ b/boost/geometry/algorithms/detail/overlay/assign_parents.hpp @@ -3,8 +3,9 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland. -// This file was modified by Oracle on 2017-2020. -// Modifications copyright (c) 2017-2020 Oracle and/or its affiliates. +// This file was modified by Oracle on 2017-2023. +// Modifications copyright (c) 2017-2023 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, @@ -18,15 +19,19 @@ #include <boost/range/end.hpp> #include <boost/geometry/core/coordinate_type.hpp> + +#include <boost/geometry/algorithms/area_result.hpp> #include <boost/geometry/algorithms/envelope.hpp> #include <boost/geometry/algorithms/expand.hpp> +#include <boost/geometry/algorithms/detail/covered_by/implementation.hpp> #include <boost/geometry/algorithms/detail/partition.hpp> #include <boost/geometry/algorithms/detail/overlay/get_ring.hpp> #include <boost/geometry/algorithms/detail/overlay/range_in_geometry.hpp> -#include <boost/geometry/algorithms/covered_by.hpp> #include <boost/geometry/geometries/box.hpp> +#include <boost/geometry/util/for_each_with_index.hpp> + namespace boost { namespace geometry { @@ -260,38 +265,31 @@ inline void assign_parents(Geometry1 const& geometry1, point_type, Strategy // TODO: point_type is technically incorrect >::type area_result_type; - typedef typename RingMap::iterator map_iterator_type; - { - typedef ring_info_helper<point_type, area_result_type> helper; - typedef std::vector<helper> vector_type; - typedef typename boost::range_iterator<vector_type const>::type vector_iterator_type; - std::size_t count_total = ring_map.size(); std::size_t count_positive = 0; std::size_t index_positive = 0; // only used if count_positive>0 - std::size_t index = 0; - // Copy to vector (with new approach this might be obsolete as well, using the map directly) - vector_type vector(count_total); + // Copy to vector (this might be obsolete, using the map directly) + using helper = ring_info_helper<point_type, area_result_type>; + std::vector<helper> vector(count_total); - for (map_iterator_type it = boost::begin(ring_map); - it != boost::end(ring_map); ++it, ++index) + for_each_with_index(ring_map, [&](std::size_t index, auto const& pair) { - vector[index] = helper(it->first, it->second.get_area()); + vector[index] = helper(pair.first, pair.second.get_area()); helper& item = vector[index]; - switch(it->first.source_index) + switch(pair.first.source_index) { case 0 : - geometry::envelope(get_ring<tag1>::apply(it->first, geometry1), + geometry::envelope(get_ring<tag1>::apply(pair.first, geometry1), item.envelope, strategy); break; case 1 : - geometry::envelope(get_ring<tag2>::apply(it->first, geometry2), + geometry::envelope(get_ring<tag2>::apply(pair.first, geometry2), item.envelope, strategy); break; case 2 : - geometry::envelope(get_ring<void>::apply(it->first, collection), + geometry::envelope(get_ring<void>::apply(pair.first, collection), item.envelope, strategy); break; } @@ -304,7 +302,7 @@ inline void assign_parents(Geometry1 const& geometry1, count_positive++; index_positive = index; } - } + }); if (! check_for_orientation) { @@ -325,17 +323,15 @@ inline void assign_parents(Geometry1 const& geometry1, // located outside the outer ring, this cannot be done ring_identifier id_of_positive = vector[index_positive].id; ring_info_type& outer = ring_map[id_of_positive]; - index = 0; - for (vector_iterator_type it = boost::begin(vector); - it != boost::end(vector); ++it, ++index) + for_each_with_index(vector, [&](std::size_t index, auto const& item) { if (index != index_positive) { - ring_info_type& inner = ring_map[it->id]; + ring_info_type& inner = ring_map[item.id]; inner.parent = id_of_positive; - outer.children.push_back(it->id); + outer.children.push_back(item.id); } - } + }); return; } } @@ -357,10 +353,9 @@ inline void assign_parents(Geometry1 const& geometry1, if (check_for_orientation) { - for (map_iterator_type it = boost::begin(ring_map); - it != boost::end(ring_map); ++it) + for (auto& pair : ring_map) { - ring_info_type& info = it->second; + ring_info_type& info = pair.second; if (geometry::math::equals(info.get_area(), 0)) { info.discarded = true; @@ -397,12 +392,11 @@ inline void assign_parents(Geometry1 const& geometry1, } // Assign childlist - for (map_iterator_type it = boost::begin(ring_map); - it != boost::end(ring_map); ++it) + for (auto& pair : ring_map) { - if (it->second.parent.source_index >= 0) + if (pair.second.parent.source_index >= 0) { - ring_map[it->second.parent].children.push_back(it->first); + ring_map[pair.second.parent].children.push_back(pair.first); } } } diff --git a/boost/geometry/algorithms/detail/overlay/backtrack_check_si.hpp b/boost/geometry/algorithms/detail/overlay/backtrack_check_si.hpp index 14be63a554..49d190bd0c 100644 --- a/boost/geometry/algorithms/detail/overlay/backtrack_check_si.hpp +++ b/boost/geometry/algorithms/detail/overlay/backtrack_check_si.hpp @@ -38,21 +38,11 @@ namespace detail { namespace overlay template <typename Turns> inline void clear_visit_info(Turns& turns) { - typedef typename boost::range_value<Turns>::type tp_type; - - for (typename boost::range_iterator<Turns>::type - it = boost::begin(turns); - it != boost::end(turns); - ++it) + for (auto& turn : turns) { - for (typename boost::range_iterator - < - typename tp_type::container_type - >::type op_it = boost::begin(it->operations); - op_it != boost::end(it->operations); - ++op_it) + for (auto& op : turn.operations) { - op_it->visited.clear(); + op.visited.clear(); } } } diff --git a/boost/geometry/algorithms/detail/overlay/check_enrich.hpp b/boost/geometry/algorithms/detail/overlay/check_enrich.hpp index 843e120a18..ad3bd6bda9 100644 --- a/boost/geometry/algorithms/detail/overlay/check_enrich.hpp +++ b/boost/geometry/algorithms/detail/overlay/check_enrich.hpp @@ -127,37 +127,30 @@ inline bool check_graph(TurnPoints& turn_points, operation_type for_operation) typedef typename boost::range_value<TurnPoints>::type turn_point_type; bool error = false; - int index = 0; std::vector<meta_turn<turn_point_type> > meta_turns; - for (typename boost::range_iterator<TurnPoints const>::type - it = boost::begin(turn_points); - it != boost::end(turn_points); - ++it, ++index) + for_each_with_index(turn_points, [&](std::size_t index, auto const& point) { - meta_turns.push_back(meta_turn<turn_point_type>(index, *it)); - } + meta_turns.push_back(meta_turn<turn_point_type>(index, point)); + }); int cycle = 0; - for (typename boost::range_iterator<std::vector<meta_turn<turn_point_type> > > ::type - it = boost::begin(meta_turns); - it != boost::end(meta_turns); - ++it) + for (auto& meta_turn : meta_turns) { - if (! (it->turn->blocked() || it->turn->discarded)) + if (! (meta_turn.turn->blocked() || meta_turn.turn->discarded)) { for (int i = 0 ; i < 2; i++) { - if (! it->handled[i] - && it->turn->operations[i].operation == for_operation) + if (! meta_turn.handled[i] + && meta_turn.turn->operations[i].operation == for_operation) { #ifdef BOOST_GEOMETRY_DEBUG_ENRICH std::cout << "CYCLE " << cycle << std::endl; #endif - it->handled[i] = true; - check_detailed(meta_turns, *it, i, cycle++, it->index, for_operation, error); + meta_turn.handled[i] = true; + check_detailed(meta_turns, meta_turn, i, cycle++, meta_turn.index, for_operation, error); #ifdef BOOST_GEOMETRY_DEBUG_ENRICH - std::cout <<" END CYCLE " << it->index << std::endl; + std::cout <<" END CYCLE " << meta_turn.index << std::endl; #endif } } diff --git a/boost/geometry/algorithms/detail/overlay/clip_linestring.hpp b/boost/geometry/algorithms/detail/overlay/clip_linestring.hpp index f99140dcd0..2eb70aa7d8 100644 --- a/boost/geometry/algorithms/detail/overlay/clip_linestring.hpp +++ b/boost/geometry/algorithms/detail/overlay/clip_linestring.hpp @@ -197,9 +197,8 @@ OutputIterator clip_range_with_box(Box const& b, Range const& range, OutputLinestring line_out; - typedef typename boost::range_iterator<Range const>::type iterator_type; - iterator_type vertex = boost::begin(range); - for(iterator_type previous = vertex++; + auto vertex = boost::begin(range); + for (auto previous = vertex++; vertex != boost::end(range); ++previous, ++vertex) { diff --git a/boost/geometry/algorithms/detail/overlay/cluster_exits.hpp b/boost/geometry/algorithms/detail/overlay/cluster_exits.hpp index c4d01b1c14..8c4f4c7f31 100644 --- a/boost/geometry/algorithms/detail/overlay/cluster_exits.hpp +++ b/boost/geometry/algorithms/detail/overlay/cluster_exits.hpp @@ -2,8 +2,9 @@ // Copyright (c) 2020 Barend Gehrels, Amsterdam, the Netherlands. -// This file was modified by Oracle on 2020. -// Modifications copyright (c) 2020 Oracle and/or its affiliates. +// This file was modified by Oracle on 2020-2023. +// Modifications copyright (c) 2020-2023 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, @@ -22,6 +23,7 @@ #include <boost/geometry/core/access.hpp> #include <boost/geometry/core/assert.hpp> #include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp> +#include <boost/geometry/algorithms/detail/overlay/sort_by_side.hpp> #include <boost/geometry/algorithms/detail/signed_size_type.hpp> #include <boost/geometry/util/condition.hpp> @@ -67,16 +69,11 @@ private : signed_size_type rank_index; }; - typedef typename std::vector<linked_turn_op_info>::const_iterator const_it_type; - typedef typename std::vector<linked_turn_op_info>::iterator it_type; - typedef typename std::set<signed_size_type>::const_iterator sit_type; - inline signed_size_type get_rank(Sbs const& sbs, linked_turn_op_info const& info) const { - for (std::size_t i = 0; i < sbs.m_ranked_points.size(); i++) + for (auto const& rp : sbs.m_ranked_points) { - typename Sbs::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) @@ -95,9 +92,8 @@ private : bool collect(Turns const& turns) { - for (sit_type it = m_ids.begin(); it != m_ids.end(); ++it) + for (auto cluster_turn_index : m_ids) { - signed_size_type cluster_turn_index = *it; turn_type const& cluster_turn = turns[cluster_turn_index]; if (cluster_turn.discarded) { @@ -148,23 +144,19 @@ private : return true; } - for (it_type it = possibilities.begin(); it != possibilities.end(); ++it) + for (auto& info : possibilities) { - linked_turn_op_info& info = *it; info.rank_index = get_rank(sbs, info); } - for (it_type it = blocked.begin(); it != blocked.end(); ++it) + for (auto& info : blocked) { - linked_turn_op_info& info = *it; info.rank_index = get_rank(sbs, info); } - for (const_it_type it = possibilities.begin(); it != possibilities.end(); ++it) + for (auto const& lti : possibilities) { - linked_turn_op_info const& lti = *it; - for (const_it_type bit = blocked.begin(); bit != blocked.end(); ++bit) + for (auto const& blti : blocked) { - linked_turn_op_info const& blti = *bit; if (blti.next_turn_index == lti.next_turn_index && blti.rank_index == lti.rank_index) { @@ -198,10 +190,8 @@ public : // 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) + for (auto const& lti : possibilities) { - linked_turn_op_info const& lti = *it; if (m_ids.count(lti.next_turn_index) == 0) { if (target.turn_index >= 0 diff --git a/boost/geometry/algorithms/detail/overlay/colocate_clusters.hpp b/boost/geometry/algorithms/detail/overlay/colocate_clusters.hpp new file mode 100644 index 0000000000..06d6e7bd61 --- /dev/null +++ b/boost/geometry/algorithms/detail/overlay/colocate_clusters.hpp @@ -0,0 +1,107 @@ +// Boost.Geometry + +// Copyright (c) 2023 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_OVERLAY_COLOCATE_CLUSTERS_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_COLOCATE_CLUSTERS_HPP + +#include <boost/geometry/core/access.hpp> +#include <boost/geometry/core/cs.hpp> +#include <boost/geometry/core/coordinate_type.hpp> +#include <boost/geometry/core/tags.hpp> + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace overlay +{ + +// Default implementation, using the first point for all turns in the cluster. +template +< + typename Point, + typename CoordinateType = typename geometry::coordinate_type<Point>::type, + typename CsTag = typename geometry::cs_tag<Point>::type, + bool IsIntegral = std::is_integral<CoordinateType>::value +> +struct cluster_colocator +{ + template <typename TurnIndices, typename Turns> + static inline void apply(TurnIndices const& indices, Turns& turns) + { + // This approach works for all but one testcase (rt_p13) + // The problem is fill_sbs, which uses sides and these sides might change slightly + // depending on the exact location of the cluster. + // Using the centroid is, on the average, a safer choice for sides. + // Alternatively fill_sbs could be revised, but that requires a lot of work + // and is outside current scope. + // Integer coordinates are always colocated already and do not need centroid calculation. + // Geographic/spherical coordinates might (in extremely rare cases) cross the date line + // and therefore the first point is taken for them as well. + auto it = indices.begin(); + auto const& first_point = turns[*it].point; + for (++it; it != indices.end(); ++it) + { + turns[*it].point = first_point; + } + } +}; + +// Specialization for non-integral cartesian coordinates, calculating +// the centroid of the points of the turns in the cluster. +template <typename Point, typename CoordinateType> +struct cluster_colocator<Point, CoordinateType, geometry::cartesian_tag, false> +{ + template <typename TurnIndices, typename Turns> + static inline void apply(TurnIndices const& indices, Turns& turns) + { + CoordinateType centroid_0 = 0; + CoordinateType centroid_1 = 0; + for (const auto& index : indices) + { + centroid_0 += geometry::get<0>(turns[index].point); + centroid_1 += geometry::get<1>(turns[index].point); + } + centroid_0 /= indices.size(); + centroid_1 /= indices.size(); + for (const auto& index : indices) + { + geometry::set<0>(turns[index].point, centroid_0); + geometry::set<1>(turns[index].point, centroid_1); + } + } +}; + +// Moves intersection points per cluster such that they are identical. +// Because clusters are intersection close together, and +// handled as one location. Then they should also have one location. +// It is necessary to avoid artefacts and invalidities. +template <typename Clusters, typename Turns> +inline void colocate_clusters(Clusters const& clusters, Turns& turns) +{ + for (auto const& pair : clusters) + { + auto const& indices = pair.second.turn_indices; + if (indices.size() < 2) + { + // Defensive check + continue; + } + using point_t = decltype(turns[*indices.begin()].point); + cluster_colocator<point_t>::apply(indices, turns); + } +} + + +}} // namespace detail::overlay +#endif //DOXYGEN_NO_DETAIL + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_COLOCATE_CLUSTERS_HPP diff --git a/boost/geometry/algorithms/detail/overlay/convert_ring.hpp b/boost/geometry/algorithms/detail/overlay/convert_ring.hpp index becaaafc37..c7c1cf7030 100644 --- a/boost/geometry/algorithms/detail/overlay/convert_ring.hpp +++ b/boost/geometry/algorithms/detail/overlay/convert_ring.hpp @@ -86,6 +86,7 @@ struct convert_ring<polygon_tag> if (geometry::num_points(source) >= min_num_points) { + // TODO: resize and .size() and .back() should not be called here interior_rings(destination).resize( interior_rings(destination).size() + 1); geometry::convert(source, interior_rings(destination).back()); diff --git a/boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp b/boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp index 30a0a25095..8280a25018 100644 --- a/boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp +++ b/boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp @@ -1,6 +1,7 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2023 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2020-2021. // Modifications copyright (c) 2020-2021, Oracle and/or its affiliates. @@ -14,7 +15,8 @@ #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_COPY_SEGMENT_POINT_HPP -#include <boost/array.hpp> +#include <array> + #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/range/size.hpp> @@ -113,7 +115,7 @@ struct copy_segment_point_box SegmentIdentifier const& seg_id, signed_size_type offset, PointOut& point) { - boost::array<typename point_type<Box>::type, 4> bp; + std::array<typename point_type<Box>::type, 4> bp; assign_box_corners_oriented<Reverse>(box, bp); signed_size_type const target = circular_offset(4, seg_id.segment_index, offset); diff --git a/boost/geometry/algorithms/detail/overlay/copy_segments.hpp b/boost/geometry/algorithms/detail/overlay/copy_segments.hpp index 8af9ea4c1f..545bdc0314 100644 --- a/boost/geometry/algorithms/detail/overlay/copy_segments.hpp +++ b/boost/geometry/algorithms/detail/overlay/copy_segments.hpp @@ -1,6 +1,7 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2023 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2014-2021. // Modifications copyright (c) 2014-2021 Oracle and/or its affiliates. @@ -15,10 +16,10 @@ #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_COPY_SEGMENTS_HPP +#include <array> #include <type_traits> #include <vector> -#include <boost/array.hpp> #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/range/size.hpp> @@ -167,10 +168,7 @@ public: } signed_size_type const count = to_index - from_index + 1; - - typename boost::range_iterator<LineString const>::type - it = boost::begin(ls) + from_index; - + auto it = boost::begin(ls) + from_index; for (signed_size_type i = 0; i < count; ++i, ++it) { append_to_output(current_output, *it, strategy, robust_policy, @@ -238,7 +236,7 @@ struct copy_segments_box : 5 - index + to_index + 1; // Create array of points, the fifth one closes it - boost::array<typename point_type<Box>::type, 5> bp; + std::array<typename point_type<Box>::type, 5> bp; assign_box_corners_oriented<Reverse>(box, bp); bp[4] = bp[0]; diff --git a/boost/geometry/algorithms/detail/overlay/discard_duplicate_turns.hpp b/boost/geometry/algorithms/detail/overlay/discard_duplicate_turns.hpp index f5a4a82656..258a815f09 100644 --- a/boost/geometry/algorithms/detail/overlay/discard_duplicate_turns.hpp +++ b/boost/geometry/algorithms/detail/overlay/discard_duplicate_turns.hpp @@ -2,6 +2,10 @@ // Copyright (c) 2021 Barend Gehrels, Amsterdam, the Netherlands. +// This file was modified by Oracle on 2023. +// Modifications copyright (c) 2023 Oracle and/or its affiliates. +// Contributed and/or modified by Vissarion Fysikopoulos, 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,6 +13,8 @@ #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_DISCARD_DUPLICATE_TURNS_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_DISCARD_DUPLICATE_TURNS_HPP +#include <map> + #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp> #include <boost/geometry/algorithms/detail/overlay/get_ring.hpp> diff --git a/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp b/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp index 58ab4fcdda..b94bba6c5a 100644 --- a/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp +++ b/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp @@ -3,9 +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-2020. +// This file was modified by Oracle on 2017-2021. // Modifications copyright (c) 2017-2020 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, @@ -42,6 +41,7 @@ #include <boost/geometry/algorithms/detail/overlay/less_by_segment_ratio.hpp> #include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp> #include <boost/geometry/policies/robustness/robust_type.hpp> +#include <boost/geometry/util/for_each_with_index.hpp> #ifdef BOOST_GEOMETRY_DEBUG_ENRICH # include <boost/geometry/algorithms/detail/overlay/check_enrich.hpp> @@ -83,24 +83,24 @@ template typename Turns, typename Geometry1, typename Geometry2, typename RobustPolicy, - typename SideStrategy + typename Strategy > inline void enrich_sort(Operations& operations, Turns const& turns, Geometry1 const& geometry1, Geometry2 const& geometry2, RobustPolicy const& robust_policy, - SideStrategy const& strategy) + Strategy const& strategy) { - std::sort(boost::begin(operations), - boost::end(operations), - less_by_segment_ratio + std::sort(std::begin(operations), + std::end(operations), + less_by_segment_ratio < Turns, typename boost::range_value<Operations>::type, Geometry1, Geometry2, RobustPolicy, - SideStrategy, + Strategy, Reverse1, Reverse2 >(turns, geometry1, geometry2, robust_policy, strategy)); } @@ -110,93 +110,83 @@ template <typename Operations, typename Turns> inline void enrich_assign(Operations& operations, Turns& turns, bool check_turns) { - typedef typename boost::range_value<Turns>::type turn_type; - typedef typename turn_type::turn_operation_type op_type; - typedef typename boost::range_iterator<Operations>::type iterator_type; + if (operations.empty()) + { + return; + } + // Assign travel-to-vertex/ip index for each turning point. + // Iterator "next" is circular - if (operations.size() > 0) - { - // Assign travel-to-vertex/ip index for each turning point. - // Iterator "next" is circular + geometry::ever_circling_range_iterator<Operations const> next(operations); + ++next; - geometry::ever_circling_range_iterator<Operations const> next(operations); - ++next; + for (auto const& indexed : operations) + { + auto& turn = turns[indexed.turn_index]; + auto& op = turn.operations[indexed.operation_index]; - for (iterator_type it = boost::begin(operations); - it != boost::end(operations); ++it) + if (check_turns && indexed.turn_index == next->turn_index) { - turn_type& turn = turns[it->turn_index]; - op_type& op = turn.operations[it->operation_index]; - - if (check_turns && it->turn_index == next->turn_index) - { - // Normal behaviour: next points at next turn, increase next. - // For dissolve this should not be done, turn_index is often - // the same for two consecutive operations - ++next; - } + // Normal behaviour: next points at next turn, increase next. + // For dissolve this should not be done, turn_index is often + // the same for two consecutive operations + ++next; + } - // Cluster behaviour: next should point after cluster, unless - // their seg_ids are not the same - // (For dissolve, this is still to be examined - TODO) - while (turn.is_clustered() - && it->turn_index != next->turn_index - && turn.cluster_id == turns[next->turn_index].cluster_id - && op.seg_id == turns[next->turn_index].operations[next->operation_index].seg_id) - { - ++next; - } + // Cluster behaviour: next should point after cluster, unless + // their seg_ids are not the same + // (For dissolve, this is still to be examined - TODO) + while (turn.is_clustered() + && indexed.turn_index != next->turn_index + && turn.cluster_id == turns[next->turn_index].cluster_id + && op.seg_id == turns[next->turn_index].operations[next->operation_index].seg_id) + { + ++next; + } - turn_type const& next_turn = turns[next->turn_index]; - op_type const& next_op = next_turn.operations[next->operation_index]; + auto const& next_turn = turns[next->turn_index]; + auto const& next_op = next_turn.operations[next->operation_index]; - op.enriched.travels_to_ip_index - = static_cast<signed_size_type>(next->turn_index); - op.enriched.travels_to_vertex_index - = next->subject->seg_id.segment_index; + op.enriched.travels_to_ip_index + = static_cast<signed_size_type>(next->turn_index); + op.enriched.travels_to_vertex_index + = next->subject->seg_id.segment_index; - if (op.seg_id.segment_index == next_op.seg_id.segment_index - && op.fraction < next_op.fraction) - { - // Next turn is located further on same segment - // assign next_ip_index - // (this is one not circular therefore fraction is considered) - op.enriched.next_ip_index = static_cast<signed_size_type>(next->turn_index); - } + if (op.seg_id.segment_index == next_op.seg_id.segment_index + && op.fraction < next_op.fraction) + { + // Next turn is located further on same segment + // assign next_ip_index + // (this is one not circular therefore fraction is considered) + op.enriched.next_ip_index = static_cast<signed_size_type>(next->turn_index); + } - if (! check_turns) - { - ++next; - } + if (! check_turns) + { + ++next; } } // DEBUG #ifdef BOOST_GEOMETRY_DEBUG_ENRICH + for (auto const& indexed_op : operations) { - for (iterator_type it = boost::begin(operations); - it != boost::end(operations); - ++it) - { - op_type const& op = turns[it->turn_index] - .operations[it->operation_index]; - - std::cout << it->turn_index - << " cl=" << turns[it->turn_index].cluster_id - << " meth=" << method_char(turns[it->turn_index].method) - << " seg=" << op.seg_id - << " dst=" << op.fraction // needs define - << " op=" << operation_char(turns[it->turn_index].operations[0].operation) - << operation_char(turns[it->turn_index].operations[1].operation) - << " (" << operation_char(op.operation) << ")" - << " nxt=" << op.enriched.next_ip_index - << " / " << op.enriched.travels_to_ip_index - << " [vx " << op.enriched.travels_to_vertex_index << "]" - << (turns[it->turn_index].discarded ? " discarded" : "") - << std::endl; - ; - } + auto const& op = turns[indexed_op.turn_index].operations[indexed_op.operation_index]; + + std::cout << indexed_op.turn_index + << " cl=" << turns[indexed_op.turn_index].cluster_id + << " meth=" << method_char(turns[indexed_op.turn_index].method) + << " seg=" << op.seg_id + << " dst=" << op.fraction // needs define + << " op=" << operation_char(turns[indexed_op.turn_index].operations[0].operation) + << operation_char(turns[indexed_op.turn_index].operations[1].operation) + << " (" << operation_char(op.operation) << ")" + << " nxt=" << op.enriched.next_ip_index + << " / " << op.enriched.travels_to_ip_index + << " [vx " << op.enriched.travels_to_vertex_index << "]" + << (turns[indexed_op.turn_index].discarded ? " discarded" : "") + << std::endl; } #endif // END DEBUG @@ -206,47 +196,37 @@ inline void enrich_assign(Operations& operations, Turns& turns, template <typename Operations, typename Turns> inline void enrich_adapt(Operations& operations, Turns& turns) { - typedef typename boost::range_value<Turns>::type turn_type; - typedef typename turn_type::turn_operation_type op_type; - typedef typename boost::range_value<Operations>::type indexed_turn_type; - + // Operations is a vector of indexed_turn_operation<> + // If it is empty, or contains one or two items, it makes no sense if (operations.size() < 3) { - // If it is empty, or contains one or two turns, it makes no sense return; } - // Operations is a vector of indexed_turn_operation<> - - // Last index: - std::size_t const x = operations.size() - 1; bool next_phase = false; + std::size_t previous_index = operations.size() - 1; - for (std::size_t i = 0; i < operations.size(); i++) + for_each_with_index(operations, [&](std::size_t index, auto const& indexed) { - indexed_turn_type const& indexed = operations[i]; - - turn_type& turn = turns[indexed.turn_index]; - op_type& op = turn.operations[indexed.operation_index]; - - // Previous/next index - std::size_t const p = i > 0 ? i - 1 : x; - std::size_t const n = i < x ? i + 1 : 0; + auto& turn = turns[indexed.turn_index]; + auto& op = turn.operations[indexed.operation_index]; - turn_type const& next_turn = turns[operations[n].turn_index]; - op_type const& next_op = next_turn.operations[operations[n].operation_index]; + std::size_t const next_index = index + 1 < operations.size() ? index + 1 : 0; + auto const& next_turn = turns[operations[next_index].turn_index]; + auto const& next_op = next_turn.operations[operations[next_index].operation_index]; if (op.seg_id.segment_index == next_op.seg_id.segment_index) { - turn_type const& prev_turn = turns[operations[p].turn_index]; - op_type const& prev_op = prev_turn.operations[operations[p].operation_index]; + auto const& prev_turn = turns[operations[previous_index].turn_index]; + auto const& prev_op = prev_turn.operations[operations[previous_index].operation_index]; if (op.seg_id.segment_index == prev_op.seg_id.segment_index) { op.enriched.startable = false; next_phase = true; } } - } + previous_index = index; + }); if (! next_phase) { @@ -255,12 +235,8 @@ inline void enrich_adapt(Operations& operations, Turns& turns) // Discard turns which are both non-startable next_phase = false; - for (typename boost::range_iterator<Turns>::type - it = boost::begin(turns); - it != boost::end(turns); - ++it) + for (auto& turn : turns) { - turn_type& turn = *it; if (! turn.operations[0].enriched.startable && ! turn.operations[1].enriched.startable) { @@ -276,8 +252,8 @@ inline void enrich_adapt(Operations& operations, Turns& turns) // Remove discarded turns from operations to avoid having them as next turn discarded_indexed_turn<Turns> const predicate(turns); - operations.erase(std::remove_if(boost::begin(operations), - boost::end(operations), predicate), boost::end(operations)); + operations.erase(std::remove_if(std::begin(operations), + std::end(operations), predicate), std::end(operations)); } struct enriched_map_default_include_policy @@ -290,52 +266,35 @@ struct enriched_map_default_include_policy } }; +// Add all (non discarded) operations on this ring +// Blocked operations or uu on clusters (for intersection) +// should be included, to block potential paths in clusters template <typename Turns, typename MappedVector, typename IncludePolicy> inline void create_map(Turns const& turns, MappedVector& mapped_vector, IncludePolicy const& include_policy) { - typedef typename boost::range_value<Turns>::type turn_type; - typedef typename turn_type::container_type container_type; - typedef typename MappedVector::mapped_type mapped_type; - typedef typename boost::range_value<mapped_type>::type indexed_type; - - std::size_t index = 0; - for (typename boost::range_iterator<Turns const>::type - it = boost::begin(turns); - it != boost::end(turns); - ++it, ++index) + for_each_with_index(turns, [&](std::size_t index, auto const& turn) { - // Add all (non discarded) operations on this ring - // Blocked operations or uu on clusters (for intersection) - // should be included, to block potential paths in clusters - turn_type const& turn = *it; - if (turn.discarded) - { - continue; - } - - std::size_t op_index = 0; - for (typename boost::range_iterator<container_type const>::type - op_it = boost::begin(turn.operations); - op_it != boost::end(turn.operations); - ++op_it, ++op_index) + if (! turn.discarded) { - if (include_policy.include(op_it->operation)) + for_each_with_index(turn.operations, [&](std::size_t op_index, auto const& op) { - ring_identifier const ring_id - ( - op_it->seg_id.source_index, - op_it->seg_id.multi_index, - op_it->seg_id.ring_index - ); - mapped_vector[ring_id].push_back - ( - indexed_type(index, op_index, *op_it, - it->operations[1 - op_index].seg_id) - ); - } + if (include_policy.include(op.operation)) + { + ring_identifier const ring_id + ( + op.seg_id.source_index, + op.seg_id.multi_index, + op.seg_id.ring_index + ); + mapped_vector[ring_id].emplace_back + ( + index, op_index, op, turn.operations[1 - op_index].seg_id + ); + } + }); } - } + }); } template <typename Point1, typename Point2> @@ -344,7 +303,7 @@ inline typename geometry::coordinate_type<Point1>::type { // TODO: use comparable distance for point-point instead - but that // causes currently cycling include problems - typedef typename geometry::coordinate_type<Point1>::type ctype; + using ctype = typename geometry::coordinate_type<Point1>::type; ctype const dx = get<0>(a) - get<0>(b); ctype const dy = get<1>(a) - get<1>(b); return dx * dx + dy * dy; @@ -353,30 +312,24 @@ inline typename geometry::coordinate_type<Point1>::type template <typename Turns> inline void calculate_remaining_distance(Turns& turns) { - typedef typename boost::range_value<Turns>::type turn_type; - typedef typename turn_type::turn_operation_type op_type; - - for (typename boost::range_iterator<Turns>::type - it = boost::begin(turns); - it != boost::end(turns); - ++it) + for (auto& turn : turns) { - turn_type& turn = *it; + auto& op0 = turn.operations[0]; + auto& op1 = turn.operations[1]; - op_type& op0 = turn.operations[0]; - op_type& op1 = turn.operations[1]; + static decltype(op0.remaining_distance) const zero_distance = 0; - if (op0.remaining_distance != 0 - || op1.remaining_distance != 0) + if (op0.remaining_distance != zero_distance + || op1.remaining_distance != zero_distance) { continue; } - signed_size_type const to_index0 = op0.enriched.get_next_turn_index(); - signed_size_type const to_index1 = op1.enriched.get_next_turn_index(); + auto const to_index0 = op0.enriched.get_next_turn_index(); + auto const to_index1 = op1.enriched.get_next_turn_index(); if (to_index0 >= 0 - && to_index1 >= 0 - && to_index0 != to_index1) + && to_index1 >= 0 + && to_index0 != to_index1) { op0.remaining_distance = distance_measure(turn.point, turns[to_index0].point); op1.remaining_distance = distance_measure(turn.point, turns[to_index1].point); @@ -422,29 +375,28 @@ inline void enrich_intersection_points(Turns& turns, RobustPolicy const& robust_policy, IntersectionStrategy const& strategy) { - static const detail::overlay::operation_type target_operation + constexpr detail::overlay::operation_type target_operation = detail::overlay::operation_from_overlay<OverlayType>::value; - static const detail::overlay::operation_type opposite_operation + constexpr detail::overlay::operation_type opposite_operation = target_operation == detail::overlay::operation_union ? detail::overlay::operation_intersection : detail::overlay::operation_union; - static const bool is_dissolve = OverlayType == overlay_dissolve; + constexpr bool is_dissolve = OverlayType == overlay_dissolve; - typedef typename boost::range_value<Turns>::type turn_type; - typedef typename turn_type::turn_operation_type op_type; - typedef detail::overlay::indexed_turn_operation + using turn_type = typename boost::range_value<Turns>::type; + using indexed_turn_operation = detail::overlay::indexed_turn_operation < - op_type - > indexed_turn_operation; + typename turn_type::turn_operation_type + > ; - typedef std::map + using mapped_vector_type = std::map < ring_identifier, std::vector<indexed_turn_operation> - > mapped_vector_type; + >; // From here on, turn indexes are used (in clusters, next_index, etc) - // and may not be DELETED - they may only be flagged as discarded + // and turns may not be DELETED - they may only be flagged as discarded discard_duplicate_start_turns(turns, geometry1, geometry2); bool has_cc = false; @@ -455,13 +407,8 @@ inline void enrich_intersection_points(Turns& turns, >(turns, clusters, robust_policy); // Discard turns not part of target overlay - for (typename boost::range_iterator<Turns>::type - it = boost::begin(turns); - it != boost::end(turns); - ++it) + for (auto& turn : turns) { - turn_type& turn = *it; - if (turn.both(detail::overlay::operation_none) || turn.both(opposite_operation) || turn.both(detail::overlay::operation_blocked) @@ -514,20 +461,15 @@ inline void enrich_intersection_points(Turns& turns, detail::overlay::create_map(turns, mapped_vector, detail::overlay::enriched_map_default_include_policy()); - // No const-iterator; contents of mapped copy is temporary, - // and changed by enrich - for (typename mapped_vector_type::iterator mit - = mapped_vector.begin(); - mit != mapped_vector.end(); - ++mit) + for (auto& pair : mapped_vector) { detail::overlay::enrich_sort<Reverse1, Reverse2>( - mit->second, turns, + pair.second, turns, geometry1, geometry2, - robust_policy, strategy.side()); // TODO: pass strategy + robust_policy, strategy); #ifdef BOOST_GEOMETRY_DEBUG_ENRICH - std::cout << "ENRICH-sort Ring " << mit->first << std::endl; - for (auto const& op : mit->second) + std::cout << "ENRICH-sort Ring " << pair.first << std::endl; + for (auto const& op : pair.second) { std::cout << op.turn_index << " " << op.operation_index << std::endl; } @@ -551,20 +493,17 @@ inline void enrich_intersection_points(Turns& turns, // After cleaning up clusters assign the next turns - for (typename mapped_vector_type::iterator mit - = mapped_vector.begin(); - mit != mapped_vector.end(); - ++mit) + for (auto& pair : mapped_vector) { #ifdef BOOST_GEOMETRY_DEBUG_ENRICH - std::cout << "ENRICH-assign Ring " << mit->first << std::endl; + std::cout << "ENRICH-assign Ring " << pair.first << std::endl; #endif if (is_dissolve) { - detail::overlay::enrich_adapt(mit->second, turns); + detail::overlay::enrich_adapt(pair.second, turns); } - detail::overlay::enrich_assign(mit->second, turns, ! is_dissolve); + detail::overlay::enrich_assign(pair.second, turns, ! is_dissolve); } if (has_cc) diff --git a/boost/geometry/algorithms/detail/overlay/follow.hpp b/boost/geometry/algorithms/detail/overlay/follow.hpp index afcd2bd82e..d945605413 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-2020. -// Modifications copyright (c) 2014-2020 Oracle and/or its affiliates. +// This file was modified by Oracle on 2014-2022. +// Modifications copyright (c) 2014-2022 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,8 +23,8 @@ #include <boost/range/size.hpp> #include <boost/range/value_type.hpp> -#include <boost/geometry/algorithms/covered_by.hpp> #include <boost/geometry/algorithms/clear.hpp> +#include <boost/geometry/algorithms/detail/covered_by/implementation.hpp> #include <boost/geometry/algorithms/detail/overlay/append_no_duplicates.hpp> #include <boost/geometry/algorithms/detail/overlay/copy_segments.hpp> #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp> @@ -422,13 +422,6 @@ public : OutputIterator out, Strategy const& strategy) { - typedef typename boost::range_iterator<Turns>::type turn_iterator; - typedef typename boost::range_value<Turns>::type turn_type; - typedef typename boost::range_iterator - < - typename turn_type::container_type - >::type turn_operation_iterator_type; - typedef following::action_selector<OverlayType, RemoveSpikes> action; // Sort intersection points on segments-along-linestring, and distance @@ -438,8 +431,7 @@ public : // for different ring id: c, i, u, x typedef relate::turns::less < - 0, relate::turns::less_op_linear_areal_single<0>, - typename Strategy::cs_tag + 0, relate::turns::less_op_linear_areal_single<0>, Strategy > turn_less; std::sort(boost::begin(turns), boost::end(turns), turn_less()); @@ -449,51 +441,51 @@ public : // Iterate through all intersection points (they are ordered along the line) bool entered = false; bool first = true; - for (turn_iterator it = boost::begin(turns); it != boost::end(turns); ++it) + for (auto const& turn : turns) { - turn_operation_iterator_type iit = boost::begin(it->operations); + auto const& op = turn.operations[0]; - if (following::was_entered(*it, *iit, first, linestring, polygon, strategy)) + if (following::was_entered(turn, op, first, linestring, polygon, strategy)) { - debug_traverse(*it, *iit, "-> Was entered"); + debug_traverse(turn, op, "-> Was entered"); entered = true; } - if (following::is_staying_inside(*it, *iit, entered, first, linestring, polygon, strategy)) + if (following::is_staying_inside(turn, op, entered, first, linestring, polygon, strategy)) { - debug_traverse(*it, *iit, "-> Staying inside"); + debug_traverse(turn, op, "-> Staying inside"); entered = true; } - else if (following::is_entering(*it, *iit)) + else if (following::is_entering(turn, op)) { - debug_traverse(*it, *iit, "-> Entering"); + debug_traverse(turn, op, "-> Entering"); entered = true; action::enter(current_piece, linestring, current_segment_id, - iit->seg_id.segment_index, it->point, *iit, + op.seg_id.segment_index, turn.point, op, strategy, robust_policy, linear::get(out)); } - else if (following::is_leaving(*it, *iit, entered, first, linestring, polygon, strategy)) + else if (following::is_leaving(turn, op, entered, first, linestring, polygon, strategy)) { - debug_traverse(*it, *iit, "-> Leaving"); + debug_traverse(turn, op, "-> Leaving"); entered = false; action::leave(current_piece, linestring, current_segment_id, - iit->seg_id.segment_index, it->point, *iit, + op.seg_id.segment_index, turn.point, op, strategy, robust_policy, linear::get(out)); } else if (BOOST_GEOMETRY_CONDITION(FollowIsolatedPoints) - && following::is_touching(*it, *iit, entered)) + && following::is_touching(turn, op, entered)) { - debug_traverse(*it, *iit, "-> Isolated point"); + debug_traverse(turn, op, "-> Isolated point"); action::template isolated_point < typename pointlike::type - >(it->point, pointlike::get(out)); + >(turn.point, pointlike::get(out)); } first = false; diff --git a/boost/geometry/algorithms/detail/overlay/follow_linear_linear.hpp b/boost/geometry/algorithms/detail/overlay/follow_linear_linear.hpp index a3ad620162..5d1577c481 100644 --- a/boost/geometry/algorithms/detail/overlay/follow_linear_linear.hpp +++ b/boost/geometry/algorithms/detail/overlay/follow_linear_linear.hpp @@ -74,7 +74,7 @@ static inline bool is_entering(Turn const& turn, template <typename Turn, typename Operation> static inline bool is_staying_inside(Turn const& turn, - Operation const& operation, + Operation const& operation, bool entered) { if ( !entered ) @@ -327,21 +327,17 @@ public: for (TurnIterator it = first; it != beyond; ++it) { oit = process_turn(it, boost::begin(it->operations), - entered, enter_count, + entered, enter_count, linestring, current_piece, current_segment_id, oit, strategy); } -#if ! defined(BOOST_GEOMETRY_OVERLAY_NO_THROW) if (enter_count != 0) { - BOOST_THROW_EXCEPTION(inconsistent_turns_exception()); + return oit; } -#else - BOOST_GEOMETRY_ASSERT(enter_count == 0); -#endif return process_end(entered, linestring, current_segment_id, current_piece, diff --git a/boost/geometry/algorithms/detail/overlay/get_clusters.hpp b/boost/geometry/algorithms/detail/overlay/get_clusters.hpp index 1e612d6577..2747fa68ba 100644 --- a/boost/geometry/algorithms/detail/overlay/get_clusters.hpp +++ b/boost/geometry/algorithms/detail/overlay/get_clusters.hpp @@ -35,19 +35,29 @@ namespace detail { namespace overlay template <typename Tag = no_rescale_policy_tag, bool Integral = false> struct sweep_equal_policy { +private: + template <typename T> + static inline T threshold() + { + // Points within some epsilons are considered as equal. + return T(100); + } +public: + // Returns true if point are considered equal (within an epsilon) template <typename P> static inline bool equals(P const& p1, P const& p2) { - // Points within a kilo epsilon are considered as equal - return approximately_equals(p1, p2, 1000.0); + using coor_t = typename coordinate_type<P>::type; + return approximately_equals(p1, p2, threshold<coor_t>()); } template <typename T> static inline bool exceeds(T value) { // This threshold is an arbitrary value - // as long as it is than the used kilo-epsilon - return value > 1.0e-3; + // as long as it is bigger than the used value above + T const limit = T(1) / threshold<T>(); + return value > limit; } }; diff --git a/boost/geometry/algorithms/detail/overlay/get_distance_measure.hpp b/boost/geometry/algorithms/detail/overlay/get_distance_measure.hpp index 82ab3d5d04..d462bb524d 100644 --- a/boost/geometry/algorithms/detail/overlay/get_distance_measure.hpp +++ b/boost/geometry/algorithms/detail/overlay/get_distance_measure.hpp @@ -1,6 +1,10 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2019 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2019-2021 Barend Gehrels, Amsterdam, the Netherlands. + +// This file was modified by Oracle on 2022. +// Modifications copyright (c) 2022 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 @@ -61,53 +65,48 @@ namespace detail_dispatch template <typename CalculationType, typename CsTag> struct get_distance_measure - : not_implemented<CsTag> + : not_implemented<CsTag> {}; template <typename CalculationType> -struct get_distance_measure<CalculationType, cartesian_tag> +struct get_distance_measure<CalculationType, spherical_tag> { - typedef detail::distance_measure<CalculationType> result_type; + // By default the distance measure is zero, no side difference + using result_type = detail::distance_measure<CalculationType>; template <typename SegmentPoint, typename Point> - static result_type apply(SegmentPoint const& p1, SegmentPoint const& p2, - Point const& p) + static result_type apply(SegmentPoint const& , SegmentPoint const& , + Point const& ) { - // Get the distance measure / side value - // It is not a real distance and purpose is - // to detect small differences in collinearity - - typedef model::infinite_line<CalculationType> line_type; - line_type const line = detail::make::make_infinite_line<CalculationType>(p1, p2); - result_type result; - result.measure = arithmetic::side_value(line, p); + const result_type result; return result; } }; template <typename CalculationType> -struct get_distance_measure<CalculationType, spherical_tag> +struct get_distance_measure<CalculationType, geographic_tag> + : get_distance_measure<CalculationType, spherical_tag> +{}; + +template <typename CalculationType> +struct get_distance_measure<CalculationType, cartesian_tag> { - typedef detail::distance_measure<CalculationType> result_type; + using result_type = detail::distance_measure<CalculationType>; template <typename SegmentPoint, typename Point> - static result_type apply(SegmentPoint const& , SegmentPoint const& , - Point const& ) + static result_type apply(SegmentPoint const& p1, SegmentPoint const& p2, + Point const& p) { - // TODO, optional + // Get the distance measure / side value + // It is not a real distance and purpose is + // to detect small differences in collinearity + auto const line = detail::make::make_infinite_line<CalculationType>(p1, p2); result_type result; + result.measure = arithmetic::side_value(line, p); return result; } }; -template <typename CalculationType> -struct get_distance_measure<CalculationType, geographic_tag> - : get_distance_measure<CalculationType, spherical_tag> {}; - -template <typename CalculationType> -struct get_distance_measure<CalculationType, spherical_equatorial_tag> - : get_distance_measure<CalculationType, spherical_tag> {}; - } // namespace detail_dispatch namespace detail @@ -117,18 +116,32 @@ namespace detail // 0 (absolutely 0, not even an epsilon) means collinear. Like side, // a negative means that p is to the right of p1-p2. And a positive value // means that p is to the left of p1-p2. - -template <typename SegmentPoint, typename Point> -static distance_measure<typename select_coordinate_type<SegmentPoint, Point>::type> -get_distance_measure(SegmentPoint const& p1, SegmentPoint const& p2, Point const& p) +template <typename SegmentPoint, typename Point, typename Strategies> +inline auto get_distance_measure(SegmentPoint const& p1, SegmentPoint const& p2, Point const& p, + Strategies const&) { - typedef typename geometry::cs_tag<Point>::type cs_tag; - return detail_dispatch::get_distance_measure - < - typename select_coordinate_type<SegmentPoint, Point>::type, - cs_tag - >::apply(p1, p2, p); + using calc_t = typename select_coordinate_type<SegmentPoint, Point>::type; + + // Verify equality, without using a tolerance + // (so don't use equals or equals_point_point) + // because it is about very tiny differences. + auto identical = [](const auto& point1, const auto& point2) + { + return geometry::get<0>(point1) == geometry::get<0>(point2) + && geometry::get<1>(point1) == geometry::get<1>(point2); + }; + if (identical(p1, p) || identical(p2, p)) + { + detail::distance_measure<calc_t> const result; + return result; + } + + return detail_dispatch::get_distance_measure + < + calc_t, + typename Strategies::cs_tag + >::apply(p1, p2, p); } } // namespace detail diff --git a/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp b/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp index fcd3635fd6..4e10c07bde 100644 --- a/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp +++ b/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp @@ -1,11 +1,10 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2007-2021 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland. -// This file was modified by Oracle on 2015-2020. -// Modifications copyright (c) 2015-2020 Oracle and/or its affiliates. - +// This file was modified by Oracle on 2015-2022. +// Modifications copyright (c) 2015-2022 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, @@ -26,14 +25,9 @@ #include <boost/geometry/algorithms/convert.hpp> #include <boost/geometry/algorithms/detail/overlay/get_distance_measure.hpp> #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp> - #include <boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp> -// Silence warning C4127: conditional expression is constant -#if defined(_MSC_VER) -#pragma warning(push) -#pragma warning(disable : 4127) -#endif +#include <boost/geometry/util/condition.hpp> namespace boost { namespace geometry @@ -66,6 +60,36 @@ public: namespace detail { namespace overlay { + +struct policy_verify_nothing +{ + static bool const use_side_verification = false; + static bool const use_start_turn = false; + static bool const use_handle_as_touch = false; + static bool const use_handle_as_equal = false; + static bool const use_handle_imperfect_touch = false; +}; + +struct policy_verify_all +{ + static bool const use_side_verification = true; + static bool const use_start_turn = true; + static bool const use_handle_as_touch = true; + static bool const use_handle_as_equal = true; + static bool const use_handle_imperfect_touch = true; +}; + + +#if defined(BOOST_GEOMETRY_USE_RESCALING) +using verify_policy_aa = policy_verify_nothing; +#else +using verify_policy_aa = policy_verify_all; +#endif + +using verify_policy_ll = policy_verify_nothing; +using verify_policy_la = policy_verify_nothing; + + struct base_turn_handler { // Returns true if both sides are opposite @@ -107,52 +131,6 @@ struct base_turn_handler both(ti, condition ? operation_union : operation_intersection); } - -#if ! defined(BOOST_GEOMETRY_USE_RESCALING) - template - < - typename UniqueSubRange1, - typename UniqueSubRange2 - > - static inline int side_with_distance_measure(UniqueSubRange1 const& range_p, - UniqueSubRange2 const& range_q, - int range_index, int point_index) - { - if (range_index >= 1 && range_p.is_last_segment()) - { - return 0; - } - if (point_index >= 2 && range_q.is_last_segment()) - { - return 0; - } - - auto const dm = get_distance_measure(range_p.at(range_index), range_p.at(range_index + 1), range_q.at(point_index)); - return dm.measure == 0 ? 0 : dm.measure > 0 ? 1 : -1; - } - - template - < - typename UniqueSubRange1, - typename UniqueSubRange2 - > - static inline int verified_side(int side, - UniqueSubRange1 const& range_p, - UniqueSubRange2 const& range_q, - int range_index, - int point_index) - { - return side == 0 ? side_with_distance_measure(range_p, range_q, range_index, point_index) : side; - } -#else - template <typename T1, typename T2> - static inline int verified_side(int side, T1 const& , T2 const& , int , int) - { - return side; - } -#endif - - template <typename TurnInfo, typename IntersectionInfo> static inline void assign_point(TurnInfo& ti, method_type method, @@ -208,14 +186,22 @@ struct base_turn_handler ? 1 : 0; } +}; + +template<typename VerifyPolicy> +struct turn_info_verification_functions +{ template <typename Point1, typename Point2> - static inline typename geometry::coordinate_type<Point1>::type - distance_measure(Point1 const& a, Point2 const& b) + static inline + typename select_coordinate_type<Point1, Point2>::type + distance_measure(Point1 const& a, Point2 const& b) { - // TODO: use comparable distance for point-point instead - but that - // causes currently cycling include problems - auto const dx = get<0>(a) - get<0>(b); - auto const dy = get<1>(a) - get<1>(b); + // TODO: revise this using comparable distance for various + // coordinate systems + using coor_t = typename select_coordinate_type<Point1, Point2>::type; + + coor_t const dx = get<0>(a) - get<0>(b); + coor_t const dy = get<1>(a) - get<1>(b); return dx * dx + dy * dy; } @@ -228,50 +214,127 @@ struct base_turn_handler typename UmbrellaStrategy, typename TurnInfo > - static inline void both_collinear( + static inline void set_both_verified( UniqueSubRange1 const& range_p, UniqueSubRange2 const& range_q, - UmbrellaStrategy const&, + UmbrellaStrategy const& umbrella_strategy, std::size_t index_p, std::size_t index_q, TurnInfo& ti) { - boost::ignore_unused(range_p, range_q); BOOST_GEOMETRY_ASSERT(IndexP + IndexQ == 1); BOOST_GEOMETRY_ASSERT(index_p > 0 && index_p <= 2); BOOST_GEOMETRY_ASSERT(index_q > 0 && index_q <= 2); -#if ! defined(BOOST_GEOMETRY_USE_RESCALING) - ti.operations[IndexP].remaining_distance = distance_measure(ti.point, range_p.at(index_p)); - ti.operations[IndexQ].remaining_distance = distance_measure(ti.point, range_q.at(index_q)); - - // pk/q2 is considered as collinear, but there might be - // a tiny measurable difference. If so, use that. - // Calculate pk // qj-qk - bool const p_closer = - ti.operations[IndexP].remaining_distance - < ti.operations[IndexQ].remaining_distance; - auto const dm + using distance_measure_result_type = typename geometry::coordinate_type<decltype(ti.point)>::type; + + bool const p_in_range = index_p < range_p.size(); + bool const q_in_range = index_q < range_q.size(); + ti.operations[IndexP].remaining_distance + = p_in_range + ? distance_measure(ti.point, range_p.at(index_p)) + : distance_measure_result_type{0}; + ti.operations[IndexQ].remaining_distance + = q_in_range + ? distance_measure(ti.point, range_q.at(index_q)) + : distance_measure_result_type{0}; + + if (p_in_range && q_in_range) + { + // pk/q2 is considered as collinear, but there might be + // a tiny measurable difference. If so, use that. + // Calculate pk // qj-qk + bool const p_closer + = ti.operations[IndexP].remaining_distance + < ti.operations[IndexQ].remaining_distance; + auto const dm = p_closer ? get_distance_measure(range_q.at(index_q - 1), - range_q.at(index_q), range_p.at(index_p)) + range_q.at(index_q), range_p.at(index_p), + umbrella_strategy) : get_distance_measure(range_p.at(index_p - 1), - range_p.at(index_p), range_q.at(index_q)); + range_p.at(index_p), range_q.at(index_q), + umbrella_strategy); + + if (! dm.is_zero()) + { + // Not truely collinear, distinguish for union/intersection + // If p goes left (positive), take that for a union + bool const p_left + = p_closer ? dm.is_positive() : dm.is_negative(); + + ti.operations[IndexP].operation = p_left + ? operation_union : operation_intersection; + ti.operations[IndexQ].operation = p_left + ? operation_intersection : operation_union; + return; + } + } + + base_turn_handler::both(ti, operation_continue); + } - if (! dm.is_zero()) + template + < + std::size_t IndexP, + std::size_t IndexQ, + typename UniqueSubRange1, + typename UniqueSubRange2, + typename UmbrellaStrategy, + typename TurnInfo + > + static inline void both_collinear( + UniqueSubRange1 const& range_p, + UniqueSubRange2 const& range_q, + UmbrellaStrategy const& umbrella_strategy, + std::size_t index_p, std::size_t index_q, + TurnInfo& ti) + { + if (BOOST_GEOMETRY_CONDITION(VerifyPolicy::use_side_verification)) { - // Not truely collinear, distinguish for union/intersection - // If p goes left (positive), take that for a union - bool const p_left = p_closer ? dm.is_positive() : dm.is_negative(); - - ti.operations[IndexP].operation = p_left - ? operation_union : operation_intersection; - ti.operations[IndexQ].operation = p_left - ? operation_intersection : operation_union; - return; + set_both_verified<IndexP, IndexQ>(range_p, range_q, umbrella_strategy, + index_p, index_q, ti); } -#endif + else + { + base_turn_handler::both(ti, operation_continue); + } + } - both(ti, operation_continue); + template + < + typename UniqueSubRange1, + typename UniqueSubRange2, + typename UmbrellaStrategy + > + static inline int verified_side(int side, + UniqueSubRange1 const& range_p, + UniqueSubRange2 const& range_q, + UmbrellaStrategy const& umbrella_strategy, + int index_p, int index_q) + { + if (side == 0 + && BOOST_GEOMETRY_CONDITION(VerifyPolicy::use_side_verification)) + { + if (index_p >= 1 && range_p.is_last_segment()) + { + return 0; + } + if (index_q >= 2 && range_q.is_last_segment()) + { + return 0; + } + + auto const dm = get_distance_measure(range_p.at(index_p), + range_p.at(index_p + 1), + range_q.at(index_q), + umbrella_strategy); + static decltype(dm.measure) const zero = 0; + return dm.measure == zero ? 0 : dm.measure > zero ? 1 : -1; + } + else + { + return side; + } } }; @@ -279,10 +342,12 @@ struct base_turn_handler template < - typename TurnInfo + typename TurnInfo, + typename VerifyPolicy > struct touch_interior : public base_turn_handler { + using fun = turn_info_verification_functions<VerifyPolicy>; template < @@ -292,9 +357,11 @@ struct touch_interior : public base_turn_handler static bool handle_as_touch(IntersectionInfo const& info, UniqueSubRange const& non_touching_range) { -#if defined(BOOST_GEOMETRY_USE_RESCALING) - return false; -#endif + if (! BOOST_GEOMETRY_CONDITION(VerifyPolicy::use_handle_as_touch)) + { + return false; + } + // // // ^ Q(i) ^ P(i) @@ -325,7 +392,7 @@ struct touch_interior : public base_turn_handler // Therefore handle it as a normal touch (two segments arrive at the // intersection point). It currently checks for zero, but even a // distance a little bit larger would do. - auto const dm = distance_measure(info.intersections[0], non_touching_range.at(1)); + auto const dm = fun::distance_measure(info.intersections[0], non_touching_range.at(1)); decltype(dm) const zero = 0; bool const result = math::equals(dm, zero); return result; @@ -448,7 +515,8 @@ struct touch_interior : public base_turn_handler // Q intersects on interior of P and continues collinearly if (side_qk_q == side_qi_p) { - both_collinear<index_p, index_q>(range_p, range_q, umbrella_strategy, 1, 2, ti); + fun::template both_collinear<index_p, index_q>(range_p, range_q, umbrella_strategy, + 1, 2, ti); } else { @@ -472,24 +540,35 @@ struct touch_interior : public base_turn_handler template < - typename TurnInfo + typename TurnInfo, + typename VerifyPolicy > struct touch : public base_turn_handler { + using fun = turn_info_verification_functions<VerifyPolicy>; + static inline bool between(int side1, int side2, int turn) { return side1 == side2 && ! opposite(side1, turn); } -#if ! defined(BOOST_GEOMETRY_USE_RESCALING) template < typename UniqueSubRange1, - typename UniqueSubRange2 + typename UniqueSubRange2, + typename UmbrellaStrategy > static inline bool handle_imperfect_touch(UniqueSubRange1 const& range_p, - UniqueSubRange2 const& range_q, TurnInfo& ti) + UniqueSubRange2 const& range_q, + int side_pk_q2, + UmbrellaStrategy const& umbrella_strategy, + TurnInfo& ti) { + if (! BOOST_GEOMETRY_CONDITION(VerifyPolicy::use_handle_imperfect_touch)) + { + return false; + } + // Q // ^ // || @@ -513,13 +592,18 @@ struct touch : public base_turn_handler // >----->P qj is LEFT of P1 and pi is LEFT of Q2 // (the other way round is also possible) - auto const dm_qj_p1 = get_distance_measure(range_p.at(0), range_p.at(1), range_q.at(1)); - auto const dm_pi_q2 = get_distance_measure(range_q.at(1), range_q.at(2), range_p.at(0)); + auto has_distance = [&](const auto& r1, const auto& r2) -> bool + { + auto const d1 = get_distance_measure(r1.at(0), r1.at(1), r2.at(1), umbrella_strategy); + auto const d2 = get_distance_measure(r2.at(1), r2.at(2), r1.at(0), umbrella_strategy); + return d1.measure > 0 && d2.measure > 0; + }; - if (dm_qj_p1.measure > 0 && dm_pi_q2.measure > 0) + if (side_pk_q2 == -1 && has_distance(range_p, range_q)) { // Even though there is a touch, Q(j) is left of P1 // and P(i) is still left from Q2. + // Q continues to the right. // It can continue. ti.operations[0].operation = operation_blocked; // Q turns right -> union (both independent), @@ -529,24 +613,17 @@ struct touch : public base_turn_handler return true; } - auto const dm_pj_q1 = get_distance_measure(range_q.at(0), range_q.at(1), range_p.at(1)); - auto const dm_qi_p2 = get_distance_measure(range_p.at(1), range_p.at(2), range_q.at(0)); - - if (dm_pj_q1.measure > 0 && dm_qi_p2.measure > 0) + if (side_pk_q2 == 1 && has_distance(range_q, range_p)) { - // Even though there is a touch, Q(j) is left of P1 - // and P(i) is still left from Q2. - // It can continue. + // Similarly, but the other way round. + // Q continues to the left. ti.operations[0].operation = operation_union; - // Q turns right -> union (both independent), - // Q turns left -> intersection ti.operations[1].operation = operation_blocked; ti.touch_only = true; return true; } return false; } -#endif template < @@ -572,8 +649,12 @@ struct touch : public base_turn_handler int const side_pk_q1 = has_pk ? side.pk_wrt_q1() : 0; - int const side_qi_p1 = verified_side(dir_info.sides.template get<1, 0>(), range_p, range_q, 0, 0); - int const side_qk_p1 = has_qk ? verified_side(side.qk_wrt_p1(), range_p, range_q, 0, 2) : 0; + int const side_qi_p1 = fun::verified_side(dir_info.sides.template get<1, 0>(), + range_p, range_q, umbrella_strategy, 0, 0); + int const side_qk_p1 = has_qk + ? fun::verified_side(side.qk_wrt_p1(), range_p, range_q, + umbrella_strategy, 0, 2) + : 0; // If Qi and Qk are both at same side of Pi-Pj, // or collinear (so: not opposite sides) @@ -596,21 +677,20 @@ struct touch : public base_turn_handler || side_pk_p == side_qk_p1 || (side_qi_p1 == 0 && side_qk_p1 == 0 && side_pk_p != -1)) { -#if ! defined(BOOST_GEOMETRY_USE_RESCALING) if (side_qk_p1 == 0 && side_pk_q1 == 0 - && has_qk && has_qk - && handle_imperfect_touch(range_p, range_q, ti)) + && has_pk && has_qk + && handle_imperfect_touch(range_p, range_q, side_pk_q2, umbrella_strategy, ti)) { // If q continues collinearly (opposite) with p, it should be blocked // but (FP) not if there is just a tiny space in between return; } -#endif // Collinear -> lines join, continue // (#BRL2) if (side_pk_q2 == 0 && ! block_q) { - both_collinear<0, 1>(range_p, range_q, umbrella_strategy, 2, 2, ti); + fun::template both_collinear<0, 1>(range_p, range_q, umbrella_strategy, + 2, 2, ti); return; } @@ -687,7 +767,10 @@ struct touch : public base_turn_handler { // The qi/qk are opposite to each other, w.r.t. p1 // From left to right or from right to left - int const side_pk_p = has_pk ? verified_side(side.pk_wrt_p1(), range_p, range_p, 0, 2) : 0; + int const side_pk_p = has_pk + ? fun::verified_side(side.pk_wrt_p1(), range_p, range_p, + umbrella_strategy, 0, 2) + : 0; bool const right_to_left = side_qk_p1 == 1; // If p turns into direction of qi (1,2) @@ -738,10 +821,13 @@ struct touch : public base_turn_handler template < - typename TurnInfo + typename TurnInfo, + typename VerifyPolicy > struct equal : public base_turn_handler { + using fun = turn_info_verification_functions<VerifyPolicy>; + template < typename UniqueSubRange1, @@ -769,17 +855,18 @@ struct equal : public base_turn_handler 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 ! defined(BOOST_GEOMETRY_USE_RESCALING) - - if (has_pk && has_qk && side_pk_p == side_qk_p) + if (BOOST_GEOMETRY_CONDITION(VerifyPolicy::use_side_verification) + && has_pk && has_qk && side_pk_p == side_qk_p) { // They turn to the same side, or continue both collinearly // Without rescaling, to check for union/intersection, // try to check side values (without any thresholds) auto const dm_pk_q2 - = get_distance_measure(range_q.at(1), range_q.at(2), range_p.at(2)); + = get_distance_measure(range_q.at(1), range_q.at(2), range_p.at(2), + umbrella_strategy); auto const dm_qk_p2 - = get_distance_measure(range_p.at(1), range_p.at(2), range_q.at(2)); + = get_distance_measure(range_p.at(1), range_p.at(2), range_q.at(2), + umbrella_strategy); if (dm_qk_p2.measure != dm_pk_q2.measure) { @@ -789,7 +876,6 @@ struct equal : public base_turn_handler return; } } -#endif // If pk is collinear with qj-qk, they continue collinearly. // This can be on either side of p1 (== q1), or collinear @@ -797,7 +883,7 @@ struct equal : public base_turn_handler // oppositely if (side_pk_q2 == 0 && side_pk_p == side_qk_p) { - both_collinear<0, 1>(range_p, range_q, umbrella_strategy, 2, 2, ti); + fun::template both_collinear<0, 1>(range_p, range_q, umbrella_strategy, 2, 2, ti); return; } @@ -819,7 +905,8 @@ struct equal : public base_turn_handler template < - typename TurnInfo + typename TurnInfo, + typename VerifyPolicy > struct start : public base_turn_handler { @@ -840,10 +927,10 @@ struct start : public base_turn_handler SideCalculator const& side, UmbrellaStrategy const& ) { -#if defined(BOOST_GEOMETRY_USE_RESCALING) - // With rescaling, start turns are not needed. - return false; -#endif + if (! BOOST_GEOMETRY_CONDITION(VerifyPolicy::use_start_turn)) + { + return false; + } // Start turns have either how_a = -1, or how_b = -1 (either p leaves or q leaves) BOOST_GEOMETRY_ASSERT(dir_info.how_a != dir_info.how_b); @@ -898,7 +985,7 @@ struct equal_opposite : public base_turn_handler IntersectionInfo const& intersection_info) { // For equal-opposite segments, normally don't do anything. - if (AssignPolicy::include_opposite) + if (BOOST_GEOMETRY_CONDITION(AssignPolicy::include_opposite)) { tp.method = method_equal; for (unsigned int i = 0; i < 2; i++) @@ -916,10 +1003,13 @@ struct equal_opposite : public base_turn_handler template < - typename TurnInfo + typename TurnInfo, + typename VerifyPolicy > struct collinear : public base_turn_handler { + using fun = turn_info_verification_functions<VerifyPolicy>; + template < typename IntersectionInfo, @@ -932,9 +1022,11 @@ struct collinear : public base_turn_handler UniqueSubRange2 const& range_q, DirInfo const& dir_info) { -#if defined(BOOST_GEOMETRY_USE_RESCALING) - return false; -#endif + if (! BOOST_GEOMETRY_CONDITION(VerifyPolicy::use_handle_as_equal)) + { + return false; + } + int const arrival_p = dir_info.arrival[0]; int const arrival_q = dir_info.arrival[1]; if (arrival_p * arrival_q != -1 || info.count != 2) @@ -943,8 +1035,9 @@ struct collinear : public base_turn_handler return false; } - auto const dm = distance_measure(info.intersections[1], - arrival_p == 1 ? range_q.at(1) : range_p.at(1)); + auto const dm = arrival_p == 1 + ? fun::distance_measure(info.intersections[1], range_q.at(1)) + : fun::distance_measure(info.intersections[1], range_p.at(1)); decltype(dm) const zero = 0; return math::equals(dm, zero); } @@ -1046,12 +1139,12 @@ struct collinear : public base_turn_handler // measured until the end of the next segment ti.operations[0].remaining_distance = side_p == 0 && has_pk - ? distance_measure(ti.point, range_p.at(2)) - : distance_measure(ti.point, range_p.at(1)); + ? fun::distance_measure(ti.point, range_p.at(2)) + : fun::distance_measure(ti.point, range_p.at(1)); ti.operations[1].remaining_distance = side_q == 0 && has_qk - ? distance_measure(ti.point, range_q.at(2)) - : distance_measure(ti.point, range_q.at(1)); + ? fun::distance_measure(ti.point, range_q.at(2)) + : fun::distance_measure(ti.point, range_q.at(1)); } }; @@ -1110,7 +1203,7 @@ private : // two operations blocked, so the whole point does not need // to be generated. // So return false to indicate nothing is to be done. - if (AssignPolicy::include_opposite) + if (BOOST_GEOMETRY_CONDITION(AssignPolicy::include_opposite)) { tp.operations[Index].operation = operation_opposite; blocked = operation_opposite; @@ -1204,7 +1297,7 @@ public: *out++ = tp; } - if (AssignPolicy::include_opposite) + if (BOOST_GEOMETRY_CONDITION(AssignPolicy::include_opposite)) { // Handle cases not yet handled above if ((arrival_q == -1 && arrival_p == 0) @@ -1352,8 +1445,11 @@ struct get_turn_info if (handle_as_start) { // It is in some cases necessary to handle a start turn - if (AssignPolicy::include_start_turn - && start<TurnInfo>::apply(range_p, range_q, tp, inters.i_info(), inters.d_info(), inters.sides(), umbrella_strategy)) + using handler = start<TurnInfo, verify_policy_aa>; + if (BOOST_GEOMETRY_CONDITION(AssignPolicy::include_start_turn) + && handler::apply(range_p, range_q, tp, + inters.i_info(), inters.d_info(), inters.sides(), + umbrella_strategy)) { *out++ = tp; } @@ -1365,7 +1461,7 @@ struct get_turn_info if (handle_as_touch_interior) { - typedef touch_interior<TurnInfo> handler; + using handler = touch_interior<TurnInfo, verify_policy_aa>; if ( inters.d_info().arrival[1] == 1 ) { @@ -1406,7 +1502,9 @@ struct get_turn_info if (handle_as_touch) { // Touch: both segments arrive at the intersection point - touch<TurnInfo>::apply(range_p, range_q, tp, inters.i_info(), inters.d_info(), inters.sides(), umbrella_strategy); + using handler = touch<TurnInfo, verify_policy_aa>; + handler::apply(range_p, range_q, tp, inters.i_info(), inters.d_info(), inters.sides(), + umbrella_strategy); *out++ = tp; } @@ -1415,16 +1513,17 @@ struct get_turn_info // Collinear if ( ! inters.d_info().opposite ) { + using handler = collinear<TurnInfo, verify_policy_aa>; if (inters.d_info().arrival[0] == 0 - || collinear<TurnInfo>::handle_as_equal(inters.i_info(), range_p, range_q, inters.d_info())) + || handler::handle_as_equal(inters.i_info(), range_p, range_q, inters.d_info())) { // Both segments arrive at the second intersection point handle_as_equal = true; } else { - collinear<TurnInfo>::apply(range_p, range_q, tp, - inters.i_info(), inters.d_info(), inters.sides()); + handler::apply(range_p, range_q, tp, inters.i_info(), + inters.d_info(), inters.sides()); *out++ = tp; } } @@ -1445,7 +1544,8 @@ struct get_turn_info { // Both equal // or collinear-and-ending at intersection point - equal<TurnInfo>::apply(range_p, range_q, tp, + using handler = equal<TurnInfo, verify_policy_aa>; + handler::apply(range_p, range_q, tp, inters.i_info(), inters.d_info(), inters.sides(), umbrella_strategy); if (handle_as_collinear) @@ -1467,8 +1567,10 @@ struct get_turn_info } } - if ((handle_as_degenerate && AssignPolicy::include_degenerate) - || (do_only_convert && AssignPolicy::include_no_turn)) + if ((handle_as_degenerate + && BOOST_GEOMETRY_CONDITION(AssignPolicy::include_degenerate)) + || (do_only_convert + && BOOST_GEOMETRY_CONDITION(AssignPolicy::include_no_turn))) { if (inters.i_info().count > 0) { @@ -1489,8 +1591,4 @@ struct get_turn_info }} // namespace boost::geometry -#if defined(_MSC_VER) -#pragma warning(pop) -#endif - #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_HPP 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 2b56d7dd57..007ada0f2f 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 @@ -201,7 +201,7 @@ public: BOOST_STATIC_ASSERT(I < 2); return ips[I]; } - + private: // only if collinear (same_dirs) @@ -287,7 +287,7 @@ struct get_turn_info_for_endpoint if ( intersections.template get<1>().p_operation == operation_none ) return result_ignore_ip0; - + bool append1_last = analyse_segment_and_assign_ip(range_p, range_q, intersections.template get<1>(), @@ -436,7 +436,7 @@ struct get_turn_info_for_endpoint if ( operations_both(operations, operation_continue) ) { - if ( op1 != operation_union + if ( op1 != operation_union || op2 != operation_union || ! ( G1Index == 0 ? inters.is_spike_q() : inters.is_spike_p() ) ) { @@ -544,7 +544,7 @@ struct get_turn_info_for_endpoint OutputIterator out) { TurnInfo tp = tp_model; - + //geometry::convert(ip, tp.point); //tp.method = method; base_turn_handler::assign_point(tp, method, result.intersection_points, ip_index); 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 b82528fa4d..00a6004f2d 100644 --- a/boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp +++ b/boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp @@ -50,8 +50,6 @@ template > struct side_calculator { - typedef typename UniqueSubRange1::point_type point1_type; - typedef typename UniqueSubRange2::point_type point2_type; typedef decltype(std::declval<Strategy>().side()) side_strategy_type; inline side_calculator(UniqueSubRange1 const& range_p, @@ -76,13 +74,13 @@ struct side_calculator 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 auto const& get_pi() const { return m_range_p.at(0); } + inline auto const& get_pj() const { return m_range_p.at(1); } + inline auto 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); } + inline auto const& get_qi() const { return m_range_q.at(0); } + inline auto const& get_qj() const { return m_range_q.at(1); } + inline auto const& get_qk() const { return m_range_q.at(2); } // Used side-strategy, owned by the calculator side_strategy_type m_side_strategy; @@ -338,9 +336,6 @@ public: typedef typename intersection_policy_type::return_type result_type; - typedef typename UniqueSubRange1::point_type point1_type; - typedef typename UniqueSubRange2::point_type point2_type; - typedef side_calculator < UniqueSubRange1, UniqueSubRange2, UmbrellaStrategy @@ -350,7 +345,7 @@ public: < UniqueSubRange2, UniqueSubRange1, UmbrellaStrategy > swapped_side_calculator_type; - + intersection_info_base(UniqueSubRange1 const& range_p, UniqueSubRange2 const& range_q, UmbrellaStrategy const& umbrella_strategy, @@ -366,13 +361,13 @@ public: inline bool p_is_last_segment() const { return m_range_p.is_last_segment(); } inline bool q_is_last_segment() const { return m_range_q.is_last_segment(); } - 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 auto const& rpi() const { return m_side_calc.get_pi(); } + inline auto const& rpj() const { return m_side_calc.get_pj(); } + inline auto const& rpk() const { return m_side_calc.get_pk(); } - 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 auto const& rqi() const { return m_side_calc.get_qi(); } + inline auto const& rqj() const { return m_side_calc.get_qj(); } + inline auto const& rqk() const { return m_side_calc.get_qk(); } inline side_calculator_type const& sides() const { return m_side_calc; } inline swapped_side_calculator_type const& swapped_sides() const @@ -410,14 +405,11 @@ class intersection_info public: - typedef typename UniqueSubRange1::point_type point1_type; - typedef typename UniqueSubRange2::point_type point2_type; - typedef typename UmbrellaStrategy::cs_tag cs_tag; typedef typename base::side_calculator_type side_calculator_type; typedef typename base::result_type result_type; - + typedef typename result_type::intersection_points_type i_info_type; typedef typename result_type::direction_type d_info_type; @@ -470,7 +462,7 @@ public: return true; } } - + return false; } @@ -493,18 +485,18 @@ public: bool const has_pk = ! base::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 direction_code<cs_tag>(base::rqi(), base::rqj(), base::rqk()) == -1; } - + return true; } } - + return false; } 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 20aaa6a434..76d7faf6de 100644 --- a/boost/geometry/algorithms/detail/overlay/get_turn_info_la.hpp +++ b/boost/geometry/algorithms/detail/overlay/get_turn_info_la.hpp @@ -95,7 +95,7 @@ struct get_turn_info_linear_areal } else { - typedef touch_interior<TurnInfo> handler; + using handler = touch_interior<TurnInfo, verify_policy_la>; // If Q (1) arrives (1) if ( inters.d_info().arrival[1] == 1 ) @@ -120,12 +120,12 @@ struct get_turn_info_linear_areal replace_method_and_operations_tm(tp.method, tp.operations[0].operation, tp.operations[1].operation); - + // this function assumes that 'u' must be set for a spike calculate_spike_operation(tp.operations[0].operation, inters, umbrella_strategy); - + *out++ = tp; } } @@ -148,9 +148,10 @@ struct get_turn_info_linear_areal { // do nothing } - else + else { - touch<TurnInfo>::apply(range_p, range_q, tp, + using handler = touch<TurnInfo, verify_policy_la>; + handler::apply(range_p, range_q, tp, inters.i_info(), inters.d_info(), inters.sides(), umbrella_strategy); @@ -177,7 +178,7 @@ struct get_turn_info_linear_areal } else { - tp.operations[0].operation = operation_union; + tp.operations[0].operation = operation_union; } } } @@ -246,7 +247,8 @@ struct get_turn_info_linear_areal { // Both equal // or collinear-and-ending at intersection point - equal<TurnInfo>::apply(range_p, range_q, tp, + using handler = equal<TurnInfo, verify_policy_la>; + handler::apply(range_p, range_q, tp, inters.i_info(), inters.d_info(), inters.sides(), umbrella_strategy); @@ -295,7 +297,8 @@ struct get_turn_info_linear_areal if ( inters.d_info().arrival[0] == 0 ) { // Collinear, but similar thus handled as equal - equal<TurnInfo>::apply(range_p, range_q, tp, + using handler = equal<TurnInfo, verify_policy_la>; + handler::apply(range_p, range_q, tp, inters.i_info(), inters.d_info(), inters.sides(), umbrella_strategy); @@ -304,8 +307,9 @@ struct get_turn_info_linear_areal } else { - collinear<TurnInfo>::apply(range_p, range_q, tp, - inters.i_info(), inters.d_info(), inters.sides()); + using handler = collinear<TurnInfo, verify_policy_la>; + handler::apply(range_p, range_q, tp, inters.i_info(), + inters.d_info(), inters.sides()); //method_replace = method_touch_interior; //version = append_collinear; @@ -403,7 +407,7 @@ struct get_turn_info_linear_areal if ( is_p_spike ) { int const pk_q1 = inters.sides().pk_wrt_q1(); - + bool going_in = pk_q1 < 0; // Pk on the right bool going_out = pk_q1 > 0; // Pk on the left @@ -411,7 +415,7 @@ struct get_turn_info_linear_areal // special cases if ( qk_q1 < 0 ) // Q turning R - { + { // spike on the edge point // if it's already known that the spike is going out this musn't be checked if ( ! going_out @@ -524,7 +528,7 @@ struct get_turn_info_linear_areal || tp.operations[0].operation == operation_intersection ) : // i ??? true ) && inters.is_spike_p(); - + // TODO: throw an exception for spike in Areal? /*bool is_q_spike = ( ( Version == append_touches && tp.operations[1].operation == operation_continue ) @@ -671,7 +675,7 @@ struct get_turn_info_linear_areal // possible to define a spike on an endpoint. Areal geometries must // NOT have spikes at all. One thing that could be done is to throw // an exception when spike is detected in Areal geometry. - + template <bool EnableFirst, bool EnableLast, typename UniqueSubRange1, @@ -797,7 +801,7 @@ struct get_turn_info_linear_areal && ( ip_count > 1 ? (ip1.is_pj && !ip1.is_qi) : (ip0.is_pj && !ip0.is_qi) ) ) // prevents duplication { TurnInfo tp = tp_model; - + if ( inters.i_info().count > 1 ) { //BOOST_GEOMETRY_ASSERT( result.template get<1>().dir_a == 0 && result.template get<1>().dir_b == 0 ); @@ -823,7 +827,7 @@ struct get_turn_info_linear_areal { 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 + 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 @@ -849,7 +853,7 @@ struct get_turn_info_linear_areal tp.operations[0].operation = operation_blocked; tp.operations[0].position = position_back; tp.operations[1].position = position_middle; - + // equals<> or collinear<> will assign the second point, // we'd like to assign the first one unsigned int ip_index = ip_count > 1 ? 1 : 0; 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 ccb5e668ae..6dbd6d682c 100644 --- a/boost/geometry/algorithms/detail/overlay/get_turn_info_ll.hpp +++ b/boost/geometry/algorithms/detail/overlay/get_turn_info_ll.hpp @@ -83,6 +83,8 @@ struct get_turn_info_linear_linear case 'm' : { + using handler = touch_interior<TurnInfo, verify_policy_ll>; + if ( get_turn_info_for_endpoint<false, true> ::apply(range_p, range_q, tp_model, inters, method_touch_interior, out, @@ -92,15 +94,10 @@ struct get_turn_info_linear_linear } else { - typedef touch_interior - < - TurnInfo - > policy; - // If Q (1) arrives (1) if ( inters.d_info().arrival[1] == 1) { - policy::template apply<0>(range_p, range_q, tp, + handler::template apply<0>(range_p, range_q, tp, inters.i_info(), inters.d_info(), inters.sides(), umbrella_strategy); @@ -108,12 +105,12 @@ struct get_turn_info_linear_linear else { // Swap p/q - policy::template apply<1>(range_q, range_p, tp, + handler::template apply<1>(range_q, range_p, tp, inters.i_info(), inters.d_info(), inters.swapped_sides(), umbrella_strategy); } - + if ( tp.operations[0].operation == operation_blocked ) { tp.operations[1].is_collinear = true; @@ -126,7 +123,7 @@ struct get_turn_info_linear_linear replace_method_and_operations_tm(tp.method, tp.operations[0].operation, tp.operations[1].operation); - + *out++ = tp; } } @@ -142,6 +139,8 @@ struct get_turn_info_linear_linear break; case 't' : { + using handler = touch<TurnInfo, verify_policy_ll>; + // Both touch (both arrive there) if ( get_turn_info_for_endpoint<false, true> ::apply(range_p, range_q, @@ -150,12 +149,12 @@ struct get_turn_info_linear_linear { // do nothing } - else + else { - touch<TurnInfo>::apply(range_p, range_q, tp, - inters.i_info(), inters.d_info(), - inters.sides(), - umbrella_strategy); + handler::apply(range_p, range_q, tp, + inters.i_info(), inters.d_info(), + inters.sides(), + umbrella_strategy); // workarounds for touch<> not taking spikes into account starts here // those was discovered empirically @@ -170,7 +169,7 @@ struct get_turn_info_linear_linear if ( inters.is_spike_p() && inters.is_spike_q() ) { tp.operations[0].operation = operation_union; - tp.operations[1].operation = operation_union; + tp.operations[1].operation = operation_union; } else { @@ -189,7 +188,7 @@ struct get_turn_info_linear_linear } else { - tp.operations[0].operation = operation_union; + tp.operations[0].operation = operation_union; } } else @@ -208,7 +207,7 @@ struct get_turn_info_linear_linear } else { - tp.operations[1].operation = operation_union; + tp.operations[1].operation = operation_union; } } else @@ -224,7 +223,7 @@ struct get_turn_info_linear_linear && inters.is_spike_p() ) { tp.operations[0].operation = operation_union; - tp.operations[1].operation = operation_union; + tp.operations[1].operation = operation_union; } } else if ( tp.operations[0].operation == operation_none @@ -275,6 +274,8 @@ struct get_turn_info_linear_linear break; case 'e': { + using handler = equal<TurnInfo, verify_policy_ll>; + if ( get_turn_info_for_endpoint<true, true> ::apply(range_p, range_q, tp_model, inters, method_equal, out, @@ -291,7 +292,7 @@ struct get_turn_info_linear_linear { // Both equal // or collinear-and-ending at intersection point - equal<TurnInfo>::apply(range_p, range_q, tp, + handler::apply(range_p, range_q, tp, inters.i_info(), inters.d_info(), inters.sides(), umbrella_strategy); @@ -351,7 +352,9 @@ struct get_turn_info_linear_linear if ( inters.d_info().arrival[0] == 0 ) { // Collinear, but similar thus handled as equal - equal<TurnInfo>::apply(range_p, range_q, tp, + using handler = equal<TurnInfo, verify_policy_ll>; + + handler::apply(range_p, range_q, tp, inters.i_info(), inters.d_info(), inters.sides(), umbrella_strategy); @@ -364,8 +367,10 @@ struct get_turn_info_linear_linear } else { - collinear<TurnInfo>::apply(range_p, range_q, - tp, inters.i_info(), inters.d_info(), inters.sides()); + using handler = collinear<TurnInfo, verify_policy_ll>; + handler::apply(range_p, range_q, tp, + inters.i_info(), inters.d_info(), + inters.sides()); //method_replace = method_touch_interior; //spike_op = operation_continue; @@ -374,7 +379,7 @@ struct get_turn_info_linear_linear // transform turn turn_transformer_ec transformer(method_replace); transformer(tp); - + // conditionally handle spikes if ( ! BOOST_GEOMETRY_CONDITION(handle_spikes) || ! append_collinear_spikes(tp, inters, @@ -519,7 +524,7 @@ struct get_turn_info_linear_linear return true; } - + return false; } @@ -562,9 +567,9 @@ struct get_turn_info_linear_linear { tp.operations[0].is_collinear = true; tp.operations[1].is_collinear = false; - + BOOST_GEOMETRY_ASSERT(inters.i_info().count > 1); - + base_turn_handler::assign_point(tp, method_touch_interior, inters.i_info(), 1); } @@ -593,7 +598,7 @@ struct get_turn_info_linear_linear { tp.operations[0].is_collinear = false; tp.operations[1].is_collinear = true; - + BOOST_GEOMETRY_ASSERT(inters.i_info().count > 0); base_turn_handler::assign_point(tp, method_touch_interior, inters.i_info(), 0); @@ -608,7 +613,7 @@ struct get_turn_info_linear_linear res = true; } - + return res; } diff --git a/boost/geometry/algorithms/detail/overlay/get_turns.hpp b/boost/geometry/algorithms/detail/overlay/get_turns.hpp index 35ca5157de..326c883b39 100644 --- a/boost/geometry/algorithms/detail/overlay/get_turns.hpp +++ b/boost/geometry/algorithms/detail/overlay/get_turns.hpp @@ -1,11 +1,10 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. -// Copyright (c) 2014-2017 Adam Wulkiewicz, Lodz, Poland. +// Copyright (c) 2014-2023 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2014-2021. // Modifications copyright (c) 2014-2021 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,10 +15,10 @@ #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURNS_HPP +#include <array> #include <cstddef> #include <map> -#include <boost/array.hpp> #include <boost/concept_check.hpp> #include <boost/core/ignore_unused.hpp> #include <boost/range/begin.hpp> @@ -29,7 +28,6 @@ #include <boost/geometry/algorithms/detail/disjoint/box_box.hpp> #include <boost/geometry/algorithms/detail/disjoint/point_point.hpp> -#include <boost/geometry/algorithms/detail/interior_iterator.hpp> #include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp> #include <boost/geometry/algorithms/detail/overlay/get_turn_info_ll.hpp> #include <boost/geometry/algorithms/detail/overlay/get_turn_info_la.hpp> @@ -111,7 +109,7 @@ template > struct unique_sub_range_from_section { - typedef Point point_type; + using point_type = Point; unique_sub_range_from_section(Section const& section, signed_size_type index, CircularIterator circular_iterator, @@ -123,7 +121,7 @@ struct unique_sub_range_from_section , m_previous_point(previous) , m_current_point(current) , m_circular_iterator(circular_iterator) - , m_point_retrieved(false) + , m_next_point_retrieved(false) , m_strategy(strategy) , m_robust_policy(robust_policy) {} @@ -158,18 +156,18 @@ struct unique_sub_range_from_section private : inline Point const& get_next_point() const { - if (! m_point_retrieved) + if (! m_next_point_retrieved) { advance_to_non_duplicate_next(m_current_point, m_circular_iterator); - m_point = *m_circular_iterator; - m_point_retrieved = true; + m_next_point_retrieved = true; } - return m_point; + return *m_circular_iterator; } inline void advance_to_non_duplicate_next(Point const& current, CircularIterator& circular_iterator) const { - typedef typename robust_point_type<Point, RobustPolicy>::type robust_point_type; + using box_point_type = typename geometry::point_type<typename Section::box_type>::type; + using robust_point_type = typename robust_point_type<box_point_type, RobustPolicy>::type; robust_point_type current_robust_point; robust_point_type next_robust_point; geometry::recalculate(current_robust_point, current, m_robust_policy); @@ -199,8 +197,7 @@ private : Point const& m_previous_point; Point const& m_current_point; mutable CircularIterator m_circular_iterator; - mutable Point m_point; - mutable bool m_point_retrieved; + mutable bool m_next_point_retrieved; Strategy m_strategy; RobustPolicy m_robust_policy; }; @@ -571,7 +568,7 @@ struct get_turns_cs { 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 std::array<box_point_type, 4> box_array; using view_type = detail::closed_clockwise_view < @@ -843,10 +840,8 @@ struct get_turns_polygon_cs signed_size_type i = 0; - typename interior_return_type<Polygon const>::type - rings = interior_rings(polygon); - for (typename detail::interior_iterator<Polygon const>::type - it = boost::begin(rings); it != boost::end(rings); ++it, ++i) + auto const& rings = interior_rings(polygon); + for (auto it = boost::begin(rings); it != boost::end(rings); ++it, ++i) { intersector_type::apply( source_id1, *it, @@ -878,15 +873,8 @@ struct get_turns_multi_polygon_cs Turns& turns, InterruptPolicy& interrupt_policy) { - typedef typename boost::range_iterator - < - Multi const - >::type iterator_type; - signed_size_type i = 0; - for (iterator_type it = boost::begin(multi); - it != boost::end(multi); - ++it, ++i) + for (auto it = boost::begin(multi); it != boost::end(multi); ++it, ++i) { // Call its single version get_turns_polygon_cs @@ -927,24 +915,24 @@ struct get_turn_info_type<Geometry1, Geometry2, AssignPolicy, Tag1, Tag2, linear : overlay::get_turn_info_linear_areal<AssignPolicy> {}; -template <typename Geometry1, typename Geometry2, typename SegmentRatio, +template <typename Geometry1, typename Geometry2, typename Point, typename SegmentRatio, typename Tag1 = typename tag<Geometry1>::type, typename Tag2 = typename tag<Geometry2>::type, typename TagBase1 = typename topological_tag_base<Geometry1>::type, typename TagBase2 = typename topological_tag_base<Geometry2>::type> struct turn_operation_type { - typedef overlay::turn_operation<typename point_type<Geometry1>::type, SegmentRatio> type; + using type = overlay::turn_operation<Point, SegmentRatio>; }; -template <typename Geometry1, typename Geometry2, typename SegmentRatio, typename Tag1, typename Tag2> -struct turn_operation_type<Geometry1, Geometry2, SegmentRatio, Tag1, Tag2, linear_tag, linear_tag> +template <typename Geometry1, typename Geometry2, typename Point, typename SegmentRatio, typename Tag1, typename Tag2> +struct turn_operation_type<Geometry1, Geometry2, Point, SegmentRatio, Tag1, Tag2, linear_tag, linear_tag> { - typedef overlay::turn_operation_linear<typename point_type<Geometry1>::type, SegmentRatio> type; + using type = overlay::turn_operation_linear<Point, SegmentRatio>; }; -template <typename Geometry1, typename Geometry2, typename SegmentRatio, typename Tag1, typename Tag2> -struct turn_operation_type<Geometry1, Geometry2, SegmentRatio, Tag1, Tag2, linear_tag, areal_tag> +template <typename Geometry1, typename Geometry2, typename Point, typename SegmentRatio, typename Tag1, typename Tag2> +struct turn_operation_type<Geometry1, Geometry2, Point, SegmentRatio, Tag1, Tag2, linear_tag, areal_tag> { - typedef overlay::turn_operation_linear<typename point_type<Geometry1>::type, SegmentRatio> type; + using type = overlay::turn_operation_linear<Point, SegmentRatio>; }; }} // namespace detail::get_turns diff --git a/boost/geometry/algorithms/detail/overlay/handle_colocations.hpp b/boost/geometry/algorithms/detail/overlay/handle_colocations.hpp index 9afea24c2b..aaabb4a4df 100644 --- a/boost/geometry/algorithms/detail/overlay/handle_colocations.hpp +++ b/boost/geometry/algorithms/detail/overlay/handle_colocations.hpp @@ -29,6 +29,7 @@ #include <boost/geometry/core/point_order.hpp> #include <boost/geometry/algorithms/detail/overlay/cluster_info.hpp> #include <boost/geometry/algorithms/detail/overlay/do_reverse.hpp> +#include <boost/geometry/algorithms/detail/overlay/colocate_clusters.hpp> #include <boost/geometry/algorithms/detail/overlay/get_clusters.hpp> #include <boost/geometry/algorithms/detail/overlay/get_ring.hpp> #include <boost/geometry/algorithms/detail/overlay/is_self_turn.hpp> @@ -52,22 +53,22 @@ namespace boost { namespace geometry namespace detail { namespace overlay { +// Removes clusters which have only one point left, or are empty. template <typename Turns, typename Clusters> inline void remove_clusters(Turns& turns, Clusters& clusters) { - typename Clusters::iterator it = clusters.begin(); + auto it = clusters.begin(); while (it != clusters.end()) { // Hold iterator and increase. We can erase cit, this keeps the // iterator valid (cf The standard associative-container erase idiom) - typename Clusters::iterator current_it = it; + auto current_it = it; ++it; - std::set<signed_size_type> const& turn_indices - = current_it->second.turn_indices; + auto const& turn_indices = current_it->second.turn_indices; if (turn_indices.size() == 1) { - signed_size_type const turn_index = *turn_indices.begin(); + auto const turn_index = *turn_indices.begin(); turns[turn_index].cluster_id = -1; clusters.erase(current_it); } @@ -78,36 +79,35 @@ template <typename Turns, typename Clusters> inline void cleanup_clusters(Turns& turns, Clusters& clusters) { // Removes discarded turns from clusters - for (typename Clusters::iterator mit = clusters.begin(); - mit != clusters.end(); ++mit) + for (auto& pair : clusters) { - cluster_info& cinfo = mit->second; - std::set<signed_size_type>& ids = cinfo.turn_indices; - for (std::set<signed_size_type>::iterator sit = ids.begin(); - sit != ids.end(); /* no increment */) + auto& cinfo = pair.second; + auto& indices = cinfo.turn_indices; + for (auto sit = indices.begin(); sit != indices.end(); /* no increment */) { - std::set<signed_size_type>::iterator current_it = sit; + auto current_it = sit; ++sit; - signed_size_type const turn_index = *current_it; + auto const turn_index = *current_it; if (turns[turn_index].discarded) { - ids.erase(current_it); + indices.erase(current_it); } } } remove_clusters(turns, clusters); + colocate_clusters(clusters, turns); } -template <typename Turn, typename IdSet> -inline void discard_colocated_turn(Turn& turn, IdSet& ids, signed_size_type id) +template <typename Turn, typename IndexSet> +inline void discard_colocated_turn(Turn& turn, IndexSet& indices, signed_size_type index) { turn.discarded = true; // Set cluster id to -1, but don't clear colocated flags turn.cluster_id = -1; // To remove it later from clusters - ids.insert(id); + indices.insert(index); } template <bool Reverse> @@ -167,22 +167,17 @@ template > inline void discard_interior_exterior_turns(Turns& turns, Clusters& clusters) { - typedef std::set<signed_size_type>::const_iterator set_iterator; - typedef typename boost::range_value<Turns>::type turn_type; - - std::set<signed_size_type> ids_to_remove; + std::set<signed_size_type> indices_to_remove; - for (typename Clusters::iterator cit = clusters.begin(); - cit != clusters.end(); ++cit) + for (auto& pair : clusters) { - cluster_info& cinfo = cit->second; - std::set<signed_size_type>& ids = cinfo.turn_indices; + cluster_info& cinfo = pair.second; - ids_to_remove.clear(); + indices_to_remove.clear(); - for (set_iterator it = ids.begin(); it != ids.end(); ++it) + for (auto index : cinfo.turn_indices) { - turn_type& turn = turns[*it]; + auto& turn = turns[index]; segment_identifier const& seg_0 = turn.operations[0].seg_id; segment_identifier const& seg_1 = turn.operations[1].seg_id; @@ -193,34 +188,33 @@ inline void discard_interior_exterior_turns(Turns& turns, Clusters& clusters) continue; } - for (set_iterator int_it = ids.begin(); int_it != ids.end(); ++int_it) + for (auto interior_index : cinfo.turn_indices) { - if (*it == *int_it) + if (index == interior_index) { continue; } // Turn with, possibly, an interior ring involved - turn_type& int_turn = turns[*int_it]; - segment_identifier const& int_seg_0 = int_turn.operations[0].seg_id; - segment_identifier const& int_seg_1 = int_turn.operations[1].seg_id; + auto& interior_turn = turns[interior_index]; + segment_identifier const& int_seg_0 = interior_turn.operations[0].seg_id; + segment_identifier const& int_seg_1 = interior_turn.operations[1].seg_id; if (is_ie_turn<Reverse0, Reverse1>(seg_0, seg_1, int_seg_0, int_seg_1)) { - discard_colocated_turn(int_turn, ids_to_remove, *int_it); + discard_colocated_turn(interior_turn, indices_to_remove, interior_index); } if (is_ie_turn<Reverse1, Reverse0>(seg_1, seg_0, int_seg_1, int_seg_0)) { - discard_colocated_turn(int_turn, ids_to_remove, *int_it); + discard_colocated_turn(interior_turn, indices_to_remove, interior_index); } } } - // Erase from the ids (which cannot be done above) - for (set_iterator sit = ids_to_remove.begin(); - sit != ids_to_remove.end(); ++sit) + // Erase from the indices (which cannot be done above) + for (auto index : indices_to_remove) { - ids.erase(*sit); + cinfo.turn_indices.erase(index); } } } @@ -233,19 +227,14 @@ template > inline void set_colocation(Turns& turns, Clusters const& clusters) { - typedef std::set<signed_size_type>::const_iterator set_iterator; - typedef typename boost::range_value<Turns>::type turn_type; - - for (typename Clusters::const_iterator cit = clusters.begin(); - cit != clusters.end(); ++cit) + for (auto const& pair : clusters) { - cluster_info const& cinfo = cit->second; - std::set<signed_size_type> const& ids = cinfo.turn_indices; + cluster_info const& cinfo = pair.second; bool both_target = false; - for (set_iterator it = ids.begin(); it != ids.end(); ++it) + for (auto index : cinfo.turn_indices) { - turn_type const& turn = turns[*it]; + auto const& turn = turns[index]; if (turn.both(operation_from_overlay<OverlayType>::value)) { both_target = true; @@ -255,9 +244,9 @@ inline void set_colocation(Turns& turns, Clusters const& clusters) if (both_target) { - for (set_iterator it = ids.begin(); it != ids.end(); ++it) + for (auto index : cinfo.turn_indices) { - turn_type& turn = turns[*it]; + auto& turn = turns[index]; turn.has_colocated_both = true; } } @@ -276,7 +265,7 @@ inline void check_colocation(bool& has_blocked, has_blocked = false; - typename Clusters::const_iterator mit = clusters.find(cluster_id); + auto mit = clusters.find(cluster_id); if (mit == clusters.end()) { return; @@ -284,11 +273,9 @@ inline void check_colocation(bool& has_blocked, cluster_info const& cinfo = mit->second; - for (std::set<signed_size_type>::const_iterator it - = cinfo.turn_indices.begin(); - it != cinfo.turn_indices.end(); ++it) + for (auto index : cinfo.turn_indices) { - turn_type const& turn = turns[*it]; + turn_type const& turn = turns[index]; if (turn.any_blocked()) { has_blocked = true; @@ -410,21 +397,15 @@ inline bool fill_sbs(Sbs& sbs, Point& turn_point, Turns const& turns, Geometry1 const& geometry1, Geometry2 const& geometry2) { - typedef typename boost::range_value<Turns>::type turn_type; - - std::set<signed_size_type> const& ids = cinfo.turn_indices; - - if (ids.empty()) + if (cinfo.turn_indices.empty()) { return false; } bool first = true; - for (std::set<signed_size_type>::const_iterator sit = ids.begin(); - sit != ids.end(); ++sit) + for (auto turn_index : cinfo.turn_indices) { - signed_size_type turn_index = *sit; - turn_type const& turn = turns[turn_index]; + auto const& turn = turns[turn_index]; if (first) { turn_point = turn.point; @@ -464,10 +445,9 @@ inline void gather_cluster_properties(Clusters& clusters, Turns& turns, Reverse1, Reverse2, OverlayType, point_type, SideStrategy, std::less<int> > sbs_type; - for (typename Clusters::iterator mit = clusters.begin(); - mit != clusters.end(); ++mit) + for (auto& pair : clusters) { - cluster_info& cinfo = mit->second; + cluster_info& cinfo = pair.second; sbs_type sbs(strategy); point_type turn_point; // should be all the same for all turns in cluster @@ -515,10 +495,10 @@ inline void gather_cluster_properties(Clusters& clusters, Turns& turns, continue; } - if (BOOST_GEOMETRY_CONDITION(OverlayType != overlay_difference) + if (BOOST_GEOMETRY_CONDITION(OverlayType == overlay_difference) && is_self_turn<OverlayType>(turn)) { - // Difference needs the self-turns, TODO: investigate + // TODO: investigate continue; } diff --git a/boost/geometry/algorithms/detail/overlay/handle_self_turns.hpp b/boost/geometry/algorithms/detail/overlay/handle_self_turns.hpp index aec43548d4..435a80c272 100644 --- a/boost/geometry/algorithms/detail/overlay/handle_self_turns.hpp +++ b/boost/geometry/algorithms/detail/overlay/handle_self_turns.hpp @@ -1,10 +1,10 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2017 Barend Gehrels, Amsterdam, the Netherlands. -// Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland. +// Copyright (c) 2017-2023 Adam Wulkiewicz, Lodz, Poland. -// This file was modified by Oracle on 2019-2020. -// Modifications copyright (c) 2019-2020 Oracle and/or its affiliates. +// This file was modified by Oracle on 2019-2022. +// Modifications copyright (c) 2019-2022 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -19,11 +19,11 @@ #include <boost/range/end.hpp> #include <boost/range/value_type.hpp> +#include <boost/geometry/algorithms/detail/covered_by/implementation.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/overlay_type.hpp> -#include <boost/geometry/algorithms/covered_by.hpp> -#include <boost/geometry/algorithms/within.hpp> +#include <boost/geometry/algorithms/detail/within/implementation.hpp> namespace boost { namespace geometry { @@ -106,15 +106,8 @@ struct discard_closed_turns<overlay_union, operation_union> Geometry0 const& geometry0, Geometry1 const& geometry1, Strategy const& strategy) { - typedef typename boost::range_value<Turns>::type turn_type; - - for (typename boost::range_iterator<Turns>::type - it = boost::begin(turns); - it != boost::end(turns); - ++it) + for (auto& turn : turns) { - turn_type& turn = *it; - if (! turn.discarded && is_self_turn<overlay_union>(turn) && check_within<overlay_union>::apply(turn, geometry0, @@ -137,18 +130,16 @@ private : bool is_self_cluster(signed_size_type cluster_id, const Turns& turns, Clusters const& clusters) { - typename Clusters::const_iterator cit = clusters.find(cluster_id); + auto cit = clusters.find(cluster_id); if (cit == clusters.end()) { return false; } cluster_info const& cinfo = cit->second; - for (std::set<signed_size_type>::const_iterator it - = cinfo.turn_indices.begin(); - it != cinfo.turn_indices.end(); ++it) + for (auto index : cinfo.turn_indices) { - if (! is_self_turn<OverlayType>(turns[*it])) + if (! is_self_turn<OverlayType>(turns[index])) { return false; } @@ -164,28 +155,25 @@ private : Geometry0 const& geometry0, Geometry1 const& geometry1, Strategy const& strategy) { - for (typename Clusters::const_iterator cit = clusters.begin(); - cit != clusters.end(); ++cit) + for (auto const& pair : clusters) { - signed_size_type const cluster_id = cit->first; + signed_size_type const cluster_id = pair.first; + cluster_info const& cinfo = pair.second; // If there are only self-turns in the cluster, the cluster should // be located within the other geometry, for intersection - if (! cit->second.turn_indices.empty() + if (! cinfo.turn_indices.empty() && is_self_cluster(cluster_id, turns, clusters)) { - cluster_info const& cinfo = cit->second; - signed_size_type const index = *cinfo.turn_indices.begin(); - if (! check_within<OverlayType>::apply(turns[index], + signed_size_type const first_index = *cinfo.turn_indices.begin(); + if (! check_within<OverlayType>::apply(turns[first_index], geometry0, geometry1, strategy)) { // Discard all turns in cluster - for (std::set<signed_size_type>::const_iterator sit - = cinfo.turn_indices.begin(); - sit != cinfo.turn_indices.end(); ++sit) + for (auto index : cinfo.turn_indices) { - turns[*sit].discarded = true; + turns[index].discarded = true; } } } @@ -203,15 +191,8 @@ public : { discard_clusters(turns, clusters, geometry0, geometry1, strategy); - typedef typename boost::range_value<Turns>::type turn_type; - - for (typename boost::range_iterator<Turns>::type - it = boost::begin(turns); - it != boost::end(turns); - ++it) + for (auto& turn : turns) { - turn_type& turn = *it; - // It is a ii self-turn // Check if it is within the other geometry if (! turn.discarded diff --git a/boost/geometry/algorithms/detail/overlay/intersection_box_box.hpp b/boost/geometry/algorithms/detail/overlay/intersection_box_box.hpp index c62b7d2834..31db94dd95 100644 --- a/boost/geometry/algorithms/detail/overlay/intersection_box_box.hpp +++ b/boost/geometry/algorithms/detail/overlay/intersection_box_box.hpp @@ -63,7 +63,7 @@ struct intersection_box_box // Set dimensions of output coordinate set<min_corner, Dimension>(box_out, min1 < min2 ? min2 : min1); set<max_corner, Dimension>(box_out, max1 > max2 ? max2 : max1); - + return intersection_box_box<Dimension + 1, DimensionCount> ::apply(box1, box2, robust_policy, box_out, strategy); } diff --git a/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp b/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp index 153fb1cf4b..df3b70a456 100644 --- a/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp +++ b/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp @@ -2,9 +2,10 @@ // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. -// This file was modified by Oracle on 2014-2020. -// Modifications copyright (c) 2014-2020 Oracle and/or its affiliates. +// This file was modified by Oracle on 2014-2021. +// Modifications copyright (c) 2014-2021 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 @@ -25,7 +26,6 @@ #include <boost/range/size.hpp> #include <boost/geometry/algorithms/convert.hpp> -#include <boost/geometry/algorithms/detail/check_iterator_range.hpp> #include <boost/geometry/algorithms/detail/point_on_border.hpp> #include <boost/geometry/algorithms/detail/overlay/clip_linestring.hpp> #include <boost/geometry/algorithms/detail/overlay/follow.hpp> @@ -59,6 +59,7 @@ #if defined(BOOST_GEOMETRY_DEBUG_FOLLOW) #include <boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp> #include <boost/geometry/io/wkt/wkt.hpp> +#include <boost/geometry/util/for_each_with_index.hpp> #endif namespace boost { namespace geometry @@ -145,11 +146,10 @@ struct intersection_linestring_linestring_point geometry::get_intersection_points(linestring1, linestring2, robust_policy, turns, strategy); - for (typename boost::range_iterator<std::deque<turn_info> const>::type - it = boost::begin(turns); it != boost::end(turns); ++it) + for (auto const& turn : turns) { PointOut p; - geometry::convert(it->point, p); + geometry::convert(turn.point, p); *out++ = p; } return out; @@ -212,11 +212,10 @@ struct intersection_of_linestring_with_areal bool found_union = false; bool found_front = false; - for (typename Turns::const_iterator it = turns.begin(); - it != turns.end(); ++it) + for (auto const& turn : turns) { - method_type const method = it->method; - operation_type const op = it->operations[0].operation; + method_type const method = turn.method; + operation_type const op = turn.operations[0].operation; if (method == method_crosses) { @@ -240,7 +239,7 @@ struct intersection_of_linestring_with_areal return false; } - if (it->operations[0].position == position_front) + if (turn.operations[0].position == position_front) { found_front = true; } @@ -378,14 +377,12 @@ struct intersection_of_linestring_with_areal return out; } - + #if defined(BOOST_GEOMETRY_DEBUG_FOLLOW) - int index = 0; - for(typename std::deque<turn_info>::const_iterator - it = turns.begin(); it != turns.end(); ++it) + for_each_with_index(turns, [](auto index, auto const& turn) { - debug_follow(*it, it->operations[0], index++); - } + debug_follow(turn, turn.operations[0], index); + }); #endif return follower::apply @@ -402,10 +399,9 @@ template <typename Turns, typename OutputIterator> inline OutputIterator intersection_output_turn_points(Turns const& turns, OutputIterator out) { - for (typename Turns::const_iterator - it = turns.begin(); it != turns.end(); ++it) + for (auto const& turn : turns) { - *out++ = it->point; + *out++ = turn.point; } return out; @@ -1543,7 +1539,7 @@ inline OutputIterator intersection_insert(Geometry1 const& geometry1, < Geometry1, Geometry2 >::type strategy_type; - + return intersection_insert<GeometryOut>(geometry1, geometry2, out, strategy_type()); } diff --git a/boost/geometry/algorithms/detail/overlay/is_self_turn.hpp b/boost/geometry/algorithms/detail/overlay/is_self_turn.hpp index 448c04404f..1606c31e90 100644 --- a/boost/geometry/algorithms/detail/overlay/is_self_turn.hpp +++ b/boost/geometry/algorithms/detail/overlay/is_self_turn.hpp @@ -26,8 +26,7 @@ struct is_self_turn_check template <typename Turn> static inline bool apply(Turn const& turn) { - return turn.operations[0].seg_id.source_index - == turn.operations[1].seg_id.source_index; + return turn.is_self(); } }; diff --git a/boost/geometry/algorithms/detail/overlay/less_by_segment_ratio.hpp b/boost/geometry/algorithms/detail/overlay/less_by_segment_ratio.hpp index 06ce0a7f0d..1ce97d261e 100644 --- a/boost/geometry/algorithms/detail/overlay/less_by_segment_ratio.hpp +++ b/boost/geometry/algorithms/detail/overlay/less_by_segment_ratio.hpp @@ -66,7 +66,7 @@ template typename Indexed, typename Geometry1, typename Geometry2, typename RobustPolicy, - typename SideStrategy, + typename Strategy, bool Reverse1, bool Reverse2 > struct less_by_segment_ratio @@ -75,7 +75,7 @@ struct less_by_segment_ratio , Geometry1 const& geometry1 , Geometry2 const& geometry2 , RobustPolicy const& robust_policy - , SideStrategy const& strategy) + , Strategy const& strategy) : m_turns(turns) , m_geometry1(geometry1) , m_geometry2(geometry2) @@ -90,7 +90,7 @@ private : Geometry1 const& m_geometry1; Geometry2 const& m_geometry2; RobustPolicy const& m_robust_policy; - SideStrategy const& m_strategy; + Strategy const& m_strategy; typedef typename geometry::point_type<Geometry1>::type point_type; @@ -115,8 +115,9 @@ private : *right.other_seg_id, si, sj); - int const side_rj_p = m_strategy.apply(pi, pj, rj); - int const side_sj_p = m_strategy.apply(pi, pj, sj); + auto side_strategy = m_strategy.side(); + int const side_rj_p = side_strategy.apply(pi, pj, rj); + int const side_sj_p = side_strategy.apply(pi, pj, sj); // Put the one turning left (1; right == -1) as last if (side_rj_p != side_sj_p) @@ -124,8 +125,8 @@ private : return side_rj_p < side_sj_p; } - int const side_sj_r = m_strategy.apply(ri, rj, sj); - int const side_rj_s = m_strategy.apply(si, sj, rj); + int const side_sj_r = side_strategy.apply(ri, rj, sj); + int const side_rj_s = side_strategy.apply(si, sj, rj); // If they both turn left: the most left as last // If they both turn right: this is not relevant, but take also here most left @@ -156,10 +157,8 @@ public : return left.subject->fraction < right.subject->fraction; } - - typedef typename boost::range_value<Turns>::type turn_type; - turn_type const& left_turn = m_turns[left.turn_index]; - turn_type const& right_turn = m_turns[right.turn_index]; + auto const& left_turn = m_turns[left.turn_index]; + auto const& right_turn = m_turns[right.turn_index]; // First check "real" intersection (crosses) // -> distance zero due to precision, solve it by sorting diff --git a/boost/geometry/algorithms/detail/overlay/linear_linear.hpp b/boost/geometry/algorithms/detail/overlay/linear_linear.hpp index f5d5f7bf4d..f67a06b0bb 100644 --- a/boost/geometry/algorithms/detail/overlay/linear_linear.hpp +++ b/boost/geometry/algorithms/detail/overlay/linear_linear.hpp @@ -1,6 +1,6 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014-2020, Oracle and/or its affiliates. +// Copyright (c) 2014-2022, 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 @@ -30,7 +30,7 @@ #include <boost/geometry/algorithms/convert.hpp> - +#include <boost/geometry/geometries/helper_geometry.hpp> namespace boost { namespace geometry { @@ -82,9 +82,7 @@ struct linear_linear_no_intersections static inline OutputIterator apply(MultiLineString const& multilinestring, OutputIterator oit) { - for (typename boost::range_iterator<MultiLineString const>::type - it = boost::begin(multilinestring); - it != boost::end(multilinestring); ++it) + for (auto it = boost::begin(multilinestring); it != boost::end(multilinestring); ++it) { LineStringOut ls_out; geometry::convert(*it, ls_out); @@ -206,7 +204,7 @@ protected: turns::remove_duplicate_turns < Turns, EnableRemoveDuplicateTurns - >::apply(turns); + >::apply(turns, strategy); return detail::overlay::following::linear::follow < diff --git a/boost/geometry/algorithms/detail/overlay/overlay.hpp b/boost/geometry/algorithms/detail/overlay/overlay.hpp index 7d960987d4..e0451f9dd6 100644 --- a/boost/geometry/algorithms/detail/overlay/overlay.hpp +++ b/boost/geometry/algorithms/detail/overlay/overlay.hpp @@ -103,10 +103,6 @@ template > inline void get_ring_turn_info(TurnInfoMap& turn_info_map, Turns const& turns, Clusters const& clusters) { - typedef typename boost::range_value<Turns>::type turn_type; - typedef typename turn_type::turn_operation_type turn_operation_type; - typedef typename turn_type::container_type container_type; - static const operation_type target_operation = operation_from_overlay<OverlayType>::value; static const operation_type opposite_operation @@ -114,13 +110,8 @@ inline void get_ring_turn_info(TurnInfoMap& turn_info_map, Turns const& turns, C ? operation_intersection : operation_union; - for (typename boost::range_iterator<Turns const>::type - it = boost::begin(turns); - it != boost::end(turns); - ++it) + for (auto const& turn : turns) { - turn_type const& turn = *it; - bool cluster_checked = false; bool has_blocked = false; @@ -130,12 +121,8 @@ inline void get_ring_turn_info(TurnInfoMap& turn_info_map, Turns const& turns, C continue; } - for (typename boost::range_iterator<container_type const>::type - op_it = boost::begin(turn.operations); - op_it != boost::end(turn.operations); - ++op_it) + for (auto const& op : turn.operations) { - turn_operation_type const& op = *op_it; ring_identifier const ring_id = ring_id_by_seg_id(op.seg_id); if (! is_self_turn<OverlayType>(turn) @@ -369,12 +356,9 @@ std::cout << "traverse" << std::endl; // Add rings created during traversal { ring_identifier id(2, 0, -1); - for (typename boost::range_iterator<ring_container_type>::type - it = boost::begin(rings); - it != boost::end(rings); - ++it) + for (auto const& ring : rings) { - selected_ring_properties[id] = properties(*it, strategy); + selected_ring_properties[id] = properties(ring, strategy); selected_ring_properties[id].reversed = ReverseOut; id.multi_index++; } @@ -392,15 +376,18 @@ std::cout << "traverse" << std::endl; // it can be returned or an exception can be thrown. return add_rings<GeometryOut>(selected_ring_properties, geometry1, geometry2, rings, out, strategy, - OverlayType == overlay_union ? #if defined(BOOST_GEOMETRY_UNION_THROW_INVALID_OUTPUT_EXCEPTION) + OverlayType == overlay_union ? add_rings_throw_if_reversed + : add_rings_ignore_unordered #elif defined(BOOST_GEOMETRY_UNION_RETURN_INVALID) + OverlayType == overlay_union ? add_rings_add_unordered + : add_rings_ignore_unordered #else add_rings_ignore_unordered #endif - : add_rings_ignore_unordered); + ); } template <typename RobustPolicy, typename OutputIterator, typename Strategy> diff --git a/boost/geometry/algorithms/detail/overlay/pointlike_areal.hpp b/boost/geometry/algorithms/detail/overlay/pointlike_areal.hpp index 8b62b0752b..503d656478 100644 --- a/boost/geometry/algorithms/detail/overlay/pointlike_areal.hpp +++ b/boost/geometry/algorithms/detail/overlay/pointlike_areal.hpp @@ -157,7 +157,7 @@ private: private: MultiPolygon const& m_multipolygon; - OutputIterator& m_oit; + OutputIterator& m_oit; Strategy const& m_strategy; }; diff --git a/boost/geometry/algorithms/detail/overlay/pointlike_linear.hpp b/boost/geometry/algorithms/detail/overlay/pointlike_linear.hpp index bbf62b3633..19045b250a 100644 --- a/boost/geometry/algorithms/detail/overlay/pointlike_linear.hpp +++ b/boost/geometry/algorithms/detail/overlay/pointlike_linear.hpp @@ -98,10 +98,7 @@ struct multipoint_single_point OutputIterator oit, Strategy const& strategy) { - for (typename boost::range_iterator<MultiPoint const>::type - it = boost::begin(multipoint); - it != boost::end(multipoint); - ++it) + for (auto it = boost::begin(multipoint); it != boost::end(multipoint); ++it) { action_selector_pl < diff --git a/boost/geometry/algorithms/detail/overlay/pointlike_pointlike.hpp b/boost/geometry/algorithms/detail/overlay/pointlike_pointlike.hpp index a46fc8b5f7..4ad311277a 100644 --- a/boost/geometry/algorithms/detail/overlay/pointlike_pointlike.hpp +++ b/boost/geometry/algorithms/detail/overlay/pointlike_pointlike.hpp @@ -1,7 +1,10 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014-2020, Oracle and/or its affiliates. +// Copyright (c) 2023 Adam Wulkiewicz, Lodz, Poland. +// Copyright (c) 2014-2023, 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 @@ -33,6 +36,8 @@ #include <boost/geometry/policies/compare.hpp> +#include <boost/geometry/util/condition.hpp> + namespace boost { namespace geometry { @@ -75,9 +80,7 @@ struct copy_points<PointOut, MultiPointIn, multi_point_tag> static inline void apply(MultiPointIn const& multi_point_in, OutputIterator& oit) { - for (typename boost::range_iterator<MultiPointIn const>::type - it = boost::begin(multi_point_in); - it != boost::end(multi_point_in); ++it) + for (auto it = boost::begin(multi_point_in); it != boost::end(multi_point_in); ++it) { PointOut point_out; geometry::convert(*it, point_out); @@ -189,9 +192,7 @@ struct multipoint_point_point { BOOST_GEOMETRY_ASSERT( OverlayType == overlay_difference ); - for (typename boost::range_iterator<MultiPoint const>::type - it = boost::begin(multipoint); - it != boost::end(multipoint); ++it) + for (auto it = boost::begin(multipoint); it != boost::end(multipoint); ++it) { action_selector_pl < @@ -225,9 +226,7 @@ struct point_multipoint_point { typedef action_selector_pl<PointOut, OverlayType> action; - for (typename boost::range_iterator<MultiPoint const>::type - it = boost::begin(multipoint); - it != boost::end(multipoint); ++it) + for (auto it = boost::begin(multipoint); it != boost::end(multipoint); ++it) { if ( detail::equals::equals_point_point(*it, point, strategy) ) { @@ -260,10 +259,10 @@ struct multipoint_multipoint_point OutputIterator oit, Strategy const& strategy) { - typedef geometry::less<void, -1, typename Strategy::cs_tag> less_type; + typedef geometry::less<void, -1, Strategy> less_type; - if ( OverlayType != overlay_difference - && boost::size(multipoint1) > boost::size(multipoint2) ) + if (BOOST_GEOMETRY_CONDITION(OverlayType != overlay_difference) + && boost::size(multipoint1) > boost::size(multipoint2)) { return multipoint_multipoint_point < @@ -279,9 +278,7 @@ struct multipoint_multipoint_point less_type const less = less_type(); std::sort(points2.begin(), points2.end(), less); - for (typename boost::range_iterator<MultiPoint1 const>::type - it1 = boost::begin(multipoint1); - it1 != boost::end(multipoint1); ++it1) + for (auto it1 = boost::begin(multipoint1); it1 != boost::end(multipoint1); ++it1) { bool found = std::binary_search(points2.begin(), points2.end(), *it1, less); diff --git a/boost/geometry/algorithms/detail/overlay/range_in_geometry.hpp b/boost/geometry/algorithms/detail/overlay/range_in_geometry.hpp index 6f49f5168d..e41ee8238c 100644 --- a/boost/geometry/algorithms/detail/overlay/range_in_geometry.hpp +++ b/boost/geometry/algorithms/detail/overlay/range_in_geometry.hpp @@ -1,6 +1,6 @@ // Boost.Geometry -// Copyright (c) 2017-2020 Oracle and/or its affiliates. +// Copyright (c) 2017-2022 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, @@ -12,7 +12,7 @@ #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_RANGE_IN_GEOMETRY_HPP -#include <boost/geometry/algorithms/covered_by.hpp> +#include <boost/geometry/algorithms/detail/covered_by/implementation.hpp> #include <boost/geometry/core/access.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/iterators/point_iterator.hpp> @@ -154,7 +154,7 @@ inline int range_in_geometry(Point1 const& first_point1, // check points of geometry1 until point inside/outside is found // NOTE: skip first point because it should be already tested above result = range_in_geometry(geometry1, geometry2, strategy, true); - } + } return result; } diff --git a/boost/geometry/algorithms/detail/overlay/ring_properties.hpp b/boost/geometry/algorithms/detail/overlay/ring_properties.hpp index c5341832bc..4039891f74 100644 --- a/boost/geometry/algorithms/detail/overlay/ring_properties.hpp +++ b/boost/geometry/algorithms/detail/overlay/ring_properties.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-2022. +// Modifications copyright (c) 2017-2022 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, @@ -15,8 +15,8 @@ #include <boost/geometry/algorithms/area.hpp> -#include <boost/geometry/algorithms/within.hpp> #include <boost/geometry/algorithms/detail/point_on_border.hpp> +#include <boost/geometry/algorithms/detail/within/implementation.hpp> namespace boost { namespace geometry diff --git a/boost/geometry/algorithms/detail/overlay/select_rings.hpp b/boost/geometry/algorithms/detail/overlay/select_rings.hpp index 1f43133367..58371606e2 100644 --- a/boost/geometry/algorithms/detail/overlay/select_rings.hpp +++ b/boost/geometry/algorithms/detail/overlay/select_rings.hpp @@ -3,8 +3,8 @@ // Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland. -// This file was modified by Oracle on 2017-2021. -// Modifications copyright (c) 2017-2021 Oracle and/or its affiliates. +// This file was modified by Oracle on 2017-2022. +// Modifications copyright (c) 2017-2022 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, @@ -23,12 +23,11 @@ #include <boost/geometry/core/tags.hpp> -#include <boost/geometry/algorithms/covered_by.hpp> -#include <boost/geometry/algorithms/detail/interior_iterator.hpp> -#include <boost/geometry/algorithms/detail/ring_identifier.hpp> +#include <boost/geometry/algorithms/detail/covered_by/implementation.hpp> #include <boost/geometry/algorithms/detail/overlay/range_in_geometry.hpp> #include <boost/geometry/algorithms/detail/overlay/ring_properties.hpp> #include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp> +#include <boost/geometry/algorithms/detail/ring_identifier.hpp> namespace boost { namespace geometry @@ -119,10 +118,8 @@ namespace dispatch per_ring::apply(exterior_ring(polygon), geometry, id, ring_properties, strategy); - typename interior_return_type<Polygon const>::type - rings = interior_rings(polygon); - for (typename detail::interior_iterator<Polygon const>::type - it = boost::begin(rings); it != boost::end(rings); ++it) + auto const& rings = interior_rings(polygon); + for (auto it = boost::begin(rings); it != boost::end(rings); ++it) { id.ring_index++; per_ring::apply(*it, geometry, id, ring_properties, strategy); @@ -139,10 +136,8 @@ namespace dispatch per_ring::apply(exterior_ring(polygon), id, ring_properties, strategy); - typename interior_return_type<Polygon const>::type - rings = interior_rings(polygon); - for (typename detail::interior_iterator<Polygon const>::type - it = boost::begin(rings); it != boost::end(rings); ++it) + auto const& rings = interior_rings(polygon); + for (auto it = boost::begin(rings); it != boost::end(rings); ++it) { id.ring_index++; per_ring::apply(*it, id, ring_properties, strategy); @@ -158,15 +153,10 @@ namespace dispatch ring_identifier id, RingPropertyMap& ring_properties, Strategy const& strategy) { - typedef typename boost::range_iterator - < - Multi const - >::type iterator_type; - typedef select_rings<polygon_tag, typename boost::range_value<Multi>::type> per_polygon; id.multi_index = 0; - for (iterator_type it = boost::begin(multi); it != boost::end(multi); ++it) + for (auto it = boost::begin(multi); it != boost::end(multi); ++it) { id.ring_index = -1; per_polygon::apply(*it, geometry, id, ring_properties, strategy); @@ -254,15 +244,13 @@ inline void update_ring_selection(Geometry1 const& geometry1, { selected_ring_properties.clear(); - for (typename RingPropertyMap::const_iterator it = boost::begin(all_ring_properties); - it != boost::end(all_ring_properties); - ++it) + for (auto const& pair : all_ring_properties) { - ring_identifier const& id = it->first; + ring_identifier const& id = pair.first; ring_turn_info info; - typename TurnInfoMap::const_iterator tcit = turn_info_map.find(id); + auto tcit = turn_info_map.find(id); if (tcit != turn_info_map.end()) { info = tcit->second; // Copy by value @@ -281,12 +269,12 @@ inline void update_ring_selection(Geometry1 const& geometry1, { // within case 0 : - info.within_other = range_in_geometry(it->second.point, + info.within_other = range_in_geometry(pair.second.point, geometry1, geometry2, strategy) > 0; break; case 1 : - info.within_other = range_in_geometry(it->second.point, + info.within_other = range_in_geometry(pair.second.point, geometry2, geometry1, strategy) > 0; break; @@ -294,7 +282,7 @@ inline void update_ring_selection(Geometry1 const& geometry1, if (decide<OverlayType>::include(id, info)) { - typename RingPropertyMap::mapped_type properties = it->second; // Copy by value + auto properties = pair.second; // Copy by value properties.reversed = decide<OverlayType>::reversed(id, info); selected_ring_properties[id] = properties; } @@ -321,7 +309,7 @@ inline void select_rings(Geometry1 const& geometry1, Geometry2 const& geometry2, { typedef typename geometry::tag<Geometry1>::type tag1; typedef typename geometry::tag<Geometry2>::type tag2; - + RingPropertyMap all_ring_properties; dispatch::select_rings<tag1, Geometry1>::apply(geometry1, geometry2, ring_identifier(0, -1, -1), all_ring_properties, diff --git a/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp b/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp index 0845390a90..20369fa95a 100644 --- a/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp +++ b/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp @@ -3,9 +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-2020. -// Modifications copyright (c) 2017-2020 Oracle and/or its affiliates. - +// This file was modified by Oracle on 2017-2021. +// Modifications copyright (c) 2017-2021 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, @@ -33,6 +32,9 @@ #include <boost/geometry/geometries/box.hpp> #include <boost/geometry/geometries/concepts/check.hpp> +#include <boost/geometry/strategies/detail.hpp> +#include <boost/geometry/strategies/relate/services.hpp> + #include <boost/geometry/util/condition.hpp> @@ -271,24 +273,103 @@ struct self_get_turn_points #endif // DOXYGEN_NO_DISPATCH +namespace resolve_strategy +{ + +template +< + bool Reverse, + typename AssignPolicy, + typename Strategies, + bool IsUmbrella = strategies::detail::is_umbrella_strategy<Strategies>::value +> +struct self_get_turn_points +{ + template + < + typename Geometry, + typename RobustPolicy, + typename Turns, + typename InterruptPolicy + > + static inline void apply(Geometry const& geometry, + Strategies const& strategies, + RobustPolicy const& robust_policy, + Turns& turns, + InterruptPolicy& interrupt_policy, + int source_index, + bool skip_adjacent) + { + using turn_policy = detail::overlay::get_turn_info<AssignPolicy>; + + dispatch::self_get_turn_points + < + Reverse, + typename tag<Geometry>::type, + Geometry, + turn_policy + >::apply(geometry, strategies, robust_policy, turns, interrupt_policy, + source_index, skip_adjacent); + } +}; + +template <bool Reverse, typename AssignPolicy, typename Strategy> +struct self_get_turn_points<Reverse, AssignPolicy, Strategy, false> +{ + template + < + typename Geometry, + typename RobustPolicy, + typename Turns, + typename InterruptPolicy + > + static inline void apply(Geometry const& geometry, + Strategy const& strategy, + RobustPolicy const& robust_policy, + Turns& turns, + InterruptPolicy& interrupt_policy, + int source_index, + bool skip_adjacent) + { + using strategies::relate::services::strategy_converter; + + self_get_turn_points + < + Reverse, + AssignPolicy, + decltype(strategy_converter<Strategy>::get(strategy)) + >::apply(geometry, + strategy_converter<Strategy>::get(strategy), + robust_policy, + turns, + interrupt_policy, + source_index, + skip_adjacent); + } +}; + + +} // namespace resolve_strategy + + #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace self_get_turn_points { -// Version where Reverse can be specified manually. TODO: +// Version where Reverse can be specified manually. TODO: // can most probably be merged with self_get_turn_points::get_turn template < bool Reverse, typename AssignPolicy, typename Geometry, - typename IntersectionStrategy, + typename Strategy, typename RobustPolicy, typename Turns, typename InterruptPolicy > inline void self_turns(Geometry const& geometry, - IntersectionStrategy const& strategy, + Strategy const& strategy, RobustPolicy const& robust_policy, Turns& turns, InterruptPolicy& interrupt_policy, @@ -297,14 +378,9 @@ inline void self_turns(Geometry const& geometry, { concepts::check<Geometry const>(); - typedef detail::overlay::get_turn_info<detail::overlay::assign_null_policy> turn_policy; - - dispatch::self_get_turn_points + resolve_strategy::self_get_turn_points < - Reverse, - typename tag<Geometry>::type, - Geometry, - turn_policy + Reverse, AssignPolicy, Strategy >::apply(geometry, strategy, robust_policy, turns, interrupt_policy, source_index, skip_adjacent); } @@ -351,12 +427,11 @@ inline void self_turns(Geometry const& geometry, geometry::point_order<Geometry>::value >::value; - detail::self_get_turn_points::self_turns + resolve_strategy::self_get_turn_points < - reverse, - AssignPolicy - >(geometry, strategy, robust_policy, turns, interrupt_policy, - source_index, skip_adjacent); + reverse, AssignPolicy, Strategy + >::apply(geometry, strategy, robust_policy, turns, interrupt_policy, + source_index, skip_adjacent); } diff --git a/boost/geometry/algorithms/detail/overlay/sort_by_side.hpp b/boost/geometry/algorithms/detail/overlay/sort_by_side.hpp index 49e6761860..503b36720a 100644 --- a/boost/geometry/algorithms/detail/overlay/sort_by_side.hpp +++ b/boost/geometry/algorithms/detail/overlay/sort_by_side.hpp @@ -3,9 +3,10 @@ // Copyright (c) 2015 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland. -// This file was modified by Oracle on 2017, 2019. -// Modifications copyright (c) 2017, 2019 Oracle and/or its affiliates. +// This file was modified by Oracle on 2017-2023. +// Modifications copyright (c) 2017-2023 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, @@ -17,6 +18,7 @@ #include <algorithm> #include <map> +#include <set> #include <vector> #include <boost/geometry/algorithms/detail/overlay/approximately_equals.hpp> @@ -127,10 +129,10 @@ struct less_false } }; -template <typename Point, typename SideStrategy, typename LessOnSame, typename Compare> +template <typename PointOrigin, typename PointTurn, typename SideStrategy, typename LessOnSame, typename Compare> struct less_by_side { - less_by_side(const Point& p1, const Point& p2, SideStrategy const& strategy) + less_by_side(const PointOrigin& p1, const PointTurn& p2, SideStrategy const& strategy) : m_origin(p1) , m_turn_point(p2) , m_strategy(strategy) @@ -209,8 +211,8 @@ struct less_by_side } private : - Point const& m_origin; - Point const& m_turn_point; + PointOrigin const& m_origin; + PointTurn const& m_turn_point; SideStrategy const& m_strategy; }; @@ -316,7 +318,15 @@ public : // then take a point (or more) further back. // The limit of offset avoids theoretical infinite loops. // In practice it currently walks max 1 point back in all cases. - double const tolerance = 1.0e9; + // Use the coordinate type, but if it is too small (e.g. std::int16), use a double + using ct_type = typename geometry::select_most_precise + < + typename geometry::coordinate_type<Point>::type, + double + >::type; + + ct_type const tolerance = 1000000000; + int offset = 0; while (approximately_equals(point_from, turn.point, tolerance) && offset > -10) @@ -371,7 +381,8 @@ public : } } - void apply(Point const& turn_point) + template <typename PointTurn> + void apply(PointTurn const& turn_point) { // We need three compare functors: // 1) to order clockwise (union) or counter clockwise (intersection) @@ -380,8 +391,8 @@ public : // to give colinear points // Sort by side and assign rank - less_by_side<Point, SideStrategy, less_by_index, Compare> less_unique(m_origin, turn_point, m_strategy); - less_by_side<Point, SideStrategy, less_false, Compare> less_non_unique(m_origin, turn_point, m_strategy); + less_by_side<Point, PointTurn, SideStrategy, less_by_index, Compare> less_unique(m_origin, turn_point, m_strategy); + less_by_side<Point, PointTurn, SideStrategy, less_false, Compare> less_non_unique(m_origin, turn_point, m_strategy); std::sort(m_ranked_points.begin(), m_ranked_points.end(), less_unique); @@ -467,7 +478,7 @@ public : // Move iterator after rank==0 bool has_first = false; - typename container_type::iterator it = m_ranked_points.begin() + 1; + auto it = m_ranked_points.begin() + 1; for (; it != m_ranked_points.end() && it->rank == 0; ++it) { has_first = true; @@ -478,8 +489,7 @@ public : // Reverse first part (having rank == 0), if any, // but skip the very first row std::reverse(m_ranked_points.begin() + 1, it); - for (typename container_type::iterator fit = m_ranked_points.begin(); - fit != it; ++fit) + for (auto fit = m_ranked_points.begin(); fit != it; ++fit) { BOOST_ASSERT(fit->rank == 0); } diff --git a/boost/geometry/algorithms/detail/overlay/traversal.hpp b/boost/geometry/algorithms/detail/overlay/traversal.hpp index a0149789c6..22ae1a2de8 100644 --- a/boost/geometry/algorithms/detail/overlay/traversal.hpp +++ b/boost/geometry/algorithms/detail/overlay/traversal.hpp @@ -123,12 +123,8 @@ public : template <typename TurnInfoMap> inline void finalize_visit_info(TurnInfoMap& turn_info_map) { - for (typename boost::range_iterator<Turns>::type - it = boost::begin(m_turns); - it != boost::end(m_turns); - ++it) + for (auto& turn : m_turns) { - turn_type& turn = *it; for (int i = 0; i < 2; i++) { turn_operation_type& op = turn.operations[i]; @@ -158,23 +154,18 @@ public : inline void set_visited_in_cluster(signed_size_type cluster_id, signed_size_type rank) { - typename Clusters::const_iterator mit = m_clusters.find(cluster_id); + auto mit = m_clusters.find(cluster_id); BOOST_ASSERT(mit != m_clusters.end()); cluster_info const& cinfo = mit->second; - std::set<signed_size_type> const& ids = cinfo.turn_indices; - for (typename std::set<signed_size_type>::const_iterator it = ids.begin(); - it != ids.end(); ++it) + for (auto turn_index : cinfo.turn_indices) { - signed_size_type const turn_index = *it; turn_type& turn = m_turns[turn_index]; - for (int i = 0; i < 2; i++) + for (auto& op : turn.operations) { - turn_operation_type& op = turn.operations[i]; - if (op.visited.none() - && op.enriched.rank == rank) + if (op.visited.none() && op.enriched.rank == rank) { op.visited.set_visited(); } @@ -621,31 +612,32 @@ public : return m_turns[rp.turn_index].operations[rp.operation_index]; } - inline sort_by_side::rank_type select_rank(sbs_type const& sbs, - bool skip_isolated) const + inline sort_by_side::rank_type select_rank(sbs_type const& sbs) const { + static bool const is_intersection + = target_operation == operation_intersection; + // Take the first outgoing rank corresponding to incoming region, // or take another region if it is not isolated - turn_operation_type const& incoming_op - = operation_from_rank(sbs.m_ranked_points.front()); + auto const& in_op = operation_from_rank(sbs.m_ranked_points.front()); for (std::size_t i = 0; i < sbs.m_ranked_points.size(); i++) { - typename sbs_type::rp const& rp = sbs.m_ranked_points[i]; + auto const& rp = sbs.m_ranked_points[i]; if (rp.rank == 0 || rp.direction == sort_by_side::dir_from) { continue; } - turn_operation_type const& op = operation_from_rank(rp); + auto const& out_op = operation_from_rank(rp); - if (op.operation != target_operation - && op.operation != operation_continue) + if (out_op.operation != target_operation + && out_op.operation != operation_continue) { continue; } - if (op.enriched.region_id == incoming_op.enriched.region_id - || (skip_isolated && ! op.enriched.isolated)) + if (in_op.enriched.region_id == out_op.enriched.region_id + || (is_intersection && ! out_op.enriched.isolated)) { // Region corresponds to incoming region, or (for intersection) // there is a non-isolated other region which should be taken @@ -660,7 +652,7 @@ public : int& op_index, sbs_type const& sbs, signed_size_type start_turn_index, int start_op_index) const { - sort_by_side::rank_type const selected_rank = select_rank(sbs, false); + sort_by_side::rank_type const selected_rank = select_rank(sbs); int current_priority = 0; for (std::size_t i = 1; i < sbs.m_ranked_points.size(); i++) @@ -688,49 +680,59 @@ public : inline bool analyze_cluster_intersection(signed_size_type& turn_index, int& op_index, sbs_type const& sbs) const { - sort_by_side::rank_type const selected_rank = select_rank(sbs, true); + // Select the rank based on regions and isolation + sort_by_side::rank_type const selected_rank = select_rank(sbs); - if (selected_rank > 0) + if (selected_rank <= 0) { - typename turn_operation_type::comparable_distance_type - min_remaining_distance = 0; + return false; + } - std::size_t selected_index = sbs.m_ranked_points.size(); - for (std::size_t i = 0; i < sbs.m_ranked_points.size(); i++) + // From these ranks, select the index: the first, or the one with + // the smallest remaining distance + typename turn_operation_type::comparable_distance_type + min_remaining_distance = 0; + + std::size_t selected_index = sbs.m_ranked_points.size(); + for (std::size_t i = 0; i < sbs.m_ranked_points.size(); i++) + { + auto const& ranked_point = sbs.m_ranked_points[i]; + + if (ranked_point.rank > selected_rank) { - typename sbs_type::rp const& ranked_point = sbs.m_ranked_points[i]; + break; + } + else if (ranked_point.rank == selected_rank) + { + auto const& op = operation_from_rank(ranked_point); - if (ranked_point.rank == selected_rank) + if (op.visited.finalized()) { - turn_operation_type const& op = operation_from_rank(ranked_point); - - if (op.visited.finalized()) - { - // This direction is already traveled before, the same - // cannot be traveled again - continue; - } - - // Take turn with the smallest remaining distance - if (selected_index == sbs.m_ranked_points.size() - || op.remaining_distance < min_remaining_distance) - { - selected_index = i; - min_remaining_distance = op.remaining_distance; - } + // This direction is already traveled, + // it cannot be traveled again + continue; } - } - if (selected_index < sbs.m_ranked_points.size()) - { - typename sbs_type::rp const& ranked_point = sbs.m_ranked_points[selected_index]; - turn_index = ranked_point.turn_index; - op_index = ranked_point.operation_index; - return true; + if (selected_index == sbs.m_ranked_points.size() + || op.remaining_distance < min_remaining_distance) + { + // It was unassigned or it is better + selected_index = i; + min_remaining_distance = op.remaining_distance; + } } } - return false; + if (selected_index == sbs.m_ranked_points.size()) + { + // Should not happen, there must be points with the selected rank + return false; + } + + auto const& ranked_point = sbs.m_ranked_points[selected_index]; + turn_index = ranked_point.turn_index; + op_index = ranked_point.operation_index; + return true; } inline bool fill_sbs(sbs_type& sbs, @@ -778,21 +780,19 @@ public : turn_type const& turn = m_turns[turn_index]; BOOST_ASSERT(turn.is_clustered()); - typename Clusters::const_iterator mit = m_clusters.find(turn.cluster_id); + auto 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& cluster_indices = cinfo.turn_indices; sbs_type sbs(m_strategy); - - if (! fill_sbs(sbs, turn_index, cluster_indices, previous_seg_id)) + if (! fill_sbs(sbs, turn_index, cinfo.turn_indices, previous_seg_id)) { return false; } - cluster_exits<OverlayType, Turns, sbs_type> exits(m_turns, cluster_indices, sbs); + cluster_exits<OverlayType, Turns, sbs_type> exits(m_turns, cinfo.turn_indices, sbs); if (exits.apply(turn_index, op_index)) { @@ -803,7 +803,7 @@ public : if (is_union) { - result = select_from_cluster_union(turn_index, cluster_indices, + result = select_from_cluster_union(turn_index, cinfo.turn_indices, op_index, sbs, start_turn_index, start_op_index); if (! result) @@ -819,6 +819,7 @@ public : return result; } + // Analyzes a non-clustered "ii" intersection, as if it is clustered. inline bool analyze_ii_intersection(signed_size_type& turn_index, int& op_index, turn_type const& current_turn, segment_identifier const& previous_seg_id) @@ -956,31 +957,43 @@ public : { turn_type const& current_turn = m_turns[turn_index]; + bool const back_at_start_cluster + = has_points + && current_turn.is_clustered() + && m_turns[start_turn_index].cluster_id == current_turn.cluster_id; if (BOOST_GEOMETRY_CONDITION(target_operation == operation_intersection)) { - if (has_points) - { - bool const back_at_start_cluster - = current_turn.is_clustered() - && m_turns[start_turn_index].cluster_id == current_turn.cluster_id; + // Intersection or difference - if (turn_index == start_turn_index || back_at_start_cluster) - { - // Intersection can always be finished if returning - turn_index = start_turn_index; - op_index = start_op_index; - return true; - } + if (has_points && (turn_index == start_turn_index || back_at_start_cluster)) + { + // Intersection can always be finished if returning + turn_index = start_turn_index; + op_index = start_op_index; + return true; } if (! current_turn.is_clustered() - && current_turn.both(operation_intersection)) - { - if (analyze_ii_intersection(turn_index, op_index, + && current_turn.both(operation_intersection) + && analyze_ii_intersection(turn_index, op_index, current_turn, previous_seg_id)) - { - return true; - } + { + return true; + } + } + else if (turn_index == start_turn_index || back_at_start_cluster) + { + // Union or buffer: cannot return immediately to starting turn, because it then + // might miss a formed multi polygon with a touching point. + auto const& current_op = current_turn.operations[op_index]; + signed_size_type const next_turn_index = current_op.enriched.get_next_turn_index(); + bool const to_other_turn = next_turn_index >= 0 && m_turns[next_turn_index].cluster_id != current_turn.cluster_id; + if (! to_other_turn) + { + // Return to starting point + turn_index = start_turn_index; + op_index = start_op_index; + return true; } } diff --git a/boost/geometry/algorithms/detail/overlay/traversal_switch_detector.hpp b/boost/geometry/algorithms/detail/overlay/traversal_switch_detector.hpp index ad248826dd..be0f2bcd87 100644 --- a/boost/geometry/algorithms/detail/overlay/traversal_switch_detector.hpp +++ b/boost/geometry/algorithms/detail/overlay/traversal_switch_detector.hpp @@ -89,7 +89,6 @@ struct traversal_switch_detector enum isolation_type { - isolation_unknown = -1, isolation_no = 0, isolation_yes = 1, isolation_multiple = 2 @@ -121,7 +120,7 @@ struct traversal_switch_detector struct region_properties { signed_size_type region_id = -1; - isolation_type isolated = isolation_unknown; + isolation_type isolated = isolation_no; set_type unique_turn_ids; connection_map connected_region_counts; }; @@ -374,7 +373,7 @@ struct traversal_switch_detector { region_properties& properties = key_val.second; - if (properties.isolated == isolation_unknown + if (properties.isolated == isolation_no && has_only_isolated_children(properties)) { properties.isolated = isolation_yes; @@ -388,13 +387,36 @@ struct traversal_switch_detector { for (turn_type& turn : m_turns) { + // For difference, for the input walked through in reverse, + // the meaning is reversed: what is isolated is actually not, + // and vice versa. + bool const reverseMeaningInTurn + = (Reverse1 || Reverse2) + && ! turn.is_self() + && ! turn.is_clustered() + && uu_or_ii(turn) + && turn.operations[0].enriched.region_id + != turn.operations[1].enriched.region_id; + for (auto& op : turn.operations) { auto mit = m_connected_regions.find(op.enriched.region_id); if (mit != m_connected_regions.end()) { + bool const reverseMeaningInOp + = reverseMeaningInTurn + && ((op.seg_id.source_index == 0 && Reverse1) + || (op.seg_id.source_index == 1 && Reverse2)); + + // It is assigned to isolated if it's property is "Yes", + // (one connected interior, or chained). + // "Multiple" doesn't count for isolation, + // neither for intersection, neither for difference. region_properties const& prop = mit->second; - op.enriched.isolated = prop.isolated == isolation_yes; + op.enriched.isolated + = reverseMeaningInOp + ? false + : prop.isolated == isolation_yes; } } } @@ -478,8 +500,12 @@ struct traversal_switch_detector // Discarded turns don't connect rings to the same region // Also xx are not relevant // (otherwise discarded colocated uu turn could make a connection) - return ! turn.discarded - && ! turn.both(operation_blocked); + return ! turn.discarded && ! turn.both(operation_blocked); + } + + inline bool uu_or_ii(turn_type const& turn) const + { + return turn.both(operation_union) || turn.both(operation_intersection); } inline bool connects_same_region(turn_type const& turn) const @@ -492,7 +518,7 @@ struct traversal_switch_detector if (! turn.is_clustered()) { // If it is a uu/ii-turn (non clustered), it is never same region - return ! (turn.both(operation_union) || turn.both(operation_intersection)); + return ! uu_or_ii(turn); } if (BOOST_GEOMETRY_CONDITION(target_operation == operation_union)) @@ -565,10 +591,83 @@ struct traversal_switch_detector } } +#if defined(BOOST_GEOMETRY_DEBUG_TRAVERSAL_SWITCH_DETECTOR) + void debug_show_results() + { + auto isolation_to_string = [](isolation_type const& iso) -> std::string + { + switch(iso) + { + case isolation_no : return "no"; + case isolation_yes : return "yes"; + case isolation_multiple : return "multiple"; + } + return "error"; + }; + auto set_to_string = [](auto const& s) -> std::string + { + std::ostringstream result; + for (auto item : s) { result << " " << item; } + return result.str(); + }; + + for (auto const& kv : m_connected_regions) + { + auto const& prop = kv.second; + + std::ostringstream sub; + sub << "[turns" << set_to_string(prop.unique_turn_ids) + << "] regions"; + for (auto const& kvs : prop.connected_region_counts) + { + sub << " { " << kvs.first + << " : via [" << set_to_string(kvs.second.unique_turn_ids) + << " ] }"; + } + + std::cout << "REGION " << prop.region_id + << " " << isolation_to_string(prop.isolated) + << " " << sub.str() + << std::endl; + } + + for (std::size_t turn_index = 0; turn_index < m_turns.size(); ++turn_index) + { + turn_type const& turn = m_turns[turn_index]; + + if (uu_or_ii(turn) && ! turn.is_clustered()) + { + std::cout << (turn.both(operation_union) ? "UU" : "II") + << " " << turn_index + << " (" << geometry::get<0>(turn.point) + << ", " << geometry::get<1>(turn.point) << ")" + << " -> " << std::boolalpha + << " [" << turn.operations[0].seg_id.source_index + << "/" << turn.operations[1].seg_id.source_index << "] " + << "(" << turn.operations[0].enriched.region_id + << " " << turn.operations[0].enriched.isolated + << ") / (" << turn.operations[1].enriched.region_id + << " " << turn.operations[1].enriched.isolated << ")" + << std::endl; + } + } + + for (auto const& key_val : m_clusters) + { + cluster_info const& cinfo = key_val.second; + std::cout << "CL RESULT " << key_val.first + << " -> " << cinfo.open_count << std::endl; + } + } +#endif + void iterate() { #if defined(BOOST_GEOMETRY_DEBUG_TRAVERSAL_SWITCH_DETECTOR) - std::cout << "BEGIN SWITCH DETECTOR (region_ids and isolation)" << std::endl; + std::cout << "BEGIN SWITCH DETECTOR (region_ids and isolation)" + << (Reverse1 ? " REVERSE_1" : "") + << (Reverse2 ? " REVERSE_2" : "") + << std::endl; #endif // Collect turns per ring @@ -608,33 +707,7 @@ struct traversal_switch_detector #if defined(BOOST_GEOMETRY_DEBUG_TRAVERSAL_SWITCH_DETECTOR) std::cout << "END SWITCH DETECTOR" << std::endl; - - for (std::size_t turn_index = 0; turn_index < m_turns.size(); ++turn_index) - { - turn_type const& turn = m_turns[turn_index]; - - if ((turn.both(operation_union) || turn.both(operation_intersection)) - && ! turn.is_clustered()) - { - std::cout << (turn.both(operation_union) ? "UU" : "II") - << " " << turn_index - << " (" << geometry::get<0>(turn.point) - << ", " << geometry::get<1>(turn.point) << ")" - << " -> " << std::boolalpha - << "(" << turn.operations[0].enriched.region_id - << " " << turn.operations[0].enriched.isolated - << ") / (" << turn.operations[1].enriched.region_id - << " " << turn.operations[1].enriched.isolated << ")" - << std::endl; - } - } - - for (auto const& key_val : m_clusters) - { - cluster_info const& cinfo = key_val.second; - std::cout << "CL RESULT " << key_val.first - << " -> " << cinfo.open_count << std::endl; - } + debug_show_results(); #endif } diff --git a/boost/geometry/algorithms/detail/overlay/traverse.hpp b/boost/geometry/algorithms/detail/overlay/traverse.hpp index b9cbea3127..710cea09e9 100644 --- a/boost/geometry/algorithms/detail/overlay/traverse.hpp +++ b/boost/geometry/algorithms/detail/overlay/traverse.hpp @@ -42,14 +42,11 @@ class traverse template <typename Turns> static void reset_visits(Turns& turns) { - for (typename boost::range_iterator<Turns>::type - it = boost::begin(turns); - it != boost::end(turns); - ++it) + for (auto& turn : turns) { - for (int i = 0; i < 2; i++) + for (auto& op : turn.operations) { - it->operations[i].visited.reset(); + op.visited.reset(); } } } diff --git a/boost/geometry/algorithms/detail/overlay/turn_info.hpp b/boost/geometry/algorithms/detail/overlay/turn_info.hpp index 7dcbf4c8ef..8f1d22c8c0 100644 --- a/boost/geometry/algorithms/detail/overlay/turn_info.hpp +++ b/boost/geometry/algorithms/detail/overlay/turn_info.hpp @@ -1,6 +1,7 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2023 Adam Wulkiewicz, Lodz, Poland. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at @@ -10,7 +11,7 @@ #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TURN_INFO_HPP -#include <boost/array.hpp> +#include <array> #include <boost/geometry/core/coordinate_type.hpp> #include <boost/geometry/algorithms/detail/signed_size_type.hpp> @@ -80,7 +81,7 @@ template typename Point, typename SegmentRatio = geometry::segment_ratio<typename coordinate_type<Point>::type>, typename Operation = turn_operation<Point, SegmentRatio>, - typename Container = boost::array<Operation, 2> + typename Container = std::array<Operation, 2> > struct turn_info { @@ -138,6 +139,11 @@ struct turn_info { return cluster_id > 0; } + inline bool is_self() const + { + return operations[0].seg_id.source_index + == operations[1].seg_id.source_index; + } private : inline bool has12(operation_type type1, operation_type type2) const diff --git a/boost/geometry/algorithms/detail/partition.hpp b/boost/geometry/algorithms/detail/partition.hpp index 2a47eb2b64..e3c4208e3e 100644 --- a/boost/geometry/algorithms/detail/partition.hpp +++ b/boost/geometry/algorithms/detail/partition.hpp @@ -52,20 +52,39 @@ struct divide_interval<T, true> { static inline T apply(T const& mi, T const& ma) { - // avoid overflow + // Avoid overflow return mi / 2 + ma / 2 + (mi % 2 + ma % 2) / 2; } }; -template <int Dimension, typename Box> +struct visit_no_policy +{ + template <typename Box> + static inline void apply(Box const&, std::size_t ) + {} +}; + +struct include_all_policy +{ + template <typename Item> + static inline bool apply(Item const&) + { + return true; + } +}; + + +template <std::size_t Dimension, typename Box> inline void divide_box(Box const& box, Box& lower_box, Box& upper_box) { - typedef typename coordinate_type<Box>::type ctype; + using coor_t = typename coordinate_type<Box>::type; - // Divide input box into two parts, e.g. left/right - ctype mid = divide_interval<ctype>::apply( - geometry::get<min_corner, Dimension>(box), - geometry::get<max_corner, Dimension>(box)); + // Divide input box into two halves + // either left/right (Dimension 0) + // or top/bottom (Dimension 1) + coor_t const mid + = divide_interval<coor_t>::apply(geometry::get<min_corner, Dimension>(box), + geometry::get<max_corner, Dimension>(box)); lower_box = box; upper_box = box; @@ -85,12 +104,7 @@ inline void divide_into_subsets(Box const& lower_box, IteratorVector& exceeding, OverlapsPolicy const& overlaps_policy) { - typedef typename boost::range_iterator - < - IteratorVector const - >::type it_type; - - for(it_type it = boost::begin(input); it != boost::end(input); ++it) + for (auto it = boost::begin(input); it != boost::end(input); ++it) { bool const lower_overlapping = overlaps_policy.apply(lower_box, **it); bool const upper_overlapping = overlaps_policy.apply(upper_box, **it); @@ -124,10 +138,9 @@ template inline void expand_with_elements(Box& total, IteratorVector const& input, ExpandPolicy const& expand_policy) { - typedef typename boost::range_iterator<IteratorVector const>::type it_type; - for(it_type it = boost::begin(input); it != boost::end(input); ++it) + for (auto const& it : input) { - expand_policy.apply(total, **it); + expand_policy.apply(total, *it); } } @@ -141,17 +154,15 @@ inline bool handle_one(IteratorVector const& input, VisitPolicy& visitor) return true; } - typedef typename boost::range_iterator<IteratorVector const>::type it_type; - // Quadratic behaviour at lowest level (lowest quad, or all exceeding) - for (it_type it1 = boost::begin(input); it1 != boost::end(input); ++it1) + for (auto it1 = boost::begin(input); it1 != boost::end(input); ++it1) { - it_type it2 = it1; + auto it2 = it1; for (++it2; it2 != boost::end(input); ++it2) { if (! visitor.apply(**it1, **it2)) { - return false; // interrupt + return false; // Bail out if visitor returns false } } } @@ -170,32 +181,19 @@ inline bool handle_two(IteratorVector1 const& input1, IteratorVector2 const& input2, VisitPolicy& visitor) { - typedef typename boost::range_iterator - < - IteratorVector1 const - >::type iterator_type1; - - typedef typename boost::range_iterator - < - IteratorVector2 const - >::type iterator_type2; if (boost::empty(input1) || boost::empty(input2)) { return true; } - for(iterator_type1 it1 = boost::begin(input1); - it1 != boost::end(input1); - ++it1) + for (auto const& it1 : input1) { - for(iterator_type2 it2 = boost::begin(input2); - it2 != boost::end(input2); - ++it2) + for (auto const& it2 : input2) { - if (! visitor.apply(**it1, **it2)) + if (! visitor.apply(*it1, *it2)) { - return false; // interrupt + return false; // Bail out if visitor returns false } } } @@ -236,11 +234,11 @@ inline bool recurse_ok(IteratorVector1 const& input1, } -template <int Dimension, typename Box> +template <std::size_t Dimension, typename Box> class partition_two_ranges; -template <int Dimension, typename Box> +template <std::size_t Dimension, typename Box> class partition_one_range { template <typename IteratorVector, typename ExpandPolicy> @@ -349,10 +347,10 @@ public : if (! boost::empty(exceeding)) { // Get the box of exceeding-only - Box exceeding_box = get_new_box(exceeding, expand_policy); + Box const exceeding_box = get_new_box(exceeding, expand_policy); - // Recursively do exceeding elements only, in next dimension they - // will probably be less exceeding within the new box + // Recursively do exceeding elements only, in next dimension they + // will probably be less exceeding within the new box if (! (next_level(exceeding_box, exceeding, level, min_elements, visitor, expand_policy, overlaps_policy, box_policy) // Switch to two forward ranges, combine exceeding with @@ -362,7 +360,7 @@ public : && next_level2(exceeding_box, exceeding, upper, level, min_elements, visitor, expand_policy, overlaps_policy, box_policy)) ) { - return false; // interrupt + return false; // Bail out if visitor returns false } } @@ -376,7 +374,7 @@ public : template < - int Dimension, + std::size_t Dimension, typename Box > class partition_two_ranges @@ -480,20 +478,20 @@ public : if (recurse_ok(exceeding1, exceeding2, min_elements, level)) { - Box exceeding_box = get_new_box(exceeding1, exceeding2, - expand_policy1, expand_policy2); + Box const exceeding_box = get_new_box(exceeding1, exceeding2, + expand_policy1, expand_policy2); if (! next_level(exceeding_box, exceeding1, exceeding2, level, min_elements, visitor, expand_policy1, overlaps_policy1, expand_policy2, overlaps_policy2, box_policy)) { - return false; // interrupt + return false; // Bail out if visitor returns false } } else { if (! handle_two(exceeding1, exceeding2, visitor)) { - return false; // interrupt + return false; // Bail out if visitor returns false } } @@ -503,7 +501,7 @@ public : // the same combinations again and again) if (recurse_ok(lower2, upper2, exceeding1, min_elements, level)) { - Box exceeding_box = get_new_box(exceeding1, expand_policy1); + Box const exceeding_box = get_new_box(exceeding1, expand_policy1); if (! (next_level(exceeding_box, exceeding1, lower2, level, min_elements, visitor, expand_policy1, overlaps_policy1, expand_policy2, overlaps_policy2, box_policy) @@ -511,7 +509,7 @@ public : min_elements, visitor, expand_policy1, overlaps_policy1, expand_policy2, overlaps_policy2, box_policy)) ) { - return false; // interrupt + return false; // Bail out if visitor returns false } } else @@ -519,7 +517,7 @@ public : if (! (handle_two(exceeding1, lower2, visitor) && handle_two(exceeding1, upper2, visitor)) ) { - return false; // interrupt + return false; // Bail out if visitor returns false } } } @@ -529,7 +527,7 @@ public : // All exceeding from 2 with lower and upper of 1: if (recurse_ok(lower1, upper1, exceeding2, min_elements, level)) { - Box exceeding_box = get_new_box(exceeding2, expand_policy2); + Box const exceeding_box = get_new_box(exceeding2, expand_policy2); if (! (next_level(exceeding_box, lower1, exceeding2, level, min_elements, visitor, expand_policy1, overlaps_policy1, expand_policy2, overlaps_policy2, box_policy) @@ -537,7 +535,7 @@ public : min_elements, visitor, expand_policy1, overlaps_policy1, expand_policy2, overlaps_policy2, box_policy)) ) { - return false; // interrupt + return false; // Bail out if visitor returns false } } else @@ -545,7 +543,7 @@ public : if (! (handle_two(lower1, exceeding2, visitor) && handle_two(upper1, exceeding2, visitor)) ) { - return false; // interrupt + return false; // Bail out if visitor returns false } } } @@ -556,14 +554,14 @@ public : min_elements, visitor, expand_policy1, overlaps_policy1, expand_policy2, overlaps_policy2, box_policy) ) { - return false; // interrupt + return false; // Bail out if visitor returns false } } else { if (! handle_two(lower1, lower2, visitor)) { - return false; // interrupt + return false; // Bail out if visitor returns false } } @@ -573,14 +571,14 @@ public : min_elements, visitor, expand_policy1, overlaps_policy1, expand_policy2, overlaps_policy2, box_policy) ) { - return false; // interrupt + return false; // Bail out if visitor returns false } } else { if (! handle_two(upper1, upper2, visitor)) { - return false; // interrupt + return false; // Bail out if visitor returns false } } @@ -588,22 +586,6 @@ public : } }; -struct visit_no_policy -{ - template <typename Box> - static inline void apply(Box const&, std::size_t ) - {} -}; - -struct include_all_policy -{ - template <typename Item> - static inline bool apply(Item const&) - { - return true; - } -}; - }} // namespace detail::partition @@ -629,10 +611,7 @@ class partition IteratorVector& iterator_vector, ExpandPolicy const& expand_policy) { - for(typename boost::range_iterator<ForwardRange const>::type - it = boost::begin(forward_range); - it != boost::end(forward_range); - ++it) + for (auto it = boost::begin(forward_range); it != boost::end(forward_range); ++it) { if (IncludePolicy::apply(*it)) { @@ -691,14 +670,14 @@ public: std::size_t min_elements, VisitBoxPolicy box_visitor) { - typedef typename boost::range_iterator + using iterator_t = typename boost::range_iterator < ForwardRange const - >::type iterator_type; + >::type; if (std::size_t(boost::size(forward_range)) > min_elements) { - std::vector<iterator_type> iterator_vector; + std::vector<iterator_t> iterator_vector; Box total; assign_inverse(total); expand_to_range<IncludePolicy1>(forward_range, total, @@ -712,16 +691,16 @@ public: } else { - for(iterator_type it1 = boost::begin(forward_range); + for (auto it1 = boost::begin(forward_range); it1 != boost::end(forward_range); ++it1) { - iterator_type it2 = it1; - for(++it2; it2 != boost::end(forward_range); ++it2) + auto it2 = it1; + for (++it2; it2 != boost::end(forward_range); ++it2) { if (! visitor.apply(*it1, *it2)) { - return false; // interrupt + return false; // Bail out if visitor returns false } } } @@ -817,21 +796,21 @@ public: std::size_t min_elements, VisitBoxPolicy box_visitor) { - typedef typename boost::range_iterator + using iterator1_t = typename boost::range_iterator < ForwardRange1 const - >::type iterator_type1; + >::type; - typedef typename boost::range_iterator + using iterator2_t = typename boost::range_iterator < ForwardRange2 const - >::type iterator_type2; + >::type; if (std::size_t(boost::size(forward_range1)) > min_elements && std::size_t(boost::size(forward_range2)) > min_elements) { - std::vector<iterator_type1> iterator_vector1; - std::vector<iterator_type2> iterator_vector2; + std::vector<iterator1_t> iterator_vector1; + std::vector<iterator2_t> iterator_vector2; Box total; assign_inverse(total); expand_to_range<IncludePolicy1>(forward_range1, total, @@ -849,17 +828,17 @@ public: } else { - for(iterator_type1 it1 = boost::begin(forward_range1); + for (auto it1 = boost::begin(forward_range1); it1 != boost::end(forward_range1); ++it1) { - for(iterator_type2 it2 = boost::begin(forward_range2); + for (auto it2 = boost::begin(forward_range2); it2 != boost::end(forward_range2); ++it2) { if (! visitor.apply(*it1, *it2)) { - return false; // interrupt + return false; // Bail out if visitor returns false } } } diff --git a/boost/geometry/algorithms/detail/point_on_border.hpp b/boost/geometry/algorithms/detail/point_on_border.hpp index 3969939b4e..8b3a20a16f 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-2020. -// Modifications copyright (c) 2017-2020 Oracle and/or its affiliates. +// This file was modified by Oracle on 2017-2022. +// Modifications copyright (c) 2017-2022 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 @@ -25,17 +25,15 @@ #include <boost/range/end.hpp> #include <boost/static_assert.hpp> +#include <boost/geometry/algorithms/assign.hpp> +#include <boost/geometry/algorithms/detail/convert_point_to_point.hpp> +#include <boost/geometry/algorithms/detail/equals/point_point.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/core/point_type.hpp> #include <boost/geometry/core/ring_type.hpp> - #include <boost/geometry/geometries/concepts/check.hpp> - -#include <boost/geometry/algorithms/assign.hpp> -#include <boost/geometry/algorithms/detail/convert_point_to_point.hpp> -#include <boost/geometry/algorithms/detail/equals/point_point.hpp> - #include <boost/geometry/util/condition.hpp> +#include <boost/geometry/views/detail/indexed_point_view.hpp> namespace boost { namespace geometry @@ -49,10 +47,10 @@ namespace detail { namespace point_on_border struct get_point { - template <typename Point> - static inline bool apply(Point& destination, Point const& source) + template <typename Destination, typename Source> + static inline bool apply(Destination& destination, Source const& source) { - destination = source; + detail::conversion::convert_point_to_point(source, destination); return true; } }; @@ -69,7 +67,7 @@ struct point_on_range return false; } - geometry::detail::conversion::convert_point_to_point(*begin, point); + detail::conversion::convert_point_to_point(*begin, point); return true; } @@ -92,12 +90,13 @@ struct point_on_polygon }; -struct point_on_box +struct point_on_segment_or_box { - template<typename Point, typename Box> - static inline bool apply(Point& point, Box const& box) + template<typename Point, typename SegmentOrBox> + static inline bool apply(Point& point, SegmentOrBox const& segment_or_box) { - detail::assign::assign_box_2d_corner<min_corner, min_corner>(box, point); + detail::indexed_point_view<SegmentOrBox const, 0> view(segment_or_box); + detail::conversion::convert_point_to_point(view, point); return true; } }; @@ -111,12 +110,7 @@ struct point_on_multi { // Take a point on the first multi-geometry // (i.e. the first that is not empty) - for (typename boost::range_iterator - < - MultiGeometry const - >::type it = boost::begin(multi); - it != boost::end(multi); - ++it) + for (auto it = boost::begin(multi); it != boost::end(multi); ++it) { if (Policy::apply(point, *it)) { @@ -147,6 +141,11 @@ struct point_on_border<point_tag> {}; template <> +struct point_on_border<segment_tag> + : detail::point_on_border::point_on_segment_or_box +{}; + +template <> struct point_on_border<linestring_tag> : detail::point_on_border::point_on_range {}; @@ -163,11 +162,16 @@ struct point_on_border<polygon_tag> template <> struct point_on_border<box_tag> - : detail::point_on_border::point_on_box + : detail::point_on_border::point_on_segment_or_box {}; template <> +struct point_on_border<multi_point_tag> + : detail::point_on_border::point_on_range +{}; + +template <> struct point_on_border<multi_polygon_tag> : detail::point_on_border::point_on_multi < @@ -189,6 +193,9 @@ struct point_on_border<multi_linestring_tag> #endif // DOXYGEN_NO_DISPATCH +// TODO: We should probably rename this utility because it can return point +// which is in the interior of a geometry (for PointLike and LinearRings). + /*! \brief Take point on a border \ingroup overlay diff --git a/boost/geometry/algorithms/detail/recalculate.hpp b/boost/geometry/algorithms/detail/recalculate.hpp index 688d49237d..eb633c9c2f 100644 --- a/boost/geometry/algorithms/detail/recalculate.hpp +++ b/boost/geometry/algorithms/detail/recalculate.hpp @@ -106,13 +106,10 @@ struct range_to_range typedef recalculate_point<geometry::dimension<point_type>::value> per_point; geometry::clear(destination); - for (typename boost::range_iterator<Range2 const>::type it - = boost::begin(source); - it != boost::end(source); - ++it) + for (auto const& source_point : source) { point_type p; - per_point::apply(p, *it, strategy); + per_point::apply(p, source_point, strategy); geometry::append(destination, p); } } diff --git a/boost/geometry/algorithms/detail/relate/areal_areal.hpp b/boost/geometry/algorithms/detail/relate/areal_areal.hpp index 99df598da8..41366e3167 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, 2018, 2019. -// Modifications copyright (c) 2013-2019 Oracle and/or its affiliates. +// This file was modified by Oracle on 2013-2022. +// Modifications copyright (c) 2013-2022 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -29,12 +29,14 @@ #include <boost/geometry/algorithms/detail/relate/boundary_checker.hpp> #include <boost/geometry/algorithms/detail/relate/follow_helpers.hpp> +#include <boost/geometry/geometries/helper_geometry.hpp> + namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace relate { - + // WARNING! // TODO: In the worst case calling this Pred in a loop for MultiPolygon/MultiPolygon may take O(NM) // Use the rtree in this case! @@ -85,9 +87,9 @@ public: return false; } - typedef typename geometry::point_type<Areal>::type point_type; - point_type pt; - bool const ok = boost::geometry::point_on_border(pt, areal); + using point_type = typename geometry::point_type<Areal>::type; + typename helper_geometry<point_type>::type pt; + bool const ok = geometry::point_on_border(pt, areal); // TODO: for now ignore, later throw an exception? if ( !ok ) @@ -102,7 +104,7 @@ public: m_other_areal, m_point_in_areal_strategy); //BOOST_GEOMETRY_ASSERT( pig != 0 ); - + // inside if ( pig > 0 ) { @@ -185,7 +187,7 @@ public: } } } - + return m_flags != 3 && !m_result.interrupt; } @@ -206,9 +208,6 @@ struct areal_areal static const bool interruption_enabled = true; - typedef typename geometry::point_type<Geometry1>::type point1_type; - typedef typename geometry::point_type<Geometry2>::type point2_type; - template <typename Result, typename Strategy> static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Result & result, @@ -216,17 +215,16 @@ struct areal_areal { // TODO: If Areal geometry may have infinite size, change the following line: - // The result should be FFFFFFFFF - relate::set<exterior, exterior, result_dimension<Geometry2>::value>(result);// FFFFFFFFd, d in [1,9] or T + update<exterior, exterior, result_dimension<Geometry2>::value>(result);// FFFFFFFFd, d in [1,9] or T if ( BOOST_GEOMETRY_CONDITION(result.interrupt) ) return; // get and analyse turns - typedef typename turns::get_turns + using turn_type = typename turns::get_turns < Geometry1, Geometry2 - >::template turn_info_type<Strategy>::type turn_type; + >::template turn_info_type<Strategy>::type; std::vector<turn_type> turns; interrupt_policy_areal_areal<Result> interrupt_policy(geometry1, geometry2, result); @@ -235,8 +233,6 @@ struct areal_areal if ( BOOST_GEOMETRY_CONDITION(result.interrupt) ) return; - typedef typename Strategy::cs_tag cs_tag; - no_turns_aa_pred<Geometry2, Result, Strategy, false> pred1(geometry2, result, strategy); for_each_disjoint_geometry_if<0, Geometry1>::apply(turns.begin(), turns.end(), geometry1, pred1); @@ -248,7 +244,7 @@ struct areal_areal for_each_disjoint_geometry_if<1, Geometry2>::apply(turns.begin(), turns.end(), geometry2, pred2); if ( BOOST_GEOMETRY_CONDITION(result.interrupt) ) return; - + if ( turns.empty() ) return; @@ -259,8 +255,8 @@ struct areal_areal || may_update<exterior, interior, '2'>(result) ) { // sort turns - typedef turns::less<0, turns::less_op_areal_areal<0>, cs_tag> less; - std::sort(turns.begin(), turns.end(), less()); + using less_t = turns::less<0, turns::less_op_areal_areal<0>, Strategy>; + std::sort(turns.begin(), turns.end(), less_t()); /*if ( may_update<interior, exterior, '2'>(result) || may_update<boundary, exterior, '1'>(result) @@ -299,8 +295,8 @@ struct areal_areal || may_update<exterior, interior, '2', true>(result) ) { // sort turns - typedef turns::less<1, turns::less_op_areal_areal<1>, cs_tag> less; - std::sort(turns.begin(), turns.end(), less()); + using less_t = turns::less<1, turns::less_op_areal_areal<1>, Strategy>; + std::sort(turns.begin(), turns.end(), less_t()); /*if ( may_update<interior, exterior, '2', true>(result) || may_update<boundary, exterior, '1', true>(result) @@ -352,9 +348,7 @@ struct areal_areal template <typename Range> inline bool apply(Range const& turns) { - typedef typename boost::range_iterator<Range const>::type iterator; - - for (iterator it = boost::begin(turns) ; it != boost::end(turns) ; ++it) + for (auto it = boost::begin(turns) ; it != boost::end(turns) ; ++it) { per_turn<0>(*it); per_turn<1>(*it); @@ -469,7 +463,7 @@ struct areal_areal { m_exit_detected = false; } - } + } /*else*/ if ( m_enter_detected /*m_previous_operation == overlay::operation_intersection*/ ) { @@ -652,15 +646,14 @@ struct areal_areal return; } - typename detail::sub_range_return_type<Geometry const>::type - range_ref = detail::sub_range(geometry, seg_id); + auto const& sub_range = detail::sub_range(geometry, seg_id); - if ( boost::empty(range_ref) ) + if ( boost::empty(sub_range) ) { // TODO: throw an exception? return; // ignore } - + // TODO: possible optimization // if the range is an interior ring we may use other IPs generated for this single geometry // to know which other single geometries should be checked @@ -668,7 +661,7 @@ struct areal_areal // TODO: optimize! e.g. use spatial index // O(N) - running it in a loop gives O(NM) using detail::within::point_in_geometry; - int const pig = point_in_geometry(range::front(range_ref), + int const pig = point_in_geometry(range::front(sub_range), other_geometry, m_point_in_areal_strategy); @@ -713,12 +706,12 @@ struct areal_areal for ( TurnIt it = first ; it != last ; ++it ) { - if ( it->operations[0].operation == overlay::operation_intersection + if ( it->operations[0].operation == overlay::operation_intersection && it->operations[1].operation == overlay::operation_intersection ) { found_ii = true; } - else if ( it->operations[0].operation == overlay::operation_union + else if ( it->operations[0].operation == overlay::operation_union && it->operations[1].operation == overlay::operation_union ) { found_uu = true; @@ -735,7 +728,7 @@ struct areal_areal update<interior, interior, '2', transpose_result>(m_result); m_flags |= 1; - //update<boundary, boundary, '0', transpose_result>(m_result); + //update<boundary, boundary, '0', transpose_result>(m_result); update<boundary, interior, '1', transpose_result>(m_result); update<exterior, interior, '2', transpose_result>(m_result); @@ -846,7 +839,7 @@ struct areal_areal count = boost::numeric_cast<signed_size_type>( geometry::num_interior_rings( detail::single_geometry(analyser.geometry, seg_id))); - + for_no_turns_rings(analyser, turn, seg_id.ring_index + 1, count); } diff --git a/boost/geometry/algorithms/detail/relate/boundary_checker.hpp b/boost/geometry/algorithms/detail/relate/boundary_checker.hpp index 487c706e9f..0d95aabac1 100644 --- a/boost/geometry/algorithms/detail/relate/boundary_checker.hpp +++ b/boost/geometry/algorithms/detail/relate/boundary_checker.hpp @@ -1,7 +1,8 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014-2020 Oracle and/or its affiliates. +// Copyright (c) 2014-2023, 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, @@ -17,8 +18,14 @@ #include <boost/geometry/algorithms/detail/sub_range.hpp> #include <boost/geometry/algorithms/num_points.hpp> +#include <boost/geometry/geometries/helper_geometry.hpp> + #include <boost/geometry/policies/compare.hpp> +#include <boost/geometry/strategies/relate/cartesian.hpp> +#include <boost/geometry/strategies/relate/geographic.hpp> +#include <boost/geometry/strategies/relate/spherical.hpp> + #include <boost/geometry/util/has_nan_coordinate.hpp> #include <boost/geometry/util/range.hpp> @@ -26,9 +33,9 @@ namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL -namespace detail { namespace relate { +namespace detail { namespace relate +{ -enum boundary_query { boundary_front, boundary_back, boundary_any }; template < @@ -41,30 +48,26 @@ class boundary_checker {}; template <typename Geometry, typename Strategy> class boundary_checker<Geometry, Strategy, linestring_tag> { - typedef typename point_type<Geometry>::type point_type; - public: boundary_checker(Geometry const& g, Strategy const& s) - : m_has_boundary( boost::size(g) >= 2 - && ! detail::equals::equals_point_point(range::front(g), - range::back(g), - s) ) + : m_has_boundary( + boost::size(g) >= 2 + && ! detail::equals::equals_point_point(range::front(g), range::back(g), s)) #ifdef BOOST_GEOMETRY_DEBUG_RELATE_BOUNDARY_CHECKER , m_geometry(g) #endif , m_strategy(s) {} - template <boundary_query BoundaryQuery> - bool is_endpoint_boundary(point_type const& pt) const + template <typename Point> + bool is_endpoint_boundary(Point const& pt) const { boost::ignore_unused(pt); #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(m_geometry), m_strategy) - || (BoundaryQuery == boundary_back || BoundaryQuery == boundary_any) - && detail::equals::equals_point_point(pt, range::back(m_geometry), m_strategy) ); + BOOST_GEOMETRY_ASSERT( + detail::equals::equals_point_point(pt, range::front(m_geometry), m_strategy) + || detail::equals::equals_point_point(pt, range::back(m_geometry), m_strategy)); #endif return m_has_boundary; } @@ -82,10 +85,72 @@ private: Strategy const& m_strategy; }; + +template <typename Point, typename Strategy, typename Out> +inline void copy_boundary_points(Point const& front_pt, Point const& back_pt, + Strategy const& strategy, Out & boundary_points) +{ + using mutable_point_type = typename Out::value_type; + // linear ring or point - no boundary + if (! equals::equals_point_point(front_pt, back_pt, strategy)) + { + // do not add points containing NaN coordinates + // because they cannot be reasonably compared, e.g. with MSVC + // an assertion failure is reported in std::equal_range() + if (! geometry::has_nan_coordinate(front_pt)) + { + mutable_point_type pt; + geometry::convert(front_pt, pt); + boundary_points.push_back(pt); + } + if (! geometry::has_nan_coordinate(back_pt)) + { + mutable_point_type pt; + geometry::convert(back_pt, pt); + boundary_points.push_back(pt); + } + } +} + +template <typename Segment, typename Strategy, typename Out> +inline void copy_boundary_points_of_seg(Segment const& seg, Strategy const& strategy, + Out & boundary_points) +{ + typename Out::value_type front_pt, back_pt; + assign_point_from_index<0>(seg, front_pt); + assign_point_from_index<1>(seg, back_pt); + copy_boundary_points(front_pt, back_pt, strategy, boundary_points); +} + +template <typename Linestring, typename Strategy, typename Out> +inline void copy_boundary_points_of_ls(Linestring const& ls, Strategy const& strategy, + Out & boundary_points) +{ + // empty or point - no boundary + if (boost::size(ls) >= 2) + { + auto const& front_pt = range::front(ls); + auto const& back_pt = range::back(ls); + copy_boundary_points(front_pt, back_pt, strategy, boundary_points); + } +} + +template <typename MultiLinestring, typename Strategy, typename Out> +inline void copy_boundary_points_of_mls(MultiLinestring const& mls, Strategy const& strategy, + Out & boundary_points) +{ + for (auto it = boost::begin(mls); it != boost::end(mls); ++it) + { + copy_boundary_points_of_ls(*it, strategy, boundary_points); + } +} + + template <typename Geometry, typename Strategy> class boundary_checker<Geometry, Strategy, multi_linestring_tag> { - typedef typename point_type<Geometry>::type point_type; + using point_type = typename point_type<Geometry>::type; + using mutable_point_type = typename helper_geometry<point_type>::type; public: boundary_checker(Geometry const& g, Strategy const& s) @@ -94,75 +159,38 @@ public: // First call O(NlogN) // Each next call O(logN) - template <boundary_query BoundaryQuery> - bool is_endpoint_boundary(point_type const& pt) const + template <typename Point> + bool is_endpoint_boundary(Point const& pt) const { - typedef geometry::less<point_type, -1, typename Strategy::cs_tag> less_type; + using less_type = geometry::less<mutable_point_type, -1, Strategy>; - typedef typename boost::range_size<Geometry>::type size_type; - size_type multi_count = boost::size(m_geometry); + auto const multi_count = boost::size(m_geometry); - if ( multi_count < 1 ) + if (multi_count < 1) + { return false; + } - if ( ! m_is_filled ) + if (! m_is_filled) { //boundary_points.clear(); m_boundary_points.reserve(multi_count * 2); - typedef typename boost::range_iterator<Geometry const>::type multi_iterator; - for ( multi_iterator it = boost::begin(m_geometry) ; - it != boost::end(m_geometry) ; ++ it ) - { - typename boost::range_reference<Geometry const>::type - ls = *it; - - // empty or point - no boundary - if (boost::size(ls) < 2) - { - continue; - } - - typedef typename boost::range_reference - < - typename boost::range_value<Geometry const>::type const - >::type point_reference; - - point_reference front_pt = range::front(ls); - point_reference back_pt = range::back(ls); - - // linear ring or point - no boundary - if (! equals::equals_point_point(front_pt, back_pt, m_strategy)) - { - // do not add points containing NaN coordinates - // because they cannot be reasonably compared, e.g. with MSVC - // an assertion failure is reported in std::equal_range() - if (! geometry::has_nan_coordinate(front_pt)) - { - m_boundary_points.push_back(front_pt); - } - if (! geometry::has_nan_coordinate(back_pt)) - { - m_boundary_points.push_back(back_pt); - } - } - } - - std::sort(m_boundary_points.begin(), - m_boundary_points.end(), - less_type()); + copy_boundary_points_of_mls(m_geometry, m_strategy, m_boundary_points); + + std::sort(m_boundary_points.begin(), m_boundary_points.end(), less_type()); m_is_filled = true; } - std::size_t equal_points_count - = boost::size( - std::equal_range(m_boundary_points.begin(), - m_boundary_points.end(), - pt, - less_type()) - ); + mutable_point_type mpt; + geometry::convert(pt, mpt); + auto const equal_range = std::equal_range(m_boundary_points.begin(), + m_boundary_points.end(), + mpt, + less_type()); + std::size_t const equal_points_count = boost::size(equal_range); return equal_points_count % 2 != 0;// && equal_points_count > 0; // the number is odd and > 0 } @@ -173,13 +201,14 @@ public: private: mutable bool m_is_filled; - // TODO: store references/pointers instead of points? - mutable std::vector<point_type> m_boundary_points; + // TODO: store references/pointers instead of converted points? + mutable std::vector<mutable_point_type> m_boundary_points; Geometry const& m_geometry; Strategy const& m_strategy; }; + }} // namespace detail::relate #endif // DOXYGEN_NO_DETAIL diff --git a/boost/geometry/algorithms/detail/relate/box_areal.hpp b/boost/geometry/algorithms/detail/relate/box_areal.hpp new file mode 100644 index 0000000000..a9e749fdb2 --- /dev/null +++ b/boost/geometry/algorithms/detail/relate/box_areal.hpp @@ -0,0 +1,70 @@ +// Boost.Geometry + +// Copyright (c) 2022, Oracle and/or its affiliates. + +// Contributed and/or modified by Vissarion Fysikopoulos, 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_RELATE_BOX_AREAL_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_BOX_AREAL_HPP + +#include <boost/geometry/algorithms/detail/relate/areal_areal.hpp> +#include <boost/geometry/views/box_view.hpp> + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace relate { + + +// The implementation of an algorithm calculating relate() for B/A +template <typename Box, typename Areal> +struct box_areal +{ + static const bool interruption_enabled = true; + + template <typename Result, typename Strategy> + static inline void apply(Box const& box, Areal const& areal, + Result& result, + Strategy const& strategy) + { + using is_cartesian = std::is_same + < + typename Strategy::cs_tag, + cartesian_tag + >; + apply(box, areal, result, strategy, is_cartesian()); + } + + template <typename Result, typename Strategy> + static inline void apply(Box const& box, Areal const& areal, + Result& result, + Strategy const& strategy, + std::true_type /*is_cartesian*/) + { + using box_view = boost::geometry::box_view<Box>; + box_view view(box); + areal_areal<box_view, Areal>::apply(view, areal, result, strategy); + } + + template <typename Result, typename Strategy> + static inline void apply(Box const& box, Areal const& areal, + Result& result, + Strategy const& strategy, + std::false_type /*is_cartesian*/) + { + BOOST_GEOMETRY_STATIC_ASSERT_FALSE( + "Not implemented for this coordinate system.", + typename Strategy::cs_tag()); + } +}; + +}} // namespace detail::relate +#endif // DOXYGEN_NO_DETAIL + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_BOX_AREAL_HPP diff --git a/boost/geometry/algorithms/detail/relate/de9im.hpp b/boost/geometry/algorithms/detail/relate/de9im.hpp index a89d46100a..a9d6ea5792 100644 --- a/boost/geometry/algorithms/detail/relate/de9im.hpp +++ b/boost/geometry/algorithms/detail/relate/de9im.hpp @@ -1,9 +1,10 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2022 Adam Wulkiewicz, Lodz, Poland. -// This file was modified by Oracle on 2013-2020. -// Modifications copyright (c) 2013-2020 Oracle and/or its affiliates. +// This file was modified by Oracle on 2013-2022. +// Modifications copyright (c) 2013-2022 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -25,7 +26,7 @@ namespace boost { namespace geometry { - + namespace de9im { @@ -103,7 +104,7 @@ public: inline explicit mask(const char* code) : base_type(code) {} - + /*! \brief The constructor. \param code The mask pattern. @@ -275,6 +276,11 @@ struct static_mask_touches_impl<Geometry1, Geometry2, 0, 0> }; template <typename Geometry1, typename Geometry2> +struct static_mask_touches_not_pp_type + : static_mask_touches_impl<Geometry1, Geometry2, 2, 2> // dummy dimensions +{}; + +template <typename Geometry1, typename Geometry2> struct static_mask_touches_type : static_mask_touches_impl<Geometry1, Geometry2> {}; @@ -344,6 +350,21 @@ struct static_mask_crosses_type : static_mask_crosses_impl<Geometry1, Geometry2> {}; +template <typename Geometry1, typename Geometry2> +struct static_mask_crosses_d1_le_d2_type // specific dimensions are not important here + : static_mask_crosses_impl<Geometry1, Geometry2, 0, 1> +{}; + +template <typename Geometry1, typename Geometry2> +struct static_mask_crosses_d2_le_d1_type // specific dimensions are not important here + : static_mask_crosses_impl<Geometry1, Geometry2, 1, 0> +{}; + +template <typename Geometry1, typename Geometry2> +struct static_mask_crosses_d1_1_d2_1_type + : static_mask_crosses_impl<Geometry1, Geometry2, 1, 1> +{}; + // OVERLAPS // dim(G1) != dim(G2) - NOT P/P, L/L, A/A @@ -376,6 +397,16 @@ struct static_mask_overlaps_type : static_mask_overlaps_impl<Geometry1, Geometry2> {}; +template <typename Geometry1, typename Geometry2> +struct static_mask_overlaps_d1_eq_d2_type + : static_mask_overlaps_impl<Geometry1, Geometry2, 2, 2> +{}; + +template <typename Geometry1, typename Geometry2> +struct static_mask_overlaps_d1_1_d2_1_type + : static_mask_overlaps_impl<Geometry1, Geometry2, 1, 1> +{}; + }} // namespace detail::de9im #endif // DOXYGEN_NO_DETAIL diff --git a/boost/geometry/algorithms/detail/relate/follow_helpers.hpp b/boost/geometry/algorithms/detail/relate/follow_helpers.hpp index d584e81e5c..cb1f0f40c9 100644 --- a/boost/geometry/algorithms/detail/relate/follow_helpers.hpp +++ b/boost/geometry/algorithms/detail/relate/follow_helpers.hpp @@ -2,8 +2,8 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. -// This file was modified by Oracle on 2013, 2014, 2018. -// Modifications copyright (c) 2013-2018 Oracle and/or its affiliates. +// This file was modified by Oracle on 2013-2022. +// Modifications copyright (c) 2013-2022 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -30,6 +30,8 @@ #include <boost/geometry/util/condition.hpp> #include <boost/geometry/util/range.hpp> +#include <type_traits> + namespace boost { namespace geometry { @@ -42,7 +44,7 @@ namespace detail { namespace relate { template <std::size_t OpId, typename Geometry, typename Tag = typename geometry::tag<Geometry>::type, - bool IsMulti = boost::is_base_of<multi_tag, Tag>::value + bool IsMulti = std::is_base_of<multi_tag, Tag>::value > struct for_each_disjoint_geometry_if : public not_implemented<Tag> @@ -52,14 +54,12 @@ template <std::size_t OpId, typename Geometry, typename Tag> struct for_each_disjoint_geometry_if<OpId, Geometry, Tag, false> { template <typename TurnIt, typename Pred> - static inline bool apply(TurnIt first, TurnIt last, - Geometry const& geometry, - Pred & pred) + static void apply(TurnIt first, TurnIt last, Geometry const& geometry, Pred & pred) { - if ( first != last ) - return false; - pred(geometry); - return true; + if (first == last) + { + pred(geometry); + } } }; @@ -67,49 +67,43 @@ template <std::size_t OpId, typename Geometry, typename Tag> struct for_each_disjoint_geometry_if<OpId, Geometry, Tag, true> { template <typename TurnIt, typename Pred> - static inline bool apply(TurnIt first, TurnIt last, - Geometry const& geometry, - Pred & pred) + static void apply(TurnIt first, TurnIt last, Geometry const& geometry, Pred & pred) { - if ( first != last ) - return for_turns(first, last, geometry, pred); + if (first == last) + { + for_empty(geometry, pred); + } else - return for_empty(geometry, pred); + { + for_turns(first, last, geometry, pred); + } } template <typename Pred> - static inline bool for_empty(Geometry const& geometry, - Pred & pred) + static void for_empty(Geometry const& geometry, Pred & pred) { - typedef typename boost::range_iterator<Geometry const>::type iterator; - // O(N) // check predicate for each contained geometry without generated turn - for ( iterator it = boost::begin(geometry) ; - it != boost::end(geometry) ; ++it ) + for (auto it = boost::begin(geometry); it != boost::end(geometry) ; ++it) { - bool cont = pred(*it); - if ( !cont ) + if (! pred(*it)) + { break; + } } - - return !boost::empty(geometry); } template <typename TurnIt, typename Pred> - static inline bool for_turns(TurnIt first, TurnIt last, - Geometry const& geometry, - Pred & pred) + static void for_turns(TurnIt first, TurnIt last, Geometry const& geometry, Pred & pred) { BOOST_GEOMETRY_ASSERT(first != last); const std::size_t count = boost::size(geometry); - boost::ignore_unused(count); // O(I) // gather info about turns generated for contained geometries std::vector<bool> detected_intersections(count, false); - for ( TurnIt it = first ; it != last ; ++it ) + for (TurnIt it = first; it != last; ++it) { signed_size_type multi_index = it->operations[OpId].seg_id.multi_index; BOOST_GEOMETRY_ASSERT(multi_index >= 0); @@ -118,28 +112,23 @@ struct for_each_disjoint_geometry_if<OpId, Geometry, Tag, true> detected_intersections[index] = true; } - bool found = false; - // O(N) // check predicate for each contained geometry without generated turn - for ( std::vector<bool>::iterator it = detected_intersections.begin() ; - it != detected_intersections.end() ; ++it ) + for (std::size_t index = 0; index < detected_intersections.size(); ++index) { // if there were no intersections for this multi_index - if ( *it == false ) + if (detected_intersections[index] == false) { - found = true; - std::size_t const index = std::size_t(std::distance(detected_intersections.begin(), it)); - bool cont = pred(range::at(geometry, index)); - if ( !cont ) + if (! pred(range::at(geometry, index))) + { break; + } } } - - return found; } }; + // WARNING! This class stores pointers! // Passing a reference to local variable will result in undefined behavior! template <typename Point> @@ -184,7 +173,7 @@ public: bool operator()(segment_identifier const& sid) const { - return sid.multi_index == sid_ptr->multi_index; + return sid.multi_index == sid_ptr->multi_index; } template <typename Point> @@ -267,11 +256,10 @@ public: segment_identifier const& other_id = turn.operations[other_op_id].seg_id; overlay::operation_type exit_op = turn.operations[op_id].operation; - typedef typename std::vector<point_info>::iterator point_iterator; // search for the entry point in the same range of other geometry - point_iterator entry_it = std::find_if(m_other_entry_points.begin(), - m_other_entry_points.end(), - same_single(other_id)); + auto entry_it = std::find_if(m_other_entry_points.begin(), + m_other_entry_points.end(), + same_single(other_id)); // this end point has corresponding entry point if ( entry_it != m_other_entry_points.end() ) @@ -298,11 +286,10 @@ public: bool is_outside(TurnInfo const& turn) const { return m_other_entry_points.empty() - || std::find_if(m_other_entry_points.begin(), + || std::none_of(m_other_entry_points.begin(), m_other_entry_points.end(), same_single( - turn.operations[other_op_id].seg_id)) - == m_other_entry_points.end(); + turn.operations[other_op_id].seg_id)); } overlay::operation_type get_exit_operation() const @@ -366,44 +353,17 @@ inline bool turn_on_the_same_ip(Turn const& prev_turn, Turn const& curr_turn, return detail::equals::equals_point_point(prev_turn.point, curr_turn.point, strategy); } -template <boundary_query BoundaryQuery, - typename Point, - typename BoundaryChecker> -static inline bool is_endpoint_on_boundary(Point const& pt, - BoundaryChecker & boundary_checker) -{ - return boundary_checker.template is_endpoint_boundary<BoundaryQuery>(pt); -} - -template <boundary_query BoundaryQuery, - typename IntersectionPoint, - typename OperationInfo, - typename BoundaryChecker> +template <typename IntersectionPoint, typename OperationInfo, typename BoundaryChecker> static inline bool is_ip_on_boundary(IntersectionPoint const& ip, OperationInfo const& operation_info, - BoundaryChecker & boundary_checker, - segment_identifier const& seg_id) + BoundaryChecker const& boundary_checker) { - boost::ignore_unused(seg_id); - - bool res = false; - - // IP on the last point of the linestring - if ( BOOST_GEOMETRY_CONDITION(BoundaryQuery == boundary_back || BoundaryQuery == boundary_any) - && operation_info.position == overlay::position_back ) - { - // check if this point is a boundary - res = boundary_checker.template is_endpoint_boundary<boundary_back>(ip); - } - // IP on the last point of the linestring - else if ( BOOST_GEOMETRY_CONDITION(BoundaryQuery == boundary_front || BoundaryQuery == boundary_any) - && operation_info.position == overlay::position_front ) - { - // check if this point is a boundary - res = boundary_checker.template is_endpoint_boundary<boundary_front>(ip); - } - - return res; + // IP on the first or the last point of the linestring + return (operation_info.position == overlay::position_back + || operation_info.position == overlay::position_front) + // check if this point is a boundary + ? boundary_checker.is_endpoint_boundary(ip) + : false; } diff --git a/boost/geometry/algorithms/detail/relate/implementation.hpp b/boost/geometry/algorithms/detail/relate/implementation.hpp index 190a5e3d6b..458bfdba3f 100644 --- a/boost/geometry/algorithms/detail/relate/implementation.hpp +++ b/boost/geometry/algorithms/detail/relate/implementation.hpp @@ -2,9 +2,8 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. -// This file was modified by Oracle on 2013-2021. -// Modifications copyright (c) 2013-2021 Oracle and/or its affiliates. - +// This file was modified by Oracle on 2013-2022. +// Modifications copyright (c) 2013-2022 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, @@ -15,16 +14,16 @@ #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_IMPLEMENTATION_HPP -#include <boost/geometry/core/tags.hpp> - +#include <boost/geometry/algorithms/detail/relate/areal_areal.hpp> +#include <boost/geometry/algorithms/detail/relate/box_areal.hpp> #include <boost/geometry/algorithms/detail/relate/interface.hpp> - -#include <boost/geometry/algorithms/detail/relate/point_point.hpp> -#include <boost/geometry/algorithms/detail/relate/point_geometry.hpp> -#include <boost/geometry/algorithms/detail/relate/linear_linear.hpp> #include <boost/geometry/algorithms/detail/relate/linear_areal.hpp> +#include <boost/geometry/algorithms/detail/relate/linear_linear.hpp> #include <boost/geometry/algorithms/detail/relate/multi_point_geometry.hpp> -#include <boost/geometry/algorithms/detail/relate/areal_areal.hpp> +#include <boost/geometry/algorithms/detail/relate/point_geometry.hpp> +#include <boost/geometry/algorithms/detail/relate/point_point.hpp> + +#include <boost/geometry/core/tags.hpp> #include <boost/geometry/strategies/relate/cartesian.hpp> #include <boost/geometry/strategies/relate/geographic.hpp> @@ -116,6 +115,23 @@ struct relate<Areal1, Areal2, Tag1, Tag2, 2, 2, true> : detail::relate::areal_areal<Areal1, Areal2> {}; + +template <typename Box, typename Ring> +struct relate<Box, Ring, box_tag, ring_tag, 2, 2, false> + : detail::relate::box_areal<Box, Ring> +{}; + +template <typename Box, typename Polygon> +struct relate<Box, Polygon, box_tag, polygon_tag, 2, 2, false> + : detail::relate::box_areal<Box, Polygon> +{}; + +template <typename Box, typename MultiPolygon> +struct relate<Box, MultiPolygon, box_tag, multi_polygon_tag, 2, 2, false> + : detail::relate::box_areal<Box, MultiPolygon> +{}; + + } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH diff --git a/boost/geometry/algorithms/detail/relate/implementation_gc.hpp b/boost/geometry/algorithms/detail/relate/implementation_gc.hpp new file mode 100644 index 0000000000..f0fa11d2af --- /dev/null +++ b/boost/geometry/algorithms/detail/relate/implementation_gc.hpp @@ -0,0 +1,696 @@ +// Boost.Geometry + +// Copyright (c) 2022-2023 Adam Wulkiewicz, Lodz, Poland. + +// Copyright (c) 2022 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) + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_IMPLEMENTATION_GC_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_IMPLEMENTATION_GC_HPP + + +#include <boost/geometry/algorithms/detail/relate/boundary_checker.hpp> +#include <boost/geometry/algorithms/detail/relate/interface.hpp> +#include <boost/geometry/algorithms/difference.hpp> +#include <boost/geometry/algorithms/intersection.hpp> +#include <boost/geometry/algorithms/is_empty.hpp> +#include <boost/geometry/algorithms/union.hpp> +#include <boost/geometry/geometries/linestring.hpp> +#include <boost/geometry/geometries/multi_linestring.hpp> +#include <boost/geometry/geometries/multi_point.hpp> +#include <boost/geometry/geometries/multi_polygon.hpp> +#include <boost/geometry/geometries/polygon.hpp> +#include <boost/geometry/util/condition.hpp> +#include <boost/geometry/views/detail/geometry_collection_view.hpp> + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace relate +{ + +// For fields II IE and EI this handler behaves like matrix_handler. +// It has to be created at the beginning of processing because it relies on the +// fact that all of the fields are set to F and no geometry was handled yet. +// This way it can check which fields are required for any mask and matrix +// without accessing the internals. +// An alternative would be to remove this wrapper and always set the matrix +// in static_mask_handler even if this is not required. +template <typename Handler> +struct aa_handler_wrapper +{ + bool interrupt = false; + + explicit aa_handler_wrapper(Handler& handler) + : m_handler(handler) + , m_overwrite_ii(! handler.template may_update<interior, interior, '2'>()) + , m_overwrite_ie(! handler.template may_update<interior, exterior, '2'>()) + , m_overwrite_ei(! handler.template may_update<exterior, interior, '2'>()) + {} + + template <field F1, field F2, char D> + inline bool may_update() const + { + if ((BOOST_GEOMETRY_CONDITION(F1 == interior && F2 == interior) && m_overwrite_ii) + || (BOOST_GEOMETRY_CONDITION(F1 == interior && F2 == exterior) && m_overwrite_ie) + || (BOOST_GEOMETRY_CONDITION(F1 == exterior && F2 == interior) && m_overwrite_ei)) + { + char const c = m_handler.template get<F1, F2>(); + return D > c || c > '9'; + } + else + { + return m_handler.template may_update<F1, F2, D>(); + } + } + + template <field F1, field F2, char V> + inline void update() + { + if ((BOOST_GEOMETRY_CONDITION(F1 == interior && F2 == interior) && m_overwrite_ii) + || (BOOST_GEOMETRY_CONDITION(F1 == interior && F2 == exterior) && m_overwrite_ie) + || (BOOST_GEOMETRY_CONDITION(F1 == exterior && F2 == interior) && m_overwrite_ei)) + { + // NOTE: Other handlers first check for potential interruption + // and only after that checks update condition. + char const c = m_handler.template get<F1, F2>(); + // If c == T and V == T it will be set anyway but that's fine. + if (V > c || c > '9') + { + // set may set interrupt flag + m_handler.template set<F1, F2, V>(); + } + } + else + { + m_handler.template update<F1, F2, V>(); + } + interrupt = interrupt || m_handler.interrupt; + } + +private: + Handler & m_handler; + bool const m_overwrite_ii; + bool const m_overwrite_ie; + bool const m_overwrite_ei; +}; + + +template <typename Geometry1, typename Geometry2> +struct gc_gc +{ + static const bool interruption_enabled = true; + + using mpt1_found_t = typename util::sequence_find_if + < + typename traits::geometry_types<Geometry1>::type, + util::is_multi_point + >::type; + using mls1_found_t = typename util::sequence_find_if + < + typename traits::geometry_types<Geometry1>::type, + util::is_multi_linestring + >::type; + using mpo1_found_t = typename util::sequence_find_if + < + typename traits::geometry_types<Geometry1>::type, + util::is_multi_polygon + >::type; + using pt1_t = typename geometry::point_type<Geometry1>::type; + using mpt1_t = std::conditional_t + < + std::is_void<mpt1_found_t>::value, + geometry::model::multi_point<pt1_t>, + mpt1_found_t + >; + using mls1_t = std::conditional_t + < + std::is_void<mls1_found_t>::value, + geometry::model::multi_linestring<geometry::model::linestring<pt1_t>>, + mls1_found_t + >; + using mpo1_t = std::conditional_t + < + std::is_void<mpo1_found_t>::value, + geometry::model::multi_polygon<geometry::model::polygon<pt1_t>>, + mpo1_found_t + >; + using tuple1_t = boost::tuple<mpt1_t, mls1_t, mpo1_t>; + + using mpt2_found_t = typename util::sequence_find_if + < + typename traits::geometry_types<Geometry2>::type, + util::is_multi_point + >::type; + using mls2_found_t = typename util::sequence_find_if + < + typename traits::geometry_types<Geometry2>::type, + util::is_multi_linestring + >::type; + using mpo2_found_t = typename util::sequence_find_if + < + typename traits::geometry_types<Geometry2>::type, + util::is_multi_polygon + >::type; + using pt2_t = typename geometry::point_type<Geometry2>::type; + using mpt2_t = std::conditional_t + < + std::is_void<mpt2_found_t>::value, + geometry::model::multi_point<pt2_t>, + mpt2_found_t + >; + using mls2_t = std::conditional_t + < + std::is_void<mls2_found_t>::value, + geometry::model::multi_linestring<geometry::model::linestring<pt2_t>>, + mls2_found_t + >; + using mpo2_t = std::conditional_t + < + std::is_void<mpo2_found_t>::value, + geometry::model::multi_polygon<geometry::model::polygon<pt2_t>>, + mpo2_found_t + >; + using tuple2_t = boost::tuple<mpt2_t, mls2_t, mpo2_t>; + + template <typename Geometry> + using kind_id = util::index_constant + < + util::is_areal<Geometry>::value ? 2 + : util::is_linear<Geometry>::value ? 1 + : 0 + >; + + template <typename Result, typename Strategy> + static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2, + Result & result, + Strategy const& strategy) + { + using gc1_view_t = random_access_view<Geometry1 const>; + using gc2_view_t = random_access_view<Geometry2 const>; + gc1_view_t const gc1_view(geometry1); + gc2_view_t const gc2_view(geometry2); + + bool inters_found[2][3] = {{false, false, false}, {false, false, false}}; + bool disjoint_found[2][3] = {{false, false, false}, {false, false, false}}; + bool disjoint_linear_boundary_found[2] = {false, false}; + bool has_disjoint = false; + + gc_group_elements(gc1_view, gc2_view, strategy, + [&](auto const& inters_group) + { + tuple1_t tuple1; + tuple2_t tuple2; + + // Create MPts, MLss and MPos containing all gc elements from this group + // They may potentially intersect each other + for (auto const& id : inters_group) + { + BOOST_GEOMETRY_ASSERT(id.source_id == 0 || id.source_id == 1); + if (id.source_id == 0) + { + traits::iter_visit<gc1_view_t>::apply([&](auto const& g1) + { + merge_geometry(tuple1, g1, strategy); + }, boost::begin(gc1_view) + id.gc_id); + } + else + { + traits::iter_visit<gc2_view_t>::apply([&](auto const& g2) + { + merge_geometry(tuple2, g2, strategy); + }, boost::begin(gc2_view) + id.gc_id); + } + } + + // Subtract higher topo-dim elements from elements of lower topo-dim + // MPts do not intersect other geometries, MLss and MPos may touch + subtract_elements(tuple1, strategy); + subtract_elements(tuple2, strategy); + + // Helpers + auto const& mpt1 = boost::get<0>(tuple1); + auto const& mls1 = boost::get<1>(tuple1); + auto const& mpo1 = boost::get<2>(tuple1); + auto const& mpt2 = boost::get<0>(tuple2); + auto const& mls2 = boost::get<1>(tuple2); + auto const& mpo2 = boost::get<2>(tuple2); + + // A/A + if (! geometry::is_empty(mpo1) && ! geometry::is_empty(mpo2)) + { + inters_found[0][2] = true; + inters_found[1][2] = true; + aa_handler_wrapper<Result> wrapper(result); + call_relate(mpo1, mpo2, wrapper, strategy); + } + + if (BOOST_GEOMETRY_CONDITION(result.interrupt)) + { + return false; + } + + bool is_aa_ii = result.template get<interior, interior>() != 'F'; + bool is_aa_ie = result.template get<interior, exterior>() != 'F'; + bool is_aa_ei = result.template get<exterior, interior>() != 'F'; + // is_aa_ii implies is_aa_checked and non-empty Areal geometries + bool are_aa_equal = is_aa_ii && ! is_aa_ie && ! is_aa_ei; + + // Boundary checkers are internally initialized lazily later if a point has to be checked + boundary_checker<mls1_t, Strategy> mls1_boundary(mls1, strategy); + boundary_checker<mls2_t, Strategy> mls2_boundary(mls2, strategy); + + // If needed divide MLss into two parts: + // - inside Areal of other GC + // - outside of other GC Areal to check WRT Linear of other GC + mls2_t mls2_diff_mpo1, mls2_inters_mpo1; + bool is_mls2_divided = false; + mls1_t mls1_diff_mpo2, mls1_inters_mpo2; + bool is_mls1_divided = false; + // If Areal are equal then Linear are outside of both so there is no need to divide + if (! are_aa_equal && ! geometry::is_empty(mls1) && ! geometry::is_empty(mls2)) + { + // LA/L + if (! geometry::is_empty(mpo1)) + { + geometry::difference(mls2, mpo1, mls2_diff_mpo1); + geometry::intersection(mls2, mpo1, mls2_inters_mpo1); + is_mls2_divided = true; + } + // L/LA + if (! geometry::is_empty(mpo2)) + { + geometry::difference(mls1, mpo2, mls1_diff_mpo2); + geometry::intersection(mls1, mpo2, mls1_inters_mpo2); + is_mls1_divided = true; + } + } + + // A/L + if (! geometry::is_empty(mpo1) && ! geometry::is_empty(mls2)) + { + inters_found[0][2] = true; + inters_found[1][1] = true; + if (is_aa_ii && ! is_aa_ie && ! is_aa_ei && ! geometry::is_empty(mls1)) + { + // Equal Areal and both Linear non-empty, calculate only L/L below + } + else if (is_aa_ii && ! is_aa_ie && geometry::is_empty(mls1)) + { + // An alternative would be to calculate L/L with one empty below + mpo1_t empty; + call_relate_al(empty, mls2, mls2_boundary, result, strategy); + } + else + { + if (is_mls2_divided) + { + if (! geometry::is_empty(mls2_inters_mpo1)) + { + call_relate_al(mpo1, mls2_inters_mpo1, mls2_boundary, result, strategy); + } + } + else + { + call_relate_al(mpo1, mls2, mls2_boundary, result, strategy); + } + } + } + + if (BOOST_GEOMETRY_CONDITION(result.interrupt)) + { + return false; + } + + // L/A + if (! geometry::is_empty(mls1) && ! geometry::is_empty(mpo2)) + { + inters_found[0][1] = true; + inters_found[1][2] = true; + if (is_aa_ii && ! is_aa_ei && ! is_aa_ie && ! geometry::is_empty(mls2)) + { + // Equal Areal and both Linear non-empty, calculate only L/L below + } + else if (is_aa_ii && ! is_aa_ei && geometry::is_empty(mls2)) + { + // An alternative would be to calculate L/L with one empty below + mpo2_t empty; + call_relate_la(mls1, empty, mls1_boundary, result, strategy); + } + else + { + if (is_mls1_divided) + { + if (! geometry::is_empty(mls1_inters_mpo2)) + { + call_relate_la(mls1_inters_mpo2, mpo2, mls1_boundary, result, strategy); + } + } + else + { + call_relate_la(mls1, mpo2, mls1_boundary, result, strategy); + } + } + } + + if (BOOST_GEOMETRY_CONDITION(result.interrupt)) + { + return false; + } + + // L/L + if (! geometry::is_empty(mls1) && ! geometry::is_empty(mls2)) + { + inters_found[0][1] = true; + inters_found[1][1] = true; + if (is_mls1_divided && is_mls2_divided) + { + if (! geometry::is_empty(mls1_diff_mpo2) && ! geometry::is_empty(mls2_diff_mpo1)) + { + call_relate_ll(mls1_diff_mpo2, mls2_diff_mpo1, mls1_boundary, mls2_boundary, result, strategy); + } + } + else if (is_mls1_divided) + { + if (! geometry::is_empty(mls1_diff_mpo2)) + { + call_relate_ll(mls1_diff_mpo2, mls2, mls1_boundary, mls2_boundary, result, strategy); + } + } + else if (is_mls2_divided) + { + if (! geometry::is_empty(mls2_diff_mpo1)) + { + call_relate_ll(mls1, mls2_diff_mpo1, mls1_boundary, mls2_boundary, result, strategy); + } + } + else + { + call_relate_ll(mls1, mls2, mls1_boundary, mls2_boundary, result, strategy); + } + } + + if (BOOST_GEOMETRY_CONDITION(result.interrupt)) + { + return false; + } + + // A/P + if (! geometry::is_empty(mpo1) && ! geometry::is_empty(mpt2)) + { + inters_found[0][2] = true; + inters_found[1][0] = true; + call_relate(mpo1, mpt2, result, strategy); + } + + if (BOOST_GEOMETRY_CONDITION(result.interrupt)) + { + return false; + } + + // P/A + if (! geometry::is_empty(mpt1) && ! geometry::is_empty(mpo2)) + { + inters_found[0][0] = true; + inters_found[1][2] = true; + call_relate(mpt1, mpo2, result, strategy); + } + + if (BOOST_GEOMETRY_CONDITION(result.interrupt)) + { + return false; + } + + // L/P + if (! geometry::is_empty(mls1) && ! geometry::is_empty(mpt2)) + { + inters_found[0][1] = true; + inters_found[1][0] = true; + call_relate(mls1, mpt2, result, strategy); + } + + if (BOOST_GEOMETRY_CONDITION(result.interrupt)) + { + return false; + } + + // P/L + if (! geometry::is_empty(mpt1) && ! geometry::is_empty(mls2)) + { + inters_found[0][0] = true; + inters_found[1][1] = true; + call_relate(mpt1, mls2, result, strategy); + } + + if (BOOST_GEOMETRY_CONDITION(result.interrupt)) + { + return false; + } + + // P/P + if (! geometry::is_empty(mpt1) && ! geometry::is_empty(mpt2)) + { + inters_found[0][0] = true; + inters_found[1][0] = true; + call_relate(mpt1, mpt2, result, strategy); + } + + if (BOOST_GEOMETRY_CONDITION(result.interrupt)) + { + return false; + } + + return true; + }, + [&](auto const& disjoint_group) + { + for (auto const& id : disjoint_group) + { + BOOST_GEOMETRY_ASSERT(id.source_id == 0 || id.source_id == 1); + if (id.source_id == 0) + { + traits::iter_visit<gc1_view_t>::apply([&](auto const& g1) + { + if (! geometry::is_empty(g1)) + { + static const std::size_t index = kind_id<util::remove_cref_t<decltype(g1)>>::value; + disjoint_found[0][index] = true; + disjoint_linear_boundary_found[0] = has_linear_boundary(g1, strategy); + has_disjoint = true; + } + }, boost::begin(gc1_view) + id.gc_id); + } + else + { + traits::iter_visit<gc2_view_t>::apply([&](auto const& g2) + { + if (! geometry::is_empty(g2)) + { + static const std::size_t index = kind_id<util::remove_cref_t<decltype(g2)>>::value; + disjoint_found[1][index] = true; + disjoint_linear_boundary_found[1] = has_linear_boundary(g2, strategy); + has_disjoint = true; + } + }, boost::begin(gc2_view) + id.gc_id); + } + } + }, true); + + // Based on found disjoint geometries as well as those intersecting set exteriors + if (has_disjoint) + { + if (disjoint_found[0][2] == true) + { + update<interior, exterior, '2'>(result); + update<boundary, exterior, '1'>(result); + } + else if (disjoint_found[0][1] == true) + { + update<interior, exterior, '1'>(result); + if (disjoint_linear_boundary_found[0]) + { + update<boundary, exterior, '0'>(result); + } + } + else if (disjoint_found[0][0] == true) + { + update<interior, exterior, '0'>(result); + } + + if (disjoint_found[1][2] == true) + { + update<exterior, interior, '2'>(result); + update<exterior, boundary, '1'>(result); + } + else if (disjoint_found[1][1] == true) + { + update<exterior, interior, '1'>(result); + if (disjoint_linear_boundary_found[1]) + { + update<exterior, boundary, '0'>(result); + } + } + else if (disjoint_found[1][0] == true) + { + update<exterior, interior, '0'>(result); + } + } + } + +private: + template <typename Tuple, typename Geometry, typename Strategy> + static inline void merge_geometry(Tuple& tuple, Geometry const& geometry, Strategy const& strategy) + { + static const std::size_t index = kind_id<Geometry>::value; + typename boost::tuples::element<index, Tuple>::type temp_out; + geometry::union_(boost::get<index>(tuple), geometry, temp_out, strategy); + boost::get<index>(tuple) = std::move(temp_out); + } + + template <typename Tuple, typename Strategy> + static inline void subtract_elements(Tuple& tuple, Strategy const& strategy) + { + if (! geometry::is_empty(boost::get<1>(tuple))) + { + if (! geometry::is_empty(boost::get<2>(tuple))) + { + typename boost::tuples::element<1, Tuple>::type mls; + geometry::difference(boost::get<1>(tuple), boost::get<2>(tuple), mls, strategy); + boost::get<1>(tuple) = std::move(mls); + } + } + if (! geometry::is_empty(boost::get<0>(tuple))) + { + if (! geometry::is_empty(boost::get<2>(tuple))) + { + typename boost::tuples::element<0, Tuple>::type mpt; + geometry::difference(boost::get<0>(tuple), boost::get<2>(tuple), mpt, strategy); + boost::get<0>(tuple) = std::move(mpt); + } + if (! geometry::is_empty(boost::get<1>(tuple))) + { + typename boost::tuples::element<0, Tuple>::type mpt; + geometry::difference(boost::get<0>(tuple), boost::get<1>(tuple), mpt, strategy); + boost::get<0>(tuple) = std::move(mpt); + } + } + } + + template + < + typename Geometry, typename Strategy, + std::enable_if_t<util::is_linear<Geometry>::value, int> = 0 + > + static inline bool has_linear_boundary(Geometry const& geometry, Strategy const& strategy) + { + topology_check<Geometry, Strategy> tc(geometry, strategy); + return tc.has_boundary(); + } + + template + < + typename Geometry, typename Strategy, + std::enable_if_t<! util::is_linear<Geometry>::value, int> = 0 + > + static inline bool has_linear_boundary(Geometry const& , Strategy const& ) + { + return false; + } + + + template <typename Multi1, typename Multi2, typename Result, typename Strategy> + static inline void call_relate(Multi1 const& multi1, Multi2 const& multi2, + Result& result, Strategy const& strategy) + { + dispatch::relate + < + Multi1, Multi2 + >::apply(multi1, multi2, result, strategy); + } + + template <typename MLs, typename MPo, typename MLsBoundary, typename Result, typename Strategy> + static inline void call_relate_la(MLs const& mls, MPo const& mpo, + MLsBoundary const& mls_boundary, + Result& result, Strategy const& strategy) + { + linear_areal<MLs, MPo>::apply(mls, mpo, mls_boundary, result, strategy); + } + + template <typename MPo, typename MLs, typename MLsBoundary, typename Result, typename Strategy> + static inline void call_relate_al(MPo const& mls, MLs const& mpo, + MLsBoundary const& mls_boundary, + Result& result, Strategy const& strategy) + { + areal_linear<MPo, MLs>::apply(mls, mpo, mls_boundary, result, strategy); + } + + template <typename MLs1, typename MLs2, typename MLs1Boundary, typename MLs2Boundary, typename Result, typename Strategy> + static inline void call_relate_ll(MLs1 const& mls1, MLs2 const& mls2, + MLs1Boundary const& mls1_boundary, + MLs2Boundary const& mls2_boundary, + Result& result, Strategy const& strategy) + { + linear_linear<MLs1, MLs2>::apply(mls1, mls2, mls1_boundary, mls2_boundary, + result, strategy); + } + + +}; + + +}} // namespace detail::relate +#endif // DOXYGEN_NO_DETAIL + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch { + +template <typename Geometry1, typename Geometry2> +struct relate<Geometry1, Geometry2, geometry_collection_tag, geometry_collection_tag, -1, -1, false> + : detail::relate::gc_gc<Geometry1, Geometry2> +{}; + + +template <typename Geometry1, typename Geometry2, typename Tag1, int TopDim1> +struct relate<Geometry1, Geometry2, Tag1, geometry_collection_tag, TopDim1, -1, false> +{ + static const bool interruption_enabled = true; + + template <typename Result, typename Strategy> + static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2, + Result & result, + Strategy const& strategy) + { + using gc1_view_t = detail::geometry_collection_view<Geometry1>; + relate<gc1_view_t, Geometry2>::apply(gc1_view_t(geometry1), geometry2, result, strategy); + } +}; + +template <typename Geometry1, typename Geometry2, typename Tag2, int TopDim2> +struct relate<Geometry1, Geometry2, geometry_collection_tag, Tag2, -1, TopDim2, false> +{ + static const bool interruption_enabled = true; + + template <typename Result, typename Strategy> + static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2, + Result & result, + Strategy const& strategy) + { + using gc2_view_t = detail::geometry_collection_view<Geometry2>; + relate<Geometry1, gc2_view_t>::apply(geometry1, gc2_view_t(geometry2), result, strategy); + } +}; + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_IMPLEMENTATION_HPP diff --git a/boost/geometry/algorithms/detail/relate/interface.hpp b/boost/geometry/algorithms/detail/relate/interface.hpp index 801ad21db1..19568a870e 100644 --- a/boost/geometry/algorithms/detail/relate/interface.hpp +++ b/boost/geometry/algorithms/detail/relate/interface.hpp @@ -2,8 +2,8 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. -// This file was modified by Oracle on 2013-2020. -// Modifications copyright (c) 2013-2020 Oracle and/or its affiliates. +// This file was modified by Oracle on 2013-2022. +// Modifications copyright (c) 2013-2022 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -17,16 +17,13 @@ #include <tuple> -#include <boost/variant/apply_visitor.hpp> -#include <boost/variant/static_visitor.hpp> -#include <boost/variant/variant_fwd.hpp> - #include <boost/geometry/algorithms/detail/relate/de9im.hpp> #include <boost/geometry/algorithms/not_implemented.hpp> #include <boost/geometry/core/coordinate_dimension.hpp> #include <boost/geometry/core/tag.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/core/topological_dimension.hpp> +#include <boost/geometry/geometries/adapted/boost_variant.hpp> #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/strategies/default_strategy.hpp> #include <boost/geometry/strategies/detail.hpp> @@ -160,8 +157,8 @@ struct result_handler_type<Geometry1, Geometry2, util::type_sequence<StaticMasks }} // namespace detail::relate #endif // DOXYGEN_NO_DETAIL -namespace resolve_strategy { - +namespace resolve_strategy +{ template < @@ -217,7 +214,7 @@ struct relate<default_strategy, false> Geometry1, Geometry2 >::type strategy_type; - + dispatch::relate < Geometry1, @@ -228,9 +225,15 @@ struct relate<default_strategy, false> } // resolve_strategy -namespace resolve_variant { +namespace resolve_dynamic +{ -template <typename Geometry1, typename Geometry2> +template +< + typename Geometry1, typename Geometry2, + typename Tag1 = typename geometry::tag<Geometry1>::type, + typename Tag2 = typename geometry::tag<Geometry2>::type +> struct relate { template <typename Mask, typename Strategy> @@ -256,109 +259,73 @@ struct relate } }; -template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2> -struct relate<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2> +template <typename Geometry1, typename Geometry2, typename Tag2> +struct relate<Geometry1, Geometry2, dynamic_geometry_tag, Tag2> { template <typename Mask, typename Strategy> - struct visitor : boost::static_visitor<bool> + static inline bool apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Mask const& mask, + Strategy const& strategy) { - Geometry2 const& m_geometry2; - Mask const& m_mask; - Strategy const& m_strategy; - - visitor(Geometry2 const& geometry2, Mask const& mask, Strategy const& strategy) - : m_geometry2(geometry2), m_mask(mask), m_strategy(strategy) {} - - template <typename Geometry1> - bool operator()(Geometry1 const& geometry1) const + bool result = false; + traits::visit<Geometry1>::apply([&](auto const& g1) { - return relate<Geometry1, Geometry2> - ::apply(geometry1, m_geometry2, m_mask, m_strategy); - } - }; - - template <typename Mask, typename Strategy> - static inline bool - apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1, - Geometry2 const& geometry2, - Mask const& mask, - Strategy const& strategy) - { - return boost::apply_visitor(visitor<Mask, Strategy>(geometry2, mask, strategy), geometry1); + result = relate + < + util::remove_cref_t<decltype(g1)>, + Geometry2 + >::apply(g1, geometry2, mask, strategy); + }, geometry1); + return result; } }; -template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)> -struct relate<Geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > +template <typename Geometry1, typename Geometry2, typename Tag1> +struct relate<Geometry1, Geometry2, Tag1, dynamic_geometry_tag> { template <typename Mask, typename Strategy> - struct visitor : boost::static_visitor<bool> + static inline bool apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Mask const& mask, + Strategy const& strategy) { - Geometry1 const& m_geometry1; - Mask const& m_mask; - Strategy const& m_strategy; - - visitor(Geometry1 const& geometry1, Mask const& mask, Strategy const& strategy) - : m_geometry1(geometry1), m_mask(mask), m_strategy(strategy) {} - - template <typename Geometry2> - bool operator()(Geometry2 const& geometry2) const + bool result = false; + traits::visit<Geometry2>::apply([&](auto const& g2) { - return relate<Geometry1, Geometry2> - ::apply(m_geometry1, geometry2, m_mask, m_strategy); - } - }; - - template <typename Mask, typename Strategy> - static inline bool - apply(Geometry1 const& geometry1, - boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2, - Mask const& mask, - Strategy const& strategy) - { - return boost::apply_visitor(visitor<Mask, Strategy>(geometry1, mask, strategy), geometry2); + result = relate + < + Geometry1, + util::remove_cref_t<decltype(g2)> + >::apply(geometry1, g2, mask, strategy); + }, geometry2); + return result; } }; -template < - BOOST_VARIANT_ENUM_PARAMS(typename T1), - BOOST_VARIANT_ENUM_PARAMS(typename T2) -> -struct relate< - boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>, - boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> -> +template <typename Geometry1, typename Geometry2> +struct relate<Geometry1, Geometry2, dynamic_geometry_tag, dynamic_geometry_tag> { template <typename Mask, typename Strategy> - struct visitor : boost::static_visitor<bool> + static inline bool apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Mask const& mask, + Strategy const& strategy) { - Mask const& m_mask; - Strategy const& m_strategy; - - visitor(Mask const& mask, Strategy const& strategy) - : m_mask(mask), m_strategy(strategy) {} - - template <typename Geometry1, typename Geometry2> - bool operator()(Geometry1 const& geometry1, - Geometry2 const& geometry2) const + bool result = false; + traits::visit<Geometry1, Geometry2>::apply([&](auto const& g1, auto const& g2) { - return relate<Geometry1, Geometry2> - ::apply(geometry1, geometry2, m_mask, m_strategy); - } - }; - - template <typename Mask, typename Strategy> - static inline bool - apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1, - boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2, - Mask const& mask, - Strategy const& strategy) - { - return boost::apply_visitor(visitor<Mask, Strategy>(mask, strategy), geometry1, geometry2); + result = relate + < + util::remove_cref_t<decltype(g1)>, + util::remove_cref_t<decltype(g2)> + >::apply(g1, g2, mask, strategy); + }, geometry1, geometry2); + return result; } }; -} // namespace resolve_variant +} // namespace resolve_dynamic /*! \brief Checks relation between a pair of geometries defined by a mask. @@ -382,7 +349,7 @@ inline bool relate(Geometry1 const& geometry1, Mask const& mask, Strategy const& strategy) { - return resolve_variant::relate + return resolve_dynamic::relate < Geometry1, Geometry2 @@ -407,7 +374,7 @@ inline bool relate(Geometry1 const& geometry1, Geometry2 const& geometry2, Mask const& mask) { - return resolve_variant::relate + return resolve_dynamic::relate < Geometry1, Geometry2 diff --git a/boost/geometry/algorithms/detail/relate/linear_areal.hpp b/boost/geometry/algorithms/detail/relate/linear_areal.hpp index e32c4afcba..1e35e64fc5 100644 --- a/boost/geometry/algorithms/detail/relate/linear_areal.hpp +++ b/boost/geometry/algorithms/detail/relate/linear_areal.hpp @@ -1,10 +1,10 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2023 Adam Wulkiewicz, Lodz, Poland. -// This file was modified by Oracle on 2013-2021. -// Modifications copyright (c) 2013-2021 Oracle and/or its affiliates. - +// This file was modified by Oracle on 2013-2022. +// Modifications copyright (c) 2013-2022 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, @@ -34,6 +34,8 @@ #include <boost/geometry/algorithms/detail/relate/boundary_checker.hpp> #include <boost/geometry/algorithms/detail/relate/follow_helpers.hpp> +#include <boost/geometry/geometries/helper_geometry.hpp> + #include <boost/geometry/views/detail/closed_clockwise_view.hpp> namespace boost { namespace geometry @@ -51,7 +53,7 @@ template < typename Geometry2, typename Result, - typename PointInArealStrategy, + typename Strategy, typename BoundaryChecker, bool TransposeResult > @@ -60,11 +62,11 @@ class no_turns_la_linestring_pred public: no_turns_la_linestring_pred(Geometry2 const& geometry2, Result & res, - PointInArealStrategy const& point_in_areal_strategy, + Strategy const& strategy, BoundaryChecker const& boundary_checker) : m_geometry2(geometry2) , m_result(res) - , m_point_in_areal_strategy(point_in_areal_strategy) + , m_strategy(strategy) , m_boundary_checker(boundary_checker) , m_interrupt_flags(0) { @@ -93,7 +95,7 @@ public: bool operator()(Linestring const& linestring) { std::size_t const count = boost::size(linestring); - + // invalid input if ( count < 2 ) { @@ -110,7 +112,7 @@ public: int const pig = detail::within::point_in_geometry(range::front(linestring), m_geometry2, - m_point_in_areal_strategy); + m_strategy); //BOOST_GEOMETRY_ASSERT_MSG(pig != 0, "There should be no IPs"); if ( pig > 0 ) @@ -125,11 +127,9 @@ public: } // check if there is a boundary - if ( ( m_interrupt_flags & 0xC ) != 0xC // if wasn't already set - && ( m_boundary_checker.template - is_endpoint_boundary<boundary_front>(range::front(linestring)) - || m_boundary_checker.template - is_endpoint_boundary<boundary_back>(range::back(linestring)) ) ) + if ((m_interrupt_flags & 0xC) != 0xC // if wasn't already set + && (m_boundary_checker.is_endpoint_boundary(range::front(linestring)) + || m_boundary_checker.is_endpoint_boundary(range::back(linestring)))) { if ( pig > 0 ) { @@ -150,7 +150,7 @@ public: private: Geometry2 const& m_geometry2; Result & m_result; - PointInArealStrategy const& m_point_in_areal_strategy; + Strategy const& m_strategy; BoundaryChecker const& m_boundary_checker; unsigned m_interrupt_flags; }; @@ -177,9 +177,9 @@ public: // TODO: // handle empty/invalid geometries in a different way than below? - typedef typename geometry::point_type<Areal>::type point_type; - point_type dummy; - bool const ok = boost::geometry::point_on_border(dummy, areal); + using point_type = typename geometry::point_type<Areal>::type; + typename helper_geometry<point_type>::type pt; + bool const ok = geometry::point_on_border(pt, areal); // TODO: for now ignore, later throw an exception? if ( !ok ) @@ -189,7 +189,7 @@ public: update<interior, exterior, '2', TransposeResult>(m_result); update<boundary, exterior, '1', TransposeResult>(m_result); - + return false; } @@ -198,6 +198,129 @@ private: bool const interrupt; }; + +template <typename It, typename Strategy> +inline It find_next_non_duplicated(It first, It current, It last, Strategy const& strategy) +{ + BOOST_GEOMETRY_ASSERT(current != last); + + It it = current; + for (++it ; it != last ; ++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, strategy)) + { + return it; + } + } + + return current; +} + +// calculate inside or outside based on side_calc +// this is simplified version of a check from equal<> +template +< + typename Pi, typename Pj, typename Pk, + typename Qi, typename Qj, typename Qk, + typename Strategy +> +inline bool calculate_from_inside_sides(Pi const& pi, Pj const& pj, Pk const& pk, + Qi const& , Qj const& qj, Qk const& qk, + Strategy const& strategy) +{ + auto const side_strategy = strategy.side(); + + int const side_pk_p = side_strategy.apply(pi, pj, pk); + int const side_qk_p = side_strategy.apply(pi, pj, qk); + // If they turn to same side (not opposite sides) + if (! overlay::base_turn_handler::opposite(side_pk_p, side_qk_p)) + { + int const side_pk_q2 = side_strategy.apply(qj, qk, pk); + return side_pk_q2 == -1; + } + else + { + return side_pk_p == -1; + } +} + +// check if the passed turn's segment of Linear geometry arrived +// from the inside or the outside of the Areal geometry +template +< + std::size_t OpId, + typename Geometry1, typename Geometry2, + typename Turn, typename Strategy +> +inline bool calculate_from_inside(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Turn const& turn, + Strategy const& strategy) +{ + static const std::size_t op_id = OpId; + static const std::size_t other_op_id = (OpId + 1) % 2; + + if (turn.operations[op_id].position == overlay::position_front) + { + return false; + } + + auto const& range1 = sub_range(geometry1, turn.operations[op_id].seg_id); + + using range2_view = detail::closed_clockwise_view<typename ring_type<Geometry2>::type const>; + range2_view const range2(sub_range(geometry2, turn.operations[other_op_id].seg_id)); + + BOOST_GEOMETRY_ASSERT(boost::size(range1)); + std::size_t const s2 = boost::size(range2); + BOOST_GEOMETRY_ASSERT(s2 > 2); + std::size_t const seg_count2 = s2 - 1; + + std::size_t const p_seg_ij = static_cast<std::size_t>(turn.operations[op_id].seg_id.segment_index); + std::size_t const q_seg_ij = static_cast<std::size_t>(turn.operations[other_op_id].seg_id.segment_index); + + BOOST_GEOMETRY_ASSERT(p_seg_ij + 1 < boost::size(range1)); + BOOST_GEOMETRY_ASSERT(q_seg_ij + 1 < s2); + + auto const& pi = range::at(range1, p_seg_ij); + auto const& qi = range::at(range2, q_seg_ij); + auto const& qj = range::at(range2, q_seg_ij + 1); + + bool const is_ip_qj = equals::equals_point_point(turn.point, qj, strategy); + // TODO: test this! + // BOOST_GEOMETRY_ASSERT(!equals::equals_point_point(turn.point, pi)); + // BOOST_GEOMETRY_ASSERT(!equals::equals_point_point(turn.point, qi)); + + if (is_ip_qj) + { + std::size_t const q_seg_jk = (q_seg_ij + 1) % seg_count2; + // TODO: the following function should return immediately, however the worst case complexity is O(N) + // It would be good to replace it with some O(1) mechanism + auto qk_it = find_next_non_duplicated(boost::begin(range2), + range::pos(range2, q_seg_jk), + boost::end(range2), + strategy); + + // Calculate sides in a different point order for P and Q + // Will this sequence of points be always correct? + return calculate_from_inside_sides(qi, turn.point, pi, qi, qj, *qk_it, strategy); + } + else + { + // Calculate sides with different points for P and Q + return calculate_from_inside_sides(qi, turn.point, pi, qi, turn.point, qj, strategy); + } +} + + // The implementation of an algorithm calculating relate() for L/A template <typename Geometry1, typename Geometry2, bool TransposeResult = false> struct linear_areal @@ -208,9 +331,6 @@ struct linear_areal static const bool interruption_enabled = true; - typedef typename geometry::point_type<Geometry1>::type point1_type; - typedef typename geometry::point_type<Geometry2>::type point2_type; - template <typename Geom1, typename Geom2, typename Strategy> struct multi_turn_info : turns::get_turns<Geom1, Geom2>::template turn_info_type<Strategy>::type @@ -228,45 +348,49 @@ struct linear_areal typename turns::get_turns<Geom1, Geom2>::template turn_info_type<Strategy>::type > {}; - + template <typename Result, typename Strategy> static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Result & result, Strategy const& strategy) { -// TODO: If Areal geometry may have infinite size, change the following line: + boundary_checker<Geometry1, Strategy> boundary_checker1(geometry1, strategy); + apply(geometry1, geometry2, boundary_checker1, result, strategy); + } + + template <typename BoundaryChecker1, typename Result, typename Strategy> + static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2, + BoundaryChecker1 const& boundary_checker1, + Result & result, + Strategy const& strategy) + { + // TODO: If Areal geometry may have infinite size, change the following line: - // The result should be FFFFFFFFF - relate::set<exterior, exterior, result_dimension<Geometry2>::value, TransposeResult>(result);// FFFFFFFFd, d in [1,9] or T + update<exterior, exterior, result_dimension<Geometry2>::value, TransposeResult>(result);// FFFFFFFFd, d in [1,9] or T if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) ) + { return; + } // get and analyse turns - typedef typename turn_info_type<Geometry1, Geometry2, Strategy>::type turn_type; + using turn_type = typename turn_info_type<Geometry1, Geometry2, Strategy>::type; std::vector<turn_type> turns; interrupt_policy_linear_areal<Geometry2, Result> interrupt_policy(geometry2, result); turns::get_turns<Geometry1, Geometry2>::apply(turns, geometry1, geometry2, interrupt_policy, strategy); if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) ) + { return; - - typedef typename Strategy::cs_tag cs_tag; - - typedef boundary_checker - < - Geometry1, - Strategy - > boundary_checker1_type; - boundary_checker1_type boundary_checker1(geometry1, strategy); + } no_turns_la_linestring_pred < Geometry2, Result, Strategy, - boundary_checker1_type, + BoundaryChecker1, TransposeResult > pred1(geometry2, result, @@ -274,24 +398,32 @@ struct linear_areal boundary_checker1); for_each_disjoint_geometry_if<0, Geometry1>::apply(turns.begin(), turns.end(), geometry1, pred1); if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) ) + { return; + } no_turns_la_areal_pred<Result, !TransposeResult> pred2(result); for_each_disjoint_geometry_if<1, Geometry2>::apply(turns.begin(), turns.end(), geometry2, pred2); if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) ) + { return; - + } + if ( turns.empty() ) + { return; + } // This is set here because in the case if empty Areal geometry were passed // those shouldn't be set - relate::set<exterior, interior, '2', TransposeResult>(result);// FFFFFF2Fd + update<exterior, interior, '2', TransposeResult>(result);// FFFFFF2Fd if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) ) + { return; + } { - sort_dispatch<cs_tag>(turns.begin(), turns.end(), util::is_multi<Geometry2>()); + sort_dispatch(turns.begin(), turns.end(), strategy, util::is_multi<Geometry2>()); turns_analyser<turn_type> analyser; analyse_each_turn(result, analyser, @@ -301,13 +433,15 @@ struct linear_areal strategy); if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) ) + { return; + } } // If 'c' (insersection_boundary) was not found we know that any Ls isn't equal to one of the Rings if ( !interrupt_policy.is_boundary_found ) { - relate::set<exterior, boundary, '1', TransposeResult>(result); + update<exterior, boundary, '1', TransposeResult>(result); } // Don't calculate it if it's required else if ( may_update<exterior, boundary, '1', TransposeResult>(result) ) @@ -323,12 +457,9 @@ struct linear_areal // sort by multi_index and rind_index std::sort(turns.begin(), turns.end(), less_ring()); - typedef typename std::vector<turn_type>::iterator turn_iterator; - - turn_iterator it = turns.begin(); segment_identifier * prev_seg_id_ptr = NULL; // for each ring - for ( ; it != turns.end() ; ) + for (auto it = turns.begin() ; it != turns.end() ; ) { // it's the next single geometry if ( prev_seg_id_ptr == NULL @@ -338,7 +469,7 @@ struct linear_areal if ( it->operations[1].seg_id.ring_index > -1 ) { // we can be sure that the exterior overlaps the boundary - relate::set<exterior, boundary, '1', TransposeResult>(result); + update<exterior, boundary, '1', TransposeResult>(result); break; } // if there was some previous ring @@ -346,14 +477,14 @@ struct linear_areal { signed_size_type const next_ring_index = prev_seg_id_ptr->ring_index + 1; BOOST_GEOMETRY_ASSERT(next_ring_index >= 0); - + // if one of the last rings of previous single geometry was ommited if ( static_cast<std::size_t>(next_ring_index) < geometry::num_interior_rings( single_geometry(geometry2, *prev_seg_id_ptr)) ) { // we can be sure that the exterior overlaps the boundary - relate::set<exterior, boundary, '1', TransposeResult>(result); + update<exterior, boundary, '1', TransposeResult>(result); break; } } @@ -366,7 +497,7 @@ struct linear_areal && prev_seg_id_ptr->ring_index + 1 < it->operations[1].seg_id.ring_index ) { // we can be sure that the exterior overlaps the boundary - relate::set<exterior, boundary, '1', TransposeResult>(result); + update<exterior, boundary, '1', TransposeResult>(result); break; } } @@ -375,25 +506,25 @@ struct linear_areal // find the next ring first iterator and check if the analysis should be performed has_boundary_intersection has_boundary_inters; - turn_iterator next = find_next_ring(it, turns.end(), has_boundary_inters); + auto next = find_next_ring(it, turns.end(), has_boundary_inters); // if there is no 1d overlap with the boundary if ( !has_boundary_inters.result ) { // we can be sure that the exterior overlaps the boundary - relate::set<exterior, boundary, '1', TransposeResult>(result); + update<exterior, boundary, '1', TransposeResult>(result); break; } // else there is 1d overlap with the boundary so we must analyse the boundary else { // u, c - typedef turns::less<1, turns::less_op_areal_linear<1>, cs_tag> less; - std::sort(it, next, less()); + using less_t = turns::less<1, turns::less_op_areal_linear<1>, Strategy>; + std::sort(it, next, less_t()); // analyse areal_boundary_analyser<turn_type> analyser; - for ( turn_iterator rit = it ; rit != next ; ++rit ) + for (auto rit = it ; rit != next ; ++rit) { // if the analyser requests, break the search if ( !analyser.apply(it, rit, next, strategy) ) @@ -404,7 +535,7 @@ struct linear_areal if ( analyser.is_union_detected ) { // we can be sure that the boundary of Areal overlaps the exterior of Linear - relate::set<exterior, boundary, '1', TransposeResult>(result); + update<exterior, boundary, '1', TransposeResult>(result); break; } } @@ -424,7 +555,7 @@ struct linear_areal single_geometry(geometry2, *prev_seg_id_ptr)) ) { // we can be sure that the exterior overlaps the boundary - relate::set<exterior, boundary, '1', TransposeResult>(result); + update<exterior, boundary, '1', TransposeResult>(result); } } } @@ -434,7 +565,9 @@ struct linear_areal static void for_each_equal_range(It first, It last, Pred pred, Comp comp) { if ( first == last ) + { return; + } It first_equal = first; It prev = first; @@ -445,9 +578,11 @@ struct linear_areal pred(first_equal, first); first_equal = first; } - + if ( first == last ) + { break; + } } } @@ -516,12 +651,13 @@ struct linear_areal } }; - template <typename CSTag, typename TurnIt> - static void sort_dispatch(TurnIt first, TurnIt last, std::true_type const& /*is_multi*/) + template <typename TurnIt, typename Strategy> + static void sort_dispatch(TurnIt first, TurnIt last, Strategy const& , + std::true_type const& /*is_multi*/) { // sort turns by Linear seg_id, then by fraction, then by other multi_index - typedef turns::less<0, turns::less_other_multi_index<0>, CSTag> less; - std::sort(first, last, less()); + using less_t = turns::less<0, turns::less_other_multi_index<0>, Strategy>; + std::sort(first, last, less_t()); // For the same IP and multi_index - the same other's single geometry // set priorities as the least operation found for the whole single geometry @@ -534,22 +670,23 @@ struct linear_areal // When priorities for single geometries are set now sort turns for the same IP // if multi_index is the same sort them according to the single-less // else use priority of the whole single-geometry set earlier - typedef turns::less<0, turns::less_op_linear_areal_single<0>, CSTag> single_less; + using single_less_t = turns::less<0, turns::less_op_linear_areal_single<0>, Strategy>; for_each_equal_range(first, last, - sort_turns_group<single_less>(), + sort_turns_group<single_less_t>(), same_ip()); } - template <typename CSTag, typename TurnIt> - static void sort_dispatch(TurnIt first, TurnIt last, std::false_type const& /*is_multi*/) + template <typename TurnIt, typename Strategy> + static void sort_dispatch(TurnIt first, TurnIt last, Strategy const& , + std::false_type const& /*is_multi*/) { // sort turns by Linear seg_id, then by fraction, then // for same ring id: x, u, i, c // for different ring id: c, i, u, x - typedef turns::less<0, turns::less_op_linear_areal_single<0>, CSTag> less; - std::sort(first, last, less()); + using less_t = turns::less<0, turns::less_op_linear_areal_single<0>, Strategy>; + std::sort(first, last, less_t()); } - + // interrupt policy which may be passed to get_turns to interrupt the analysis // based on the info in the passed result/mask @@ -569,9 +706,7 @@ struct linear_areal template <typename Range> inline bool apply(Range const& turns) { - typedef typename boost::range_iterator<Range const>::type iterator; - - for (iterator it = boost::begin(turns) ; it != boost::end(turns) ; ++it) + for (auto it = boost::begin(turns) ; it != boost::end(turns) ; ++it) { if ( it->operations[0].operation == overlay::operation_intersection ) { @@ -619,39 +754,6 @@ 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 Strategy, - typename Pi = PointP, typename Pj = PointP, typename Pk = PointP, - typename Qi = PointQ, typename Qj = PointQ, typename Qk = PointQ - > - struct la_side_calculator - { - typedef decltype(std::declval<Strategy>().side()) side_strategy_type; - - inline la_side_calculator(Pi const& pi, Pj const& pj, Pk const& pk, - Qi const& qi, Qj const& qj, Qk const& qk, - Strategy const& strategy) - : m_pi(pi), m_pj(pj), m_pk(pk) - , m_qi(qi), m_qj(qj), m_qk(qk) - , m_side_strategy(strategy.side()) - {} - - 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; - - side_strategy_type m_side_strategy; - }; - - public: turns_analyser() : m_previous_turn_ptr(NULL) @@ -705,7 +807,7 @@ struct linear_areal strategy) ) { m_exit_watcher.reset_detected_exit(); - + update<interior, exterior, '1', TransposeResult>(res); // next single geometry @@ -714,9 +816,8 @@ struct linear_areal // NOTE: similar code is in the post-last-ip-apply() segment_identifier const& prev_seg_id = m_previous_turn_ptr->operations[op_id].seg_id; - bool const prev_back_b = is_endpoint_on_boundary<boundary_back>( - range::back(sub_range(geometry, prev_seg_id)), - boundary_checker); + bool const prev_back_b = boundary_checker.is_endpoint_boundary( + range::back(sub_range(geometry, prev_seg_id))); // if there is a boundary on the last point if ( prev_back_b ) @@ -790,7 +891,7 @@ struct linear_areal // TODO: THIS IS POTENTIALLY ERROREOUS! // THIS ALGORITHM DEPENDS ON SOME SPECIFIC SEQUENCE OF OPERATIONS // IT WOULD GIVE WRONG RESULTS E.G. -// IN THE CASE OF SELF-TOUCHING POINT WHEN 'i' WOULD BE BEFORE 'u' +// IN THE CASE OF SELF-TOUCHING POINT WHEN 'i' WOULD BE BEFORE 'u' // handle the interior overlap if ( m_interior_detected ) @@ -809,9 +910,8 @@ struct linear_areal { segment_identifier const& prev_seg_id = m_previous_turn_ptr->operations[op_id].seg_id; - bool const prev_back_b = is_endpoint_on_boundary<boundary_back>( - range::back(sub_range(geometry, prev_seg_id)), - boundary_checker); + bool const prev_back_b = boundary_checker.is_endpoint_boundary( + range::back(sub_range(geometry, prev_seg_id))); // if there is a boundary on the last point if ( prev_back_b ) @@ -890,11 +990,8 @@ struct linear_areal update<interior, boundary, '1', TransposeResult>(res); } - bool const this_b - = is_ip_on_boundary<boundary_front>(it->point, - it->operations[op_id], - boundary_checker, - seg_id); + bool const this_b = is_ip_on_boundary(it->point, it->operations[op_id], + boundary_checker); // going inside on boundary point if ( this_b ) { @@ -911,11 +1008,11 @@ struct linear_areal && it->operations[op_id].position != overlay::position_front ) { // TODO: calculate_from_inside() is only needed if the current Linestring is not closed - bool const from_inside = first_point - && calculate_from_inside(geometry, - other_geometry, - *it, - strategy); + bool const from_inside = + first_point && calculate_from_inside<op_id>(geometry, + other_geometry, + *it, + strategy); if ( from_inside ) update<interior, interior, '1', TransposeResult>(res); @@ -925,9 +1022,8 @@ struct linear_areal // if it's the first IP then the first point is outside if ( first_point ) { - bool const front_b = is_endpoint_on_boundary<boundary_front>( - range::front(sub_range(geometry, seg_id)), - boundary_checker); + bool const front_b = boundary_checker.is_endpoint_boundary( + range::front(sub_range(geometry, seg_id))); // if there is a boundary on the first point if ( front_b ) @@ -955,7 +1051,7 @@ struct linear_areal // TODO: is this condition ok? // TODO: move it into the exit_watcher? && m_exit_watcher.get_exit_operation() == overlay::operation_none; - + if ( op == overlay::operation_union ) { if ( m_boundary_counter > 0 && it->operations[op_id].is_collinear ) @@ -974,7 +1070,7 @@ struct linear_areal { // check if this is indeed the boundary point // NOTE: is_ip_on_boundary<>() should be called here but the result will be the same - if ( is_endpoint_on_boundary<boundary_back>(it->point, boundary_checker) ) + if (boundary_checker.is_endpoint_boundary(it->point)) { update<boundary, boundary, '0', TransposeResult>(res); } @@ -989,10 +1085,8 @@ struct linear_areal // we're outside or inside and this is the first turn else { - bool const this_b = is_ip_on_boundary<boundary_any>(it->point, - it->operations[op_id], - boundary_checker, - seg_id); + bool const this_b = is_ip_on_boundary(it->point, it->operations[op_id], + boundary_checker); // if current IP is on boundary of the geometry if ( this_b ) { @@ -1012,11 +1106,11 @@ struct linear_areal // For LS/MultiPolygon multiple x/u turns may be generated // the first checked Polygon may be the one which LS is outside for. bool const first_point = first_in_range || m_first_from_unknown; - bool const first_from_inside = first_point - && calculate_from_inside(geometry, - other_geometry, - *it, - strategy); + bool const first_from_inside = + first_point && calculate_from_inside<op_id>(geometry, + other_geometry, + *it, + strategy); if ( first_from_inside ) { update<interior, interior, '1', TransposeResult>(res); @@ -1044,9 +1138,8 @@ struct linear_areal // first IP on the last segment point - this means that the first point is outside or inside if ( first_point && ( !this_b || op_blocked ) ) { - bool const front_b = is_endpoint_on_boundary<boundary_front>( - range::front(sub_range(geometry, seg_id)), - boundary_checker); + bool const front_b = boundary_checker.is_endpoint_boundary( + range::front(sub_range(geometry, seg_id))); // if there is a boundary on the first point if ( front_b ) @@ -1135,9 +1228,8 @@ struct linear_areal segment_identifier const& prev_seg_id = m_previous_turn_ptr->operations[op_id].seg_id; - bool const prev_back_b = is_endpoint_on_boundary<boundary_back>( - range::back(sub_range(geometry, prev_seg_id)), - boundary_checker); + bool const prev_back_b = boundary_checker.is_endpoint_boundary( + range::back(sub_range(geometry, prev_seg_id))); // if there is a boundary on the last point if ( prev_back_b ) @@ -1158,9 +1250,8 @@ struct linear_areal segment_identifier const& prev_seg_id = m_previous_turn_ptr->operations[op_id].seg_id; - bool const prev_back_b = is_endpoint_on_boundary<boundary_back>( - range::back(sub_range(geometry, prev_seg_id)), - boundary_checker); + bool const prev_back_b = boundary_checker.is_endpoint_boundary( + range::back(sub_range(geometry, prev_seg_id))); // if there is a boundary on the last point if ( prev_back_b ) @@ -1184,9 +1275,8 @@ struct linear_areal segment_identifier const& prev_seg_id = m_previous_turn_ptr->operations[op_id].seg_id; - bool const prev_back_b = is_endpoint_on_boundary<boundary_back>( - range::back(sub_range(geometry, prev_seg_id)), - boundary_checker); + bool const prev_back_b = boundary_checker.is_endpoint_boundary( + range::back(sub_range(geometry, prev_seg_id))); // if there is a boundary on the last point if ( prev_back_b ) @@ -1202,120 +1292,6 @@ struct linear_areal m_first_from_unknown_boundary_detected = false; } - // check if the passed turn's segment of Linear geometry arrived - // from the inside or the outside of the Areal geometry - template <typename Turn, typename Strategy> - static inline bool calculate_from_inside(Geometry1 const& geometry1, - Geometry2 const& geometry2, - Turn const& turn, - Strategy const& strategy) - { - typedef typename cs_tag<typename Turn::point_type>::type cs_tag; - - if ( turn.operations[op_id].position == overlay::position_front ) - return false; - - typename sub_range_return_type<Geometry1 const>::type - range1 = sub_range(geometry1, turn.operations[op_id].seg_id); - - using range2_view = detail::closed_clockwise_view<typename ring_type<Geometry2>::type const>; - using range2_iterator = typename boost::range_iterator<range2_view const>::type; - range2_view const range2(sub_range(geometry2, turn.operations[other_op_id].seg_id)); - - BOOST_GEOMETRY_ASSERT(boost::size(range1)); - std::size_t const s2 = boost::size(range2); - BOOST_GEOMETRY_ASSERT(s2 > 2); - std::size_t const seg_count2 = s2 - 1; - - std::size_t const p_seg_ij = static_cast<std::size_t>(turn.operations[op_id].seg_id.segment_index); - std::size_t const q_seg_ij = static_cast<std::size_t>(turn.operations[other_op_id].seg_id.segment_index); - - BOOST_GEOMETRY_ASSERT(p_seg_ij + 1 < boost::size(range1)); - BOOST_GEOMETRY_ASSERT(q_seg_ij + 1 < s2); - - point1_type const& pi = range::at(range1, p_seg_ij); - point2_type const& qi = range::at(range2, q_seg_ij); - 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, strategy); -// TODO: test this! -// BOOST_GEOMETRY_ASSERT(!equals::equals_point_point(turn.point, pi)); -// BOOST_GEOMETRY_ASSERT(!equals::equals_point_point(turn.point, qi)); - point1_type new_pj; - geometry::convert(turn.point, new_pj); - - if ( is_ip_qj ) - { - std::size_t const q_seg_jk = (q_seg_ij + 1) % seg_count2; -// TODO: the following function should return immediately, however the worst case complexity is O(N) -// 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), - strategy); - - // Will this sequence of points be always correct? - la_side_calculator<cs_tag, point1_type, point2_type, Strategy> - side_calc(qi_conv, new_pj, pi, qi, qj, *qk_it, strategy); - - return calculate_from_inside_sides(side_calc); - } - else - { - point2_type new_qj; - geometry::convert(turn.point, new_qj); - - la_side_calculator<cs_tag, point1_type, point2_type, Strategy> - side_calc(qi_conv, new_pj, pi, qi, new_qj, qj, strategy); - - return calculate_from_inside_sides(side_calc); - } - } - - template <typename It, typename Strategy> - static inline It find_next_non_duplicated(It first, It current, It last, - Strategy const& strategy) - { - BOOST_GEOMETRY_ASSERT( current != last ); - - It it = current; - - for ( ++it ; it != last ; ++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, strategy) ) - return it; - } - - return current; - } - - // calculate inside or outside based on side_calc - // this is simplified version of a check from equal<> - template <typename SideCalc> - static inline bool calculate_from_inside_sides(SideCalc const& side_calc) - { - int const side_pk_p = side_calc.pk_wrt_p1(); - int const side_qk_p = side_calc.qk_wrt_p1(); - // If they turn to same side (not opposite sides) - if (! overlay::base_turn_handler::opposite(side_pk_p, side_qk_p)) - { - int const side_pk_q2 = side_calc.pk_wrt_q2(); - return side_pk_q2 == -1; - } - else - { - return side_pk_p == -1; - } - } - private: exit_watcher<TurnInfo, op_id> m_exit_watcher; segment_watcher<same_single> m_seg_watcher; @@ -1346,7 +1322,9 @@ struct linear_areal Strategy const& strategy) { if ( first == last ) + { return; + } for ( TurnIt it = first ; it != last ; ++it ) { @@ -1356,7 +1334,9 @@ struct linear_areal strategy); if ( BOOST_GEOMETRY_CONDITION( res.interrupt ) ) + { return; + } } analyser.apply(res, first, last, @@ -1472,7 +1452,7 @@ struct linear_areal else { return false; - } + } } bool is_union_detected; @@ -1496,6 +1476,15 @@ struct areal_linear { linear_areal_type::apply(geometry2, geometry1, result, strategy); } + + template <typename BoundaryChecker2, typename Result, typename Strategy> + static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2, + BoundaryChecker2 const& boundary_checker2, + Result & result, + Strategy const& strategy) + { + linear_areal_type::apply(geometry2, geometry1, boundary_checker2, result, strategy); + } }; }} // namespace detail::relate diff --git a/boost/geometry/algorithms/detail/relate/linear_linear.hpp b/boost/geometry/algorithms/detail/relate/linear_linear.hpp index fa46db2459..8a326265af 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, 2018, 2019. -// Modifications copyright (c) 2013-2019 Oracle and/or its affiliates. +// This file was modified by Oracle on 2013-2022. +// Modifications copyright (c) 2013-2022 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -33,6 +33,8 @@ #include <boost/geometry/algorithms/detail/relate/boundary_checker.hpp> #include <boost/geometry/algorithms/detail/relate/follow_helpers.hpp> +#include <boost/geometry/geometries/helper_geometry.hpp> + namespace boost { namespace geometry { @@ -68,7 +70,7 @@ public: } std::size_t const count = boost::size(linestring); - + // invalid input if ( count < 2 ) { @@ -91,11 +93,9 @@ public: m_flags |= 1; // check if there is a boundary - if ( m_flags < 2 - && ( m_boundary_checker.template - is_endpoint_boundary<boundary_front>(range::front(linestring)) - || m_boundary_checker.template - is_endpoint_boundary<boundary_back>(range::back(linestring)) ) ) + if (m_flags < 2 + && (m_boundary_checker.is_endpoint_boundary(range::front(linestring)) + || m_boundary_checker.is_endpoint_boundary(range::back(linestring)))) { update<boundary, exterior, '0', TransposeResult>(m_result); m_flags |= 2; @@ -117,26 +117,33 @@ struct linear_linear { static const bool interruption_enabled = true; - typedef typename geometry::point_type<Geometry1>::type point1_type; - typedef typename geometry::point_type<Geometry2>::type point2_type; - template <typename Result, typename Strategy> static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Result & result, Strategy const& strategy) { - typedef typename Strategy::cs_tag cs_tag; + boundary_checker<Geometry1, Strategy> boundary_checker1(geometry1, strategy); + boundary_checker<Geometry2, Strategy> boundary_checker2(geometry2, strategy); + apply(geometry1, geometry2, boundary_checker1, boundary_checker2, result, strategy); + } + template <typename BoundaryChecker1, typename BoundaryChecker2, typename Result, typename Strategy> + static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2, + BoundaryChecker1 const& boundary_checker1, + BoundaryChecker2 const& boundary_checker2, + Result & result, + Strategy const& strategy) + { // The result should be FFFFFFFFF - relate::set<exterior, exterior, result_dimension<Geometry1>::value>(result);// FFFFFFFFd, d in [1,9] or T + update<exterior, exterior, result_dimension<Geometry1>::value>(result);// FFFFFFFFd, d in [1,9] or T if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) ) return; // get and analyse turns - typedef typename turns::get_turns + using turn_type = typename turns::get_turns < Geometry1, Geometry2 - >::template turn_info_type<Strategy>::type turn_type; + >::template turn_info_type<Strategy>::type; std::vector<turn_type> turns; interrupt_policy_linear_linear<Result> interrupt_policy(result); @@ -151,20 +158,16 @@ struct linear_linear if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) ) return; - typedef boundary_checker<Geometry1, Strategy> boundary_checker1_type; - boundary_checker1_type boundary_checker1(geometry1, strategy); - disjoint_linestring_pred<Result, boundary_checker1_type, false> pred1(result, boundary_checker1); + disjoint_linestring_pred<Result, BoundaryChecker1, 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; - typedef boundary_checker<Geometry2, Strategy> boundary_checker2_type; - boundary_checker2_type boundary_checker2(geometry2, strategy); - disjoint_linestring_pred<Result, boundary_checker2_type, true> pred2(result, boundary_checker2); + disjoint_linestring_pred<Result, BoundaryChecker2, 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; - + if ( turns.empty() ) return; @@ -178,8 +181,8 @@ struct linear_linear || may_update<boundary, boundary, '0'>(result) || may_update<boundary, exterior, '0'>(result) ) { - typedef turns::less<0, turns::less_op_linear_linear<0>, cs_tag> less; - std::sort(turns.begin(), turns.end(), less()); + using less_t = turns::less<0, turns::less_op_linear_linear<0>, Strategy>; + std::sort(turns.begin(), turns.end(), less_t()); turns_analyser<turn_type, 0> analyser; analyse_each_turn(result, analyser, @@ -190,7 +193,7 @@ struct linear_linear if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) ) return; - + if ( may_update<interior, interior, '1', true>(result) || may_update<interior, boundary, '0', true>(result) || may_update<interior, exterior, '1', true>(result) @@ -198,8 +201,8 @@ struct linear_linear || may_update<boundary, boundary, '0', true>(result) || may_update<boundary, exterior, '0', true>(result) ) { - typedef turns::less<1, turns::less_op_linear_linear<1>, cs_tag> less; - std::sort(turns.begin(), turns.end(), less()); + using less_t = turns::less<1, turns::less_op_linear_linear<1>, Strategy>; + std::sort(turns.begin(), turns.end(), less_t()); turns_analyser<turn_type, 1> analyser; analyse_each_turn(result, analyser, @@ -224,9 +227,7 @@ struct linear_linear template <typename Range> inline bool apply(Range const& turns) { - typedef typename boost::range_iterator<Range const>::type iterator; - - for (iterator it = boost::begin(turns) ; it != boost::end(turns) ; ++it) + for (auto it = boost::begin(turns) ; it != boost::end(turns) ; ++it) { if ( it->operations[0].operation == overlay::operation_intersection || it->operations[1].operation == overlay::operation_intersection ) @@ -285,7 +286,6 @@ struct linear_linear overlay::operation_type const op = it->operations[op_id].operation; segment_identifier const& seg_id = it->operations[op_id].seg_id; - segment_identifier const& other_id = it->operations[other_op_id].seg_id; bool const first_in_range = m_seg_watcher.update(seg_id); @@ -296,8 +296,8 @@ struct linear_linear // degenerated turn if ( op == overlay::operation_continue && it->method == overlay::method_none - && m_exit_watcher.is_outside(*it) - /*&& ( m_exit_watcher.get_exit_operation() == overlay::operation_none + && m_exit_watcher.is_outside(*it) + /*&& ( m_exit_watcher.get_exit_operation() == overlay::operation_none || ! turn_on_the_same_ip<op_id>(m_exit_watcher.get_exit_turn(), *it) )*/ ) { // TODO: rewrite the above condition @@ -336,7 +336,7 @@ struct linear_linear boundary_checker.strategy()) ) { m_exit_watcher.reset_detected_exit(); - + // not the last IP update<interior, exterior, '1', transpose_result>(res); } @@ -374,20 +374,16 @@ struct linear_linear update<interior, interior, '1', transpose_result>(res); bool const this_b = it->operations[op_id].position == overlay::position_front // ignore spikes! - && is_ip_on_boundary<boundary_front>(it->point, - it->operations[op_id], - boundary_checker, - seg_id); + && is_ip_on_boundary(it->point, it->operations[op_id], + boundary_checker); // going inside on boundary point // may be front only if ( this_b ) { // may be front and back - bool const other_b = is_ip_on_boundary<boundary_any>(it->point, - it->operations[other_op_id], - other_boundary_checker, - other_id); + bool const other_b = is_ip_on_boundary(it->point, it->operations[other_op_id], + other_boundary_checker); // it's also the boundary of the other geometry if ( other_b ) @@ -413,9 +409,8 @@ struct linear_linear // if it's the first IP then the first point is outside if ( first_in_range ) { - bool const front_b = is_endpoint_on_boundary<boundary_front>( - range::front(sub_range(geometry, seg_id)), - boundary_checker); + bool const front_b = boundary_checker.is_endpoint_boundary( + range::front(sub_range(geometry, seg_id))); // if there is a boundary on the first point if ( front_b ) @@ -461,13 +456,12 @@ struct linear_linear { // check if this is indeed the boundary point // NOTE: is_ip_on_boundary<>() should be called here but the result will be the same - if ( is_endpoint_on_boundary<boundary_back>(it->point, boundary_checker) ) + if (boundary_checker.is_endpoint_boundary(it->point)) { // may be front and back - bool const other_b = is_ip_on_boundary<boundary_any>(it->point, - it->operations[other_op_id], - other_boundary_checker, - other_id); + bool const other_b = is_ip_on_boundary(it->point, + it->operations[other_op_id], + other_boundary_checker); // it's also the boundary of the other geometry if ( other_b ) { @@ -501,9 +495,8 @@ struct linear_linear // it's the first point in range if ( first_in_range ) { - bool const front_b = is_endpoint_on_boundary<boundary_front>( - range::front(sub_range(geometry, seg_id)), - boundary_checker); + bool const front_b = boundary_checker.is_endpoint_boundary( + range::front(sub_range(geometry, seg_id))); // if there is a boundary on the first point if ( front_b ) @@ -515,16 +508,14 @@ struct linear_linear // method other than crosses, check more conditions else { - bool const this_b = is_ip_on_boundary<boundary_any>(it->point, - it->operations[op_id], - boundary_checker, - seg_id); - - bool const other_b = is_ip_on_boundary<boundary_any>(it->point, - it->operations[other_op_id], - other_boundary_checker, - other_id); - + bool const this_b = is_ip_on_boundary(it->point, + it->operations[op_id], + boundary_checker); + + bool const other_b = is_ip_on_boundary(it->point, + it->operations[other_op_id], + other_boundary_checker); + // if current IP is on boundary of the geometry if ( this_b ) { @@ -560,9 +551,8 @@ struct linear_linear && ! m_collinear_spike_exit /*&& !is_collinear*/ ) { - bool const front_b = is_endpoint_on_boundary<boundary_front>( - range::front(sub_range(geometry, seg_id)), - boundary_checker); + bool const front_b = boundary_checker.is_endpoint_boundary( + range::front(sub_range(geometry, seg_id))); // if there is a boundary on the first point if ( front_b ) @@ -570,7 +560,7 @@ struct linear_linear update<boundary, exterior, '0', transpose_result>(res); } } - + } } } @@ -613,15 +603,14 @@ struct linear_linear turn_ptr = m_degenerated_turn_ptr; else if ( m_previous_turn_ptr ) turn_ptr = m_previous_turn_ptr; - + if ( turn_ptr ) { segment_identifier const& prev_seg_id = turn_ptr->operations[op_id].seg_id; //BOOST_GEOMETRY_ASSERT(!boost::empty(sub_range(geometry, prev_seg_id))); - bool const prev_back_b = is_endpoint_on_boundary<boundary_back>( - range::back(sub_range(geometry, prev_seg_id)), - boundary_checker); + bool const prev_back_b = boundary_checker.is_endpoint_boundary( + range::back(sub_range(geometry, prev_seg_id))); // if there is a boundary on the last point if ( prev_back_b ) @@ -659,19 +648,17 @@ struct linear_linear OtherBoundaryChecker const& other_boundary_checker, bool first_in_range) { - 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 - ls2_ref = detail::single_geometry(other_geometry, turn.operations[other_op_id].seg_id); + auto const& ls1 = detail::single_geometry(geometry, turn.operations[op_id].seg_id); + auto const& ls2 = detail::single_geometry(other_geometry, turn.operations[other_op_id].seg_id); // only one of those should be true: if ( turn.operations[op_id].position == overlay::position_front ) { // valid, point-sized - if ( boost::size(ls2_ref) == 2 ) + if ( boost::size(ls2) == 2 ) { - bool const front_b = is_endpoint_on_boundary<boundary_front>(turn.point, boundary_checker); + bool const front_b = boundary_checker.is_endpoint_boundary(turn.point); if ( front_b ) { @@ -691,11 +678,11 @@ struct linear_linear else if ( turn.operations[op_id].position == overlay::position_back ) { // valid, point-sized - if ( boost::size(ls2_ref) == 2 ) + if ( boost::size(ls2) == 2 ) { update<interior, exterior, '1', transpose_result>(res); - bool const back_b = is_endpoint_on_boundary<boundary_back>(turn.point, boundary_checker); + bool const back_b = boundary_checker.is_endpoint_boundary(turn.point); if ( back_b ) { @@ -708,9 +695,9 @@ struct linear_linear if ( first_in_range ) { - //BOOST_GEOMETRY_ASSERT(!boost::empty(ls1_ref)); - bool const front_b = is_endpoint_on_boundary<boundary_front>( - range::front(ls1_ref), boundary_checker); + //BOOST_GEOMETRY_ASSERT(!boost::empty(ls1)); + bool const front_b = boundary_checker.is_endpoint_boundary( + range::front(ls1)); if ( front_b ) { update<boundary, exterior, '0', transpose_result>(res); @@ -725,13 +712,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), + bool const is_point1 = boost::size(ls1) == 2 + && equals::equals_point_point(range::front(ls1), + range::back(ls1), boundary_checker.strategy()); - bool const is_point2 = boost::size(ls2_ref) == 2 - && equals::equals_point_point(range::front(ls2_ref), - range::back(ls2_ref), + bool const is_point2 = boost::size(ls2) == 2 + && equals::equals_point_point(range::front(ls2), + range::back(ls2), other_boundary_checker.strategy()); // if the second one is degenerated @@ -741,9 +728,9 @@ struct linear_linear if ( first_in_range ) { - //BOOST_GEOMETRY_ASSERT(!boost::empty(ls1_ref)); - bool const front_b = is_endpoint_on_boundary<boundary_front>( - range::front(ls1_ref), boundary_checker); + //BOOST_GEOMETRY_ASSERT(!boost::empty(ls1)); + bool const front_b = boundary_checker.is_endpoint_boundary( + range::front(ls1)); if ( front_b ) { update<boundary, exterior, '0', transpose_result>(res); diff --git a/boost/geometry/algorithms/detail/relate/multi_point_geometry.hpp b/boost/geometry/algorithms/detail/relate/multi_point_geometry.hpp index 7da7f2be5e..204a4fe22d 100644 --- a/boost/geometry/algorithms/detail/relate/multi_point_geometry.hpp +++ b/boost/geometry/algorithms/detail/relate/multi_point_geometry.hpp @@ -1,7 +1,8 @@ // Boost.Geometry -// Copyright (c) 2017-2020 Oracle and/or its affiliates. +// Copyright (c) 2014-2023, 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, @@ -94,9 +95,8 @@ struct multi_point_geometry_eb<Geometry, linestring_tag> template <typename Point, typename Strategy> bool apply(Point const& boundary_point, Strategy const& strategy) { - if ( std::find_if(m_points.begin(), m_points.end(), - find_pred<Point, Strategy>(boundary_point, strategy)) - == m_points.end() ) + if ( std::none_of(m_points.begin(), m_points.end(), + find_pred<Point, Strategy>(boundary_point, strategy))) { m_boundary_found = true; return false; @@ -135,7 +135,7 @@ struct multi_point_geometry_eb<Geometry, multi_linestring_tag> template <typename Point, typename Strategy> bool apply(Point const& boundary_point, Strategy const&) { - typedef geometry::less<void, -1, typename Strategy::cs_tag> less_type; + typedef geometry::less<void, -1, Strategy> less_type; if (! std::binary_search(m_points.begin(), m_points.end(), boundary_point, less_type()) ) @@ -159,9 +159,9 @@ struct multi_point_geometry_eb<Geometry, multi_linestring_tag> { typedef typename boost::range_value<MultiPoint>::type point_type; typedef std::vector<point_type> points_type; - typedef geometry::less<void, -1, typename Strategy::cs_tag> less_type; + typedef geometry::less<void, -1, Strategy> less_type; - points_type points(boost::begin(multi_point), boost::end(multi_point)); + points_type points(boost::begin(multi_point), boost::end(multi_point)); std::sort(points.begin(), points.end(), less_type()); boundary_visitor<points_type> visitor(points); @@ -184,13 +184,12 @@ struct multi_point_single_geometry { typedef typename point_type<SingleGeometry>::type point2_type; typedef model::box<point2_type> box2_type; - + box2_type box2; geometry::envelope(single_geometry, box2, strategy); geometry::detail::expand_by_epsilon(box2); - typedef typename boost::range_const_iterator<MultiPoint>::type iterator; - for ( iterator it = boost::begin(multi_point) ; it != boost::end(multi_point) ; ++it ) + for (auto it = boost::begin(multi_point); it != boost::end(multi_point); ++it) { if (! (relate::may_update<interior, interior, '0', Transpose>(result) || relate::may_update<interior, boundary, '0', Transpose>(result) @@ -202,7 +201,7 @@ struct multi_point_single_geometry // The default strategy is enough for Point/Box if (detail::disjoint::disjoint_point_box(*it, box2, strategy)) { - relate::set<interior, exterior, '0', Transpose>(result); + update<interior, exterior, '0', Transpose>(result); } else { @@ -210,15 +209,15 @@ struct multi_point_single_geometry if (in_val > 0) // within { - relate::set<interior, interior, '0', Transpose>(result); + update<interior, interior, '0', Transpose>(result); } else if (in_val == 0) { - relate::set<interior, boundary, '0', Transpose>(result); + update<interior, boundary, '0', Transpose>(result); } else // in_val < 0 - not within { - relate::set<interior, exterior, '0', Transpose>(result); + update<interior, exterior, '0', Transpose>(result); } } @@ -240,7 +239,7 @@ struct multi_point_single_geometry { // TODO: this is not true if a linestring is degenerated to a point // then the interior has topological dimension = 0, not 1 - relate::set<exterior, interior, tc_t::interior, Transpose>(result); + update<exterior, interior, tc_t::interior, Transpose>(result); } if ( relate::may_update<exterior, boundary, tc_t::boundary, Transpose>(result) @@ -248,12 +247,12 @@ struct multi_point_single_geometry { if (multi_point_geometry_eb<SingleGeometry>::apply(multi_point, tc)) { - relate::set<exterior, boundary, tc_t::boundary, Transpose>(result); + update<exterior, boundary, tc_t::boundary, Transpose>(result); } } } - relate::set<exterior, exterior, result_dimension<MultiPoint>::value, Transpose>(result); + update<exterior, exterior, result_dimension<MultiPoint>::value, Transpose>(result); } }; @@ -365,14 +364,18 @@ class multi_point_multi_geometry_ii_ib if (in_val > 0) // within { - relate::set<interior, interior, '0', Transpose>(m_result); + update<interior, interior, '0', Transpose>(m_result); } else if (in_val == 0) { if (m_tc.check_boundary_point(point)) - relate::set<interior, boundary, '0', Transpose>(m_result); + { + update<interior, boundary, '0', Transpose>(m_result); + } else - relate::set<interior, interior, '0', Transpose>(m_result); + { + update<interior, interior, '0', Transpose>(m_result); + } } } @@ -442,7 +445,6 @@ struct multi_point_multi_geometry_ii_ib_ie typedef model::box<point2_type> box2_type; typedef std::pair<box2_type, std::size_t> box_pair_type; typedef std::vector<box_pair_type> boxes_type; - typedef typename boxes_type::const_iterator boxes_iterator; template <typename Result, typename Strategy> static inline void apply(MultiPoint const& multi_point, @@ -463,8 +465,7 @@ struct multi_point_multi_geometry_ii_ib_ie rtree(boxes.begin(), boxes.end(), index_parameters_type(index::rstar<4>(), strategy)); - typedef typename boost::range_const_iterator<MultiPoint>::type iterator; - for ( iterator it = boost::begin(multi_point) ; it != boost::end(multi_point) ; ++it ) + for (auto it = boost::begin(multi_point); it != boost::end(multi_point); ++it) { if (! (relate::may_update<interior, interior, '0', Transpose>(result) || relate::may_update<interior, boundary, '0', Transpose>(result) @@ -479,24 +480,28 @@ struct multi_point_multi_geometry_ii_ib_ie rtree.query(index::intersects(point), std::back_inserter(boxes_found)); bool found_ii_or_ib = false; - for (boxes_iterator bi = boxes_found.begin() ; bi != boxes_found.end() ; ++bi) + for (auto const& box_found : boxes_found) { typename boost::range_value<MultiGeometry>::type const& - single = range::at(multi_geometry, bi->second); + single = range::at(multi_geometry, box_found.second); int in_val = detail::within::point_in_geometry(point, single, strategy); if (in_val > 0) // within { - relate::set<interior, interior, '0', Transpose>(result); + update<interior, interior, '0', Transpose>(result); found_ii_or_ib = true; } else if (in_val == 0) // on boundary of single { if (tc.check_boundary_point(point)) - relate::set<interior, boundary, '0', Transpose>(result); + { + update<interior, boundary, '0', Transpose>(result); + } else - relate::set<interior, interior, '0', Transpose>(result); + { + update<interior, interior, '0', Transpose>(result); + } found_ii_or_ib = true; } } @@ -504,7 +509,7 @@ struct multi_point_multi_geometry_ii_ib_ie // neither interior nor boundary found -> exterior if (found_ii_or_ib == false) { - relate::set<interior, exterior, '0', Transpose>(result); + update<interior, exterior, '0', Transpose>(result); } if ( BOOST_GEOMETRY_CONDITION(result.interrupt) ) @@ -573,7 +578,7 @@ struct multi_point_multi_geometry { // TODO: this is not true if a linestring is degenerated to a point // then the interior has topological dimension = 0, not 1 - relate::set<exterior, interior, tc_t::interior, Transpose>(result); + update<exterior, interior, tc_t::interior, Transpose>(result); } if ( relate::may_update<exterior, boundary, tc_t::boundary, Transpose>(result) @@ -581,12 +586,12 @@ struct multi_point_multi_geometry { if (multi_point_geometry_eb<MultiGeometry>::apply(multi_point, tc)) { - relate::set<exterior, boundary, tc_t::boundary, Transpose>(result); + update<exterior, boundary, tc_t::boundary, Transpose>(result); } } } - relate::set<exterior, exterior, result_dimension<MultiPoint>::value, Transpose>(result); + update<exterior, exterior, result_dimension<MultiPoint>::value, Transpose>(result); } }; diff --git a/boost/geometry/algorithms/detail/relate/point_geometry.hpp b/boost/geometry/algorithms/detail/relate/point_geometry.hpp index 501c5f3dd6..e570a7209b 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-2020. -// Modifications copyright (c) 2013-2020 Oracle and/or its affiliates. +// This file was modified by Oracle on 2013-2022. +// Modifications copyright (c) 2013-2022 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -14,12 +14,9 @@ #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_POINT_GEOMETRY_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_POINT_GEOMETRY_HPP -#include <boost/geometry/algorithms/detail/within/point_in_geometry.hpp> -//#include <boost/geometry/algorithms/within.hpp> -//#include <boost/geometry/algorithms/covered_by.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> #include <boost/geometry/util/condition.hpp> @@ -44,18 +41,18 @@ struct point_geometry if ( pig > 0 ) // within { - relate::set<interior, interior, '0', Transpose>(result); + update<interior, interior, '0', Transpose>(result); } else if ( pig == 0 ) { - relate::set<interior, boundary, '0', Transpose>(result); + update<interior, boundary, '0', Transpose>(result); } else // pig < 0 - not within { - relate::set<interior, exterior, '0', Transpose>(result); + update<interior, exterior, '0', Transpose>(result); } - relate::set<exterior, exterior, result_dimension<Point>::value, Transpose>(result); + update<exterior, exterior, result_dimension<Point>::value, Transpose>(result); if ( BOOST_GEOMETRY_CONDITION(result.interrupt) ) return; @@ -70,17 +67,21 @@ struct point_geometry { // NOTE: even for MLs, if there is at least one boundary point, // somewhere there must be another one - relate::set<exterior, interior, tc_t::interior, Transpose>(result); - relate::set<exterior, boundary, tc_t::boundary, Transpose>(result); + update<exterior, interior, tc_t::interior, Transpose>(result); + update<exterior, boundary, tc_t::boundary, Transpose>(result); } else { // check if there is a boundary in Geometry tc_t tc(geometry, strategy); if ( tc.has_interior() ) - relate::set<exterior, interior, tc_t::interior, Transpose>(result); + { + update<exterior, interior, tc_t::interior, Transpose>(result); + } if ( tc.has_boundary() ) - relate::set<exterior, boundary, tc_t::boundary, Transpose>(result); + { + update<exterior, boundary, tc_t::boundary, Transpose>(result); + } } } } @@ -168,7 +169,7 @@ struct geometry_point // //} // return result("F0FFFF**T"); // } -// else +// else // { // /*if ( box_has_interior<Box>::apply(box) ) // { @@ -194,7 +195,7 @@ struct geometry_point // return result("0FTFFTFFT"); // else if ( geometry::covered_by(point, box) ) // return result("FF*0F*FFT"); -// else +// else // return result("FF*FFT0FT"); // } //}; diff --git a/boost/geometry/algorithms/detail/relate/point_point.hpp b/boost/geometry/algorithms/detail/relate/point_point.hpp index 7103e2dc92..c987bb44cb 100644 --- a/boost/geometry/algorithms/detail/relate/point_point.hpp +++ b/boost/geometry/algorithms/detail/relate/point_point.hpp @@ -2,9 +2,10 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. -// This file was modified by Oracle on 2013, 2014, 2017, 2018. -// Modifications copyright (c) 2013-2018, Oracle and/or its affiliates. +// This file was modified by Oracle on 2013-2022. +// Modifications copyright (c) 2013-2023, 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, @@ -44,15 +45,15 @@ struct point_point bool equal = detail::equals::equals_point_point(point1, point2, strategy); if ( equal ) { - relate::set<interior, interior, '0'>(result); + update<interior, interior, '0'>(result); } else { - relate::set<interior, exterior, '0'>(result); - relate::set<exterior, interior, '0'>(result); + update<interior, exterior, '0'>(result); + update<exterior, interior, '0'>(result); } - relate::set<exterior, exterior, result_dimension<Point1>::value>(result); + update<exterior, exterior, result_dimension<Point1>::value>(result); } }; @@ -67,20 +68,25 @@ std::pair<bool, bool> point_multipoint_check(Point const& point, // point_in_geometry could be used here but why iterate over MultiPoint twice? // we must search for a point in the exterior because all points in MultiPoint can be equal - typedef typename boost::range_iterator<MultiPoint const>::type iterator; - iterator it = boost::begin(multi_point); - iterator last = boost::end(multi_point); - for ( ; it != last ; ++it ) + + auto const end = boost::end(multi_point); + for (auto it = boost::begin(multi_point); it != end; ++it) { bool ii = detail::equals::equals_point_point(point, *it, strategy); - if ( ii ) + if (ii) + { found_inside = true; + } else + { found_outside = true; + } - if ( found_inside && found_outside ) + if (found_inside && found_outside) + { break; + } } return std::make_pair(found_inside, found_outside); @@ -99,7 +105,7 @@ struct point_multipoint if ( boost::empty(multi_point) ) { // TODO: throw on empty input? - relate::set<interior, exterior, '0', Transpose>(result); + update<interior, exterior, '0', Transpose>(result); return; } @@ -107,20 +113,20 @@ struct point_multipoint if ( rel.first ) // some point of MP is equal to P { - relate::set<interior, interior, '0', Transpose>(result); + update<interior, interior, '0', Transpose>(result); if ( rel.second ) // a point of MP was found outside P { - relate::set<exterior, interior, '0', Transpose>(result); + update<exterior, interior, '0', Transpose>(result); } } else { - relate::set<interior, exterior, '0', Transpose>(result); - relate::set<exterior, interior, '0', Transpose>(result); + update<interior, exterior, '0', Transpose>(result); + update<exterior, interior, '0', Transpose>(result); } - relate::set<exterior, exterior, result_dimension<Point>::value, Transpose>(result); + update<exterior, exterior, result_dimension<Point>::value, Transpose>(result); } }; @@ -148,8 +154,6 @@ struct multipoint_multipoint Result & result, Strategy const& /*strategy*/) { - typedef typename Strategy::cs_tag cs_tag; - { // TODO: throw on empty input? bool empty1 = boost::empty(multi_point1); @@ -160,12 +164,12 @@ struct multipoint_multipoint } else if ( empty1 ) { - relate::set<exterior, interior, '0'>(result); + update<exterior, interior, '0'>(result); return; } else if ( empty2 ) { - relate::set<interior, exterior, '0'>(result); + update<interior, exterior, '0'>(result); return; } } @@ -173,17 +177,17 @@ struct multipoint_multipoint // The geometry containing smaller number of points will be analysed first if ( boost::size(multi_point1) < boost::size(multi_point2) ) { - search_both<false, cs_tag>(multi_point1, multi_point2, result); + search_both<false, Strategy>(multi_point1, multi_point2, result); } else { - search_both<true, cs_tag>(multi_point2, multi_point1, result); + search_both<true, Strategy>(multi_point2, multi_point1, result); } - relate::set<exterior, exterior, result_dimension<MultiPoint1>::value>(result); + update<exterior, exterior, result_dimension<MultiPoint1>::value>(result); } - template <bool Transpose, typename CSTag, typename MPt1, typename MPt2, typename Result> + template <bool Transpose, typename Strategy, typename MPt1, typename MPt2, typename Result> static inline void search_both(MPt1 const& first_sorted_mpt, MPt2 const& first_iterated_mpt, Result & result) { @@ -192,7 +196,7 @@ struct multipoint_multipoint || relate::may_update<exterior, interior, '0'>(result) ) { // NlogN + MlogN - bool is_disjoint = search<Transpose, CSTag>(first_sorted_mpt, first_iterated_mpt, result); + bool is_disjoint = search<Transpose, Strategy>(first_sorted_mpt, first_iterated_mpt, result); if ( BOOST_GEOMETRY_CONDITION(is_disjoint || result.interrupt) ) return; @@ -203,12 +207,12 @@ struct multipoint_multipoint || relate::may_update<exterior, interior, '0'>(result) ) { // MlogM + NlogM - search<! Transpose, CSTag>(first_iterated_mpt, first_sorted_mpt, result); + search<! Transpose, Strategy>(first_iterated_mpt, first_sorted_mpt, result); } } template <bool Transpose, - typename CSTag, + typename Strategy, typename SortedMultiPoint, typename IteratedMultiPoint, typename Result> @@ -218,7 +222,7 @@ struct multipoint_multipoint { // sort points from the 1 MPt typedef typename geometry::point_type<SortedMultiPoint>::type point_type; - typedef geometry::less<void, -1, CSTag> less_type; + typedef geometry::less<void, -1, Strategy> less_type; std::vector<point_type> points(boost::begin(sorted_mpt), boost::end(sorted_mpt)); @@ -229,19 +233,22 @@ struct multipoint_multipoint bool found_outside = false; // for each point in the second MPt - typedef typename boost::range_iterator<IteratedMultiPoint const>::type iterator; - for ( iterator it = boost::begin(iterated_mpt) ; - it != boost::end(iterated_mpt) ; ++it ) + for (auto it = boost::begin(iterated_mpt); it != boost::end(iterated_mpt); ++it) { - bool ii = - std::binary_search(points.begin(), points.end(), *it, less); - if ( ii ) + bool ii = std::binary_search(points.begin(), points.end(), *it, less); + if (ii) + { found_inside = true; + } else + { found_outside = true; + } - if ( found_inside && found_outside ) + if (found_inside && found_outside) + { break; + } } if ( found_inside ) // some point of MP2 is equal to some of MP1 @@ -249,17 +256,17 @@ struct multipoint_multipoint // TODO: if I/I is set for one MPt, this won't be changed when the other one in analysed // so if e.g. only I/I must be analysed we musn't check the other MPt - relate::set<interior, interior, '0', Transpose>(result); + update<interior, interior, '0', Transpose>(result); if ( found_outside ) // some point of MP2 was found outside of MP1 { - relate::set<exterior, interior, '0', Transpose>(result); + update<exterior, interior, '0', Transpose>(result); } } else { - relate::set<interior, exterior, '0', Transpose>(result); - relate::set<exterior, interior, '0', Transpose>(result); + update<interior, exterior, '0', Transpose>(result); + update<exterior, interior, '0', Transpose>(result); } // if no point is intersecting the other MPt then we musn't analyse the reversed case diff --git a/boost/geometry/algorithms/detail/relate/result.hpp b/boost/geometry/algorithms/detail/relate/result.hpp index c7a83665bd..84c342e636 100644 --- a/boost/geometry/algorithms/detail/relate/result.hpp +++ b/boost/geometry/algorithms/detail/relate/result.hpp @@ -1,11 +1,10 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. -// Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland. - -// This file was modified by Oracle on 2013-2020. -// Modifications copyright (c) 2013-2020 Oracle and/or its affiliates. +// Copyright (c) 2017-2023 Adam Wulkiewicz, Lodz, Poland. +// This file was modified by Oracle on 2013-2022. +// Modifications copyright (c) 2013-2022 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, @@ -19,10 +18,10 @@ #include <cstddef> #include <cstring> #include <string> +#include <tuple> #include <type_traits> #include <boost/throw_exception.hpp> -#include <boost/tuple/tuple.hpp> #include <boost/geometry/core/assert.hpp> #include <boost/geometry/core/coordinate_dimension.hpp> @@ -44,6 +43,13 @@ enum field { interior = 0, boundary = 1, exterior = 2 }; // but for safety reasons (STATIC_ASSERT) we should check if parameter D is valid and set() doesn't do that // so some additional function could be added, e.g. set_dim() + +template <typename MatrixOrMask, field F1, field F2> +using fields_in_bounds = util::bool_constant + < + (F1 < MatrixOrMask::static_height && F2 < MatrixOrMask::static_width) + >; + // --------------- MATRIX ---------------- // matrix @@ -60,25 +66,31 @@ public: static const std::size_t static_width = Width; static const std::size_t static_height = Height; static const std::size_t static_size = Width * Height; - + inline matrix() { - ::memset(m_array, 'F', static_size); + std::fill_n(m_array, static_size, 'F'); } - template <field F1, field F2> + template + < + field F1, field F2, + std::enable_if_t<fields_in_bounds<matrix, F1, F2>::value, int> = 0 + > inline char get() const { - BOOST_STATIC_ASSERT(F1 < Height && F2 < Width); static const std::size_t index = F1 * Width + F2; BOOST_STATIC_ASSERT(index < static_size); return m_array[index]; } - template <field F1, field F2, char V> + template + < + field F1, field F2, char V, + std::enable_if_t<fields_in_bounds<matrix, F1, F2>::value, int> = 0 + > inline void set() { - BOOST_STATIC_ASSERT(F1 < Height && F2 < Width); static const std::size_t index = F1 * Width + F2; BOOST_STATIC_ASSERT(index < static_size); m_array[index] = V; @@ -104,7 +116,7 @@ public: { return static_size; } - + inline const char * data() const { return m_array; @@ -151,56 +163,36 @@ public: inline bool may_update() const { BOOST_STATIC_ASSERT('0' <= D && D <= '9'); - char const c = m_matrix.template get<F1, F2>(); return D > c || c > '9'; } template <field F1, field F2, char V> - inline void set() - { - static const bool in_bounds = F1 < Matrix::static_height - && F2 < Matrix::static_width; - typedef std::integral_constant<bool, in_bounds> in_bounds_t; - set_dispatch<F1, F2, V>(in_bounds_t()); - } - - template <field F1, field F2, char D> inline void update() { - static const bool in_bounds = F1 < Matrix::static_height - && F2 < Matrix::static_width; - typedef std::integral_constant<bool, in_bounds> in_bounds_t; - update_dispatch<F1, F2, D>(in_bounds_t()); + BOOST_STATIC_ASSERT(('0' <= V && V <= '9') || V == 'T'); + char const c = m_matrix.template get<F1, F2>(); + // If c == T and V == T it will be set anyway but that's fine + if (V > c || c > '9') + { + m_matrix.template set<F1, F2, V>(); + } } -private: template <field F1, field F2, char V> - inline void set_dispatch(std::true_type) + inline void set() { - static const std::size_t index = F1 * Matrix::static_width + F2; - BOOST_STATIC_ASSERT(index < Matrix::static_size); - BOOST_STATIC_ASSERT(('0' <= V && V <= '9') || V == 'T' || V == 'F'); + BOOST_STATIC_ASSERT(('0' <= V && V <= '9') || V == 'T'); m_matrix.template set<F1, F2, V>(); } - template <field F1, field F2, char V> - inline void set_dispatch(std::false_type) - {} - template <field F1, field F2, char D> - inline void update_dispatch(std::true_type) + template <field F1, field F2> + inline char get() const { - static const std::size_t index = F1 * Matrix::static_width + F2; - BOOST_STATIC_ASSERT(index < Matrix::static_size); - BOOST_STATIC_ASSERT('0' <= D && D <= '9'); - char const c = m_matrix.template get<F1, F2>(); - if ( D > c || c > '9') - m_matrix.template set<F1, F2, D>(); + return m_matrix.template get<F1, F2>(); } - template <field F1, field F2, char D> - inline void update_dispatch(std::false_type) - {} +private: Matrix m_matrix; }; @@ -228,7 +220,7 @@ public: } if ( it != last ) { - ::memset(it, '*', last - it); + std::fill(it, last, '*'); } } @@ -241,18 +233,21 @@ public: if ( count > 0 ) { std::for_each(s, s + count, check_char); - ::memcpy(m_array, s, count); + std::copy_n(s, count, m_array); } if ( count < static_size ) { - ::memset(m_array + count, '*', static_size - count); + std::fill_n(m_array + count, static_size - count, '*'); } } - template <field F1, field F2> + template + < + field F1, field F2, + std::enable_if_t<fields_in_bounds<mask, F1, F2>::value, int> = 0 + > inline char get() const { - BOOST_STATIC_ASSERT(F1 < Height && F2 < Width); static const std::size_t index = F1 * Width + F2; BOOST_STATIC_ASSERT(index < static_size); return m_array[index]; @@ -362,7 +357,7 @@ struct may_update_dispatch BOOST_STATIC_ASSERT('0' <= D && D <= '9'); char const m = mask.template get<F1, F2>(); - + if ( m == 'F' ) { return true; @@ -575,37 +570,41 @@ public: template <field F1, field F2, char D> inline bool may_update() const { - return detail::relate::may_update<F1, F2, D>( - m_mask, base_t::matrix() - ); + return detail::relate::may_update<F1, F2, D>(m_mask, base_t::matrix()); } template <field F1, field F2, char V> - inline void set() + inline void update() { - if ( relate::interrupt<F1, F2, V, Interrupt>(m_mask) ) + if (relate::interrupt<F1, F2, V, Interrupt>(m_mask)) { interrupt = true; } else { - base_t::template set<F1, F2, V>(); + base_t::template update<F1, F2, V>(); } } template <field F1, field F2, char V> - inline void update() + inline void set() { - if ( relate::interrupt<F1, F2, V, Interrupt>(m_mask) ) + if (relate::interrupt<F1, F2, V, Interrupt>(m_mask)) { interrupt = true; } else { - base_t::template update<F1, F2, V>(); + base_t::template set<F1, F2, V>(); } } + template <field F1, field F2> + inline char get() const + { + return base_t::template get<F1, F2>(); + } + private: Mask const& m_mask; }; @@ -647,7 +646,7 @@ struct static_mask BOOST_STATIC_ASSERT( std::size_t(util::sequence_size<Seq>::value) == static_size); - + template <detail::relate::field F1, detail::relate::field F2> struct static_get { @@ -744,7 +743,7 @@ struct static_interrupt_dispatch<StaticMask, V, F1, F2, true, IsSequence> static const char mask_el = StaticMask::template static_get<F1, F2>::value; static const bool value - = ( V >= '0' && V <= '9' ) ? + = ( V >= '0' && V <= '9' ) ? ( mask_el == 'F' || ( mask_el < V && mask_el >= '0' && mask_el <= '9' ) ) : ( ( V == 'T' ) ? mask_el == 'F' : false ); }; @@ -930,7 +929,7 @@ struct static_check_dispatch && per_one<exterior, boundary>::apply(matrix) && per_one<exterior, exterior>::apply(matrix); } - + template <field F1, field F2> struct per_one { @@ -1067,24 +1066,6 @@ public: apply(base_type::matrix()); } - template <field F1, field F2> - static inline bool expects() - { - return static_should_handle_element<StaticMask, F1, F2>::value; - } - - template <field F1, field F2, char V> - inline void set() - { - static const bool interrupt_c = static_interrupt<StaticMask, V, F1, F2, Interrupt>::value; - static const bool should_handle = static_should_handle_element<StaticMask, F1, F2>::value; - static const int version = interrupt_c ? 0 - : should_handle ? 1 - : 2; - - set_dispatch<F1, F2, V>(integral_constant<int, version>()); - } - template <field F1, field F2, char V> inline void update() { @@ -1097,24 +1078,33 @@ public: update_dispatch<F1, F2, V>(integral_constant<int, version>()); } -private: - // Interrupt && interrupt - template <field F1, field F2, char V> - inline void set_dispatch(integral_constant<int, 0>) + template + < + field F1, field F2, char V, + std::enable_if_t<static_interrupt<StaticMask, V, F1, F2, Interrupt>::value, int> = 0 + > + inline void set() { interrupt = true; } - // else should_handle - template <field F1, field F2, char V> - inline void set_dispatch(integral_constant<int, 1>) + + template + < + field F1, field F2, char V, + std::enable_if_t<! static_interrupt<StaticMask, V, F1, F2, Interrupt>::value, int> = 0 + > + inline void set() { base_type::template set<F1, F2, V>(); } - // else - template <field F1, field F2, char V> - inline void set_dispatch(integral_constant<int, 2>) - {} + template <field F1, field F2> + inline char get() const + { + return base_type::template get<F1, F2>(); + } + +private: // Interrupt && interrupt template <field F1, field F2, char V> inline void update_dispatch(integral_constant<int, 0>) @@ -1135,40 +1125,6 @@ private: // --------------- UTIL FUNCTIONS ---------------- -// set - -template <field F1, field F2, char V, typename Result> -inline void set(Result & res) -{ - res.template set<F1, F2, V>(); -} - -template <field F1, field F2, char V, bool Transpose> -struct set_dispatch -{ - template <typename Result> - static inline void apply(Result & res) - { - res.template set<F1, F2, V>(); - } -}; - -template <field F1, field F2, char V> -struct set_dispatch<F1, F2, V, true> -{ - template <typename Result> - static inline void apply(Result & res) - { - res.template set<F2, F1, V>(); - } -}; - -template <field F1, field F2, char V, bool Transpose, typename Result> -inline void set(Result & res) -{ - set_dispatch<F1, F2, V, Transpose>::apply(res); -} - // update template <field F1, field F2, char D, typename Result> @@ -1177,30 +1133,24 @@ inline void update(Result & res) res.template update<F1, F2, D>(); } -template <field F1, field F2, char D, bool Transpose> -struct update_result_dispatch -{ - template <typename Result> - static inline void apply(Result & res) - { - update<F1, F2, D>(res); - } -}; - -template <field F1, field F2, char D> -struct update_result_dispatch<F1, F2, D, true> +template +< + field F1, field F2, char D, bool Transpose, typename Result, + std::enable_if_t<! Transpose, int> = 0 +> +inline void update(Result & res) { - template <typename Result> - static inline void apply(Result & res) - { - update<F2, F1, D>(res); - } -}; + res.template update<F1, F2, D>(); +} -template <field F1, field F2, char D, bool Transpose, typename Result> +template +< + field F1, field F2, char D, bool Transpose, typename Result, + std::enable_if_t<Transpose, int> = 0 +> inline void update(Result & res) { - update_result_dispatch<F1, F2, D, Transpose>::apply(res); + res.template update<F2, F1, D>(); } // may_update @@ -1211,30 +1161,24 @@ inline bool may_update(Result const& res) return res.template may_update<F1, F2, D>(); } -template <field F1, field F2, char D, bool Transpose> -struct may_update_result_dispatch -{ - template <typename Result> - static inline bool apply(Result const& res) - { - return may_update<F1, F2, D>(res); - } -}; - -template <field F1, field F2, char D> -struct may_update_result_dispatch<F1, F2, D, true> +template +< + field F1, field F2, char D, bool Transpose, typename Result, + std::enable_if_t<! Transpose, int> = 0 +> +inline bool may_update(Result const& res) { - template <typename Result> - static inline bool apply(Result const& res) - { - return may_update<F2, F1, D>(res); - } -}; + return res.template may_update<F1, F2, D>(); +} -template <field F1, field F2, char D, bool Transpose, typename Result> +template +< + field F1, field F2, char D, bool Transpose, typename Result, + std::enable_if_t<Transpose, int> = 0 +> inline bool may_update(Result const& res) { - return may_update_result_dispatch<F1, F2, D, Transpose>::apply(res); + return res.template may_update<F2, F1, D>(); } // result_dimension @@ -1242,11 +1186,9 @@ inline bool may_update(Result const& res) template <typename Geometry> struct result_dimension { - BOOST_STATIC_ASSERT(geometry::dimension<Geometry>::value >= 0); - static const char value - = ( geometry::dimension<Geometry>::value <= 9 ) ? - ( '0' + geometry::dimension<Geometry>::value ) : - 'T'; + static const std::size_t dim = geometry::dimension<Geometry>::value; + BOOST_STATIC_ASSERT(dim >= 0); + static const char value = (dim <= 9) ? ('0' + dim) : 'T'; }; }} // namespace detail::relate diff --git a/boost/geometry/algorithms/detail/relate/topology_check.hpp b/boost/geometry/algorithms/detail/relate/topology_check.hpp index 459c816143..2fc31ab51b 100644 --- a/boost/geometry/algorithms/detail/relate/topology_check.hpp +++ b/boost/geometry/algorithms/detail/relate/topology_check.hpp @@ -1,7 +1,8 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014-2020, Oracle and/or its affiliates. +// Copyright (c) 2014-2023, 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, @@ -170,22 +171,22 @@ struct topology_check<MultiLinestring, Strategy, multi_linestring_tag> } private: - typedef geometry::less<void, -1, typename Strategy::cs_tag> less_type; + typedef geometry::less<void, -1, Strategy> less_type; void init() const { if (m_is_initialized) + { return; + } m_endpoints.reserve(boost::size(m_mls) * 2); m_has_interior = false; - typedef typename boost::range_iterator<MultiLinestring const>::type ls_iterator; - for ( ls_iterator it = boost::begin(m_mls) ; it != boost::end(m_mls) ; ++it ) + for (auto it = boost::begin(m_mls); it != boost::end(m_mls); ++it) { - typename boost::range_reference<MultiLinestring const>::type - ls = *it; + auto const& ls = *it; std::size_t count = boost::size(ls); @@ -196,13 +197,8 @@ private: if (count > 1) { - typedef typename boost::range_reference - < - typename boost::range_value<MultiLinestring const>::type const - >::type point_reference; - - point_reference front_pt = range::front(ls); - point_reference back_pt = range::back(ls); + auto const& front_pt = range::front(ls); + auto const& 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, m_strategy)) @@ -226,7 +222,7 @@ private: m_has_boundary = false; - if (! m_endpoints.empty() ) + if (! m_endpoints.empty()) { std::sort(m_endpoints.begin(), m_endpoints.end(), less_type()); m_has_boundary = find_odd_count(m_endpoints.begin(), m_endpoints.end()); @@ -341,7 +337,7 @@ struct topology_check<MultiPolygon, Strategy, multi_polygon_tag> : topology_check_areal { topology_check(MultiPolygon const&, Strategy const&) {} - + 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 7d82887300..d98794e78a 100644 --- a/boost/geometry/algorithms/detail/relate/turns.hpp +++ b/boost/geometry/algorithms/detail/relate/turns.hpp @@ -2,8 +2,8 @@ // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. -// This file was modified by Oracle on 2013-2020. -// Modifications copyright (c) 2013-2020 Oracle and/or its affiliates. +// This file was modified by Oracle on 2013-2022. +// Modifications copyright (c) 2013-2022 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 @@ -20,6 +20,8 @@ #include <boost/geometry/algorithms/detail/overlay/get_turns.hpp> #include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp> +#include <boost/geometry/geometries/helper_geometry.hpp> + #include <boost/geometry/policies/robustness/get_rescale_policy.hpp> #include <boost/geometry/policies/robustness/segment_ratio_type.hpp> @@ -40,7 +42,7 @@ struct assign_policy static bool const include_degenerate = IncludeDegenerate; }; -// GET_TURNS +// turn retriever, calling get_turns template < @@ -53,7 +55,10 @@ template > struct get_turns { - typedef typename geometry::point_type<Geometry1>::type point1_type; + using turn_point_type = typename helper_geometry + < + typename geometry::point_type<Geometry1>::type + >::type; template <typename Strategy> struct robust_policy_type @@ -72,16 +77,16 @@ struct get_turns > struct turn_info_type { - typedef typename segment_ratio_type<point1_type, RobustPolicy>::type ratio_type; - typedef overlay::turn_info + using ratio_type = typename segment_ratio_type<turn_point_type, RobustPolicy>::type; + using type = overlay::turn_info < - point1_type, + turn_point_type, ratio_type, typename detail::get_turns::turn_operation_type < - Geometry1, Geometry2, ratio_type + Geometry1, Geometry2, turn_point_type, ratio_type >::type - > type; + >; }; template <typename Turns, typename InterruptPolicy, typename Strategy> @@ -167,7 +172,7 @@ struct less_op_xxx_linear template <std::size_t OpId> struct less_op_linear_linear - : less_op_xxx_linear< OpId, op_to_int<0,2,3,1,4,0> > + : less_op_xxx_linear< OpId, op_to_int<0,2,3,1,4,0> > // xuic {}; template <std::size_t OpId> @@ -244,7 +249,7 @@ struct less_op_areal_areal else if ( right_operation.operation == overlay::operation_intersection ) return false; } - + return op_to_int_iuxc(left_operation) < op_to_int_iuxc(right_operation); } } @@ -270,7 +275,7 @@ struct less_other_multi_index // sort turns by G1 - source_index == 0 by: // seg_id -> distance and coordinates -> operation -template <std::size_t OpId, typename LessOp, typename CSTag> +template <std::size_t OpId, typename LessOp, typename Strategy> struct less { BOOST_STATIC_ASSERT(OpId < 2); @@ -278,14 +283,8 @@ struct less template <typename Turn> static inline bool use_fraction(Turn const& left, Turn const& right) { - typedef typename geometry::strategy::within::services::default_strategy - < - typename Turn::point_type, typename Turn::point_type, - point_tag, point_tag, - pointlike_tag, pointlike_tag, - typename tag_cast<CSTag, spherical_tag>::type, - typename tag_cast<CSTag, spherical_tag>::type - >::type eq_pp_strategy_type; + using eq_pp_strategy_type = decltype(std::declval<Strategy>().relate( + detail::dummy_point(), detail::dummy_point())); static LessOp less_op; diff --git a/boost/geometry/algorithms/detail/relation/interface.hpp b/boost/geometry/algorithms/detail/relation/interface.hpp index e9d940c3e9..4c3616ab42 100644 --- a/boost/geometry/algorithms/detail/relation/interface.hpp +++ b/boost/geometry/algorithms/detail/relation/interface.hpp @@ -2,8 +2,8 @@ // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. -// This file was modified by Oracle on 2013-2020. -// Modifications copyright (c) 2013-2020 Oracle and/or its affiliates. +// This file was modified by Oracle on 2013-2022. +// Modifications copyright (c) 2013-2022 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -35,10 +35,15 @@ struct result_handler_type<Geometry1, Geometry2, geometry::de9im::matrix> }} // namespace detail::relate #endif // DOXYGEN_NO_DETAIL -namespace resolve_variant +namespace resolve_dynamic { -template <typename Geometry1, typename Geometry2> +template +< + typename Geometry1, typename Geometry2, + typename Tag1 = typename geometry::tag<Geometry1>::type, + typename Tag2 = typename geometry::tag<Geometry2>::type +> struct relation { template <typename Matrix, typename Strategy> @@ -66,105 +71,70 @@ struct relation } }; -template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2> -struct relation<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2> +template <typename Geometry1, typename Geometry2, typename Tag2> +struct relation<Geometry1, Geometry2, dynamic_geometry_tag, Tag2> { template <typename Matrix, typename Strategy> - struct visitor : boost::static_visitor<Matrix> + static inline Matrix apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Strategy const& strategy) { - Geometry2 const& m_geometry2; - Strategy const& m_strategy; - - visitor(Geometry2 const& geometry2, Strategy const& strategy) - : m_geometry2(geometry2), m_strategy(strategy) {} - - template <typename Geometry1> - Matrix operator()(Geometry1 const& geometry1) const + Matrix result; + traits::visit<Geometry1>::apply([&](auto const& g1) { - return relation<Geometry1, Geometry2> - ::template apply<Matrix>(geometry1, m_geometry2, m_strategy); - } - }; - - template <typename Matrix, typename Strategy> - static inline Matrix - apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1, - Geometry2 const& geometry2, - Strategy const& strategy) - { - return boost::apply_visitor(visitor<Matrix, Strategy>(geometry2, strategy), geometry1); + result = relation + < + util::remove_cref_t<decltype(g1)>, + Geometry2 + >::template apply<Matrix>(g1, geometry2, strategy); + }, geometry1); + return result; } }; -template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)> -struct relation<Geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > +template <typename Geometry1, typename Geometry2, typename Tag1> +struct relation<Geometry1, Geometry2, Tag1, dynamic_geometry_tag> { template <typename Matrix, typename Strategy> - struct visitor : boost::static_visitor<Matrix> + static inline Matrix apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Strategy const& strategy) { - Geometry1 const& m_geometry1; - Strategy const& m_strategy; - - visitor(Geometry1 const& geometry1, Strategy const& strategy) - : m_geometry1(geometry1), m_strategy(strategy) {} - - template <typename Geometry2> - Matrix operator()(Geometry2 const& geometry2) const + Matrix result; + traits::visit<Geometry2>::apply([&](auto const& g2) { - return relation<Geometry1, Geometry2> - ::template apply<Matrix>(m_geometry1, geometry2, m_strategy); - } - }; - - template <typename Matrix, typename Strategy> - static inline Matrix - apply(Geometry1 const& geometry1, - boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2, - Strategy const& strategy) - { - return boost::apply_visitor(visitor<Matrix, Strategy>(geometry1, strategy), geometry2); + result = relation + < + Geometry1, + util::remove_cref_t<decltype(g2)> + >::template apply<Matrix>(geometry1, g2, strategy); + }, geometry2); + return result; } }; -template -< - BOOST_VARIANT_ENUM_PARAMS(typename T1), - BOOST_VARIANT_ENUM_PARAMS(typename T2) -> -struct relation - < - boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>, - boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> - > +template <typename Geometry1, typename Geometry2> +struct relation<Geometry1, Geometry2, dynamic_geometry_tag, dynamic_geometry_tag> { template <typename Matrix, typename Strategy> - struct visitor : boost::static_visitor<Matrix> + static inline Matrix apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Strategy const& strategy) { - Strategy const& m_strategy; - - visitor(Strategy const& strategy) - : m_strategy(strategy) {} - - template <typename Geometry1, typename Geometry2> - Matrix operator()(Geometry1 const& geometry1, - Geometry2 const& geometry2) const + Matrix result; + traits::visit<Geometry1, Geometry2>::apply([&](auto const& g1, auto const& g2) { - return relation<Geometry1, Geometry2> - ::template apply<Matrix>(geometry1, geometry2, m_strategy); - } - }; - - template <typename Matrix, typename Strategy> - static inline Matrix - apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1, - boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2, - Strategy const& strategy) - { - return boost::apply_visitor(visitor<Matrix, Strategy>(strategy), geometry1, geometry2); + result = relation + < + util::remove_cref_t<decltype(g1)>, + util::remove_cref_t<decltype(g2)> + >::template apply<Matrix>(g1, g2, strategy); + }, geometry1, geometry2); + return result; } }; -} // namespace resolve_variant +} // namespace resolve_dynamic /*! @@ -186,7 +156,7 @@ inline de9im::matrix relation(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { - return resolve_variant::relation + return resolve_dynamic::relation < Geometry1, Geometry2 @@ -209,7 +179,7 @@ template <typename Geometry1, typename Geometry2> inline de9im::matrix relation(Geometry1 const& geometry1, Geometry2 const& geometry2) { - return resolve_variant::relation + return resolve_dynamic::relation < Geometry1, Geometry2 diff --git a/boost/geometry/algorithms/detail/sections/section_functions.hpp b/boost/geometry/algorithms/detail/sections/section_functions.hpp index abc6de409c..df4f31025a 100644 --- a/boost/geometry/algorithms/detail/sections/section_functions.hpp +++ b/boost/geometry/algorithms/detail/sections/section_functions.hpp @@ -70,7 +70,7 @@ struct preceding_check<0, Geometry, spherical_tag> calc_t const value = get<0>(point); 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::detail::covered_by_range < Point, 0, spherical_tag @@ -124,13 +124,14 @@ template typename Box, typename RobustPolicy > -static inline bool preceding(int dir, - Point const& point, - Box const& point_box, - Box const& other_box, - RobustPolicy const& robust_policy) +inline bool preceding(int dir, + Point const& point, + Box const& point_box, + Box const& other_box, + RobustPolicy const& robust_policy) { - typename geometry::robust_point_type<Point, RobustPolicy>::type robust_point; + using box_point_type = typename geometry::point_type<Box>::type; + typename geometry::robust_point_type<box_point_type, RobustPolicy>::type robust_point; geometry::recalculate(robust_point, point, robust_policy); // After recalculate() to prevent warning: 'robust_point' may be used uninitialized @@ -148,11 +149,11 @@ template typename Box, typename RobustPolicy > -static inline bool exceeding(int dir, - Point const& point, - Box const& point_box, - Box const& other_box, - RobustPolicy const& robust_policy) +inline bool exceeding(int dir, + Point const& point, + Box const& point_box, + Box const& other_box, + RobustPolicy const& robust_policy) { return preceding<Dimension>(-dir, point, point_box, other_box, robust_policy); } diff --git a/boost/geometry/algorithms/detail/sections/sectionalize.hpp b/boost/geometry/algorithms/detail/sections/sectionalize.hpp index e98536e3fd..3317ff70a9 100644 --- a/boost/geometry/algorithms/detail/sections/sectionalize.hpp +++ b/boost/geometry/algorithms/detail/sections/sectionalize.hpp @@ -38,11 +38,9 @@ #include <boost/geometry/algorithms/envelope.hpp> #include <boost/geometry/algorithms/expand.hpp> #include <boost/geometry/algorithms/detail/expand_by_epsilon.hpp> -#include <boost/geometry/algorithms/detail/interior_iterator.hpp> #include <boost/geometry/algorithms/detail/recalculate.hpp> #include <boost/geometry/algorithms/detail/ring_identifier.hpp> #include <boost/geometry/algorithms/detail/signed_size_type.hpp> -#include <boost/geometry/algorithms/detail/buffer/buffer_box.hpp> #include <boost/geometry/core/access.hpp> #include <boost/geometry/core/closure.hpp> @@ -87,7 +85,7 @@ template > struct section { - typedef Box box_type; + using box_type = Box; static std::size_t const dimension_count = DimensionCount; int directions[DimensionCount]; @@ -134,7 +132,7 @@ struct section template <typename Box, std::size_t DimensionCount> struct sections : std::vector<section<Box, DimensionCount> > { - typedef Box box_type; + using box_type = Box; static std::size_t const value = DimensionCount; }; @@ -161,16 +159,14 @@ template > struct get_direction_loop { - typedef typename util::sequence_element<Index, DimensionVector>::type dimension; + using dimension = typename util::sequence_element<Index, DimensionVector>::type; template <typename Segment> static inline void apply(Segment const& seg, int directions[Count]) { - typedef typename coordinate_type<Segment>::type coordinate_type; - - coordinate_type const c0 = geometry::get<0, dimension::value>(seg); - coordinate_type const c1 = geometry::get<1, dimension::value>(seg); + auto const& c0 = geometry::get<0, dimension::value>(seg); + auto const& c1 = geometry::get<1, dimension::value>(seg); directions[Index] = c1 > c0 ? 1 : c1 < c0 ? -1 : 0; @@ -193,14 +189,14 @@ template > struct get_direction_loop<Point, DimensionVector, 0, Count, spherical_tag> { - typedef typename util::sequence_element<0, DimensionVector>::type dimension; + using dimension = typename util::sequence_element<0, DimensionVector>::type; template <typename Segment> static inline void apply(Segment const& seg, int directions[Count]) { - typedef typename coordinate_type<Segment>::type coordinate_type; - typedef typename coordinate_system<Point>::type::units units_t; + using coordinate_type = typename coordinate_type<Segment>::type; + using units_t = typename coordinate_system<Point>::type::units; coordinate_type const diff = math::longitude_distance_signed < @@ -381,11 +377,7 @@ struct box_next_in_section<cartesian_tag> }; /// @brief Helper class to create sections of a part of a range, on the fly -template -< - typename Point, - typename DimensionVector -> +template<typename DimensionVector> struct sectionalize_part { static const std::size_t dimension_count @@ -407,18 +399,21 @@ struct sectionalize_part { boost::ignore_unused(robust_policy); - typedef typename boost::range_value<Sections>::type section_type; + using section_type = typename boost::range_value<Sections>::type; + using box_type = typename section_type::box_type; + using point_type = typename geometry::point_type<box_type>::type; + BOOST_STATIC_ASSERT ( section_type::dimension_count == util::sequence_size<DimensionVector>::value ); - typedef typename geometry::robust_point_type + using robust_point_type = typename geometry::robust_point_type < - Point, + point_type, RobustPolicy - >::type robust_point_type; + >::type; std::size_t const count = std::distance(begin, end); if (count == 0) @@ -436,7 +431,7 @@ struct sectionalize_part Iterator it = begin; robust_point_type previous_robust_point; geometry::recalculate(previous_robust_point, *it, robust_policy); - + for(Iterator previous = it++; it != end; ++previous, ++it, index++) @@ -449,7 +444,7 @@ struct sectionalize_part int direction_classes[dimension_count] = {0}; get_direction_loop < - Point, DimensionVector, 0, dimension_count + point_type, DimensionVector, 0, dimension_count >::apply(robust_segment, direction_classes); // if "dir" == 0 for all point-dimensions, it is duplicate. @@ -463,7 +458,7 @@ struct sectionalize_part // (dimension_count might be < dimension<P>::value) if (check_duplicate_loop < - 0, geometry::dimension<Point>::type::value + 0, geometry::dimension<point_type>::type::value >::apply(robust_segment) ) { @@ -562,7 +557,6 @@ template < closure_selector Closure, bool Reverse, - typename Point, typename DimensionVector > struct sectionalize_range @@ -601,7 +595,7 @@ struct sectionalize_range return; } - sectionalize_part<Point, DimensionVector>::apply(sections, + sectionalize_part<DimensionVector>::apply(sections, boost::begin(view), boost::end(view), robust_policy, strategy, ring_id, max_count); @@ -629,23 +623,21 @@ struct sectionalize_polygon ring_identifier ring_id, std::size_t max_count) { - typedef typename point_type<Polygon>::type point_type; - typedef sectionalize_range + using sectionalizer = sectionalize_range < - closure<Polygon>::value, Reverse, point_type, DimensionVector - > per_range; + closure<Polygon>::value, Reverse, DimensionVector + >; ring_id.ring_index = -1; - per_range::apply(exterior_ring(poly), robust_policy, sections, + sectionalizer::apply(exterior_ring(poly), robust_policy, sections, strategy, ring_id, max_count); ring_id.ring_index++; - typename interior_return_type<Polygon const>::type - rings = interior_rings(poly); - for (typename detail::interior_iterator<Polygon const>::type - it = boost::begin(rings); it != boost::end(rings); ++it, ++ring_id.ring_index) + auto const& rings = interior_rings(poly); + for (auto it = boost::begin(rings); it != boost::end(rings); + ++it, ++ring_id.ring_index) { - per_range::apply(*it, robust_policy, sections, + sectionalizer::apply(*it, robust_policy, sections, strategy, ring_id, max_count); } } @@ -667,7 +659,7 @@ struct sectionalize_box Strategy const& strategy, ring_identifier const& ring_id, std::size_t max_count) { - typedef typename point_type<Box>::type point_type; + using point_type = typename point_type<Box>::type; assert_dimension<Box, 2>(); @@ -693,7 +685,7 @@ struct sectionalize_box // because edges of a box are not geodesic segments sectionalize_range < - closed, false, point_type, DimensionVector + closed, false, DimensionVector >::apply(points, robust_policy, sections, strategy, ring_id, max_count); } @@ -717,10 +709,7 @@ struct sectionalize_multi std::size_t max_count) { ring_id.multi_index = 0; - for (typename boost::range_iterator<MultiGeometry const>::type - it = boost::begin(multi); - it != boost::end(multi); - ++it, ++ring_id.multi_index) + for (auto it = boost::begin(multi); it != boost::end(multi); ++it, ++ring_id.multi_index) { Policy::apply(*it, robust_policy, sections, strategy, @@ -729,77 +718,28 @@ struct sectionalize_multi } }; -// TODO: If it depends on CS it should probably be made into strategy. -// For now implemented here because of ongoing work on robustness -// the fact that it interferes with detail::buffer::buffer_box -// and that we probably need a general strategy for defining epsilon in -// various coordinate systems, e.g. for point comparison, enlargement of -// bounding boxes, etc. -template <typename CSTag> -struct expand_by_epsilon - : not_implemented<CSTag> -{}; - -template <> -struct expand_by_epsilon<cartesian_tag> -{ - template <typename Box> - static inline void apply(Box & box) - { - detail::expand_by_epsilon(box); - } -}; - -template <> -struct expand_by_epsilon<spherical_tag> -{ - template <typename Box> - static inline void apply(Box & box) - { - typedef typename coordinate_type<Box>::type coord_t; - static const coord_t eps = std::is_same<coord_t, float>::value - ? coord_t(1e-6) - : coord_t(1e-12); - detail::expand_by_epsilon(box, eps); - } -}; - -// TODO: In geographic CS it should probably also depend on FormulaPolicy. -template <> -struct expand_by_epsilon<geographic_tag> - : expand_by_epsilon<spherical_tag> -{}; - template <typename Sections, typename Strategy> inline void enlarge_sections(Sections& sections, Strategy const&) { - // Enlarge sections slightly, this should be consistent with math::equals() - // and with the tolerances used in general_form intersections. - // This avoids missing turns. - - // Points and Segments are equal-compared WRT machine epsilon, but Boxes aren't - // Enlarging Boxes ensures that they correspond to the bound objects, - // Segments in this case, since Sections are collections of Segments. - - // It makes section a tiny bit too large, which might cause (a small number) - // of more comparisons - for (typename boost::range_iterator<Sections>::type it = boost::begin(sections); - it != boost::end(sections); - ++it) + // Expand the box to avoid missing any intersection. The amount is + // should be larger than epsilon. About the value itself: the smaller + // it is, the higher the risk to miss intersections. The larger it is, + // the more comparisons are made, which is not harmful for the result + // (but it might be for the performance). + // So it should be on the high side. + + // Use a compilable and workable epsilon for all types, for example: + // - for double :~ 2.22e-13 + // - for float :~ 1e-4 + // - for Boost.Multiprecision (50) :~ 5.35e-48 + // - for Boost.Rational : 0/1 + + for (auto& section : sections) { -#if defined(BOOST_GEOMETRY_USE_RESCALING) - detail::sectionalize::expand_by_epsilon - < - typename Strategy::cs_tag - >::apply(it->bounding_box); - -#else - // Expand the box to avoid missing any intersection. The amount is - // should be larger than epsilon. About the value itself: the smaller - // it is, the higher the risk to miss intersections. The larger it is, - // the more comparisons are made. So it should be on the high side. - detail::buffer::buffer_box(it->bounding_box, 0.001, it->bounding_box); -#endif + using gt = decltype(section.bounding_box); + using ct = typename geometry::coordinate_type<gt>::type; + static ct const eps = math::scaled_epsilon<ct>(1000); + expand_by_epsilon(section.bounding_box, eps); } } @@ -848,12 +788,7 @@ struct sectionalize false, DimensionVector > - : detail::sectionalize::sectionalize_range - < - closed, false, - typename point_type<LineString>::type, - DimensionVector - > + : detail::sectionalize::sectionalize_range<closed, false, DimensionVector> {}; template @@ -866,7 +801,6 @@ struct sectionalize<ring_tag, Ring, Reverse, DimensionVector> : detail::sectionalize::sectionalize_range < geometry::closure<Ring>::value, Reverse, - typename point_type<Ring>::type, DimensionVector > {}; @@ -913,12 +847,7 @@ struct sectionalize<multi_linestring_tag, MultiLinestring, Reverse, DimensionVec : detail::sectionalize::sectionalize_multi < DimensionVector, - detail::sectionalize::sectionalize_range - < - closed, false, - typename point_type<MultiLinestring>::type, - DimensionVector - > + detail::sectionalize::sectionalize_range<closed, false, DimensionVector> > {}; @@ -960,26 +889,6 @@ inline void sectionalize(Geometry const& geometry, { concepts::check<Geometry const>(); - typedef typename boost::range_value<Sections>::type section_type; - - // Compiletime check for point type of section boxes - // and point type related to robust policy - typedef typename geometry::coordinate_type - < - typename section_type::box_type - >::type ctype1; - typedef typename geometry::coordinate_type - < - typename geometry::robust_point_type - < - typename geometry::point_type<Geometry>::type, - RobustPolicy - >::type - >::type ctype2; - - BOOST_STATIC_ASSERT((std::is_same<ctype1, ctype2>::value)); - - sections.clear(); ring_identifier ring_id; @@ -1013,11 +922,12 @@ inline void sectionalize(Geometry const& geometry, int source_index = 0, std::size_t max_count = 10) { - typedef typename strategies::envelope::services::default_strategy + using box_type = typename Sections::box_type; + using strategy_type = typename strategies::envelope::services::default_strategy < Geometry, - model::box<typename point_type<Geometry>::type> - >::type strategy_type; + box_type + >::type; boost::geometry::sectionalize < diff --git a/boost/geometry/algorithms/detail/select_geometry_type.hpp b/boost/geometry/algorithms/detail/select_geometry_type.hpp index 2e94ae73e6..5592fa5c4b 100644 --- a/boost/geometry/algorithms/detail/select_geometry_type.hpp +++ b/boost/geometry/algorithms/detail/select_geometry_type.hpp @@ -11,6 +11,9 @@ #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_SELECT_GEOMETRY_TYPE_HPP #include <boost/geometry/core/geometry_types.hpp> +#include <boost/geometry/core/static_assert.hpp> +#include <boost/geometry/core/tag.hpp> +#include <boost/geometry/core/tags.hpp> #include <boost/geometry/util/sequence.hpp> #include <boost/geometry/util/type_traits.hpp> @@ -21,29 +24,33 @@ namespace boost { namespace geometry namespace detail { -template -< - typename Geometry, - template <typename, typename> class LessPred, - bool IsDynamicOrCollection = util::is_dynamic_geometry<Geometry>::value - || util::is_geometry_collection<Geometry>::value -> -struct select_geometry_type + +template <typename Geometry, typename Tag = typename tag<Geometry>::type> +struct first_geometry_type { using type = Geometry; }; -template -< - typename Geometry, - template <typename, typename> class LessPred -> -struct select_geometry_type<Geometry, LessPred, true> - : util::select_element +template <typename Geometry> +struct first_geometry_type<Geometry, geometry_collection_tag> +{ + template <typename T> + using pred = util::bool_constant < - typename traits::geometry_types<std::remove_const_t<Geometry>>::type, - LessPred - > + ! util::is_dynamic_geometry<T>::value + && ! util::is_geometry_collection<T>::value + >; + + using type = typename util::sequence_find_if + < + typename traits::geometry_types<Geometry>::type, + pred + >::type; +}; + +template <typename Geometry> +struct first_geometry_type<Geometry, dynamic_geometry_tag> + : first_geometry_type<Geometry, geometry_collection_tag> {}; @@ -67,6 +74,32 @@ struct geometry_types<Geometry, true> template < + typename Geometry, + template <typename, typename> class LessPred, + bool IsDynamicOrCollection = util::is_dynamic_geometry<Geometry>::value + || util::is_geometry_collection<Geometry>::value +> +struct select_geometry_type +{ + using type = Geometry; +}; + +template +< + typename Geometry, + template <typename, typename> class LessPred +> +struct select_geometry_type<Geometry, LessPred, true> + : util::sequence_min_element + < + typename traits::geometry_types<std::remove_const_t<Geometry>>::type, + LessPred + > +{}; + + +template +< typename Geometry1, typename Geometry2, template <typename, typename> class LessPred, bool IsDynamicOrCollection = util::is_dynamic_geometry<Geometry1>::value @@ -89,10 +122,13 @@ template template <typename, typename> class LessPred > struct select_geometry_types<Geometry1, Geometry2, LessPred, true> - : util::select_combination_element + : util::sequence_min_element < - typename geometry_types<Geometry1>::type, - typename geometry_types<Geometry2>::type, + typename util::sequence_combine + < + typename geometry_types<Geometry1>::type, + typename geometry_types<Geometry2>::type + >::type, LessPred > {}; diff --git a/boost/geometry/algorithms/detail/sweep.hpp b/boost/geometry/algorithms/detail/sweep.hpp index 3dc78261f2..a8c7f9a91a 100644 --- a/boost/geometry/algorithms/detail/sweep.hpp +++ b/boost/geometry/algorithms/detail/sweep.hpp @@ -1,7 +1,8 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2015, Oracle and/or its affiliates. +// Copyright (c) 2023 Adam Wulkiewicz, Lodz, Poland. +// Copyright (c) 2015, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Licensed under the Boost Software License version 1.0. @@ -10,6 +11,8 @@ #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_SWEEP_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_SWEEP_HPP +#include <boost/geometry/util/condition.hpp> + #include <boost/core/ignore_unused.hpp> @@ -56,7 +59,7 @@ inline void sweep(Range const& range, PriorityQueue& queue, event_type event = queue.top(); queue.pop(); event_visitor.apply(event, queue); - if (interrupt_policy.enabled && interrupt_policy.apply(event)) + if (BOOST_GEOMETRY_CONDITION(interrupt_policy.enabled) && interrupt_policy.apply(event)) { break; } diff --git a/boost/geometry/algorithms/detail/touches/implementation.hpp b/boost/geometry/algorithms/detail/touches/implementation.hpp index b37e7bc7ea..15a899e701 100644 --- a/boost/geometry/algorithms/detail/touches/implementation.hpp +++ b/boost/geometry/algorithms/detail/touches/implementation.hpp @@ -3,10 +3,10 @@ // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2015 Bruno Lalande, Paris, France. // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. -// Copyright (c) 2013-2015 Adam Wulkiewicz, Lodz, Poland. +// Copyright (c) 2013-2022 Adam Wulkiewicz, Lodz, Poland. -// This file was modified by Oracle on 2013-2020. -// Modifications copyright (c) 2013-2020, Oracle and/or its affiliates. +// This file was modified by Oracle on 2013-2022. +// Modifications copyright (c) 2013-2022, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -24,15 +24,20 @@ #include <type_traits> #include <boost/geometry/algorithms/detail/for_each_range.hpp> +#include <boost/geometry/algorithms/detail/gc_topological_dimension.hpp> #include <boost/geometry/algorithms/detail/overlay/overlay.hpp> #include <boost/geometry/algorithms/detail/overlay/self_turn_points.hpp> #include <boost/geometry/algorithms/detail/sub_range.hpp> +#include <boost/geometry/algorithms/detail/relate/implementation.hpp> +#include <boost/geometry/algorithms/detail/relate/implementation_gc.hpp> #include <boost/geometry/algorithms/detail/relate/relate_impl.hpp> #include <boost/geometry/algorithms/detail/touches/interface.hpp> +#include <boost/geometry/algorithms/detail/visit.hpp> #include <boost/geometry/algorithms/disjoint.hpp> #include <boost/geometry/algorithms/intersects.hpp> #include <boost/geometry/algorithms/num_geometries.hpp> -#include <boost/geometry/algorithms/relate.hpp> + +#include <boost/geometry/geometries/helper_geometry.hpp> #include <boost/geometry/policies/robustness/no_rescale_policy.hpp> @@ -40,6 +45,8 @@ #include <boost/geometry/strategies/relate/geographic.hpp> #include <boost/geometry/strategies/relate/spherical.hpp> +#include <boost/geometry/views/detail/geometry_collection_view.hpp> + namespace boost { namespace geometry { @@ -80,7 +87,7 @@ struct box_box_loop { touch = true; } - + return box_box_loop < Dimension + 1, @@ -150,19 +157,20 @@ struct areal_interrupt_policy inline bool apply(Range const& range) { // if already rejected (temp workaround?) - if ( found_not_touch ) + if (found_not_touch) + { return true; + } - typedef typename boost::range_iterator<Range const>::type iterator; - for ( iterator it = boost::begin(range) ; it != boost::end(range) ; ++it ) + for (auto it = boost::begin(range); it != boost::end(range); ++it) { - if ( it->has(overlay::operation_intersection) ) + if (it->has(overlay::operation_intersection)) { found_not_touch = true; return true; } - switch(it->method) + switch (it->method) { case overlay::method_crosses: found_not_touch = true; @@ -211,7 +219,8 @@ inline bool point_on_border_within(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { - typename geometry::point_type<Geometry1>::type pt; + using point_type = typename geometry::point_type<Geometry1>::type; + typename helper_geometry<point_type>::type pt; return geometry::point_on_border(pt, geometry1) && geometry::within(pt, geometry2, strategy); } @@ -235,17 +244,18 @@ struct areal_areal Geometry2 const& geometry2, Strategy const& strategy) { - typedef typename geometry::point_type<Geometry1>::type point_type; - typedef detail::overlay::turn_info<point_type> turn_info; + using point_type = typename geometry::point_type<Geometry1>::type; + using mutable_point_type = typename helper_geometry<point_type>::type; + using turn_info = detail::overlay::turn_info<mutable_point_type>; std::deque<turn_info> turns; detail::touches::areal_interrupt_policy policy; - boost::geometry::get_turns - < - detail::overlay::do_reverse<geometry::point_order<Geometry1>::value>::value, - detail::overlay::do_reverse<geometry::point_order<Geometry2>::value>::value, - detail::overlay::assign_null_policy - >(geometry1, geometry2, strategy, detail::no_rescale_policy(), turns, policy); + geometry::get_turns + < + detail::overlay::do_reverse<geometry::point_order<Geometry1>::value>::value, + detail::overlay::do_reverse<geometry::point_order<Geometry2>::value>::value, + detail::overlay::assign_null_policy + >(geometry1, geometry2, strategy, detail::no_rescale_policy(), turns, policy); return policy.result() && ! geometry::detail::touches::rings_containing(geometry1, geometry2, strategy) @@ -264,6 +274,55 @@ struct use_point_in_geometry } }; +// GC + +struct gc_gc +{ + template <typename Geometry1, typename Geometry2, typename Strategy> + static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, + Strategy const& strategy) + { + int const dimension1 = detail::gc_topological_dimension(geometry1); + int const dimension2 = detail::gc_topological_dimension(geometry2); + + if (dimension1 == 0 && dimension2 == 0) + { + return false; + } + else + { + return detail::relate::relate_impl + < + detail::de9im::static_mask_touches_not_pp_type, + Geometry1, + Geometry2 + >::apply(geometry1, geometry2, strategy); + } + } +}; + +struct notgc_gc +{ + template <typename Geometry1, typename Geometry2, typename Strategy> + static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, + Strategy const& strategy) + { + using gc1_view_t = detail::geometry_collection_view<Geometry1>; + return gc_gc::apply(gc1_view_t(geometry1), geometry2, strategy); + } +}; + +struct gc_notgc +{ + template <typename Geometry1, typename Geometry2, typename Strategy> + static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, + Strategy const& strategy) + { + using gc2_view_t = detail::geometry_collection_view<Geometry2>; + return gc_gc::apply(geometry1, gc2_view_t(geometry2), strategy); + } +}; + }} #endif // DOXYGEN_NO_DETAIL @@ -396,14 +455,52 @@ struct touches<Areal1, Areal2, ring_tag, ring_tag, areal_tag, areal_tag, false> : detail::touches::areal_areal<Areal1, Areal2> {}; +// GC + +template <typename Geometry1, typename Geometry2> +struct touches + < + Geometry1, Geometry2, + geometry_collection_tag, geometry_collection_tag, + geometry_collection_tag, geometry_collection_tag, + false + > + : detail::touches::gc_gc +{}; + + +template <typename Geometry1, typename Geometry2, typename Tag1, typename CastedTag1> +struct touches + < + Geometry1, Geometry2, + Tag1, geometry_collection_tag, + CastedTag1, geometry_collection_tag, + false + > + : detail::touches::notgc_gc +{}; + + +template <typename Geometry1, typename Geometry2, typename Tag2, typename CastedTag2> +struct touches + < + Geometry1, Geometry2, + geometry_collection_tag, Tag2, + geometry_collection_tag, CastedTag2, + false + > + : detail::touches::gc_notgc +{}; + + } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH -namespace resolve_variant +namespace resolve_dynamic { -template <typename Geometry> +template <typename Geometry, typename Tag> struct self_touches { static bool apply(Geometry const& geometry) @@ -436,7 +533,7 @@ struct self_touches } }; -} +} // namespace resolve_dynamic }} // namespace boost::geometry diff --git a/boost/geometry/algorithms/detail/touches/interface.hpp b/boost/geometry/algorithms/detail/touches/interface.hpp index 39d997463e..271697c5d9 100644 --- a/boost/geometry/algorithms/detail/touches/interface.hpp +++ b/boost/geometry/algorithms/detail/touches/interface.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-2021. -// Modifications copyright (c) 2013-2021, Oracle and/or its affiliates. +// This file was modified by Oracle on 2013-2022. +// Modifications copyright (c) 2013-2022, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -23,15 +23,13 @@ #include <deque> -#include <boost/variant/apply_visitor.hpp> -#include <boost/variant/static_visitor.hpp> -#include <boost/variant/variant_fwd.hpp> - #include <boost/geometry/core/reverse_dispatch.hpp> #include <boost/geometry/core/tag.hpp> #include <boost/geometry/core/tag_cast.hpp> #include <boost/geometry/core/tags.hpp> +#include <boost/geometry/core/visit.hpp> +#include <boost/geometry/geometries/adapted/boost_variant.hpp> #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/strategies/default_strategy.hpp> @@ -146,13 +144,19 @@ struct touches<default_strategy, false> } // namespace resolve_strategy -namespace resolve_variant { +namespace resolve_dynamic { -template <typename Geometry1, typename Geometry2> +template +< + typename Geometry1, typename Geometry2, + typename Tag1 = typename geometry::tag<Geometry1>::type, + typename Tag2 = typename geometry::tag<Geometry2>::type +> struct touches { template <typename Strategy> - static bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) + static bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, + Strategy const& strategy) { concepts::check<Geometry1 const>(); concepts::check<Geometry2 const>(); @@ -164,120 +168,87 @@ struct touches } }; -template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2> -struct touches<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2> +template <typename Geometry1, typename Geometry2, typename Tag2> +struct touches<Geometry1, Geometry2, dynamic_geometry_tag, Tag2> { template <typename Strategy> - struct visitor: boost::static_visitor<bool> + static bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, + Strategy const& strategy) { - Geometry2 const& m_geometry2; - Strategy const& m_strategy; - - visitor(Geometry2 const& geometry2, Strategy const& strategy) - : m_geometry2(geometry2) - , m_strategy(strategy) - {} - - template <typename Geometry1> - bool operator()(Geometry1 const& geometry1) const + bool result = false; + traits::visit<Geometry1>::apply([&](auto const& g1) { - return touches<Geometry1, Geometry2>::apply(geometry1, m_geometry2, m_strategy); - } - }; - - template <typename Strategy> - static inline bool apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1, - Geometry2 const& geometry2, - Strategy const& strategy) - { - return boost::apply_visitor(visitor<Strategy>(geometry2, strategy), geometry1); + result = touches + < + util::remove_cref_t<decltype(g1)>, + Geometry2 + >::apply(g1, geometry2, strategy); + }, geometry1); + return result; } }; -template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)> -struct touches<Geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > +template <typename Geometry1, typename Geometry2, typename Tag1> +struct touches<Geometry1, Geometry2, Tag1, dynamic_geometry_tag> { template <typename Strategy> - struct visitor: boost::static_visitor<bool> + static bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, + Strategy const& strategy) { - Geometry1 const& m_geometry1; - Strategy const& m_strategy; - - visitor(Geometry1 const& geometry1, Strategy const& strategy) - : m_geometry1(geometry1) - , m_strategy(strategy) - {} - - template <typename Geometry2> - bool operator()(Geometry2 const& geometry2) const + bool result = false; + traits::visit<Geometry2>::apply([&](auto const& g2) { - return touches<Geometry1, Geometry2>::apply(m_geometry1, geometry2, m_strategy); - } - }; - - template <typename Strategy> - static inline bool apply(Geometry1 const& geometry1, - boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2, - Strategy const& strategy) - { - return boost::apply_visitor(visitor<Strategy>(geometry1, strategy), geometry2); + result = touches + < + Geometry1, + util::remove_cref_t<decltype(g2)> + >::apply(geometry1, g2, strategy); + }, geometry2); + return result; } }; -template <BOOST_VARIANT_ENUM_PARAMS(typename T1), - BOOST_VARIANT_ENUM_PARAMS(typename T2)> -struct touches<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>, - boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> > +template <typename Geometry1, typename Geometry2> +struct touches<Geometry1, Geometry2, dynamic_geometry_tag, dynamic_geometry_tag> { template <typename Strategy> - struct visitor: boost::static_visitor<bool> + static bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, + Strategy const& strategy) { - Strategy const& m_strategy; - - visitor(Strategy const& strategy) - : m_strategy(strategy) - {} - - template <typename Geometry1, typename Geometry2> - bool operator()(Geometry1 const& geometry1, - Geometry2 const& geometry2) const + bool result = false; + traits::visit<Geometry1, Geometry2>::apply([&](auto const& g1, auto const& g2) { - return touches<Geometry1, Geometry2>::apply(geometry1, geometry2, m_strategy); - } - }; - - template <typename Strategy> - static inline bool apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1, - boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2, - Strategy const& strategy) - { - return boost::apply_visitor(visitor<Strategy>(strategy), geometry1, geometry2); + result = touches + < + util::remove_cref_t<decltype(g1)>, + util::remove_cref_t<decltype(g2)> + >::apply(g1, g2, strategy); + }, geometry1, geometry2); + return result; } }; -template <typename Geometry> +template <typename Geometry, typename Tag = typename geometry::tag<Geometry>::type> struct self_touches; -template <BOOST_VARIANT_ENUM_PARAMS(typename T)> -struct self_touches<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > +template <typename Geometry> +struct self_touches<Geometry, dynamic_geometry_tag> { - struct visitor: boost::static_visitor<bool> + static bool apply(Geometry const& geometry) { - template <typename Geometry> - bool operator()(Geometry const& geometry) const + bool result = false; + traits::visit<Geometry>::apply([&](auto const& g) { - return self_touches<Geometry>::apply(geometry); - } - }; - - static inline bool - apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry) - { - return boost::apply_visitor(visitor(), geometry); + result = self_touches + < + util::remove_cref_t<decltype(g)> + >::apply(g); + }, geometry); + return result; } }; -} // namespace resolve_variant +} // namespace resolve_dynamic /*! @@ -301,7 +272,7 @@ struct self_touches<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > template <typename Geometry> inline bool touches(Geometry const& geometry) { - return resolve_variant::self_touches<Geometry>::apply(geometry); + return resolve_dynamic::self_touches<Geometry>::apply(geometry); } @@ -325,7 +296,7 @@ inline bool touches(Geometry const& geometry) template <typename Geometry1, typename Geometry2> inline bool touches(Geometry1 const& geometry1, Geometry2 const& geometry2) { - return resolve_variant::touches + return resolve_dynamic::touches < Geometry1, Geometry2 >::apply(geometry1, geometry2, default_strategy()); @@ -350,7 +321,7 @@ inline bool touches(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { - return resolve_variant::touches + return resolve_dynamic::touches < Geometry1, Geometry2 >::apply(geometry1, geometry2, strategy); diff --git a/boost/geometry/algorithms/detail/tupled_output.hpp b/boost/geometry/algorithms/detail/tupled_output.hpp index e0f889745b..8d9652683a 100644 --- a/boost/geometry/algorithms/detail/tupled_output.hpp +++ b/boost/geometry/algorithms/detail/tupled_output.hpp @@ -389,7 +389,7 @@ struct output_geometry_access<TupledOut, Tag, DefaultTag, void> >::value; typedef typename geometry::tuples::element<index, TupledOut>::type type; - + template <typename Tuple> static typename geometry::tuples::element<index, Tuple>::type& get(Tuple & tup) @@ -593,8 +593,7 @@ struct convert_to_output<Geometry, SingleOut, true> static OutputIterator apply(Geometry const& geometry, OutputIterator oit) { - typedef typename boost::range_iterator<Geometry const>::type iterator; - for (iterator it = boost::begin(geometry); it != boost::end(geometry); ++it) + for (auto it = boost::begin(geometry); it != boost::end(geometry); ++it) { SingleOut single_out; geometry::convert(*it, single_out); diff --git a/boost/geometry/algorithms/detail/turns/remove_duplicate_turns.hpp b/boost/geometry/algorithms/detail/turns/remove_duplicate_turns.hpp index ccb19efb73..7819b5e2e1 100644 --- a/boost/geometry/algorithms/detail/turns/remove_duplicate_turns.hpp +++ b/boost/geometry/algorithms/detail/turns/remove_duplicate_turns.hpp @@ -1,18 +1,19 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014, Oracle and/or its affiliates. +// Copyright (c) 2014-2022, 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 -// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle - #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_TURNS_REMOVE_DUPLICATE_TURNS_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_TURNS_REMOVE_DUPLICATE_TURNS_HPP #include <algorithm> -#include <boost/geometry/algorithms/equals.hpp> +#include <boost/geometry/algorithms/detail/equals/point_point.hpp> namespace boost { namespace geometry { @@ -23,33 +24,27 @@ namespace detail { namespace turns template <typename Turns, bool Enable> struct remove_duplicate_turns { - static inline void apply(Turns&) {} + template <typename Strategy> + static inline void apply(Turns const&, Strategy const&) {} }; template <typename Turns> -class remove_duplicate_turns<Turns, true> +struct remove_duplicate_turns<Turns, true> { -private: - struct TurnEqualsTo - { - template <typename Turn> - bool operator()(Turn const& t1, Turn const& t2) const - { - return geometry::equals(t1.point, t2.point) - && t1.operations[0].seg_id == t2.operations[0].seg_id - && t1.operations[1].seg_id == t2.operations[1].seg_id; - } - }; - -public: - static inline void apply(Turns& turns) + template <typename Strategy> + static inline void apply(Turns& turns, Strategy const& strategy) { - turns.erase( std::unique(turns.begin(), turns.end(), - TurnEqualsTo()), - turns.end() - ); + turns.erase( + std::unique(turns.begin(), turns.end(), + [&](auto const& t1, auto const& t2) + { + return detail::equals::equals_point_point(t1.point, t2.point, strategy) + && t1.operations[0].seg_id == t2.operations[0].seg_id + && t1.operations[1].seg_id == t2.operations[1].seg_id; + }), + turns.end()); } }; diff --git a/boost/geometry/algorithms/detail/visit.hpp b/boost/geometry/algorithms/detail/visit.hpp index 60958f4b40..7cbf9e2318 100644 --- a/boost/geometry/algorithms/detail/visit.hpp +++ b/boost/geometry/algorithms/detail/visit.hpp @@ -181,20 +181,16 @@ struct visit_breadth_first<Geometry, dynamic_geometry_tag> } }; -// NOTE: This specialization works partially like std::visit and partially like -// std::ranges::for_each. If the argument is rvalue reference then the elements -// are passed into the function as rvalue references as well. This is consistent -// with std::visit but different than std::ranges::for_each. It's done this way -// because visit_breadth_first is also specialized for static and dynamic geometries -// which and references for them has to be propagated like that. If this is not -// desireable then the support for other kinds of geometries should be dropped and -// this algorithm should work only for geometry collection. -// This is not a problem right now because only non-rvalue references are passed -// but in the future there might be some issues. Consider e.g. passing a temporary -// mutable proxy range as geometry collection. In such case the elements would be -// passed as rvalue references which would be incorrect. -template <typename Geometry> -struct visit_breadth_first<Geometry, geometry_collection_tag> +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail +{ + +template <bool PassIterator = false> +struct visit_breadth_first_impl { template <typename F, typename Geom> static bool apply(F function, Geom && geom) @@ -217,7 +213,8 @@ struct visit_breadth_first<Geometry, geometry_collection_tag> bool result = true; traits::iter_visit<util::remove_cref_t<Geom>>::apply([&](auto && g) { - result = visit_or_enqueue(function, std::forward<decltype(g)>(g), queue, it); + result = visit_breadth_first_impl::visit_or_enqueue<PassIterator>( + function, std::forward<decltype(g)>(g), queue, it); }, it); if (! result) @@ -235,7 +232,7 @@ struct visit_breadth_first<Geometry, geometry_collection_tag> // so this call can be avoided. traits::iter_visit<util::remove_cref_t<Geom>>::apply([&](auto && g) { - set_iterators(std::forward<decltype(g)>(g), it, end); + visit_breadth_first_impl::set_iterators(std::forward<decltype(g)>(g), it, end); }, queue.front()); queue.pop_front(); } @@ -246,7 +243,7 @@ struct visit_breadth_first<Geometry, geometry_collection_tag> private: template < - typename F, typename Geom, typename Iterator, + bool PassIter, typename F, typename Geom, typename Iterator, std::enable_if_t<util::is_geometry_collection<Geom>::value, int> = 0 > static bool visit_or_enqueue(F &, Geom &&, std::deque<Iterator> & queue, Iterator iter) @@ -256,13 +253,22 @@ private: } template < - typename F, typename Geom, typename Iterator, - std::enable_if_t<! util::is_geometry_collection<Geom>::value, int> = 0 + bool PassIter, typename F, typename Geom, typename Iterator, + std::enable_if_t<! util::is_geometry_collection<Geom>::value && ! PassIter, int> = 0 > static bool visit_or_enqueue(F & f, Geom && g, std::deque<Iterator> & , Iterator) { return f(std::forward<Geom>(g)); } + template + < + bool PassIter, typename F, typename Geom, typename Iterator, + std::enable_if_t<! util::is_geometry_collection<Geom>::value && PassIter, int> = 0 + > + static bool visit_or_enqueue(F & f, Geom && g, std::deque<Iterator> & , Iterator iter) + { + return f(std::forward<Geom>(g), iter); + } template < @@ -283,6 +289,32 @@ private: {} }; +} // namespace detail +#endif // DOXYGEN_NO_DETAIL + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + +// NOTE: This specialization works partially like std::visit and partially like +// std::ranges::for_each. If the argument is rvalue reference then the elements +// are passed into the function as rvalue references as well. This is consistent +// with std::visit but different than std::ranges::for_each. It's done this way +// because visit_breadth_first is also specialized for static and dynamic geometries +// and references for them has to be propagated like that. If this is not +// desireable then the support for other kinds of geometries should be dropped and +// this algorithm should work only for geometry collection. Or forwarding of rvalue +// references should simply be dropped entirely. +// This is not a problem right now because only non-rvalue references are passed +// but in the future there might be some issues. Consider e.g. passing a temporary +// mutable proxy range as geometry collection. In such case the elements would be +// passed as rvalue references which would be incorrect. +template <typename Geometry> +struct visit_breadth_first<Geometry, geometry_collection_tag> + : detail::visit_breadth_first_impl<> +{}; + } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH diff --git a/boost/geometry/algorithms/detail/within/implementation.hpp b/boost/geometry/algorithms/detail/within/implementation.hpp index 72561cd890..b5300a9934 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-2021. -// Modifications copyright (c) 2013-2021 Oracle and/or its affiliates. +// This file was modified by Oracle on 2013-2022. +// Modifications copyright (c) 2013-2022 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -29,7 +29,8 @@ #include <boost/geometry/algorithms/detail/within/interface.hpp> #include <boost/geometry/algorithms/detail/within/multi_point.hpp> #include <boost/geometry/algorithms/detail/within/point_in_geometry.hpp> -#include <boost/geometry/algorithms/relate.hpp> +#include <boost/geometry/algorithms/detail/relate/implementation.hpp> +#include <boost/geometry/algorithms/detail/relate/relate_impl.hpp> #include <boost/geometry/core/access.hpp> #include <boost/geometry/core/closure.hpp> @@ -68,11 +69,12 @@ struct use_relate template <typename Geometry1, typename Geometry2, typename Strategy> static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { - typedef typename detail::de9im::static_mask_within_type + return detail::relate::relate_impl < - Geometry1, Geometry2 - >::type within_mask; - return geometry::relate(geometry1, geometry2, within_mask(), strategy); + detail::de9im::static_mask_within_type, + Geometry1, + Geometry2 + >::apply(geometry1, geometry2, strategy); } }; diff --git a/boost/geometry/algorithms/detail/within/implementation_gc.hpp b/boost/geometry/algorithms/detail/within/implementation_gc.hpp new file mode 100644 index 0000000000..6f40f318d8 --- /dev/null +++ b/boost/geometry/algorithms/detail/within/implementation_gc.hpp @@ -0,0 +1,46 @@ +// Boost.Geometry + +// Copyright (c) 2022 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) + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_WITHIN_IMPLEMENTATION_GC_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_WITHIN_IMPLEMENTATION_GC_HPP + + +#include <boost/geometry/algorithms/detail/relate/implementation_gc.hpp> +#include <boost/geometry/algorithms/detail/within/implementation.hpp> + + +namespace boost { namespace geometry { + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch { + +template <typename Geometry1, typename Geometry2> +struct within<Geometry1, Geometry2, geometry_collection_tag, geometry_collection_tag> + : detail::within::use_relate +{}; + +template <typename Geometry1, typename Geometry2, typename Tag1> +struct within<Geometry1, Geometry2, Tag1, geometry_collection_tag> + : detail::within::use_relate +{}; + +template <typename Geometry1, typename Geometry2, typename Tag2> +struct within<Geometry1, Geometry2, geometry_collection_tag, Tag2> + : detail::within::use_relate +{}; + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_WITHIN_IMPLEMENTATION_GC_HPP diff --git a/boost/geometry/algorithms/detail/within/interface.hpp b/boost/geometry/algorithms/detail/within/interface.hpp index 1a10ca84d8..572e0e5c94 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-2021. -// Modifications copyright (c) 2013-2021 Oracle and/or its affiliates. +// This file was modified by Oracle on 2013-2022. +// Modifications copyright (c) 2013-2022 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 @@ -21,16 +21,14 @@ #include <boost/concept_check.hpp> -#include <boost/variant/apply_visitor.hpp> -#include <boost/variant/static_visitor.hpp> -#include <boost/variant/variant_fwd.hpp> - #include <boost/geometry/algorithms/not_implemented.hpp> #include <boost/geometry/core/tag.hpp> #include <boost/geometry/core/tag_cast.hpp> +#include <boost/geometry/geometries/adapted/boost_variant.hpp> #include <boost/geometry/geometries/concepts/check.hpp> + #include <boost/geometry/strategies/concepts/within_concept.hpp> #include <boost/geometry/strategies/default_strategy.hpp> #include <boost/geometry/strategies/detail.hpp> @@ -126,10 +124,15 @@ struct within<default_strategy, false> } // namespace resolve_strategy -namespace resolve_variant +namespace resolve_dynamic { -template <typename Geometry1, typename Geometry2> +template +< + typename Geometry1, typename Geometry2, + typename Tag1 = typename geometry::tag<Geometry1>::type, + typename Tag2 = typename geometry::tag<Geometry2>::type +> struct within { template <typename Strategy> @@ -148,110 +151,66 @@ struct within } }; -template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2> -struct within<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2> +template <typename Geometry1, typename Geometry2, typename Tag2> +struct within<Geometry1, Geometry2, dynamic_geometry_tag, Tag2> { template <typename Strategy> - struct visitor: boost::static_visitor<bool> + static inline bool apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Strategy const& strategy) { - Geometry2 const& m_geometry2; - Strategy const& m_strategy; - - visitor(Geometry2 const& geometry2, Strategy const& strategy) - : m_geometry2(geometry2) - , m_strategy(strategy) - {} - - template <typename Geometry1> - bool operator()(Geometry1 const& geometry1) const + bool result = false; + traits::visit<Geometry1>::apply([&](auto const& g1) { - return within<Geometry1, Geometry2>::apply(geometry1, - m_geometry2, - m_strategy); - } - }; - - template <typename Strategy> - static inline bool - apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1, - Geometry2 const& geometry2, - Strategy const& strategy) - { - return boost::apply_visitor(visitor<Strategy>(geometry2, strategy), - geometry1); + result = within + < + util::remove_cref_t<decltype(g1)>, + Geometry2 + >::apply(g1, geometry2, strategy); + }, geometry1); + return result; } }; -template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)> -struct within<Geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > +template <typename Geometry1, typename Geometry2, typename Tag1> +struct within<Geometry1, Geometry2, Tag1, dynamic_geometry_tag> { template <typename Strategy> - struct visitor: boost::static_visitor<bool> + static inline bool apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Strategy const& strategy) { - Geometry1 const& m_geometry1; - Strategy const& m_strategy; - - visitor(Geometry1 const& geometry1, Strategy const& strategy) - : m_geometry1(geometry1) - , m_strategy(strategy) - {} - - template <typename Geometry2> - bool operator()(Geometry2 const& geometry2) const + bool result = false; + traits::visit<Geometry2>::apply([&](auto const& g2) { - return within<Geometry1, Geometry2>::apply(m_geometry1, - geometry2, - m_strategy); - } - }; - - template <typename Strategy> - static inline bool - apply(Geometry1 const& geometry1, - boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2, - Strategy const& strategy) - { - return boost::apply_visitor(visitor<Strategy>(geometry1, strategy), - geometry2 - ); + result = within + < + Geometry1, + util::remove_cref_t<decltype(g2)> + >::apply(geometry1, g2, strategy); + }, geometry2); + return result; } }; -template < - BOOST_VARIANT_ENUM_PARAMS(typename T1), - BOOST_VARIANT_ENUM_PARAMS(typename T2) -> -struct within< - boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>, - boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> -> +template <typename Geometry1, typename Geometry2> +struct within<Geometry1, Geometry2, dynamic_geometry_tag, dynamic_geometry_tag> { template <typename Strategy> - struct visitor: boost::static_visitor<bool> + static inline bool apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Strategy const& strategy) { - Strategy const& m_strategy; - - visitor(Strategy const& strategy): m_strategy(strategy) {} - - template <typename Geometry1, typename Geometry2> - bool operator()(Geometry1 const& geometry1, - Geometry2 const& geometry2) const + bool result = false; + traits::visit<Geometry1, Geometry2>::apply([&](auto const& g1, auto const& g2) { - return within<Geometry1, Geometry2>::apply(geometry1, - geometry2, - m_strategy); - } - }; - - template <typename Strategy> - static inline bool - apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1, - boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2, - Strategy const& strategy) - { - return boost::apply_visitor(visitor<Strategy>(strategy), - geometry1, - geometry2); + result = within + < + util::remove_cref_t<decltype(g1)>, + util::remove_cref_t<decltype(g2)> + >::apply(g1, g2, strategy); + }, geometry1, geometry2); + return result; } }; @@ -282,7 +241,7 @@ struct within< template<typename Geometry1, typename Geometry2> inline bool within(Geometry1 const& geometry1, Geometry2 const& geometry2) { - return resolve_variant::within + return resolve_dynamic::within < Geometry1, Geometry2 @@ -320,7 +279,7 @@ inline bool within(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { - return resolve_variant::within + return resolve_dynamic::within < Geometry1, Geometry2 diff --git a/boost/geometry/algorithms/detail/within/multi_point.hpp b/boost/geometry/algorithms/detail/within/multi_point.hpp index 349ef03026..be984e9364 100644 --- a/boost/geometry/algorithms/detail/within/multi_point.hpp +++ b/boost/geometry/algorithms/detail/within/multi_point.hpp @@ -1,6 +1,10 @@ // Boost.Geometry -// Copyright (c) 2017-2020, Oracle and/or its affiliates. +// Copyright (c) 2023 Adam Wulkiewicz, Lodz, Poland. + +// Copyright (c) 2017-2023, 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, @@ -38,6 +42,7 @@ #include <boost/geometry/strategies/covered_by.hpp> #include <boost/geometry/strategies/disjoint.hpp> +#include <boost/geometry/util/condition.hpp> #include <boost/geometry/util/type_traits.hpp> @@ -55,8 +60,7 @@ struct multi_point_point { auto const s = strategy.relate(multi_point, point); - typedef typename boost::range_const_iterator<MultiPoint>::type iterator; - for ( iterator it = boost::begin(multi_point) ; it != boost::end(multi_point) ; ++it ) + for (auto it = boost::begin(multi_point); it != boost::end(multi_point); ++it) { if (! s.apply(*it, point)) { @@ -78,8 +82,7 @@ struct multi_point_multi_point Strategy const& /*strategy*/) { typedef typename boost::range_value<MultiPoint2>::type point2_type; - typedef typename Strategy::cs_tag cs_tag; - typedef geometry::less<void, -1, cs_tag> less_type; + typedef geometry::less<void, -1, Strategy> less_type; less_type const less = less_type(); @@ -88,8 +91,7 @@ struct multi_point_multi_point bool result = false; - typedef typename boost::range_const_iterator<MultiPoint1>::type iterator; - for ( iterator it = boost::begin(multi_point1) ; it != boost::end(multi_point1) ; ++it ) + for (auto it = boost::begin(multi_point1); it != boost::end(multi_point1); ++it) { if (! std::binary_search(points2.begin(), points2.end(), *it, less)) { @@ -134,13 +136,12 @@ struct multi_point_single_geometry // If in the exterior, break bool result = false; - typedef typename boost::range_const_iterator<MultiPoint>::type iterator; - for ( iterator it = boost::begin(multi_point) ; it != boost::end(multi_point) ; ++it ) + for (auto it = boost::begin(multi_point); it != boost::end(multi_point); ++it ) { typedef decltype(strategy.covered_by(*it, box)) point_in_box_type; int in_val = 0; - + // exterior of box and of geometry if (! point_in_box_type::apply(*it, box) || (in_val = point_in_geometry(*it, linear_or_areal, strategy)) < 0) @@ -198,8 +199,7 @@ struct multi_point_multi_geometry // If a point is in the exterior break bool result = false; - typedef typename boost::range_const_iterator<MultiPoint>::type iterator; - for ( iterator it = boost::begin(multi_point) ; it != boost::end(multi_point) ; ++it ) + for (auto it = boost::begin(multi_point); it != boost::end(multi_point); ++it) { // TODO: investigate the possibility of using satisfies // TODO: investigate the possibility of using iterative queries (optimization below) @@ -238,7 +238,7 @@ struct multi_point_multi_geometry if (boundaries > 0) { - if (is_linear && boundaries % 2 == 0) + if (BOOST_GEOMETRY_CONDITION(is_linear) && boundaries % 2 == 0) { found_interior = true; } diff --git a/boost/geometry/algorithms/detail/within/point_in_geometry.hpp b/boost/geometry/algorithms/detail/within/point_in_geometry.hpp index c9b9cbfd81..459e54ec85 100644 --- a/boost/geometry/algorithms/detail/within/point_in_geometry.hpp +++ b/boost/geometry/algorithms/detail/within/point_in_geometry.hpp @@ -30,7 +30,6 @@ #include <boost/geometry/algorithms/detail/assign_indexed_point.hpp> #include <boost/geometry/algorithms/detail/equals/point_point.hpp> -#include <boost/geometry/algorithms/detail/interior_iterator.hpp> #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/strategies/concepts/within_concept.hpp> @@ -49,13 +48,12 @@ int point_in_range(Point const& point, Range const& range, Strategy const& strat { typename Strategy::state_type state; - typedef typename boost::range_iterator<Range const>::type iterator_type; - iterator_type it = boost::begin(range); - iterator_type end = boost::end(range); + auto it = boost::begin(range); + auto const end = boost::end(range); - for ( iterator_type previous = it++ ; it != end ; ++previous, ++it ) + for (auto previous = it++; it != end; ++previous, ++it) { - if ( ! strategy.apply(point, *previous, *it, state) ) + if (! strategy.apply(point, *previous, *it, state)) { break; } @@ -202,13 +200,8 @@ struct point_in_geometry<Polygon, polygon_tag> if (code == 1) { - typename interior_return_type<Polygon const>::type - rings = interior_rings(polygon); - - for (typename detail::interior_iterator<Polygon const>::type - it = boost::begin(rings); - it != boost::end(rings); - ++it) + auto const& rings = interior_rings(polygon); + for (auto it = boost::begin(rings); it != boost::end(rings); ++it) { int const interior_code = point_in_geometry < @@ -235,14 +228,16 @@ struct point_in_geometry<Geometry, multi_point_tag> int apply(Point const& point, Geometry const& geometry, Strategy const& strategy) { typedef typename boost::range_value<Geometry>::type point_type; - typedef typename boost::range_const_iterator<Geometry>::type iterator; - for ( iterator it = boost::begin(geometry) ; it != boost::end(geometry) ; ++it ) + for (auto it = boost::begin(geometry); it != boost::end(geometry); ++it) { int pip = point_in_geometry<point_type>::apply(point, *it, strategy); //BOOST_GEOMETRY_ASSERT(pip != 0); - if ( pip > 0 ) // inside + if (pip > 0) + { + // inside return 1; + } } return -1; // outside @@ -259,14 +254,13 @@ struct point_in_geometry<Geometry, multi_linestring_tag> typedef typename boost::range_value<Geometry>::type linestring_type; typedef typename boost::range_value<linestring_type>::type point_type; - typedef typename boost::range_iterator<Geometry const>::type iterator; - iterator it = boost::begin(geometry); - for ( ; it != boost::end(geometry) ; ++it ) + auto it = boost::begin(geometry); + for ( ; it != boost::end(geometry); ++it) { pip = point_in_geometry<linestring_type>::apply(point, *it, strategy); // inside or on the boundary - if ( pip >= 0 ) + if (pip >= 0) { ++it; break; @@ -274,24 +268,30 @@ struct point_in_geometry<Geometry, multi_linestring_tag> } // outside - if ( pip < 0 ) + if (pip < 0) + { return -1; + } // TODO: the following isn't needed for covered_by() unsigned boundaries = pip == 0 ? 1 : 0; - for ( ; it != boost::end(geometry) ; ++it ) + for (; it != boost::end(geometry); ++it) { - if ( boost::size(*it) < 2 ) + if (boost::size(*it) < 2) + { continue; + } point_type const& front = range::front(*it); point_type const& back = range::back(*it); // is closed_ring - no boundary - if ( detail::equals::equals_point_point(front, back, strategy) ) + if (detail::equals::equals_point_point(front, back, strategy)) + { continue; + } // is point on boundary if ( detail::equals::equals_point_point(point, front, strategy) @@ -316,14 +316,15 @@ struct point_in_geometry<Geometry, multi_polygon_tag> //int res = -1; // outside typedef typename boost::range_value<Geometry>::type polygon_type; - typedef typename boost::range_const_iterator<Geometry>::type iterator; - for ( iterator it = boost::begin(geometry) ; it != boost::end(geometry) ; ++it ) + for (auto it = boost::begin(geometry); it != boost::end(geometry); ++it) { int pip = point_in_geometry<polygon_type>::apply(point, *it, strategy); // inside or on the boundary - if ( pip >= 0 ) + if (pip >= 0) + { return pip; + } // For invalid multi-polygons //if ( 1 == pip ) // inside polygon diff --git a/boost/geometry/algorithms/detail/within/within_no_turns.hpp b/boost/geometry/algorithms/detail/within/within_no_turns.hpp index 8da05e58fd..d6d0417c3b 100644 --- a/boost/geometry/algorithms/detail/within/within_no_turns.hpp +++ b/boost/geometry/algorithms/detail/within/within_no_turns.hpp @@ -4,8 +4,9 @@ // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. -// This file was modified by Oracle on 2013. -// Modifications copyright (c) 2013, Oracle and/or its affiliates. +// This file was modified by Oracle on 2013-2023. +// Modifications copyright (c) 2013-2023, Oracle and/or its affiliates. +// Contributed and/or modified by Vissarion Fysikopoulos, 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. @@ -41,8 +42,10 @@ struct within_no_turns { typedef typename geometry::point_type<Geometry1>::type point1_type; point1_type p; - if ( !geometry::point_on_border(p, geometry1) ) + if (! geometry::point_on_border(p, geometry1)) + { return false; + } return detail::within::point_in_geometry(p, geometry2, strategy) >= 0; } @@ -57,25 +60,28 @@ struct within_no_turns<Geometry1, Geometry2, ring_tag, polygon_tag> typedef typename geometry::point_type<Geometry1>::type point1_type; typedef typename geometry::point_type<Geometry2>::type point2_type; point1_type p; - if ( !geometry::point_on_border(p, geometry1) ) + if (! geometry::point_on_border(p, geometry1)) + { return false; + } // check if one of ring points is outside the polygon - if ( detail::within::point_in_geometry(p, geometry2, strategy) < 0 ) + if (detail::within::point_in_geometry(p, geometry2, strategy) < 0) + { return false; + } // Now check if holes of G2 aren't inside G1 - typedef typename boost::range_const_iterator - < - typename geometry::interior_type<Geometry2>::type - >::type iterator; - for ( iterator it = boost::begin(geometry::interior_rings(geometry2)) ; - it != boost::end(geometry::interior_rings(geometry2)) ; - ++it ) + auto const& rings2 = geometry::interior_rings(geometry2); + for (auto it = boost::begin(rings2); it != boost::end(rings2); ++it) { point2_type p; - if ( !geometry::point_on_border(p, *it) ) + if (! geometry::point_on_border(p, *it)) + { return false; - if ( detail::within::point_in_geometry(p, geometry1, strategy) > 0 ) + } + if (detail::within::point_in_geometry(p, geometry1, strategy) > 0) + { return false; + } } return true; } @@ -90,44 +96,42 @@ struct within_no_turns<Geometry1, Geometry2, polygon_tag, polygon_tag> typedef typename geometry::point_type<Geometry1>::type point1_type; typedef typename geometry::point_type<Geometry2>::type point2_type; point1_type p; - if ( !geometry::point_on_border(p, geometry1) ) + if (! geometry::point_on_border(p, geometry1)) + { return false; + } // check if one of ring points is outside the polygon - if ( detail::within::point_in_geometry(p, geometry2, strategy) < 0 ) + if (detail::within::point_in_geometry(p, geometry2, strategy) < 0) + { return false; + } // Now check if holes of G2 aren't inside G1 - typedef typename boost::range_const_iterator - < - typename geometry::interior_type<Geometry2>::type - >::type iterator2; - for ( iterator2 it = boost::begin(geometry::interior_rings(geometry2)) ; - it != boost::end(geometry::interior_rings(geometry2)) ; - ++it ) + auto const& rings2 = geometry::interior_rings(geometry2); + for (auto it2 = boost::begin(rings2); it2 != boost::end(rings2); ++it2) { point2_type p2; - if ( !geometry::point_on_border(p2, *it) ) + if (! geometry::point_on_border(p2, *it2)) + { return false; + } // if the hole of G2 is inside G1 - if ( detail::within::point_in_geometry(p2, geometry1, strategy) > 0 ) + if (detail::within::point_in_geometry(p2, geometry1, strategy) > 0) { // if it's also inside one of the G1 holes, it's ok bool ok = false; - typedef typename boost::range_const_iterator - < - typename geometry::interior_type<Geometry1>::type - >::type iterator1; - for ( iterator1 it1 = boost::begin(geometry::interior_rings(geometry1)) ; - it1 != boost::end(geometry::interior_rings(geometry1)) ; - ++it1 ) + auto const& rings1 = geometry::interior_rings(geometry1); + for (auto it1 = boost::begin(rings1); it1 != boost::end(rings1); ++it1) { - if ( detail::within::point_in_geometry(p2, *it1, strategy) < 0 ) + if (detail::within::point_in_geometry(p2, *it1, strategy) < 0) { ok = true; break; } } - if ( !ok ) + if (! ok) + { return false; + } } } return true; @@ -157,11 +161,12 @@ struct within_no_turns_multi<Geometry1, Geometry2, Tag1, Tag2, true, false> { // All values of G1 must be inside G2 typedef typename boost::range_value<Geometry1>::type subgeometry1; - typedef typename boost::range_const_iterator<Geometry1>::type iterator; - for ( iterator it = boost::begin(geometry1) ; it != boost::end(geometry1) ; ++it ) + for (auto it = boost::begin(geometry1) ; it != boost::end(geometry1) ; ++it ) { - if ( !within_no_turns<subgeometry1, Geometry2>::apply(*it, geometry2, strategy) ) + if (! within_no_turns<subgeometry1, Geometry2>::apply(*it, geometry2, strategy)) + { return false; + } } return true; } @@ -175,11 +180,12 @@ struct within_no_turns_multi<Geometry1, Geometry2, Tag1, Tag2, false, true> { // G1 must be within at least one value of G2 typedef typename boost::range_value<Geometry2>::type subgeometry2; - typedef typename boost::range_const_iterator<Geometry2>::type iterator; - for ( iterator it = boost::begin(geometry2) ; it != boost::end(geometry2) ; ++it ) + for (auto it = boost::begin(geometry2); it != boost::end(geometry2); ++it) { - if ( within_no_turns<Geometry1, subgeometry2>::apply(geometry1, *it, strategy) ) + if (within_no_turns<Geometry1, subgeometry2>::apply(geometry1, *it, strategy)) + { return true; + } } return false; } @@ -193,11 +199,12 @@ struct within_no_turns_multi<Geometry1, Geometry2, Tag1, Tag2, true, true> { // each value of G1 must be inside at least one value of G2 typedef typename boost::range_value<Geometry1>::type subgeometry1; - typedef typename boost::range_const_iterator<Geometry1>::type iterator; - for ( iterator it = boost::begin(geometry1) ; it != boost::end(geometry1) ; ++it ) + for (auto it = boost::begin(geometry1) ; it != boost::end(geometry1) ; ++it) { - if ( !within_no_turns_multi<subgeometry1, Geometry2>::apply(*it, geometry2, strategy) ) + if (! within_no_turns_multi<subgeometry1, Geometry2>::apply(*it, geometry2, strategy)) + { return false; + } } return true; } |