]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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 | ||
b32b8144 FG |
7 | // This file was modified by Oracle on 2017. |
8 | // Modifications copyright (c) 2017 Oracle and/or its affiliates. | |
9 | // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle | |
10 | ||
7c673cae FG |
11 | // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library |
12 | // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. | |
13 | ||
14 | // Use, modification and distribution is subject to the Boost Software License, | |
15 | // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at | |
16 | // http://www.boost.org/LICENSE_1_0.txt) | |
17 | ||
18 | #ifndef BOOST_GEOMETRY_ALGORITHMS_BUFFER_HPP | |
19 | #define BOOST_GEOMETRY_ALGORITHMS_BUFFER_HPP | |
20 | ||
21 | #include <cstddef> | |
22 | ||
23 | #include <boost/numeric/conversion/cast.hpp> | |
24 | ||
25 | #include <boost/range.hpp> | |
26 | ||
27 | #include <boost/variant/apply_visitor.hpp> | |
28 | #include <boost/variant/static_visitor.hpp> | |
29 | #include <boost/variant/variant_fwd.hpp> | |
30 | ||
31 | #include <boost/geometry/algorithms/clear.hpp> | |
32 | #include <boost/geometry/algorithms/envelope.hpp> | |
33 | #include <boost/geometry/algorithms/is_empty.hpp> | |
34 | #include <boost/geometry/algorithms/not_implemented.hpp> | |
35 | #include <boost/geometry/arithmetic/arithmetic.hpp> | |
36 | #include <boost/geometry/geometries/concepts/check.hpp> | |
37 | #include <boost/geometry/geometries/box.hpp> | |
38 | #include <boost/geometry/util/math.hpp> | |
39 | ||
40 | #include <boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp> | |
41 | ||
42 | namespace boost { namespace geometry | |
43 | { | |
44 | ||
45 | ||
46 | #ifndef DOXYGEN_NO_DETAIL | |
47 | namespace detail { namespace buffer | |
48 | { | |
49 | ||
50 | template <typename BoxIn, typename BoxOut, typename T, std::size_t C, std::size_t D, std::size_t N> | |
51 | struct box_loop | |
52 | { | |
53 | typedef typename coordinate_type<BoxOut>::type coordinate_type; | |
54 | ||
55 | static inline void apply(BoxIn const& box_in, T const& distance, BoxOut& box_out) | |
56 | { | |
57 | coordinate_type d = distance; | |
58 | set<C, D>(box_out, get<C, D>(box_in) + d); | |
59 | box_loop<BoxIn, BoxOut, T, C, D + 1, N>::apply(box_in, distance, box_out); | |
60 | } | |
61 | }; | |
62 | ||
63 | template <typename BoxIn, typename BoxOut, typename T, std::size_t C, std::size_t N> | |
64 | struct box_loop<BoxIn, BoxOut, T, C, N, N> | |
65 | { | |
66 | static inline void apply(BoxIn const&, T const&, BoxOut&) {} | |
67 | }; | |
68 | ||
69 | // Extends a box with the same amount in all directions | |
70 | template<typename BoxIn, typename BoxOut, typename T> | |
71 | inline void buffer_box(BoxIn const& box_in, T const& distance, BoxOut& box_out) | |
72 | { | |
73 | assert_dimension_equal<BoxIn, BoxOut>(); | |
74 | ||
75 | static const std::size_t N = dimension<BoxIn>::value; | |
76 | ||
77 | box_loop<BoxIn, BoxOut, T, min_corner, 0, N>::apply(box_in, -distance, box_out); | |
78 | box_loop<BoxIn, BoxOut, T, max_corner, 0, N>::apply(box_in, distance, box_out); | |
79 | } | |
80 | ||
81 | ||
82 | ||
83 | }} // namespace detail::buffer | |
84 | #endif // DOXYGEN_NO_DETAIL | |
85 | ||
86 | #ifndef DOXYGEN_NO_DISPATCH | |
87 | namespace dispatch | |
88 | { | |
89 | ||
90 | template | |
91 | < | |
92 | typename Input, | |
93 | typename Output, | |
94 | typename TagIn = typename tag<Input>::type, | |
95 | typename TagOut = typename tag<Output>::type | |
96 | > | |
97 | struct buffer: not_implemented<TagIn, TagOut> | |
98 | {}; | |
99 | ||
100 | ||
101 | template <typename BoxIn, typename BoxOut> | |
102 | struct buffer<BoxIn, BoxOut, box_tag, box_tag> | |
103 | { | |
104 | template <typename Distance> | |
105 | static inline void apply(BoxIn const& box_in, Distance const& distance, | |
106 | Distance const& , BoxOut& box_out) | |
107 | { | |
108 | detail::buffer::buffer_box(box_in, distance, box_out); | |
109 | } | |
110 | }; | |
111 | ||
112 | } // namespace dispatch | |
113 | #endif // DOXYGEN_NO_DISPATCH | |
114 | ||
115 | ||
116 | namespace resolve_variant { | |
117 | ||
118 | template <typename Geometry> | |
119 | struct buffer | |
120 | { | |
121 | template <typename Distance, typename GeometryOut> | |
122 | static inline void apply(Geometry const& geometry, | |
123 | Distance const& distance, | |
124 | Distance const& chord_length, | |
125 | GeometryOut& out) | |
126 | { | |
127 | dispatch::buffer<Geometry, GeometryOut>::apply(geometry, distance, chord_length, out); | |
128 | } | |
129 | }; | |
130 | ||
131 | template <BOOST_VARIANT_ENUM_PARAMS(typename T)> | |
132 | struct buffer<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > | |
133 | { | |
134 | template <typename Distance, typename GeometryOut> | |
135 | struct visitor: boost::static_visitor<void> | |
136 | { | |
137 | Distance const& m_distance; | |
138 | Distance const& m_chord_length; | |
139 | GeometryOut& m_out; | |
140 | ||
141 | visitor(Distance const& distance, | |
142 | Distance const& chord_length, | |
143 | GeometryOut& out) | |
144 | : m_distance(distance), | |
145 | m_chord_length(chord_length), | |
146 | m_out(out) | |
147 | {} | |
148 | ||
149 | template <typename Geometry> | |
150 | void operator()(Geometry const& geometry) const | |
151 | { | |
152 | buffer<Geometry>::apply(geometry, m_distance, m_chord_length, m_out); | |
153 | } | |
154 | }; | |
155 | ||
156 | template <typename Distance, typename GeometryOut> | |
157 | static inline void apply( | |
158 | boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry, | |
159 | Distance const& distance, | |
160 | Distance const& chord_length, | |
161 | GeometryOut& out | |
162 | ) | |
163 | { | |
164 | boost::apply_visitor(visitor<Distance, GeometryOut>(distance, chord_length, out), geometry); | |
165 | } | |
166 | }; | |
167 | ||
168 | } // namespace resolve_variant | |
169 | ||
170 | ||
171 | /*! | |
172 | \brief \brief_calc{buffer} | |
173 | \ingroup buffer | |
174 | \details \details_calc{buffer, \det_buffer}. | |
175 | \tparam Input \tparam_geometry | |
176 | \tparam Output \tparam_geometry | |
177 | \tparam Distance \tparam_numeric | |
178 | \param geometry_in \param_geometry | |
179 | \param geometry_out \param_geometry | |
180 | \param distance The distance to be used for the buffer | |
181 | \param chord_length (optional) The length of the chord's in the generated arcs around points or bends | |
182 | ||
183 | \qbk{[include reference/algorithms/buffer.qbk]} | |
184 | */ | |
185 | template <typename Input, typename Output, typename Distance> | |
186 | inline void buffer(Input const& geometry_in, Output& geometry_out, | |
187 | Distance const& distance, Distance const& chord_length = -1) | |
188 | { | |
189 | concepts::check<Input const>(); | |
190 | concepts::check<Output>(); | |
191 | ||
192 | resolve_variant::buffer<Input>::apply(geometry_in, distance, chord_length, geometry_out); | |
193 | } | |
194 | ||
195 | /*! | |
196 | \brief \brief_calc{buffer} | |
197 | \ingroup buffer | |
198 | \details \details_calc{return_buffer, \det_buffer}. \details_return{buffer}. | |
199 | \tparam Input \tparam_geometry | |
200 | \tparam Output \tparam_geometry | |
201 | \tparam Distance \tparam_numeric | |
202 | \param geometry \param_geometry | |
203 | \param distance The distance to be used for the buffer | |
204 | \param chord_length (optional) The length of the chord's in the generated arcs | |
205 | around points or bends (RESERVED, NOT YET USED) | |
206 | \return \return_calc{buffer} | |
207 | */ | |
208 | template <typename Output, typename Input, typename Distance> | |
209 | Output return_buffer(Input const& geometry, Distance const& distance, Distance const& chord_length = -1) | |
210 | { | |
211 | concepts::check<Input const>(); | |
212 | concepts::check<Output>(); | |
213 | ||
214 | Output geometry_out; | |
215 | ||
216 | resolve_variant::buffer<Input>::apply(geometry, distance, chord_length, geometry_out); | |
217 | ||
218 | return geometry_out; | |
219 | } | |
220 | ||
221 | /*! | |
222 | \brief \brief_calc{buffer} | |
223 | \ingroup buffer | |
224 | \details \details_calc{buffer, \det_buffer}. | |
225 | \tparam GeometryIn \tparam_geometry | |
226 | \tparam MultiPolygon \tparam_geometry{MultiPolygon} | |
227 | \tparam DistanceStrategy A strategy defining distance (or radius) | |
228 | \tparam SideStrategy A strategy defining creation along sides | |
229 | \tparam JoinStrategy A strategy defining creation around convex corners | |
230 | \tparam EndStrategy A strategy defining creation at linestring ends | |
231 | \tparam PointStrategy A strategy defining creation around points | |
232 | \param geometry_in \param_geometry | |
233 | \param geometry_out output multi polygon (or std:: collection of polygons), | |
234 | will contain a buffered version of the input geometry | |
235 | \param distance_strategy The distance strategy to be used | |
236 | \param side_strategy The side strategy to be used | |
237 | \param join_strategy The join strategy to be used | |
238 | \param end_strategy The end strategy to be used | |
239 | \param point_strategy The point strategy to be used | |
240 | ||
241 | \qbk{distinguish,with strategies} | |
242 | \qbk{[include reference/algorithms/buffer_with_strategies.qbk]} | |
243 | */ | |
244 | template | |
245 | < | |
246 | typename GeometryIn, | |
247 | typename MultiPolygon, | |
248 | typename DistanceStrategy, | |
249 | typename SideStrategy, | |
250 | typename JoinStrategy, | |
251 | typename EndStrategy, | |
252 | typename PointStrategy | |
253 | > | |
254 | inline void buffer(GeometryIn const& geometry_in, | |
255 | MultiPolygon& geometry_out, | |
256 | DistanceStrategy const& distance_strategy, | |
257 | SideStrategy const& side_strategy, | |
258 | JoinStrategy const& join_strategy, | |
259 | EndStrategy const& end_strategy, | |
260 | PointStrategy const& point_strategy) | |
261 | { | |
262 | typedef typename boost::range_value<MultiPolygon>::type polygon_type; | |
263 | concepts::check<GeometryIn const>(); | |
264 | concepts::check<polygon_type>(); | |
265 | ||
266 | typedef typename point_type<GeometryIn>::type point_type; | |
267 | typedef typename rescale_policy_type<point_type>::type rescale_policy_type; | |
268 | ||
269 | geometry_out.clear(); | |
270 | ||
271 | if (geometry::is_empty(geometry_in)) | |
272 | { | |
273 | // Then output geometry is kept empty as well | |
274 | return; | |
275 | } | |
276 | ||
277 | model::box<point_type> box; | |
278 | geometry::envelope(geometry_in, box); | |
279 | geometry::buffer(box, box, distance_strategy.max_distance(join_strategy, end_strategy)); | |
280 | ||
b32b8144 FG |
281 | typename strategy::intersection::services::default_strategy |
282 | < | |
283 | typename cs_tag<GeometryIn>::type | |
284 | >::type intersection_strategy; | |
285 | ||
7c673cae FG |
286 | rescale_policy_type rescale_policy |
287 | = boost::geometry::get_rescale_policy<rescale_policy_type>(box); | |
288 | ||
289 | detail::buffer::buffer_inserter<polygon_type>(geometry_in, range::back_inserter(geometry_out), | |
290 | distance_strategy, | |
291 | side_strategy, | |
292 | join_strategy, | |
293 | end_strategy, | |
294 | point_strategy, | |
b32b8144 | 295 | intersection_strategy, |
7c673cae FG |
296 | rescale_policy); |
297 | } | |
298 | ||
299 | ||
300 | }} // namespace boost::geometry | |
301 | ||
302 | #endif // BOOST_GEOMETRY_ALGORITHMS_BUFFER_HPP |