1 // Boost.Geometry (aka GGL, Generic Geometry Library) 2 3 // Copyright (c) 2014, 2019, Oracle and/or its affiliates. 4 5 // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle 6 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle 7 8 // Licensed under the Boost Software License version 1.0. 9 // http://www.boost.org/users/license.html 10 11 #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_GEOMETRY_TO_SEGMENT_OR_BOX_HPP 12 #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_GEOMETRY_TO_SEGMENT_OR_BOX_HPP 13 14 #include <iterator> 15 16 #include <boost/range.hpp> 17 18 #include <boost/geometry/core/point_type.hpp> 19 #include <boost/geometry/core/tag.hpp> 20 #include <boost/geometry/core/tags.hpp> 21 22 #include <boost/geometry/strategies/distance.hpp> 23 #include <boost/geometry/strategies/tags.hpp> 24 25 #include <boost/geometry/algorithms/assign.hpp> 26 #include <boost/geometry/algorithms/intersects.hpp> 27 #include <boost/geometry/algorithms/num_points.hpp> 28 29 #include <boost/geometry/iterators/point_iterator.hpp> 30 #include <boost/geometry/iterators/segment_iterator.hpp> 31 32 #include <boost/geometry/algorithms/dispatch/distance.hpp> 33 34 #include <boost/geometry/algorithms/detail/closest_feature/geometry_to_range.hpp> 35 #include <boost/geometry/algorithms/detail/closest_feature/point_to_range.hpp> 36 37 #include <boost/geometry/algorithms/detail/distance/is_comparable.hpp> 38 39 #include <boost/geometry/util/condition.hpp> 40 41 42 namespace boost { namespace geometry 43 { 44 45 #ifndef DOXYGEN_NO_DETAIL 46 namespace detail { namespace distance 47 { 48 49 50 // closure of segment or box point range 51 template 52 < 53 typename SegmentOrBox, 54 typename Tag = typename tag<SegmentOrBox>::type 55 > 56 struct segment_or_box_point_range_closure 57 : not_implemented<SegmentOrBox> 58 {}; 59 60 template <typename Segment> 61 struct segment_or_box_point_range_closure<Segment, segment_tag> 62 { 63 static const closure_selector value = closed; 64 }; 65 66 template <typename Box> 67 struct segment_or_box_point_range_closure<Box, box_tag> 68 { 69 static const closure_selector value = open; 70 }; 71 72 73 74 template 75 < 76 typename Geometry, 77 typename SegmentOrBox, 78 typename Strategy, 79 typename Tag = typename tag<Geometry>::type 80 > 81 class geometry_to_segment_or_box 82 { 83 private: 84 typedef typename point_type<SegmentOrBox>::type segment_or_box_point; 85 86 typedef typename strategy::distance::services::comparable_type 87 < 88 Strategy 89 >::type comparable_strategy; 90 91 typedef detail::closest_feature::point_to_point_range 92 < 93 typename point_type<Geometry>::type, 94 std::vector<segment_or_box_point>, 95 segment_or_box_point_range_closure<SegmentOrBox>::value, 96 comparable_strategy 97 > point_to_point_range; 98 99 typedef detail::closest_feature::geometry_to_range geometry_to_range; 100 101 typedef typename strategy::distance::services::return_type 102 < 103 comparable_strategy, 104 typename point_type<Geometry>::type, 105 segment_or_box_point 106 >::type comparable_return_type; 107 108 109 // assign the new minimum value for an iterator of the point range 110 // of a segment or a box 111 template 112 < 113 typename SegOrBox, 114 typename SegOrBoxTag = typename tag<SegOrBox>::type 115 > 116 struct assign_new_min_iterator 117 : not_implemented<SegOrBox> 118 {}; 119 120 template <typename Segment> 121 struct assign_new_min_iterator<Segment, segment_tag> 122 { 123 template <typename Iterator> applyboost::geometry::detail::distance::geometry_to_segment_or_box::assign_new_min_iterator124 static inline void apply(Iterator&, Iterator) 125 { 126 } 127 }; 128 129 template <typename Box> 130 struct assign_new_min_iterator<Box, box_tag> 131 { 132 template <typename Iterator> applyboost::geometry::detail::distance::geometry_to_segment_or_box::assign_new_min_iterator133 static inline void apply(Iterator& it_min, Iterator it) 134 { 135 it_min = it; 136 } 137 }; 138 139 140 // assign the points of a segment or a box to a range 141 template 142 < 143 typename SegOrBox, 144 typename PointRange, 145 typename SegOrBoxTag = typename tag<SegOrBox>::type 146 > 147 struct assign_segment_or_box_points 148 {}; 149 150 template <typename Segment, typename PointRange> 151 struct assign_segment_or_box_points<Segment, PointRange, segment_tag> 152 { applyboost::geometry::detail::distance::geometry_to_segment_or_box::assign_segment_or_box_points153 static inline void apply(Segment const& segment, PointRange& range) 154 { 155 detail::assign_point_from_index<0>(segment, range[0]); 156 detail::assign_point_from_index<1>(segment, range[1]); 157 } 158 }; 159 160 template <typename Box, typename PointRange> 161 struct assign_segment_or_box_points<Box, PointRange, box_tag> 162 { applyboost::geometry::detail::distance::geometry_to_segment_or_box::assign_segment_or_box_points163 static inline void apply(Box const& box, PointRange& range) 164 { 165 detail::assign_box_corners_oriented<true>(box, range); 166 } 167 }; 168 169 template 170 < 171 typename SegOrBox, 172 typename SegOrBoxTag = typename tag<SegOrBox>::type 173 > 174 struct intersects 175 { applyboost::geometry::detail::distance::geometry_to_segment_or_box::intersects176 static inline bool apply(Geometry const& g1, SegOrBox const& g2, Strategy const&) 177 { 178 return geometry::intersects(g1, g2); 179 } 180 }; 181 182 template <typename SegOrBox> 183 struct intersects<SegOrBox, segment_tag> 184 { applyboost::geometry::detail::distance::geometry_to_segment_or_box::intersects185 static inline bool apply(Geometry const& g1, SegOrBox const& g2, Strategy const& s) 186 { 187 return geometry::intersects(g1, g2, s.get_relate_segment_segment_strategy()); 188 } 189 }; 190 191 public: 192 typedef typename strategy::distance::services::return_type 193 < 194 Strategy, 195 typename point_type<Geometry>::type, 196 segment_or_box_point 197 >::type return_type; 198 apply(Geometry const & geometry,SegmentOrBox const & segment_or_box,Strategy const & strategy,bool check_intersection=true)199 static inline return_type apply(Geometry const& geometry, 200 SegmentOrBox const& segment_or_box, 201 Strategy const& strategy, 202 bool check_intersection = true) 203 { 204 typedef geometry::point_iterator<Geometry const> point_iterator_type; 205 typedef geometry::segment_iterator 206 < 207 Geometry const 208 > segment_iterator_type; 209 210 typedef typename boost::range_const_iterator 211 < 212 std::vector<segment_or_box_point> 213 >::type seg_or_box_const_iterator; 214 215 typedef assign_new_min_iterator<SegmentOrBox> assign_new_value; 216 217 218 if (check_intersection 219 && intersects<SegmentOrBox>::apply(geometry, segment_or_box, strategy)) 220 { 221 return 0; 222 } 223 224 comparable_strategy cstrategy = 225 strategy::distance::services::get_comparable 226 < 227 Strategy 228 >::apply(strategy); 229 230 // get all points of the segment or the box 231 std::vector<segment_or_box_point> 232 seg_or_box_points(geometry::num_points(segment_or_box)); 233 234 assign_segment_or_box_points 235 < 236 SegmentOrBox, 237 std::vector<segment_or_box_point> 238 >::apply(segment_or_box, seg_or_box_points); 239 240 // consider all distances of the points in the geometry to the 241 // segment or box 242 comparable_return_type cd_min1(0); 243 point_iterator_type pit_min; 244 seg_or_box_const_iterator it_min1 = boost::const_begin(seg_or_box_points); 245 seg_or_box_const_iterator it_min2 = it_min1; 246 ++it_min2; 247 bool first = true; 248 249 for (point_iterator_type pit = points_begin(geometry); 250 pit != points_end(geometry); ++pit, first = false) 251 { 252 comparable_return_type cd; 253 std::pair 254 < 255 seg_or_box_const_iterator, seg_or_box_const_iterator 256 > it_pair 257 = point_to_point_range::apply(*pit, 258 boost::const_begin(seg_or_box_points), 259 boost::const_end(seg_or_box_points), 260 cstrategy, 261 cd); 262 263 if (first || cd < cd_min1) 264 { 265 cd_min1 = cd; 266 pit_min = pit; 267 assign_new_value::apply(it_min1, it_pair.first); 268 assign_new_value::apply(it_min2, it_pair.second); 269 } 270 } 271 272 // consider all distances of the points in the segment or box to the 273 // segments of the geometry 274 comparable_return_type cd_min2(0); 275 segment_iterator_type sit_min; 276 seg_or_box_const_iterator it_min; 277 278 first = true; 279 for (seg_or_box_const_iterator it = boost::const_begin(seg_or_box_points); 280 it != boost::const_end(seg_or_box_points); ++it, first = false) 281 { 282 comparable_return_type cd; 283 segment_iterator_type sit 284 = geometry_to_range::apply(*it, 285 segments_begin(geometry), 286 segments_end(geometry), 287 cstrategy, 288 cd); 289 290 if (first || cd < cd_min2) 291 { 292 cd_min2 = cd; 293 it_min = it; 294 sit_min = sit; 295 } 296 } 297 298 if (BOOST_GEOMETRY_CONDITION(is_comparable<Strategy>::value)) 299 { 300 return (std::min)(cd_min1, cd_min2); 301 } 302 303 if (cd_min1 < cd_min2) 304 { 305 return strategy.apply(*pit_min, *it_min1, *it_min2); 306 } 307 else 308 { 309 return dispatch::distance 310 < 311 segment_or_box_point, 312 typename std::iterator_traits 313 < 314 segment_iterator_type 315 >::value_type, 316 Strategy 317 >::apply(*it_min, *sit_min, strategy); 318 } 319 } 320 321 322 static inline return_type apply(SegmentOrBox const & segment_or_box,Geometry const & geometry,Strategy const & strategy,bool check_intersection=true)323 apply(SegmentOrBox const& segment_or_box, Geometry const& geometry, 324 Strategy const& strategy, bool check_intersection = true) 325 { 326 return apply(geometry, segment_or_box, strategy, check_intersection); 327 } 328 }; 329 330 331 332 template <typename MultiPoint, typename SegmentOrBox, typename Strategy> 333 class geometry_to_segment_or_box 334 < 335 MultiPoint, SegmentOrBox, Strategy, multi_point_tag 336 > 337 { 338 private: 339 typedef detail::closest_feature::geometry_to_range base_type; 340 341 typedef typename boost::range_iterator 342 < 343 MultiPoint const 344 >::type iterator_type; 345 346 typedef detail::closest_feature::geometry_to_range geometry_to_range; 347 348 public: 349 typedef typename strategy::distance::services::return_type 350 < 351 Strategy, 352 typename point_type<SegmentOrBox>::type, 353 typename point_type<MultiPoint>::type 354 >::type return_type; 355 apply(MultiPoint const & multipoint,SegmentOrBox const & segment_or_box,Strategy const & strategy)356 static inline return_type apply(MultiPoint const& multipoint, 357 SegmentOrBox const& segment_or_box, 358 Strategy const& strategy) 359 { 360 namespace sds = strategy::distance::services; 361 362 typename sds::return_type 363 < 364 typename sds::comparable_type<Strategy>::type, 365 typename point_type<SegmentOrBox>::type, 366 typename point_type<MultiPoint>::type 367 >::type cd_min; 368 369 iterator_type it_min 370 = geometry_to_range::apply(segment_or_box, 371 boost::begin(multipoint), 372 boost::end(multipoint), 373 sds::get_comparable 374 < 375 Strategy 376 >::apply(strategy), 377 cd_min); 378 379 return 380 is_comparable<Strategy>::value 381 ? 382 cd_min 383 : 384 dispatch::distance 385 < 386 typename point_type<MultiPoint>::type, 387 SegmentOrBox, 388 Strategy 389 >::apply(*it_min, segment_or_box, strategy); 390 } 391 }; 392 393 394 395 }} // namespace detail::distance 396 #endif // DOXYGEN_NO_DETAIL 397 398 399 400 #ifndef DOXYGEN_NO_DISPATCH 401 namespace dispatch 402 { 403 404 405 template <typename Linear, typename Segment, typename Strategy> 406 struct distance 407 < 408 Linear, Segment, Strategy, linear_tag, segment_tag, 409 strategy_tag_distance_point_segment, false 410 > : detail::distance::geometry_to_segment_or_box<Linear, Segment, Strategy> 411 {}; 412 413 414 template <typename Areal, typename Segment, typename Strategy> 415 struct distance 416 < 417 Areal, Segment, Strategy, areal_tag, segment_tag, 418 strategy_tag_distance_point_segment, false 419 > : detail::distance::geometry_to_segment_or_box<Areal, Segment, Strategy> 420 {}; 421 422 423 template <typename Segment, typename Areal, typename Strategy> 424 struct distance 425 < 426 Segment, Areal, Strategy, segment_tag, areal_tag, 427 strategy_tag_distance_point_segment, false 428 > : detail::distance::geometry_to_segment_or_box<Areal, Segment, Strategy> 429 {}; 430 431 432 template <typename Linear, typename Box, typename Strategy> 433 struct distance 434 < 435 Linear, Box, Strategy, linear_tag, box_tag, 436 strategy_tag_distance_point_segment, false 437 > : detail::distance::geometry_to_segment_or_box 438 < 439 Linear, Box, Strategy 440 > 441 {}; 442 443 444 template <typename Areal, typename Box, typename Strategy> 445 struct distance 446 < 447 Areal, Box, Strategy, areal_tag, box_tag, 448 strategy_tag_distance_point_segment, false 449 > : detail::distance::geometry_to_segment_or_box<Areal, Box, Strategy> 450 {}; 451 452 453 template <typename MultiPoint, typename Segment, typename Strategy> 454 struct distance 455 < 456 MultiPoint, Segment, Strategy, 457 multi_point_tag, segment_tag, 458 strategy_tag_distance_point_segment, false 459 > : detail::distance::geometry_to_segment_or_box 460 < 461 MultiPoint, Segment, Strategy 462 > 463 {}; 464 465 466 template <typename MultiPoint, typename Box, typename Strategy> 467 struct distance 468 < 469 MultiPoint, Box, Strategy, 470 multi_point_tag, box_tag, 471 strategy_tag_distance_point_box, false 472 > : detail::distance::geometry_to_segment_or_box 473 < 474 MultiPoint, Box, Strategy 475 > 476 {}; 477 478 479 } // namespace dispatch 480 #endif // DOXYGEN_NO_DISPATCH 481 482 483 }} // namespace boost::geometry 484 485 486 #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_GEOMETRY_TO_SEGMENT_OR_BOX_HPP 487