1 // Boost.Geometry (aka GGL, Generic Geometry Library)
2 
3 // Copyright (c) 2014-2015, Oracle and/or its affiliates.
4 
5 // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
6 
7 // Licensed under the Boost Software License version 1.0.
8 // http://www.boost.org/users/license.html
9 
10 #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_IS_ACCEPTABLE_TURN_HPP
11 #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_IS_ACCEPTABLE_TURN_HPP
12 
13 #include <boost/range.hpp>
14 
15 #include <boost/geometry/core/point_order.hpp>
16 #include <boost/geometry/core/tag.hpp>
17 #include <boost/geometry/core/tags.hpp>
18 
19 #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
20 
21 
22 namespace boost { namespace geometry
23 {
24 
25 
26 #ifndef DOXYGEN_NO_DETAIL
27 namespace detail { namespace is_valid
28 {
29 
30 
31 template
32 <
33     typename Geometry,
34     order_selector Order = geometry::point_order<Geometry>::value,
35     typename Tag = typename tag<Geometry>::type
36 >
37 struct acceptable_operation
38 {};
39 
40 template <typename Polygon>
41 struct acceptable_operation<Polygon, counterclockwise, polygon_tag>
42 {
43     static const detail::overlay::operation_type value =
44         detail::overlay::operation_union;
45 };
46 
47 template <typename Polygon>
48 struct acceptable_operation<Polygon, clockwise, polygon_tag>
49 {
50     static const detail::overlay::operation_type value =
51         detail::overlay::operation_intersection;
52 };
53 
54 template <typename MultiPolygon>
55 struct acceptable_operation<MultiPolygon, counterclockwise, multi_polygon_tag>
56 {
57     static const detail::overlay::operation_type value =
58         detail::overlay::operation_intersection;
59 };
60 
61 template <typename MultiPolygon>
62 struct acceptable_operation<MultiPolygon, clockwise, multi_polygon_tag>
63 {
64     static const detail::overlay::operation_type value =
65         detail::overlay::operation_union;
66 };
67 
68 
69 
70 
71 template <typename Geometry, typename Tag = typename tag<Geometry>::type>
72 struct is_acceptable_turn
73 {};
74 
75 template <typename Ring>
76 struct is_acceptable_turn<Ring, ring_tag>
77 {
78     template <typename Turn>
applyboost::geometry::detail::is_valid::is_acceptable_turn79     static inline bool apply(Turn const&)
80     {
81         return false;
82     }
83 };
84 
85 template <typename Polygon>
86 class is_acceptable_turn<Polygon, polygon_tag>
87 {
88 protected:
89     template <typename Turn, typename Method, typename Operation>
check_turn(Turn const & turn,Method method,Operation operation)90     static inline bool check_turn(Turn const& turn,
91                                   Method method,
92                                   Operation operation)
93     {
94         return turn.method == method
95             && turn.operations[0].operation == operation
96             && turn.operations[1].operation == operation;
97     }
98 
99 
100 public:
101     template <typename Turn>
apply(Turn const & turn)102     static inline bool apply(Turn const& turn)
103     {
104         using namespace detail::overlay;
105 
106         if ( turn.operations[0].seg_id.ring_index
107              == turn.operations[1].seg_id.ring_index )
108         {
109             return false;
110         }
111 
112         operation_type const op = acceptable_operation<Polygon>::value;
113 
114         return check_turn(turn, method_touch_interior, op)
115             || check_turn(turn, method_touch, op)
116             ;
117     }
118 };
119 
120 template <typename MultiPolygon>
121 class is_acceptable_turn<MultiPolygon, multi_polygon_tag>
122     : is_acceptable_turn<typename boost::range_value<MultiPolygon>::type>
123 {
124 private:
125     typedef typename boost::range_value<MultiPolygon>::type polygon;
126     typedef is_acceptable_turn<polygon> base;
127 
128 public:
129     template <typename Turn>
apply(Turn const & turn)130     static inline bool apply(Turn const& turn)
131     {
132         using namespace detail::overlay;
133 
134         if ( turn.operations[0].seg_id.multi_index
135              == turn.operations[1].seg_id.multi_index )
136         {
137             return base::apply(turn);
138         }
139 
140         operation_type const op = acceptable_operation<MultiPolygon>::value;
141         if ( base::check_turn(turn, method_touch_interior, op)
142           || base::check_turn(turn, method_touch, op))
143         {
144             return true;
145         }
146 
147         // Turn is acceptable only in case of a touch(interior) and both lines
148         // (polygons) do not cross
149         return (turn.method == method_touch
150                 || turn.method == method_touch_interior)
151                 && turn.touch_only;
152     }
153 };
154 
155 
156 }} // namespace detail::is_valid
157 #endif // DOXYGEN_NO_DETAIL
158 
159 }} // namespace boost::geometry
160 
161 #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_IS_ACCEPTABLE_TURN_HPP
162