File indexing completed on 2025-01-18 09:35:03
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022 #ifndef BOOST_GEOMETRY_ALGORITHMS_CONVEX_HULL_INTERFACE_HPP
0023 #define BOOST_GEOMETRY_ALGORITHMS_CONVEX_HULL_INTERFACE_HPP
0024
0025 #include <array>
0026
0027 #include <boost/range/size.hpp>
0028
0029 #include <boost/geometry/algorithms/detail/assign_box_corners.hpp>
0030 #include <boost/geometry/algorithms/detail/convex_hull/graham_andrew.hpp>
0031 #include <boost/geometry/algorithms/detail/equals/point_point.hpp>
0032 #include <boost/geometry/algorithms/detail/for_each_range.hpp>
0033 #include <boost/geometry/algorithms/detail/select_geometry_type.hpp>
0034 #include <boost/geometry/algorithms/detail/visit.hpp>
0035 #include <boost/geometry/algorithms/is_empty.hpp>
0036
0037 #include <boost/geometry/core/closure.hpp>
0038 #include <boost/geometry/core/cs.hpp>
0039 #include <boost/geometry/core/exterior_ring.hpp>
0040 #include <boost/geometry/core/geometry_types.hpp>
0041 #include <boost/geometry/core/point_order.hpp>
0042 #include <boost/geometry/core/ring_type.hpp>
0043 #include <boost/geometry/core/tag.hpp>
0044 #include <boost/geometry/core/tags.hpp>
0045 #include <boost/geometry/core/visit.hpp>
0046
0047 #include <boost/geometry/geometries/adapted/boost_variant.hpp> // For backward compatibility
0048 #include <boost/geometry/geometries/concepts/check.hpp>
0049 #include <boost/geometry/geometries/ring.hpp>
0050
0051 #include <boost/geometry/strategies/convex_hull/cartesian.hpp>
0052 #include <boost/geometry/strategies/convex_hull/geographic.hpp>
0053 #include <boost/geometry/strategies/convex_hull/spherical.hpp>
0054 #include <boost/geometry/strategies/default_strategy.hpp>
0055
0056 #include <boost/geometry/util/condition.hpp>
0057 #include <boost/geometry/util/range.hpp>
0058 #include <boost/geometry/util/sequence.hpp>
0059 #include <boost/geometry/util/type_traits.hpp>
0060
0061
0062 namespace boost { namespace geometry
0063 {
0064
0065
0066
0067
0068 #ifndef DOXYGEN_NO_DETAIL
0069 namespace detail { namespace convex_hull
0070 {
0071
0072
0073 template <typename Geometry>
0074 struct input_geometry_proxy
0075 {
0076 input_geometry_proxy(Geometry const& geometry)
0077 : m_geometry(geometry)
0078 {}
0079
0080 template <typename UnaryFunction>
0081 inline void for_each_range(UnaryFunction fun) const
0082 {
0083 geometry::detail::for_each_range(m_geometry, fun);
0084 }
0085
0086 Geometry const& m_geometry;
0087 };
0088
0089
0090
0091 template <typename Geometry, typename BoxRings>
0092 struct input_geometry_collection_proxy
0093 {
0094 input_geometry_collection_proxy(Geometry const& geometry, BoxRings const& box_rings)
0095 : m_geometry(geometry)
0096 , m_box_rings(box_rings)
0097 {}
0098
0099 template <typename UnaryFunction>
0100 inline void for_each_range(UnaryFunction fun) const
0101 {
0102 detail::visit_breadth_first([&](auto const& g)
0103 {
0104 input_geometry_collection_proxy::call_for_non_boxes(g, fun);
0105 return true;
0106 }, m_geometry);
0107
0108 for (auto const& r : m_box_rings)
0109 {
0110 geometry::detail::for_each_range(r, fun);
0111 }
0112 }
0113
0114 private:
0115 template <typename G, typename F, std::enable_if_t<! util::is_box<G>::value, int> = 0>
0116 static inline void call_for_non_boxes(G const& g, F & f)
0117 {
0118 geometry::detail::for_each_range(g, f);
0119 }
0120 template <typename G, typename F, std::enable_if_t<util::is_box<G>::value, int> = 0>
0121 static inline void call_for_non_boxes(G const&, F &)
0122 {}
0123
0124 Geometry const& m_geometry;
0125 BoxRings const& m_box_rings;
0126 };
0127
0128
0129
0130
0131 template <typename Geometry, typename Tag = typename tag<Geometry>::type>
0132 struct default_strategy
0133 {
0134 using type = typename strategies::convex_hull::services::default_strategy
0135 <
0136 Geometry
0137 >::type;
0138 };
0139
0140 template <typename Geometry>
0141 struct default_strategy<Geometry, geometry_collection_tag>
0142 : default_strategy<typename detail::first_geometry_type<Geometry>::type>
0143 {};
0144
0145
0146
0147 template <typename G1, typename G2>
0148 struct output_polygonal_less
0149 {
0150 template <typename G>
0151 using priority = std::integral_constant
0152 <
0153 int,
0154 (util::is_ring<G>::value ? 0 :
0155 util::is_polygon<G>::value ? 1 :
0156 util::is_multi_polygon<G>::value ? 2 : 3)
0157 >;
0158
0159 static const bool value = priority<G1>::value < priority<G2>::value;
0160 };
0161
0162 template <typename G1, typename G2>
0163 struct output_linear_less
0164 {
0165 template <typename G>
0166 using priority = std::integral_constant
0167 <
0168 int,
0169 (util::is_segment<G>::value ? 0 :
0170 util::is_linestring<G>::value ? 1 :
0171 util::is_multi_linestring<G>::value ? 2 : 3)
0172 >;
0173
0174 static const bool value = priority<G1>::value < priority<G2>::value;
0175 };
0176
0177 template <typename G1, typename G2>
0178 struct output_pointlike_less
0179 {
0180 template <typename G>
0181 using priority = std::integral_constant
0182 <
0183 int,
0184 (util::is_point<G>::value ? 0 :
0185 util::is_multi_point<G>::value ? 1 : 2)
0186 >;
0187
0188 static const bool value = priority<G1>::value < priority<G2>::value;
0189 };
0190
0191
0192 }}
0193 #endif
0194
0195
0196 #ifndef DOXYGEN_NO_DISPATCH
0197 namespace dispatch
0198 {
0199
0200
0201 template
0202 <
0203 typename Geometry,
0204 typename Tag = typename tag<Geometry>::type
0205 >
0206 struct convex_hull
0207 {
0208 template <typename OutputGeometry, typename Strategy>
0209 static inline void apply(Geometry const& geometry,
0210 OutputGeometry& out,
0211 Strategy const& strategy)
0212 {
0213 detail::convex_hull::input_geometry_proxy<Geometry> in_proxy(geometry);
0214 detail::convex_hull::graham_andrew
0215 <
0216 typename point_type<Geometry>::type
0217 >::apply(in_proxy, out, strategy);
0218 }
0219 };
0220
0221
0222
0223
0224 template <typename Box>
0225 struct convex_hull<Box, box_tag>
0226 {
0227 template <typename OutputGeometry, typename Strategy>
0228 static inline void apply(Box const& box,
0229 OutputGeometry& out,
0230 Strategy const& )
0231 {
0232 static bool const Close
0233 = geometry::closure<OutputGeometry>::value == closed;
0234 static bool const Reverse
0235 = geometry::point_order<OutputGeometry>::value == counterclockwise;
0236
0237 std::array<typename point_type<OutputGeometry>::type, 4> arr;
0238
0239
0240 geometry::detail::assign_box_corners_oriented<Reverse>(box, arr);
0241
0242 std::move(arr.begin(), arr.end(), range::back_inserter(out));
0243 if (BOOST_GEOMETRY_CONDITION(Close))
0244 {
0245 range::push_back(out, range::front(out));
0246 }
0247 }
0248 };
0249
0250
0251 template <typename GeometryCollection>
0252 struct convex_hull<GeometryCollection, geometry_collection_tag>
0253 {
0254 template <typename OutputGeometry, typename Strategy>
0255 static inline void apply(GeometryCollection const& geometry,
0256 OutputGeometry& out,
0257 Strategy const& strategy)
0258 {
0259
0260 using subgeometry_type = typename detail::first_geometry_type<GeometryCollection>::type;
0261 using point_type = typename geometry::point_type<subgeometry_type>::type;
0262 using ring_type = model::ring<point_type, true, false>;
0263
0264
0265 std::vector<ring_type> box_rings;
0266 detail::visit_breadth_first([&](auto const& g)
0267 {
0268 convex_hull::add_ring_for_box(box_rings, g, strategy);
0269 return true;
0270 }, geometry);
0271
0272 detail::convex_hull::input_geometry_collection_proxy
0273 <
0274 GeometryCollection, std::vector<ring_type>
0275 > in_proxy(geometry, box_rings);
0276
0277 detail::convex_hull::graham_andrew
0278 <
0279 point_type
0280 >::apply(in_proxy, out, strategy);
0281 }
0282
0283 private:
0284 template
0285 <
0286 typename Ring, typename SubGeometry, typename Strategy,
0287 std::enable_if_t<util::is_box<SubGeometry>::value, int> = 0
0288 >
0289 static inline void add_ring_for_box(std::vector<Ring> & rings, SubGeometry const& box,
0290 Strategy const& strategy)
0291 {
0292 Ring ring;
0293 convex_hull<SubGeometry>::apply(box, ring, strategy);
0294 rings.push_back(std::move(ring));
0295 }
0296 template
0297 <
0298 typename Ring, typename SubGeometry, typename Strategy,
0299 std::enable_if_t<! util::is_box<SubGeometry>::value, int> = 0
0300 >
0301 static inline void add_ring_for_box(std::vector<Ring> & , SubGeometry const& ,
0302 Strategy const& )
0303 {}
0304 };
0305
0306
0307 template <typename OutputGeometry, typename Tag = typename tag<OutputGeometry>::type>
0308 struct convex_hull_out
0309 {
0310 BOOST_GEOMETRY_STATIC_ASSERT_FALSE("This OutputGeometry is not supported.", OutputGeometry, Tag);
0311 };
0312
0313 template <typename OutputGeometry>
0314 struct convex_hull_out<OutputGeometry, ring_tag>
0315 {
0316 template <typename Geometry, typename Strategies>
0317 static inline void apply(Geometry const& geometry,
0318 OutputGeometry& out,
0319 Strategies const& strategies)
0320 {
0321 dispatch::convex_hull<Geometry>::apply(geometry, out, strategies);
0322 }
0323 };
0324
0325 template <typename OutputGeometry>
0326 struct convex_hull_out<OutputGeometry, polygon_tag>
0327 {
0328 template <typename Geometry, typename Strategies>
0329 static inline void apply(Geometry const& geometry,
0330 OutputGeometry& out,
0331 Strategies const& strategies)
0332 {
0333 auto&& ring = exterior_ring(out);
0334 dispatch::convex_hull<Geometry>::apply(geometry, ring, strategies);
0335 }
0336 };
0337
0338 template <typename OutputGeometry>
0339 struct convex_hull_out<OutputGeometry, multi_polygon_tag>
0340 {
0341 template <typename Geometry, typename Strategies>
0342 static inline void apply(Geometry const& geometry,
0343 OutputGeometry& out,
0344 Strategies const& strategies)
0345 {
0346 typename boost::range_value<OutputGeometry>::type polygon;
0347 auto&& ring = exterior_ring(polygon);
0348 dispatch::convex_hull<Geometry>::apply(geometry, ring, strategies);
0349
0350 range::push_back(out, std::move(polygon));
0351 }
0352 };
0353
0354 template <typename OutputGeometry>
0355 struct convex_hull_out<OutputGeometry, geometry_collection_tag>
0356 {
0357 using polygonal_t = typename util::sequence_min_element
0358 <
0359 typename traits::geometry_types<OutputGeometry>::type,
0360 detail::convex_hull::output_polygonal_less
0361 >::type;
0362 using linear_t = typename util::sequence_min_element
0363 <
0364 typename traits::geometry_types<OutputGeometry>::type,
0365 detail::convex_hull::output_linear_less
0366 >::type;
0367 using pointlike_t = typename util::sequence_min_element
0368 <
0369 typename traits::geometry_types<OutputGeometry>::type,
0370 detail::convex_hull::output_pointlike_less
0371 >::type;
0372
0373
0374 BOOST_GEOMETRY_STATIC_ASSERT(util::is_polygonal<polygonal_t>::value,
0375 "It must be possible to store polygonal geometry in OutputGeometry.", polygonal_t);
0376 BOOST_GEOMETRY_STATIC_ASSERT(util::is_linear<linear_t>::value,
0377 "It must be possible to store linear geometry in OutputGeometry.", linear_t);
0378 BOOST_GEOMETRY_STATIC_ASSERT(util::is_pointlike<pointlike_t>::value,
0379 "It must be possible to store pointlike geometry in OutputGeometry.", pointlike_t);
0380
0381 template <typename Geometry, typename Strategies>
0382 static inline void apply(Geometry const& geometry,
0383 OutputGeometry& out,
0384 Strategies const& strategies)
0385 {
0386 polygonal_t polygonal;
0387 convex_hull_out<polygonal_t>::apply(geometry, polygonal, strategies);
0388
0389 auto&& out_ring = ring(polygonal);
0390
0391 if (boost::size(out_ring) == detail::minimum_ring_size<polygonal_t>::value)
0392 {
0393 using detail::equals::equals_point_point;
0394 if (equals_point_point(range::front(out_ring), range::at(out_ring, 1), strategies))
0395 {
0396 pointlike_t pointlike;
0397 move_to_pointlike(out_ring, pointlike);
0398 move_to_out(pointlike, out);
0399 return;
0400 }
0401 if (equals_point_point(range::front(out_ring), range::at(out_ring, 2), strategies))
0402 {
0403 linear_t linear;
0404 move_to_linear(out_ring, linear);
0405 move_to_out(linear, out);
0406 return;
0407 }
0408 }
0409
0410 move_to_out(polygonal, out);
0411 }
0412
0413 private:
0414 template <typename Polygonal, util::enable_if_ring_t<Polygonal, int> = 0>
0415 static decltype(auto) ring(Polygonal const& polygonal)
0416 {
0417 return polygonal;
0418 }
0419 template <typename Polygonal, util::enable_if_polygon_t<Polygonal, int> = 0>
0420 static decltype(auto) ring(Polygonal const& polygonal)
0421 {
0422 return exterior_ring(polygonal);
0423 }
0424 template <typename Polygonal, util::enable_if_multi_polygon_t<Polygonal, int> = 0>
0425 static decltype(auto) ring(Polygonal const& polygonal)
0426 {
0427 return exterior_ring(range::front(polygonal));
0428 }
0429
0430 template <typename Range, typename Linear, util::enable_if_segment_t<Linear, int> = 0>
0431 static void move_to_linear(Range & out_range, Linear & seg)
0432 {
0433 detail::assign_point_to_index<0>(range::front(out_range), seg);
0434 detail::assign_point_to_index<1>(range::at(out_range, 1), seg);
0435 }
0436 template <typename Range, typename Linear, util::enable_if_linestring_t<Linear, int> = 0>
0437 static void move_to_linear(Range & out_range, Linear & ls)
0438 {
0439 std::move(boost::begin(out_range), boost::begin(out_range) + 2, range::back_inserter(ls));
0440 }
0441 template <typename Range, typename Linear, util::enable_if_multi_linestring_t<Linear, int> = 0>
0442 static void move_to_linear(Range & out_range, Linear & mls)
0443 {
0444 typename boost::range_value<Linear>::type ls;
0445 std::move(boost::begin(out_range), boost::begin(out_range) + 2, range::back_inserter(ls));
0446 range::push_back(mls, std::move(ls));
0447 }
0448
0449 template <typename Range, typename PointLike, util::enable_if_point_t<PointLike, int> = 0>
0450 static void move_to_pointlike(Range & out_range, PointLike & pt)
0451 {
0452 pt = range::front(out_range);
0453 }
0454 template <typename Range, typename PointLike, util::enable_if_multi_point_t<PointLike, int> = 0>
0455 static void move_to_pointlike(Range & out_range, PointLike & mpt)
0456 {
0457 range::push_back(mpt, std::move(range::front(out_range)));
0458 }
0459
0460 template
0461 <
0462 typename Geometry, typename OutputGeometry_,
0463 util::enable_if_geometry_collection_t<OutputGeometry_, int> = 0
0464 >
0465 static void move_to_out(Geometry & g, OutputGeometry_ & out)
0466 {
0467 range::emplace_back(out, std::move(g));
0468 }
0469 template
0470 <
0471 typename Geometry, typename OutputGeometry_,
0472 util::enable_if_dynamic_geometry_t<OutputGeometry_, int> = 0
0473 >
0474 static void move_to_out(Geometry & g, OutputGeometry_ & out)
0475 {
0476 out = std::move(g);
0477 }
0478 };
0479
0480 template <typename OutputGeometry>
0481 struct convex_hull_out<OutputGeometry, dynamic_geometry_tag>
0482 : convex_hull_out<OutputGeometry, geometry_collection_tag>
0483 {};
0484
0485
0486
0487 template <typename OutputGeometry>
0488 struct convex_hull_out<OutputGeometry, linestring_tag>
0489 : convex_hull_out<OutputGeometry, ring_tag>
0490 {};
0491
0492
0493 }
0494 #endif
0495
0496
0497 namespace resolve_strategy {
0498
0499 template <typename Strategies>
0500 struct convex_hull
0501 {
0502 template <typename Geometry, typename OutputGeometry>
0503 static inline void apply(Geometry const& geometry,
0504 OutputGeometry& out,
0505 Strategies const& strategies)
0506 {
0507 dispatch::convex_hull_out<OutputGeometry>::apply(geometry, out, strategies);
0508 }
0509 };
0510
0511 template <>
0512 struct convex_hull<default_strategy>
0513 {
0514 template <typename Geometry, typename OutputGeometry>
0515 static inline void apply(Geometry const& geometry,
0516 OutputGeometry& out,
0517 default_strategy const&)
0518 {
0519 using strategy_type = typename detail::convex_hull::default_strategy
0520 <
0521 Geometry
0522 >::type;
0523
0524 dispatch::convex_hull_out<OutputGeometry>::apply(geometry, out, strategy_type());
0525 }
0526 };
0527
0528
0529 }
0530
0531
0532 namespace resolve_dynamic {
0533
0534 template <typename Geometry, typename Tag = typename tag<Geometry>::type>
0535 struct convex_hull
0536 {
0537 template <typename OutputGeometry, typename Strategy>
0538 static inline void apply(Geometry const& geometry,
0539 OutputGeometry& out,
0540 Strategy const& strategy)
0541 {
0542 concepts::check_concepts_and_equal_dimensions<
0543 const Geometry,
0544 OutputGeometry
0545 >();
0546
0547 resolve_strategy::convex_hull<Strategy>::apply(geometry, out, strategy);
0548 }
0549 };
0550
0551 template <typename Geometry>
0552 struct convex_hull<Geometry, dynamic_geometry_tag>
0553 {
0554 template <typename OutputGeometry, typename Strategy>
0555 static inline void apply(Geometry const& geometry,
0556 OutputGeometry& out,
0557 Strategy const& strategy)
0558 {
0559 traits::visit<Geometry>::apply([&](auto const& g)
0560 {
0561 convex_hull<util::remove_cref_t<decltype(g)>>::apply(g, out, strategy);
0562 }, geometry);
0563 }
0564 };
0565
0566
0567 }
0568
0569
0570
0571
0572
0573
0574
0575
0576
0577
0578
0579
0580
0581
0582
0583
0584
0585 template<typename Geometry, typename OutputGeometry, typename Strategy>
0586 inline void convex_hull(Geometry const& geometry, OutputGeometry& out, Strategy const& strategy)
0587 {
0588 if (geometry::is_empty(geometry))
0589 {
0590
0591 return;
0592 }
0593
0594 resolve_dynamic::convex_hull<Geometry>::apply(geometry, out, strategy);
0595 }
0596
0597
0598
0599
0600
0601
0602
0603
0604
0605
0606
0607
0608
0609 template<typename Geometry, typename OutputGeometry>
0610 inline void convex_hull(Geometry const& geometry, OutputGeometry& hull)
0611 {
0612 geometry::convex_hull(geometry, hull, default_strategy());
0613 }
0614
0615
0616 }}
0617
0618
0619 #endif