diff --git a/include/boost/geometry/algorithms/assign.hpp b/include/boost/geometry/algorithms/assign.hpp index fd23f1ddb..f7b8679f1 100644 --- a/include/boost/geometry/algorithms/assign.hpp +++ b/include/boost/geometry/algorithms/assign.hpp @@ -3,6 +3,7 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. +// Copyright (c) 2014 Samuel Debionne, Grenoble, France. // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. @@ -40,6 +41,8 @@ #include +#include + namespace boost { namespace geometry { @@ -121,6 +124,137 @@ inline void assign_zero(Geometry& geometry) >::apply(geometry); } + +namespace resolve_variant +{ + +template +struct assign +{ + static inline void + apply( + Geometry1& geometry1, + const Geometry2& geometry2) + { + concept::check(); + concept::check(); + concept::check_concepts_and_equal_dimensions(); + + bool const same_point_order = + point_order::value == point_order::value; + bool const same_closure = + closure::value == closure::value; + + BOOST_MPL_ASSERT_MSG + ( + same_point_order, ASSIGN_IS_NOT_SUPPORTED_FOR_DIFFERENT_POINT_ORDER + , (types) + ); + BOOST_MPL_ASSERT_MSG + ( + same_closure, ASSIGN_IS_NOT_SUPPORTED_FOR_DIFFERENT_CLOSURE + , (types) + ); + + dispatch::convert::apply(geometry2, geometry1); + } +}; + + +template +struct assign, Geometry2> +{ + struct visitor: static_visitor + { + Geometry2 const& m_geometry2; + + visitor(Geometry2 const& geometry2) + : m_geometry2(geometry2) + {} + + template + result_type operator()(Geometry1& geometry1) const + { + return assign + < + Geometry1, + Geometry2 + >::apply + (geometry1, m_geometry2); + } + }; + + static inline void + apply(variant& geometry1, + Geometry2 const& geometry2) + { + return apply_visitor(visitor(geometry2), geometry1); + } +}; + + +template +struct assign > +{ + struct visitor: static_visitor + { + Geometry1& m_geometry1; + + visitor(Geometry1 const& geometry1) + : m_geometry1(geometry1) + {} + + template + result_type operator()(Geometry2 const& geometry2) const + { + return assign + < + Geometry1, + Geometry2 + >::apply + (m_geometry1, geometry2); + } + }; + + static inline void + apply(Geometry1& geometry1, + variant const& geometry2) + { + return apply_visitor(visitor(geometry1), geometry2); + } +}; + + +template +struct assign, variant > +{ + struct visitor: static_visitor + { + template + result_type operator()( + Geometry1& geometry1, + Geometry2 const& geometry2) const + { + return assign + < + Geometry1, + Geometry2 + >::apply + (geometry1, geometry2); + } + }; + + static inline void + apply(variant& geometry1, + variant const& geometry2) + { + return apply_visitor(visitor(), geometry1, geometry2); + } +}; + +} // namespace resolve_variant + + /*! \brief Assigns one geometry to another geometry \details The assign algorithm assigns one geometry, e.g. a BOX, to another @@ -142,25 +276,7 @@ geometry, e.g. a RING. This only works if it is possible and applicable. template inline void assign(Geometry1& geometry1, Geometry2 const& geometry2) { - concept::check_concepts_and_equal_dimensions(); - - bool const same_point_order = - point_order::value == point_order::value; - bool const same_closure = - closure::value == closure::value; - - BOOST_MPL_ASSERT_MSG - ( - same_point_order, ASSIGN_IS_NOT_SUPPORTED_FOR_DIFFERENT_POINT_ORDER - , (types) - ); - BOOST_MPL_ASSERT_MSG - ( - same_closure, ASSIGN_IS_NOT_SUPPORTED_FOR_DIFFERENT_CLOSURE - , (types) - ); - - dispatch::convert::apply(geometry2, geometry1); + resolve_variant::assign::apply(geometry1, geometry2); } diff --git a/test/algorithms/assign.cpp b/test/algorithms/assign.cpp index a64f4010d..df8901324 100644 --- a/test/algorithms/assign.cpp +++ b/test/algorithms/assign.cpp @@ -4,6 +4,7 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. +// Copyright (c) 2014 Samuel Debionne, Grenoble, France. // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. @@ -189,6 +190,70 @@ void test_assign_conversion() } +template +void test_assign_conversion_variant() +{ + typedef bg::model::box

box_type; + typedef bg::model::ring

ring_type; + typedef bg::model::polygon

polygon_type; + + P p; + bg::assign_values(p, 1, 2); + + box_type b; + bg::assign(boost::variant(b), p); + + BOOST_CHECK_CLOSE((bg::get<0, 0>(b)), 1.0, 0.001); + BOOST_CHECK_CLOSE((bg::get<0, 1>(b)), 2.0, 0.001); + BOOST_CHECK_CLOSE((bg::get<1, 0>(b)), 1.0, 0.001); + BOOST_CHECK_CLOSE((bg::get<1, 1>(b)), 2.0, 0.001); + + + bg::set(b, 1); + bg::set(b, 2); + bg::set(b, 3); + bg::set(b, 4); + + ring_type ring; + bg::assign(boost::variant(ring), boost::variant(b)); + + { + typedef bg::model::ring ring_type_ccw; + ring_type_ccw ring_ccw; + // Should NOT compile (currently): bg::assign(ring_ccw, ring); + + } + + typename boost::range_const_iterator::type it = ring.begin(); + BOOST_CHECK_CLOSE(bg::get<0>(*it), 1.0, 0.001); + BOOST_CHECK_CLOSE(bg::get<1>(*it), 2.0, 0.001); + it++; + BOOST_CHECK_CLOSE(bg::get<0>(*it), 1.0, 0.001); + BOOST_CHECK_CLOSE(bg::get<1>(*it), 4.0, 0.001); + it++; + BOOST_CHECK_CLOSE(bg::get<0>(*it), 3.0, 0.001); + BOOST_CHECK_CLOSE(bg::get<1>(*it), 4.0, 0.001); + it++; + BOOST_CHECK_CLOSE(bg::get<0>(*it), 3.0, 0.001); + BOOST_CHECK_CLOSE(bg::get<1>(*it), 2.0, 0.001); + it++; + BOOST_CHECK_CLOSE(bg::get<0>(*it), 1.0, 0.001); + BOOST_CHECK_CLOSE(bg::get<1>(*it), 2.0, 0.001); + + BOOST_CHECK_EQUAL(ring.size(), 5u); + + + polygon_type polygon; + + bg::assign(boost::variant(polygon), boost::variant(ring)); + BOOST_CHECK_EQUAL(bg::num_points(polygon), 5u); + + ring_type ring2; + bg::assign(boost::variant(ring2), boost::variant(polygon)); + BOOST_CHECK_EQUAL(bg::num_points(ring2), 5u); +} + + template void test_assign_point_2d() { @@ -225,6 +290,7 @@ int test_main(int, char* []) test_assign_point_2d >(); test_assign_conversion >(); + test_assign_conversion_variant >(); // Segment (currently) cannot handle array's because derived from std::pair