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