You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and dots ('.'), can be up to 35 characters long. Letters must be lowercase.
348 lines
11 KiB
348 lines
11 KiB
// Boost.Geometry (aka GGL, Generic Geometry Library) |
|
|
|
// Copyright (c) 2007-2011 Barend Gehrels, Amsterdam, the Netherlands. |
|
|
|
// Use, modification and distribution is subject to the Boost Software License, |
|
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at |
|
// http://www.boost.org/LICENSE_1_0.txt) |
|
|
|
#ifndef BOOST_GEOMETRY_GEOMETRY_POLICIES_RELATE_DIRECTION_HPP |
|
#define BOOST_GEOMETRY_GEOMETRY_POLICIES_RELATE_DIRECTION_HPP |
|
|
|
|
|
#include <cstddef> |
|
#include <string> |
|
|
|
#include <boost/concept_check.hpp> |
|
|
|
#include <boost/geometry/strategies/side_info.hpp> |
|
|
|
#include <boost/geometry/util/math.hpp> |
|
#include <boost/geometry/util/select_calculation_type.hpp> |
|
#include <boost/geometry/util/select_most_precise.hpp> |
|
|
|
|
|
namespace boost { namespace geometry |
|
{ |
|
|
|
|
|
namespace policies { namespace relate |
|
{ |
|
|
|
struct direction_type |
|
{ |
|
inline direction_type(side_info const& s, char h, |
|
int ha, int hb, |
|
int da = 0, int db = 0, |
|
bool op = false) |
|
: how(h) |
|
, opposite(op) |
|
, how_a(ha) |
|
, how_b(hb) |
|
, dir_a(da) |
|
, dir_b(db) |
|
, sides(s) |
|
{ |
|
arrival[0] = ha; |
|
arrival[1] = hb; |
|
} |
|
|
|
inline direction_type(char h, bool op, int ha = 0, int hb = 0) |
|
: how(h) |
|
, opposite(op) |
|
, how_a(ha) |
|
, how_b(hb) |
|
, dir_a(0) |
|
, dir_b(0) |
|
{ |
|
arrival[0] = ha; |
|
arrival[1] = hb; |
|
} |
|
|
|
|
|
// "How" is the intersection formed? |
|
char how; |
|
|
|
// Is it opposite (for collinear/equal cases) |
|
bool opposite; |
|
|
|
// Information on how A arrives at intersection, how B arrives at intersection |
|
// 1: arrives at intersection |
|
// -1: starts from intersection |
|
int how_a; |
|
int how_b; |
|
|
|
// Direction: how is A positioned from B |
|
// 1: points left, seen from IP |
|
// -1: points right, seen from IP |
|
// In case of intersection: B's TO direction |
|
// In case that B's TO direction is at A: B's from direction |
|
// In collinear cases: it is 0 |
|
int dir_a; // Direction of A-s TO from IP |
|
int dir_b; // Direction of B-s TO from IP |
|
|
|
// New information |
|
side_info sides; |
|
int arrival[2]; // 1=arrival, -1departure, 0=neutral; == how_a//how_b |
|
|
|
|
|
// About arrival[0] (== arrival of a2 w.r.t. b) for COLLINEAR cases |
|
// Arrival 1: a1--------->a2 (a arrives within b) |
|
// b1----->b2 |
|
|
|
// Arrival 1: (a in b) |
|
// |
|
|
|
|
|
// Arrival -1: a1--------->a2 (a does not arrive within b) |
|
// b1----->b2 |
|
|
|
// Arrival -1: (b in a) a_1-------------a_2 |
|
// b_1---b_2 |
|
|
|
// Arrival 0: a1------->a2 (a arrives at TO-border of b) |
|
// b1--->b2 |
|
|
|
}; |
|
|
|
|
|
template <typename S1, typename S2, typename CalculationType = void> |
|
struct segments_direction |
|
{ |
|
typedef direction_type return_type; |
|
typedef S1 segment_type1; |
|
typedef S2 segment_type2; |
|
typedef typename select_calculation_type |
|
< |
|
S1, S2, CalculationType |
|
>::type coordinate_type; |
|
|
|
// Get the same type, but at least a double |
|
typedef typename select_most_precise<coordinate_type, double>::type rtype; |
|
|
|
|
|
static inline return_type segments_intersect(side_info const& sides, |
|
coordinate_type const& dx1, coordinate_type const& dy1, |
|
coordinate_type const& dx2, coordinate_type const& dy2, |
|
S1 const& s1, S2 const& s2) |
|
{ |
|
bool const ra0 = sides.get<0,0>() == 0; |
|
bool const ra1 = sides.get<0,1>() == 0; |
|
bool const rb0 = sides.get<1,0>() == 0; |
|
bool const rb1 = sides.get<1,1>() == 0; |
|
|
|
return |
|
// opposite and same starting point (FROM) |
|
ra0 && rb0 ? calculate_side<1>(sides, dx1, dy1, s1, s2, 'f', -1, -1) |
|
|
|
// opposite and point to each other (TO) |
|
: ra1 && rb1 ? calculate_side<0>(sides, dx1, dy1, s1, s2, 't', 1, 1) |
|
|
|
// not opposite, forming an angle, first a then b, |
|
// directed either both left, or both right |
|
// Check side of B2 from A. This is not calculated before |
|
: ra1 && rb0 ? angle<1>(sides, dx1, dy1, s1, s2, 'a', 1, -1) |
|
|
|
// not opposite, forming a angle, first b then a, |
|
// directed either both left, or both right |
|
: ra0 && rb1 ? angle<0>(sides, dx1, dy1, s1, s2, 'a', -1, 1) |
|
|
|
// b starts from interior of a |
|
: rb0 ? starts_from_middle(sides, dx1, dy1, s1, s2, 'B', 0, -1) |
|
|
|
// a starts from interior of b (#39) |
|
: ra0 ? starts_from_middle(sides, dx1, dy1, s1, s2, 'A', -1, 0) |
|
|
|
// b ends at interior of a, calculate direction of A from IP |
|
: rb1 ? b_ends_at_middle(sides, dx2, dy2, s1, s2) |
|
|
|
// a ends at interior of b |
|
: ra1 ? a_ends_at_middle(sides, dx1, dy1, s1, s2) |
|
|
|
// normal intersection |
|
: calculate_side<1>(sides, dx1, dy1, s1, s2, 'i', -1, -1) |
|
; |
|
} |
|
|
|
static inline return_type collinear_touch( |
|
coordinate_type const& , |
|
coordinate_type const& , int arrival_a, int arrival_b) |
|
{ |
|
// Though this is 'collinear', we handle it as To/From/Angle because it is the same. |
|
// It only does NOT have a direction. |
|
side_info sides; |
|
//int const arrive = how == 'T' ? 1 : -1; |
|
bool opposite = arrival_a == arrival_b; |
|
return |
|
! opposite |
|
? return_type(sides, 'a', arrival_a, arrival_b) |
|
: return_type(sides, arrival_a == 0 ? 't' : 'f', arrival_a, arrival_b, 0, 0, true); |
|
} |
|
|
|
template <typename S> |
|
static inline return_type collinear_interior_boundary_intersect(S const& , bool, |
|
int arrival_a, int arrival_b, bool opposite) |
|
{ |
|
return_type r('c', opposite); |
|
r.arrival[0] = arrival_a; |
|
r.arrival[1] = arrival_b; |
|
return r; |
|
} |
|
|
|
static inline return_type collinear_a_in_b(S1 const& , bool opposite) |
|
{ |
|
return_type r('c', opposite); |
|
r.arrival[0] = 1; |
|
r.arrival[1] = -1; |
|
return r; |
|
} |
|
static inline return_type collinear_b_in_a(S2 const& , bool opposite) |
|
{ |
|
return_type r('c', opposite); |
|
r.arrival[0] = -1; |
|
r.arrival[1] = 1; |
|
return r; |
|
} |
|
|
|
static inline return_type collinear_overlaps( |
|
coordinate_type const& , coordinate_type const& , |
|
coordinate_type const& , coordinate_type const& , |
|
int arrival_a, int arrival_b, bool opposite) |
|
{ |
|
return_type r('c', opposite); |
|
r.arrival[0] = arrival_a; |
|
r.arrival[1] = arrival_b; |
|
return r; |
|
} |
|
|
|
static inline return_type segment_equal(S1 const& , bool opposite) |
|
{ |
|
return return_type('e', opposite); |
|
} |
|
|
|
static inline return_type degenerate(S1 const& , bool) |
|
{ |
|
return return_type('0', false); |
|
} |
|
|
|
static inline return_type disjoint() |
|
{ |
|
return return_type('d', false); |
|
} |
|
|
|
static inline return_type collinear_disjoint() |
|
{ |
|
return return_type('d', false); |
|
} |
|
|
|
|
|
static inline return_type parallel() |
|
{ |
|
return return_type('p', false); |
|
} |
|
|
|
static inline return_type error(std::string const& msg) |
|
{ |
|
// msg |
|
return return_type('d', false); |
|
} |
|
|
|
private : |
|
|
|
|
|
template <std::size_t I> |
|
static inline return_type calculate_side(side_info const& sides, |
|
coordinate_type const& dx1, coordinate_type const& dy1, |
|
S1 const& s1, S2 const& s2, |
|
char how, int how_a, int how_b) |
|
{ |
|
coordinate_type dpx = get<I, 0>(s2) - get<0, 0>(s1); |
|
coordinate_type dpy = get<I, 1>(s2) - get<0, 1>(s1); |
|
|
|
// This is a "side calculation" as in the strategies, but here two terms are precalculated |
|
// We might merge this with side, offering a pre-calculated term |
|
// Waiting for implementing spherical... |
|
|
|
return dx1 * dpy - dy1 * dpx > 0 |
|
? return_type(sides, how, how_a, how_b, -1, 1) |
|
: return_type(sides, how, how_a, how_b, 1, -1); |
|
} |
|
|
|
template <std::size_t I> |
|
static inline return_type angle(side_info const& sides, |
|
coordinate_type const& dx1, coordinate_type const& dy1, |
|
S1 const& s1, S2 const& s2, |
|
char how, int how_a, int how_b) |
|
{ |
|
coordinate_type dpx = get<I, 0>(s2) - get<0, 0>(s1); |
|
coordinate_type dpy = get<I, 1>(s2) - get<0, 1>(s1); |
|
|
|
return dx1 * dpy - dy1 * dpx > 0 |
|
? return_type(sides, how, how_a, how_b, 1, 1) |
|
: return_type(sides, how, how_a, how_b, -1, -1); |
|
} |
|
|
|
|
|
static inline return_type starts_from_middle(side_info const& sides, |
|
coordinate_type const& dx1, coordinate_type const& dy1, |
|
S1 const& s1, S2 const& s2, |
|
char which, |
|
int how_a, int how_b) |
|
{ |
|
// Calculate ARROW of b segment w.r.t. s1 |
|
coordinate_type dpx = get<1, 0>(s2) - get<0, 0>(s1); |
|
coordinate_type dpy = get<1, 1>(s2) - get<0, 1>(s1); |
|
|
|
int dir = dx1 * dpy - dy1 * dpx > 0 ? 1 : -1; |
|
|
|
// From other perspective, then reverse |
|
bool const is_a = which == 'A'; |
|
if (is_a) |
|
{ |
|
dir = -dir; |
|
} |
|
|
|
return return_type(sides, 's', |
|
how_a, |
|
how_b, |
|
is_a ? dir : -dir, |
|
! is_a ? dir : -dir); |
|
} |
|
|
|
|
|
|
|
// To be harmonized |
|
static inline return_type a_ends_at_middle(side_info const& sides, |
|
coordinate_type const& dx, coordinate_type const& dy, |
|
S1 const& s1, S2 const& s2) |
|
{ |
|
coordinate_type dpx = get<1, 0>(s2) - get<0, 0>(s1); |
|
coordinate_type dpy = get<1, 1>(s2) - get<0, 1>(s1); |
|
|
|
// Ending at the middle, one ARRIVES, the other one is NEUTRAL |
|
// (because it both "arrives" and "departs" there |
|
return dx * dpy - dy * dpx > 0 |
|
? return_type(sides, 'm', 1, 0, 1, 1) |
|
: return_type(sides, 'm', 1, 0, -1, -1); |
|
} |
|
|
|
|
|
static inline return_type b_ends_at_middle(side_info const& sides, |
|
coordinate_type const& dx, coordinate_type const& dy, |
|
S1 const& s1, S2 const& s2) |
|
{ |
|
coordinate_type dpx = get<1, 0>(s1) - get<0, 0>(s2); |
|
coordinate_type dpy = get<1, 1>(s1) - get<0, 1>(s2); |
|
|
|
return dx * dpy - dy * dpx > 0 |
|
? return_type(sides, 'm', 0, 1, 1, 1) |
|
: return_type(sides, 'm', 0, 1, -1, -1); |
|
} |
|
|
|
}; |
|
|
|
}} // namespace policies::relate |
|
|
|
}} // namespace boost::geometry |
|
|
|
#endif // BOOST_GEOMETRY_GEOMETRY_POLICIES_RELATE_DIRECTION_HPP
|
|
|