File indexing completed on 2025-01-18 09:35:18
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017 #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXTREME_POINTS_HPP
0018 #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXTREME_POINTS_HPP
0019
0020
0021 #include <cstddef>
0022
0023 #include <boost/range/begin.hpp>
0024 #include <boost/range/end.hpp>
0025 #include <boost/range/size.hpp>
0026 #include <boost/range/value_type.hpp>
0027
0028 #include <boost/geometry/algorithms/detail/assign_box_corners.hpp>
0029
0030 #include <boost/geometry/arithmetic/arithmetic.hpp>
0031
0032 #include <boost/geometry/core/cs.hpp>
0033 #include <boost/geometry/core/point_order.hpp>
0034 #include <boost/geometry/core/point_type.hpp>
0035 #include <boost/geometry/core/ring_type.hpp>
0036 #include <boost/geometry/core/tags.hpp>
0037
0038 #include <boost/geometry/geometries/concepts/check.hpp>
0039 #include <boost/geometry/iterators/ever_circling_iterator.hpp>
0040
0041 #include <boost/geometry/strategies/side.hpp>
0042
0043 #include <boost/geometry/util/math.hpp>
0044
0045
0046 namespace boost { namespace geometry
0047 {
0048
0049
0050 #ifndef DOXYGEN_NO_DETAIL
0051 namespace detail { namespace extreme_points
0052 {
0053
0054 template <std::size_t Dimension>
0055 struct compare
0056 {
0057 template <typename Point>
0058 inline bool operator()(Point const& lhs, Point const& rhs)
0059 {
0060 return geometry::get<Dimension>(lhs) < geometry::get<Dimension>(rhs);
0061 }
0062 };
0063
0064
0065 template <std::size_t Dimension, typename PointType, typename CoordinateType>
0066 inline void move_along_vector(PointType& point, PointType const& extreme, CoordinateType const& base_value)
0067 {
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079 CoordinateType const value = geometry::get<Dimension>(point);
0080
0081 if (value >= base_value)
0082 {
0083 return;
0084 }
0085
0086 PointType vector = point;
0087 subtract_point(vector, extreme);
0088
0089 CoordinateType const diff = geometry::get<Dimension>(vector);
0090
0091
0092
0093
0094 if (geometry::math::equals(diff, 0))
0095 {
0096 return;
0097 }
0098
0099 CoordinateType const base_diff = base_value - geometry::get<Dimension>(extreme);
0100
0101 multiply_value(vector, base_diff);
0102 divide_value(vector, diff);
0103
0104
0105 point = extreme;
0106 add_point(point, vector);
0107 }
0108
0109
0110 template <std::size_t Dimension, typename Range, typename CoordinateType>
0111 inline void move_along_vector(Range& range, CoordinateType const& base_value)
0112 {
0113 if (range.size() >= 3)
0114 {
0115 move_along_vector<Dimension>(range.front(), *(range.begin() + 1), base_value);
0116 move_along_vector<Dimension>(range.back(), *(range.rbegin() + 1), base_value);
0117 }
0118 }
0119
0120
0121 template<typename Ring, std::size_t Dimension>
0122 struct extreme_points_on_ring
0123 {
0124
0125 typedef typename geometry::coordinate_type<Ring>::type coordinate_type;
0126 typedef typename geometry::point_type<Ring>::type point_type;
0127
0128 template <typename CirclingIterator, typename Points>
0129 static inline bool extend(CirclingIterator& it,
0130 std::size_t n,
0131 coordinate_type max_coordinate_value,
0132 Points& points, int direction)
0133 {
0134 std::size_t safe_index = 0;
0135 do
0136 {
0137 it += direction;
0138
0139 points.push_back(*it);
0140
0141 if (safe_index++ >= n)
0142 {
0143
0144 return false;
0145 }
0146 } while (geometry::math::equals(geometry::get<Dimension>(*it), max_coordinate_value));
0147
0148 return true;
0149 }
0150
0151
0152 template <typename CirclingIterator>
0153 static inline bool extend(CirclingIterator& it,
0154 std::size_t n,
0155 coordinate_type max_coordinate_value,
0156 int direction)
0157 {
0158 std::size_t safe_index = 0;
0159 do
0160 {
0161 it += direction;
0162
0163 if (safe_index++ >= n)
0164 {
0165
0166 return false;
0167 }
0168 } while (geometry::math::equals(geometry::get<Dimension>(*it), max_coordinate_value));
0169
0170 return true;
0171 }
0172
0173 template <typename CirclingIterator>
0174 static inline bool extent_both_sides(Ring const& ring,
0175 point_type extreme,
0176 CirclingIterator& left,
0177 CirclingIterator& right)
0178 {
0179 std::size_t const n = boost::size(ring);
0180 coordinate_type const max_coordinate_value = geometry::get<Dimension>(extreme);
0181
0182 if (! extend(left, n, max_coordinate_value, -1))
0183 {
0184 return false;
0185 }
0186 if (! extend(right, n, max_coordinate_value, +1))
0187 {
0188 return false;
0189 }
0190
0191 return true;
0192 }
0193
0194 template <typename Collection, typename CirclingIterator>
0195 static inline bool collect(Ring const& ring,
0196 point_type extreme,
0197 Collection& points,
0198 CirclingIterator& left,
0199 CirclingIterator& right)
0200 {
0201 std::size_t const n = boost::size(ring);
0202 coordinate_type const max_coordinate_value = geometry::get<Dimension>(extreme);
0203
0204
0205 if (! extend(left, n, max_coordinate_value, points, -1))
0206 {
0207 return false;
0208 }
0209 std::reverse(points.begin(), points.end());
0210 points.push_back(extreme);
0211 if (! extend(right, n, max_coordinate_value, points, +1))
0212 {
0213 return false;
0214 }
0215
0216 return true;
0217 }
0218
0219 template <typename Extremes, typename Intruders, typename CirclingIterator, typename SideStrategy>
0220 static inline void get_intruders(Ring const& ring, CirclingIterator left, CirclingIterator right,
0221 Extremes const& extremes,
0222 Intruders& intruders,
0223 SideStrategy const& strategy)
0224 {
0225 if (boost::size(extremes) < 3)
0226 {
0227 return;
0228 }
0229 coordinate_type const min_value = geometry::get<Dimension>(*std::min_element(boost::begin(extremes), boost::end(extremes), compare<Dimension>()));
0230
0231
0232 coordinate_type const other_min = geometry::get<1 - Dimension>(*std::min_element(boost::begin(extremes), boost::end(extremes), compare<1 - Dimension>()));
0233 coordinate_type const other_max = geometry::get<1 - Dimension>(*std::max_element(boost::begin(extremes), boost::end(extremes), compare<1 - Dimension>()));
0234
0235 std::size_t defensive_check_index = 0;
0236 std::size_t const n = boost::size(ring);
0237 while (left != right && defensive_check_index < n)
0238 {
0239 coordinate_type const coordinate = geometry::get<Dimension>(*right);
0240 coordinate_type const other_coordinate = geometry::get<1 - Dimension>(*right);
0241 if (coordinate > min_value && other_coordinate > other_min && other_coordinate < other_max)
0242 {
0243 int const factor = geometry::point_order<Ring>::value == geometry::clockwise ? 1 : -1;
0244 int const first_side = strategy.apply(*right, extremes.front(), *(extremes.begin() + 1)) * factor;
0245 int const last_side = strategy.apply(*right, *(extremes.rbegin() + 1), extremes.back()) * factor;
0246
0247
0248 if (first_side != 1 && last_side != 1)
0249 {
0250
0251
0252
0253 CirclingIterator left_intrusion_it = right;
0254 typename boost::range_value<Intruders>::type intruder;
0255 collect(ring, *right, intruder, left_intrusion_it, right);
0256
0257
0258
0259 move_along_vector<Dimension>(intruder, min_value);
0260 intruders.push_back(intruder);
0261 --right;
0262 }
0263 }
0264 ++right;
0265 defensive_check_index++;
0266 }
0267 }
0268
0269 template <typename Extremes, typename Intruders, typename SideStrategy>
0270 static inline void get_intruders(Ring const& ring,
0271 Extremes const& extremes,
0272 Intruders& intruders,
0273 SideStrategy const& strategy)
0274 {
0275 std::size_t const n = boost::size(ring);
0276 if (n >= 3)
0277 {
0278 geometry::ever_circling_range_iterator<Ring const> left(ring);
0279 geometry::ever_circling_range_iterator<Ring const> right(ring);
0280 ++right;
0281
0282 get_intruders(ring, left, right, extremes, intruders, strategy);
0283 }
0284 }
0285
0286 template <typename Iterator, typename SideStrategy>
0287 static inline bool right_turn(Ring const& ring, Iterator it, SideStrategy const& strategy)
0288 {
0289 auto const index = std::distance(boost::begin(ring), it);
0290 geometry::ever_circling_range_iterator<Ring const> left(ring);
0291 geometry::ever_circling_range_iterator<Ring const> right(ring);
0292 left += index;
0293 right += index;
0294
0295 if (! extent_both_sides(ring, *it, left, right))
0296 {
0297 return false;
0298 }
0299
0300 int const factor = geometry::point_order<Ring>::value == geometry::clockwise ? 1 : -1;
0301 int const first_side = strategy.apply(*(right - 1), *right, *left) * factor;
0302 int const last_side = strategy.apply(*left, *(left + 1), *right) * factor;
0303
0304
0305
0306
0307 return first_side != 1 && last_side != 1;
0308 }
0309
0310
0311
0312 template <typename Extremes, typename Intruders, typename SideStrategy>
0313 static inline bool apply(Ring const& ring,
0314 Extremes& extremes,
0315 Intruders& intruders,
0316 SideStrategy const& strategy)
0317 {
0318 std::size_t const n = boost::size(ring);
0319 if (n < 3)
0320 {
0321 return false;
0322 }
0323
0324
0325
0326 auto max_it = boost::begin(ring);
0327 compare<Dimension> smaller;
0328 for (auto it = max_it + 1; it != boost::end(ring); ++it)
0329 {
0330 if (smaller(*max_it, *it) && right_turn(ring, it, strategy))
0331 {
0332 max_it = it;
0333 }
0334 }
0335
0336 if (max_it == boost::end(ring))
0337 {
0338 return false;
0339 }
0340
0341 auto const index = std::distance(boost::begin(ring), max_it);
0342
0343
0344 geometry::ever_circling_range_iterator<Ring const> left(ring);
0345 geometry::ever_circling_range_iterator<Ring const> right(ring);
0346 left += index;
0347 right += index;
0348
0349
0350 std::vector<point_type> points;
0351 points.reserve(3);
0352 if (! collect(ring, *max_it, points, left, right))
0353 {
0354 return false;
0355 }
0356
0357
0358
0359 coordinate_type const front_value = geometry::get<Dimension>(points.front());
0360 coordinate_type const back_value = geometry::get<Dimension>(points.back());
0361 coordinate_type const base_value = (std::max)(front_value, back_value);
0362 if (front_value < back_value)
0363 {
0364 move_along_vector<Dimension>(points.front(), *(points.begin() + 1), base_value);
0365 }
0366 else
0367 {
0368 move_along_vector<Dimension>(points.back(), *(points.rbegin() + 1), base_value);
0369 }
0370
0371 std::copy(points.begin(), points.end(), std::back_inserter(extremes));
0372
0373 get_intruders(ring, left, right, extremes, intruders, strategy);
0374
0375 return true;
0376 }
0377 };
0378
0379
0380
0381
0382
0383 }}
0384 #endif
0385
0386
0387 #ifndef DOXYGEN_NO_DISPATCH
0388 namespace dispatch
0389 {
0390
0391
0392 template
0393 <
0394 typename Geometry,
0395 std::size_t Dimension,
0396 typename GeometryTag = typename tag<Geometry>::type
0397 >
0398 struct extreme_points
0399 {};
0400
0401
0402 template<typename Ring, std::size_t Dimension>
0403 struct extreme_points<Ring, Dimension, ring_tag>
0404 : detail::extreme_points::extreme_points_on_ring<Ring, Dimension>
0405 {};
0406
0407
0408 template<typename Polygon, std::size_t Dimension>
0409 struct extreme_points<Polygon, Dimension, polygon_tag>
0410 {
0411 template <typename Extremes, typename Intruders, typename SideStrategy>
0412 static inline bool apply(Polygon const& polygon, Extremes& extremes, Intruders& intruders,
0413 SideStrategy const& strategy)
0414 {
0415 typedef typename geometry::ring_type<Polygon>::type ring_type;
0416 typedef detail::extreme_points::extreme_points_on_ring
0417 <
0418 ring_type, Dimension
0419 > ring_implementation;
0420
0421 if (! ring_implementation::apply(geometry::exterior_ring(polygon),
0422 extremes, intruders, strategy))
0423 {
0424 return false;
0425 }
0426
0427
0428 auto const& rings = interior_rings(polygon);
0429 for (auto it = boost::begin(rings); it != boost::end(rings); ++it)
0430 {
0431 ring_implementation::get_intruders(*it, extremes, intruders, strategy);
0432 }
0433
0434 return true;
0435 }
0436 };
0437
0438 template<typename Box>
0439 struct extreme_points<Box, 1, box_tag>
0440 {
0441 template <typename Extremes, typename Intruders, typename SideStrategy>
0442 static inline bool apply(Box const& box, Extremes& extremes, Intruders& ,
0443 SideStrategy const& )
0444 {
0445 extremes.resize(4);
0446 geometry::detail::assign_box_corners_oriented<false>(box, extremes);
0447
0448 return true;
0449 }
0450 };
0451
0452 template<typename Box>
0453 struct extreme_points<Box, 0, box_tag>
0454 {
0455 template <typename Extremes, typename Intruders, typename SideStrategy>
0456 static inline bool apply(Box const& box, Extremes& extremes, Intruders& ,
0457 SideStrategy const& )
0458 {
0459 extremes.resize(4);
0460 geometry::detail::assign_box_corners_oriented<false>(box, extremes);
0461
0462 std::rotate(extremes.begin(), extremes.begin() + 1, extremes.end());
0463 return true;
0464 }
0465 };
0466
0467 template<typename MultiPolygon, std::size_t Dimension>
0468 struct extreme_points<MultiPolygon, Dimension, multi_polygon_tag>
0469 {
0470 template <typename Extremes, typename Intruders, typename SideStrategy>
0471 static inline bool apply(MultiPolygon const& multi, Extremes& extremes,
0472 Intruders& intruders, SideStrategy const& strategy)
0473 {
0474
0475
0476
0477 if (boost::size(multi) >= 1)
0478 {
0479 return extreme_points
0480 <
0481 typename boost::range_value<MultiPolygon const>::type,
0482 Dimension,
0483 polygon_tag
0484 >::apply(*boost::begin(multi), extremes, intruders, strategy);
0485 }
0486
0487 return false;
0488 }
0489 };
0490
0491 }
0492 #endif
0493
0494
0495
0496
0497
0498
0499
0500 template
0501 <
0502 std::size_t Edge,
0503 typename Geometry,
0504 typename Extremes,
0505 typename Intruders,
0506 typename SideStrategy
0507 >
0508 inline bool extreme_points(Geometry const& geometry,
0509 Extremes& extremes,
0510 Intruders& intruders,
0511 SideStrategy const& strategy)
0512 {
0513 concepts::check<Geometry const>();
0514
0515
0516
0517 concepts::check<typename boost::range_value<Extremes>::type>();
0518
0519
0520
0521 concepts::check
0522 <
0523 typename boost::range_value
0524 <
0525 typename boost::range_value<Intruders>::type
0526 >::type
0527 const
0528 >();
0529
0530 return dispatch::extreme_points
0531 <
0532 Geometry,
0533 Edge
0534 >::apply(geometry, extremes, intruders, strategy);
0535 }
0536
0537
0538 template
0539 <
0540 std::size_t Edge,
0541 typename Geometry,
0542 typename Extremes,
0543 typename Intruders
0544 >
0545 inline bool extreme_points(Geometry const& geometry,
0546 Extremes& extremes,
0547 Intruders& intruders)
0548 {
0549 typedef typename strategy::side::services::default_strategy
0550 <
0551 typename cs_tag<Geometry>::type
0552 >::type strategy_type;
0553
0554 return geometry::extreme_points<Edge>(geometry,extremes, intruders, strategy_type());
0555 }
0556
0557 }}
0558
0559
0560 #endif