Imported Upstream version 1.64.0
[platform/upstream/boost.git] / boost / geometry / algorithms / touches.hpp
1 // Boost.Geometry (aka GGL, Generic Geometry Library)
2
3 // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
4 // Copyright (c) 2008-2015 Bruno Lalande, Paris, France.
5 // Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
6 // Copyright (c) 2013-2015 Adam Wulkiewicz, Lodz, Poland.
7
8 // This file was modified by Oracle on 2013, 2014, 2015, 2017.
9 // Modifications copyright (c) 2013-2017, Oracle and/or its affiliates.
10
11 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
12
13 // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
14 // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
15
16 // Use, modification and distribution is subject to the Boost Software License,
17 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
18 // http://www.boost.org/LICENSE_1_0.txt)
19
20 #ifndef BOOST_GEOMETRY_ALGORITHMS_TOUCHES_HPP
21 #define BOOST_GEOMETRY_ALGORITHMS_TOUCHES_HPP
22
23
24 #include <deque>
25
26 #include <boost/variant/apply_visitor.hpp>
27 #include <boost/variant/static_visitor.hpp>
28 #include <boost/variant/variant_fwd.hpp>
29
30 #include <boost/geometry/geometries/concepts/check.hpp>
31 #include <boost/geometry/algorithms/detail/for_each_range.hpp>
32 #include <boost/geometry/algorithms/detail/overlay/overlay.hpp>
33 #include <boost/geometry/algorithms/detail/overlay/self_turn_points.hpp>
34 #include <boost/geometry/algorithms/disjoint.hpp>
35 #include <boost/geometry/algorithms/intersects.hpp>
36 #include <boost/geometry/algorithms/num_geometries.hpp>
37 #include <boost/geometry/algorithms/detail/sub_range.hpp>
38 #include <boost/geometry/policies/robustness/no_rescale_policy.hpp>
39
40 #include <boost/geometry/algorithms/relate.hpp>
41 #include <boost/geometry/algorithms/detail/relate/relate_impl.hpp>
42
43
44 namespace boost { namespace geometry
45 {
46
47 #ifndef DOXYGEN_NO_DETAIL
48 namespace detail { namespace touches
49 {
50
51 // Box/Box
52
53 template
54 <
55     std::size_t Dimension,
56     std::size_t DimensionCount
57 >
58 struct box_box_loop
59 {
60     template <typename Box1, typename Box2>
61     static inline bool apply(Box1 const& b1, Box2 const& b2, bool & touch)
62     {
63         typedef typename coordinate_type<Box1>::type coordinate_type1;
64         typedef typename coordinate_type<Box2>::type coordinate_type2;
65
66         coordinate_type1 const& min1 = get<min_corner, Dimension>(b1);
67         coordinate_type1 const& max1 = get<max_corner, Dimension>(b1);
68         coordinate_type2 const& min2 = get<min_corner, Dimension>(b2);
69         coordinate_type2 const& max2 = get<max_corner, Dimension>(b2);
70
71         // TODO assert or exception?
72         //BOOST_GEOMETRY_ASSERT(min1 <= max1 && min2 <= max2);
73
74         if (max1 < min2 || max2 < min1)
75         {
76             return false;
77         }
78
79         if (max1 == min2 || max2 == min1)
80         {
81             touch = true;
82         }
83         
84         return box_box_loop
85                 <
86                     Dimension + 1,
87                     DimensionCount
88                 >::apply(b1, b2, touch);
89     }
90 };
91
92 template
93 <
94     std::size_t DimensionCount
95 >
96 struct box_box_loop<DimensionCount, DimensionCount>
97 {
98     template <typename Box1, typename Box2>
99     static inline bool apply(Box1 const& , Box2 const&, bool &)
100     {
101         return true;
102     }
103 };
104
105 struct box_box
106 {
107     template <typename Box1, typename Box2, typename Strategy>
108     static inline bool apply(Box1 const& b1, Box2 const& b2, Strategy const& /*strategy*/)
109     {
110         BOOST_STATIC_ASSERT((boost::is_same
111                                 <
112                                     typename geometry::coordinate_system<Box1>::type,
113                                     typename geometry::coordinate_system<Box2>::type
114                                 >::value
115                            ));
116         assert_dimension_equal<Box1, Box2>();
117
118         bool touches = false;
119         bool ok = box_box_loop
120                     <
121                         0,
122                         dimension<Box1>::type::value
123                     >::apply(b1, b2, touches);
124
125         return ok && touches;
126     }
127 };
128
129 // Areal/Areal
130
131 struct areal_interrupt_policy
132 {
133     static bool const enabled = true;
134     bool found_touch;
135     bool found_not_touch;
136
137     // dummy variable required by self_get_turn_points::get_turns
138     static bool const has_intersections = false;
139
140     inline bool result()
141     {
142         return found_touch && !found_not_touch;
143     }
144
145     inline areal_interrupt_policy()
146         : found_touch(false), found_not_touch(false)
147     {}
148
149     template <typename Range>
150     inline bool apply(Range const& range)
151     {
152         // if already rejected (temp workaround?)
153         if ( found_not_touch )
154             return true;
155
156         typedef typename boost::range_iterator<Range const>::type iterator;
157         for ( iterator it = boost::begin(range) ; it != boost::end(range) ; ++it )
158         {
159             if ( it->has(overlay::operation_intersection) )
160             {
161                 found_not_touch = true;
162                 return true;
163             }
164
165             switch(it->method)
166             {
167                 case overlay::method_crosses:
168                     found_not_touch = true;
169                     return true;
170                 case overlay::method_equal:
171                     // Segment spatially equal means: at the right side
172                     // the polygon internally overlaps. So return false.
173                     found_not_touch = true;
174                     return true;
175                 case overlay::method_touch:
176                 case overlay::method_touch_interior:
177                 case overlay::method_collinear:
178                     if ( ok_for_touch(*it) )
179                     {
180                         found_touch = true;
181                     }
182                     else
183                     {
184                         found_not_touch = true;
185                         return true;
186                     }
187                     break;
188                 case overlay::method_none :
189                 case overlay::method_disjoint :
190                 case overlay::method_error :
191                     break;
192             }
193         }
194
195         return false;
196     }
197
198     template <typename Turn>
199     inline bool ok_for_touch(Turn const& turn)
200     {
201         return turn.both(overlay::operation_union)
202             || turn.both(overlay::operation_blocked)
203             || turn.combination(overlay::operation_union, overlay::operation_blocked)
204             ;
205     }
206 };
207
208 template<typename Geometry, typename PointInRingStrategy>
209 struct check_each_ring_for_within
210 {
211     bool has_within;
212     Geometry const& m_geometry;
213     PointInRingStrategy const& m_strategy;
214
215     inline check_each_ring_for_within(Geometry const& g, PointInRingStrategy const& strategy)
216         : has_within(false)
217         , m_geometry(g)
218         , m_strategy(strategy)
219     {}
220
221     template <typename Range>
222     inline void apply(Range const& range)
223     {
224         typename geometry::point_type<Range>::type p;
225         geometry::point_on_border(p, range);
226         if ( !has_within && geometry::within(p, m_geometry, m_strategy) )
227         {
228             has_within = true;
229         }
230     }
231 };
232
233 template <typename FirstGeometry, typename SecondGeometry, typename IntersectionStrategy>
234 inline bool rings_containing(FirstGeometry const& geometry1,
235                              SecondGeometry const& geometry2,
236                              IntersectionStrategy const& strategy)
237 {
238     // NOTE: This strategy could be defined inside IntersectionStrategy
239     typedef typename IntersectionStrategy::template point_in_geometry_strategy
240         <
241             FirstGeometry, SecondGeometry
242         >::type point_in_ring_strategy_type;
243
244     point_in_ring_strategy_type point_in_ring_strategy
245         = strategy.template get_point_in_geometry_strategy<FirstGeometry, SecondGeometry>();
246
247     check_each_ring_for_within
248         <
249             FirstGeometry, point_in_ring_strategy_type
250         > checker(geometry1, point_in_ring_strategy);
251     geometry::detail::for_each_range(geometry2, checker);
252     return checker.has_within;
253 }
254
255 template <typename Geometry1, typename Geometry2>
256 struct areal_areal
257 {
258     template <typename IntersectionStrategy>
259     static inline bool apply(Geometry1 const& geometry1,
260                              Geometry2 const& geometry2,
261                              IntersectionStrategy const& strategy)
262     {
263         typedef detail::no_rescale_policy rescale_policy_type;
264         typedef typename geometry::point_type<Geometry1>::type point_type;
265         typedef detail::overlay::turn_info
266             <
267                 point_type,
268                 typename segment_ratio_type<point_type, rescale_policy_type>::type
269             > turn_info;
270
271         std::deque<turn_info> turns;
272         detail::touches::areal_interrupt_policy policy;
273         rescale_policy_type robust_policy;
274         boost::geometry::get_turns
275                 <
276                     detail::overlay::do_reverse<geometry::point_order<Geometry1>::value>::value,
277                     detail::overlay::do_reverse<geometry::point_order<Geometry2>::value>::value,
278                     detail::overlay::assign_null_policy
279                 >(geometry1, geometry2, strategy, robust_policy, turns, policy);
280
281         return policy.result()
282             && ! geometry::detail::touches::rings_containing(geometry1, geometry2, strategy)
283             && ! geometry::detail::touches::rings_containing(geometry2, geometry1, strategy);
284     }
285 };
286
287 // P/*
288
289 struct use_point_in_geometry
290 {
291     template <typename Point, typename Geometry, typename Strategy>
292     static inline bool apply(Point const& point, Geometry const& geometry, Strategy const& strategy)
293     {
294         return detail::within::point_in_geometry(point, geometry, strategy) == 0;
295     }
296 };
297
298 }}
299 #endif // DOXYGEN_NO_DETAIL
300
301 #ifndef DOXYGEN_NO_DISPATCH
302 namespace dispatch {
303
304 // TODO: Since CastedTags are used is Reverse needed?
305
306 template
307 <
308     typename Geometry1,
309     typename Geometry2,
310     typename Tag1 = typename tag<Geometry1>::type,
311     typename Tag2 = typename tag<Geometry2>::type,
312     typename CastedTag1 = typename tag_cast<Tag1, pointlike_tag, linear_tag, areal_tag>::type,
313     typename CastedTag2 = typename tag_cast<Tag2, pointlike_tag, linear_tag, areal_tag>::type,
314     bool Reverse = reverse_dispatch<Geometry1, Geometry2>::type::value
315 >
316 struct touches
317     : not_implemented<Tag1, Tag2>
318 {};
319
320 // If reversal is needed, perform it
321 template
322 <
323     typename Geometry1, typename Geometry2,
324     typename Tag1, typename Tag2,
325     typename CastedTag1, typename CastedTag2
326 >
327 struct touches<Geometry1, Geometry2, Tag1, Tag2, CastedTag1, CastedTag2, true>
328     : touches<Geometry2, Geometry1, Tag2, Tag1, CastedTag2, CastedTag1, false>
329 {
330     template <typename Strategy>
331     static inline bool apply(Geometry1 const& g1, Geometry2 const& g2, Strategy const& strategy)
332     {
333         return touches<Geometry2, Geometry1>::apply(g2, g1, strategy);
334     }
335 };
336
337 // P/P
338
339 template <typename Geometry1, typename Geometry2, typename Tag2>
340 struct touches<Geometry1, Geometry2, point_tag, Tag2, pointlike_tag, pointlike_tag, false>
341 {
342     template <typename Strategy>
343     static inline bool apply(Geometry1 const& , Geometry2 const& , Strategy const&)
344     {
345         return false;
346     }
347 };
348
349 template <typename Geometry1, typename Geometry2, typename Tag2>
350 struct touches<Geometry1, Geometry2, multi_point_tag, Tag2, pointlike_tag, pointlike_tag, false>
351 {
352     template <typename Strategy>
353     static inline bool apply(Geometry1 const&, Geometry2 const&, Strategy const&)
354     {
355         return false;
356     }
357 };
358
359 // P/*
360
361 template <typename Point, typename Geometry, typename Tag2, typename CastedTag2>
362 struct touches<Point, Geometry, point_tag, Tag2, pointlike_tag, CastedTag2, false>
363     : detail::touches::use_point_in_geometry
364 {};
365
366 // TODO: support touches(MPt, Linear/Areal)
367
368 // Box/Box
369
370 template <typename Box1, typename Box2, typename CastedTag1, typename CastedTag2>
371 struct touches<Box1, Box2, box_tag, box_tag, CastedTag1, CastedTag2, false>
372     : detail::touches::box_box
373 {};
374
375 template <typename Box1, typename Box2>
376 struct touches<Box1, Box2, box_tag, box_tag, areal_tag, areal_tag, false>
377     : detail::touches::box_box
378 {};
379
380 // L/L
381
382 template <typename Linear1, typename Linear2, typename Tag1, typename Tag2>
383 struct touches<Linear1, Linear2, Tag1, Tag2, linear_tag, linear_tag, false>
384     : detail::relate::relate_impl
385     <
386         detail::de9im::static_mask_touches_type,
387         Linear1,
388         Linear2
389     >
390 {};
391
392 // L/A
393
394 template <typename Linear, typename Areal, typename Tag1, typename Tag2>
395 struct touches<Linear, Areal, Tag1, Tag2, linear_tag, areal_tag, false>
396     : detail::relate::relate_impl
397     <
398         detail::de9im::static_mask_touches_type,
399         Linear,
400         Areal
401     >
402 {};
403
404 // A/L
405 template <typename Linear, typename Areal, typename Tag1, typename Tag2>
406 struct touches<Areal, Linear, Tag1, Tag2, areal_tag, linear_tag, false>
407     : detail::relate::relate_impl
408     <
409         detail::de9im::static_mask_touches_type,
410         Areal,
411         Linear
412     >
413 {};
414
415 // A/A
416
417 template <typename Areal1, typename Areal2, typename Tag1, typename Tag2>
418 struct touches<Areal1, Areal2, Tag1, Tag2, areal_tag, areal_tag, false>
419     : detail::relate::relate_impl
420         <
421             detail::de9im::static_mask_touches_type,
422             Areal1,
423             Areal2
424         >
425 {};
426
427 template <typename Areal1, typename Areal2>
428 struct touches<Areal1, Areal2, ring_tag, ring_tag, areal_tag, areal_tag, false>
429     : detail::touches::areal_areal<Areal1, Areal2>
430 {};
431
432 } // namespace dispatch
433 #endif // DOXYGEN_NO_DISPATCH
434
435
436 namespace resolve_strategy
437 {
438
439 struct touches
440 {
441     template <typename Geometry1, typename Geometry2, typename Strategy>
442     static inline bool apply(Geometry1 const& geometry1,
443                              Geometry2 const& geometry2,
444                              Strategy const& strategy)
445     {
446         return dispatch::touches
447             <
448                 Geometry1, Geometry2
449             >::apply(geometry1, geometry2, strategy);
450     }
451
452     template <typename Geometry1, typename Geometry2>
453     static inline bool apply(Geometry1 const& geometry1,
454                              Geometry2 const& geometry2,
455                              default_strategy)
456     {
457         typedef typename strategy::relate::services::default_strategy
458             <
459                 Geometry1,
460                 Geometry2
461             >::type strategy_type;
462
463         return dispatch::touches
464             <
465                 Geometry1, Geometry2
466             >::apply(geometry1, geometry2, strategy_type());
467     }
468 };
469
470 } // namespace resolve_strategy
471
472
473 namespace resolve_variant {
474
475 template <typename Geometry1, typename Geometry2>
476 struct touches
477 {
478     template <typename Strategy>
479     static bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy)
480     {
481         concepts::check<Geometry1 const>();
482         concepts::check<Geometry2 const>();
483
484         return resolve_strategy::touches::apply(geometry1, geometry2, strategy);
485     }
486 };
487
488 template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2>
489 struct touches<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2>
490 {
491     template <typename Strategy>
492     struct visitor: boost::static_visitor<bool>
493     {
494         Geometry2 const& m_geometry2;
495         Strategy const& m_strategy;
496
497         visitor(Geometry2 const& geometry2, Strategy const& strategy)
498             : m_geometry2(geometry2)
499             , m_strategy(strategy)
500         {}
501
502         template <typename Geometry1>
503         bool operator()(Geometry1 const& geometry1) const
504         {
505             return touches<Geometry1, Geometry2>::apply(geometry1, m_geometry2, m_strategy);
506         }
507     };
508
509     template <typename Strategy>
510     static inline bool apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1,
511                              Geometry2 const& geometry2,
512                              Strategy const& strategy)
513     {
514         return boost::apply_visitor(visitor<Strategy>(geometry2, strategy), geometry1);
515     }
516 };
517
518 template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)>
519 struct touches<Geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
520 {
521     template <typename Strategy>
522     struct visitor: boost::static_visitor<bool>
523     {
524         Geometry1 const& m_geometry1;
525         Strategy const& m_strategy;
526
527         visitor(Geometry1 const& geometry1, Strategy const& strategy)
528             : m_geometry1(geometry1)
529             , m_strategy(strategy)
530         {}
531
532         template <typename Geometry2>
533         bool operator()(Geometry2 const& geometry2) const
534         {
535             return touches<Geometry1, Geometry2>::apply(m_geometry1, geometry2, m_strategy);
536         }
537     };
538
539     template <typename Strategy>
540     static inline bool apply(Geometry1 const& geometry1,
541                              boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2,
542                              Strategy const& strategy)
543     {
544         return boost::apply_visitor(visitor<Strategy>(geometry1, strategy), geometry2);
545     }
546 };
547
548 template <BOOST_VARIANT_ENUM_PARAMS(typename T1),
549           BOOST_VARIANT_ENUM_PARAMS(typename T2)>
550 struct touches<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>,
551                boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> >
552 {
553     template <typename Strategy>
554     struct visitor: boost::static_visitor<bool>
555     {
556         Strategy const& m_strategy;
557
558         visitor(Strategy const& strategy)
559             : m_strategy(strategy)
560         {}
561
562         template <typename Geometry1, typename Geometry2>
563         bool operator()(Geometry1 const& geometry1,
564                         Geometry2 const& geometry2) const
565         {
566             return touches<Geometry1, Geometry2>::apply(geometry1, geometry2, m_strategy);
567         }
568     };
569
570     template <typename Strategy>
571     static inline bool apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1,
572                              boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2,
573                              Strategy const& strategy)
574     {
575         return boost::apply_visitor(visitor<Strategy>(strategy), geometry1, geometry2);
576     }
577 };
578
579 template <typename Geometry>
580 struct self_touches
581 {
582     static bool apply(Geometry const& geometry)
583     {
584         concepts::check<Geometry const>();
585
586         typedef typename strategy::relate::services::default_strategy
587             <
588                 Geometry, Geometry
589             >::type strategy_type;
590         typedef detail::no_rescale_policy rescale_policy_type;
591         typedef typename geometry::point_type<Geometry>::type point_type;
592         typedef detail::overlay::turn_info
593             <
594                 point_type,
595                 typename segment_ratio_type<point_type, rescale_policy_type>::type
596             > turn_info;
597
598         typedef detail::overlay::get_turn_info
599         <
600             detail::overlay::assign_null_policy
601         > policy_type;
602
603         std::deque<turn_info> turns;
604         detail::touches::areal_interrupt_policy policy;
605         strategy_type strategy;
606         rescale_policy_type robust_policy;
607         detail::self_get_turn_points::get_turns
608         <
609             policy_type
610         >::apply(geometry, strategy, robust_policy, turns, policy);
611
612         return policy.result();
613     }
614 };
615
616 template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
617 struct self_touches<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
618 {
619     struct visitor: boost::static_visitor<bool>
620     {
621         template <typename Geometry>
622         bool operator()(Geometry const& geometry) const
623         {
624             return self_touches<Geometry>::apply(geometry);
625         }
626     };
627
628     static inline bool
629     apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry)
630     {
631         return boost::apply_visitor(visitor(), geometry);
632     }
633 };
634
635 } // namespace resolve_variant
636
637
638 /*!
639 \brief \brief_check{has at least one touching point (self-tangency)}
640 \note This function can be called for one geometry (self-tangency) and
641     also for two geometries (touch)
642 \ingroup touches
643 \tparam Geometry \tparam_geometry
644 \param geometry \param_geometry
645 \return \return_check{is self-touching}
646
647 \qbk{distinguish,one geometry}
648 \qbk{[def __one_parameter__]}
649 \qbk{[include reference/algorithms/touches.qbk]}
650 */
651 template <typename Geometry>
652 inline bool touches(Geometry const& geometry)
653 {
654     return resolve_variant::self_touches<Geometry>::apply(geometry);
655 }
656
657
658 /*!
659 \brief \brief_check2{have at least one touching point (tangent - non overlapping)}
660 \ingroup touches
661 \tparam Geometry1 \tparam_geometry
662 \tparam Geometry2 \tparam_geometry
663 \param geometry1 \param_geometry
664 \param geometry2 \param_geometry
665 \return \return_check2{touch each other}
666
667 \qbk{distinguish,two geometries}
668 \qbk{[include reference/algorithms/touches.qbk]}
669  */
670 template <typename Geometry1, typename Geometry2>
671 inline bool touches(Geometry1 const& geometry1, Geometry2 const& geometry2)
672 {
673     return resolve_variant::touches
674         <
675             Geometry1, Geometry2
676         >::apply(geometry1, geometry2, default_strategy());
677 }
678
679 /*!
680 \brief \brief_check2{have at least one touching point (tangent - non overlapping)}
681 \ingroup touches
682 \tparam Geometry1 \tparam_geometry
683 \tparam Geometry2 \tparam_geometry
684 \tparam Strategy \tparam_strategy{Touches}
685 \param geometry1 \param_geometry
686 \param geometry2 \param_geometry
687 \param strategy \param_strategy{touches}
688 \return \return_check2{touch each other}
689
690 \qbk{distinguish,with strategy}
691 \qbk{[include reference/algorithms/touches.qbk]}
692  */
693 template <typename Geometry1, typename Geometry2, typename Strategy>
694 inline bool touches(Geometry1 const& geometry1,
695                     Geometry2 const& geometry2,
696                     Strategy const& strategy)
697 {
698     return resolve_variant::touches
699         <
700             Geometry1, Geometry2
701         >::apply(geometry1, geometry2, strategy);
702 }
703
704
705 }} // namespace boost::geometry
706
707 #endif // BOOST_GEOMETRY_ALGORITHMS_TOUCHES_HPP