1 // Boost.Geometry (aka GGL, Generic Geometry Library)
3 // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
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)
9 #ifndef BOOST_GEOMETRY_GEOMETRY_POLICIES_RELATE_DIRECTION_HPP
10 #define BOOST_GEOMETRY_GEOMETRY_POLICIES_RELATE_DIRECTION_HPP
16 #include <boost/concept_check.hpp>
18 #include <boost/geometry/arithmetic/determinant.hpp>
19 #include <boost/geometry/strategies/side_info.hpp>
21 #include <boost/geometry/util/math.hpp>
22 #include <boost/geometry/util/select_calculation_type.hpp>
23 #include <boost/geometry/util/select_most_precise.hpp>
26 namespace boost { namespace geometry
30 namespace policies { namespace relate
35 // NOTE: "char" will be replaced by enum in future version
37 inline direction_type(side_info const& s, char h,
39 int da = 0, int db = 0,
53 inline direction_type(char h, bool op, int ha = 0, int hb = 0)
67 // NOTE: "char" will be replaced by enum in future version
68 // "How" is the intersection formed?
71 // Is it opposite (for collinear/equal cases)
74 // Information on how A arrives at intersection, how B arrives at intersection
75 // 1: arrives at intersection
76 // -1: starts from intersection
80 // Direction: how is A positioned from B
81 // 1: points left, seen from IP
82 // -1: points right, seen from IP
83 // In case of intersection: B's TO direction
84 // In case that B's TO direction is at A: B's from direction
85 // In collinear cases: it is 0
86 int dir_a; // Direction of A-s TO from IP
87 int dir_b; // Direction of B-s TO from IP
91 // THIS IS EQUAL TO arrival_a, arrival_b - they probably can go now we have robust fractions
92 int arrival[2]; // 1=arrival, -1=departure, 0=neutral; == how_a//how_b
95 // About arrival[0] (== arrival of a2 w.r.t. b) for COLLINEAR cases
96 // Arrival 1: a1--------->a2 (a arrives within b)
99 // Arrival 1: (a in b)
103 // Arrival -1: a1--------->a2 (a does not arrive within b)
106 // Arrival -1: (b in a) a_1-------------a_2
109 // Arrival 0: a1------->a2 (a arrives at TO-border of b)
114 struct segments_direction
116 typedef direction_type return_type;
122 typename SegmentIntersectionInfo
124 static inline return_type segments_crosses(side_info const& sides,
125 SegmentIntersectionInfo const& ,
126 Segment1 const& , Segment2 const& )
128 bool const ra0 = sides.get<0,0>() == 0;
129 bool const ra1 = sides.get<0,1>() == 0;
130 bool const rb0 = sides.get<1,0>() == 0;
131 bool const rb1 = sides.get<1,1>() == 0;
134 // opposite and same starting point (FROM)
135 ra0 && rb0 ? calculate_side<1>(sides, 'f', -1, -1)
137 // opposite and point to each other (TO)
138 : ra1 && rb1 ? calculate_side<0>(sides, 't', 1, 1)
140 // not opposite, forming an angle, first a then b,
141 // directed either both left, or both right
142 // Check side of B2 from A. This is not calculated before
143 : ra1 && rb0 ? angle<1>(sides, 'a', 1, -1)
145 // not opposite, forming a angle, first b then a,
146 // directed either both left, or both right
147 : ra0 && rb1 ? angle<0>(sides, 'a', -1, 1)
149 // b starts from interior of a
150 : rb0 ? starts_from_middle(sides, 'B', 0, -1)
152 // a starts from interior of b (#39)
153 : ra0 ? starts_from_middle(sides, 'A', -1, 0)
155 // b ends at interior of a, calculate direction of A from IP
156 : rb1 ? b_ends_at_middle(sides)
158 // a ends at interior of b
159 : ra1 ? a_ends_at_middle(sides)
161 // normal intersection
162 : calculate_side<1>(sides, 'i', -1, -1)
166 template <typename Ratio>
167 static inline int arrival_value(Ratio const& r_from, Ratio const& r_to)
179 // both arrive there -> r-to = 1/1, or 0/1 (on_segment)
181 // First check the TO (for arrival), then FROM (for departure)
182 return r_to.in_segment() ? 1
183 : r_to.on_segment() ? 0
184 : r_from.on_segment() ? -1
189 template <typename Ratio>
190 static inline void analyze(Ratio const& r,
191 int& in_segment_count,
193 int& outside_segment_count)
199 else if (r.in_segment())
205 outside_segment_count++;
209 static inline int arrival_from_position_value(int /*v_from*/, int v_to)
212 : v_to == 1 || v_to == 3 ? 0
213 //: v_from >= 1 && v_from <= 3 ? -1
216 // NOTE: this should be an equivalent of the above for the other order
217 /* (v_from < 3 && v_to > 3) || (v_from > 3 && v_to < 3) ? 1
218 : v_from == 3 || v_to == 3 ? 0
222 static inline void analyse_position_value(int pos_val,
223 int & in_segment_count,
225 int & outside_segment_count)
227 if ( pos_val == 1 || pos_val == 3 )
231 else if ( pos_val == 2 )
237 outside_segment_count++;
241 template <typename Segment1, typename Segment2, typename Ratio>
242 static inline return_type segments_collinear(
243 Segment1 const& , Segment2 const& , bool opposite,
244 int a1_wrt_b, int a2_wrt_b, int b1_wrt_a, int b2_wrt_a,
245 Ratio const& /*ra_from_wrt_b*/, Ratio const& /*ra_to_wrt_b*/,
246 Ratio const& /*rb_from_wrt_a*/, Ratio const& /*rb_to_wrt_a*/)
248 return_type r('c', opposite);
250 // IMPORTANT: the order of conditions is different as in intersection_points.hpp
251 // We assign A in 0 and B in 1
252 r.arrival[0] = arrival_from_position_value(a1_wrt_b, a2_wrt_b);
253 r.arrival[1] = arrival_from_position_value(b1_wrt_a, b2_wrt_a);
256 int a_in_segment_count = 0;
257 int a_on_end_count = 0;
258 int a_outside_segment_count = 0;
259 int b_in_segment_count = 0;
260 int b_on_end_count = 0;
261 int b_outside_segment_count = 0;
262 analyse_position_value(a1_wrt_b,
263 a_in_segment_count, a_on_end_count, a_outside_segment_count);
264 analyse_position_value(a2_wrt_b,
265 a_in_segment_count, a_on_end_count, a_outside_segment_count);
266 analyse_position_value(b1_wrt_a,
267 b_in_segment_count, b_on_end_count, b_outside_segment_count);
268 analyse_position_value(b2_wrt_a,
269 b_in_segment_count, b_on_end_count, b_outside_segment_count);
271 if (a_on_end_count == 1
272 && b_on_end_count == 1
273 && a_outside_segment_count == 1
274 && b_outside_segment_count == 1)
276 // This is a collinear touch
277 // --------> A (or B)
278 // <---------- B (or A)
279 // We adapt the "how"
280 // TODO: how was to be refactored anyway,
287 r.how = r.arrival[0] == 0 ? 't' : 'f';
290 else if (a_on_end_count == 2
291 && b_on_end_count == 2)
299 template <typename Segment>
300 static inline return_type degenerate(Segment const& , bool)
302 return return_type('0', false);
305 template <typename Segment, typename Ratio>
306 static inline return_type one_degenerate(Segment const& ,
311 return return_type('0', false);
314 static inline return_type disjoint()
316 return return_type('d', false);
319 static inline return_type error(std::string const&)
321 // Return "E" to denote error
322 // This will throw an error in get_turn_info
323 // TODO: change to enum or similar
324 return return_type('E', false);
329 template <std::size_t I>
330 static inline return_type calculate_side(side_info const& sides,
331 char how, int how_a, int how_b)
333 int const dir = sides.get<1, I>() == 1 ? 1 : -1;
334 return return_type(sides, how, how_a, how_b, -dir, dir);
337 template <std::size_t I>
338 static inline return_type angle(side_info const& sides,
339 char how, int how_a, int how_b)
341 int const dir = sides.get<1, I>() == 1 ? 1 : -1;
342 return return_type(sides, how, how_a, how_b, dir, dir);
346 static inline return_type starts_from_middle(side_info const& sides,
348 int how_a, int how_b)
350 // Calculate ARROW of b segment w.r.t. s1
351 int dir = sides.get<1, 1>() == 1 ? 1 : -1;
353 // From other perspective, then reverse
354 bool const is_a = which == 'A';
360 return return_type(sides, 's',
364 ! is_a ? dir : -dir);
370 static inline return_type a_ends_at_middle(side_info const& sides)
372 // Ending at the middle, one ARRIVES, the other one is NEUTRAL
373 // (because it both "arrives" and "departs" there)
374 int const dir = sides.get<1, 1>() == 1 ? 1 : -1;
375 return return_type(sides, 'm', 1, 0, dir, dir);
379 static inline return_type b_ends_at_middle(side_info const& sides)
381 int const dir = sides.get<0, 1>() == 1 ? 1 : -1;
382 return return_type(sides, 'm', 0, 1, dir, dir);
387 }} // namespace policies::relate
389 }} // namespace boost::geometry
391 #endif // BOOST_GEOMETRY_GEOMETRY_POLICIES_RELATE_DIRECTION_HPP