From e4e7bd4a286997d244ac9a777dc916dcb60ebc4a Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Fri, 3 May 2013 20:36:29 +0000 Subject: [PATCH] geometry.index: added segment_intersection algorithm. [SVN r84129] --- .../algorithms/segment_intersection.hpp | 141 ++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 include/boost/geometry/index/detail/algorithms/segment_intersection.hpp diff --git a/include/boost/geometry/index/detail/algorithms/segment_intersection.hpp b/include/boost/geometry/index/detail/algorithms/segment_intersection.hpp new file mode 100644 index 000000000..b4389a8ec --- /dev/null +++ b/include/boost/geometry/index/detail/algorithms/segment_intersection.hpp @@ -0,0 +1,141 @@ +// Boost.Geometry Index +// +// n-dimensional box-segment intersection +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_SEGMENT_INTERSECTION_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_SEGMENT_INTERSECTION_HPP + +#include + +namespace boost { namespace geometry { namespace index { namespace detail { + +template +struct default_relative_distance_type +{ + typedef typename select_most_precise< + typename select_most_precise< + typename traits::coordinate_type::type, + typename traits::coordinate_type::type + >::type, + float // TODO - use bigger type, calculated from the size of coordinate types + >::type type; + + + BOOST_MPL_ASSERT_MSG((!::boost::is_unsigned::value), + THIS_TYPE_SHOULDNT_BE_UNSIGNED, (type)); +}; + +namespace dispatch { + +template +struct box_segment_intersection_dim +{ + BOOST_STATIC_ASSERT(I < traits::dimension::value); + BOOST_STATIC_ASSERT(I < traits::dimension::value); + BOOST_STATIC_ASSERT(traits::dimension::value == traits::dimension::value); + + typedef typename default_relative_distance_type::type relative_distance_type; + + // WARNING! - relative_distance_type must be IEEE float for this to work + + static inline bool apply(Box const& b, Point const& p0, Point const& p1, + relative_distance_type & t_near, relative_distance_type & t_far) + { + relative_distance_type ray_d = geometry::get(p1) - geometry::get(p0); + relative_distance_type tn = ( detail::get(b) - geometry::get(p0) ) / ray_d; + relative_distance_type tf = ( detail::get(b) - geometry::get(p0) ) / ray_d; + if ( tf < tn ) + ::std::swap(tn, tf); + + if ( t_near < tn ) + t_near = tn; + if ( tf < t_far ) + t_far = tf; + + return 0 <= t_far && t_near <= t_far; + } +}; + +template +struct box_segment_intersection +{ + BOOST_STATIC_ASSERT(0 < CurrentDimension); + + typedef box_segment_intersection_dim for_dim; + typedef typename for_dim::relative_distance_type relative_distance_type; + + static inline bool apply(Box const& b, Point const& p0, Point const& p1, + relative_distance_type & t_near, relative_distance_type & t_far) + { + return box_segment_intersection::apply(b, p0, p1, t_near, t_far) + && for_dim::apply(b, p0, p1, t_near, t_far); + } +}; + +template +struct box_segment_intersection +{ + typedef box_segment_intersection_dim for_dim; + typedef typename for_dim::relative_distance_type relative_distance_type; + + static inline bool apply(Box const& b, Point const& p0, Point const& p1, + relative_distance_type & t_near, relative_distance_type & t_far) + { + return for_dim::apply(b, p0, p1, t_near, t_far); + } +}; + +template +struct segment_intersection +{ + BOOST_MPL_ASSERT_MSG((false), NOT_IMPLEMENTED_FOR_THIS_GEOMETRY, (segment_intersection)); +}; + +template +struct segment_intersection +{ + BOOST_MPL_ASSERT_MSG((false), SEGMENT_POINT_INTERSECTION_UNAVAILABLE, (segment_intersection)); +}; + +template +struct segment_intersection +{ + typedef dispatch::box_segment_intersection::value> impl; + typedef typename impl::relative_distance_type relative_distance_type; + + static inline bool apply(Indexable const& b, Point const& p0, Point const& p1, relative_distance_type & relative_distance) + { + relative_distance_type t_near = -(::std::numeric_limits::max)(); + relative_distance_type t_far = (::std::numeric_limits::max)(); + + return impl::apply(b, p0, p1, t_near, t_far) && + (t_near <= 1) && + ( relative_distance = 0 < t_near ? t_near : 0, true ); + } +}; + +} // namespace dispatch + +template inline +bool segment_intersection(Indexable const& b, + Point const& p0, + Point const& p1, + typename default_relative_distance_type::type & relative_distance) +{ + // TODO check Indexable and Point concepts + + return dispatch::segment_intersection< + Indexable, Point, + typename detail::traits::tag::type + >::apply(b, p0, p1, relative_distance); +} + +}}}} // namespace boost::geometry::index::detail + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_SEGMENT_INTERSECTION_HPP