From e2f11f015d2b51c7d4cd681d5de3b5cadc6da3a8 Mon Sep 17 00:00:00 2001 From: Bruno Lalande Date: Wed, 23 Oct 2013 10:13:28 +0000 Subject: [PATCH] Converted convex_hull to the multi-stage approach and made it variant-aware. [SVN r86401] --- .../boost/geometry/algorithms/convex_hull.hpp | 204 ++++++++++++++---- test/algorithms/test_convex_hull.hpp | 83 ++++--- 2 files changed, 207 insertions(+), 80 deletions(-) diff --git a/include/boost/geometry/algorithms/convex_hull.hpp b/include/boost/geometry/algorithms/convex_hull.hpp index a623064bf..72aee0f2a 100644 --- a/include/boost/geometry/algorithms/convex_hull.hpp +++ b/include/boost/geometry/algorithms/convex_hull.hpp @@ -15,6 +15,9 @@ #define BOOST_GEOMETRY_ALGORITHMS_CONVEX_HULL_HPP #include +#include +#include +#include #include #include @@ -24,6 +27,7 @@ #include #include +#include #include @@ -77,18 +81,6 @@ struct hull_to_geometry } }; - -// Helper metafunction for default strategy retrieval -template -struct default_strategy - : strategy_convex_hull - < - Geometry, - typename point_type::type - > -{}; - - }} // namespace detail::convex_hull #endif // DOXYGEN_NO_DETAIL @@ -142,25 +134,169 @@ struct convex_hull_insert #endif // DOXYGEN_NO_DISPATCH -template -inline void convex_hull(Geometry const& geometry, - OutputGeometry& out, Strategy const& strategy) +namespace resolve_strategy { + +struct convex_hull { - concept::check_concepts_and_equal_dimensions - < + template + static inline void apply(Geometry const& geometry, + OutputGeometry& out, + Strategy const& strategy) + { + BOOST_CONCEPT_ASSERT( (geometry::concept::ConvexHullStrategy) ); + dispatch::convex_hull::apply(geometry, out, strategy); + } + + template + static inline void apply(Geometry const& geometry, + OutputGeometry& out, + default_strategy) + { + typedef typename strategy_convex_hull< + Geometry, + typename point_type::type + >::type strategy_type; + + apply(geometry, out, strategy_type()); + } +}; + +struct convex_hull_insert +{ + template + static inline OutputIterator apply(Geometry const& geometry, + OutputIterator& out, + Strategy const& strategy) + { + BOOST_CONCEPT_ASSERT( (geometry::concept::ConvexHullStrategy) ); + + return dispatch::convex_hull_insert< + geometry::point_order::value + >::apply(geometry, out, strategy); + } + + template + static inline OutputIterator apply(Geometry const& geometry, + OutputIterator& out, + default_strategy) + { + typedef typename strategy_convex_hull< + Geometry, + typename point_type::type + >::type strategy_type; + + return apply(geometry, out, strategy_type()); + } +}; + +}; // namespace resolve_strategy + + +namespace resolve_variant { + +template +struct convex_hull +{ + template + static inline void apply(Geometry const& geometry, OutputGeometry& out, Strategy const& strategy) + { + concept::check_concepts_and_equal_dimensions< const Geometry, OutputGeometry >(); - BOOST_CONCEPT_ASSERT( (geometry::concept::ConvexHullStrategy) ); + resolve_strategy::convex_hull::apply(geometry, out, strategy); + } +}; +template +struct convex_hull > +{ + template + struct visitor: boost::static_visitor + { + OutputGeometry& m_out; + Strategy const& m_strategy; + + visitor(OutputGeometry& out, Strategy const& strategy) + : m_out(out), m_strategy(strategy) + {} + + template + void operator()(Geometry const& geometry) const + { + convex_hull::apply(geometry, m_out, m_strategy); + } + }; + + template + static inline void + apply(boost::variant const& geometry, + OutputGeometry& out, + Strategy const& strategy) + { + boost::apply_visitor(visitor(out, strategy), geometry); + } +}; + +template +struct convex_hull_insert +{ + template + static inline OutputIterator apply(Geometry const& geometry, OutputIterator& out, Strategy const& strategy) + { + // Concept: output point type = point type of input geometry + concept::check(); + concept::check::type>(); + + return resolve_strategy::convex_hull_insert::apply(geometry, out, strategy); + } +}; + +template +struct convex_hull_insert > +{ + template + struct visitor: boost::static_visitor + { + OutputIterator& m_out; + Strategy const& m_strategy; + + visitor(OutputIterator& out, Strategy const& strategy) + : m_out(out), m_strategy(strategy) + {} + + template + OutputIterator operator()(Geometry const& geometry) const + { + return convex_hull_insert::apply(geometry, m_out, m_strategy); + } + }; + + template + static inline OutputIterator + apply(boost::variant const& geometry, + OutputIterator& out, + Strategy const& strategy) + { + return boost::apply_visitor(visitor(out, strategy), geometry); + } +}; + +} // namespace resolve_variant + + +template +inline void convex_hull(Geometry const& geometry, + OutputGeometry& out, Strategy const& strategy) +{ if (geometry::num_points(geometry) == 0) { // Leave output empty return; } - dispatch::convex_hull::apply(geometry, out, strategy); + resolve_variant::convex_hull::apply(geometry, out, strategy); } @@ -179,15 +315,7 @@ template inline void convex_hull(Geometry const& geometry, OutputGeometry& hull) { - concept::check_concepts_and_equal_dimensions - < - const Geometry, - OutputGeometry - >(); - - typedef typename detail::convex_hull::default_strategy::type strategy_type; - - convex_hull(geometry, hull, strategy_type()); + convex_hull(geometry, hull, default_strategy()); } #ifndef DOXYGEN_NO_DETAIL @@ -199,16 +327,8 @@ template inline OutputIterator convex_hull_insert(Geometry const& geometry, OutputIterator out, Strategy const& strategy) { - // Concept: output point type = point type of input geometry - concept::check(); - concept::check::type>(); - - BOOST_CONCEPT_ASSERT( (geometry::concept::ConvexHullStrategy) ); - - return dispatch::convex_hull_insert - < - geometry::point_order::value - >::apply(geometry, out, strategy); + return resolve_variant::convex_hull_insert + ::apply(geometry, out, strategy); } @@ -229,13 +349,7 @@ template inline OutputIterator convex_hull_insert(Geometry const& geometry, OutputIterator out) { - // Concept: output point type = point type of input geometry - concept::check(); - concept::check::type>(); - - typedef typename detail::convex_hull::default_strategy::type strategy_type; - - return convex_hull_insert(geometry, out, strategy_type()); + return convex_hull_insert(geometry, out, default_strategy()); } diff --git a/test/algorithms/test_convex_hull.hpp b/test/algorithms/test_convex_hull.hpp index a6a108a79..a00bbce2f 100644 --- a/test/algorithms/test_convex_hull.hpp +++ b/test/algorithms/test_convex_hull.hpp @@ -9,6 +9,8 @@ #ifndef BOOST_GEOMETRY_TEST_CONVEX_HULL_HPP #define BOOST_GEOMETRY_TEST_CONVEX_HULL_HPP +#include + #include #include @@ -24,11 +26,10 @@ template -void test_convex_hull(Geometry const& geometry, Hull const& hull, +void check_convex_hull(Geometry const& geometry, Hull const& hull, std::size_t size_original, std::size_t size_hull, double expected_area, bool reverse) { - std::size_t n = bg::num_points(hull); BOOST_CHECK_MESSAGE(n == size_hull, @@ -49,55 +50,67 @@ void test_convex_hull(Geometry const& geometry, Hull const& hull, ah = -ah; } -//std::cout << "Area: " << bg::area(geometry) << std::endl; -//std::cout << bg::wkt(hull) << std::endl; - BOOST_CHECK_CLOSE(ah, expected_area, 0.001); } +template +void test_convex_hull(Geometry const& geometry, + std::size_t size_original, std::size_t size_hull, + double expected_area, + bool reverse) +{ + Hull hull; + + // Test version with output iterator + bg::detail::convex_hull::convex_hull_insert(geometry, std::back_inserter(hull.outer())); + check_convex_hull(geometry, hull, + size_original, size_hull, expected_area, reverse); + + // Test version with ring as output + bg::clear(hull); + bg::convex_hull(geometry, hull.outer()); + check_convex_hull(geometry, hull, size_original, size_hull, expected_area, false); + + // Test version with polygon as output + bg::clear(hull); + bg::convex_hull(geometry, hull); + check_convex_hull(geometry, hull, size_original, size_hull, expected_area, false); + + // Test version with strategy + bg::clear(hull); + bg::convex_hull(geometry, hull.outer(), Strategy()); + check_convex_hull(geometry, hull, size_original, size_hull, expected_area, false); + + // Test version with output iterator and strategy + bg::clear(hull); + bg::detail::convex_hull::convex_hull_insert(geometry, std::back_inserter(hull.outer()), Strategy()); + check_convex_hull(geometry, hull, size_original, size_hull, expected_area, reverse); +} + + template void test_geometry_order(std::string const& wkt, std::size_t size_original, std::size_t size_hull, double expected_area) { - Geometry geometry; - bg::read_wkt(wkt, geometry); - - bg::model::polygon + typedef bg::model::polygon < typename bg::point_type::type, Clockwise - > hull; + > hull_type; - // Test version with output iterator - bg::detail::convex_hull::convex_hull_insert(geometry, std::back_inserter(hull.outer())); - test_convex_hull(geometry, hull, - size_original, size_hull, expected_area, ! Clockwise); - - // Test version with ring as output - bg::clear(hull); - bg::convex_hull(geometry, hull.outer()); - test_convex_hull(geometry, hull, size_original, size_hull, expected_area, false); - - // Test version with polygon as output - bg::clear(hull); - bg::convex_hull(geometry, hull); - test_convex_hull(geometry, hull, size_original, size_hull, expected_area, false); - - // Test version with strategy - bg::clear(hull); - bg::strategy::convex_hull::graham_andrew + typedef bg::strategy::convex_hull::graham_andrew < Geometry, typename bg::point_type::type - > graham; - bg::convex_hull(geometry, hull.outer(), graham); - test_convex_hull(geometry, hull, size_original, size_hull, expected_area, false); + > strategy_type; - // Test version with output iterator and strategy - bg::clear(hull); - bg::detail::convex_hull::convex_hull_insert(geometry, std::back_inserter(hull.outer()), graham); - test_convex_hull(geometry, hull, size_original, size_hull, expected_area, ! Clockwise); + Geometry geometry; + bg::read_wkt(wkt, geometry); + boost::variant v(geometry); + + test_convex_hull(geometry, size_original, size_hull, expected_area, !Clockwise); + test_convex_hull(v, size_original, size_hull, expected_area, !Clockwise); } template