From d7890385a68f3c8bb8ced8da57460bbfe29eb884 Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Fri, 29 Sep 2023 14:57:32 +0200 Subject: [PATCH 1/5] [experimental] update buffer and test with partition version with lambdas --- .../detail/buffer/buffer_policies.hpp | 90 ---------- .../buffer/buffered_piece_collection.hpp | 132 +++++++++++--- .../buffer/turn_in_original_visitor.hpp | 68 ------- .../algorithms/detail/partition_lambda.hpp | 148 +++++++++++++++ test/robustness/within/Jamfile | 17 ++ test/robustness/within/partition_within.cpp | 168 ++++++------------ 6 files changed, 330 insertions(+), 293 deletions(-) create mode 100644 include/boost/geometry/algorithms/detail/partition_lambda.hpp create mode 100644 test/robustness/within/Jamfile diff --git a/include/boost/geometry/algorithms/detail/buffer/buffer_policies.hpp b/include/boost/geometry/algorithms/detail/buffer/buffer_policies.hpp index e75532c3f3..4a699f4677 100644 --- a/include/boost/geometry/algorithms/detail/buffer/buffer_policies.hpp +++ b/include/boost/geometry/algorithms/detail/buffer/buffer_policies.hpp @@ -191,96 +191,6 @@ struct buffer_less } }; -template -struct piece_get_box -{ - explicit piece_get_box(Strategy const& strategy) - : m_strategy(strategy) - {} - - template - inline void apply(Box& total, Piece const& piece) const - { - assert_coordinate_type_equal(total, piece.m_piece_border.m_envelope); - - if (piece.m_piece_border.m_has_envelope) - { - geometry::expand(total, piece.m_piece_border.m_envelope, - m_strategy); - } - } - - Strategy const& m_strategy; -}; - -template -struct piece_overlaps_box -{ - explicit piece_overlaps_box(Strategy const& strategy) - : m_strategy(strategy) - {} - - template - inline bool apply(Box const& box, Piece const& piece) const - { - assert_coordinate_type_equal(box, piece.m_piece_border.m_envelope); - - if (piece.type == strategy::buffer::buffered_flat_end - || piece.type == strategy::buffer::buffered_concave) - { - // Turns cannot be inside a flat end (though they can be on border) - // Neither we need to check if they are inside concave helper pieces - - // Skip all pieces not used as soon as possible - return false; - } - if (! piece.m_piece_border.m_has_envelope) - { - return false; - } - - return ! geometry::detail::disjoint::disjoint_box_box(box, piece.m_piece_border.m_envelope, - m_strategy); - } - - Strategy const& m_strategy; -}; - -template -struct turn_get_box -{ - explicit turn_get_box(Strategy const& strategy) - : m_strategy(strategy) - {} - - template - inline void apply(Box& total, Turn const& turn) const - { - assert_coordinate_type_equal(total, turn.point); - geometry::expand(total, turn.point, m_strategy); - } - - Strategy const& m_strategy; -}; - -template -struct turn_overlaps_box -{ - explicit turn_overlaps_box(Strategy const& strategy) - : m_strategy(strategy) - {} - - template - inline bool apply(Box const& box, Turn const& turn) const - { - assert_coordinate_type_equal(turn.point, box); - return ! geometry::detail::disjoint::disjoint_point_box(turn.point, box, - m_strategy); - } - - Strategy const& m_strategy; -}; - struct enriched_map_buffer_include_policy { template diff --git a/include/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp b/include/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp index 66943b303c..65faac16de 100644 --- a/include/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp +++ b/include/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp @@ -54,7 +54,7 @@ #include #include #include -#include +#include #include #include @@ -358,22 +358,59 @@ struct buffered_piece_collection // Check if a turn is inside any of the originals inline void check_turn_in_original() { + auto const& strategy = m_strategy; + + struct specific_options : experimental::partition_options + { + struct include_turn_policy + { + static inline bool apply(buffer_turn_info_type const& turn) + { + return turn.is_turn_traversable && ! turn.within_original; + } + }; + + using include_policy1 = include_turn_policy; + }; + turn_in_original_visitor < turn_vector_type, Strategy > visitor(m_turns, m_strategy); - geometry::partition + // Partition over the turns and original rings, visiting + // all turns located in an original and changing the turn's + // "count_in_original" and "within_original" values + experimental::partition < - box_type, - include_turn_policy, - detail::partition::include_all_policy - >::apply(m_turns, original_rings, visitor, - turn_get_box(m_strategy), - turn_in_original_overlaps_box(m_strategy), - original_get_box(m_strategy), - original_overlaps_box(m_strategy)); + box_type + >(m_turns, original_rings, + [&strategy](auto& box, auto const& turn) + { + geometry::expand(box, turn.point, strategy); + }, + [&strategy](auto& box, auto const& turn) + { + return ! geometry::detail::disjoint::disjoint_point_box(turn.point, + box, strategy); + }, + [&strategy](auto& box, auto const& original) + { + geometry::expand(box, original.m_box, strategy); + }, + [&strategy](auto& box, auto const& original) + { + return ! detail::disjoint::disjoint_box_box(box, + original.m_box, strategy); + }, + [&visitor](auto const& turn, auto const& original) + { + return visitor.apply(turn, original); + }, + [](auto const&, int) {}, + specific_options() + ); bool const deflate = m_distance_strategy.negative(); @@ -447,6 +484,8 @@ struct buffered_piece_collection { update_piece_administration(); + auto const& strategy = m_strategy; + { // Calculate the turns piece_turn_visitor @@ -461,32 +500,75 @@ struct buffered_piece_collection detail::sectionalize::enlarge_sections(monotonic_sections, m_strategy); - geometry::partition - < - robust_box_type - >::apply(monotonic_sections, visitor, - detail::section::get_section_box(m_strategy), - detail::section::overlaps_section_box(m_strategy)); + experimental::partition(monotonic_sections, + [&strategy](auto& box, auto const& section) + { + geometry::expand(box, section.bounding_box, strategy); + }, + [&strategy](auto const& box, auto const& section) + { + return ! detail::disjoint::disjoint_box_box(box, + section.bounding_box, strategy); + }, + [&visitor](auto const& section1, auto const& section2) + { + return visitor.apply(section1, section2); + } + ); } + update_turn_administration(); { - // Check if turns are inside pieces turn_in_piece_visitor < typename geometry::cs_tag::type, turn_vector_type, piece_vector_type, DistanceStrategy, Strategy > visitor(m_turns, m_pieces, m_distance_strategy, m_strategy); - geometry::partition - < - box_type - >::apply(m_turns, m_pieces, visitor, - turn_get_box(m_strategy), - turn_overlaps_box(m_strategy), - piece_get_box(m_strategy), - piece_overlaps_box(m_strategy)); + // Partition over the turns and pieces, checking if turns are inside pieces. + experimental::partition(m_turns, m_pieces, + [&strategy](auto& box, auto const& turn) + { + geometry::expand(box, turn.point, strategy); + }, + [&strategy](auto& box, auto const& turn) + { + return ! geometry::detail::disjoint::disjoint_point_box(turn.point, + box, strategy); + }, + [&strategy](auto& box, auto const& piece) + { + if (piece.m_piece_border.m_has_envelope) + { + geometry::expand(box, piece.m_piece_border.m_envelope, strategy); + } + }, + [&strategy](auto& box, auto const& piece) + { + if (piece.type == strategy::buffer::buffered_flat_end + || piece.type == strategy::buffer::buffered_concave) + { + // Turns cannot be inside a flat end (though they can be on border) + // Neither we need to check if they are inside concave helper pieces + + // Skip all pieces not used as soon as possible + return false; + } + if (! piece.m_piece_border.m_has_envelope) + { + return false; + } + + return ! geometry::detail::disjoint::disjoint_box_box(box, + piece.m_piece_border.m_envelope, strategy); + }, + [&visitor](auto const& turn, auto const& piece) + { + return visitor.apply(turn, piece); + } + ); } } diff --git a/include/boost/geometry/algorithms/detail/buffer/turn_in_original_visitor.hpp b/include/boost/geometry/algorithms/detail/buffer/turn_in_original_visitor.hpp index 12fffc4c4a..d3b6abebf6 100644 --- a/include/boost/geometry/algorithms/detail/buffer/turn_in_original_visitor.hpp +++ b/include/boost/geometry/algorithms/detail/buffer/turn_in_original_visitor.hpp @@ -34,74 +34,6 @@ namespace boost { namespace geometry namespace detail { namespace buffer { - -template -struct original_get_box -{ - explicit original_get_box(Strategy const& strategy) - : m_strategy(strategy) - {} - - template - inline void apply(Box& total, Original const& original) const - { - assert_coordinate_type_equal(total, original.m_box); - geometry::expand(total, original.m_box, m_strategy); - } - - Strategy const& m_strategy; -}; - -template -struct original_overlaps_box -{ - explicit original_overlaps_box(Strategy const& strategy) - : m_strategy(strategy) - {} - - template - inline bool apply(Box const& box, Original const& original) const - { - assert_coordinate_type_equal(box, original.m_box); - return ! detail::disjoint::disjoint_box_box(box, original.m_box, - m_strategy); - } - - Strategy const& m_strategy; -}; - -struct include_turn_policy -{ - template - static inline bool apply(Turn const& turn) - { - return turn.is_turn_traversable; - } -}; - -template -struct turn_in_original_overlaps_box -{ - explicit turn_in_original_overlaps_box(Strategy const& strategy) - : m_strategy(strategy) - {} - - template - inline bool apply(Box const& box, Turn const& turn) const - { - if (! turn.is_turn_traversable || turn.within_original) - { - // Skip all points already processed - return false; - } - - return ! geometry::detail::disjoint::disjoint_point_box( - turn.point, box, m_strategy); - } - - Strategy const& m_strategy; -}; - //! Check if specified is in range of specified iterators //! Return value of strategy (true if we can bail out) template diff --git a/include/boost/geometry/algorithms/detail/partition_lambda.hpp b/include/boost/geometry/algorithms/detail/partition_lambda.hpp new file mode 100644 index 0000000000..84eb9719f8 --- /dev/null +++ b/include/boost/geometry/algorithms/detail/partition_lambda.hpp @@ -0,0 +1,148 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// 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_PARTITION_LAMBDA_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_PARTITION_LAMBDA_HPP + +#include +#include + +#include + +namespace boost { namespace geometry { namespace experimental +{ + +template +struct adapt_partition_visitor +{ + F m_f; + + explicit adapt_partition_visitor(F&& f) + : m_f(std::move(f)) + {} + + template + decltype(auto) apply(Ts&& ...is) const + { + return m_f(std::forward(is)...); + } +}; + +struct partition_options +{ + // Include policy for the (first) range + using include_policy1 = detail::partition::include_all_policy; + + // Include policy for the second range + using include_policy2 = detail::partition::include_all_policy; + + // Defines the end of the iteration (as soon as range 1 or range 2 has + // these number of elements, or less, it will switch to iterative mode) + std::size_t min_elements = 16; +}; + +template +< + typename BoxType, + typename ForwardRange1, + typename ForwardRange2, + typename Options = partition_options +> +bool partition(ForwardRange1 const& forward_range1, + ForwardRange2 const& forward_range2, + const std::function + < + void(BoxType&, + typename boost::range_value::type const&) + >& expand_policy1, + const std::function + < + bool(BoxType const&, + typename boost::range_value::type const&) + >& overlaps_policy1, + const std::function + < + void(BoxType&, + typename boost::range_value::type const&) + >& expand_policy2, + const std::function + < + bool(BoxType const&, + typename boost::range_value::type const&) + >& overlaps_policy2, + const std::function + < + bool(typename boost::range_value::type const&, + typename boost::range_value::type const&) + >& visitor, + const std::function + < + void(BoxType const&, int level) + >& box_visitor = [](auto const&, int) {}, + const Options& options = {}) +{ + adapt_partition_visitor av(visitor); + adapt_partition_visitor aev1(expand_policy1); + adapt_partition_visitor aev2(expand_policy2); + adapt_partition_visitor aov1(overlaps_policy1); + adapt_partition_visitor aov2(overlaps_policy2); + adapt_partition_visitor apbv(box_visitor); + + return geometry::partition + < + BoxType, + typename Options::include_policy1, + typename Options::include_policy2 + >::apply(forward_range1, forward_range2, av, + aev1, aov1, + aev2, aov2, options.min_elements, apbv); +} + +template +< + typename BoxType, + typename ForwardRange, + typename Options = partition_options +> +bool partition(ForwardRange const& forward_range, + const std::function + < + void(BoxType&, + typename boost::range_value::type const&) + >& expand_policy, + const std::function + < + bool(BoxType const&, + typename boost::range_value::type const&) + >& overlaps_policy, + const std::function + < + bool(typename boost::range_value::type const&, + typename boost::range_value::type const&) + >& visitor, + const std::function + < + void(BoxType const&, int level) + >& box_visitor = [](auto const&, int) {}, + const Options& options = {}) +{ + adapt_partition_visitor av(visitor); + adapt_partition_visitor aev(expand_policy); + adapt_partition_visitor aov(overlaps_policy); + adapt_partition_visitor apbv(box_visitor); + + return geometry::partition + < + BoxType, + typename Options::include_policy1 + >::apply(forward_range, av, + aev, aov, options.min_elements, apbv); +} + +}}} // namespace boost::geometry::experimental + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_PARTITION_LAMBDA_HPP diff --git a/test/robustness/within/Jamfile b/test/robustness/within/Jamfile new file mode 100644 index 0000000000..aa967f4a94 --- /dev/null +++ b/test/robustness/within/Jamfile @@ -0,0 +1,17 @@ +# Boost.Geometry (aka GGL, Generic Geometry Library) +# Robustness Test - partition and within +# +# 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) + + +project partition_within + : requirements + . + static + ; + +exe partition_within : partition_within.cpp ; diff --git a/test/robustness/within/partition_within.cpp b/test/robustness/within/partition_within.cpp index f42842fa83..5614c5e29e 100644 --- a/test/robustness/within/partition_within.cpp +++ b/test/robustness/within/partition_within.cpp @@ -13,6 +13,8 @@ #include #include +#include + #if defined(TEST_WITH_SVG) # include #endif @@ -43,112 +45,41 @@ struct ring_item BOOST_GEOMETRY_REGISTER_POINT_2D(point_item, double, cs::cartesian, x, y) - -struct expand_for_point -{ - template - static inline void apply(Box& total, InputItem const& item) - { - bg::expand(total, item); - } -}; - -struct overlaps_point +#if defined(TEST_WITH_SVG) +template +void create_svg(std::size_t size, Points const& points, Rings const& rings, std::size_t index, + Box const& box, int level, + Boxes& boxes) { - template - static inline bool apply(Box const& box, InputItem const& item) - { - return ! bg::disjoint(item, box); - } -}; + std::ostringstream filename; + filename << "partition_demo_" << std::setfill('0') << std::setw(3) << index << "_" << level << ".svg"; + std::ofstream svg(filename.str()); + bg::svg_mapper mapper(svg, 800, 800); -struct expand_for_ring -{ - template - static inline void apply(Box& total, InputItem const& item) { - bg::expand(total, item.box); + point_item p; + p.x = -1; p.y = -1; mapper.add(p); + p.x = size + 1; p.y = size + 1; mapper.add(p); } -}; -struct overlaps_ring -{ - template - static inline bool apply(Box const& box, InputItem const& item) + for (auto const& item : rings) { - typename bg::strategy::disjoint::services::default_strategy - < - Box, Box - >::type strategy; - - return ! bg::detail::disjoint::disjoint_box_box(box, item.box, strategy); + mapper.map(item.ring, "opacity:0.6;fill:rgb(0,255,0);stroke:rgb(0,0,0);stroke-width:0.1"); } -}; - -struct point_in_ring_visitor -{ - std::size_t count = 0; - - template - inline bool apply(Point const& point, BoxItem const& ring_item) + for (auto const& point : points) { - if (bg::within(point, ring_item.ring)) - { - count++; - } - return true; + mapper.map(point, "fill:rgb(0,0,255);stroke:rgb(0,0,100);stroke-width:0.1", 3); } -}; -#if defined(TEST_WITH_SVG) -template -struct svg_visitor -{ - std::vector boxes; - Points const& m_points; - Rings const& m_rings; - std::size_t m_size = 0; - std::size_t m_index = 0; - - svg_visitor(std::size_t size, Points const& points, Rings const& rings) - : m_points(points) - , m_rings(rings) - , m_size(size) - {} - - inline void apply(Box const& box, int level) + for (auto const& b : boxes) { - std::ostringstream filename; - filename << "partition_demo_" << std::setfill('0') << std::setw(3) << m_index++ << "_" << level << ".svg"; - std::ofstream svg(filename.str()); - - bg::svg_mapper mapper(svg, 800, 800); - - { - point_item p; - p.x = -1; p.y = -1; mapper.add(p); - p.x = m_size + 1; p.y = m_size + 1; mapper.add(p); - } - - for (auto const& item : m_rings) - { - mapper.map(item.ring, "opacity:0.6;fill:rgb(0,255,0);stroke:rgb(0,0,0);stroke-width:0.1"); - } - for (auto const& point : m_points) - { - mapper.map(point, "fill:rgb(0,0,255);stroke:rgb(0,0,100);stroke-width:0.1", 3); - } - - for (auto const& b : boxes) - { - mapper.map(b, "fill:none;stroke-width:2;stroke:rgb(64,64,64);"); - } - mapper.map(box, "fill:none;stroke-width:4;stroke:rgb(255, 0, 0);"); - - boxes.push_back(box); + mapper.map(b, "fill:none;stroke-width:2;stroke:rgb(64,64,64);"); } -}; + mapper.map(box, "fill:none;stroke-width:4;stroke:rgb(255, 0, 0);"); + + boxes.push_back(box); +} #endif @@ -161,7 +92,7 @@ void fill_points(Collection& collection, std::size_t size, std::size_t count) std::uniform_real_distribution uniform_dist(0, size - 1); int const mean_x = uniform_dist(rde); int const mean_y = uniform_dist(rde); - + // Generate a normal distribution around these means std::seed_seq seed2{rd(), rd(), rd(), rd(), rd(), rd(), rd(), rd()}; std::mt19937 e2(seed2); @@ -302,7 +233,7 @@ void call_within(std::size_t size, std::size_t count) auto report = [&points, &rings](const char* title, auto const& start, std::size_t within_count) { auto const finish = std::chrono::steady_clock::now(); - double const elapsed + double const elapsed = std::chrono::duration_cast(finish - start).count(); std::cout << title << " time: " << std::setprecision(6) << elapsed / 1000000.0 << " ms" << std::endl; @@ -311,27 +242,44 @@ void call_within(std::size_t size, std::size_t count) return elapsed; }; - point_in_ring_visitor count_visitor; - { #if defined(TEST_WITH_SVG) - - using partition_box_visitor_type = svg_visitor, std::vector>>; - partition_box_visitor_type partition_box_visitor(size, points, rings); + std::size_t index = 0; + std::vector boxes; + auto box_visitor = [&](auto const& box, int level) + { + create_svg(size, points, rings, index++, box, level, boxes); + }; #else - using partition_box_visitor_type = bg::detail::partition::visit_no_policy; - partition_box_visitor_type partition_box_visitor; + auto box_visitor = [&](auto const& , int ) {}; #endif + std::size_t partition_count = 0; + { auto const start = std::chrono::steady_clock::now(); - bg::partition + typename bg::strategy::disjoint::services::default_strategy < - box_type, - bg::detail::partition::include_all_policy, - bg::detail::partition::include_all_policy - >::apply(points, rings, count_visitor, expand_for_point(), overlaps_point(), - expand_for_ring(), overlaps_ring(), 16, partition_box_visitor); - report("Partition", start, count_visitor.count); + box_type, box_type + >::type strategy; + + bg::experimental::partition(points, + rings, + [](auto& box, auto const& point) { bg::expand(box, point); }, + [](auto const& box, auto const& point) { return ! bg::disjoint(point, box); }, + [](auto& box, auto const& item) { bg::expand(box, item.box); }, + [&strategy](auto const& box, auto const& item) { return ! bg::disjoint(box, item.box, strategy); }, + [&partition_count](auto const& p, auto const& ri) + { + if (bg::within(p, ri.ring)) + { + partition_count++; + } + return true; + }, + box_visitor + ); + + report("Partition", start, partition_count); } { @@ -350,7 +298,7 @@ void call_within(std::size_t size, std::size_t count) } report("Quadratic loop", start, count); - if (count != count_visitor.count) + if (count != partition_count) { std::cerr << "ERROR: counts are not equal" << std::endl; } From 1410088153e45aaf254235a1c9f9d8d98d517d5d Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Wed, 4 Oct 2023 14:06:25 +0200 Subject: [PATCH 2/5] rename to partition_lambda, put in detail, and omit include policy --- .../buffer/buffered_piece_collection.hpp | 29 +++++------------- .../algorithms/detail/partition_lambda.hpp | 30 +++++++------------ test/robustness/within/partition_within.cpp | 2 +- 3 files changed, 20 insertions(+), 41 deletions(-) diff --git a/include/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp b/include/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp index 65faac16de..c2e950c962 100644 --- a/include/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp +++ b/include/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp @@ -360,19 +360,6 @@ struct buffered_piece_collection { auto const& strategy = m_strategy; - struct specific_options : experimental::partition_options - { - struct include_turn_policy - { - static inline bool apply(buffer_turn_info_type const& turn) - { - return turn.is_turn_traversable && ! turn.within_original; - } - }; - - using include_policy1 = include_turn_policy; - }; - turn_in_original_visitor < turn_vector_type, @@ -382,13 +369,16 @@ struct buffered_piece_collection // Partition over the turns and original rings, visiting // all turns located in an original and changing the turn's // "count_in_original" and "within_original" values - experimental::partition + partition_lambda < box_type >(m_turns, original_rings, [&strategy](auto& box, auto const& turn) { - geometry::expand(box, turn.point, strategy); + if (turn.is_turn_traversable && ! turn.within_original) + { + geometry::expand(box, turn.point, strategy); + } }, [&strategy](auto& box, auto const& turn) { @@ -407,10 +397,7 @@ struct buffered_piece_collection [&visitor](auto const& turn, auto const& original) { return visitor.apply(turn, original); - }, - [](auto const&, int) {}, - specific_options() - ); + }); bool const deflate = m_distance_strategy.negative(); @@ -500,7 +487,7 @@ struct buffered_piece_collection detail::sectionalize::enlarge_sections(monotonic_sections, m_strategy); - experimental::partition(monotonic_sections, + partition_lambda(monotonic_sections, [&strategy](auto& box, auto const& section) { geometry::expand(box, section.bounding_box, strategy); @@ -528,7 +515,7 @@ struct buffered_piece_collection > visitor(m_turns, m_pieces, m_distance_strategy, m_strategy); // Partition over the turns and pieces, checking if turns are inside pieces. - experimental::partition(m_turns, m_pieces, + partition_lambda(m_turns, m_pieces, [&strategy](auto& box, auto const& turn) { geometry::expand(box, turn.point, strategy); diff --git a/include/boost/geometry/algorithms/detail/partition_lambda.hpp b/include/boost/geometry/algorithms/detail/partition_lambda.hpp index 84eb9719f8..7e6c688882 100644 --- a/include/boost/geometry/algorithms/detail/partition_lambda.hpp +++ b/include/boost/geometry/algorithms/detail/partition_lambda.hpp @@ -13,7 +13,7 @@ #include -namespace boost { namespace geometry { namespace experimental +namespace boost { namespace geometry { namespace detail { template @@ -34,12 +34,6 @@ struct adapt_partition_visitor struct partition_options { - // Include policy for the (first) range - using include_policy1 = detail::partition::include_all_policy; - - // Include policy for the second range - using include_policy2 = detail::partition::include_all_policy; - // Defines the end of the iteration (as soon as range 1 or range 2 has // these number of elements, or less, it will switch to iterative mode) std::size_t min_elements = 16; @@ -49,10 +43,9 @@ template < typename BoxType, typename ForwardRange1, - typename ForwardRange2, - typename Options = partition_options + typename ForwardRange2 > -bool partition(ForwardRange1 const& forward_range1, +bool partition_lambda(ForwardRange1 const& forward_range1, ForwardRange2 const& forward_range2, const std::function < @@ -83,7 +76,7 @@ bool partition(ForwardRange1 const& forward_range1, < void(BoxType const&, int level) >& box_visitor = [](auto const&, int) {}, - const Options& options = {}) + const partition_options& options = {}) { adapt_partition_visitor av(visitor); adapt_partition_visitor aev1(expand_policy1); @@ -95,8 +88,8 @@ bool partition(ForwardRange1 const& forward_range1, return geometry::partition < BoxType, - typename Options::include_policy1, - typename Options::include_policy2 + detail::partition::include_all_policy, + detail::partition::include_all_policy >::apply(forward_range1, forward_range2, av, aev1, aov1, aev2, aov2, options.min_elements, apbv); @@ -105,10 +98,9 @@ bool partition(ForwardRange1 const& forward_range1, template < typename BoxType, - typename ForwardRange, - typename Options = partition_options + typename ForwardRange > -bool partition(ForwardRange const& forward_range, +bool partition_lambda(ForwardRange const& forward_range, const std::function < void(BoxType&, @@ -128,7 +120,7 @@ bool partition(ForwardRange const& forward_range, < void(BoxType const&, int level) >& box_visitor = [](auto const&, int) {}, - const Options& options = {}) + const partition_options& options = {}) { adapt_partition_visitor av(visitor); adapt_partition_visitor aev(expand_policy); @@ -138,11 +130,11 @@ bool partition(ForwardRange const& forward_range, return geometry::partition < BoxType, - typename Options::include_policy1 + detail::partition::include_all_policy >::apply(forward_range, av, aev, aov, options.min_elements, apbv); } -}}} // namespace boost::geometry::experimental +}}} // namespace boost::geometry::detail #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_PARTITION_LAMBDA_HPP diff --git a/test/robustness/within/partition_within.cpp b/test/robustness/within/partition_within.cpp index 5614c5e29e..c6bae3fc13 100644 --- a/test/robustness/within/partition_within.cpp +++ b/test/robustness/within/partition_within.cpp @@ -262,7 +262,7 @@ void call_within(std::size_t size, std::size_t count) box_type, box_type >::type strategy; - bg::experimental::partition(points, + bg::detail::partition_lambda(points, rings, [](auto& box, auto const& point) { bg::expand(box, point); }, [](auto const& box, auto const& point) { return ! bg::disjoint(point, box); }, From 0eee48d0bdff57fdb67bc78eff460a1a5be8b11f Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Wed, 4 Oct 2023 14:06:50 +0200 Subject: [PATCH 3/5] use partition_lambda for assign_parents --- .../detail/overlay/assign_parents.hpp | 157 +++++------------- .../algorithms/detail/within/multi_point.hpp | 1 - 2 files changed, 43 insertions(+), 115 deletions(-) diff --git a/include/boost/geometry/algorithms/detail/overlay/assign_parents.hpp b/include/boost/geometry/algorithms/detail/overlay/assign_parents.hpp index 578ba090cf..297ee2b467 100644 --- a/include/boost/geometry/algorithms/detail/overlay/assign_parents.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/assign_parents.hpp @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include @@ -132,109 +132,6 @@ struct ring_info_helper }; -template -struct ring_info_helper_get_box -{ - ring_info_helper_get_box(Strategy const& strategy) - : m_strategy(strategy) - {} - - template - inline void apply(Box& total, InputItem const& item) const - { - assert_coordinate_type_equal(total, item.envelope); - geometry::expand(total, item.envelope, m_strategy); - } - - Strategy const& m_strategy; -}; - -template -struct ring_info_helper_overlaps_box -{ - ring_info_helper_overlaps_box(Strategy const& strategy) - : m_strategy(strategy) - {} - - template - inline bool apply(Box const& box, InputItem const& item) const - { - assert_coordinate_type_equal(box, item.envelope); - return ! geometry::detail::disjoint::disjoint_box_box( - box, item.envelope, m_strategy); - } - - Strategy const& m_strategy; -}; - -// Segments intersection Strategy -template -< - typename Geometry1, - typename Geometry2, - typename Collection, - typename RingMap, - typename Strategy -> -struct assign_visitor -{ - typedef typename RingMap::mapped_type ring_info_type; - - Geometry1 const& m_geometry1; - Geometry2 const& m_geometry2; - Collection const& m_collection; - RingMap& m_ring_map; - Strategy const& m_strategy; - bool m_check_for_orientation; - - inline assign_visitor(Geometry1 const& g1, Geometry2 const& g2, Collection const& c, - RingMap& map, Strategy const& strategy, bool check) - : m_geometry1(g1) - , m_geometry2(g2) - , m_collection(c) - , m_ring_map(map) - , m_strategy(strategy) - , m_check_for_orientation(check) - {} - - template - inline bool apply(Item const& outer, Item const& inner, bool first = true) - { - if (first && outer.abs_area < inner.abs_area) - { - // Apply with reversed arguments - apply(inner, outer, false); - return true; - } - - if (m_check_for_orientation - || (math::larger(outer.real_area, 0) - && math::smaller(inner.real_area, 0))) - { - ring_info_type& inner_in_map = m_ring_map[inner.id]; - - if (geometry::covered_by(inner_in_map.point, outer.envelope, m_strategy) - && within_selected_input(inner_in_map, inner.id, outer.id, - m_geometry1, m_geometry2, m_collection, - m_strategy) - ) - { - // Assign a parent if there was no earlier parent, or the newly - // found parent is smaller than the previous one - if (inner_in_map.parent.source_index == -1 - || outer.abs_area < inner_in_map.parent_area) - { - inner_in_map.parent = outer.id; - inner_in_map.parent_area = outer.abs_area; - } - } - } - - return true; - } -}; - - template < overlay_type OverlayType, @@ -336,19 +233,51 @@ inline void assign_parents(Geometry1 const& geometry1, } } - assign_visitor - < - Geometry1, Geometry2, - RingCollection, RingMap, - Strategy - > visitor(geometry1, geometry2, collection, ring_map, strategy, check_for_orientation); + auto assign_to_map = [&](auto const& outer, auto const& inner) + { + if (check_for_orientation + || (math::larger(outer.real_area, 0) && math::smaller(inner.real_area, 0))) + { + auto& inner_in_map = ring_map[inner.id]; + + if (geometry::covered_by(inner_in_map.point, outer.envelope, strategy) + && within_selected_input(inner_in_map, inner.id, outer.id, + geometry1, geometry2, collection, strategy) + ) + { + // Assign a parent if there was no earlier parent, or the newly + // found parent is smaller than the previous one + if (inner_in_map.parent.source_index == -1 + || outer.abs_area < inner_in_map.parent_area) + { + inner_in_map.parent = outer.id; + inner_in_map.parent_area = outer.abs_area; + } + } + } + return true; + }; - geometry::partition + partition_lambda < box_type - >::apply(vector, visitor, - ring_info_helper_get_box(strategy), - ring_info_helper_overlaps_box(strategy)); + >(vector, + [&strategy](auto& box, auto const& info) + { + geometry::expand(box, info.envelope, strategy); + }, + [&strategy](auto const& box, auto const& info) + { + return ! geometry::detail::disjoint::disjoint_box_box( + box, info.envelope, strategy); + }, + [&](auto const& info1, auto const& info2) + { + return info1.abs_area >= info2.abs_area + ? assign_to_map(info1, info2) + : assign_to_map(info2, info1); + } + ); } if (check_for_orientation) diff --git a/include/boost/geometry/algorithms/detail/within/multi_point.hpp b/include/boost/geometry/algorithms/detail/within/multi_point.hpp index be984e9364..3ae6b8e77e 100644 --- a/include/boost/geometry/algorithms/detail/within/multi_point.hpp +++ b/include/boost/geometry/algorithms/detail/within/multi_point.hpp @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include From e7f19053facba80dc6f3c4b9e1fbcfaaa745e84e Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Wed, 4 Oct 2023 14:56:33 +0200 Subject: [PATCH 4/5] use partition_lambda for get_turns and self_turns --- .../buffer/buffered_piece_collection.hpp | 1 - .../algorithms/detail/overlay/get_turns.hpp | 118 ++++++----------- .../detail/overlay/self_turn_points.hpp | 124 ++++++------------ .../detail/sections/section_box_policies.hpp | 71 ---------- 4 files changed, 82 insertions(+), 232 deletions(-) delete mode 100644 include/boost/geometry/algorithms/detail/sections/section_box_policies.hpp diff --git a/include/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp b/include/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp index c2e950c962..518d11834f 100644 --- a/include/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp +++ b/include/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp @@ -56,7 +56,6 @@ #include #include #include -#include #include #include diff --git a/include/boost/geometry/algorithms/detail/overlay/get_turns.hpp b/include/boost/geometry/algorithms/detail/overlay/get_turns.hpp index 326c883b39..6220af031e 100644 --- a/include/boost/geometry/algorithms/detail/overlay/get_turns.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/get_turns.hpp @@ -32,10 +32,9 @@ #include #include #include -#include +#include #include #include -#include #include #include @@ -434,68 +433,6 @@ private : } }; -template -< - typename Geometry1, typename Geometry2, - bool Reverse1, bool Reverse2, - typename TurnPolicy, - typename Strategy, - typename RobustPolicy, - typename Turns, - typename InterruptPolicy -> -struct section_visitor -{ - int m_source_id1; - Geometry1 const& m_geometry1; - int m_source_id2; - Geometry2 const& m_geometry2; - Strategy const& m_strategy; - RobustPolicy const& m_rescale_policy; - Turns& m_turns; - InterruptPolicy& m_interrupt_policy; - - section_visitor(int id1, Geometry1 const& g1, - int id2, Geometry2 const& g2, - Strategy const& strategy, - RobustPolicy const& robust_policy, - Turns& turns, - InterruptPolicy& ip) - : m_source_id1(id1), m_geometry1(g1) - , m_source_id2(id2), m_geometry2(g2) - , m_strategy(strategy) - , m_rescale_policy(robust_policy) - , m_turns(turns) - , m_interrupt_policy(ip) - {} - - template - inline bool apply(Section const& sec1, Section const& sec2) - { - if (! detail::disjoint::disjoint_box_box(sec1.bounding_box, - sec2.bounding_box, - m_strategy) ) - { - // false if interrupted - return get_turns_in_sections - < - Geometry1, - Geometry2, - Reverse1, Reverse2, - Section, Section, - TurnPolicy - >::apply(m_source_id1, m_geometry1, sec1, - m_source_id2, m_geometry2, sec2, - false, false, - m_strategy, - m_rescale_policy, - m_turns, m_interrupt_policy); - } - return true; - } - -}; - template < typename Geometry1, typename Geometry2, @@ -537,22 +474,49 @@ class get_turns_generic sec2, strategy, 1); // ... and then partition them, intersecting overlapping sections in visitor method - section_visitor - < - Geometry1, Geometry2, - Reverse1, Reverse2, - TurnPolicy, - Strategy, RobustPolicy, - Turns, InterruptPolicy - > visitor(source_id1, geometry1, source_id2, geometry2, - strategy, robust_policy, turns, interrupt_policy); - geometry::partition + auto visit_sections = [&](auto const& section1, auto const& section2) + { + if (detail::disjoint::disjoint_box_box(section1.bounding_box, + section2.bounding_box, + strategy)) + { + return true; + } + + // This will return false if interrupted + return get_turns_in_sections + < + Geometry1, + Geometry2, + Reverse1, Reverse2, + std::decay_t, + std::decay_t, + TurnPolicy + >::apply(source_id1, geometry1, section1, + source_id2, geometry2, section2, + false, false, + strategy, + robust_policy, + turns, interrupt_policy); + }; + + auto expand_box = [&strategy](auto& box, auto const& section) + { + geometry::expand(box, section.bounding_box, strategy); + }; + auto overlaps_box = [&strategy](auto const& box, auto const& section) + { + return ! detail::disjoint::disjoint_box_box(box, section.bounding_box, strategy); + }; + + partition_lambda < box_type - >::apply(sec1, sec2, visitor, - detail::section::get_section_box(strategy), - detail::section::overlaps_section_box(strategy)); + >(sec1, sec2, + expand_box, overlaps_box, + expand_box, overlaps_box, + visit_sections); } }; diff --git a/include/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp b/include/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp index 20369fa95a..f04bb1409c 100644 --- a/include/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp @@ -19,10 +19,9 @@ #include -#include +#include #include #include -#include #include #include @@ -58,74 +57,6 @@ struct no_interrupt_policy } }; - -template -< - bool Reverse, - typename Geometry, - typename Turns, - typename TurnPolicy, - typename Strategy, - typename RobustPolicy, - typename InterruptPolicy -> -struct self_section_visitor -{ - Geometry const& m_geometry; - Strategy const& m_strategy; - RobustPolicy const& m_rescale_policy; - Turns& m_turns; - InterruptPolicy& m_interrupt_policy; - int m_source_index; - bool m_skip_adjacent; - - inline self_section_visitor(Geometry const& g, - Strategy const& s, - RobustPolicy const& rp, - Turns& turns, - InterruptPolicy& ip, - int source_index, - bool skip_adjacent) - : m_geometry(g) - , m_strategy(s) - , m_rescale_policy(rp) - , m_turns(turns) - , m_interrupt_policy(ip) - , m_source_index(source_index) - , m_skip_adjacent(skip_adjacent) - {} - - template - inline bool apply(Section const& sec1, Section const& sec2) - { - if (! detail::disjoint::disjoint_box_box(sec1.bounding_box, - sec2.bounding_box, - m_strategy) - && ! sec1.duplicate - && ! sec2.duplicate) - { - // false if interrupted - return detail::get_turns::get_turns_in_sections - < - Geometry, Geometry, - Reverse, Reverse, - Section, Section, - TurnPolicy - >::apply(m_source_index, m_geometry, sec1, - m_source_index, m_geometry, sec2, - false, m_skip_adjacent, - m_strategy, - m_rescale_policy, - m_turns, m_interrupt_policy); - } - - return true; - } - -}; - - - template struct get_turns { @@ -153,24 +84,51 @@ struct get_turns typedef std::integer_sequence dimensions; - sections_type sec; + sections_type sections; geometry::sectionalize(geometry, robust_policy, - sec, strategy); + sections, strategy); - self_section_visitor - < - Reverse, Geometry, - Turns, TurnPolicy, Strategy, RobustPolicy, InterruptPolicy - > visitor(geometry, strategy, robust_policy, turns, interrupt_policy, - source_index, skip_adjacent); + auto visit_sections = [&](auto const& section1, auto const& section2) + { + if (detail::disjoint::disjoint_box_box(section1.bounding_box, + section2.bounding_box, + strategy) + && ! section1.duplicate + && ! section2.duplicate) + { + return true; + } + + using section_type = std::decay_t; + + // This will return false if interrupted + return detail::get_turns::get_turns_in_sections + < + Geometry, Geometry, + Reverse, Reverse, + section_type, section_type, + TurnPolicy + >::apply(source_index, geometry, section1, + source_index, geometry, section2, + false, skip_adjacent, + strategy, + robust_policy, + turns, interrupt_policy); + }; + + auto expand_box = [&strategy](auto& box, auto const& section) + { + geometry::expand(box, section.bounding_box, strategy); + }; + auto overlaps_box = [&strategy](auto const& box, auto const& section) + { + return ! detail::disjoint::disjoint_box_box(box, section.bounding_box, strategy); + }; - // false if interrupted - geometry::partition + partition_lambda < box_type - >::apply(sec, visitor, - detail::section::get_section_box(strategy), - detail::section::overlaps_section_box(strategy)); + >(sections, expand_box, overlaps_box, visit_sections); return ! interrupt_policy.has_intersections; } diff --git a/include/boost/geometry/algorithms/detail/sections/section_box_policies.hpp b/include/boost/geometry/algorithms/detail/sections/section_box_policies.hpp deleted file mode 100644 index 2caaea0966..0000000000 --- a/include/boost/geometry/algorithms/detail/sections/section_box_policies.hpp +++ /dev/null @@ -1,71 +0,0 @@ -// Boost.Geometry (aka GGL, Generic Geometry Library) - -// Copyright (c) 2015 Barend Gehrels, Amsterdam, the Netherlands. - -// This file was modified by Oracle on 2018-2020. -// Modifications copyright (c) 2018-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, -// 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_SECTIONS_SECTION_BOX_POLICIES_HPP -#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_SECTION_BOX_POLICIES_HPP - - -#include -#include -#include - - -namespace boost { namespace geometry -{ - -#ifndef DOXYGEN_NO_DETAIL -namespace detail { namespace section -{ - -template -struct get_section_box -{ - get_section_box(Strategy const& strategy) - : m_strategy(strategy) - {} - - template - inline void apply(Box& total, Section const& section) const - { - assert_coordinate_type_equal(total, section.bounding_box); - geometry::expand(total, section.bounding_box, m_strategy); - } - - Strategy const& m_strategy; -}; - -template -struct overlaps_section_box -{ - overlaps_section_box(Strategy const& strategy) - : m_strategy(strategy) - {} - - template - inline bool apply(Box const& box, Section const& section) const - { - assert_coordinate_type_equal(box, section.bounding_box); - return ! detail::disjoint::disjoint_box_box(box, section.bounding_box, - m_strategy); - } - - Strategy const& m_strategy; -}; - - -}} // namespace detail::section -#endif - - -}} // namespace boost::geometry - -#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_SECTION_BOX_POLICIES_HPP From 31e4145e473e9792f8c2db68d88d82c5266a1317 Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Wed, 4 Oct 2023 15:18:11 +0200 Subject: [PATCH 5/5] use partition_lambda for overlay pointlike with linear or areal --- .../detail/overlay/pointlike_areal.hpp | 138 ++++-------------- .../detail/overlay/pointlike_linear.hpp | 136 +++++------------ 2 files changed, 65 insertions(+), 209 deletions(-) diff --git a/include/boost/geometry/algorithms/detail/overlay/pointlike_areal.hpp b/include/boost/geometry/algorithms/detail/overlay/pointlike_areal.hpp index 503d656478..207abc2ead 100644 --- a/include/boost/geometry/algorithms/detail/overlay/pointlike_areal.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/pointlike_areal.hpp @@ -24,7 +24,7 @@ #include #include -#include +#include #include #include #include @@ -63,103 +63,6 @@ template class multipoint_multipolygon_point { private: - template - struct expand_box_point - { - explicit expand_box_point(Strategy const& strategy) - : m_strategy(strategy) - {} - - template - inline void apply(Box& total, Point const& point) const - { - geometry::expand(total, point, m_strategy); - } - - Strategy const& m_strategy; - }; - - template - struct expand_box_boxpair - { - explicit expand_box_boxpair(Strategy const& strategy) - : m_strategy(strategy) - {} - - template - inline void apply(Box1& total, std::pair const& box_pair) const - { - geometry::expand(total, box_pair.first, m_strategy); - } - - Strategy const& m_strategy; - }; - - template - struct overlaps_box_point - { - explicit overlaps_box_point(Strategy const& strategy) - : m_strategy(strategy) - {} - - template - inline bool apply(Box const& box, Point const& point) const - { - return ! geometry::disjoint(point, box, m_strategy); - } - - Strategy const& m_strategy; - }; - - template - struct overlaps_box_boxpair - { - explicit overlaps_box_boxpair(Strategy const& strategy) - : m_strategy(strategy) - {} - - template - inline bool apply(Box1 const& box, std::pair const& box_pair) const - { - return ! geometry::disjoint(box, box_pair.first, m_strategy); - } - - Strategy const& m_strategy; - }; - - template - class item_visitor_type - { - public: - item_visitor_type(MultiPolygon const& multipolygon, - OutputIterator& oit, - Strategy const& strategy) - : m_multipolygon(multipolygon) - , m_oit(oit) - , m_strategy(strategy) - {} - - template - inline bool apply(Point const& item1, std::pair const& item2) - { - action_selector_pl - < - PointOut, overlay_intersection - >::apply(item1, - Policy::apply(item1, - range::at(m_multipolygon, - item2.second), - m_strategy), - m_oit); - - return true; - } - - private: - MultiPolygon const& m_multipolygon; - OutputIterator& m_oit; - Strategy const& m_strategy; - }; template static inline void fill_box_pairs(Iterator first, Iterator last, @@ -181,8 +84,6 @@ class multipoint_multipolygon_point OutputIterator oit, Strategy const& strategy) { - item_visitor_type item_visitor(multipolygon, oit, strategy); - typedef geometry::model::point < typename geometry::coordinate_type::type, @@ -198,14 +99,39 @@ class multipoint_multipolygon_point boost::end(multipolygon), box_pairs, strategy); - geometry::partition + partition_lambda < box_type - >::apply(multipoint, box_pairs, item_visitor, - expand_box_point(strategy), - overlaps_box_point(strategy), - expand_box_boxpair(strategy), - overlaps_box_boxpair(strategy)); + >(multipoint, box_pairs, + [&strategy](auto& box, auto const& point) + { + geometry::expand(box, point, strategy); + }, + [&strategy](auto const& box, auto const& point) + { + return ! geometry::disjoint(point, box, strategy); + }, + [&strategy](auto& box, auto const& pair) + { + geometry::expand(box, pair.first, strategy); + }, + [&strategy](auto const& box, auto const& pair) + { + return ! geometry::disjoint(box, pair.first, strategy); + }, + [&](auto const& point, auto const& pair) + { + action_selector_pl + < + PointOut, overlay_intersection + >::apply(point, + Policy::apply(point, + range::at(multipolygon, pair.second), + strategy), + oit); + return true; + } + ); return oit; } diff --git a/include/boost/geometry/algorithms/detail/overlay/pointlike_linear.hpp b/include/boost/geometry/algorithms/detail/overlay/pointlike_linear.hpp index 19045b250a..199064703d 100644 --- a/include/boost/geometry/algorithms/detail/overlay/pointlike_linear.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/pointlike_linear.hpp @@ -27,7 +27,7 @@ #include #include -#include +#include #include #include #include @@ -123,98 +123,6 @@ template class multipoint_linear_point { private: - // structs for partition -- start - template - struct expand_box_point - { - expand_box_point(Strategy const& strategy) - : m_strategy(strategy) - {} - - template - inline void apply(Box& total, Point const& point) const - { - geometry::expand(total, point, m_strategy); - } - - Strategy const& m_strategy; - }; - - template - struct expand_box_segment - { - explicit expand_box_segment(Strategy const& strategy) - : m_strategy(strategy) - {} - - template - inline void apply(Box& total, Segment const& segment) const - { - geometry::expand(total, - geometry::return_envelope(segment, m_strategy), - m_strategy); - } - - Strategy const& m_strategy; - }; - - template - struct overlaps_box_point - { - explicit overlaps_box_point(Strategy const& strategy) - : m_strategy(strategy) - {} - - template - inline bool apply(Box const& box, Point const& point) const - { - return ! geometry::disjoint(point, box, m_strategy); - } - - Strategy const& m_strategy; - }; - - template - struct overlaps_box_segment - { - explicit overlaps_box_segment(Strategy const& strategy) - : m_strategy(strategy) - {} - - template - inline bool apply(Box const& box, Segment const& segment) const - { - return ! geometry::disjoint(segment, box, m_strategy); - } - - Strategy const& m_strategy; - }; - - template - class item_visitor_type - { - public: - item_visitor_type(OutputIterator& oit, Strategy const& strategy) - : m_oit(oit) - , m_strategy(strategy) - {} - - template - inline bool apply(Item1 const& item1, Item2 const& item2) - { - action_selector_pl - < - PointOut, overlay_intersection - >::apply(item1, Policy::apply(item1, item2, m_strategy), m_oit); - - return true; - } - - private: - OutputIterator& m_oit; - Strategy const& m_strategy; - }; - // structs for partition -- end class segment_range { @@ -246,24 +154,46 @@ class multipoint_linear_point OutputIterator oit, Strategy const& strategy) { - item_visitor_type item_visitor(oit, strategy); // TODO: disjoint Segment/Box may be called in partition multiple times // possibly for non-cartesian segments which could be slow. We should consider // passing a range of bounding boxes of segments after calculating them once. // Alternatively instead of a range of segments a range of Segment/Envelope pairs // should be passed, where envelope would be lazily calculated when needed the first time - geometry::partition - < - geometry::model::box + using box_type = geometry::model::box < typename boost::range_value::type - > - >::apply(multipoint, segment_range(linear), item_visitor, - expand_box_point(strategy), - overlaps_box_point(strategy), - expand_box_segment(strategy), - overlaps_box_segment(strategy)); + >; + + partition_lambda + < + box_type + >(multipoint, segment_range(linear), + [&strategy](auto& box, auto const& point) + { + geometry::expand(box, point, strategy); + }, + [&strategy](auto const& box, auto const& point) + { + return ! geometry::disjoint(point, box, strategy); + }, + [&strategy](auto& box, auto const& segment) + { + geometry::expand(box, geometry::return_envelope(segment, strategy), strategy); + }, + [&strategy](auto const& box, auto const& segment) + { + return ! geometry::disjoint(box, segment, strategy); + }, + [&](auto const& point, auto const& segment) + { + action_selector_pl + < + PointOut, overlay_intersection + >::apply(point, Policy::apply(point, segment, strategy), oit); + return true; + } + ); return oit; }