segment_intersection.hpp 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. // Boost.Geometry Index
  2. //
  3. // n-dimensional box-segment intersection
  4. //
  5. // Copyright (c) 2011-2014 Adam Wulkiewicz, Lodz, Poland.
  6. //
  7. // This file was modified by Oracle on 2020-2021.
  8. // Modifications copyright (c) 2020-2021, Oracle and/or its affiliates.
  9. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
  10. //
  11. // Use, modification and distribution is subject to the Boost Software License,
  12. // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  13. // http://www.boost.org/LICENSE_1_0.txt)
  14. #ifndef BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_SEGMENT_INTERSECTION_HPP
  15. #define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_SEGMENT_INTERSECTION_HPP
  16. #include <limits>
  17. #include <type_traits>
  18. #include <boost/geometry/core/access.hpp>
  19. #include <boost/geometry/core/coordinate_dimension.hpp>
  20. #include <boost/geometry/core/static_assert.hpp>
  21. #include <boost/geometry/core/tag.hpp>
  22. #include <boost/geometry/core/tags.hpp>
  23. namespace boost { namespace geometry { namespace index { namespace detail {
  24. //template <typename Indexable, typename Point>
  25. //struct default_relative_distance_type
  26. //{
  27. // typedef typename select_most_precise<
  28. // typename select_most_precise<
  29. // typename coordinate_type<Indexable>::type,
  30. // typename coordinate_type<Point>::type
  31. // >::type,
  32. // float // TODO - use bigger type, calculated from the size of coordinate types
  33. // >::type type;
  34. //
  35. //
  36. // BOOST_GEOMETRY_STATIC_ASSERT((!std::is_unsigned<type>::value),
  37. // "Distance type can not be unsigned.", type);
  38. //};
  39. namespace dispatch {
  40. template <typename Box, typename Point, size_t I>
  41. struct box_segment_intersection_dim
  42. {
  43. BOOST_STATIC_ASSERT(0 <= dimension<Box>::value);
  44. BOOST_STATIC_ASSERT(0 <= dimension<Point>::value);
  45. BOOST_STATIC_ASSERT(I < size_t(dimension<Box>::value));
  46. BOOST_STATIC_ASSERT(I < size_t(dimension<Point>::value));
  47. BOOST_STATIC_ASSERT(dimension<Point>::value == dimension<Box>::value);
  48. // WARNING! - RelativeDistance must be IEEE float for this to work
  49. template <typename RelativeDistance>
  50. static inline bool apply(Box const& b, Point const& p0, Point const& p1,
  51. RelativeDistance & t_near, RelativeDistance & t_far)
  52. {
  53. RelativeDistance ray_d = geometry::get<I>(p1) - geometry::get<I>(p0);
  54. RelativeDistance tn = ( geometry::get<min_corner, I>(b) - geometry::get<I>(p0) ) / ray_d;
  55. RelativeDistance tf = ( geometry::get<max_corner, I>(b) - geometry::get<I>(p0) ) / ray_d;
  56. if ( tf < tn )
  57. ::std::swap(tn, tf);
  58. if ( t_near < tn )
  59. t_near = tn;
  60. if ( tf < t_far )
  61. t_far = tf;
  62. return 0 <= t_far && t_near <= t_far;
  63. }
  64. };
  65. template <typename Box, typename Point, size_t CurrentDimension>
  66. struct box_segment_intersection
  67. {
  68. BOOST_STATIC_ASSERT(0 < CurrentDimension);
  69. typedef box_segment_intersection_dim<Box, Point, CurrentDimension - 1> for_dim;
  70. template <typename RelativeDistance>
  71. static inline bool apply(Box const& b, Point const& p0, Point const& p1,
  72. RelativeDistance & t_near, RelativeDistance & t_far)
  73. {
  74. return box_segment_intersection<Box, Point, CurrentDimension - 1>::apply(b, p0, p1, t_near, t_far)
  75. && for_dim::apply(b, p0, p1, t_near, t_far);
  76. }
  77. };
  78. template <typename Box, typename Point>
  79. struct box_segment_intersection<Box, Point, 1>
  80. {
  81. typedef box_segment_intersection_dim<Box, Point, 0> for_dim;
  82. template <typename RelativeDistance>
  83. static inline bool apply(Box const& b, Point const& p0, Point const& p1,
  84. RelativeDistance & t_near, RelativeDistance & t_far)
  85. {
  86. return for_dim::apply(b, p0, p1, t_near, t_far);
  87. }
  88. };
  89. template <typename Indexable, typename Point, typename Tag>
  90. struct segment_intersection
  91. {
  92. BOOST_GEOMETRY_STATIC_ASSERT_FALSE(
  93. "Not implemented for this Indexable type.",
  94. Indexable, Point, Tag);
  95. };
  96. template <typename Indexable, typename Point>
  97. struct segment_intersection<Indexable, Point, point_tag>
  98. {
  99. BOOST_GEOMETRY_STATIC_ASSERT_FALSE(
  100. "Segment-Point intersection unavailable.",
  101. Indexable, Point);
  102. };
  103. template <typename Indexable, typename Point>
  104. struct segment_intersection<Indexable, Point, box_tag>
  105. {
  106. typedef dispatch::box_segment_intersection<Indexable, Point, dimension<Indexable>::value> impl;
  107. template <typename RelativeDistance>
  108. static inline bool apply(Indexable const& b, Point const& p0, Point const& p1, RelativeDistance & relative_distance)
  109. {
  110. // TODO: this ASSERT CHECK is wrong for user-defined CoordinateTypes!
  111. static const bool check = !std::is_integral<RelativeDistance>::value;
  112. BOOST_GEOMETRY_STATIC_ASSERT(check,
  113. "RelativeDistance must be a floating point type.",
  114. RelativeDistance);
  115. RelativeDistance t_near = -(::std::numeric_limits<RelativeDistance>::max)();
  116. RelativeDistance t_far = (::std::numeric_limits<RelativeDistance>::max)();
  117. return impl::apply(b, p0, p1, t_near, t_far) &&
  118. (t_near <= 1) &&
  119. ( relative_distance = 0 < t_near ? t_near : 0, true );
  120. }
  121. };
  122. } // namespace dispatch
  123. template <typename Indexable, typename Point, typename RelativeDistance> inline
  124. bool segment_intersection(Indexable const& b,
  125. Point const& p0,
  126. Point const& p1,
  127. RelativeDistance & relative_distance)
  128. {
  129. // TODO check Indexable and Point concepts
  130. return dispatch::segment_intersection<
  131. Indexable, Point,
  132. typename tag<Indexable>::type
  133. >::apply(b, p0, p1, relative_distance);
  134. }
  135. }}}} // namespace boost::geometry::index::detail
  136. #endif // BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_SEGMENT_INTERSECTION_HPP