1 | // Boost.Geometry (aka GGL, Generic Geometry Library) |
2 | |
3 | // Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. |
4 | // Copyright (c) 2008-2014 Bruno Lalande, Paris, France. |
5 | // Copyright (c) 2009-2014 Mateusz Loskot, London, UK. |
6 | |
7 | // This file was modified by Oracle on 2014. |
8 | // Modifications copyright (c) 2014, Oracle and/or its affiliates. |
9 | |
10 | // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle |
11 | // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle |
12 | |
13 | // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library |
14 | // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. |
15 | |
16 | // Use, modification and distribution is subject to the Boost Software License, |
17 | // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at |
18 | // http://www.boost.org/LICENSE_1_0.txt) |
19 | |
20 | #ifndef BOOST_GEOMETRY_ALGORITHMS_APPEND_HPP |
21 | #define BOOST_GEOMETRY_ALGORITHMS_APPEND_HPP |
22 | |
23 | |
24 | #include <boost/range.hpp> |
25 | |
26 | #include <boost/variant/apply_visitor.hpp> |
27 | #include <boost/variant/static_visitor.hpp> |
28 | #include <boost/variant/variant_fwd.hpp> |
29 | |
30 | #include <boost/geometry/algorithms/num_interior_rings.hpp> |
31 | #include <boost/geometry/algorithms/detail/convert_point_to_point.hpp> |
32 | #include <boost/geometry/core/access.hpp> |
33 | #include <boost/geometry/core/mutable_range.hpp> |
34 | #include <boost/geometry/core/point_type.hpp> |
35 | #include <boost/geometry/core/tags.hpp> |
36 | #include <boost/geometry/geometries/concepts/check.hpp> |
37 | #include <boost/geometry/geometries/variant.hpp> |
38 | #include <boost/geometry/util/range.hpp> |
39 | |
40 | |
41 | namespace boost { namespace geometry |
42 | { |
43 | |
44 | |
45 | #ifndef DOXYGEN_NO_DETAIL |
46 | namespace detail { namespace append |
47 | { |
48 | |
49 | template <typename Geometry, typename Point> |
50 | struct append_no_action |
51 | { |
52 | static inline void apply(Geometry& , Point const& , |
53 | int = 0, int = 0) |
54 | { |
55 | } |
56 | }; |
57 | |
58 | template <typename Geometry, typename Point> |
59 | struct append_point |
60 | { |
61 | static inline void apply(Geometry& geometry, Point const& point, |
62 | int = 0, int = 0) |
63 | { |
64 | typename geometry::point_type<Geometry>::type copy; |
65 | geometry::detail::conversion::convert_point_to_point(point, copy); |
66 | traits::push_back<Geometry>::apply(geometry, copy); |
67 | } |
68 | }; |
69 | |
70 | |
71 | template <typename Geometry, typename Range> |
72 | struct append_range |
73 | { |
74 | typedef typename boost::range_value<Range>::type point_type; |
75 | |
76 | static inline void apply(Geometry& geometry, Range const& range, |
77 | int = 0, int = 0) |
78 | { |
79 | for (typename boost::range_iterator<Range const>::type |
80 | it = boost::begin(range); |
81 | it != boost::end(range); |
82 | ++it) |
83 | { |
84 | append_point<Geometry, point_type>::apply(geometry, *it); |
85 | } |
86 | } |
87 | }; |
88 | |
89 | |
90 | template <typename Polygon, typename Point> |
91 | struct point_to_polygon |
92 | { |
93 | typedef typename ring_type<Polygon>::type ring_type; |
94 | |
95 | static inline void apply(Polygon& polygon, Point const& point, |
96 | int ring_index, int = 0) |
97 | { |
98 | if (ring_index == -1) |
99 | { |
100 | append_point<ring_type, Point>::apply( |
101 | exterior_ring(polygon), point); |
102 | } |
103 | else if (ring_index < int(num_interior_rings(polygon))) |
104 | { |
105 | append_point<ring_type, Point>::apply( |
106 | range::at(interior_rings(polygon), ring_index), point); |
107 | } |
108 | } |
109 | }; |
110 | |
111 | |
112 | template <typename Polygon, typename Range> |
113 | struct range_to_polygon |
114 | { |
115 | typedef typename ring_type<Polygon>::type ring_type; |
116 | |
117 | static inline void apply(Polygon& polygon, Range const& range, |
118 | int ring_index, int = 0) |
119 | { |
120 | if (ring_index == -1) |
121 | { |
122 | append_range<ring_type, Range>::apply( |
123 | exterior_ring(polygon), range); |
124 | } |
125 | else if (ring_index < int(num_interior_rings(polygon))) |
126 | { |
127 | append_range<ring_type, Range>::apply( |
128 | range::at(interior_rings(polygon), ring_index), range); |
129 | } |
130 | } |
131 | }; |
132 | |
133 | |
134 | }} // namespace detail::append |
135 | #endif // DOXYGEN_NO_DETAIL |
136 | |
137 | |
138 | #ifndef DOXYGEN_NO_DISPATCH |
139 | namespace dispatch |
140 | { |
141 | |
142 | namespace splitted_dispatch |
143 | { |
144 | |
145 | template <typename Tag, typename Geometry, typename Point> |
146 | struct append_point |
147 | : detail::append::append_no_action<Geometry, Point> |
148 | {}; |
149 | |
150 | template <typename Geometry, typename Point> |
151 | struct append_point<linestring_tag, Geometry, Point> |
152 | : detail::append::append_point<Geometry, Point> |
153 | {}; |
154 | |
155 | template <typename Geometry, typename Point> |
156 | struct append_point<ring_tag, Geometry, Point> |
157 | : detail::append::append_point<Geometry, Point> |
158 | {}; |
159 | |
160 | |
161 | template <typename Polygon, typename Point> |
162 | struct append_point<polygon_tag, Polygon, Point> |
163 | : detail::append::point_to_polygon<Polygon, Point> |
164 | {}; |
165 | |
166 | |
167 | template <typename Tag, typename Geometry, typename Range> |
168 | struct append_range |
169 | : detail::append::append_no_action<Geometry, Range> |
170 | {}; |
171 | |
172 | template <typename Geometry, typename Range> |
173 | struct append_range<linestring_tag, Geometry, Range> |
174 | : detail::append::append_range<Geometry, Range> |
175 | {}; |
176 | |
177 | template <typename Geometry, typename Range> |
178 | struct append_range<ring_tag, Geometry, Range> |
179 | : detail::append::append_range<Geometry, Range> |
180 | {}; |
181 | |
182 | |
183 | template <typename Polygon, typename Range> |
184 | struct append_range<polygon_tag, Polygon, Range> |
185 | : detail::append::range_to_polygon<Polygon, Range> |
186 | {}; |
187 | |
188 | } // namespace splitted_dispatch |
189 | |
190 | |
191 | // Default: append a range (or linestring or ring or whatever) to any geometry |
192 | template |
193 | < |
194 | typename Geometry, typename RangeOrPoint, |
195 | typename TagRangeOrPoint = typename tag<RangeOrPoint>::type |
196 | > |
197 | struct append |
198 | : splitted_dispatch::append_range<typename tag<Geometry>::type, Geometry, RangeOrPoint> |
199 | {}; |
200 | |
201 | // Specialization for point to append a point to any geometry |
202 | template <typename Geometry, typename RangeOrPoint> |
203 | struct append<Geometry, RangeOrPoint, point_tag> |
204 | : splitted_dispatch::append_point<typename tag<Geometry>::type, Geometry, RangeOrPoint> |
205 | {}; |
206 | |
207 | } // namespace dispatch |
208 | #endif // DOXYGEN_NO_DISPATCH |
209 | |
210 | #ifndef DOXYGEN_NO_DETAIL |
211 | namespace detail { namespace append |
212 | { |
213 | |
214 | template <typename MultiGeometry, typename RangeOrPoint> |
215 | struct append_to_multigeometry |
216 | { |
217 | static inline void apply(MultiGeometry& multigeometry, |
218 | RangeOrPoint const& range_or_point, |
219 | int ring_index, int multi_index) |
220 | { |
221 | |
222 | dispatch::append |
223 | < |
224 | typename boost::range_value<MultiGeometry>::type, |
225 | RangeOrPoint |
226 | >::apply(range::at(multigeometry, multi_index), range_or_point, ring_index); |
227 | } |
228 | }; |
229 | |
230 | }} // namespace detail::append |
231 | #endif // DOXYGEN_NO_DETAIL |
232 | |
233 | #ifndef DOXYGEN_NO_DISPATCH |
234 | namespace dispatch |
235 | { |
236 | |
237 | namespace splitted_dispatch |
238 | { |
239 | |
240 | template <typename Geometry, typename Point> |
241 | struct append_point<multi_point_tag, Geometry, Point> |
242 | : detail::append::append_point<Geometry, Point> |
243 | {}; |
244 | |
245 | template <typename Geometry, typename Range> |
246 | struct append_range<multi_point_tag, Geometry, Range> |
247 | : detail::append::append_range<Geometry, Range> |
248 | {}; |
249 | |
250 | template <typename MultiGeometry, typename RangeOrPoint> |
251 | struct append_point<multi_linestring_tag, MultiGeometry, RangeOrPoint> |
252 | : detail::append::append_to_multigeometry<MultiGeometry, RangeOrPoint> |
253 | {}; |
254 | |
255 | template <typename MultiGeometry, typename RangeOrPoint> |
256 | struct append_range<multi_linestring_tag, MultiGeometry, RangeOrPoint> |
257 | : detail::append::append_to_multigeometry<MultiGeometry, RangeOrPoint> |
258 | {}; |
259 | |
260 | template <typename MultiGeometry, typename RangeOrPoint> |
261 | struct append_point<multi_polygon_tag, MultiGeometry, RangeOrPoint> |
262 | : detail::append::append_to_multigeometry<MultiGeometry, RangeOrPoint> |
263 | {}; |
264 | |
265 | template <typename MultiGeometry, typename RangeOrPoint> |
266 | struct append_range<multi_polygon_tag, MultiGeometry, RangeOrPoint> |
267 | : detail::append::append_to_multigeometry<MultiGeometry, RangeOrPoint> |
268 | {}; |
269 | |
270 | } // namespace splitted_dispatch |
271 | |
272 | } // namespace dispatch |
273 | #endif // DOXYGEN_NO_DISPATCH |
274 | |
275 | |
276 | namespace resolve_variant { |
277 | |
278 | template <typename Geometry> |
279 | struct append |
280 | { |
281 | template <typename RangeOrPoint> |
282 | static inline void apply(Geometry& geometry, |
283 | RangeOrPoint const& range_or_point, |
284 | int ring_index, |
285 | int multi_index) |
286 | { |
287 | concept::check<Geometry>(); |
288 | dispatch::append<Geometry, RangeOrPoint>::apply(geometry, |
289 | range_or_point, |
290 | ring_index, |
291 | multi_index); |
292 | } |
293 | }; |
294 | |
295 | |
296 | template <BOOST_VARIANT_ENUM_PARAMS(typename T)> |
297 | struct append<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > |
298 | { |
299 | template <typename RangeOrPoint> |
300 | struct visitor: boost::static_visitor<void> |
301 | { |
302 | RangeOrPoint const& m_range_or_point; |
303 | int m_ring_index; |
304 | int m_multi_index; |
305 | |
306 | visitor(RangeOrPoint const& range_or_point, |
307 | int ring_index, |
308 | int multi_index): |
309 | m_range_or_point(range_or_point), |
310 | m_ring_index(ring_index), |
311 | m_multi_index(multi_index) |
312 | {} |
313 | |
314 | template <typename Geometry> |
315 | void operator()(Geometry& geometry) const |
316 | { |
317 | append<Geometry>::apply(geometry, |
318 | m_range_or_point, |
319 | m_ring_index, |
320 | m_multi_index); |
321 | } |
322 | }; |
323 | |
324 | template <typename RangeOrPoint> |
325 | static inline void apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>& variant_geometry, |
326 | RangeOrPoint const& range_or_point, |
327 | int ring_index, |
328 | int multi_index) |
329 | { |
330 | boost::apply_visitor( |
331 | visitor<RangeOrPoint>( |
332 | range_or_point, |
333 | ring_index, |
334 | multi_index |
335 | ), |
336 | variant_geometry |
337 | ); |
338 | } |
339 | }; |
340 | |
341 | } // namespace resolve_variant; |
342 | |
343 | |
344 | /*! |
345 | \brief Appends one or more points to a linestring, ring, polygon, multi-geometry |
346 | \ingroup append |
347 | \tparam Geometry \tparam_geometry |
348 | \tparam RangeOrPoint Either a range or a point, fullfilling Boost.Range concept or Boost.Geometry Point Concept |
349 | \param geometry \param_geometry |
350 | \param range_or_point The point or range to add |
351 | \param ring_index The index of the ring in case of a polygon: |
352 | exterior ring (-1, the default) or interior ring index |
353 | \param multi_index The index of the geometry to which the points are appended |
354 | |
355 | \qbk{[include reference/algorithms/append.qbk]} |
356 | } |
357 | */ |
358 | template <typename Geometry, typename RangeOrPoint> |
359 | inline void append(Geometry& geometry, RangeOrPoint const& range_or_point, |
360 | int ring_index = -1, int multi_index = 0) |
361 | { |
362 | resolve_variant::append<Geometry> |
363 | ::apply(geometry, range_or_point, ring_index, multi_index); |
364 | } |
365 | |
366 | |
367 | }} // namespace boost::geometry |
368 | |
369 | |
370 | #endif // BOOST_GEOMETRY_ALGORITHMS_APPEND_HPP |
371 | |