1 // Boost.Geometry (aka GGL, Generic Geometry Library)
2 
3 // Copyright (c) 2017 Barend Gehrels, Amsterdam, the Netherlands.
4 
5 // Use, modification and distribution is subject to the Boost Software License,
6 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
7 // http://www.boost.org/LICENSE_1_0.txt)
8 
9 #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_HANDLE_SELF_TURNS_HPP
10 #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_HANDLE_SELF_TURNS_HPP
11 
12 #include <boost/range.hpp>
13 
14 #include <boost/geometry/algorithms/detail/overlay/is_self_turn.hpp>
15 #include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp>
16 #include <boost/geometry/algorithms/within.hpp>
17 
18 namespace boost { namespace geometry
19 {
20 
21 #ifndef DOXYGEN_NO_DETAIL
22 namespace detail { namespace overlay
23 {
24 
25 struct discard_turns
26 {
27     template <typename Turns, typename Geometry0, typename Geometry1>
28     static inline
applyboost::geometry::detail::overlay::discard_turns29     void apply(Turns& , Geometry0 const& , Geometry1 const& )
30     {}
31 };
32 
33 template <overlay_type OverlayType, operation_type OperationType>
34 struct discard_closed_turns : discard_turns {};
35 
36 // It is only implemented for operation_union, not in buffer
37 template <>
38 struct discard_closed_turns<overlay_union, operation_union>
39 {
40 
41     template <typename Turns, typename Geometry0, typename Geometry1>
42     static inline
applyboost::geometry::detail::overlay::discard_closed_turns43     void apply(Turns& turns,
44             Geometry0 const& geometry0, Geometry1 const& geometry1)
45     {
46         typedef typename boost::range_value<Turns>::type turn_type;
47 
48         for (typename boost::range_iterator<Turns>::type
49                 it = boost::begin(turns);
50              it != boost::end(turns);
51              ++it)
52         {
53             turn_type& turn = *it;
54 
55             if (turn.cluster_id >= 0
56                     || turn.discarded
57                     || ! is_self_turn<overlay_union>(turn))
58             {
59                 continue;
60             }
61 
62             bool const within =
63                     turn.operations[0].seg_id.source_index == 0
64                     ? geometry::within(turn.point, geometry1)
65                     : geometry::within(turn.point, geometry0);
66 
67             if (within)
68             {
69                 // It is in the interior of the other geometry
70                 turn.discarded = true;
71             }
72         }
73     }
74 };
75 
76 struct discard_self_intersection_turns
77 {
78     template <typename Turns, typename Geometry0, typename Geometry1>
79     static inline
applyboost::geometry::detail::overlay::discard_self_intersection_turns80     void apply(Turns& turns,
81             Geometry0 const& geometry0, Geometry1 const& geometry1)
82     {
83         typedef typename boost::range_value<Turns>::type turn_type;
84 
85         for (typename boost::range_iterator<Turns>::type
86                 it = boost::begin(turns);
87              it != boost::end(turns);
88              ++it)
89         {
90             turn_type& turn = *it;
91 
92             if (turn.cluster_id >= 0
93                     || turn.discarded
94                     || ! is_self_turn<overlay_intersection>(turn))
95             {
96                 continue;
97             }
98 
99             segment_identifier const& id0 = turn.operations[0].seg_id;
100             segment_identifier const& id1 = turn.operations[1].seg_id;
101             if (id0.multi_index != id1.multi_index
102                     || (id0.ring_index == -1 && id1.ring_index == -1)
103                     || (id0.ring_index >= 0 && id1.ring_index >= 0))
104             {
105                 // Not an ii ring (int/ext) on same ring
106                 continue;
107             }
108 
109             // It is a non co-located ii self-turn
110             // Check if it is within the other geometry
111             // If not, it can be ignored
112 
113             bool const within =
114                     turn.operations[0].seg_id.source_index == 0
115                     ? geometry::within(turn.point, geometry1)
116                     : geometry::within(turn.point, geometry0);
117 
118             if (! within)
119             {
120                 // It is not within another geometry, discard the turn
121                 turn.discarded = true;
122             }
123         }
124     }
125 };
126 
127 template <overlay_type OverlayType, operation_type OperationType>
128 struct discard_open_turns : discard_turns {};
129 
130 // Handler it for intersection
131 template <>
132 struct discard_open_turns<overlay_intersection, operation_intersection>
133         : discard_self_intersection_turns {};
134 
135 // For difference, it should be done in a different way (TODO)
136 
137 }} // namespace detail::overlay
138 #endif //DOXYGEN_NO_DETAIL
139 
140 
141 }} // namespace boost::geometry
142 
143 #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_HANDLE_SELF_TURNS_HPP
144