Converted convex_hull to the multi-stage approach and made it variant-aware.

[SVN r86401]
This commit is contained in:
Bruno Lalande 2013-10-23 10:13:28 +00:00
parent 72046f98b9
commit e2f11f015d
2 changed files with 207 additions and 80 deletions

View File

@ -15,6 +15,9 @@
#define BOOST_GEOMETRY_ALGORITHMS_CONVEX_HULL_HPP
#include <boost/array.hpp>
#include <boost/variant/static_visitor.hpp>
#include <boost/variant/apply_visitor.hpp>
#include <boost/variant/variant_fwd.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/point_order.hpp>
@ -24,6 +27,7 @@
#include <boost/geometry/strategies/convex_hull.hpp>
#include <boost/geometry/strategies/concepts/convex_hull_concept.hpp>
#include <boost/geometry/strategies/default_strategy.hpp>
#include <boost/geometry/views/detail/range_type.hpp>
@ -77,18 +81,6 @@ struct hull_to_geometry
}
};
// Helper metafunction for default strategy retrieval
template <typename Geometry>
struct default_strategy
: strategy_convex_hull
<
Geometry,
typename point_type<Geometry>::type
>
{};
}} // namespace detail::convex_hull
#endif // DOXYGEN_NO_DETAIL
@ -142,25 +134,169 @@ struct convex_hull_insert
#endif // DOXYGEN_NO_DISPATCH
template<typename Geometry, typename OutputGeometry, typename Strategy>
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 <typename Geometry, typename OutputGeometry, typename Strategy>
static inline void apply(Geometry const& geometry,
OutputGeometry& out,
Strategy const& strategy)
{
BOOST_CONCEPT_ASSERT( (geometry::concept::ConvexHullStrategy<Strategy>) );
dispatch::convex_hull<Geometry>::apply(geometry, out, strategy);
}
template <typename Geometry, typename OutputGeometry>
static inline void apply(Geometry const& geometry,
OutputGeometry& out,
default_strategy)
{
typedef typename strategy_convex_hull<
Geometry,
typename point_type<Geometry>::type
>::type strategy_type;
apply(geometry, out, strategy_type());
}
};
struct convex_hull_insert
{
template <typename Geometry, typename OutputIterator, typename Strategy>
static inline OutputIterator apply(Geometry const& geometry,
OutputIterator& out,
Strategy const& strategy)
{
BOOST_CONCEPT_ASSERT( (geometry::concept::ConvexHullStrategy<Strategy>) );
return dispatch::convex_hull_insert<
geometry::point_order<Geometry>::value
>::apply(geometry, out, strategy);
}
template <typename Geometry, typename OutputIterator>
static inline OutputIterator apply(Geometry const& geometry,
OutputIterator& out,
default_strategy)
{
typedef typename strategy_convex_hull<
Geometry,
typename point_type<Geometry>::type
>::type strategy_type;
return apply(geometry, out, strategy_type());
}
};
}; // namespace resolve_strategy
namespace resolve_variant {
template <typename Geometry>
struct convex_hull
{
template <typename OutputGeometry, typename Strategy>
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<Strategy>) );
resolve_strategy::convex_hull::apply(geometry, out, strategy);
}
};
template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
struct convex_hull<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
{
template <typename OutputGeometry, typename Strategy>
struct visitor: boost::static_visitor<void>
{
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);
}
};
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);
}
};
template <typename Geometry>
struct convex_hull_insert
{
template <typename OutputIterator, typename Strategy>
static inline OutputIterator apply(Geometry const& geometry, OutputIterator& out, Strategy const& strategy)
{
// Concept: output point type = point type of input geometry
concept::check<Geometry const>();
concept::check<typename point_type<Geometry>::type>();
return resolve_strategy::convex_hull_insert::apply(geometry, out, strategy);
}
};
template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
struct convex_hull_insert<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
{
template <typename OutputIterator, typename Strategy>
struct visitor: boost::static_visitor<OutputIterator>
{
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
{
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);
}
};
} // namespace resolve_variant
template<typename Geometry, typename OutputGeometry, typename Strategy>
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<Geometry>::apply(geometry, out, strategy);
resolve_variant::convex_hull<Geometry>::apply(geometry, out, strategy);
}
@ -179,15 +315,7 @@ template<typename Geometry, typename OutputGeometry>
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<Geometry>::type strategy_type;
convex_hull(geometry, hull, strategy_type());
convex_hull(geometry, hull, default_strategy());
}
#ifndef DOXYGEN_NO_DETAIL
@ -199,16 +327,8 @@ template<typename Geometry, typename OutputIterator, typename Strategy>
inline OutputIterator convex_hull_insert(Geometry const& geometry,
OutputIterator out, Strategy const& strategy)
{
// Concept: output point type = point type of input geometry
concept::check<Geometry const>();
concept::check<typename point_type<Geometry>::type>();
BOOST_CONCEPT_ASSERT( (geometry::concept::ConvexHullStrategy<Strategy>) );
return dispatch::convex_hull_insert
<
geometry::point_order<Geometry>::value
>::apply(geometry, out, strategy);
return resolve_variant::convex_hull_insert<Geometry>
::apply(geometry, out, strategy);
}
@ -229,13 +349,7 @@ template<typename Geometry, typename OutputIterator>
inline OutputIterator convex_hull_insert(Geometry const& geometry,
OutputIterator out)
{
// Concept: output point type = point type of input geometry
concept::check<Geometry const>();
concept::check<typename point_type<Geometry>::type>();
typedef typename detail::convex_hull::default_strategy<Geometry>::type strategy_type;
return convex_hull_insert(geometry, out, strategy_type());
return convex_hull_insert(geometry, out, default_strategy());
}

View File

@ -9,6 +9,8 @@
#ifndef BOOST_GEOMETRY_TEST_CONVEX_HULL_HPP
#define BOOST_GEOMETRY_TEST_CONVEX_HULL_HPP
#include <boost/variant/variant.hpp>
#include <geometry_test_common.hpp>
#include <boost/geometry/algorithms/convex_hull.hpp>
@ -24,11 +26,10 @@
template <typename Geometry, typename Hull>
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 <typename Hull, typename Strategy, typename Geometry>
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 <typename Geometry, bool Clockwise>
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<Geometry>::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<Geometry>::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<Geometry> v(geometry);
test_convex_hull<hull_type, strategy_type>(geometry, size_original, size_hull, expected_area, !Clockwise);
test_convex_hull<hull_type, strategy_type>(v, size_original, size_hull, expected_area, !Clockwise);
}
template <typename Geometry>