Chris@16
|
1 // Boost.Geometry (aka GGL, Generic Geometry Library)
|
Chris@16
|
2
|
Chris@16
|
3 // Copyright (c) 2007-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_GEOMETRY_POLICIES_RELATE_DIRECTION_HPP
|
Chris@16
|
10 #define BOOST_GEOMETRY_GEOMETRY_POLICIES_RELATE_DIRECTION_HPP
|
Chris@16
|
11
|
Chris@16
|
12
|
Chris@16
|
13 #include <cstddef>
|
Chris@16
|
14 #include <string>
|
Chris@16
|
15
|
Chris@16
|
16 #include <boost/concept_check.hpp>
|
Chris@16
|
17
|
Chris@16
|
18 #include <boost/geometry/arithmetic/determinant.hpp>
|
Chris@16
|
19 #include <boost/geometry/strategies/side_info.hpp>
|
Chris@16
|
20
|
Chris@16
|
21 #include <boost/geometry/util/math.hpp>
|
Chris@16
|
22 #include <boost/geometry/util/select_calculation_type.hpp>
|
Chris@16
|
23 #include <boost/geometry/util/select_most_precise.hpp>
|
Chris@16
|
24
|
Chris@16
|
25
|
Chris@16
|
26 namespace boost { namespace geometry
|
Chris@16
|
27 {
|
Chris@16
|
28
|
Chris@16
|
29
|
Chris@16
|
30 namespace policies { namespace relate
|
Chris@16
|
31 {
|
Chris@16
|
32
|
Chris@16
|
33 struct direction_type
|
Chris@16
|
34 {
|
Chris@16
|
35 // NOTE: "char" will be replaced by enum in future version
|
Chris@16
|
36
|
Chris@16
|
37 inline direction_type(side_info const& s, char h,
|
Chris@16
|
38 int ha, int hb,
|
Chris@16
|
39 int da = 0, int db = 0,
|
Chris@16
|
40 bool op = false)
|
Chris@16
|
41 : how(h)
|
Chris@16
|
42 , opposite(op)
|
Chris@16
|
43 , how_a(ha)
|
Chris@16
|
44 , how_b(hb)
|
Chris@16
|
45 , dir_a(da)
|
Chris@16
|
46 , dir_b(db)
|
Chris@16
|
47 , sides(s)
|
Chris@16
|
48 {
|
Chris@16
|
49 arrival[0] = ha;
|
Chris@16
|
50 arrival[1] = hb;
|
Chris@16
|
51 }
|
Chris@16
|
52
|
Chris@16
|
53 inline direction_type(char h, bool op, int ha = 0, int hb = 0)
|
Chris@16
|
54 : how(h)
|
Chris@16
|
55 , opposite(op)
|
Chris@16
|
56 , how_a(ha)
|
Chris@16
|
57 , how_b(hb)
|
Chris@16
|
58 , dir_a(0)
|
Chris@16
|
59 , dir_b(0)
|
Chris@16
|
60 {
|
Chris@16
|
61 arrival[0] = ha;
|
Chris@16
|
62 arrival[1] = hb;
|
Chris@16
|
63 }
|
Chris@16
|
64
|
Chris@16
|
65
|
Chris@16
|
66 // TODO: replace this
|
Chris@16
|
67 // NOTE: "char" will be replaced by enum in future version
|
Chris@16
|
68 // "How" is the intersection formed?
|
Chris@16
|
69 char how;
|
Chris@16
|
70
|
Chris@16
|
71 // Is it opposite (for collinear/equal cases)
|
Chris@16
|
72 bool opposite;
|
Chris@16
|
73
|
Chris@16
|
74 // Information on how A arrives at intersection, how B arrives at intersection
|
Chris@16
|
75 // 1: arrives at intersection
|
Chris@16
|
76 // -1: starts from intersection
|
Chris@16
|
77 int how_a;
|
Chris@16
|
78 int how_b;
|
Chris@16
|
79
|
Chris@16
|
80 // Direction: how is A positioned from B
|
Chris@16
|
81 // 1: points left, seen from IP
|
Chris@16
|
82 // -1: points right, seen from IP
|
Chris@16
|
83 // In case of intersection: B's TO direction
|
Chris@16
|
84 // In case that B's TO direction is at A: B's from direction
|
Chris@16
|
85 // In collinear cases: it is 0
|
Chris@16
|
86 int dir_a; // Direction of A-s TO from IP
|
Chris@16
|
87 int dir_b; // Direction of B-s TO from IP
|
Chris@16
|
88
|
Chris@16
|
89 // New information
|
Chris@16
|
90 side_info sides;
|
Chris@101
|
91 // THIS IS EQUAL TO arrival_a, arrival_b - they probably can go now we have robust fractions
|
Chris@101
|
92 int arrival[2]; // 1=arrival, -1=departure, 0=neutral; == how_a//how_b
|
Chris@16
|
93
|
Chris@16
|
94
|
Chris@16
|
95 // About arrival[0] (== arrival of a2 w.r.t. b) for COLLINEAR cases
|
Chris@16
|
96 // Arrival 1: a1--------->a2 (a arrives within b)
|
Chris@16
|
97 // b1----->b2
|
Chris@16
|
98
|
Chris@16
|
99 // Arrival 1: (a in b)
|
Chris@16
|
100 //
|
Chris@16
|
101
|
Chris@16
|
102
|
Chris@16
|
103 // Arrival -1: a1--------->a2 (a does not arrive within b)
|
Chris@16
|
104 // b1----->b2
|
Chris@16
|
105
|
Chris@16
|
106 // Arrival -1: (b in a) a_1-------------a_2
|
Chris@16
|
107 // b_1---b_2
|
Chris@16
|
108
|
Chris@16
|
109 // Arrival 0: a1------->a2 (a arrives at TO-border of b)
|
Chris@16
|
110 // b1--->b2
|
Chris@16
|
111
|
Chris@16
|
112 };
|
Chris@16
|
113
|
Chris@16
|
114 struct segments_direction
|
Chris@16
|
115 {
|
Chris@16
|
116 typedef direction_type return_type;
|
Chris@16
|
117
|
Chris@101
|
118 template
|
Chris@101
|
119 <
|
Chris@101
|
120 typename Segment1,
|
Chris@101
|
121 typename Segment2,
|
Chris@101
|
122 typename SegmentIntersectionInfo
|
Chris@101
|
123 >
|
Chris@101
|
124 static inline return_type segments_crosses(side_info const& sides,
|
Chris@101
|
125 SegmentIntersectionInfo const& ,
|
Chris@101
|
126 Segment1 const& , Segment2 const& )
|
Chris@16
|
127 {
|
Chris@16
|
128 bool const ra0 = sides.get<0,0>() == 0;
|
Chris@16
|
129 bool const ra1 = sides.get<0,1>() == 0;
|
Chris@16
|
130 bool const rb0 = sides.get<1,0>() == 0;
|
Chris@16
|
131 bool const rb1 = sides.get<1,1>() == 0;
|
Chris@16
|
132
|
Chris@16
|
133 return
|
Chris@16
|
134 // opposite and same starting point (FROM)
|
Chris@101
|
135 ra0 && rb0 ? calculate_side<1>(sides, 'f', -1, -1)
|
Chris@16
|
136
|
Chris@16
|
137 // opposite and point to each other (TO)
|
Chris@101
|
138 : ra1 && rb1 ? calculate_side<0>(sides, 't', 1, 1)
|
Chris@16
|
139
|
Chris@16
|
140 // not opposite, forming an angle, first a then b,
|
Chris@16
|
141 // directed either both left, or both right
|
Chris@16
|
142 // Check side of B2 from A. This is not calculated before
|
Chris@101
|
143 : ra1 && rb0 ? angle<1>(sides, 'a', 1, -1)
|
Chris@16
|
144
|
Chris@16
|
145 // not opposite, forming a angle, first b then a,
|
Chris@16
|
146 // directed either both left, or both right
|
Chris@101
|
147 : ra0 && rb1 ? angle<0>(sides, 'a', -1, 1)
|
Chris@16
|
148
|
Chris@16
|
149 // b starts from interior of a
|
Chris@101
|
150 : rb0 ? starts_from_middle(sides, 'B', 0, -1)
|
Chris@16
|
151
|
Chris@16
|
152 // a starts from interior of b (#39)
|
Chris@101
|
153 : ra0 ? starts_from_middle(sides, 'A', -1, 0)
|
Chris@16
|
154
|
Chris@16
|
155 // b ends at interior of a, calculate direction of A from IP
|
Chris@101
|
156 : rb1 ? b_ends_at_middle(sides)
|
Chris@16
|
157
|
Chris@16
|
158 // a ends at interior of b
|
Chris@101
|
159 : ra1 ? a_ends_at_middle(sides)
|
Chris@16
|
160
|
Chris@16
|
161 // normal intersection
|
Chris@101
|
162 : calculate_side<1>(sides, 'i', -1, -1)
|
Chris@16
|
163 ;
|
Chris@16
|
164 }
|
Chris@16
|
165
|
Chris@101
|
166 template <typename Ratio>
|
Chris@101
|
167 static inline int arrival_value(Ratio const& r_from, Ratio const& r_to)
|
Chris@16
|
168 {
|
Chris@101
|
169 // a1--------->a2
|
Chris@101
|
170 // b1----->b2
|
Chris@101
|
171 // a departs: -1
|
Chris@101
|
172
|
Chris@101
|
173 // a1--------->a2
|
Chris@101
|
174 // b1----->b2
|
Chris@101
|
175 // a arrives: 1
|
Chris@101
|
176
|
Chris@101
|
177 // a1--------->a2
|
Chris@101
|
178 // b1----->b2
|
Chris@101
|
179 // both arrive there -> r-to = 1/1, or 0/1 (on_segment)
|
Chris@101
|
180
|
Chris@101
|
181 // First check the TO (for arrival), then FROM (for departure)
|
Chris@101
|
182 return r_to.in_segment() ? 1
|
Chris@101
|
183 : r_to.on_segment() ? 0
|
Chris@101
|
184 : r_from.on_segment() ? -1
|
Chris@101
|
185 : -1
|
Chris@101
|
186 ;
|
Chris@16
|
187 }
|
Chris@16
|
188
|
Chris@101
|
189 template <typename Ratio>
|
Chris@101
|
190 static inline void analyze(Ratio const& r,
|
Chris@101
|
191 int& in_segment_count,
|
Chris@101
|
192 int& on_end_count,
|
Chris@101
|
193 int& outside_segment_count)
|
Chris@101
|
194 {
|
Chris@101
|
195 if (r.on_end())
|
Chris@101
|
196 {
|
Chris@101
|
197 on_end_count++;
|
Chris@101
|
198 }
|
Chris@101
|
199 else if (r.in_segment())
|
Chris@101
|
200 {
|
Chris@101
|
201 in_segment_count++;
|
Chris@101
|
202 }
|
Chris@101
|
203 else
|
Chris@101
|
204 {
|
Chris@101
|
205 outside_segment_count++;
|
Chris@101
|
206 }
|
Chris@101
|
207 }
|
Chris@101
|
208
|
Chris@101
|
209 static inline int arrival_from_position_value(int /*v_from*/, int v_to)
|
Chris@101
|
210 {
|
Chris@101
|
211 return v_to == 2 ? 1
|
Chris@101
|
212 : v_to == 1 || v_to == 3 ? 0
|
Chris@101
|
213 //: v_from >= 1 && v_from <= 3 ? -1
|
Chris@101
|
214 : -1;
|
Chris@101
|
215
|
Chris@101
|
216 // NOTE: this should be an equivalent of the above for the other order
|
Chris@101
|
217 /* (v_from < 3 && v_to > 3) || (v_from > 3 && v_to < 3) ? 1
|
Chris@101
|
218 : v_from == 3 || v_to == 3 ? 0
|
Chris@101
|
219 : -1;*/
|
Chris@101
|
220 }
|
Chris@101
|
221
|
Chris@101
|
222 static inline void analyse_position_value(int pos_val,
|
Chris@101
|
223 int & in_segment_count,
|
Chris@101
|
224 int & on_end_count,
|
Chris@101
|
225 int & outside_segment_count)
|
Chris@101
|
226 {
|
Chris@101
|
227 if ( pos_val == 1 || pos_val == 3 )
|
Chris@101
|
228 {
|
Chris@101
|
229 on_end_count++;
|
Chris@101
|
230 }
|
Chris@101
|
231 else if ( pos_val == 2 )
|
Chris@101
|
232 {
|
Chris@101
|
233 in_segment_count++;
|
Chris@101
|
234 }
|
Chris@101
|
235 else
|
Chris@101
|
236 {
|
Chris@101
|
237 outside_segment_count++;
|
Chris@101
|
238 }
|
Chris@101
|
239 }
|
Chris@101
|
240
|
Chris@101
|
241 template <typename Segment1, typename Segment2, typename Ratio>
|
Chris@101
|
242 static inline return_type segments_collinear(
|
Chris@101
|
243 Segment1 const& , Segment2 const& , bool opposite,
|
Chris@101
|
244 int a1_wrt_b, int a2_wrt_b, int b1_wrt_a, int b2_wrt_a,
|
Chris@101
|
245 Ratio const& /*ra_from_wrt_b*/, Ratio const& /*ra_to_wrt_b*/,
|
Chris@101
|
246 Ratio const& /*rb_from_wrt_a*/, Ratio const& /*rb_to_wrt_a*/)
|
Chris@16
|
247 {
|
Chris@16
|
248 return_type r('c', opposite);
|
Chris@101
|
249
|
Chris@101
|
250 // IMPORTANT: the order of conditions is different as in intersection_points.hpp
|
Chris@101
|
251 // We assign A in 0 and B in 1
|
Chris@101
|
252 r.arrival[0] = arrival_from_position_value(a1_wrt_b, a2_wrt_b);
|
Chris@101
|
253 r.arrival[1] = arrival_from_position_value(b1_wrt_a, b2_wrt_a);
|
Chris@101
|
254
|
Chris@101
|
255 // Analyse them
|
Chris@101
|
256 int a_in_segment_count = 0;
|
Chris@101
|
257 int a_on_end_count = 0;
|
Chris@101
|
258 int a_outside_segment_count = 0;
|
Chris@101
|
259 int b_in_segment_count = 0;
|
Chris@101
|
260 int b_on_end_count = 0;
|
Chris@101
|
261 int b_outside_segment_count = 0;
|
Chris@101
|
262 analyse_position_value(a1_wrt_b,
|
Chris@101
|
263 a_in_segment_count, a_on_end_count, a_outside_segment_count);
|
Chris@101
|
264 analyse_position_value(a2_wrt_b,
|
Chris@101
|
265 a_in_segment_count, a_on_end_count, a_outside_segment_count);
|
Chris@101
|
266 analyse_position_value(b1_wrt_a,
|
Chris@101
|
267 b_in_segment_count, b_on_end_count, b_outside_segment_count);
|
Chris@101
|
268 analyse_position_value(b2_wrt_a,
|
Chris@101
|
269 b_in_segment_count, b_on_end_count, b_outside_segment_count);
|
Chris@101
|
270
|
Chris@101
|
271 if (a_on_end_count == 1
|
Chris@101
|
272 && b_on_end_count == 1
|
Chris@101
|
273 && a_outside_segment_count == 1
|
Chris@101
|
274 && b_outside_segment_count == 1)
|
Chris@101
|
275 {
|
Chris@101
|
276 // This is a collinear touch
|
Chris@101
|
277 // --------> A (or B)
|
Chris@101
|
278 // <---------- B (or A)
|
Chris@101
|
279 // We adapt the "how"
|
Chris@101
|
280 // TODO: how was to be refactored anyway,
|
Chris@101
|
281 if (! opposite)
|
Chris@101
|
282 {
|
Chris@101
|
283 r.how = 'a';
|
Chris@101
|
284 }
|
Chris@101
|
285 else
|
Chris@101
|
286 {
|
Chris@101
|
287 r.how = r.arrival[0] == 0 ? 't' : 'f';
|
Chris@101
|
288 }
|
Chris@101
|
289 }
|
Chris@101
|
290 else if (a_on_end_count == 2
|
Chris@101
|
291 && b_on_end_count == 2)
|
Chris@101
|
292 {
|
Chris@101
|
293 r.how = 'e';
|
Chris@101
|
294 }
|
Chris@101
|
295
|
Chris@16
|
296 return r;
|
Chris@16
|
297 }
|
Chris@16
|
298
|
Chris@101
|
299 template <typename Segment>
|
Chris@101
|
300 static inline return_type degenerate(Segment const& , bool)
|
Chris@16
|
301 {
|
Chris@16
|
302 return return_type('0', false);
|
Chris@16
|
303 }
|
Chris@16
|
304
|
Chris@101
|
305 template <typename Segment, typename Ratio>
|
Chris@101
|
306 static inline return_type one_degenerate(Segment const& ,
|
Chris@101
|
307 Ratio const& ,
|
Chris@101
|
308 bool)
|
Chris@16
|
309 {
|
Chris@101
|
310 // To be decided
|
Chris@101
|
311 return return_type('0', false);
|
Chris@16
|
312 }
|
Chris@16
|
313
|
Chris@101
|
314 static inline return_type disjoint()
|
Chris@16
|
315 {
|
Chris@16
|
316 return return_type('d', false);
|
Chris@16
|
317 }
|
Chris@16
|
318
|
Chris@16
|
319 static inline return_type error(std::string const&)
|
Chris@16
|
320 {
|
Chris@16
|
321 // Return "E" to denote error
|
Chris@16
|
322 // This will throw an error in get_turn_info
|
Chris@16
|
323 // TODO: change to enum or similar
|
Chris@16
|
324 return return_type('E', false);
|
Chris@16
|
325 }
|
Chris@16
|
326
|
Chris@16
|
327 private :
|
Chris@16
|
328
|
Chris@16
|
329 template <std::size_t I>
|
Chris@16
|
330 static inline return_type calculate_side(side_info const& sides,
|
Chris@16
|
331 char how, int how_a, int how_b)
|
Chris@16
|
332 {
|
Chris@101
|
333 int const dir = sides.get<1, I>() == 1 ? 1 : -1;
|
Chris@101
|
334 return return_type(sides, how, how_a, how_b, -dir, dir);
|
Chris@16
|
335 }
|
Chris@16
|
336
|
Chris@16
|
337 template <std::size_t I>
|
Chris@16
|
338 static inline return_type angle(side_info const& sides,
|
Chris@16
|
339 char how, int how_a, int how_b)
|
Chris@16
|
340 {
|
Chris@101
|
341 int const dir = sides.get<1, I>() == 1 ? 1 : -1;
|
Chris@101
|
342 return return_type(sides, how, how_a, how_b, dir, dir);
|
Chris@16
|
343 }
|
Chris@16
|
344
|
Chris@16
|
345
|
Chris@16
|
346 static inline return_type starts_from_middle(side_info const& sides,
|
Chris@16
|
347 char which,
|
Chris@16
|
348 int how_a, int how_b)
|
Chris@16
|
349 {
|
Chris@16
|
350 // Calculate ARROW of b segment w.r.t. s1
|
Chris@101
|
351 int dir = sides.get<1, 1>() == 1 ? 1 : -1;
|
Chris@16
|
352
|
Chris@16
|
353 // From other perspective, then reverse
|
Chris@16
|
354 bool const is_a = which == 'A';
|
Chris@16
|
355 if (is_a)
|
Chris@16
|
356 {
|
Chris@16
|
357 dir = -dir;
|
Chris@16
|
358 }
|
Chris@16
|
359
|
Chris@16
|
360 return return_type(sides, 's',
|
Chris@16
|
361 how_a,
|
Chris@16
|
362 how_b,
|
Chris@16
|
363 is_a ? dir : -dir,
|
Chris@16
|
364 ! is_a ? dir : -dir);
|
Chris@16
|
365 }
|
Chris@16
|
366
|
Chris@16
|
367
|
Chris@16
|
368
|
Chris@16
|
369 // To be harmonized
|
Chris@101
|
370 static inline return_type a_ends_at_middle(side_info const& sides)
|
Chris@16
|
371 {
|
Chris@16
|
372 // Ending at the middle, one ARRIVES, the other one is NEUTRAL
|
Chris@101
|
373 // (because it both "arrives" and "departs" there)
|
Chris@101
|
374 int const dir = sides.get<1, 1>() == 1 ? 1 : -1;
|
Chris@101
|
375 return return_type(sides, 'm', 1, 0, dir, dir);
|
Chris@16
|
376 }
|
Chris@16
|
377
|
Chris@16
|
378
|
Chris@101
|
379 static inline return_type b_ends_at_middle(side_info const& sides)
|
Chris@16
|
380 {
|
Chris@101
|
381 int const dir = sides.get<0, 1>() == 1 ? 1 : -1;
|
Chris@101
|
382 return return_type(sides, 'm', 0, 1, dir, dir);
|
Chris@16
|
383 }
|
Chris@16
|
384
|
Chris@16
|
385 };
|
Chris@16
|
386
|
Chris@16
|
387 }} // namespace policies::relate
|
Chris@16
|
388
|
Chris@16
|
389 }} // namespace boost::geometry
|
Chris@16
|
390
|
Chris@16
|
391 #endif // BOOST_GEOMETRY_GEOMETRY_POLICIES_RELATE_DIRECTION_HPP
|