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