File indexing completed on 2025-01-18 09:35:19
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021 #ifndef BOOST_GEOMETRY_ALGORITHMS_CENTROID_HPP
0022 #define BOOST_GEOMETRY_ALGORITHMS_CENTROID_HPP
0023
0024
0025 #include <cstddef>
0026
0027 #include <boost/core/ignore_unused.hpp>
0028 #include <boost/range/begin.hpp>
0029 #include <boost/range/end.hpp>
0030 #include <boost/range/size.hpp>
0031 #include <boost/throw_exception.hpp>
0032
0033 #include <boost/geometry/core/exception.hpp>
0034 #include <boost/geometry/core/exterior_ring.hpp>
0035 #include <boost/geometry/core/interior_rings.hpp>
0036 #include <boost/geometry/core/tags.hpp>
0037 #include <boost/geometry/core/point_type.hpp>
0038 #include <boost/geometry/core/visit.hpp>
0039
0040 #include <boost/geometry/algorithms/convert.hpp>
0041 #include <boost/geometry/algorithms/detail/centroid/translating_transformer.hpp>
0042 #include <boost/geometry/algorithms/detail/point_on_border.hpp>
0043 #include <boost/geometry/algorithms/is_empty.hpp>
0044 #include <boost/geometry/algorithms/not_implemented.hpp>
0045
0046 #include <boost/geometry/geometries/adapted/boost_variant.hpp> // For backward compatibility
0047 #include <boost/geometry/geometries/concepts/check.hpp>
0048
0049 #include <boost/geometry/strategies/centroid/cartesian.hpp>
0050 #include <boost/geometry/strategies/centroid/geographic.hpp>
0051 #include <boost/geometry/strategies/centroid/spherical.hpp>
0052 #include <boost/geometry/strategies/concepts/centroid_concept.hpp>
0053 #include <boost/geometry/strategies/default_strategy.hpp>
0054 #include <boost/geometry/strategies/detail.hpp>
0055
0056 #include <boost/geometry/util/algorithm.hpp>
0057 #include <boost/geometry/util/select_coordinate_type.hpp>
0058 #include <boost/geometry/util/type_traits_std.hpp>
0059
0060 #include <boost/geometry/views/closeable_view.hpp>
0061
0062
0063 namespace boost { namespace geometry
0064 {
0065
0066
0067 #if ! defined(BOOST_GEOMETRY_CENTROID_NO_THROW)
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081 class centroid_exception : public geometry::exception
0082 {
0083 public:
0084
0085 inline centroid_exception() {}
0086
0087 char const* what() const noexcept override
0088 {
0089 return "Boost.Geometry Centroid calculation exception";
0090 }
0091 };
0092
0093 #endif
0094
0095
0096 #ifndef DOXYGEN_NO_DETAIL
0097 namespace detail { namespace centroid
0098 {
0099
0100 struct centroid_point
0101 {
0102 template<typename Point, typename PointCentroid, typename Strategy>
0103 static inline void apply(Point const& point, PointCentroid& centroid,
0104 Strategy const&)
0105 {
0106 geometry::convert(point, centroid);
0107 }
0108 };
0109
0110 struct centroid_indexed
0111 {
0112 template<typename Indexed, typename Point, typename Strategy>
0113 static inline void apply(Indexed const& indexed, Point& centroid,
0114 Strategy const&)
0115 {
0116 typedef typename select_coordinate_type
0117 <
0118 Indexed, Point
0119 >::type coordinate_type;
0120
0121 detail::for_each_dimension<Indexed>([&](auto dimension)
0122 {
0123 coordinate_type const c1 = get<min_corner, dimension>(indexed);
0124 coordinate_type const c2 = get<max_corner, dimension>(indexed);
0125 coordinate_type const two = 2;
0126 set<dimension>(centroid, (c1 + c2) / two);
0127 });
0128 }
0129 };
0130
0131
0132
0133
0134
0135 template<typename Point, typename Range>
0136 inline bool range_ok(Range const& range, Point& centroid)
0137 {
0138 std::size_t const n = boost::size(range);
0139 if (n > 1)
0140 {
0141 return true;
0142 }
0143 else if (n <= 0)
0144 {
0145 #if ! defined(BOOST_GEOMETRY_CENTROID_NO_THROW)
0146 BOOST_THROW_EXCEPTION(centroid_exception());
0147 #else
0148 return false;
0149 #endif
0150 }
0151 else
0152 {
0153
0154 geometry::convert(*boost::begin(range), centroid);
0155 return false;
0156 }
0157
0158 }
0159
0160
0161
0162
0163 struct centroid_range_state
0164 {
0165 template<typename Ring, typename PointTransformer, typename Strategy, typename State>
0166 static inline void apply(Ring const& ring,
0167 PointTransformer const& transformer,
0168 Strategy const& strategy,
0169 State& state)
0170 {
0171 boost::ignore_unused(strategy);
0172
0173 detail::closed_view<Ring const> const view(ring);
0174 auto it = boost::begin(view);
0175 auto const end = boost::end(view);
0176
0177 if (it != end)
0178 {
0179 typename PointTransformer::result_type
0180 previous_pt = transformer.apply(*it);
0181
0182 for ( ++it ; it != end ; ++it)
0183 {
0184 typename PointTransformer::result_type
0185 pt = transformer.apply(*it);
0186
0187 using point_type = typename geometry::point_type<Ring const>::type;
0188 strategy.apply(static_cast<point_type const&>(previous_pt),
0189 static_cast<point_type const&>(pt),
0190 state);
0191
0192 previous_pt = pt;
0193 }
0194 }
0195 }
0196 };
0197
0198 struct centroid_range
0199 {
0200 template<typename Range, typename Point, typename Strategy>
0201 static inline bool apply(Range const& range, Point& centroid,
0202 Strategy const& strategy)
0203 {
0204 if (range_ok(range, centroid))
0205 {
0206
0207 translating_transformer<Range> transformer(*boost::begin(range));
0208
0209 typename Strategy::template state_type
0210 <
0211 typename geometry::point_type<Range>::type,
0212 Point
0213 >::type state;
0214
0215 centroid_range_state::apply(range, transformer, strategy, state);
0216
0217 if ( strategy.result(state, centroid) )
0218 {
0219
0220 transformer.apply_reverse(centroid);
0221 return true;
0222 }
0223 }
0224
0225 return false;
0226 }
0227 };
0228
0229
0230
0231
0232
0233
0234
0235 struct centroid_polygon_state
0236 {
0237 template<typename Polygon, typename PointTransformer, typename Strategy, typename State>
0238 static inline void apply(Polygon const& poly,
0239 PointTransformer const& transformer,
0240 Strategy const& strategy,
0241 State& state)
0242 {
0243 centroid_range_state::apply(exterior_ring(poly), transformer, strategy, state);
0244
0245 auto const& rings = interior_rings(poly);
0246 auto const end = boost::end(rings);
0247 for (auto it = boost::begin(rings); it != end; ++it)
0248 {
0249 centroid_range_state::apply(*it, transformer, strategy, state);
0250 }
0251 }
0252 };
0253
0254 struct centroid_polygon
0255 {
0256 template<typename Polygon, typename Point, typename Strategy>
0257 static inline bool apply(Polygon const& poly, Point& centroid,
0258 Strategy const& strategy)
0259 {
0260 if (range_ok(exterior_ring(poly), centroid))
0261 {
0262
0263 translating_transformer<Polygon>
0264 transformer(*boost::begin(exterior_ring(poly)));
0265
0266 typename Strategy::template state_type
0267 <
0268 typename geometry::point_type<Polygon>::type,
0269 Point
0270 >::type state;
0271
0272 centroid_polygon_state::apply(poly, transformer, strategy, state);
0273
0274 if ( strategy.result(state, centroid) )
0275 {
0276
0277 transformer.apply_reverse(centroid);
0278 return true;
0279 }
0280 }
0281
0282 return false;
0283 }
0284 };
0285
0286
0287
0288
0289
0290
0291 struct centroid_multi_point_state
0292 {
0293 template <typename Point, typename PointTransformer, typename Strategy, typename State>
0294 static inline void apply(Point const& point,
0295 PointTransformer const& transformer,
0296 Strategy const& strategy,
0297 State& state)
0298 {
0299 boost::ignore_unused(strategy);
0300 strategy.apply(static_cast<Point const&>(transformer.apply(point)),
0301 state);
0302 }
0303 };
0304
0305
0306
0307
0308
0309
0310
0311
0312
0313
0314 template <typename Policy>
0315 struct centroid_multi
0316 {
0317 template <typename Multi, typename Point, typename Strategy>
0318 static inline bool apply(Multi const& multi,
0319 Point& centroid,
0320 Strategy const& strategy)
0321 {
0322 #if ! defined(BOOST_GEOMETRY_CENTROID_NO_THROW)
0323
0324
0325 if (geometry::is_empty(multi))
0326 {
0327 BOOST_THROW_EXCEPTION(centroid_exception());
0328 }
0329 #endif
0330
0331
0332 translating_transformer<Multi> transformer(multi);
0333
0334 typename Strategy::template state_type
0335 <
0336 typename geometry::point_type<Multi>::type,
0337 Point
0338 >::type state;
0339
0340 for (auto it = boost::begin(multi); it != boost::end(multi); ++it)
0341 {
0342 Policy::apply(*it, transformer, strategy, state);
0343 }
0344
0345 if (strategy.result(state, centroid))
0346 {
0347
0348 transformer.apply_reverse(centroid);
0349 return true;
0350 }
0351
0352 return false;
0353 }
0354 };
0355
0356
0357 template <typename Algorithm>
0358 struct centroid_linear_areal
0359 {
0360 template <typename Geometry, typename Point, typename Strategies>
0361 static inline void apply(Geometry const& geom,
0362 Point& centroid,
0363 Strategies const& strategies)
0364 {
0365 if ( ! Algorithm::apply(geom, centroid, strategies.centroid(geom)) )
0366 {
0367 geometry::point_on_border(centroid, geom);
0368 }
0369 }
0370 };
0371
0372 template <typename Algorithm>
0373 struct centroid_pointlike
0374 {
0375 template <typename Geometry, typename Point, typename Strategies>
0376 static inline void apply(Geometry const& geom,
0377 Point& centroid,
0378 Strategies const& strategies)
0379 {
0380 Algorithm::apply(geom, centroid, strategies.centroid(geom));
0381 }
0382 };
0383
0384
0385 }}
0386 #endif
0387
0388
0389 #ifndef DOXYGEN_NO_DISPATCH
0390 namespace dispatch
0391 {
0392
0393 template
0394 <
0395 typename Geometry,
0396 typename Tag = typename tag<Geometry>::type
0397 >
0398 struct centroid: not_implemented<Tag>
0399 {};
0400
0401 template <typename Geometry>
0402 struct centroid<Geometry, point_tag>
0403 : detail::centroid::centroid_point
0404 {};
0405
0406 template <typename Box>
0407 struct centroid<Box, box_tag>
0408 : detail::centroid::centroid_indexed
0409 {};
0410
0411 template <typename Segment>
0412 struct centroid<Segment, segment_tag>
0413 : detail::centroid::centroid_indexed
0414 {};
0415
0416 template <typename Ring>
0417 struct centroid<Ring, ring_tag>
0418 : detail::centroid::centroid_linear_areal
0419 <
0420 detail::centroid::centroid_range
0421 >
0422 {};
0423
0424 template <typename Linestring>
0425 struct centroid<Linestring, linestring_tag>
0426 : detail::centroid::centroid_linear_areal
0427 <
0428 detail::centroid::centroid_range
0429 >
0430 {};
0431
0432 template <typename Polygon>
0433 struct centroid<Polygon, polygon_tag>
0434 : detail::centroid::centroid_linear_areal
0435 <
0436 detail::centroid::centroid_polygon
0437 >
0438 {};
0439
0440 template <typename MultiLinestring>
0441 struct centroid<MultiLinestring, multi_linestring_tag>
0442 : detail::centroid::centroid_linear_areal
0443 <
0444 detail::centroid::centroid_multi
0445 <
0446 detail::centroid::centroid_range_state
0447 >
0448 >
0449 {};
0450
0451 template <typename MultiPolygon>
0452 struct centroid<MultiPolygon, multi_polygon_tag>
0453 : detail::centroid::centroid_linear_areal
0454 <
0455 detail::centroid::centroid_multi
0456 <
0457 detail::centroid::centroid_polygon_state
0458 >
0459 >
0460 {};
0461
0462 template <typename MultiPoint>
0463 struct centroid<MultiPoint, multi_point_tag>
0464 : detail::centroid::centroid_pointlike
0465 <
0466 detail::centroid::centroid_multi
0467 <
0468 detail::centroid::centroid_multi_point_state
0469 >
0470 >
0471 {};
0472
0473
0474 }
0475 #endif
0476
0477
0478 namespace resolve_strategy {
0479
0480 template
0481 <
0482 typename Strategies,
0483 bool IsUmbrella = strategies::detail::is_umbrella_strategy<Strategies>::value
0484 >
0485 struct centroid
0486 {
0487 template <typename Geometry, typename Point>
0488 static inline void apply(Geometry const& geometry, Point& out, Strategies const& strategies)
0489 {
0490 dispatch::centroid<Geometry>::apply(geometry, out, strategies);
0491 }
0492 };
0493
0494 template <typename Strategy>
0495 struct centroid<Strategy, false>
0496 {
0497 template <typename Geometry, typename Point>
0498 static inline void apply(Geometry const& geometry, Point& out, Strategy const& strategy)
0499 {
0500 using strategies::centroid::services::strategy_converter;
0501 dispatch::centroid
0502 <
0503 Geometry
0504 >::apply(geometry, out, strategy_converter<Strategy>::get(strategy));
0505 }
0506 };
0507
0508 template <>
0509 struct centroid<default_strategy, false>
0510 {
0511 template <typename Geometry, typename Point>
0512 static inline void apply(Geometry const& geometry, Point& out, default_strategy)
0513 {
0514 typedef typename strategies::centroid::services::default_strategy
0515 <
0516 Geometry
0517 >::type strategies_type;
0518
0519 dispatch::centroid<Geometry>::apply(geometry, out, strategies_type());
0520 }
0521 };
0522
0523 }
0524
0525
0526 namespace resolve_dynamic {
0527
0528 template <typename Geometry, typename Tag = typename tag<Geometry>::type>
0529 struct centroid
0530 {
0531 template <typename Point, typename Strategy>
0532 static inline void apply(Geometry const& geometry, Point& out, Strategy const& strategy)
0533 {
0534 concepts::check_concepts_and_equal_dimensions<Point, Geometry const>();
0535 resolve_strategy::centroid<Strategy>::apply(geometry, out, strategy);
0536 }
0537 };
0538
0539 template <typename Geometry>
0540 struct centroid<Geometry, dynamic_geometry_tag>
0541 {
0542 template <typename Point, typename Strategy>
0543 static inline void apply(Geometry const& geometry,
0544 Point& out,
0545 Strategy const& strategy)
0546 {
0547 traits::visit<Geometry>::apply([&](auto const& g)
0548 {
0549 centroid<util::remove_cref_t<decltype(g)>>::apply(g, out, strategy);
0550 }, geometry);
0551 }
0552 };
0553
0554 }
0555
0556
0557
0558
0559
0560
0561
0562
0563
0564
0565
0566
0567
0568
0569
0570
0571
0572
0573
0574 template<typename Geometry, typename Point, typename Strategy>
0575 inline void centroid(Geometry const& geometry, Point& c, Strategy const& strategy)
0576 {
0577 resolve_dynamic::centroid<Geometry>::apply(geometry, c, strategy);
0578 }
0579
0580
0581
0582
0583
0584
0585
0586
0587
0588
0589
0590
0591
0592
0593
0594
0595
0596
0597 template<typename Geometry, typename Point>
0598 inline void centroid(Geometry const& geometry, Point& c)
0599 {
0600 geometry::centroid(geometry, c, default_strategy());
0601 }
0602
0603
0604
0605
0606
0607
0608
0609
0610
0611
0612
0613
0614
0615 template<typename Point, typename Geometry>
0616 inline Point return_centroid(Geometry const& geometry)
0617 {
0618 Point c;
0619 geometry::centroid(geometry, c);
0620 return c;
0621 }
0622
0623
0624
0625
0626
0627
0628
0629
0630
0631
0632
0633
0634
0635
0636
0637
0638 template<typename Point, typename Geometry, typename Strategy>
0639 inline Point return_centroid(Geometry const& geometry, Strategy const& strategy)
0640 {
0641 Point c;
0642 geometry::centroid(geometry, c, strategy);
0643 return c;
0644 }
0645
0646
0647 }}
0648
0649
0650 #endif