1 // Boost.Geometry (aka GGL, Generic Geometry Library)
3 // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
5 // This file was modified by Oracle on 2013, 2014, 2017.
6 // Modifications copyright (c) 2013-2017, Oracle and/or its affiliates.
8 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
10 // Use, modification and distribution is subject to the Boost Software License,
11 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
12 // http://www.boost.org/LICENSE_1_0.txt)
14 #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_POINT_POINT_HPP
15 #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_POINT_POINT_HPP
20 #include <boost/range/empty.hpp>
22 #include <boost/geometry/algorithms/detail/equals/point_point.hpp>
23 #include <boost/geometry/algorithms/detail/within/point_in_geometry.hpp>
24 #include <boost/geometry/algorithms/detail/relate/result.hpp>
26 #include <boost/geometry/policies/compare.hpp>
28 namespace boost { namespace geometry
31 #ifndef DOXYGEN_NO_DETAIL
32 namespace detail { namespace relate {
34 template <typename Point1, typename Point2>
37 static const bool interruption_enabled = false;
39 template <typename Result, typename Strategy>
40 static inline void apply(Point1 const& point1, Point2 const& point2,
42 Strategy const& /*strategy*/)
44 bool equal = detail::equals::equals_point_point(point1, point2);
47 relate::set<interior, interior, '0'>(result);
51 relate::set<interior, exterior, '0'>(result);
52 relate::set<exterior, interior, '0'>(result);
55 relate::set<exterior, exterior, result_dimension<Point1>::value>(result);
59 template <typename Point, typename MultiPoint>
60 std::pair<bool, bool> point_multipoint_check(Point const& point, MultiPoint const& multi_point)
62 bool found_inside = false;
63 bool found_outside = false;
65 // point_in_geometry could be used here but why iterate over MultiPoint twice?
66 // we must search for a point in the exterior because all points in MultiPoint can be equal
68 typedef typename boost::range_iterator<MultiPoint const>::type iterator;
69 iterator it = boost::begin(multi_point);
70 iterator last = boost::end(multi_point);
71 for ( ; it != last ; ++it )
73 bool ii = detail::equals::equals_point_point(point, *it);
80 if ( found_inside && found_outside )
84 return std::make_pair(found_inside, found_outside);
87 template <typename Point, typename MultiPoint, bool Transpose = false>
88 struct point_multipoint
90 static const bool interruption_enabled = false;
92 template <typename Result, typename Strategy>
93 static inline void apply(Point const& point, MultiPoint const& multi_point,
95 Strategy const& /*strategy*/)
97 if ( boost::empty(multi_point) )
99 // TODO: throw on empty input?
100 relate::set<interior, exterior, '0', Transpose>(result);
104 std::pair<bool, bool> rel = point_multipoint_check(point, multi_point);
106 if ( rel.first ) // some point of MP is equal to P
108 relate::set<interior, interior, '0', Transpose>(result);
110 if ( rel.second ) // a point of MP was found outside P
112 relate::set<exterior, interior, '0', Transpose>(result);
117 relate::set<interior, exterior, '0', Transpose>(result);
118 relate::set<exterior, interior, '0', Transpose>(result);
121 relate::set<exterior, exterior, result_dimension<Point>::value, Transpose>(result);
125 template <typename MultiPoint, typename Point>
126 struct multipoint_point
128 static const bool interruption_enabled = false;
130 template <typename Result, typename Strategy>
131 static inline void apply(MultiPoint const& multi_point, Point const& point,
133 Strategy const& strategy)
135 point_multipoint<Point, MultiPoint, true>::apply(point, multi_point, result, strategy);
139 template <typename MultiPoint1, typename MultiPoint2>
140 struct multipoint_multipoint
142 static const bool interruption_enabled = true;
144 template <typename Result, typename Strategy>
145 static inline void apply(MultiPoint1 const& multi_point1, MultiPoint2 const& multi_point2,
147 Strategy const& /*strategy*/)
150 // TODO: throw on empty input?
151 bool empty1 = boost::empty(multi_point1);
152 bool empty2 = boost::empty(multi_point2);
153 if ( empty1 && empty2 )
159 relate::set<exterior, interior, '0'>(result);
164 relate::set<interior, exterior, '0'>(result);
169 // The geometry containing smaller number of points will be analysed first
170 if ( boost::size(multi_point1) < boost::size(multi_point2) )
172 search_both<false>(multi_point1, multi_point2, result);
176 search_both<true>(multi_point2, multi_point1, result);
179 relate::set<exterior, exterior, result_dimension<MultiPoint1>::value>(result);
182 template <bool Transpose, typename MPt1, typename MPt2, typename Result>
183 static inline void search_both(MPt1 const& first_sorted_mpt, MPt2 const& first_iterated_mpt,
186 if ( relate::may_update<interior, interior, '0'>(result)
187 || relate::may_update<interior, exterior, '0'>(result)
188 || relate::may_update<exterior, interior, '0'>(result) )
191 bool is_disjoint = search<Transpose>(first_sorted_mpt, first_iterated_mpt, result);
193 if ( BOOST_GEOMETRY_CONDITION(is_disjoint || result.interrupt) )
197 if ( relate::may_update<interior, interior, '0'>(result)
198 || relate::may_update<interior, exterior, '0'>(result)
199 || relate::may_update<exterior, interior, '0'>(result) )
202 search<! Transpose>(first_iterated_mpt, first_sorted_mpt, result);
206 template <bool Transpose,
207 typename SortedMultiPoint,
208 typename IteratedMultiPoint,
210 static inline bool search(SortedMultiPoint const& sorted_mpt,
211 IteratedMultiPoint const& iterated_mpt,
214 // sort points from the 1 MPt
215 typedef typename geometry::point_type<SortedMultiPoint>::type point_type;
216 std::vector<point_type> points(boost::begin(sorted_mpt), boost::end(sorted_mpt));
218 geometry::less<> const less = geometry::less<>();
219 std::sort(points.begin(), points.end(), less);
221 bool found_inside = false;
222 bool found_outside = false;
224 // for each point in the second MPt
225 typedef typename boost::range_iterator<IteratedMultiPoint const>::type iterator;
226 for ( iterator it = boost::begin(iterated_mpt) ;
227 it != boost::end(iterated_mpt) ; ++it )
230 std::binary_search(points.begin(), points.end(), *it, less);
234 found_outside = true;
236 if ( found_inside && found_outside )
240 if ( found_inside ) // some point of MP2 is equal to some of MP1
242 // TODO: if I/I is set for one MPt, this won't be changed when the other one in analysed
243 // so if e.g. only I/I must be analysed we musn't check the other MPt
245 relate::set<interior, interior, '0', Transpose>(result);
247 if ( found_outside ) // some point of MP2 was found outside of MP1
249 relate::set<exterior, interior, '0', Transpose>(result);
254 relate::set<interior, exterior, '0', Transpose>(result);
255 relate::set<exterior, interior, '0', Transpose>(result);
258 // if no point is intersecting the other MPt then we musn't analyse the reversed case
259 return ! found_inside;
263 }} // namespace detail::relate
264 #endif // DOXYGEN_NO_DETAIL
266 }} // namespace boost::geometry
268 #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_POINT_POINT_HPP