// Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // This file was modified by Oracle on 2013, 2014, 2017. // Modifications copyright (c) 2013-2017, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // 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_ALGORITHMS_DETAIL_RELATE_POINT_POINT_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_POINT_POINT_HPP #include #include #include #include #include #include #include namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace relate { template struct point_point { static const bool interruption_enabled = false; template static inline void apply(Point1 const& point1, Point2 const& point2, Result & result, Strategy const& /*strategy*/) { bool equal = detail::equals::equals_point_point(point1, point2); if ( equal ) { relate::set(result); } else { relate::set(result); relate::set(result); } relate::set::value>(result); } }; template std::pair point_multipoint_check(Point const& point, MultiPoint const& multi_point) { bool found_inside = false; bool found_outside = false; // point_in_geometry could be used here but why iterate over MultiPoint twice? // we must search for a point in the exterior because all points in MultiPoint can be equal typedef typename boost::range_iterator::type iterator; iterator it = boost::begin(multi_point); iterator last = boost::end(multi_point); for ( ; it != last ; ++it ) { bool ii = detail::equals::equals_point_point(point, *it); if ( ii ) found_inside = true; else found_outside = true; if ( found_inside && found_outside ) break; } return std::make_pair(found_inside, found_outside); } template struct point_multipoint { static const bool interruption_enabled = false; template static inline void apply(Point const& point, MultiPoint const& multi_point, Result & result, Strategy const& /*strategy*/) { if ( boost::empty(multi_point) ) { // TODO: throw on empty input? relate::set(result); return; } std::pair rel = point_multipoint_check(point, multi_point); if ( rel.first ) // some point of MP is equal to P { relate::set(result); if ( rel.second ) // a point of MP was found outside P { relate::set(result); } } else { relate::set(result); relate::set(result); } relate::set::value, Transpose>(result); } }; template struct multipoint_point { static const bool interruption_enabled = false; template static inline void apply(MultiPoint const& multi_point, Point const& point, Result & result, Strategy const& strategy) { point_multipoint::apply(point, multi_point, result, strategy); } }; template struct multipoint_multipoint { static const bool interruption_enabled = true; template static inline void apply(MultiPoint1 const& multi_point1, MultiPoint2 const& multi_point2, Result & result, Strategy const& /*strategy*/) { { // TODO: throw on empty input? bool empty1 = boost::empty(multi_point1); bool empty2 = boost::empty(multi_point2); if ( empty1 && empty2 ) { return; } else if ( empty1 ) { relate::set(result); return; } else if ( empty2 ) { relate::set(result); return; } } // The geometry containing smaller number of points will be analysed first if ( boost::size(multi_point1) < boost::size(multi_point2) ) { search_both(multi_point1, multi_point2, result); } else { search_both(multi_point2, multi_point1, result); } relate::set::value>(result); } template static inline void search_both(MPt1 const& first_sorted_mpt, MPt2 const& first_iterated_mpt, Result & result) { if ( relate::may_update(result) || relate::may_update(result) || relate::may_update(result) ) { // NlogN + MlogN bool is_disjoint = search(first_sorted_mpt, first_iterated_mpt, result); if ( BOOST_GEOMETRY_CONDITION(is_disjoint || result.interrupt) ) return; } if ( relate::may_update(result) || relate::may_update(result) || relate::may_update(result) ) { // MlogM + NlogM search(first_iterated_mpt, first_sorted_mpt, result); } } template static inline bool search(SortedMultiPoint const& sorted_mpt, IteratedMultiPoint const& iterated_mpt, Result & result) { // sort points from the 1 MPt typedef typename geometry::point_type::type point_type; std::vector points(boost::begin(sorted_mpt), boost::end(sorted_mpt)); geometry::less<> const less = geometry::less<>(); std::sort(points.begin(), points.end(), less); bool found_inside = false; bool found_outside = false; // for each point in the second MPt typedef typename boost::range_iterator::type iterator; for ( iterator it = boost::begin(iterated_mpt) ; it != boost::end(iterated_mpt) ; ++it ) { bool ii = std::binary_search(points.begin(), points.end(), *it, less); if ( ii ) found_inside = true; else found_outside = true; if ( found_inside && found_outside ) break; } if ( found_inside ) // some point of MP2 is equal to some of MP1 { // TODO: if I/I is set for one MPt, this won't be changed when the other one in analysed // so if e.g. only I/I must be analysed we musn't check the other MPt relate::set(result); if ( found_outside ) // some point of MP2 was found outside of MP1 { relate::set(result); } } else { relate::set(result); relate::set(result); } // if no point is intersecting the other MPt then we musn't analyse the reversed case return ! found_inside; } }; }} // namespace detail::relate #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_POINT_POINT_HPP