Imported Upstream version 1.57.0
[platform/upstream/boost.git] / boost / geometry / algorithms / detail / buffer / get_piece_turns.hpp
1 // Boost.Geometry (aka GGL, Generic Geometry Library)
2
3 // Copyright (c) 2012-2014 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_BUFFER_GET_PIECE_TURNS_HPP
10 #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_GET_PIECE_TURNS_HPP
11
12 #include <boost/range.hpp>
13
14 #include <boost/geometry/algorithms/equals.hpp>
15 #include <boost/geometry/algorithms/expand.hpp>
16 #include <boost/geometry/algorithms/detail/disjoint/box_box.hpp>
17 #include <boost/geometry/algorithms/detail/overlay/segment_identifier.hpp>
18 #include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp>
19
20
21 namespace boost { namespace geometry
22 {
23
24
25 #ifndef DOXYGEN_NO_DETAIL
26 namespace detail { namespace buffer
27 {
28
29
30 struct piece_get_box
31 {
32     template <typename Box, typename Piece>
33     static inline void apply(Box& total, Piece const& piece)
34     {
35         geometry::expand(total, piece.robust_envelope);
36     }
37 };
38
39 struct piece_ovelaps_box
40 {
41     template <typename Box, typename Piece>
42     static inline bool apply(Box const& box, Piece const& piece)
43     {
44         return ! geometry::detail::disjoint::disjoint_box_box(box, piece.robust_envelope);
45     }
46 };
47
48 template
49 <
50     typename Rings,
51     typename Turns,
52     typename RobustPolicy
53 >
54 class piece_turn_visitor
55 {
56     Rings const& m_rings;
57     Turns& m_turns;
58     RobustPolicy const& m_robust_policy;
59
60     template <typename Piece>
61     inline bool is_adjacent(Piece const& piece1, Piece const& piece2) const
62     {
63         if (piece1.first_seg_id.multi_index != piece2.first_seg_id.multi_index)
64         {
65             return false;
66         }
67
68         return piece1.index == piece2.left_index
69             || piece1.index == piece2.right_index;
70     }
71
72     template <typename Range, typename Iterator>
73     inline void move_to_next_point(Range const& range, Iterator& next) const
74     {
75         ++next;
76         if (next == boost::end(range))
77         {
78             next = boost::begin(range) + 1;
79         }
80     }
81
82     template <typename Range, typename Iterator>
83     inline Iterator next_point(Range const& range, Iterator it) const
84     {
85         Iterator result = it;
86         move_to_next_point(range, result);
87         // TODO: we could use either piece-boundaries, or comparison with
88         // robust points, to check if the point equals the last one
89         while(geometry::equals(*it, *result))
90         {
91             move_to_next_point(range, result);
92         }
93         return result;
94     }
95
96     template <typename Piece>
97     inline void calculate_turns(Piece const& piece1, Piece const& piece2)
98     {
99         typedef typename boost::range_value<Rings const>::type ring_type;
100         typedef typename boost::range_value<Turns const>::type turn_type;
101         typedef typename boost::range_iterator<ring_type const>::type iterator;
102
103         segment_identifier seg_id1 = piece1.first_seg_id;
104         segment_identifier seg_id2 = piece2.first_seg_id;
105
106         if (seg_id1.segment_index < 0 || seg_id2.segment_index < 0)
107         {
108             return;
109         }
110
111         ring_type const& ring1 = m_rings[seg_id1.multi_index];
112         iterator it1_first = boost::begin(ring1) + seg_id1.segment_index;
113         iterator it1_last = boost::begin(ring1) + piece1.last_segment_index;
114
115         ring_type const& ring2 = m_rings[seg_id2.multi_index];
116         iterator it2_first = boost::begin(ring2) + seg_id2.segment_index;
117         iterator it2_last = boost::begin(ring2) + piece2.last_segment_index;
118
119         turn_type the_model;
120         the_model.operations[0].piece_index = piece1.index;
121         the_model.operations[0].seg_id = piece1.first_seg_id;
122
123         iterator it1 = it1_first;
124         for (iterator prev1 = it1++;
125                 it1 != it1_last;
126                 prev1 = it1++, the_model.operations[0].seg_id.segment_index++)
127         {
128             the_model.operations[1].piece_index = piece2.index;
129             the_model.operations[1].seg_id = piece2.first_seg_id;
130
131             iterator next1 = next_point(ring1, it1);
132
133             iterator it2 = it2_first;
134             for (iterator prev2 = it2++;
135                     it2 != it2_last;
136                     prev2 = it2++, the_model.operations[1].seg_id.segment_index++)
137             {
138                 iterator next2 = next_point(ring2, it2);
139
140                 // TODO: internally get_turn_info calculates robust points.
141                 // But they are already calculated.
142                 // We should be able to use them.
143                 // this means passing them to this visitor,
144                 // and iterating in sync with them...
145                 typedef detail::overlay::get_turn_info
146                     <
147                         detail::overlay::assign_null_policy
148                     > turn_policy;
149
150                 turn_policy::apply(*prev1, *it1, *next1,
151                                     *prev2, *it2, *next2,
152                                     false, false, false, false,
153                                     the_model, m_robust_policy,
154                                     std::back_inserter(m_turns));
155             }
156         }
157     }
158
159 public:
160
161     piece_turn_visitor(Rings const& ring_collection,
162             Turns& turns,
163             RobustPolicy const& robust_policy)
164         : m_rings(ring_collection)
165         , m_turns(turns)
166         , m_robust_policy(robust_policy)
167     {}
168
169     template <typename Piece>
170     inline void apply(Piece const& piece1, Piece const& piece2,
171                     bool first = true)
172     {
173         boost::ignore_unused_variable_warning(first);
174         if ( is_adjacent(piece1, piece2)
175           || detail::disjoint::disjoint_box_box(piece1.robust_envelope,
176                     piece2.robust_envelope))
177         {
178             return;
179         }
180         calculate_turns(piece1, piece2);
181     }
182 };
183
184
185 }} // namespace detail::buffer
186 #endif // DOXYGEN_NO_DETAIL
187
188
189 }} // namespace boost::geometry
190
191 #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_GET_PIECE_TURNS_HPP