3 // Copyright (c) 2017 Oracle and/or its affiliates.
5 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
7 // Use, modification and distribution is subject to the Boost Software License,
8 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
9 // http://www.boost.org/LICENSE_1_0.txt)
11 #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_MULTI_POINT_GEOMETRY_HPP
12 #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_MULTI_POINT_GEOMETRY_HPP
15 #include <boost/range.hpp>
17 #include <boost/geometry/algorithms/detail/disjoint/box_box.hpp>
18 #include <boost/geometry/algorithms/detail/disjoint/point_box.hpp>
19 #include <boost/geometry/algorithms/detail/expand_by_epsilon.hpp>
20 #include <boost/geometry/algorithms/detail/relate/result.hpp>
21 #include <boost/geometry/algorithms/detail/relate/topology_check.hpp>
22 #include <boost/geometry/algorithms/detail/within/point_in_geometry.hpp>
23 #include <boost/geometry/algorithms/envelope.hpp>
25 #include <boost/geometry/core/is_areal.hpp>
26 #include <boost/geometry/core/point_type.hpp>
28 #include <boost/geometry/geometries/box.hpp>
30 #include <boost/geometry/index/rtree.hpp>
33 namespace boost { namespace geometry
36 #ifndef DOXYGEN_NO_DETAIL
37 namespace detail { namespace relate
43 typename Tag = typename tag<Geometry>::type
45 struct multi_point_geometry_eb
47 template <typename MultiPoint>
48 static inline bool apply(MultiPoint const& ,
49 detail::relate::topology_check<Geometry> const& )
55 template <typename Geometry>
56 struct multi_point_geometry_eb<Geometry, linestring_tag>
58 template <typename Points>
59 struct boundary_visitor
61 boundary_visitor(Points const& points)
63 , m_boundary_found(false)
66 template <typename Point>
69 find_pred(Point const& point)
73 template <typename Pt>
74 bool operator()(Pt const& pt) const
76 return detail::equals::equals_point_point(pt, m_point);
82 template <typename Point>
83 bool apply(Point const& boundary_point)
85 if (std::find_if(m_points.begin(), m_points.end(), find_pred<Point>(boundary_point)) == m_points.end())
87 m_boundary_found = true;
93 bool result() const { return m_boundary_found; }
96 Points const& m_points;
97 bool m_boundary_found;
100 template <typename MultiPoint>
101 static inline bool apply(MultiPoint const& multi_point,
102 detail::relate::topology_check<Geometry> const& tc)
104 boundary_visitor<MultiPoint> visitor(multi_point);
105 tc.for_each_boundary_point(visitor);
106 return visitor.result();
110 template <typename Geometry>
111 struct multi_point_geometry_eb<Geometry, multi_linestring_tag>
113 template <typename Points>
114 struct boundary_visitor
116 boundary_visitor(Points const& points)
118 , m_boundary_found(false)
121 template <typename Point>
122 bool apply(Point const& boundary_point)
124 if (! std::binary_search(m_points.begin(), m_points.end(), boundary_point, geometry::less<>()))
126 m_boundary_found = true;
132 bool result() const { return m_boundary_found; }
135 Points const& m_points;
136 bool m_boundary_found;
139 template <typename MultiPoint>
140 static inline bool apply(MultiPoint const& multi_point,
141 detail::relate::topology_check<Geometry> const& tc)
143 typedef typename boost::range_value<MultiPoint>::type point_type;
144 typedef std::vector<point_type> points_type;
145 points_type points(boost::begin(multi_point), boost::end(multi_point));
146 std::sort(points.begin(), points.end(), geometry::less<>());
148 boundary_visitor<points_type> visitor(points);
149 tc.for_each_boundary_point(visitor);
150 return visitor.result();
154 // SingleGeometry - Linear or Areal
155 template <typename MultiPoint, typename SingleGeometry, bool Transpose = false>
156 struct multi_point_single_geometry
158 static const bool interruption_enabled = true;
160 template <typename Result, typename Strategy>
161 static inline void apply(MultiPoint const& multi_point,
162 SingleGeometry const& single_geometry,
164 Strategy const& strategy)
166 typedef typename point_type<SingleGeometry>::type point2_type;
167 typedef model::box<point2_type> box2_type;
170 geometry::envelope(single_geometry, box2, strategy.get_envelope_strategy());
171 geometry::detail::expand_by_epsilon(box2);
173 typedef typename boost::range_const_iterator<MultiPoint>::type iterator;
174 for ( iterator it = boost::begin(multi_point) ; it != boost::end(multi_point) ; ++it )
176 if (! (relate::may_update<interior, interior, '0', Transpose>(result)
177 || relate::may_update<interior, boundary, '0', Transpose>(result)
178 || relate::may_update<interior, exterior, '0', Transpose>(result) ) )
183 // The default strategy is enough for Point/Box
184 if (detail::disjoint::disjoint_point_box(*it, box2))
186 relate::set<interior, exterior, '0', Transpose>(result);
190 int in_val = detail::within::point_in_geometry(*it, single_geometry, strategy);
192 if (in_val > 0) // within
194 relate::set<interior, interior, '0', Transpose>(result);
196 else if (in_val == 0)
198 relate::set<interior, boundary, '0', Transpose>(result);
200 else // in_val < 0 - not within
202 relate::set<interior, exterior, '0', Transpose>(result);
206 if ( BOOST_GEOMETRY_CONDITION(result.interrupt) )
212 typedef detail::relate::topology_check<SingleGeometry> tc_t;
213 if ( relate::may_update<exterior, interior, tc_t::interior, Transpose>(result)
214 || relate::may_update<exterior, boundary, tc_t::boundary, Transpose>(result) )
216 tc_t tc(single_geometry);
218 if ( relate::may_update<exterior, interior, tc_t::interior, Transpose>(result)
219 && tc.has_interior() )
221 // TODO: this is not true if a linestring is degenerated to a point
222 // then the interior has topological dimension = 0, not 1
223 relate::set<exterior, interior, tc_t::interior, Transpose>(result);
226 if ( relate::may_update<exterior, boundary, tc_t::boundary, Transpose>(result)
227 && tc.has_boundary() )
229 if (multi_point_geometry_eb<SingleGeometry>::apply(multi_point, tc))
230 relate::set<exterior, boundary, tc_t::boundary, Transpose>(result);
234 relate::set<exterior, exterior, result_dimension<MultiPoint>::value, Transpose>(result);
239 // MultiGeometry - Linear or Areal
240 // part of the algorithm calculating II and IB when no IE has to be calculated
242 template <typename MultiPoint, typename MultiGeometry, bool Transpose>
243 class multi_point_multi_geometry_ii_ib
245 struct expand_box_point
247 template <typename Box, typename Point>
248 static inline void apply(Box& total, Point const& point)
250 geometry::expand(total, point);
254 struct expand_box_box_pair
256 template <typename Box, typename BoxPair>
257 static inline void apply(Box& total, BoxPair const& box_pair)
259 geometry::expand(total, box_pair.first);
263 struct overlaps_box_point
265 template <typename Box, typename Point>
266 static inline bool apply(Box const& box, Point const& point)
268 // The default strategy is enough for Point/Box
269 return ! detail::disjoint::disjoint_point_box(point, box);
273 struct overlaps_box_box_pair
275 template <typename Box, typename BoxPair>
276 static inline bool apply(Box const& box, BoxPair const& box_pair)
278 // The default strategy is enough for Box/Box
279 return ! detail::disjoint::disjoint_box_box(box_pair.first, box);
283 template <typename Result, typename PtSegStrategy>
284 class item_visitor_type
287 item_visitor_type(MultiGeometry const& multi_geometry,
288 detail::relate::topology_check<MultiGeometry> const& tc,
290 PtSegStrategy const& strategy)
291 : m_multi_geometry(multi_geometry)
294 , m_strategy(strategy)
297 template <typename Point, typename BoxPair>
298 inline bool apply(Point const& point, BoxPair const& box_pair)
300 // The default strategy is enough for Point/Box
301 if (! detail::disjoint::disjoint_point_box(point, box_pair.first))
303 typename boost::range_value<MultiGeometry>::type const&
304 single = range::at(m_multi_geometry, box_pair.second);
306 int in_val = detail::within::point_in_geometry(point, single, m_strategy);
308 if (in_val > 0) // within
310 relate::set<interior, interior, '0', Transpose>(m_result);
312 else if (in_val == 0)
314 if (m_tc.check_boundary_point(point))
315 relate::set<interior, boundary, '0', Transpose>(m_result);
317 relate::set<interior, interior, '0', Transpose>(m_result);
321 if ( BOOST_GEOMETRY_CONDITION(m_result.interrupt) )
326 if (! (relate::may_update<interior, interior, '0', Transpose>(m_result)
327 || relate::may_update<interior, boundary, '0', Transpose>(m_result) ) )
337 MultiGeometry const& m_multi_geometry;
338 detail::relate::topology_check<MultiGeometry> const& m_tc;
340 PtSegStrategy const& m_strategy;
344 typedef typename point_type<MultiPoint>::type point1_type;
345 typedef typename point_type<MultiGeometry>::type point2_type;
346 typedef model::box<point1_type> box1_type;
347 typedef model::box<point2_type> box2_type;
348 typedef std::pair<box2_type, std::size_t> box_pair_type;
350 template <typename Result, typename Strategy>
351 static inline void apply(MultiPoint const& multi_point,
352 MultiGeometry const& multi_geometry,
353 std::vector<box_pair_type> const& boxes,
354 detail::relate::topology_check<MultiGeometry> const& tc,
356 Strategy const& strategy)
358 item_visitor_type<Result, Strategy> visitor(multi_geometry, tc, result, strategy);
363 >::apply(multi_point, boxes, visitor,
365 overlaps_box_point(),
366 expand_box_box_pair(),
367 overlaps_box_box_pair());
372 // MultiGeometry - Linear or Areal
373 // part of the algorithm calculating II, IB and IE
375 template <typename MultiPoint, typename MultiGeometry, bool Transpose>
376 struct multi_point_multi_geometry_ii_ib_ie
378 typedef typename point_type<MultiPoint>::type point1_type;
379 typedef typename point_type<MultiGeometry>::type point2_type;
380 typedef model::box<point1_type> box1_type;
381 typedef model::box<point2_type> box2_type;
382 typedef std::pair<box2_type, std::size_t> box_pair_type;
383 typedef std::vector<box_pair_type> boxes_type;
384 typedef typename boxes_type::const_iterator boxes_iterator;
386 template <typename Result, typename Strategy>
387 static inline void apply(MultiPoint const& multi_point,
388 MultiGeometry const& multi_geometry,
389 std::vector<box_pair_type> const& boxes,
390 detail::relate::topology_check<MultiGeometry> const& tc,
392 Strategy const& strategy)
394 index::rtree<box_pair_type, index::rstar<4> > rt(boxes.begin(), boxes.end());
396 typedef typename boost::range_const_iterator<MultiPoint>::type iterator;
397 for ( iterator it = boost::begin(multi_point) ; it != boost::end(multi_point) ; ++it )
399 if (! (relate::may_update<interior, interior, '0', Transpose>(result)
400 || relate::may_update<interior, boundary, '0', Transpose>(result)
401 || relate::may_update<interior, exterior, '0', Transpose>(result) ) )
406 typename boost::range_value<MultiPoint>::type const& point = *it;
408 boxes_type boxes_found;
409 rt.query(index::intersects(point), std::back_inserter(boxes_found));
411 bool found_ii_or_ib = false;
412 for (boxes_iterator bi = boxes_found.begin() ; bi != boxes_found.end() ; ++bi)
414 typename boost::range_value<MultiGeometry>::type const&
415 single = range::at(multi_geometry, bi->second);
417 int in_val = detail::within::point_in_geometry(point, single, strategy);
419 if (in_val > 0) // within
421 relate::set<interior, interior, '0', Transpose>(result);
422 found_ii_or_ib = true;
424 else if (in_val == 0) // on boundary of single
426 if (tc.check_boundary_point(point))
427 relate::set<interior, boundary, '0', Transpose>(result);
429 relate::set<interior, interior, '0', Transpose>(result);
430 found_ii_or_ib = true;
434 // neither interior nor boundary found -> exterior
435 if (found_ii_or_ib == false)
437 relate::set<interior, exterior, '0', Transpose>(result);
440 if ( BOOST_GEOMETRY_CONDITION(result.interrupt) )
448 // MultiGeometry - Linear or Areal
449 template <typename MultiPoint, typename MultiGeometry, bool Transpose = false>
450 struct multi_point_multi_geometry
452 static const bool interruption_enabled = true;
454 template <typename Result, typename Strategy>
455 static inline void apply(MultiPoint const& multi_point,
456 MultiGeometry const& multi_geometry,
458 Strategy const& strategy)
460 typedef typename point_type<MultiGeometry>::type point2_type;
461 typedef model::box<point2_type> box2_type;
462 typedef std::pair<box2_type, std::size_t> box_pair_type;
464 typename Strategy::envelope_strategy_type const
465 envelope_strategy = strategy.get_envelope_strategy();
467 std::size_t count2 = boost::size(multi_geometry);
468 std::vector<box_pair_type> boxes(count2);
469 for (std::size_t i = 0 ; i < count2 ; ++i)
471 geometry::envelope(range::at(multi_geometry, i), boxes[i].first, envelope_strategy);
472 geometry::detail::expand_by_epsilon(boxes[i].first);
476 typedef detail::relate::topology_check<MultiGeometry> tc_t;
477 tc_t tc(multi_geometry);
479 if ( relate::may_update<interior, interior, '0', Transpose>(result)
480 || relate::may_update<interior, boundary, '0', Transpose>(result)
481 || relate::may_update<interior, exterior, '0', Transpose>(result) )
483 // If there is no need to calculate IE, use partition
484 if (! relate::may_update<interior, exterior, '0', Transpose>(result) )
486 multi_point_multi_geometry_ii_ib<MultiPoint, MultiGeometry, Transpose>
487 ::apply(multi_point, multi_geometry, boxes, tc, result, strategy);
489 else // otherwise use rtree
491 multi_point_multi_geometry_ii_ib_ie<MultiPoint, MultiGeometry, Transpose>
492 ::apply(multi_point, multi_geometry, boxes, tc, result, strategy);
496 if ( BOOST_GEOMETRY_CONDITION(result.interrupt) )
501 if ( relate::may_update<exterior, interior, tc_t::interior, Transpose>(result)
502 || relate::may_update<exterior, boundary, tc_t::boundary, Transpose>(result) )
504 if ( relate::may_update<exterior, interior, tc_t::interior, Transpose>(result)
505 && tc.has_interior() )
507 // TODO: this is not true if a linestring is degenerated to a point
508 // then the interior has topological dimension = 0, not 1
509 relate::set<exterior, interior, tc_t::interior, Transpose>(result);
512 if ( relate::may_update<exterior, boundary, tc_t::boundary, Transpose>(result)
513 && tc.has_boundary() )
515 if (multi_point_geometry_eb<MultiGeometry>::apply(multi_point, tc))
516 relate::set<exterior, boundary, tc_t::boundary, Transpose>(result);
520 relate::set<exterior, exterior, result_dimension<MultiPoint>::value, Transpose>(result);
528 typename MultiPoint, typename Geometry,
529 bool Transpose = false,
530 bool isMulti = boost::is_same
534 typename tag<Geometry>::type, multi_tag
539 struct multi_point_geometry
540 : multi_point_single_geometry<MultiPoint, Geometry, Transpose>
543 template <typename MultiPoint, typename Geometry, bool Transpose>
544 struct multi_point_geometry<MultiPoint, Geometry, Transpose, true>
545 : multi_point_multi_geometry<MultiPoint, Geometry, Transpose>
549 // transposed result of multi_point_geometry
550 template <typename Geometry, typename MultiPoint>
551 struct geometry_multi_point
553 static const bool interruption_enabled = true;
555 template <typename Result, typename Strategy>
556 static inline void apply(Geometry const& geometry, MultiPoint const& multi_point,
557 Result & result, Strategy const& strategy)
559 multi_point_geometry<MultiPoint, Geometry, true>::apply(multi_point, geometry, result, strategy);
563 }} // namespace detail::relate
564 #endif // DOXYGEN_NO_DETAIL
566 }} // namespace boost::geometry
568 #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_MULTI_POINT_GEOMETRY_HPP