diff --git a/include/boost/geometry/algorithms/distance.hpp b/include/boost/geometry/algorithms/distance.hpp index 953be2361..685d1f580 100644 --- a/include/boost/geometry/algorithms/distance.hpp +++ b/include/boost/geometry/algorithms/distance.hpp @@ -22,7 +22,18 @@ #include +#include +#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include @@ -497,6 +508,252 @@ struct distance } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH + +namespace resolve_variant { + + +template +struct distance +{ + template + struct result_type + { + typedef typename strategy::distance::services::return_type< + Strategy, + typename point_type::type, + typename point_type::type + >::type type; + }; + + template + static inline typename result_type::type + apply( + const Geometry1& geometry1, + const Geometry2& geometry2, + Strategy const& strategy) + { + return dispatch::distance + < + Geometry1, + Geometry2, + Strategy + >::apply(geometry1, geometry2, strategy); + } +}; + + +template +struct distance, Geometry2> +{ + template + struct result_type + { + typedef typename mpl::fold< + typename mpl::transform< + typename variant::types, + typename strategy::distance::services::return_type< + Strategy, + typename mpl::lambda >::type, + typename point_type::type + >::type + >::type, + mpl::set0<>, + mpl::insert + >::type possible_result_types; + + typedef typename mpl::if_< + mpl::greater< + mpl::size, + mpl::int_<1> + >, + typename make_variant_over::type, + typename mpl::front::type + >::type type; + }; + + template + struct visitor: static_visitor< + typename result_type >::type + > + { + Geometry2 const& m_geometry2; + Strategy const& m_strategy; + + visitor(Geometry2 const& geometry2) + : m_geometry2(geometry2), + m_strategy(strategy) + {} + + template + result_type operator()(Geometry1 const& geometry1) const + { + return dispatch::distance + < + Geometry1, + Geometry2, + Strategy + >::apply(geometry1, geometry2, strategy); + } + }; + + template + static inline typename result_type >::type + apply(variant const& geometry1, + Geometry2 const& geometry2, + Strategy const& strategy) + { + return apply_visitor(visitor(geometry2, strategy), geometry1); + } +}; + + +template +struct distance > +{ + template + struct result_type + { + typedef typename mpl::fold< + typename mpl::transform< + typename variant::types, + typename strategy::distance::services::return_type< + Strategy, + typename point_type::type, + typename mpl::lambda >::type + >::type + >::type, + mpl::set0<>, + mpl::insert + >::type possible_result_types; + + typedef typename mpl::if_< + mpl::greater< + mpl::size, + mpl::int_<1> + >, + typename make_variant_over::type, + typename mpl::front::type + >::type type; + }; + + template + struct visitor: static_visitor< + typename result_type::type + > + { + Geometry1 const& m_geometry1; + Strategy const& m_strategy; + + visitor(Geometry1 const& geometry1) + : m_geometry1(geometry1), + m_strategy(strategy) + {} + + template + bool operator()(Geometry2 const& geometry2, typename Strategy) const + { + return dispatch::distance + < + Geometry1, + Geometry2, + Strategy + >::apply(geometry1, geometry2, strategy); + } + }; + + template + static inline typename result_type >::type + apply( + Geometry1 const& geometry1, + const variant& geometry2, + Strategy const& strategy) + { + return apply_visitor(visitor(geometry1, strategy), geometry2); + } +}; + + +template +struct distance, variant > +{ + template + struct result_type + { + template + struct list_of_pairs + : mpl::fold::types, Result, + mpl::push_back > > + {}; + + typedef typename mpl::fold< + typename variant::types, + mpl::vector0<>, + mpl::lambda > + >::type combinations; + + typedef typename mpl::fold< + typename mpl::transform< + typename combinations, + typename strategy::distance::services::return_type< + Strategy, + typename mpl::lambda > >::type, + typename mpl::lambda > >::type + >::type + >::type, + mpl::set0<>, + mpl::insert + >::type possible_result_types; + + typedef typename mpl::if_< + mpl::greater< + mpl::size, + mpl::int_<1> + >, + typename make_variant_over::type, + typename mpl::front::type + >::type type; + }; + + template + struct visitor: static_visitor< + typename result_type::type + > + { + Strategy const& m_strategy; + + visitor(Strategy const& strategy) + : m_strategy(strategy) + {} + + template + typename default_distance_result::type operator()( + Geometry1 const& geometry1, + Geometry2 const& geometry2, + Strategy const& strategy) const + { + return resolve_variant::distance + < + Geometry1, + Geometry2, + Strategy + >::apply(geometry1, geometry2, strategy); + } + }; + + template + static inline typename result_type >::type + apply( + const variant& geometry1, + const variant& geometry2, + Strategy const& strategy) + { + return apply_visitor(visitor(strategy), geometry1, geometry2); + } +}; + +} // namespace resolve_variant + + /*! \brief \brief_calc2{distance} \brief_strategy \ingroup distance @@ -534,12 +791,7 @@ for distance, it is probably so that there is no specialization for return_type<...> for your strategy. */ template -inline typename strategy::distance::services::return_type - < - Strategy, - typename point_type::type, - typename point_type::type - >::type +inline typename resolve_variant::distance::result_type::type distance(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) @@ -550,11 +802,10 @@ distance(Geometry1 const& geometry1, detail::throw_on_empty_input(geometry1); detail::throw_on_empty_input(geometry2); - return dispatch::distance + return resolve_variant::distance < Geometry1, - Geometry2, - Strategy + Geometry2 >::apply(geometry1, geometry2, strategy); } @@ -572,8 +823,12 @@ distance(Geometry1 const& geometry1, \qbk{[include reference/algorithms/distance.qbk]} */ template -inline typename default_distance_result::type distance( - Geometry1 const& geometry1, Geometry2 const& geometry2) +inline typename resolve_variant::distance::result_type + < + typename detail::distance::default_strategy::type + >::type +distance(Geometry1 const& geometry1, + Geometry2 const& geometry2) { concept::check(); concept::check();