Chris@16: // Boost.Geometry (aka GGL, Generic Geometry Library) Chris@16: Chris@16: // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. Chris@16: // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. Chris@16: // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. Chris@101: // Copyright (c) 2013 Adam Wulkiewicz, Lodz, Poland. Chris@101: Chris@101: // This file was modified by Oracle on 2013, 2014. Chris@101: // Modifications copyright (c) 2013, 2014, Oracle and/or its affiliates. Chris@16: Chris@16: // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library Chris@16: // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. Chris@16: Chris@16: // Use, modification and distribution is subject to the Boost Software License, Chris@16: // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at Chris@16: // http://www.boost.org/LICENSE_1_0.txt) Chris@16: Chris@101: // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle Chris@101: Chris@16: #ifndef BOOST_GEOMETRY_ALGORITHMS_TOUCHES_HPP Chris@16: #define BOOST_GEOMETRY_ALGORITHMS_TOUCHES_HPP Chris@16: Chris@16: Chris@16: #include Chris@16: Chris@101: #include Chris@101: #include Chris@101: #include Chris@101: Chris@16: #include Chris@101: #include Chris@101: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@101: #include Chris@101: #include Chris@16: Chris@101: #include Chris@16: Chris@16: namespace boost { namespace geometry Chris@16: { Chris@16: Chris@101: #ifndef DOXYGEN_NO_DETAIL Chris@101: namespace detail { namespace touches Chris@16: { Chris@16: Chris@101: // Box/Box Chris@101: Chris@101: template Chris@101: < Chris@101: std::size_t Dimension, Chris@101: std::size_t DimensionCount Chris@101: > Chris@101: struct box_box_loop Chris@16: { Chris@101: template Chris@101: static inline bool apply(Box1 const& b1, Box2 const& b2, bool & touch) Chris@101: { Chris@101: typedef typename coordinate_type::type coordinate_type1; Chris@101: typedef typename coordinate_type::type coordinate_type2; Chris@16: Chris@101: coordinate_type1 const& min1 = get(b1); Chris@101: coordinate_type1 const& max1 = get(b1); Chris@101: coordinate_type2 const& min2 = get(b2); Chris@101: coordinate_type2 const& max2 = get(b2); Chris@101: Chris@101: // TODO assert or exception? Chris@101: //BOOST_ASSERT(min1 <= max1 && min2 <= max2); Chris@101: Chris@101: if ( max1 < min2 || max2 < min1 ) Chris@16: { Chris@16: return false; Chris@16: } Chris@16: Chris@101: if ( max1 == min2 || max2 == min1 ) Chris@16: { Chris@101: touch = true; Chris@101: } Chris@101: Chris@101: return box_box_loop Chris@101: < Chris@101: Dimension + 1, Chris@101: DimensionCount Chris@101: >::apply(b1, b2, touch); Chris@101: } Chris@101: }; Chris@101: Chris@101: template Chris@101: < Chris@101: std::size_t DimensionCount Chris@101: > Chris@101: struct box_box_loop Chris@101: { Chris@101: template Chris@101: static inline bool apply(Box1 const& , Box2 const&, bool &) Chris@101: { Chris@101: return true; Chris@101: } Chris@101: }; Chris@101: Chris@101: struct box_box Chris@101: { Chris@101: template Chris@101: static inline bool apply(Box1 const& b1, Box2 const& b2) Chris@101: { Chris@101: BOOST_STATIC_ASSERT((boost::is_same Chris@101: < Chris@101: typename geometry::coordinate_system::type, Chris@101: typename geometry::coordinate_system::type Chris@101: >::value Chris@101: )); Chris@101: assert_dimension_equal(); Chris@101: Chris@101: bool touches = false; Chris@101: bool ok = box_box_loop Chris@101: < Chris@101: 0, Chris@101: dimension::type::value Chris@101: >::apply(b1, b2, touches); Chris@101: Chris@101: return ok && touches; Chris@101: } Chris@101: }; Chris@101: Chris@101: // Areal/Areal Chris@101: Chris@101: struct areal_interrupt_policy Chris@101: { Chris@101: static bool const enabled = true; Chris@101: bool found_touch; Chris@101: bool found_not_touch; Chris@101: Chris@101: // dummy variable required by self_get_turn_points::get_turns Chris@101: static bool const has_intersections = false; Chris@101: Chris@101: inline bool result() Chris@101: { Chris@101: return found_touch && !found_not_touch; Chris@101: } Chris@101: Chris@101: inline areal_interrupt_policy() Chris@101: : found_touch(false), found_not_touch(false) Chris@101: {} Chris@101: Chris@101: template Chris@101: inline bool apply(Range const& range) Chris@101: { Chris@101: // if already rejected (temp workaround?) Chris@101: if ( found_not_touch ) Chris@101: return true; Chris@101: Chris@101: typedef typename boost::range_iterator::type iterator; Chris@101: for ( iterator it = boost::begin(range) ; it != boost::end(range) ; ++it ) Chris@101: { Chris@101: if ( it->has(overlay::operation_intersection) ) Chris@101: { Chris@101: found_not_touch = true; Chris@101: return true; Chris@101: } Chris@101: Chris@101: switch(it->method) Chris@101: { Chris@101: case overlay::method_crosses: Chris@101: found_not_touch = true; Chris@101: return true; Chris@101: case overlay::method_equal: Chris@101: // Segment spatially equal means: at the right side Chris@101: // the polygon internally overlaps. So return false. Chris@101: found_not_touch = true; Chris@101: return true; Chris@101: case overlay::method_touch: Chris@101: case overlay::method_touch_interior: Chris@101: case overlay::method_collinear: Chris@101: if ( ok_for_touch(*it) ) Chris@101: { Chris@101: found_touch = true; Chris@101: } Chris@101: else Chris@101: { Chris@101: found_not_touch = true; Chris@101: return true; Chris@101: } Chris@101: break; Chris@101: case overlay::method_none : Chris@101: case overlay::method_disjoint : Chris@101: case overlay::method_error : Chris@101: break; Chris@101: } Chris@101: } Chris@101: Chris@101: return false; Chris@101: } Chris@101: Chris@101: template Chris@101: inline bool ok_for_touch(Turn const& turn) Chris@101: { Chris@101: return turn.both(overlay::operation_union) Chris@101: || turn.both(overlay::operation_blocked) Chris@101: || turn.combination(overlay::operation_union, overlay::operation_blocked) Chris@101: ; Chris@101: } Chris@101: }; Chris@101: Chris@101: template Chris@101: struct check_each_ring_for_within Chris@101: { Chris@101: bool has_within; Chris@101: Geometry const& m_geometry; Chris@101: Chris@101: inline check_each_ring_for_within(Geometry const& g) Chris@101: : has_within(false) Chris@101: , m_geometry(g) Chris@101: {} Chris@101: Chris@101: template Chris@101: inline void apply(Range const& range) Chris@101: { Chris@101: typename geometry::point_type::type p; Chris@101: geometry::point_on_border(p, range); Chris@101: if ( !has_within && geometry::within(p, m_geometry) ) Chris@101: { Chris@101: has_within = true; Chris@16: } Chris@16: } Chris@101: }; Chris@101: Chris@101: template Chris@101: inline bool rings_containing(FirstGeometry const& geometry1, Chris@101: SecondGeometry const& geometry2) Chris@101: { Chris@101: check_each_ring_for_within checker(geometry1); Chris@101: geometry::detail::for_each_range(geometry2, checker); Chris@101: return checker.has_within; Chris@16: } Chris@16: Chris@101: template Chris@101: struct areal_areal Chris@101: { Chris@101: static inline Chris@101: bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2) Chris@101: { Chris@101: typedef detail::no_rescale_policy rescale_policy_type; Chris@101: typedef typename geometry::point_type::type point_type; Chris@101: typedef detail::overlay::turn_info Chris@101: < Chris@101: point_type, Chris@101: typename segment_ratio_type::type Chris@101: > turn_info; Chris@101: Chris@101: std::deque turns; Chris@101: detail::touches::areal_interrupt_policy policy; Chris@101: rescale_policy_type robust_policy; Chris@101: boost::geometry::get_turns Chris@101: < Chris@101: detail::overlay::do_reverse::value>::value, Chris@101: detail::overlay::do_reverse::value>::value, Chris@101: detail::overlay::assign_null_policy Chris@101: >(geometry1, geometry2, robust_policy, turns, policy); Chris@101: Chris@101: return policy.result() Chris@101: && ! geometry::detail::touches::rings_containing(geometry1, geometry2) Chris@101: && ! geometry::detail::touches::rings_containing(geometry2, geometry1); Chris@101: } Chris@101: }; Chris@101: Chris@101: // P/* Chris@101: Chris@101: struct use_point_in_geometry Chris@101: { Chris@101: template Chris@101: static inline bool apply(Point const& point, Geometry const& geometry) Chris@101: { Chris@101: return detail::within::point_in_geometry(point, geometry) == 0; Chris@101: } Chris@101: }; Chris@101: Chris@16: }} Chris@101: #endif // DOXYGEN_NO_DETAIL Chris@101: Chris@101: #ifndef DOXYGEN_NO_DISPATCH Chris@101: namespace dispatch { Chris@101: Chris@101: // TODO: Since CastedTags are used is Reverse needed? Chris@101: Chris@101: template Chris@101: < Chris@101: typename Geometry1, typename Geometry2, Chris@101: typename Tag1 = typename tag::type, Chris@101: typename Tag2 = typename tag::type, Chris@101: typename CastedTag1 = typename tag_cast::type, Chris@101: typename CastedTag2 = typename tag_cast::type, Chris@101: bool Reverse = reverse_dispatch::type::value Chris@101: > Chris@101: struct touches Chris@101: : not_implemented Chris@101: {}; Chris@101: Chris@101: // If reversal is needed, perform it Chris@101: template Chris@101: < Chris@101: typename Geometry1, typename Geometry2, Chris@101: typename Tag1, typename Tag2, Chris@101: typename CastedTag1, typename CastedTag2 Chris@101: > Chris@101: struct touches Chris@101: : touches Chris@101: { Chris@101: static inline bool apply(Geometry1 const& g1, Geometry2 const& g2) Chris@101: { Chris@101: return touches::apply(g2, g1); Chris@101: } Chris@101: }; Chris@101: Chris@101: // P/P Chris@101: Chris@101: template Chris@101: struct touches Chris@101: { Chris@101: static inline bool apply(Geometry1 const& , Geometry2 const& ) Chris@101: { Chris@101: return false; Chris@101: } Chris@101: }; Chris@101: Chris@101: // P/* Chris@101: Chris@101: template Chris@101: struct touches Chris@101: : detail::touches::use_point_in_geometry Chris@101: {}; Chris@101: Chris@101: // TODO: support touches(MPt, Linear/Areal) Chris@101: Chris@101: // Box/Box Chris@101: Chris@101: template Chris@101: struct touches Chris@101: : detail::touches::box_box Chris@101: {}; Chris@101: Chris@101: template Chris@101: struct touches Chris@101: : detail::touches::box_box Chris@101: {}; Chris@101: Chris@101: // L/L Chris@101: Chris@101: template Chris@101: struct touches Chris@101: : detail::relate::relate_base Chris@101: < Chris@101: detail::relate::static_mask_touches_type, Chris@101: Linear1, Chris@101: Linear2 Chris@101: > Chris@101: {}; Chris@101: Chris@101: // L/A Chris@101: Chris@101: template Chris@101: struct touches Chris@101: : detail::relate::relate_base Chris@101: < Chris@101: detail::relate::static_mask_touches_type, Chris@101: Linear, Chris@101: Areal Chris@101: > Chris@101: {}; Chris@101: Chris@101: // A/L Chris@101: template Chris@101: struct touches Chris@101: : detail::relate::relate_base Chris@101: < Chris@101: detail::relate::static_mask_touches_type, Chris@101: Areal, Chris@101: Linear Chris@101: > Chris@101: {}; Chris@101: Chris@101: // A/A Chris@101: Chris@101: template Chris@101: struct touches Chris@101: : detail::touches::areal_areal Chris@101: {}; Chris@101: Chris@101: } // namespace dispatch Chris@101: #endif // DOXYGEN_NO_DISPATCH Chris@101: Chris@101: Chris@101: namespace resolve_variant { Chris@101: Chris@101: template Chris@101: struct touches Chris@101: { Chris@101: static bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2) Chris@101: { Chris@101: concept::check(); Chris@101: concept::check(); Chris@101: Chris@101: return dispatch::touches Chris@101: ::apply(geometry1, geometry2); Chris@101: } Chris@101: }; Chris@101: Chris@101: template Chris@101: struct touches, Geometry2> Chris@101: { Chris@101: struct visitor: boost::static_visitor Chris@101: { Chris@101: Geometry2 const& m_geometry2; Chris@101: Chris@101: visitor(Geometry2 const& geometry2): m_geometry2(geometry2) {} Chris@101: Chris@101: template Chris@101: bool operator()(Geometry1 const& geometry1) const Chris@101: { Chris@101: return touches::apply(geometry1, m_geometry2); Chris@101: } Chris@101: }; Chris@101: Chris@101: static inline bool Chris@101: apply(boost::variant const& geometry1, Chris@101: Geometry2 const& geometry2) Chris@101: { Chris@101: return boost::apply_visitor(visitor(geometry2), geometry1); Chris@101: } Chris@101: }; Chris@101: Chris@101: template Chris@101: struct touches > Chris@101: { Chris@101: struct visitor: boost::static_visitor Chris@101: { Chris@101: Geometry1 const& m_geometry1; Chris@101: Chris@101: visitor(Geometry1 const& geometry1): m_geometry1(geometry1) {} Chris@101: Chris@101: template Chris@101: bool operator()(Geometry2 const& geometry2) const Chris@101: { Chris@101: return touches::apply(m_geometry1, geometry2); Chris@101: } Chris@101: }; Chris@101: Chris@101: static inline bool Chris@101: apply(Geometry1 const& geometry1, Chris@101: boost::variant const& geometry2) Chris@101: { Chris@101: return boost::apply_visitor(visitor(geometry1), geometry2); Chris@101: } Chris@101: }; Chris@101: Chris@101: template Chris@101: struct touches, Chris@101: boost::variant > Chris@101: { Chris@101: struct visitor: boost::static_visitor Chris@101: { Chris@101: template Chris@101: bool operator()(Geometry1 const& geometry1, Chris@101: Geometry2 const& geometry2) const Chris@101: { Chris@101: return touches::apply(geometry1, geometry2); Chris@101: } Chris@101: }; Chris@101: Chris@101: static inline bool Chris@101: apply(boost::variant const& geometry1, Chris@101: boost::variant const& geometry2) Chris@101: { Chris@101: return boost::apply_visitor(visitor(), geometry1, geometry2); Chris@101: } Chris@101: }; Chris@101: Chris@101: template Chris@101: struct self_touches Chris@101: { Chris@101: static bool apply(Geometry const& geometry) Chris@101: { Chris@101: concept::check(); Chris@101: Chris@101: typedef detail::no_rescale_policy rescale_policy_type; Chris@101: typedef typename geometry::point_type::type point_type; Chris@101: typedef detail::overlay::turn_info Chris@101: < Chris@101: point_type, Chris@101: typename segment_ratio_type::type Chris@101: > turn_info; Chris@101: Chris@101: typedef detail::overlay::get_turn_info Chris@101: < Chris@101: detail::overlay::assign_null_policy Chris@101: > policy_type; Chris@101: Chris@101: std::deque turns; Chris@101: detail::touches::areal_interrupt_policy policy; Chris@101: rescale_policy_type robust_policy; Chris@101: detail::self_get_turn_points::get_turns Chris@101: < Chris@101: policy_type Chris@101: >::apply(geometry, robust_policy, turns, policy); Chris@101: Chris@101: return policy.result(); Chris@101: } Chris@101: }; Chris@101: Chris@101: template Chris@101: struct self_touches > Chris@101: { Chris@101: struct visitor: boost::static_visitor Chris@101: { Chris@101: template Chris@101: bool operator()(Geometry const& geometry) const Chris@101: { Chris@101: return self_touches::apply(geometry); Chris@101: } Chris@101: }; Chris@101: Chris@101: static inline bool Chris@101: apply(boost::variant const& geometry) Chris@101: { Chris@101: return boost::apply_visitor(visitor(), geometry); Chris@101: } Chris@101: }; Chris@101: Chris@101: } // namespace resolve_variant Chris@101: Chris@16: Chris@16: /*! Chris@16: \brief \brief_check{has at least one touching point (self-tangency)} Chris@16: \note This function can be called for one geometry (self-tangency) and Chris@16: also for two geometries (touch) Chris@16: \ingroup touches Chris@16: \tparam Geometry \tparam_geometry Chris@16: \param geometry \param_geometry Chris@16: \return \return_check{is self-touching} Chris@16: Chris@16: \qbk{distinguish,one geometry} Chris@16: \qbk{[def __one_parameter__]} Chris@16: \qbk{[include reference/algorithms/touches.qbk]} Chris@16: */ Chris@16: template Chris@16: inline bool touches(Geometry const& geometry) Chris@16: { Chris@101: return resolve_variant::self_touches::apply(geometry); Chris@16: } Chris@16: Chris@16: Chris@16: /*! Chris@16: \brief \brief_check2{have at least one touching point (tangent - non overlapping)} Chris@16: \ingroup touches Chris@16: \tparam Geometry1 \tparam_geometry Chris@16: \tparam Geometry2 \tparam_geometry Chris@16: \param geometry1 \param_geometry Chris@16: \param geometry2 \param_geometry Chris@16: \return \return_check2{touch each other} Chris@16: Chris@16: \qbk{distinguish,two geometries} Chris@16: \qbk{[include reference/algorithms/touches.qbk]} Chris@16: */ Chris@16: template Chris@16: inline bool touches(Geometry1 const& geometry1, Geometry2 const& geometry2) Chris@16: { Chris@101: return resolve_variant::touches::apply(geometry1, geometry2); Chris@16: } Chris@16: Chris@16: Chris@16: }} // namespace boost::geometry Chris@16: Chris@16: #endif // BOOST_GEOMETRY_ALGORITHMS_TOUCHES_HPP