From 33e12180d34c694f26bea7034aa68fb7d9b2c101 Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Mon, 8 May 2023 22:34:57 +0200 Subject: [PATCH] [experimental] update test-demo with version with lambdas --- test/robustness/within/Jamfile | 17 ++ test/robustness/within/partition_within.cpp | 170 +++++++----------- test/robustness/within/quadtree_partition.hpp | 98 ++++++++++ 3 files changed, 175 insertions(+), 110 deletions(-) create mode 100644 test/robustness/within/Jamfile create mode 100644 test/robustness/within/quadtree_partition.hpp diff --git a/test/robustness/within/Jamfile b/test/robustness/within/Jamfile new file mode 100644 index 0000000000..967c5a00a9 --- /dev/null +++ b/test/robustness/within/Jamfile @@ -0,0 +1,17 @@ +# Boost.Geometry (aka GGL, Generic Geometry Library) +# Robustness Test - convex_hull +# +# Copyright (c) 2012 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..7044759c15 100644 --- a/test/robustness/within/partition_within.cpp +++ b/test/robustness/within/partition_within.cpp @@ -17,6 +17,8 @@ # include #endif +#include "quadtree_partition.hpp" + #include #include #include @@ -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 @@ -311,27 +242,46 @@ 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); -#else - using partition_box_visitor_type = bg::detail::partition::visit_no_policy; - partition_box_visitor_type partition_box_visitor; + 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 + auto box_visitor = [&](auto const& , int ) {}; #endif + std::size_t quadtree_count = 0; + { auto const start = std::chrono::steady_clock::now(); - bg::partition - < - 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); + bg::experimental::quadtree_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); }, + [](auto const& box, auto const& item) + { + typename bg::strategy::disjoint::services::default_strategy + < + box_type, box_type + >::type strategy; + return ! bg::detail::disjoint::disjoint_box_box(box, item.box, strategy); + }, + [&quadtree_count](auto const& p, auto const& ri) + { + if (bg::within(p, ri.ring)) + { + quadtree_count++; + } + return true; + }, + box_visitor + ); + + report("Partition", start, quadtree_count); } { @@ -350,7 +300,7 @@ void call_within(std::size_t size, std::size_t count) } report("Quadratic loop", start, count); - if (count != count_visitor.count) + if (count != quadtree_count) { std::cerr << "ERROR: counts are not equal" << std::endl; } diff --git a/test/robustness/within/quadtree_partition.hpp b/test/robustness/within/quadtree_partition.hpp new file mode 100644 index 0000000000..95d16914b0 --- /dev/null +++ b/test/robustness/within/quadtree_partition.hpp @@ -0,0 +1,98 @@ +// 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_EXPERIMENTAL_QUADTREE_PARTITION_HPP +#define BOOST_GEOMETRY_EXPERIMENTAL_QUADTREE_PARTITION_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)...); + } +}; + +template +< + typename BoxType, + typename ForwardRange1, + typename ForwardRange2 +> +bool quadtree_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) {}) +{ + 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); + + // TODO: the "16" could be part of an optional options structure + // The all_policies (it is never run in a different way) could be + // a compiletime part of that options structure as well. + return partition + < + BoxType, + detail::partition::include_all_policy, + detail::partition::include_all_policy + >::apply(forward_range1, forward_range2, av, + aev1, aov1, + aev2, aov2, 16, apbv); +} + +}}} // namespace boost::geometry::experimental + +#endif // BOOST_GEOMETRY_EXPERIMENTAL_QUADTREE_PARTITION_HPP