segment_to_box.hpp 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Copyright (c) 2023-2024 Adam Wulkiewicz, Lodz, Poland.
  3. // Copyright (c) 2014-2023 Oracle and/or its affiliates.
  4. // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
  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. // Licensed under the Boost Software License version 1.0.
  8. // http://www.boost.org/users/license.html
  9. #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_SEGMENT_TO_BOX_HPP
  10. #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_SEGMENT_TO_BOX_HPP
  11. #include <cstddef>
  12. #include <functional>
  13. #include <type_traits>
  14. #include <vector>
  15. #include <boost/core/ignore_unused.hpp>
  16. #include <boost/geometry/algorithms/detail/assign_box_corners.hpp>
  17. #include <boost/geometry/algorithms/detail/assign_indexed_point.hpp>
  18. #include <boost/geometry/algorithms/detail/closest_feature/point_to_range.hpp>
  19. #include <boost/geometry/algorithms/detail/disjoint/segment_box.hpp>
  20. #include <boost/geometry/algorithms/detail/distance/is_comparable.hpp>
  21. #include <boost/geometry/algorithms/detail/distance/strategy_utils.hpp>
  22. #include <boost/geometry/algorithms/detail/dummy_geometries.hpp>
  23. #include <boost/geometry/algorithms/detail/equals/point_point.hpp>
  24. #include <boost/geometry/algorithms/dispatch/distance.hpp>
  25. #include <boost/geometry/algorithms/not_implemented.hpp>
  26. #include <boost/geometry/core/access.hpp>
  27. #include <boost/geometry/core/assert.hpp>
  28. #include <boost/geometry/core/closure.hpp>
  29. #include <boost/geometry/core/coordinate_dimension.hpp>
  30. #include <boost/geometry/core/point_type.hpp>
  31. #include <boost/geometry/core/tags.hpp>
  32. #include <boost/geometry/policies/compare.hpp>
  33. #include <boost/geometry/util/calculation_type.hpp>
  34. #include <boost/geometry/util/constexpr.hpp>
  35. #include <boost/geometry/util/has_nan_coordinate.hpp>
  36. #include <boost/geometry/util/math.hpp>
  37. #include <boost/geometry/util/numeric_cast.hpp>
  38. #include <boost/geometry/strategies/disjoint.hpp>
  39. #include <boost/geometry/strategies/distance.hpp>
  40. #include <boost/geometry/strategies/tags.hpp>
  41. namespace boost { namespace geometry
  42. {
  43. #ifndef DOXYGEN_NO_DETAIL
  44. namespace detail { namespace distance
  45. {
  46. template <typename Segment, typename Box, typename Strategy>
  47. inline bool intersects_segment_box(Segment const& segment, Box const& box,
  48. Strategy const& strategy)
  49. {
  50. return ! detail::disjoint::disjoint_segment_box::apply(segment, box, strategy);
  51. }
  52. // TODO: segment_to_box_2D_generic is not used anymore. Remove?
  53. // TODO: Furthermore this utility can potentially use different strategy than
  54. // the one that was passed into bg::distance() but it seems this is by design.
  55. template
  56. <
  57. typename Segment,
  58. typename Box,
  59. typename Strategies,
  60. bool UsePointBoxStrategy = false // use only PointSegment strategy
  61. >
  62. class segment_to_box_2D_generic
  63. {
  64. private:
  65. typedef typename point_type<Segment>::type segment_point;
  66. typedef typename point_type<Box>::type box_point;
  67. typedef distance::strategy_t<box_point, Segment, Strategies> ps_strategy_type;
  68. typedef detail::closest_feature::point_to_point_range
  69. <
  70. segment_point,
  71. std::vector<box_point>,
  72. open
  73. > point_to_point_range;
  74. public:
  75. // TODO: Or should the return type be defined by sb_strategy_type?
  76. typedef distance::return_t<box_point, Segment, Strategies> return_type;
  77. static inline return_type apply(Segment const& segment,
  78. Box const& box,
  79. Strategies const& strategies,
  80. bool check_intersection = true)
  81. {
  82. if (check_intersection && intersects_segment_box(segment, box, strategies))
  83. {
  84. return return_type(0);
  85. }
  86. // get segment points
  87. segment_point p[2];
  88. detail::assign_point_from_index<0>(segment, p[0]);
  89. detail::assign_point_from_index<1>(segment, p[1]);
  90. // get box points
  91. std::vector<box_point> box_points(4);
  92. detail::assign_box_corners_oriented<true>(box, box_points);
  93. ps_strategy_type const strategy = strategies.distance(dummy_point(), dummy_segment());
  94. auto const cstrategy = strategy::distance::services::get_comparable
  95. <
  96. ps_strategy_type
  97. >::apply(strategy);
  98. distance::creturn_t<box_point, Segment, Strategies> cd[6];
  99. for (unsigned int i = 0; i < 4; ++i)
  100. {
  101. cd[i] = cstrategy.apply(box_points[i], p[0], p[1]);
  102. }
  103. std::pair
  104. <
  105. typename std::vector<box_point>::const_iterator,
  106. typename std::vector<box_point>::const_iterator
  107. > bit_min[2];
  108. bit_min[0] = point_to_point_range::apply(p[0],
  109. box_points.begin(),
  110. box_points.end(),
  111. cstrategy,
  112. cd[4]);
  113. bit_min[1] = point_to_point_range::apply(p[1],
  114. box_points.begin(),
  115. box_points.end(),
  116. cstrategy,
  117. cd[5]);
  118. unsigned int imin = 0;
  119. for (unsigned int i = 1; i < 6; ++i)
  120. {
  121. if (cd[i] < cd[imin])
  122. {
  123. imin = i;
  124. }
  125. }
  126. if BOOST_GEOMETRY_CONSTEXPR (is_comparable<ps_strategy_type>::value)
  127. {
  128. return cd[imin];
  129. }
  130. else // else prevents unreachable code warning
  131. {
  132. if (imin < 4)
  133. {
  134. return strategy.apply(box_points[imin], p[0], p[1]);
  135. }
  136. else
  137. {
  138. unsigned int bimin = imin - 4;
  139. return strategy.apply(p[bimin],
  140. *bit_min[bimin].first,
  141. *bit_min[bimin].second);
  142. }
  143. }
  144. }
  145. };
  146. template
  147. <
  148. typename Segment,
  149. typename Box,
  150. typename Strategies
  151. >
  152. class segment_to_box_2D_generic<Segment, Box, Strategies, true> // Use both PointSegment and PointBox strategies
  153. {
  154. private:
  155. typedef typename point_type<Segment>::type segment_point;
  156. typedef typename point_type<Box>::type box_point;
  157. typedef distance::strategy_t<box_point, Segment, Strategies> ps_strategy_type;
  158. typedef distance::strategy_t<segment_point, Box, Strategies> pb_strategy_type;
  159. public:
  160. // TODO: Or should the return type be defined by sb_strategy_type?
  161. typedef distance::return_t<box_point, Segment, Strategies> return_type;
  162. static inline return_type apply(Segment const& segment,
  163. Box const& box,
  164. Strategies const& strategies,
  165. bool check_intersection = true)
  166. {
  167. if (check_intersection && intersects_segment_box(segment, box, strategies))
  168. {
  169. return return_type(0);
  170. }
  171. // get segment points
  172. segment_point p[2];
  173. detail::assign_point_from_index<0>(segment, p[0]);
  174. detail::assign_point_from_index<1>(segment, p[1]);
  175. // get box points
  176. std::vector<box_point> box_points(4);
  177. detail::assign_box_corners_oriented<true>(box, box_points);
  178. distance::creturn_t<box_point, Segment, Strategies> cd[6];
  179. ps_strategy_type ps_strategy = strategies.distance(dummy_point(), dummy_segment());
  180. auto const ps_cstrategy = strategy::distance::services::get_comparable
  181. <
  182. ps_strategy_type
  183. >::apply(ps_strategy);
  184. boost::ignore_unused(ps_strategy, ps_cstrategy);
  185. for (unsigned int i = 0; i < 4; ++i)
  186. {
  187. cd[i] = ps_cstrategy.apply(box_points[i], p[0], p[1]);
  188. }
  189. pb_strategy_type const pb_strategy = strategies.distance(dummy_point(), dummy_box());
  190. auto const pb_cstrategy = strategy::distance::services::get_comparable
  191. <
  192. pb_strategy_type
  193. >::apply(pb_strategy);
  194. boost::ignore_unused(pb_strategy, pb_cstrategy);
  195. cd[4] = pb_cstrategy.apply(p[0], box);
  196. cd[5] = pb_cstrategy.apply(p[1], box);
  197. unsigned int imin = 0;
  198. for (unsigned int i = 1; i < 6; ++i)
  199. {
  200. if (cd[i] < cd[imin])
  201. {
  202. imin = i;
  203. }
  204. }
  205. if (imin < 4)
  206. {
  207. if (is_comparable<ps_strategy_type>::value)
  208. {
  209. return cd[imin];
  210. }
  211. return ps_strategy.apply(box_points[imin], p[0], p[1]);
  212. }
  213. else
  214. {
  215. if (is_comparable<pb_strategy_type>::value)
  216. {
  217. return cd[imin];
  218. }
  219. return pb_strategy.apply(p[imin - 4], box);
  220. }
  221. }
  222. };
  223. template
  224. <
  225. typename ReturnType,
  226. typename SegmentPoint,
  227. typename BoxPoint,
  228. typename Strategies
  229. >
  230. class segment_to_box_2D
  231. {
  232. private:
  233. template <typename Result>
  234. struct cast_to_result
  235. {
  236. template <typename T>
  237. static inline Result apply(T const& t)
  238. {
  239. return util::numeric_cast<Result>(t);
  240. }
  241. };
  242. template <typename T, bool IsLess /* true */>
  243. struct compare_less_equal
  244. {
  245. typedef compare_less_equal<T, !IsLess> other;
  246. template <typename T1, typename T2>
  247. inline bool operator()(T1 const& t1, T2 const& t2) const
  248. {
  249. return std::less_equal<T>()(cast_to_result<T>::apply(t1),
  250. cast_to_result<T>::apply(t2));
  251. }
  252. };
  253. template <typename T>
  254. struct compare_less_equal<T, false>
  255. {
  256. typedef compare_less_equal<T, true> other;
  257. template <typename T1, typename T2>
  258. inline bool operator()(T1 const& t1, T2 const& t2) const
  259. {
  260. return std::greater_equal<T>()(cast_to_result<T>::apply(t1),
  261. cast_to_result<T>::apply(t2));
  262. }
  263. };
  264. template <typename LessEqual>
  265. struct other_compare
  266. {
  267. typedef typename LessEqual::other type;
  268. };
  269. // it is assumed here that p0 lies to the right of the box (so the
  270. // entire segment lies to the right of the box)
  271. template <typename LessEqual>
  272. struct right_of_box
  273. {
  274. static inline ReturnType apply(SegmentPoint const& p0,
  275. SegmentPoint const& p1,
  276. BoxPoint const& bottom_right,
  277. BoxPoint const& top_right,
  278. Strategies const& strategies)
  279. {
  280. // the implementation below is written for non-negative slope
  281. // segments
  282. //
  283. // for negative slope segments swap the roles of bottom_right
  284. // and top_right and use greater_equal instead of less_equal.
  285. typedef cast_to_result<ReturnType> cast;
  286. LessEqual less_equal;
  287. auto const ps_strategy = strategies.distance(dummy_point(), dummy_segment());
  288. if (less_equal(geometry::get<1>(bottom_right), geometry::get<1>(p0)))
  289. {
  290. //if p0 is in box's band
  291. if (less_equal(geometry::get<1>(p0), geometry::get<1>(top_right)))
  292. {
  293. // segment & crosses band (TODO:merge with box-box dist)
  294. if (math::equals(geometry::get<0>(p0), geometry::get<0>(p1)))
  295. {
  296. SegmentPoint high = geometry::get<1>(p1) > geometry::get<1>(p0) ? p1 : p0;
  297. if (less_equal(geometry::get<1>(high), geometry::get<1>(top_right)))
  298. {
  299. return cast::apply(ps_strategy.apply(high, bottom_right, top_right));
  300. }
  301. return cast::apply(ps_strategy.apply(top_right, p0, p1));
  302. }
  303. return cast::apply(ps_strategy.apply(p0, bottom_right, top_right));
  304. }
  305. // distance is realized between the top-right
  306. // corner of the box and the segment
  307. return cast::apply(ps_strategy.apply(top_right, p0, p1));
  308. }
  309. else
  310. {
  311. // distance is realized between the bottom-right
  312. // corner of the box and the segment
  313. return cast::apply(ps_strategy.apply(bottom_right, p0, p1));
  314. }
  315. }
  316. };
  317. // it is assumed here that p0 lies above the box (so the
  318. // entire segment lies above the box)
  319. template <typename LessEqual>
  320. struct above_of_box
  321. {
  322. static inline ReturnType apply(SegmentPoint const& p0,
  323. SegmentPoint const& p1,
  324. BoxPoint const& top_left,
  325. Strategies const& strategies)
  326. {
  327. return apply(p0, p1, p0, top_left, strategies);
  328. }
  329. static inline ReturnType apply(SegmentPoint const& p0,
  330. SegmentPoint const& p1,
  331. SegmentPoint const& p_max,
  332. BoxPoint const& top_left,
  333. Strategies const& strategies)
  334. {
  335. auto const ps_strategy = strategies.distance(dummy_point(), dummy_segment());
  336. typedef cast_to_result<ReturnType> cast;
  337. LessEqual less_equal;
  338. // p0 is above the upper segment of the box (and inside its band)
  339. // then compute the vertical (i.e. meridian for spherical) distance
  340. if (less_equal(geometry::get<0>(top_left), geometry::get<0>(p_max)))
  341. {
  342. ReturnType diff = ps_strategy.vertical_or_meridian(
  343. geometry::get_as_radian<1>(p_max),
  344. geometry::get_as_radian<1>(top_left));
  345. return strategy::distance::services::result_from_distance
  346. <
  347. std::remove_const_t<decltype(ps_strategy)>,
  348. SegmentPoint, BoxPoint
  349. >::apply(ps_strategy, math::abs(diff));
  350. }
  351. // p0 is to the left of the box, but p1 is above the box
  352. // in this case the distance is realized between the
  353. // top-left corner of the box and the segment
  354. return cast::apply(ps_strategy.apply(top_left, p0, p1));
  355. }
  356. };
  357. template <typename LessEqual>
  358. struct check_right_left_of_box
  359. {
  360. static inline bool apply(SegmentPoint const& p0,
  361. SegmentPoint const& p1,
  362. BoxPoint const& top_left,
  363. BoxPoint const& top_right,
  364. BoxPoint const& bottom_left,
  365. BoxPoint const& bottom_right,
  366. Strategies const& strategies,
  367. ReturnType& result)
  368. {
  369. // p0 lies to the right of the box
  370. if (geometry::get<0>(p0) >= geometry::get<0>(top_right))
  371. {
  372. result = right_of_box
  373. <
  374. LessEqual
  375. >::apply(p0, p1, bottom_right, top_right,
  376. strategies);
  377. return true;
  378. }
  379. // p1 lies to the left of the box
  380. if (geometry::get<0>(p1) <= geometry::get<0>(bottom_left))
  381. {
  382. result = right_of_box
  383. <
  384. typename other_compare<LessEqual>::type
  385. >::apply(p1, p0, top_left, bottom_left,
  386. strategies);
  387. return true;
  388. }
  389. return false;
  390. }
  391. };
  392. template <typename LessEqual>
  393. struct check_above_below_of_box
  394. {
  395. static inline bool apply(SegmentPoint const& p0,
  396. SegmentPoint const& p1,
  397. BoxPoint const& top_left,
  398. BoxPoint const& top_right,
  399. BoxPoint const& bottom_left,
  400. BoxPoint const& bottom_right,
  401. Strategies const& strategies,
  402. ReturnType& result)
  403. {
  404. typedef compare_less_equal<ReturnType, false> GreaterEqual;
  405. // the segment lies below the box
  406. if (geometry::get<1>(p1) < geometry::get<1>(bottom_left))
  407. {
  408. auto const sb_strategy = strategies.distance(dummy_segment(), dummy_box());
  409. // TODO: this strategy calls this algorithm's again, specifically:
  410. // geometry::detail::distance::segment_to_box_2D<>::call_above_of_box
  411. // If possible rewrite them to avoid this.
  412. // For now just pass umbrella strategy.
  413. result = sb_strategy.template segment_below_of_box
  414. <
  415. LessEqual,
  416. ReturnType
  417. >(p0, p1,
  418. top_left, top_right,
  419. bottom_left, bottom_right,
  420. strategies);
  421. return true;
  422. }
  423. // the segment lies above the box
  424. if (geometry::get<1>(p0) > geometry::get<1>(top_right))
  425. {
  426. result = (std::min)(above_of_box
  427. <
  428. LessEqual
  429. >::apply(p0, p1, top_left, strategies),
  430. above_of_box
  431. <
  432. GreaterEqual
  433. >::apply(p1, p0, top_right, strategies));
  434. return true;
  435. }
  436. return false;
  437. }
  438. };
  439. struct check_generic_position
  440. {
  441. static inline bool apply(SegmentPoint const& p0,
  442. SegmentPoint const& p1,
  443. BoxPoint const& corner1,
  444. BoxPoint const& corner2,
  445. Strategies const& strategies,
  446. ReturnType& result)
  447. {
  448. auto const side_strategy = strategies.side();
  449. auto const ps_strategy = strategies.distance(dummy_point(), dummy_segment());
  450. typedef cast_to_result<ReturnType> cast;
  451. ReturnType diff1 = cast::apply(geometry::get<1>(p1))
  452. - cast::apply(geometry::get<1>(p0));
  453. int sign = diff1 < 0 ? -1 : 1;
  454. if (side_strategy.apply(p0, p1, corner1) * sign < 0)
  455. {
  456. result = cast::apply(ps_strategy.apply(corner1, p0, p1));
  457. return true;
  458. }
  459. if (side_strategy.apply(p0, p1, corner2) * sign > 0)
  460. {
  461. result = cast::apply(ps_strategy.apply(corner2, p0, p1));
  462. return true;
  463. }
  464. return false;
  465. }
  466. };
  467. static inline ReturnType
  468. non_negative_slope_segment(SegmentPoint const& p0,
  469. SegmentPoint const& p1,
  470. BoxPoint const& top_left,
  471. BoxPoint const& top_right,
  472. BoxPoint const& bottom_left,
  473. BoxPoint const& bottom_right,
  474. Strategies const& strategies)
  475. {
  476. typedef compare_less_equal<ReturnType, true> less_equal;
  477. // assert that the segment has non-negative slope
  478. BOOST_GEOMETRY_ASSERT( ( math::equals(geometry::get<0>(p0), geometry::get<0>(p1))
  479. && geometry::get<1>(p0) < geometry::get<1>(p1))
  480. ||
  481. ( geometry::get<0>(p0) < geometry::get<0>(p1)
  482. && geometry::get<1>(p0) <= geometry::get<1>(p1) )
  483. || geometry::has_nan_coordinate(p0)
  484. || geometry::has_nan_coordinate(p1));
  485. ReturnType result(0);
  486. if (check_right_left_of_box
  487. <
  488. less_equal
  489. >::apply(p0, p1,
  490. top_left, top_right, bottom_left, bottom_right,
  491. strategies, result))
  492. {
  493. return result;
  494. }
  495. if (check_above_below_of_box
  496. <
  497. less_equal
  498. >::apply(p0, p1,
  499. top_left, top_right, bottom_left, bottom_right,
  500. strategies, result))
  501. {
  502. return result;
  503. }
  504. if (check_generic_position::apply(p0, p1,
  505. top_left, bottom_right,
  506. strategies, result))
  507. {
  508. return result;
  509. }
  510. // in all other cases the box and segment intersect, so return 0
  511. return result;
  512. }
  513. static inline ReturnType
  514. negative_slope_segment(SegmentPoint const& p0,
  515. SegmentPoint const& p1,
  516. BoxPoint const& top_left,
  517. BoxPoint const& top_right,
  518. BoxPoint const& bottom_left,
  519. BoxPoint const& bottom_right,
  520. Strategies const& strategies)
  521. {
  522. typedef compare_less_equal<ReturnType, false> greater_equal;
  523. // assert that the segment has negative slope
  524. BOOST_GEOMETRY_ASSERT( ( geometry::get<0>(p0) < geometry::get<0>(p1)
  525. && geometry::get<1>(p0) > geometry::get<1>(p1) )
  526. || geometry::has_nan_coordinate(p0)
  527. || geometry::has_nan_coordinate(p1) );
  528. ReturnType result(0);
  529. if (check_right_left_of_box
  530. <
  531. greater_equal
  532. >::apply(p0, p1,
  533. bottom_left, bottom_right, top_left, top_right,
  534. strategies, result))
  535. {
  536. return result;
  537. }
  538. if (check_above_below_of_box
  539. <
  540. greater_equal
  541. >::apply(p1, p0,
  542. top_right, top_left, bottom_right, bottom_left,
  543. strategies, result))
  544. {
  545. return result;
  546. }
  547. if (check_generic_position::apply(p0, p1,
  548. bottom_left, top_right,
  549. strategies, result))
  550. {
  551. return result;
  552. }
  553. // in all other cases the box and segment intersect, so return 0
  554. return result;
  555. }
  556. public:
  557. static inline ReturnType apply(SegmentPoint const& p0,
  558. SegmentPoint const& p1,
  559. BoxPoint const& top_left,
  560. BoxPoint const& top_right,
  561. BoxPoint const& bottom_left,
  562. BoxPoint const& bottom_right,
  563. Strategies const& strategies)
  564. {
  565. BOOST_GEOMETRY_ASSERT( (geometry::less<SegmentPoint, -1, Strategies>()(p0, p1))
  566. || geometry::has_nan_coordinate(p0)
  567. || geometry::has_nan_coordinate(p1) );
  568. if (geometry::get<0>(p0) < geometry::get<0>(p1)
  569. && geometry::get<1>(p0) > geometry::get<1>(p1))
  570. {
  571. return negative_slope_segment(p0, p1,
  572. top_left, top_right,
  573. bottom_left, bottom_right,
  574. strategies);
  575. }
  576. return non_negative_slope_segment(p0, p1,
  577. top_left, top_right,
  578. bottom_left, bottom_right,
  579. strategies);
  580. }
  581. template <typename LessEqual>
  582. static inline ReturnType call_above_of_box(SegmentPoint const& p0,
  583. SegmentPoint const& p1,
  584. SegmentPoint const& p_max,
  585. BoxPoint const& top_left,
  586. Strategies const& strategies)
  587. {
  588. return above_of_box<LessEqual>::apply(p0, p1, p_max, top_left, strategies);
  589. }
  590. template <typename LessEqual>
  591. static inline ReturnType call_above_of_box(SegmentPoint const& p0,
  592. SegmentPoint const& p1,
  593. BoxPoint const& top_left,
  594. Strategies const& strategies)
  595. {
  596. return above_of_box<LessEqual>::apply(p0, p1, top_left, strategies);
  597. }
  598. };
  599. //=========================================================================
  600. template
  601. <
  602. typename Segment,
  603. typename Box,
  604. typename std::size_t Dimension,
  605. typename Strategies
  606. >
  607. class segment_to_box
  608. : not_implemented<Segment, Box>
  609. {};
  610. template
  611. <
  612. typename Segment,
  613. typename Box,
  614. typename Strategies
  615. >
  616. class segment_to_box<Segment, Box, 2, Strategies>
  617. {
  618. typedef distance::strategy_t<Segment, Box, Strategies> strategy_type;
  619. public:
  620. typedef distance::return_t<Segment, Box, Strategies> return_type;
  621. static inline return_type apply(Segment const& segment,
  622. Box const& box,
  623. Strategies const& strategies)
  624. {
  625. typedef typename point_type<Segment>::type segment_point;
  626. typedef typename point_type<Box>::type box_point;
  627. segment_point p[2];
  628. detail::assign_point_from_index<0>(segment, p[0]);
  629. detail::assign_point_from_index<1>(segment, p[1]);
  630. if (detail::equals::equals_point_point(p[0], p[1], strategies))
  631. {
  632. return dispatch::distance
  633. <
  634. segment_point,
  635. Box,
  636. Strategies
  637. >::apply(p[0], box, strategies);
  638. }
  639. box_point top_left, top_right, bottom_left, bottom_right;
  640. detail::assign_box_corners(box, bottom_left, bottom_right,
  641. top_left, top_right);
  642. strategy_type::mirror(p[0], p[1],
  643. bottom_left, bottom_right,
  644. top_left, top_right);
  645. typedef geometry::less<segment_point, -1, Strategies> less_type;
  646. if (less_type()(p[0], p[1]))
  647. {
  648. return segment_to_box_2D
  649. <
  650. return_type,
  651. segment_point,
  652. box_point,
  653. Strategies
  654. >::apply(p[0], p[1],
  655. top_left, top_right, bottom_left, bottom_right,
  656. strategies);
  657. }
  658. else
  659. {
  660. return segment_to_box_2D
  661. <
  662. return_type,
  663. segment_point,
  664. box_point,
  665. Strategies
  666. >::apply(p[1], p[0],
  667. top_left, top_right, bottom_left, bottom_right,
  668. strategies);
  669. }
  670. }
  671. };
  672. }} // namespace detail::distance
  673. #endif // DOXYGEN_NO_DETAIL
  674. #ifndef DOXYGEN_NO_DISPATCH
  675. namespace dispatch
  676. {
  677. template <typename Segment, typename Box, typename Strategies>
  678. struct distance
  679. <
  680. Segment, Box, Strategies, segment_tag, box_tag,
  681. strategy_tag_distance_segment_box, false
  682. >
  683. {
  684. static inline auto apply(Segment const& segment, Box const& box,
  685. Strategies const& strategies)
  686. {
  687. assert_dimension_equal<Segment, Box>();
  688. return detail::distance::segment_to_box
  689. <
  690. Segment,
  691. Box,
  692. dimension<Segment>::value,
  693. Strategies
  694. >::apply(segment, box, strategies);
  695. }
  696. };
  697. } // namespace dispatch
  698. #endif // DOXYGEN_NO_DISPATCH
  699. }} // namespace boost::geometry
  700. #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_SEGMENT_TO_BOX_HPP