1 // Boost.Geometry (aka GGL, Generic Geometry Library)
2 
3 // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
4 // Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
5 // Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
6 // Copyright (c) 2014 Samuel Debionne, Grenoble, France.
7 
8 // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
9 // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
10 
11 // Use, modification and distribution is subject to the Boost Software License,
12 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
13 // http://www.boost.org/LICENSE_1_0.txt)
14 
15 #ifndef BOOST_GEOMETRY_ALGORITHMS_ASSIGN_HPP
16 #define BOOST_GEOMETRY_ALGORITHMS_ASSIGN_HPP
17 
18 
19 #include <cstddef>
20 
21 #include <boost/concept/requires.hpp>
22 #include <boost/concept_check.hpp>
23 #include <boost/mpl/assert.hpp>
24 #include <boost/mpl/if.hpp>
25 #include <boost/numeric/conversion/bounds.hpp>
26 #include <boost/numeric/conversion/cast.hpp>
27 #include <boost/type_traits.hpp>
28 
29 #include <boost/variant/apply_visitor.hpp>
30 #include <boost/variant/static_visitor.hpp>
31 #include <boost/variant/variant_fwd.hpp>
32 
33 #include <boost/geometry/algorithms/detail/assign_box_corners.hpp>
34 #include <boost/geometry/algorithms/detail/assign_indexed_point.hpp>
35 #include <boost/geometry/algorithms/detail/assign_values.hpp>
36 #include <boost/geometry/algorithms/convert.hpp>
37 #include <boost/geometry/algorithms/append.hpp>
38 #include <boost/geometry/algorithms/clear.hpp>
39 #include <boost/geometry/arithmetic/arithmetic.hpp>
40 #include <boost/geometry/core/access.hpp>
41 #include <boost/geometry/core/exterior_ring.hpp>
42 #include <boost/geometry/core/tags.hpp>
43 
44 #include <boost/geometry/geometries/concepts/check.hpp>
45 
46 #include <boost/geometry/util/for_each_coordinate.hpp>
47 
48 namespace boost { namespace geometry
49 {
50 
51 /*!
52 \brief Assign a range of points to a linestring, ring or polygon
53 \note The point-type of the range might be different from the point-type of the geometry
54 \ingroup assign
55 \tparam Geometry \tparam_geometry
56 \tparam Range \tparam_range_point
57 \param geometry \param_geometry
58 \param range \param_range_point
59 
60 \qbk{
61 [heading Notes]
62 [note Assign automatically clears the geometry before assigning (use append if you don't want that)]
63 [heading Example]
64 [assign_points] [assign_points_output]
65 
66 [heading See also]
67 \* [link geometry.reference.algorithms.append append]
68 }
69  */
70 template <typename Geometry, typename Range>
assign_points(Geometry & geometry,Range const & range)71 inline void assign_points(Geometry& geometry, Range const& range)
72 {
73     concept::check<Geometry>();
74 
75     clear(geometry);
76     geometry::append(geometry, range, -1, 0);
77 }
78 
79 
80 /*!
81 \brief assign to a box inverse infinite
82 \details The assign_inverse function initialize a 2D or 3D box with large coordinates, the
83 min corner is very large, the max corner is very small. This is a convenient starting point to
84 collect the minimum bounding box of a geometry.
85 \ingroup assign
86 \tparam Geometry \tparam_geometry
87 \param geometry \param_geometry
88 
89 \qbk{
90 [heading Example]
91 [assign_inverse] [assign_inverse_output]
92 
93 [heading See also]
94 \* [link geometry.reference.algorithms.make.make_inverse make_inverse]
95 }
96  */
97 template <typename Geometry>
assign_inverse(Geometry & geometry)98 inline void assign_inverse(Geometry& geometry)
99 {
100     concept::check<Geometry>();
101 
102     dispatch::assign_inverse
103         <
104             typename tag<Geometry>::type,
105             Geometry
106         >::apply(geometry);
107 }
108 
109 /*!
110 \brief assign zero values to a box, point
111 \ingroup assign
112 \details The assign_zero function initializes a 2D or 3D point or box with coordinates of zero
113 \tparam Geometry \tparam_geometry
114 \param geometry \param_geometry
115 
116  */
117 template <typename Geometry>
assign_zero(Geometry & geometry)118 inline void assign_zero(Geometry& geometry)
119 {
120     concept::check<Geometry>();
121 
122     dispatch::assign_zero
123         <
124             typename tag<Geometry>::type,
125             Geometry
126         >::apply(geometry);
127 }
128 
129 /*!
130 \brief Assign two coordinates to a geometry (usually a 2D point)
131 \ingroup assign
132 \tparam Geometry \tparam_geometry
133 \tparam Type \tparam_numeric to specify the coordinates
134 \param geometry \param_geometry
135 \param c1 \param_x
136 \param c2 \param_y
137 
138 \qbk{distinguish, 2 coordinate values}
139 \qbk{
140 [heading Example]
141 [assign_2d_point] [assign_2d_point_output]
142 
143 [heading See also]
144 \* [link geometry.reference.algorithms.make.make_2_2_coordinate_values make]
145 }
146  */
147 template <typename Geometry, typename Type>
assign_values(Geometry & geometry,Type const & c1,Type const & c2)148 inline void assign_values(Geometry& geometry, Type const& c1, Type const& c2)
149 {
150     concept::check<Geometry>();
151 
152     dispatch::assign
153         <
154             typename tag<Geometry>::type,
155             Geometry,
156             geometry::dimension<Geometry>::type::value
157         >::apply(geometry, c1, c2);
158 }
159 
160 /*!
161 \brief Assign three values to a geometry (usually a 3D point)
162 \ingroup assign
163 \tparam Geometry \tparam_geometry
164 \tparam Type \tparam_numeric to specify the coordinates
165 \param geometry \param_geometry
166 \param c1 \param_x
167 \param c2 \param_y
168 \param c3 \param_z
169 
170 \qbk{distinguish, 3 coordinate values}
171 \qbk{
172 [heading Example]
173 [assign_3d_point] [assign_3d_point_output]
174 
175 [heading See also]
176 \* [link geometry.reference.algorithms.make.make_3_3_coordinate_values make]
177 }
178  */
179 template <typename Geometry, typename Type>
assign_values(Geometry & geometry,Type const & c1,Type const & c2,Type const & c3)180 inline void assign_values(Geometry& geometry,
181             Type const& c1, Type const& c2, Type const& c3)
182 {
183     concept::check<Geometry>();
184 
185     dispatch::assign
186         <
187             typename tag<Geometry>::type,
188             Geometry,
189             geometry::dimension<Geometry>::type::value
190         >::apply(geometry, c1, c2, c3);
191 }
192 
193 /*!
194 \brief Assign four values to a geometry (usually a box or segment)
195 \ingroup assign
196 \tparam Geometry \tparam_geometry
197 \tparam Type \tparam_numeric to specify the coordinates
198 \param geometry \param_geometry
199 \param c1 First coordinate (usually x1)
200 \param c2 Second coordinate (usually y1)
201 \param c3 Third coordinate (usually x2)
202 \param c4 Fourth coordinate (usually y2)
203 
204 \qbk{distinguish, 4 coordinate values}
205  */
206 template <typename Geometry, typename Type>
assign_values(Geometry & geometry,Type const & c1,Type const & c2,Type const & c3,Type const & c4)207 inline void assign_values(Geometry& geometry,
208                 Type const& c1, Type const& c2, Type const& c3, Type const& c4)
209 {
210     concept::check<Geometry>();
211 
212     dispatch::assign
213         <
214             typename tag<Geometry>::type,
215             Geometry,
216             geometry::dimension<Geometry>::type::value
217         >::apply(geometry, c1, c2, c3, c4);
218 }
219 
220 
221 
222 namespace resolve_variant
223 {
224 
225 template <typename Geometry1, typename Geometry2>
226 struct assign
227 {
228     static inline void
applyboost::geometry::resolve_variant::assign229     apply(Geometry1& geometry1, const Geometry2& geometry2)
230     {
231         concept::check<Geometry1>();
232         concept::check<Geometry2 const>();
233         concept::check_concepts_and_equal_dimensions<Geometry1, Geometry2 const>();
234 
235         static bool const same_point_order
236             = point_order<Geometry1>::value == point_order<Geometry2>::value;
237         BOOST_MPL_ASSERT_MSG
238         (
239             (same_point_order),
240             ASSIGN_IS_NOT_SUPPORTED_FOR_DIFFERENT_POINT_ORDER,
241             (types<Geometry1, Geometry2>)
242         );
243         static bool const same_closure
244             = closure<Geometry1>::value == closure<Geometry2>::value;
245         BOOST_MPL_ASSERT_MSG
246         (
247             (same_closure),
248             ASSIGN_IS_NOT_SUPPORTED_FOR_DIFFERENT_CLOSURE,
249             (types<Geometry1, Geometry2>)
250         );
251 
252         dispatch::convert<Geometry2, Geometry1>::apply(geometry2, geometry1);
253     }
254 };
255 
256 
257 template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2>
258 struct assign<variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2>
259 {
260     struct visitor: static_visitor<void>
261     {
262         Geometry2 const& m_geometry2;
263 
visitorboost::geometry::resolve_variant::assign::visitor264         visitor(Geometry2 const& geometry2)
265         : m_geometry2(geometry2)
266         {}
267 
268         template <typename Geometry1>
operator ()boost::geometry::resolve_variant::assign::visitor269         result_type operator()(Geometry1& geometry1) const
270         {
271             return assign
272             <
273                 Geometry1,
274                 Geometry2
275             >::apply
276             (geometry1, m_geometry2);
277         }
278     };
279 
280     static inline void
applyboost::geometry::resolve_variant::assign281     apply(variant<BOOST_VARIANT_ENUM_PARAMS(T)>& geometry1,
282           Geometry2 const& geometry2)
283     {
284         return boost::apply_visitor(visitor(geometry2), geometry1);
285     }
286 };
287 
288 
289 template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)>
290 struct assign<Geometry1, variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
291 {
292     struct visitor: static_visitor<void>
293     {
294         Geometry1& m_geometry1;
295 
visitorboost::geometry::resolve_variant::assign::visitor296         visitor(Geometry1 const& geometry1)
297         : m_geometry1(geometry1)
298         {}
299 
300         template <typename Geometry2>
operator ()boost::geometry::resolve_variant::assign::visitor301         result_type operator()(Geometry2 const& geometry2) const
302         {
303             return assign
304             <
305                 Geometry1,
306                 Geometry2
307             >::apply
308             (m_geometry1, geometry2);
309         }
310     };
311 
312     static inline void
applyboost::geometry::resolve_variant::assign313     apply(Geometry1& geometry1,
314           variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2)
315     {
316         return boost::apply_visitor(visitor(geometry1), geometry2);
317     }
318 };
319 
320 
321 template <BOOST_VARIANT_ENUM_PARAMS(typename T1), BOOST_VARIANT_ENUM_PARAMS(typename T2)>
322 struct assign<variant<BOOST_VARIANT_ENUM_PARAMS(T1)>, variant<BOOST_VARIANT_ENUM_PARAMS(T2)> >
323 {
324     struct visitor: static_visitor<void>
325     {
326         template <typename Geometry1, typename Geometry2>
operator ()boost::geometry::resolve_variant::assign::visitor327         result_type operator()(
328                                 Geometry1& geometry1,
329                                 Geometry2 const& geometry2) const
330         {
331             return assign
332             <
333                 Geometry1,
334                 Geometry2
335             >::apply
336             (geometry1, geometry2);
337         }
338     };
339 
340     static inline void
applyboost::geometry::resolve_variant::assign341     apply(variant<BOOST_VARIANT_ENUM_PARAMS(T1)>& geometry1,
342           variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2)
343     {
344         return boost::apply_visitor(visitor(), geometry1, geometry2);
345     }
346 };
347 
348 } // namespace resolve_variant
349 
350 
351 /*!
352 \brief Assigns one geometry to another geometry
353 \details The assign algorithm assigns one geometry, e.g. a BOX, to another
354 geometry, e.g. a RING. This only works if it is possible and applicable.
355 \ingroup assign
356 \tparam Geometry1 \tparam_geometry
357 \tparam Geometry2 \tparam_geometry
358 \param geometry1 \param_geometry (target)
359 \param geometry2 \param_geometry (source)
360 
361 \qbk{
362 [heading Example]
363 [assign] [assign_output]
364 
365 [heading See also]
366 \* [link geometry.reference.algorithms.convert convert]
367 }
368  */
369 template <typename Geometry1, typename Geometry2>
assign(Geometry1 & geometry1,Geometry2 const & geometry2)370 inline void assign(Geometry1& geometry1, Geometry2 const& geometry2)
371 {
372     resolve_variant::assign<Geometry1, Geometry2>::apply(geometry1, geometry2);
373 }
374 
375 
376 }} // namespace boost::geometry
377 
378 
379 
380 #endif // BOOST_GEOMETRY_ALGORITHMS_ASSIGN_HPP
381