annotate DEPENDENCIES/generic/include/boost/geometry/algorithms/detail/extreme_points.hpp @ 133:4acb5d8d80b6 tip

Don't fail environmental check if README.md exists (but .txt and no-suffix don't)
author Chris Cannam
date Tue, 30 Jul 2019 12:25:44 +0100
parents f46d142149f5
children
rev   line source
Chris@102 1 // Boost.Geometry (aka GGL, Generic Geometry Library)
Chris@102 2
Chris@102 3 // Copyright (c) 2007-2013 Barend Gehrels, Amsterdam, the Netherlands.
Chris@102 4 // Copyright (c) 2008-2013 Bruno Lalande, Paris, France.
Chris@102 5 // Copyright (c) 2009-2013 Mateusz Loskot, London, UK.
Chris@102 6 // Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
Chris@102 7
Chris@102 8 // Use, modification and distribution is subject to the Boost Software License,
Chris@102 9 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
Chris@102 10 // http://www.boost.org/LICENSE_1_0.txt)
Chris@102 11
Chris@102 12 #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXTREME_POINTS_HPP
Chris@102 13 #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXTREME_POINTS_HPP
Chris@102 14
Chris@102 15
Chris@102 16 #include <cstddef>
Chris@102 17
Chris@102 18 #include <boost/range.hpp>
Chris@102 19
Chris@102 20 #include <boost/geometry/algorithms/detail/interior_iterator.hpp>
Chris@102 21
Chris@102 22 #include <boost/geometry/core/cs.hpp>
Chris@102 23 #include <boost/geometry/core/point_type.hpp>
Chris@102 24 #include <boost/geometry/core/ring_type.hpp>
Chris@102 25 #include <boost/geometry/core/tags.hpp>
Chris@102 26
Chris@102 27 #include <boost/geometry/geometries/concepts/check.hpp>
Chris@102 28 #include <boost/geometry/iterators/ever_circling_iterator.hpp>
Chris@102 29
Chris@102 30 #include <boost/geometry/algorithms/detail/assign_box_corners.hpp>
Chris@102 31
Chris@102 32 #include <boost/geometry/strategies/side.hpp>
Chris@102 33
Chris@102 34 #include <boost/geometry/util/math.hpp>
Chris@102 35
Chris@102 36
Chris@102 37 namespace boost { namespace geometry
Chris@102 38 {
Chris@102 39
Chris@102 40
Chris@102 41 #ifndef DOXYGEN_NO_DETAIL
Chris@102 42 namespace detail { namespace extreme_points
Chris@102 43 {
Chris@102 44
Chris@102 45 template <std::size_t Dimension>
Chris@102 46 struct compare
Chris@102 47 {
Chris@102 48 template <typename Point>
Chris@102 49 inline bool operator()(Point const& lhs, Point const& rhs)
Chris@102 50 {
Chris@102 51 return geometry::get<Dimension>(lhs) < geometry::get<Dimension>(rhs);
Chris@102 52 }
Chris@102 53 };
Chris@102 54
Chris@102 55
Chris@102 56 template <std::size_t Dimension, typename PointType, typename CoordinateType>
Chris@102 57 inline void move_along_vector(PointType& point, PointType const& extreme, CoordinateType const& base_value)
Chris@102 58 {
Chris@102 59 // Moves a point along the vector (point, extreme) in the direction of the extreme point
Chris@102 60 // This adapts the possibly uneven legs of the triangle (or trapezium-like shape)
Chris@102 61 // _____extreme _____
Chris@102 62 // / \ / \ .
Chris@102 63 // /base \ => / \ point .
Chris@102 64 // \ point .
Chris@102 65 //
Chris@102 66 // For so-called intruders, it can be used to adapt both legs to the level of "base"
Chris@102 67 // For the base, it can be used to adapt both legs to the level of the max-value of the intruders
Chris@102 68 // If there are 2 or more extreme values, use the one close to 'point' to have a correct vector
Chris@102 69
Chris@102 70 CoordinateType const value = geometry::get<Dimension>(point);
Chris@102 71 //if (geometry::math::equals(value, base_value))
Chris@102 72 if (value >= base_value)
Chris@102 73 {
Chris@102 74 return;
Chris@102 75 }
Chris@102 76
Chris@102 77 PointType vector = point;
Chris@102 78 subtract_point(vector, extreme);
Chris@102 79
Chris@102 80 CoordinateType const diff = geometry::get<Dimension>(vector);
Chris@102 81
Chris@102 82 // diff should never be zero
Chris@102 83 // because of the way our triangle/trapezium is build.
Chris@102 84 // We just return if it would be the case.
Chris@102 85 if (geometry::math::equals(diff, 0))
Chris@102 86 {
Chris@102 87 return;
Chris@102 88 }
Chris@102 89
Chris@102 90 CoordinateType const base_diff = base_value - geometry::get<Dimension>(extreme);
Chris@102 91
Chris@102 92 multiply_value(vector, base_diff);
Chris@102 93 divide_value(vector, diff);
Chris@102 94
Chris@102 95 // The real move:
Chris@102 96 point = extreme;
Chris@102 97 add_point(point, vector);
Chris@102 98 }
Chris@102 99
Chris@102 100
Chris@102 101 template <std::size_t Dimension, typename Range, typename CoordinateType>
Chris@102 102 inline void move_along_vector(Range& range, CoordinateType const& base_value)
Chris@102 103 {
Chris@102 104 if (range.size() >= 3)
Chris@102 105 {
Chris@102 106 move_along_vector<Dimension>(range.front(), *(range.begin() + 1), base_value);
Chris@102 107 move_along_vector<Dimension>(range.back(), *(range.rbegin() + 1), base_value);
Chris@102 108 }
Chris@102 109 }
Chris@102 110
Chris@102 111
Chris@102 112 template<typename Ring, std::size_t Dimension>
Chris@102 113 struct extreme_points_on_ring
Chris@102 114 {
Chris@102 115
Chris@102 116 typedef typename geometry::coordinate_type<Ring>::type coordinate_type;
Chris@102 117 typedef typename boost::range_iterator<Ring const>::type range_iterator;
Chris@102 118 typedef typename geometry::point_type<Ring>::type point_type;
Chris@102 119
Chris@102 120 typedef typename geometry::strategy::side::services::default_strategy
Chris@102 121 <
Chris@102 122 typename geometry::cs_tag<point_type>::type
Chris@102 123 >::type side_strategy;
Chris@102 124
Chris@102 125
Chris@102 126 template <typename CirclingIterator, typename Points>
Chris@102 127 static inline bool extend(CirclingIterator& it,
Chris@102 128 std::size_t n,
Chris@102 129 coordinate_type max_coordinate_value,
Chris@102 130 Points& points, int direction)
Chris@102 131 {
Chris@102 132 std::size_t safe_index = 0;
Chris@102 133 do
Chris@102 134 {
Chris@102 135 it += direction;
Chris@102 136
Chris@102 137 points.push_back(*it);
Chris@102 138
Chris@102 139 if (safe_index++ >= n)
Chris@102 140 {
Chris@102 141 // E.g.: ring is completely horizontal or vertical (= invalid, but we don't want to have an infinite loop)
Chris@102 142 return false;
Chris@102 143 }
Chris@102 144 } while (geometry::math::equals(geometry::get<Dimension>(*it), max_coordinate_value));
Chris@102 145
Chris@102 146 return true;
Chris@102 147 }
Chris@102 148
Chris@102 149 // Overload without adding to poinst
Chris@102 150 template <typename CirclingIterator>
Chris@102 151 static inline bool extend(CirclingIterator& it,
Chris@102 152 std::size_t n,
Chris@102 153 coordinate_type max_coordinate_value,
Chris@102 154 int direction)
Chris@102 155 {
Chris@102 156 std::size_t safe_index = 0;
Chris@102 157 do
Chris@102 158 {
Chris@102 159 it += direction;
Chris@102 160
Chris@102 161 if (safe_index++ >= n)
Chris@102 162 {
Chris@102 163 // E.g.: ring is completely horizontal or vertical (= invalid, but we don't want to have an infinite loop)
Chris@102 164 return false;
Chris@102 165 }
Chris@102 166 } while (geometry::math::equals(geometry::get<Dimension>(*it), max_coordinate_value));
Chris@102 167
Chris@102 168 return true;
Chris@102 169 }
Chris@102 170
Chris@102 171 template <typename CirclingIterator>
Chris@102 172 static inline bool extent_both_sides(Ring const& ring,
Chris@102 173 point_type extreme,
Chris@102 174 CirclingIterator& left,
Chris@102 175 CirclingIterator& right)
Chris@102 176 {
Chris@102 177 std::size_t const n = boost::size(ring);
Chris@102 178 coordinate_type const max_coordinate_value = geometry::get<Dimension>(extreme);
Chris@102 179
Chris@102 180 if (! extend(left, n, max_coordinate_value, -1))
Chris@102 181 {
Chris@102 182 return false;
Chris@102 183 }
Chris@102 184 if (! extend(right, n, max_coordinate_value, +1))
Chris@102 185 {
Chris@102 186 return false;
Chris@102 187 }
Chris@102 188
Chris@102 189 return true;
Chris@102 190 }
Chris@102 191
Chris@102 192 template <typename Collection, typename CirclingIterator>
Chris@102 193 static inline bool collect(Ring const& ring,
Chris@102 194 point_type extreme,
Chris@102 195 Collection& points,
Chris@102 196 CirclingIterator& left,
Chris@102 197 CirclingIterator& right)
Chris@102 198 {
Chris@102 199 std::size_t const n = boost::size(ring);
Chris@102 200 coordinate_type const max_coordinate_value = geometry::get<Dimension>(extreme);
Chris@102 201
Chris@102 202 // Collects first left, which is reversed (if more than one point) then adds the top itself, then right
Chris@102 203 if (! extend(left, n, max_coordinate_value, points, -1))
Chris@102 204 {
Chris@102 205 return false;
Chris@102 206 }
Chris@102 207 std::reverse(points.begin(), points.end());
Chris@102 208 points.push_back(extreme);
Chris@102 209 if (! extend(right, n, max_coordinate_value, points, +1))
Chris@102 210 {
Chris@102 211 return false;
Chris@102 212 }
Chris@102 213
Chris@102 214 return true;
Chris@102 215 }
Chris@102 216
Chris@102 217 template <typename Extremes, typename Intruders, typename CirclingIterator>
Chris@102 218 static inline void get_intruders(Ring const& ring, CirclingIterator left, CirclingIterator right,
Chris@102 219 Extremes const& extremes,
Chris@102 220 Intruders& intruders)
Chris@102 221 {
Chris@102 222 if (boost::size(extremes) < 3)
Chris@102 223 {
Chris@102 224 return;
Chris@102 225 }
Chris@102 226 coordinate_type const min_value = geometry::get<Dimension>(*std::min_element(boost::begin(extremes), boost::end(extremes), compare<Dimension>()));
Chris@102 227
Chris@102 228 // Also select left/right (if Dimension=1)
Chris@102 229 coordinate_type const other_min = geometry::get<1 - Dimension>(*std::min_element(boost::begin(extremes), boost::end(extremes), compare<1 - Dimension>()));
Chris@102 230 coordinate_type const other_max = geometry::get<1 - Dimension>(*std::max_element(boost::begin(extremes), boost::end(extremes), compare<1 - Dimension>()));
Chris@102 231
Chris@102 232 std::size_t defensive_check_index = 0; // in case we skip over left/right check, collect modifies right too
Chris@102 233 std::size_t const n = boost::size(ring);
Chris@102 234 while (left != right && defensive_check_index < n)
Chris@102 235 {
Chris@102 236 coordinate_type const coordinate = geometry::get<Dimension>(*right);
Chris@102 237 coordinate_type const other_coordinate = geometry::get<1 - Dimension>(*right);
Chris@102 238 if (coordinate > min_value && other_coordinate > other_min && other_coordinate < other_max)
Chris@102 239 {
Chris@102 240 int const factor = geometry::point_order<Ring>::value == geometry::clockwise ? 1 : -1;
Chris@102 241 int const first_side = side_strategy::apply(*right, extremes.front(), *(extremes.begin() + 1)) * factor;
Chris@102 242 int const last_side = side_strategy::apply(*right, *(extremes.rbegin() + 1), extremes.back()) * factor;
Chris@102 243
Chris@102 244 // If not lying left from any of the extemes side
Chris@102 245 if (first_side != 1 && last_side != 1)
Chris@102 246 {
Chris@102 247 //std::cout << "first " << first_side << " last " << last_side << std::endl;
Chris@102 248
Chris@102 249 // we start at this intrusion until it is handled, and don't affect our initial left iterator
Chris@102 250 CirclingIterator left_intrusion_it = right;
Chris@102 251 typename boost::range_value<Intruders>::type intruder;
Chris@102 252 collect(ring, *right, intruder, left_intrusion_it, right);
Chris@102 253
Chris@102 254 // Also moves these to base-level, makes sorting possible which can be done in case of self-tangencies
Chris@102 255 // (we might postpone this action, it is often not necessary. However it is not time-consuming)
Chris@102 256 move_along_vector<Dimension>(intruder, min_value);
Chris@102 257 intruders.push_back(intruder);
Chris@102 258 --right;
Chris@102 259 }
Chris@102 260 }
Chris@102 261 ++right;
Chris@102 262 defensive_check_index++;
Chris@102 263 }
Chris@102 264 }
Chris@102 265
Chris@102 266 template <typename Extremes, typename Intruders>
Chris@102 267 static inline void get_intruders(Ring const& ring,
Chris@102 268 Extremes const& extremes,
Chris@102 269 Intruders& intruders)
Chris@102 270 {
Chris@102 271 std::size_t const n = boost::size(ring);
Chris@102 272 if (n >= 3)
Chris@102 273 {
Chris@102 274 geometry::ever_circling_range_iterator<Ring const> left(ring);
Chris@102 275 geometry::ever_circling_range_iterator<Ring const> right(ring);
Chris@102 276 ++right;
Chris@102 277
Chris@102 278 get_intruders(ring, left, right, extremes, intruders);
Chris@102 279 }
Chris@102 280 }
Chris@102 281
Chris@102 282 template <typename Iterator>
Chris@102 283 static inline bool right_turn(Ring const& ring, Iterator it)
Chris@102 284 {
Chris@102 285 typename std::iterator_traits<Iterator>::difference_type const index
Chris@102 286 = std::distance(boost::begin(ring), it);
Chris@102 287 geometry::ever_circling_range_iterator<Ring const> left(ring);
Chris@102 288 geometry::ever_circling_range_iterator<Ring const> right(ring);
Chris@102 289 left += index;
Chris@102 290 right += index;
Chris@102 291
Chris@102 292 if (! extent_both_sides(ring, *it, left, right))
Chris@102 293 {
Chris@102 294 return false;
Chris@102 295 }
Chris@102 296
Chris@102 297 int const factor = geometry::point_order<Ring>::value == geometry::clockwise ? 1 : -1;
Chris@102 298 int const first_side = side_strategy::apply(*(right - 1), *right, *left) * factor;
Chris@102 299 int const last_side = side_strategy::apply(*left, *(left + 1), *right) * factor;
Chris@102 300
Chris@102 301 //std::cout << "Candidate at " << geometry::wkt(*it) << " first=" << first_side << " last=" << last_side << std::endl;
Chris@102 302
Chris@102 303 // Turn should not be left (actually, it should be right because extent removes horizontal/collinear cases)
Chris@102 304 return first_side != 1 && last_side != 1;
Chris@102 305 }
Chris@102 306
Chris@102 307
Chris@102 308 // Gets the extreme segments (top point plus neighbouring points), plus intruders, if any, on the same ring
Chris@102 309 template <typename Extremes, typename Intruders>
Chris@102 310 static inline bool apply(Ring const& ring, Extremes& extremes, Intruders& intruders)
Chris@102 311 {
Chris@102 312 std::size_t const n = boost::size(ring);
Chris@102 313 if (n < 3)
Chris@102 314 {
Chris@102 315 return false;
Chris@102 316 }
Chris@102 317
Chris@102 318 // Get all maxima, usually one. In case of self-tangencies, or self-crossings,
Chris@102 319 // the max might be is not valid. A valid max should make a right turn
Chris@102 320 range_iterator max_it = boost::begin(ring);
Chris@102 321 compare<Dimension> smaller;
Chris@102 322 for (range_iterator it = max_it + 1; it != boost::end(ring); ++it)
Chris@102 323 {
Chris@102 324 if (smaller(*max_it, *it) && right_turn(ring, it))
Chris@102 325 {
Chris@102 326 max_it = it;
Chris@102 327 }
Chris@102 328 }
Chris@102 329
Chris@102 330 if (max_it == boost::end(ring))
Chris@102 331 {
Chris@102 332 return false;
Chris@102 333 }
Chris@102 334
Chris@102 335 typename std::iterator_traits<range_iterator>::difference_type const
Chris@102 336 index = std::distance(boost::begin(ring), max_it);
Chris@102 337 //std::cout << "Extreme point lies at " << index << " having " << geometry::wkt(*max_it) << std::endl;
Chris@102 338
Chris@102 339 geometry::ever_circling_range_iterator<Ring const> left(ring);
Chris@102 340 geometry::ever_circling_range_iterator<Ring const> right(ring);
Chris@102 341 left += index;
Chris@102 342 right += index;
Chris@102 343
Chris@102 344 // Collect all points (often 3) in a temporary vector
Chris@102 345 std::vector<point_type> points;
Chris@102 346 points.reserve(3);
Chris@102 347 if (! collect(ring, *max_it, points, left, right))
Chris@102 348 {
Chris@102 349 return false;
Chris@102 350 }
Chris@102 351
Chris@102 352 //std::cout << "Built vector of " << points.size() << std::endl;
Chris@102 353
Chris@102 354 coordinate_type const front_value = geometry::get<Dimension>(points.front());
Chris@102 355 coordinate_type const back_value = geometry::get<Dimension>(points.back());
Chris@102 356 coordinate_type const base_value = (std::max)(front_value, back_value);
Chris@102 357 if (front_value < back_value)
Chris@102 358 {
Chris@102 359 move_along_vector<Dimension>(points.front(), *(points.begin() + 1), base_value);
Chris@102 360 }
Chris@102 361 else
Chris@102 362 {
Chris@102 363 move_along_vector<Dimension>(points.back(), *(points.rbegin() + 1), base_value);
Chris@102 364 }
Chris@102 365
Chris@102 366 std::copy(points.begin(), points.end(), std::back_inserter(extremes));
Chris@102 367
Chris@102 368 get_intruders(ring, left, right, extremes, intruders);
Chris@102 369
Chris@102 370 return true;
Chris@102 371 }
Chris@102 372 };
Chris@102 373
Chris@102 374
Chris@102 375
Chris@102 376
Chris@102 377
Chris@102 378 }} // namespace detail::extreme_points
Chris@102 379 #endif // DOXYGEN_NO_DETAIL
Chris@102 380
Chris@102 381
Chris@102 382 #ifndef DOXYGEN_NO_DISPATCH
Chris@102 383 namespace dispatch
Chris@102 384 {
Chris@102 385
Chris@102 386
Chris@102 387 template
Chris@102 388 <
Chris@102 389 typename Geometry,
Chris@102 390 std::size_t Dimension,
Chris@102 391 typename GeometryTag = typename tag<Geometry>::type
Chris@102 392 >
Chris@102 393 struct extreme_points
Chris@102 394 {};
Chris@102 395
Chris@102 396
Chris@102 397 template<typename Ring, std::size_t Dimension>
Chris@102 398 struct extreme_points<Ring, Dimension, ring_tag>
Chris@102 399 : detail::extreme_points::extreme_points_on_ring<Ring, Dimension>
Chris@102 400 {};
Chris@102 401
Chris@102 402
Chris@102 403 template<typename Polygon, std::size_t Dimension>
Chris@102 404 struct extreme_points<Polygon, Dimension, polygon_tag>
Chris@102 405 {
Chris@102 406 template <typename Extremes, typename Intruders>
Chris@102 407 static inline bool apply(Polygon const& polygon, Extremes& extremes, Intruders& intruders)
Chris@102 408 {
Chris@102 409 typedef typename geometry::ring_type<Polygon>::type ring_type;
Chris@102 410 typedef detail::extreme_points::extreme_points_on_ring
Chris@102 411 <
Chris@102 412 ring_type, Dimension
Chris@102 413 > ring_implementation;
Chris@102 414
Chris@102 415 if (! ring_implementation::apply(geometry::exterior_ring(polygon), extremes, intruders))
Chris@102 416 {
Chris@102 417 return false;
Chris@102 418 }
Chris@102 419
Chris@102 420 // For a polygon, its interior rings can contain intruders
Chris@102 421 typename interior_return_type<Polygon const>::type
Chris@102 422 rings = interior_rings(polygon);
Chris@102 423 for (typename detail::interior_iterator<Polygon const>::type
Chris@102 424 it = boost::begin(rings); it != boost::end(rings); ++it)
Chris@102 425 {
Chris@102 426 ring_implementation::get_intruders(*it, extremes, intruders);
Chris@102 427 }
Chris@102 428
Chris@102 429 return true;
Chris@102 430 }
Chris@102 431 };
Chris@102 432
Chris@102 433 template<typename Box>
Chris@102 434 struct extreme_points<Box, 1, box_tag>
Chris@102 435 {
Chris@102 436 template <typename Extremes, typename Intruders>
Chris@102 437 static inline bool apply(Box const& box, Extremes& extremes, Intruders& )
Chris@102 438 {
Chris@102 439 extremes.resize(4);
Chris@102 440 geometry::detail::assign_box_corners_oriented<false>(box, extremes);
Chris@102 441 // ll,ul,ur,lr, contains too exactly the right info
Chris@102 442 return true;
Chris@102 443 }
Chris@102 444 };
Chris@102 445
Chris@102 446 template<typename Box>
Chris@102 447 struct extreme_points<Box, 0, box_tag>
Chris@102 448 {
Chris@102 449 template <typename Extremes, typename Intruders>
Chris@102 450 static inline bool apply(Box const& box, Extremes& extremes, Intruders& )
Chris@102 451 {
Chris@102 452 extremes.resize(4);
Chris@102 453 geometry::detail::assign_box_corners_oriented<false>(box, extremes);
Chris@102 454 // ll,ul,ur,lr, rotate one to start with UL and end with LL
Chris@102 455 std::rotate(extremes.begin(), extremes.begin() + 1, extremes.end());
Chris@102 456 return true;
Chris@102 457 }
Chris@102 458 };
Chris@102 459
Chris@102 460 template<typename MultiPolygon, std::size_t Dimension>
Chris@102 461 struct extreme_points<MultiPolygon, Dimension, multi_polygon_tag>
Chris@102 462 {
Chris@102 463 template <typename Extremes, typename Intruders>
Chris@102 464 static inline bool apply(MultiPolygon const& multi, Extremes& extremes, Intruders& intruders)
Chris@102 465 {
Chris@102 466 // Get one for the very first polygon, that is (for the moment) enough.
Chris@102 467 // It is not guaranteed the "extreme" then, but for the current purpose
Chris@102 468 // (point_on_surface) it can just be this point.
Chris@102 469 if (boost::size(multi) >= 1)
Chris@102 470 {
Chris@102 471 return extreme_points
Chris@102 472 <
Chris@102 473 typename boost::range_value<MultiPolygon const>::type,
Chris@102 474 Dimension,
Chris@102 475 polygon_tag
Chris@102 476 >::apply(*boost::begin(multi), extremes, intruders);
Chris@102 477 }
Chris@102 478
Chris@102 479 return false;
Chris@102 480 }
Chris@102 481 };
Chris@102 482
Chris@102 483 } // namespace dispatch
Chris@102 484 #endif // DOXYGEN_NO_DISPATCH
Chris@102 485
Chris@102 486
Chris@102 487 /*!
Chris@102 488 \brief Returns extreme points (for Edge=1 in dimension 1, so the top,
Chris@102 489 for Edge=0 in dimension 0, the right side)
Chris@102 490 \note We could specify a strategy (less/greater) to get bottom/left side too. However, until now we don't need that.
Chris@102 491 */
Chris@102 492 template <std::size_t Edge, typename Geometry, typename Extremes, typename Intruders>
Chris@102 493 inline bool extreme_points(Geometry const& geometry, Extremes& extremes, Intruders& intruders)
Chris@102 494 {
Chris@102 495 concept::check<Geometry const>();
Chris@102 496
Chris@102 497 // Extremes is not required to follow a geometry concept (but it should support an output iterator),
Chris@102 498 // but its elements should fulfil the point-concept
Chris@102 499 concept::check<typename boost::range_value<Extremes>::type>();
Chris@102 500
Chris@102 501 // Intruders should contain collections which value type is point-concept
Chris@102 502 // Extremes might be anything (supporting an output iterator), but its elements should fulfil the point-concept
Chris@102 503 concept::check
Chris@102 504 <
Chris@102 505 typename boost::range_value
Chris@102 506 <
Chris@102 507 typename boost::range_value<Intruders>::type
Chris@102 508 >::type
Chris@102 509 const
Chris@102 510 >();
Chris@102 511
Chris@102 512 return dispatch::extreme_points<Geometry, Edge>::apply(geometry, extremes, intruders);
Chris@102 513 }
Chris@102 514
Chris@102 515
Chris@102 516
Chris@102 517 }} // namespace boost::geometry
Chris@102 518
Chris@102 519
Chris@102 520 #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXTREME_POINTS_HPP