Chris@16
|
1 // Boost.Geometry (aka GGL, Generic Geometry Library)
|
Chris@16
|
2
|
Chris@16
|
3 // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
|
Chris@16
|
4 // Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
|
Chris@16
|
5 // Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
|
Chris@101
|
6 // Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
|
Chris@101
|
7
|
Chris@101
|
8 // This file was modified by Oracle on 2014, 2015.
|
Chris@101
|
9 // Modifications copyright (c) 2014-2015 Oracle and/or its affiliates.
|
Chris@101
|
10
|
Chris@101
|
11 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
|
Chris@16
|
12
|
Chris@16
|
13 // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
|
Chris@16
|
14 // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
|
Chris@16
|
15
|
Chris@16
|
16 // Use, modification and distribution is subject to the Boost Software License,
|
Chris@16
|
17 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
Chris@16
|
18 // http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
19
|
Chris@16
|
20 #ifndef BOOST_GEOMETRY_ALGORITHMS_CENTROID_HPP
|
Chris@16
|
21 #define BOOST_GEOMETRY_ALGORITHMS_CENTROID_HPP
|
Chris@16
|
22
|
Chris@16
|
23
|
Chris@16
|
24 #include <cstddef>
|
Chris@16
|
25
|
Chris@101
|
26 #include <boost/core/ignore_unused.hpp>
|
Chris@16
|
27 #include <boost/range.hpp>
|
Chris@101
|
28
|
Chris@101
|
29 #include <boost/variant/apply_visitor.hpp>
|
Chris@101
|
30 #include <boost/variant/static_visitor.hpp>
|
Chris@101
|
31 #include <boost/variant/variant_fwd.hpp>
|
Chris@16
|
32
|
Chris@16
|
33 #include <boost/geometry/core/closure.hpp>
|
Chris@16
|
34 #include <boost/geometry/core/cs.hpp>
|
Chris@16
|
35 #include <boost/geometry/core/coordinate_dimension.hpp>
|
Chris@16
|
36 #include <boost/geometry/core/exception.hpp>
|
Chris@16
|
37 #include <boost/geometry/core/exterior_ring.hpp>
|
Chris@16
|
38 #include <boost/geometry/core/interior_rings.hpp>
|
Chris@16
|
39 #include <boost/geometry/core/tag_cast.hpp>
|
Chris@101
|
40 #include <boost/geometry/core/tags.hpp>
|
Chris@101
|
41 #include <boost/geometry/core/point_type.hpp>
|
Chris@16
|
42
|
Chris@101
|
43 #include <boost/geometry/geometries/concepts/check.hpp>
|
Chris@101
|
44
|
Chris@101
|
45 #include <boost/geometry/algorithms/assign.hpp>
|
Chris@16
|
46 #include <boost/geometry/algorithms/convert.hpp>
|
Chris@101
|
47 #include <boost/geometry/algorithms/detail/interior_iterator.hpp>
|
Chris@101
|
48 #include <boost/geometry/algorithms/detail/point_on_border.hpp>
|
Chris@16
|
49 #include <boost/geometry/algorithms/not_implemented.hpp>
|
Chris@16
|
50 #include <boost/geometry/strategies/centroid.hpp>
|
Chris@16
|
51 #include <boost/geometry/strategies/concepts/centroid_concept.hpp>
|
Chris@101
|
52 #include <boost/geometry/strategies/default_strategy.hpp>
|
Chris@16
|
53 #include <boost/geometry/views/closeable_view.hpp>
|
Chris@16
|
54
|
Chris@16
|
55 #include <boost/geometry/util/for_each_coordinate.hpp>
|
Chris@16
|
56 #include <boost/geometry/util/select_coordinate_type.hpp>
|
Chris@16
|
57
|
Chris@101
|
58 #include <boost/geometry/algorithms/num_points.hpp>
|
Chris@101
|
59 #include <boost/geometry/multi/algorithms/num_points.hpp>
|
Chris@101
|
60
|
Chris@101
|
61 #include <boost/geometry/algorithms/detail/centroid/translating_transformer.hpp>
|
Chris@16
|
62
|
Chris@16
|
63
|
Chris@16
|
64 namespace boost { namespace geometry
|
Chris@16
|
65 {
|
Chris@16
|
66
|
Chris@16
|
67
|
Chris@16
|
68 #if ! defined(BOOST_GEOMETRY_CENTROID_NO_THROW)
|
Chris@16
|
69
|
Chris@16
|
70 /*!
|
Chris@16
|
71 \brief Centroid Exception
|
Chris@16
|
72 \ingroup centroid
|
Chris@16
|
73 \details The centroid_exception is thrown if the free centroid function is called with
|
Chris@16
|
74 geometries for which the centroid cannot be calculated. For example: a linestring
|
Chris@16
|
75 without points, a polygon without points, an empty multi-geometry.
|
Chris@16
|
76 \qbk{
|
Chris@16
|
77 [heading See also]
|
Chris@16
|
78 \* [link geometry.reference.algorithms.centroid the centroid function]
|
Chris@16
|
79 }
|
Chris@16
|
80
|
Chris@16
|
81 */
|
Chris@16
|
82 class centroid_exception : public geometry::exception
|
Chris@16
|
83 {
|
Chris@16
|
84 public:
|
Chris@16
|
85
|
Chris@101
|
86 /*!
|
Chris@101
|
87 \brief The default constructor
|
Chris@101
|
88 */
|
Chris@16
|
89 inline centroid_exception() {}
|
Chris@16
|
90
|
Chris@101
|
91 /*!
|
Chris@101
|
92 \brief Returns the explanatory string.
|
Chris@101
|
93 \return Pointer to a null-terminated string with explanatory information.
|
Chris@101
|
94 */
|
Chris@16
|
95 virtual char const* what() const throw()
|
Chris@16
|
96 {
|
Chris@16
|
97 return "Boost.Geometry Centroid calculation exception";
|
Chris@16
|
98 }
|
Chris@16
|
99 };
|
Chris@16
|
100
|
Chris@16
|
101 #endif
|
Chris@16
|
102
|
Chris@16
|
103
|
Chris@16
|
104 #ifndef DOXYGEN_NO_DETAIL
|
Chris@16
|
105 namespace detail { namespace centroid
|
Chris@16
|
106 {
|
Chris@16
|
107
|
Chris@16
|
108 struct centroid_point
|
Chris@16
|
109 {
|
Chris@16
|
110 template<typename Point, typename PointCentroid, typename Strategy>
|
Chris@16
|
111 static inline void apply(Point const& point, PointCentroid& centroid,
|
Chris@16
|
112 Strategy const&)
|
Chris@16
|
113 {
|
Chris@16
|
114 geometry::convert(point, centroid);
|
Chris@16
|
115 }
|
Chris@16
|
116 };
|
Chris@16
|
117
|
Chris@16
|
118 template
|
Chris@16
|
119 <
|
Chris@16
|
120 typename Indexed,
|
Chris@16
|
121 typename Point,
|
Chris@101
|
122 std::size_t Dimension = 0,
|
Chris@101
|
123 std::size_t DimensionCount = dimension<Indexed>::type::value
|
Chris@16
|
124 >
|
Chris@16
|
125 struct centroid_indexed_calculator
|
Chris@16
|
126 {
|
Chris@16
|
127 typedef typename select_coordinate_type
|
Chris@16
|
128 <
|
Chris@16
|
129 Indexed, Point
|
Chris@16
|
130 >::type coordinate_type;
|
Chris@16
|
131 static inline void apply(Indexed const& indexed, Point& centroid)
|
Chris@16
|
132 {
|
Chris@16
|
133 coordinate_type const c1 = get<min_corner, Dimension>(indexed);
|
Chris@16
|
134 coordinate_type const c2 = get<max_corner, Dimension>(indexed);
|
Chris@16
|
135 coordinate_type m = c1 + c2;
|
Chris@16
|
136 coordinate_type const two = 2;
|
Chris@16
|
137 m /= two;
|
Chris@16
|
138
|
Chris@16
|
139 set<Dimension>(centroid, m);
|
Chris@16
|
140
|
Chris@16
|
141 centroid_indexed_calculator
|
Chris@16
|
142 <
|
Chris@101
|
143 Indexed, Point, Dimension + 1
|
Chris@16
|
144 >::apply(indexed, centroid);
|
Chris@16
|
145 }
|
Chris@16
|
146 };
|
Chris@16
|
147
|
Chris@16
|
148
|
Chris@16
|
149 template<typename Indexed, typename Point, std::size_t DimensionCount>
|
Chris@16
|
150 struct centroid_indexed_calculator<Indexed, Point, DimensionCount, DimensionCount>
|
Chris@16
|
151 {
|
Chris@16
|
152 static inline void apply(Indexed const& , Point& )
|
Chris@16
|
153 {
|
Chris@16
|
154 }
|
Chris@16
|
155 };
|
Chris@16
|
156
|
Chris@16
|
157
|
Chris@16
|
158 struct centroid_indexed
|
Chris@16
|
159 {
|
Chris@16
|
160 template<typename Indexed, typename Point, typename Strategy>
|
Chris@16
|
161 static inline void apply(Indexed const& indexed, Point& centroid,
|
Chris@16
|
162 Strategy const&)
|
Chris@16
|
163 {
|
Chris@16
|
164 centroid_indexed_calculator
|
Chris@16
|
165 <
|
Chris@101
|
166 Indexed, Point
|
Chris@16
|
167 >::apply(indexed, centroid);
|
Chris@16
|
168 }
|
Chris@16
|
169 };
|
Chris@16
|
170
|
Chris@16
|
171
|
Chris@16
|
172 // There is one thing where centroid is different from e.g. within.
|
Chris@16
|
173 // If the ring has only one point, it might make sense that
|
Chris@16
|
174 // that point is the centroid.
|
Chris@16
|
175 template<typename Point, typename Range>
|
Chris@16
|
176 inline bool range_ok(Range const& range, Point& centroid)
|
Chris@16
|
177 {
|
Chris@16
|
178 std::size_t const n = boost::size(range);
|
Chris@16
|
179 if (n > 1)
|
Chris@16
|
180 {
|
Chris@16
|
181 return true;
|
Chris@16
|
182 }
|
Chris@16
|
183 else if (n <= 0)
|
Chris@16
|
184 {
|
Chris@16
|
185 #if ! defined(BOOST_GEOMETRY_CENTROID_NO_THROW)
|
Chris@16
|
186 throw centroid_exception();
|
Chris@101
|
187 #else
|
Chris@101
|
188 return false;
|
Chris@16
|
189 #endif
|
Chris@16
|
190 }
|
Chris@16
|
191 else // if (n == 1)
|
Chris@16
|
192 {
|
Chris@16
|
193 // Take over the first point in a "coordinate neutral way"
|
Chris@16
|
194 geometry::convert(*boost::begin(range), centroid);
|
Chris@16
|
195 return false;
|
Chris@16
|
196 }
|
Chris@101
|
197 //return true; // unreachable
|
Chris@16
|
198 }
|
Chris@16
|
199
|
Chris@16
|
200 /*!
|
Chris@101
|
201 \brief Calculate the centroid of a Ring or a Linestring.
|
Chris@16
|
202 */
|
Chris@16
|
203 template <closure_selector Closure>
|
Chris@16
|
204 struct centroid_range_state
|
Chris@16
|
205 {
|
Chris@101
|
206 template<typename Ring, typename PointTransformer, typename Strategy>
|
Chris@16
|
207 static inline void apply(Ring const& ring,
|
Chris@101
|
208 PointTransformer const& transformer,
|
Chris@101
|
209 Strategy const& strategy,
|
Chris@101
|
210 typename Strategy::state_type& state)
|
Chris@16
|
211 {
|
Chris@101
|
212 boost::ignore_unused(strategy);
|
Chris@101
|
213
|
Chris@101
|
214 typedef typename geometry::point_type<Ring const>::type point_type;
|
Chris@16
|
215 typedef typename closeable_view<Ring const, Closure>::type view_type;
|
Chris@16
|
216
|
Chris@16
|
217 typedef typename boost::range_iterator<view_type const>::type iterator_type;
|
Chris@16
|
218
|
Chris@16
|
219 view_type view(ring);
|
Chris@16
|
220 iterator_type it = boost::begin(view);
|
Chris@16
|
221 iterator_type end = boost::end(view);
|
Chris@16
|
222
|
Chris@101
|
223 typename PointTransformer::result_type
|
Chris@101
|
224 previous_pt = transformer.apply(*it);
|
Chris@101
|
225
|
Chris@101
|
226 for ( ++it ; it != end ; ++it)
|
Chris@16
|
227 {
|
Chris@101
|
228 typename PointTransformer::result_type
|
Chris@101
|
229 pt = transformer.apply(*it);
|
Chris@101
|
230
|
Chris@101
|
231 strategy.apply(static_cast<point_type const&>(previous_pt),
|
Chris@101
|
232 static_cast<point_type const&>(pt),
|
Chris@101
|
233 state);
|
Chris@101
|
234
|
Chris@101
|
235 previous_pt = pt;
|
Chris@16
|
236 }
|
Chris@16
|
237 }
|
Chris@16
|
238 };
|
Chris@16
|
239
|
Chris@16
|
240 template <closure_selector Closure>
|
Chris@16
|
241 struct centroid_range
|
Chris@16
|
242 {
|
Chris@16
|
243 template<typename Range, typename Point, typename Strategy>
|
Chris@101
|
244 static inline bool apply(Range const& range, Point& centroid,
|
Chris@101
|
245 Strategy const& strategy)
|
Chris@16
|
246 {
|
Chris@16
|
247 if (range_ok(range, centroid))
|
Chris@16
|
248 {
|
Chris@101
|
249 // prepare translation transformer
|
Chris@101
|
250 translating_transformer<Range> transformer(*boost::begin(range));
|
Chris@101
|
251
|
Chris@16
|
252 typename Strategy::state_type state;
|
Chris@101
|
253 centroid_range_state<Closure>::apply(range, transformer,
|
Chris@101
|
254 strategy, state);
|
Chris@101
|
255
|
Chris@101
|
256 if ( strategy.result(state, centroid) )
|
Chris@101
|
257 {
|
Chris@101
|
258 // translate the result back
|
Chris@101
|
259 transformer.apply_reverse(centroid);
|
Chris@101
|
260 return true;
|
Chris@101
|
261 }
|
Chris@16
|
262 }
|
Chris@101
|
263
|
Chris@101
|
264 return false;
|
Chris@16
|
265 }
|
Chris@16
|
266 };
|
Chris@16
|
267
|
Chris@16
|
268
|
Chris@16
|
269 /*!
|
Chris@16
|
270 \brief Centroid of a polygon.
|
Chris@16
|
271 \note Because outer ring is clockwise, inners are counter clockwise,
|
Chris@16
|
272 triangle approach is OK and works for polygons with rings.
|
Chris@16
|
273 */
|
Chris@16
|
274 struct centroid_polygon_state
|
Chris@16
|
275 {
|
Chris@101
|
276 template<typename Polygon, typename PointTransformer, typename Strategy>
|
Chris@16
|
277 static inline void apply(Polygon const& poly,
|
Chris@101
|
278 PointTransformer const& transformer,
|
Chris@101
|
279 Strategy const& strategy,
|
Chris@101
|
280 typename Strategy::state_type& state)
|
Chris@16
|
281 {
|
Chris@16
|
282 typedef typename ring_type<Polygon>::type ring_type;
|
Chris@16
|
283 typedef centroid_range_state<geometry::closure<ring_type>::value> per_ring;
|
Chris@16
|
284
|
Chris@101
|
285 per_ring::apply(exterior_ring(poly), transformer, strategy, state);
|
Chris@16
|
286
|
Chris@101
|
287 typename interior_return_type<Polygon const>::type
|
Chris@101
|
288 rings = interior_rings(poly);
|
Chris@101
|
289
|
Chris@101
|
290 for (typename detail::interior_iterator<Polygon const>::type
|
Chris@101
|
291 it = boost::begin(rings); it != boost::end(rings); ++it)
|
Chris@16
|
292 {
|
Chris@101
|
293 per_ring::apply(*it, transformer, strategy, state);
|
Chris@16
|
294 }
|
Chris@16
|
295 }
|
Chris@16
|
296 };
|
Chris@16
|
297
|
Chris@16
|
298 struct centroid_polygon
|
Chris@16
|
299 {
|
Chris@16
|
300 template<typename Polygon, typename Point, typename Strategy>
|
Chris@101
|
301 static inline bool apply(Polygon const& poly, Point& centroid,
|
Chris@101
|
302 Strategy const& strategy)
|
Chris@16
|
303 {
|
Chris@16
|
304 if (range_ok(exterior_ring(poly), centroid))
|
Chris@16
|
305 {
|
Chris@101
|
306 // prepare translation transformer
|
Chris@101
|
307 translating_transformer<Polygon>
|
Chris@101
|
308 transformer(*boost::begin(exterior_ring(poly)));
|
Chris@101
|
309
|
Chris@16
|
310 typename Strategy::state_type state;
|
Chris@101
|
311 centroid_polygon_state::apply(poly, transformer, strategy, state);
|
Chris@101
|
312
|
Chris@101
|
313 if ( strategy.result(state, centroid) )
|
Chris@101
|
314 {
|
Chris@101
|
315 // translate the result back
|
Chris@101
|
316 transformer.apply_reverse(centroid);
|
Chris@101
|
317 return true;
|
Chris@101
|
318 }
|
Chris@101
|
319 }
|
Chris@101
|
320
|
Chris@101
|
321 return false;
|
Chris@101
|
322 }
|
Chris@101
|
323 };
|
Chris@101
|
324
|
Chris@101
|
325
|
Chris@101
|
326 /*!
|
Chris@101
|
327 \brief Building block of a multi-point, to be used as Policy in the
|
Chris@101
|
328 more generec centroid_multi
|
Chris@101
|
329 */
|
Chris@101
|
330 struct centroid_multi_point_state
|
Chris@101
|
331 {
|
Chris@101
|
332 template <typename Point, typename PointTransformer, typename Strategy>
|
Chris@101
|
333 static inline void apply(Point const& point,
|
Chris@101
|
334 PointTransformer const& transformer,
|
Chris@101
|
335 Strategy const& strategy,
|
Chris@101
|
336 typename Strategy::state_type& state)
|
Chris@101
|
337 {
|
Chris@101
|
338 boost::ignore_unused(strategy);
|
Chris@101
|
339 strategy.apply(static_cast<Point const&>(transformer.apply(point)),
|
Chris@101
|
340 state);
|
Chris@101
|
341 }
|
Chris@101
|
342 };
|
Chris@101
|
343
|
Chris@101
|
344
|
Chris@101
|
345 /*!
|
Chris@101
|
346 \brief Generic implementation which calls a policy to calculate the
|
Chris@101
|
347 centroid of the total of its single-geometries
|
Chris@101
|
348 \details The Policy is, in general, the single-version, with state. So
|
Chris@101
|
349 detail::centroid::centroid_polygon_state is used as a policy for this
|
Chris@101
|
350 detail::centroid::centroid_multi
|
Chris@101
|
351
|
Chris@101
|
352 */
|
Chris@101
|
353 template <typename Policy>
|
Chris@101
|
354 struct centroid_multi
|
Chris@101
|
355 {
|
Chris@101
|
356 template <typename Multi, typename Point, typename Strategy>
|
Chris@101
|
357 static inline bool apply(Multi const& multi,
|
Chris@101
|
358 Point& centroid,
|
Chris@101
|
359 Strategy const& strategy)
|
Chris@101
|
360 {
|
Chris@101
|
361 #if ! defined(BOOST_GEOMETRY_CENTROID_NO_THROW)
|
Chris@101
|
362 // If there is nothing in any of the ranges, it is not possible
|
Chris@101
|
363 // to calculate the centroid
|
Chris@101
|
364 if (geometry::num_points(multi) == 0)
|
Chris@101
|
365 {
|
Chris@101
|
366 throw centroid_exception();
|
Chris@101
|
367 }
|
Chris@101
|
368 #endif
|
Chris@101
|
369
|
Chris@101
|
370 // prepare translation transformer
|
Chris@101
|
371 translating_transformer<Multi> transformer(multi);
|
Chris@101
|
372
|
Chris@101
|
373 typename Strategy::state_type state;
|
Chris@101
|
374
|
Chris@101
|
375 for (typename boost::range_iterator<Multi const>::type
|
Chris@101
|
376 it = boost::begin(multi);
|
Chris@101
|
377 it != boost::end(multi);
|
Chris@101
|
378 ++it)
|
Chris@101
|
379 {
|
Chris@101
|
380 Policy::apply(*it, transformer, strategy, state);
|
Chris@101
|
381 }
|
Chris@101
|
382
|
Chris@101
|
383 if ( strategy.result(state, centroid) )
|
Chris@101
|
384 {
|
Chris@101
|
385 // translate the result back
|
Chris@101
|
386 transformer.apply_reverse(centroid);
|
Chris@101
|
387 return true;
|
Chris@101
|
388 }
|
Chris@101
|
389
|
Chris@101
|
390 return false;
|
Chris@101
|
391 }
|
Chris@101
|
392 };
|
Chris@101
|
393
|
Chris@101
|
394
|
Chris@101
|
395 template <typename Algorithm>
|
Chris@101
|
396 struct centroid_linear_areal
|
Chris@101
|
397 {
|
Chris@101
|
398 template <typename Geometry, typename Point, typename Strategy>
|
Chris@101
|
399 static inline void apply(Geometry const& geom,
|
Chris@101
|
400 Point& centroid,
|
Chris@101
|
401 Strategy const& strategy)
|
Chris@101
|
402 {
|
Chris@101
|
403 if ( ! Algorithm::apply(geom, centroid, strategy) )
|
Chris@101
|
404 {
|
Chris@101
|
405 geometry::point_on_border(centroid, geom);
|
Chris@16
|
406 }
|
Chris@16
|
407 }
|
Chris@16
|
408 };
|
Chris@16
|
409
|
Chris@16
|
410
|
Chris@16
|
411 }} // namespace detail::centroid
|
Chris@16
|
412 #endif // DOXYGEN_NO_DETAIL
|
Chris@16
|
413
|
Chris@16
|
414
|
Chris@16
|
415 #ifndef DOXYGEN_NO_DISPATCH
|
Chris@16
|
416 namespace dispatch
|
Chris@16
|
417 {
|
Chris@16
|
418
|
Chris@16
|
419 template
|
Chris@16
|
420 <
|
Chris@16
|
421 typename Geometry,
|
Chris@16
|
422 typename Tag = typename tag<Geometry>::type
|
Chris@16
|
423 >
|
Chris@16
|
424 struct centroid: not_implemented<Tag>
|
Chris@16
|
425 {};
|
Chris@16
|
426
|
Chris@16
|
427 template <typename Geometry>
|
Chris@16
|
428 struct centroid<Geometry, point_tag>
|
Chris@16
|
429 : detail::centroid::centroid_point
|
Chris@16
|
430 {};
|
Chris@16
|
431
|
Chris@16
|
432 template <typename Box>
|
Chris@16
|
433 struct centroid<Box, box_tag>
|
Chris@16
|
434 : detail::centroid::centroid_indexed
|
Chris@16
|
435 {};
|
Chris@16
|
436
|
Chris@16
|
437 template <typename Segment>
|
Chris@16
|
438 struct centroid<Segment, segment_tag>
|
Chris@16
|
439 : detail::centroid::centroid_indexed
|
Chris@16
|
440 {};
|
Chris@16
|
441
|
Chris@16
|
442 template <typename Ring>
|
Chris@16
|
443 struct centroid<Ring, ring_tag>
|
Chris@101
|
444 : detail::centroid::centroid_linear_areal
|
Chris@101
|
445 <
|
Chris@101
|
446 detail::centroid::centroid_range<geometry::closure<Ring>::value>
|
Chris@101
|
447 >
|
Chris@16
|
448 {};
|
Chris@16
|
449
|
Chris@16
|
450 template <typename Linestring>
|
Chris@16
|
451 struct centroid<Linestring, linestring_tag>
|
Chris@101
|
452 : detail::centroid::centroid_linear_areal
|
Chris@101
|
453 <
|
Chris@101
|
454 detail::centroid::centroid_range<closed>
|
Chris@101
|
455 >
|
Chris@101
|
456 {};
|
Chris@16
|
457
|
Chris@16
|
458 template <typename Polygon>
|
Chris@16
|
459 struct centroid<Polygon, polygon_tag>
|
Chris@101
|
460 : detail::centroid::centroid_linear_areal
|
Chris@101
|
461 <
|
Chris@101
|
462 detail::centroid::centroid_polygon
|
Chris@101
|
463 >
|
Chris@101
|
464 {};
|
Chris@101
|
465
|
Chris@101
|
466 template <typename MultiLinestring>
|
Chris@101
|
467 struct centroid<MultiLinestring, multi_linestring_tag>
|
Chris@101
|
468 : detail::centroid::centroid_linear_areal
|
Chris@101
|
469 <
|
Chris@101
|
470 detail::centroid::centroid_multi
|
Chris@101
|
471 <
|
Chris@101
|
472 detail::centroid::centroid_range_state<closed>
|
Chris@101
|
473 >
|
Chris@101
|
474 >
|
Chris@101
|
475 {};
|
Chris@101
|
476
|
Chris@101
|
477 template <typename MultiPolygon>
|
Chris@101
|
478 struct centroid<MultiPolygon, multi_polygon_tag>
|
Chris@101
|
479 : detail::centroid::centroid_linear_areal
|
Chris@101
|
480 <
|
Chris@101
|
481 detail::centroid::centroid_multi
|
Chris@101
|
482 <
|
Chris@101
|
483 detail::centroid::centroid_polygon_state
|
Chris@101
|
484 >
|
Chris@101
|
485 >
|
Chris@101
|
486 {};
|
Chris@101
|
487
|
Chris@101
|
488 template <typename MultiPoint>
|
Chris@101
|
489 struct centroid<MultiPoint, multi_point_tag>
|
Chris@101
|
490 : detail::centroid::centroid_multi
|
Chris@101
|
491 <
|
Chris@101
|
492 detail::centroid::centroid_multi_point_state
|
Chris@101
|
493 >
|
Chris@101
|
494 {};
|
Chris@101
|
495
|
Chris@16
|
496
|
Chris@16
|
497 } // namespace dispatch
|
Chris@16
|
498 #endif // DOXYGEN_NO_DISPATCH
|
Chris@16
|
499
|
Chris@16
|
500
|
Chris@101
|
501 namespace resolve_strategy {
|
Chris@101
|
502
|
Chris@101
|
503 template <typename Geometry>
|
Chris@101
|
504 struct centroid
|
Chris@101
|
505 {
|
Chris@101
|
506 template <typename Point, typename Strategy>
|
Chris@101
|
507 static inline void apply(Geometry const& geometry, Point& out, Strategy const& strategy)
|
Chris@101
|
508 {
|
Chris@101
|
509 dispatch::centroid<Geometry>::apply(geometry, out, strategy);
|
Chris@101
|
510 }
|
Chris@101
|
511
|
Chris@101
|
512 template <typename Point>
|
Chris@101
|
513 static inline void apply(Geometry const& geometry, Point& out, default_strategy)
|
Chris@101
|
514 {
|
Chris@101
|
515 typedef typename strategy::centroid::services::default_strategy
|
Chris@101
|
516 <
|
Chris@101
|
517 typename cs_tag<Geometry>::type,
|
Chris@101
|
518 typename tag_cast
|
Chris@101
|
519 <
|
Chris@101
|
520 typename tag<Geometry>::type,
|
Chris@101
|
521 pointlike_tag,
|
Chris@101
|
522 linear_tag,
|
Chris@101
|
523 areal_tag
|
Chris@101
|
524 >::type,
|
Chris@101
|
525 dimension<Geometry>::type::value,
|
Chris@101
|
526 Point,
|
Chris@101
|
527 Geometry
|
Chris@101
|
528 >::type strategy_type;
|
Chris@101
|
529
|
Chris@101
|
530 dispatch::centroid<Geometry>::apply(geometry, out, strategy_type());
|
Chris@101
|
531 }
|
Chris@101
|
532 };
|
Chris@101
|
533
|
Chris@101
|
534 } // namespace resolve_strategy
|
Chris@101
|
535
|
Chris@101
|
536
|
Chris@101
|
537 namespace resolve_variant {
|
Chris@101
|
538
|
Chris@101
|
539 template <typename Geometry>
|
Chris@101
|
540 struct centroid
|
Chris@101
|
541 {
|
Chris@101
|
542 template <typename Point, typename Strategy>
|
Chris@101
|
543 static inline void apply(Geometry const& geometry, Point& out, Strategy const& strategy)
|
Chris@101
|
544 {
|
Chris@101
|
545 concept::check_concepts_and_equal_dimensions<Point, Geometry const>();
|
Chris@101
|
546 resolve_strategy::centroid<Geometry>::apply(geometry, out, strategy);
|
Chris@101
|
547 }
|
Chris@101
|
548 };
|
Chris@101
|
549
|
Chris@101
|
550 template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
|
Chris@101
|
551 struct centroid<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
|
Chris@101
|
552 {
|
Chris@101
|
553 template <typename Point, typename Strategy>
|
Chris@101
|
554 struct visitor: boost::static_visitor<void>
|
Chris@101
|
555 {
|
Chris@101
|
556 Point& m_out;
|
Chris@101
|
557 Strategy const& m_strategy;
|
Chris@101
|
558
|
Chris@101
|
559 visitor(Point& out, Strategy const& strategy)
|
Chris@101
|
560 : m_out(out), m_strategy(strategy)
|
Chris@101
|
561 {}
|
Chris@101
|
562
|
Chris@101
|
563 template <typename Geometry>
|
Chris@101
|
564 void operator()(Geometry const& geometry) const
|
Chris@101
|
565 {
|
Chris@101
|
566 centroid<Geometry>::apply(geometry, m_out, m_strategy);
|
Chris@101
|
567 }
|
Chris@101
|
568 };
|
Chris@101
|
569
|
Chris@101
|
570 template <typename Point, typename Strategy>
|
Chris@101
|
571 static inline void
|
Chris@101
|
572 apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry,
|
Chris@101
|
573 Point& out,
|
Chris@101
|
574 Strategy const& strategy)
|
Chris@101
|
575 {
|
Chris@101
|
576 boost::apply_visitor(visitor<Point, Strategy>(out, strategy), geometry);
|
Chris@101
|
577 }
|
Chris@101
|
578 };
|
Chris@101
|
579
|
Chris@101
|
580 } // namespace resolve_variant
|
Chris@101
|
581
|
Chris@101
|
582
|
Chris@16
|
583 /*!
|
Chris@16
|
584 \brief \brief_calc{centroid} \brief_strategy
|
Chris@16
|
585 \ingroup centroid
|
Chris@16
|
586 \details \details_calc{centroid,geometric center (or: center of mass)}. \details_strategy_reasons
|
Chris@16
|
587 \tparam Geometry \tparam_geometry
|
Chris@16
|
588 \tparam Point \tparam_point
|
Chris@16
|
589 \tparam Strategy \tparam_strategy{Centroid}
|
Chris@16
|
590 \param geometry \param_geometry
|
Chris@16
|
591 \param c \param_point \param_set{centroid}
|
Chris@16
|
592 \param strategy \param_strategy{centroid}
|
Chris@16
|
593
|
Chris@16
|
594 \qbk{distinguish,with strategy}
|
Chris@16
|
595 \qbk{[include reference/algorithms/centroid.qbk]}
|
Chris@16
|
596 \qbk{[include reference/algorithms/centroid_strategies.qbk]}
|
Chris@16
|
597 }
|
Chris@16
|
598
|
Chris@16
|
599 */
|
Chris@16
|
600 template<typename Geometry, typename Point, typename Strategy>
|
Chris@16
|
601 inline void centroid(Geometry const& geometry, Point& c,
|
Chris@16
|
602 Strategy const& strategy)
|
Chris@16
|
603 {
|
Chris@101
|
604 resolve_variant::centroid<Geometry>::apply(geometry, c, strategy);
|
Chris@16
|
605 }
|
Chris@16
|
606
|
Chris@16
|
607
|
Chris@16
|
608 /*!
|
Chris@16
|
609 \brief \brief_calc{centroid}
|
Chris@16
|
610 \ingroup centroid
|
Chris@16
|
611 \details \details_calc{centroid,geometric center (or: center of mass)}. \details_default_strategy
|
Chris@16
|
612 \tparam Geometry \tparam_geometry
|
Chris@16
|
613 \tparam Point \tparam_point
|
Chris@16
|
614 \param geometry \param_geometry
|
Chris@16
|
615 \param c The calculated centroid will be assigned to this point reference
|
Chris@16
|
616
|
Chris@16
|
617 \qbk{[include reference/algorithms/centroid.qbk]}
|
Chris@16
|
618 \qbk{
|
Chris@16
|
619 [heading Example]
|
Chris@16
|
620 [centroid]
|
Chris@16
|
621 [centroid_output]
|
Chris@16
|
622 }
|
Chris@16
|
623 */
|
Chris@16
|
624 template<typename Geometry, typename Point>
|
Chris@16
|
625 inline void centroid(Geometry const& geometry, Point& c)
|
Chris@16
|
626 {
|
Chris@101
|
627 centroid(geometry, c, default_strategy());
|
Chris@16
|
628 }
|
Chris@16
|
629
|
Chris@16
|
630
|
Chris@16
|
631 /*!
|
Chris@16
|
632 \brief \brief_calc{centroid}
|
Chris@16
|
633 \ingroup centroid
|
Chris@16
|
634 \details \details_calc{centroid,geometric center (or: center of mass)}. \details_return{centroid}.
|
Chris@16
|
635 \tparam Point \tparam_point
|
Chris@16
|
636 \tparam Geometry \tparam_geometry
|
Chris@16
|
637 \param geometry \param_geometry
|
Chris@16
|
638 \return \return_calc{centroid}
|
Chris@16
|
639
|
Chris@16
|
640 \qbk{[include reference/algorithms/centroid.qbk]}
|
Chris@16
|
641 */
|
Chris@16
|
642 template<typename Point, typename Geometry>
|
Chris@16
|
643 inline Point return_centroid(Geometry const& geometry)
|
Chris@16
|
644 {
|
Chris@16
|
645 Point c;
|
Chris@16
|
646 centroid(geometry, c);
|
Chris@16
|
647 return c;
|
Chris@16
|
648 }
|
Chris@16
|
649
|
Chris@16
|
650 /*!
|
Chris@16
|
651 \brief \brief_calc{centroid} \brief_strategy
|
Chris@16
|
652 \ingroup centroid
|
Chris@16
|
653 \details \details_calc{centroid,geometric center (or: center of mass)}. \details_return{centroid}. \details_strategy_reasons
|
Chris@16
|
654 \tparam Point \tparam_point
|
Chris@16
|
655 \tparam Geometry \tparam_geometry
|
Chris@16
|
656 \tparam Strategy \tparam_strategy{centroid}
|
Chris@16
|
657 \param geometry \param_geometry
|
Chris@16
|
658 \param strategy \param_strategy{centroid}
|
Chris@16
|
659 \return \return_calc{centroid}
|
Chris@16
|
660
|
Chris@16
|
661 \qbk{distinguish,with strategy}
|
Chris@16
|
662 \qbk{[include reference/algorithms/centroid.qbk]}
|
Chris@16
|
663 \qbk{[include reference/algorithms/centroid_strategies.qbk]}
|
Chris@16
|
664 */
|
Chris@16
|
665 template<typename Point, typename Geometry, typename Strategy>
|
Chris@16
|
666 inline Point return_centroid(Geometry const& geometry, Strategy const& strategy)
|
Chris@16
|
667 {
|
Chris@16
|
668 Point c;
|
Chris@16
|
669 centroid(geometry, c, strategy);
|
Chris@16
|
670 return c;
|
Chris@16
|
671 }
|
Chris@16
|
672
|
Chris@16
|
673
|
Chris@16
|
674 }} // namespace boost::geometry
|
Chris@16
|
675
|
Chris@16
|
676
|
Chris@16
|
677 #endif // BOOST_GEOMETRY_ALGORITHMS_CENTROID_HPP
|