Chris@16
|
1 // Boost.Geometry (aka GGL, Generic Geometry Library)
|
Chris@16
|
2
|
Chris@16
|
3 // Copyright (c) 2012 Barend Gehrels, Amsterdam, the Netherlands.
|
Chris@16
|
4
|
Chris@16
|
5 // Use, modification and distribution is subject to the Boost Software License,
|
Chris@16
|
6 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
Chris@16
|
7 // http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
8
|
Chris@16
|
9 #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OCCUPATION_INFO_HPP
|
Chris@16
|
10 #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OCCUPATION_INFO_HPP
|
Chris@16
|
11
|
Chris@16
|
12 #if ! defined(NDEBUG)
|
Chris@16
|
13 // #define BOOST_GEOMETRY_DEBUG_BUFFER_OCCUPATION
|
Chris@16
|
14 #endif
|
Chris@16
|
15
|
Chris@16
|
16 #include <algorithm>
|
Chris@16
|
17 #include <boost/range.hpp>
|
Chris@16
|
18
|
Chris@16
|
19 #include <boost/geometry/core/coordinate_type.hpp>
|
Chris@16
|
20 #include <boost/geometry/core/point_type.hpp>
|
Chris@16
|
21
|
Chris@16
|
22 #include <boost/geometry/algorithms/equals.hpp>
|
Chris@16
|
23 #include <boost/geometry/iterators/closing_iterator.hpp>
|
Chris@16
|
24
|
Chris@16
|
25 #include <boost/geometry/algorithms/detail/get_left_turns.hpp>
|
Chris@16
|
26
|
Chris@16
|
27
|
Chris@16
|
28 namespace boost { namespace geometry
|
Chris@16
|
29 {
|
Chris@16
|
30
|
Chris@16
|
31
|
Chris@16
|
32 #ifndef DOXYGEN_NO_DETAIL
|
Chris@16
|
33 namespace detail
|
Chris@16
|
34 {
|
Chris@16
|
35
|
Chris@16
|
36 template <typename P>
|
Chris@16
|
37 class relaxed_less
|
Chris@16
|
38 {
|
Chris@16
|
39 typedef typename geometry::coordinate_type<P>::type coordinate_type;
|
Chris@16
|
40
|
Chris@16
|
41 coordinate_type epsilon;
|
Chris@16
|
42
|
Chris@16
|
43 public :
|
Chris@16
|
44
|
Chris@16
|
45 inline relaxed_less()
|
Chris@16
|
46 {
|
Chris@16
|
47 // TODO: adapt for ttmath, and maybe build the map in another way
|
Chris@16
|
48 // (e.g. exact constellations of segment-id's), maybe adaptive.
|
Chris@16
|
49 epsilon = std::numeric_limits<double>::epsilon() * 100.0;
|
Chris@16
|
50 }
|
Chris@16
|
51
|
Chris@16
|
52 inline bool operator()(P const& a, P const& b) const
|
Chris@16
|
53 {
|
Chris@16
|
54 coordinate_type const dx = math::abs(geometry::get<0>(a) - geometry::get<0>(b));
|
Chris@16
|
55 coordinate_type const dy = math::abs(geometry::get<1>(a) - geometry::get<1>(b));
|
Chris@16
|
56
|
Chris@16
|
57
|
Chris@16
|
58 if (dx < epsilon && dy < epsilon)
|
Chris@16
|
59 {
|
Chris@16
|
60 return false;
|
Chris@16
|
61 }
|
Chris@16
|
62 if (dx < epsilon)
|
Chris@16
|
63 {
|
Chris@16
|
64 return geometry::get<1>(a) < geometry::get<1>(b);
|
Chris@16
|
65 }
|
Chris@16
|
66
|
Chris@16
|
67 return geometry::get<0>(a) < geometry::get<0>(b);
|
Chris@16
|
68 }
|
Chris@16
|
69
|
Chris@16
|
70 inline bool equals(P const& a, P const& b) const
|
Chris@16
|
71 {
|
Chris@16
|
72 typedef typename geometry::coordinate_type<P>::type coordinate_type;
|
Chris@16
|
73
|
Chris@16
|
74 coordinate_type const dx = math::abs(geometry::get<0>(a) - geometry::get<0>(b));
|
Chris@16
|
75 coordinate_type const dy = math::abs(geometry::get<1>(a) - geometry::get<1>(b));
|
Chris@16
|
76
|
Chris@16
|
77 return dx < epsilon && dy < epsilon;
|
Chris@16
|
78 };
|
Chris@16
|
79 };
|
Chris@16
|
80
|
Chris@16
|
81
|
Chris@16
|
82 template <typename T, typename P1, typename P2>
|
Chris@16
|
83 inline T calculate_angle(P1 const& from_point, P2 const& to_point)
|
Chris@16
|
84 {
|
Chris@16
|
85 typedef P1 vector_type;
|
Chris@16
|
86 vector_type v = from_point;
|
Chris@16
|
87 geometry::subtract_point(v, to_point);
|
Chris@16
|
88 return atan2(geometry::get<1>(v), geometry::get<0>(v));
|
Chris@16
|
89 }
|
Chris@16
|
90
|
Chris@16
|
91 template <typename Iterator, typename Vector>
|
Chris@16
|
92 inline Iterator advance_circular(Iterator it, Vector const& vector, segment_identifier& seg_id, bool forward = true)
|
Chris@16
|
93 {
|
Chris@16
|
94 int const increment = forward ? 1 : -1;
|
Chris@16
|
95 if (it == boost::begin(vector) && increment < 0)
|
Chris@16
|
96 {
|
Chris@16
|
97 it = boost::end(vector);
|
Chris@16
|
98 seg_id.segment_index = boost::size(vector);
|
Chris@16
|
99 }
|
Chris@16
|
100 it += increment;
|
Chris@16
|
101 seg_id.segment_index += increment;
|
Chris@16
|
102 if (it == boost::end(vector))
|
Chris@16
|
103 {
|
Chris@16
|
104 seg_id.segment_index = 0;
|
Chris@16
|
105 it = boost::begin(vector);
|
Chris@16
|
106 }
|
Chris@16
|
107 return it;
|
Chris@16
|
108 }
|
Chris@16
|
109
|
Chris@16
|
110 template <typename Point, typename T>
|
Chris@16
|
111 struct angle_info
|
Chris@16
|
112 {
|
Chris@16
|
113 typedef T angle_type;
|
Chris@16
|
114 typedef Point point_type;
|
Chris@16
|
115
|
Chris@16
|
116 segment_identifier seg_id;
|
Chris@16
|
117 int turn_index;
|
Chris@16
|
118 int operation_index;
|
Chris@16
|
119 Point intersection_point;
|
Chris@16
|
120 Point direction_point;
|
Chris@16
|
121 T angle;
|
Chris@16
|
122 bool incoming;
|
Chris@16
|
123 };
|
Chris@16
|
124
|
Chris@16
|
125 template <typename AngleInfo>
|
Chris@16
|
126 class occupation_info
|
Chris@16
|
127 {
|
Chris@16
|
128 typedef std::vector<AngleInfo> collection_type;
|
Chris@16
|
129
|
Chris@16
|
130 struct angle_sort
|
Chris@16
|
131 {
|
Chris@16
|
132 inline bool operator()(AngleInfo const& left, AngleInfo const& right) const
|
Chris@16
|
133 {
|
Chris@16
|
134 // In this case we can compare even double using equals
|
Chris@16
|
135 // return geometry::math::equals(left.angle, right.angle)
|
Chris@16
|
136 return left.angle == right.angle
|
Chris@16
|
137 ? int(left.incoming) < int(right.incoming)
|
Chris@16
|
138 : left.angle < right.angle
|
Chris@16
|
139 ;
|
Chris@16
|
140 }
|
Chris@16
|
141 };
|
Chris@16
|
142
|
Chris@16
|
143 public :
|
Chris@16
|
144 collection_type angles;
|
Chris@16
|
145 private :
|
Chris@16
|
146 bool m_occupied;
|
Chris@16
|
147 bool m_calculated;
|
Chris@16
|
148
|
Chris@16
|
149 inline bool is_occupied()
|
Chris@16
|
150 {
|
Chris@16
|
151 if (boost::size(angles) <= 1)
|
Chris@16
|
152 {
|
Chris@16
|
153 return false;
|
Chris@16
|
154 }
|
Chris@16
|
155
|
Chris@16
|
156 std::sort(angles.begin(), angles.end(), angle_sort());
|
Chris@16
|
157
|
Chris@16
|
158 typedef geometry::closing_iterator<collection_type const> closing_iterator;
|
Chris@16
|
159 closing_iterator vit(angles);
|
Chris@16
|
160 closing_iterator end(angles, true);
|
Chris@16
|
161
|
Chris@16
|
162 closing_iterator prev = vit++;
|
Chris@16
|
163 for( ; vit != end; prev = vit++)
|
Chris@16
|
164 {
|
Chris@16
|
165 if (! geometry::math::equals(prev->angle, vit->angle)
|
Chris@16
|
166 && ! prev->incoming
|
Chris@16
|
167 && vit->incoming)
|
Chris@16
|
168 {
|
Chris@16
|
169 return false;
|
Chris@16
|
170 }
|
Chris@16
|
171 }
|
Chris@16
|
172 return true;
|
Chris@16
|
173 }
|
Chris@16
|
174
|
Chris@16
|
175 public :
|
Chris@16
|
176 inline occupation_info()
|
Chris@16
|
177 : m_occupied(false)
|
Chris@16
|
178 , m_calculated(false)
|
Chris@16
|
179 {}
|
Chris@16
|
180
|
Chris@16
|
181 template <typename PointC, typename Point1, typename Point2>
|
Chris@16
|
182 inline void add(PointC const& map_point, Point1 const& direction_point, Point2 const& intersection_point,
|
Chris@16
|
183 int turn_index, int operation_index,
|
Chris@16
|
184 segment_identifier const& seg_id, bool incoming)
|
Chris@16
|
185 {
|
Chris@16
|
186 //std::cout << "-> adding angle " << geometry::wkt(direction_point) << " .. " << geometry::wkt(intersection_point) << " " << int(incoming) << std::endl;
|
Chris@16
|
187 if (geometry::equals(direction_point, intersection_point))
|
Chris@16
|
188 {
|
Chris@16
|
189 //std::cout << "EQUAL! Skipping" << std::endl;
|
Chris@16
|
190 return;
|
Chris@16
|
191 }
|
Chris@16
|
192
|
Chris@16
|
193 AngleInfo info;
|
Chris@16
|
194 info.incoming = incoming;
|
Chris@16
|
195 info.angle = calculate_angle<typename AngleInfo::angle_type>(direction_point, map_point);
|
Chris@16
|
196 info.seg_id = seg_id;
|
Chris@16
|
197 info.turn_index = turn_index;
|
Chris@16
|
198 info.operation_index = operation_index;
|
Chris@16
|
199 info.intersection_point = intersection_point;
|
Chris@16
|
200 info.direction_point = direction_point;
|
Chris@16
|
201 angles.push_back(info);
|
Chris@16
|
202
|
Chris@16
|
203 m_calculated = false;
|
Chris@16
|
204 }
|
Chris@16
|
205
|
Chris@16
|
206 inline bool occupied()
|
Chris@16
|
207 {
|
Chris@16
|
208 if (! m_calculated)
|
Chris@16
|
209 {
|
Chris@16
|
210 m_occupied = is_occupied();
|
Chris@16
|
211 m_calculated = true;
|
Chris@16
|
212 }
|
Chris@16
|
213 return m_occupied;
|
Chris@16
|
214 }
|
Chris@16
|
215
|
Chris@16
|
216 template <typename Turns, typename TurnSegmentIndices>
|
Chris@16
|
217 inline void get_left_turns(
|
Chris@16
|
218 Turns& turns, TurnSegmentIndices const& turn_segment_indices,
|
Chris@16
|
219 std::set<int>& keep_indices)
|
Chris@16
|
220 {
|
Chris@16
|
221 std::sort(angles.begin(), angles.end(), angle_sort());
|
Chris@16
|
222 calculate_left_turns<AngleInfo>(angles, turns, turn_segment_indices, keep_indices);
|
Chris@16
|
223 }
|
Chris@16
|
224 };
|
Chris@16
|
225
|
Chris@16
|
226
|
Chris@16
|
227 template <typename Point, typename Ring, typename Info>
|
Chris@16
|
228 inline void add_incoming_and_outgoing_angles(Point const& map_point, Point const& intersection_point,
|
Chris@16
|
229 Ring const& ring,
|
Chris@16
|
230 int turn_index,
|
Chris@16
|
231 int operation_index,
|
Chris@16
|
232 segment_identifier seg_id,
|
Chris@16
|
233 Info& info)
|
Chris@16
|
234 {
|
Chris@16
|
235 typedef typename boost::range_iterator
|
Chris@16
|
236 <
|
Chris@16
|
237 Ring const
|
Chris@16
|
238 >::type iterator_type;
|
Chris@16
|
239
|
Chris@16
|
240 int const n = boost::size(ring);
|
Chris@16
|
241 if (seg_id.segment_index >= n || seg_id.segment_index < 0)
|
Chris@16
|
242 {
|
Chris@16
|
243 return;
|
Chris@16
|
244 }
|
Chris@16
|
245
|
Chris@16
|
246 segment_identifier real_seg_id = seg_id;
|
Chris@16
|
247 iterator_type it = boost::begin(ring) + seg_id.segment_index;
|
Chris@16
|
248
|
Chris@16
|
249 // TODO: if we use turn-info ("to", "middle"), we know if to advance without resorting to equals
|
Chris@16
|
250 relaxed_less<Point> comparator;
|
Chris@16
|
251
|
Chris@16
|
252 if (comparator.equals(intersection_point, *it))
|
Chris@16
|
253 {
|
Chris@16
|
254 // It should be equal only once. But otherwise we skip it (in "add")
|
Chris@16
|
255 it = advance_circular(it, ring, seg_id, false);
|
Chris@16
|
256 }
|
Chris@16
|
257
|
Chris@16
|
258 info.add(map_point, *it, intersection_point, turn_index, operation_index, real_seg_id, true);
|
Chris@16
|
259
|
Chris@16
|
260 if (comparator.equals(intersection_point, *it))
|
Chris@16
|
261 {
|
Chris@16
|
262 it = advance_circular(it, ring, real_seg_id);
|
Chris@16
|
263 }
|
Chris@16
|
264 else
|
Chris@16
|
265 {
|
Chris@16
|
266 // Don't upgrade the ID
|
Chris@16
|
267 it = advance_circular(it, ring, seg_id);
|
Chris@16
|
268 }
|
Chris@16
|
269 for (int defensive_check = 0;
|
Chris@16
|
270 comparator.equals(intersection_point, *it) && defensive_check < n;
|
Chris@16
|
271 defensive_check++)
|
Chris@16
|
272 {
|
Chris@16
|
273 it = advance_circular(it, ring, real_seg_id);
|
Chris@16
|
274 }
|
Chris@16
|
275
|
Chris@16
|
276 info.add(map_point, *it, intersection_point, turn_index, operation_index, real_seg_id, false);
|
Chris@16
|
277 }
|
Chris@16
|
278
|
Chris@16
|
279
|
Chris@16
|
280 // Map in two senses of the word: it is a std::map where the key is a point.
|
Chris@16
|
281 // Per point an "occupation_info" record is kept
|
Chris@16
|
282 // Used for the buffer (but will also be used for intersections/unions having complex self-tangencies)
|
Chris@16
|
283 template <typename Point, typename OccupationInfo>
|
Chris@16
|
284 class occupation_map
|
Chris@16
|
285 {
|
Chris@16
|
286 public :
|
Chris@16
|
287 typedef std::map<Point, OccupationInfo, relaxed_less<Point> > map_type;
|
Chris@16
|
288
|
Chris@16
|
289 map_type map;
|
Chris@16
|
290 std::set<int> turn_indices;
|
Chris@16
|
291
|
Chris@16
|
292 inline OccupationInfo& find_or_insert(Point const& point, Point& mapped_point)
|
Chris@16
|
293 {
|
Chris@16
|
294 typename map_type::iterator it = map.find(point);
|
Chris@16
|
295 if (it == boost::end(map))
|
Chris@16
|
296 {
|
Chris@16
|
297 std::pair<typename map_type::iterator, bool> pair
|
Chris@16
|
298 = map.insert(std::make_pair(point, OccupationInfo()));
|
Chris@16
|
299 it = pair.first;
|
Chris@16
|
300 }
|
Chris@16
|
301 mapped_point = it->first;
|
Chris@16
|
302 return it->second;
|
Chris@16
|
303 }
|
Chris@16
|
304
|
Chris@16
|
305 inline bool contains(Point const& point) const
|
Chris@16
|
306 {
|
Chris@16
|
307 typename map_type::const_iterator it = map.find(point);
|
Chris@16
|
308 return it != boost::end(map);
|
Chris@16
|
309 }
|
Chris@16
|
310
|
Chris@16
|
311 inline bool contains_turn_index(int index) const
|
Chris@16
|
312 {
|
Chris@16
|
313 return turn_indices.count(index) > 0;
|
Chris@16
|
314 }
|
Chris@16
|
315
|
Chris@16
|
316 inline void insert_turn_index(int index)
|
Chris@16
|
317 {
|
Chris@16
|
318 turn_indices.insert(index);
|
Chris@16
|
319 }
|
Chris@16
|
320 };
|
Chris@16
|
321
|
Chris@16
|
322
|
Chris@16
|
323 } // namespace detail
|
Chris@16
|
324 #endif // DOXYGEN_NO_DETAIL
|
Chris@16
|
325
|
Chris@16
|
326
|
Chris@16
|
327 }} // namespace boost::geometry
|
Chris@16
|
328
|
Chris@16
|
329 #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OCCUPATION_INFO_HPP
|