Index: algorithms/disjoint.hpp =================================================================== --- algorithms/disjoint.hpp (revision 85549) +++ algorithms/disjoint.hpp (working copy) @@ -3,6 +3,7 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. +// Copyright (c) 2013 Adam Wulkiewicz, Lodz, Poland. // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. @@ -172,7 +173,51 @@ } }; +template +struct disjoint_segment_box +{ + static inline bool apply(Segment const& segment, Box const& box) + { + typedef typename point_type::type point_type; + point_type p0, p1; + geometry::detail::assign_point_from_index<0>(segment, p0); + geometry::detail::assign_point_from_index<1>(segment, p1); + return ! strategy::intersection::detail::segment_box_intersection::apply(p0, p1, box); + } +}; + +template +struct disjoint_linestring_box +{ + static inline bool apply(Linestring const& linestring, Box const& box) + { + typedef typename ::boost::range_value::type point_type; + typedef typename ::boost::range_const_iterator::type const_iterator; + typedef typename ::boost::range_size::type size_type; + + const size_type count = ::boost::size(linestring); + + if ( count == 0 ) + return false; + else if ( count == 1 ) + return geometry::intersects(*::boost::begin(linestring), box); + else + { + const_iterator it0 = ::boost::begin(linestring); + const_iterator it1 = ::boost::begin(linestring) + 1; + const_iterator last = ::boost::end(linestring); + + for ( ; it1 != last ; ++it0, ++it1 ) + { + if ( strategy::intersection::detail::segment_box_intersection::apply(*it0, *it1, box) ) + return false; + } + return true; + } + } +}; + }} // namespace detail::disjoint #endif // DOXYGEN_NO_DETAIL @@ -249,9 +294,9 @@ : detail::disjoint::disjoint_linear {}; -template -struct disjoint - : detail::disjoint::disjoint_segment +template +struct disjoint + : detail::disjoint::disjoint_segment {}; template @@ -259,7 +304,16 @@ : detail::disjoint::disjoint_linear {}; +template +struct disjoint + : detail::disjoint::disjoint_segment_box +{}; +template +struct disjoint + : detail::disjoint::disjoint_linestring_box +{}; + } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH Index: strategies/cartesian/cart_intersect.hpp =================================================================== --- strategies/cartesian/cart_intersect.hpp (revision 85549) +++ strategies/cartesian/cart_intersect.hpp (working copy) @@ -1,6 +1,7 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 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 @@ -746,8 +747,107 @@ }} // namespace strategy::intersection +// Segment - Box intersection +// Based on Ray-AABB intersection +// http://www.siggraph.org/education/materials/HyperGraph/raytrace/rtinter3.htm +// TODO - probably add a policy to conditionally extract intersection points +namespace strategy { namespace intersection { + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { + +template +struct segment_box_intersection_dim +{ + BOOST_STATIC_ASSERT(I < dimension::value); + BOOST_STATIC_ASSERT(I < dimension::value); + BOOST_STATIC_ASSERT(dimension::value == dimension::value); + + template + static inline bool apply(Point const& p0, Point const& p1, Box const& b, + RelativeDistance & t_near, RelativeDistance & t_far) + { + // WARNING! - RelativeDistance must be IEEE float for this to work (division by 0) + BOOST_STATIC_ASSERT(boost::is_float::value); + + // Ray origin is in segment point 0 + RelativeDistance ray_d = geometry::get(p1) - geometry::get(p0); + RelativeDistance tn = ( geometry::get(b) - geometry::get(p0) ) / ray_d; + RelativeDistance tf = ( geometry::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 segment_box_intersection_impl +{ + BOOST_STATIC_ASSERT(0 < CurrentDimension); + + typedef segment_box_intersection_dim for_dim; + + template + static inline bool apply(Point const& p0, Point const& p1, Box const& b, + RelativeDistance & t_near, RelativeDistance & t_far) + { + return segment_box_intersection_impl::apply(p0, p1, b, t_near, t_far) + && for_dim::apply(p0, p1, b, t_near, t_far); + } +}; + +template +struct segment_box_intersection_impl +{ + typedef segment_box_intersection_dim for_dim; + + template + static inline bool apply(Point const& p0, Point const& p1, Box const& b, + RelativeDistance & t_near, RelativeDistance & t_far) + { + return for_dim::apply(p0, p1, b, t_near, t_far); + } +}; + +template +struct segment_box_intersection +{ + typedef segment_box_intersection_impl::value> impl; + + static inline bool apply(Point const& p0, Point const& p1, Box const& b) + { + typedef + typename geometry::promote_floating_point< + typename geometry::select_most_precise< + typename coordinate_type::type, + typename coordinate_type::type + >::type + >::type relative_distance_type; + + relative_distance_type t_near = -(::std::numeric_limits::max)(); + relative_distance_type t_far = (::std::numeric_limits::max)(); + + bool res = impl::apply(p0, p1, b, t_near, t_far); + + // relative_distance = 0 < t_near ? t_near : 0; + + return res && (t_near <= 1); + } +}; + +} // namespace detail +#endif // DOXYGEN_NO_DETAIL + +}} // namespace segment::intersection + }} // namespace boost::geometry