vgl_lineseg_test.hxx
Go to the documentation of this file.
1 // This is core/vgl/vgl_lineseg_test.hxx
2 #ifndef vgl_lineseg_test_hxx_
3 #define vgl_lineseg_test_hxx_
4 //:
5 // \file
6 // \author fsm
7 
8 #include <cmath>
9 #include "vgl_lineseg_test.h"
10 #include <vgl/vgl_tolerance.h>
11 #include <vgl/vgl_triangle_test.h>
12 #ifdef _MSC_VER
13 # include <vcl_msvc_warnings.h>
14 #endif
15 
16 template <class T>
17 bool vgl_lineseg_test_line(T x1, T y1, T x2, T y2, T x3, T y3, T x4, T y4)
18 {
19  T a = vgl_triangle_test_discriminant(x1, y1, x2, y2, x3, y3);
20  T b = vgl_triangle_test_discriminant(x1, y1, x2, y2, x4, y4);
21  // this condition just says that [3] and [4] lie on opposite
22  // sides of the line joining [1], [2].
23  return (a<=0 && b>=0) || (a>=0 && b<=0);
24 }
25 
26 // Returns true iif (x3,y3) lies inbetween (x1,y1) and (x2,y2);
27 // all three points are assumed to be collinear
28 template <class T>
29 static inline
30 bool inbetween(T x1, T y1, T x2, T y2, T x3, T y3)
31 {
32  return (x1-x3)*(x2-x3)<=0 && (y1-y3)*(y2-y3)<=0;
33 }
34 
35 template <class T>
36 bool vgl_lineseg_test_lineseg(T x1, T y1, T x2, T y2, T x3, T y3, T x4, T y4)
37 {
38  // reduce precision of inputs so that signs of vgl_triangle_test_discriminants
39  // `a', `b', `c', and `d' are more stable when they are very close to zero.
40 
41  double px1 = x1;
42  double py1 = y1;
43  double px2 = x2;
44  double py2 = y2;
45  double px3 = x3;
46  double py3 = y3;
47  double px4 = x4;
48  double py4 = y4;
49 
50  px1 = (px1 + px1*1e4) - px1*1e4;
51  py1 = (py1 + py1*1e4) - py1*1e4;
52  px2 = (px2 + px2*1e4) - px2*1e4;
53  py2 = (py2 + py2*1e4) - py2*1e4;
54  px3 = (px3 + px3*1e4) - px3*1e4;
55  py3 = (py3 + py3*1e4) - py3*1e4;
56  px4 = (px4 + px4*1e4) - px4*1e4;
57  py4 = (py4 + py4*1e4) - py4*1e4;
58 
59  // two lines intersect if p1 and p2 are on two opposite sides of the line p3-p4
60  // and p3 and p4 are on two opposite sides of line p1-p2
61  // degenerate cases (collinear points) are tricky to handle
62 
63  double a = vgl_triangle_test_discriminant(px1, py1, px2, py2, px3, py3);
64  double b = vgl_triangle_test_discriminant(px1, py1, px2, py2, px4, py4);
65  double c = vgl_triangle_test_discriminant(px3, py3, px4, py4, px1, py1);
66  double d = vgl_triangle_test_discriminant(px3, py3, px4, py4, px2, py2);
67 
68  // force to be zero when they're close to zero
69  a = (std::abs(a) < 1e-12) ? 0 : a;
70  b = (std::abs(b) < 1e-12) ? 0 : b;
71  c = (std::abs(c) < 1e-12) ? 0 : c;
72  d = (std::abs(d) < 1e-12) ? 0 : d;
73 
74  return
75  ( ( (a<=0 && b>0) || (a>=0 && b<0) || (a<0 && b>=0) || (a>0 && b<=0) ) &&
76  ( (c<=0 && d>0) || (c>=0 && d<0) || (c<0 && d>=0) || (c>0 && d<=0) ) )
77  ||
78  ( // the above two conditions are only sufficient for noncollinear line segments! - PVr
79  a == 0 && b == 0 && c == 0 && d == 0 &&
80  ( inbetween(px1, py1, px2, py2, px3, py3) ||
81  inbetween(px1, py1, px2, py2, px4, py4) ||
82  inbetween(px3, py3, px4, py4, px1, py1) ||
83  inbetween(px3, py3, px4, py4, px2, py2) )
84  );
85 }
86 
87 //: true if the point lies on the line segment and is between the endpoints
88 // \relatesalso vgl_point_2d
89 // \relatesalso vgl_line_segment_2d
90 template <class T>
92  vgl_line_segment_2d<T> const& lseg)
93 {
94  vgl_point_2d<T> p1 = lseg.point1(), p2 = lseg.point2();
95  T x1 = p1.x(), y1 = p1.y(),
96  x2 = p2.x(), y2 = p2.y(),
97  xp = p.x(), yp = p.y();
98  // compute squared distances
99  double d1p = static_cast<double>((xp-x1)*(xp-x1) + (yp-y1)*(yp-y1));
100  double d2p = static_cast<double>((xp-x2)*(xp-x2) + (yp-y2)*(yp-y2));
101  double d12 = static_cast<double>((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
102  double diff = std::sqrt(d1p) + std::sqrt(d2p) - std::sqrt(d12);
103  // diff is always >= 0 (triangle inequality)
104  return diff <= vgl_tolerance<double>::position;
105 }
106 
107 //--------------------------------------------------------------------------------
108 
109 #undef VGL_LINESEG_TEST_INSTANTIATE
110 #define VGL_LINESEG_TEST_INSTANTIATE(T) \
111 template bool vgl_lineseg_test_line(T, T, T, T, T, T, T, T); \
112 template bool vgl_lineseg_test_lineseg(T, T, T, T, T, T, T, T)
113 
114 #endif // vgl_lineseg_test_hxx_
bool vgl_lineseg_test_line(vgl_line_2d< T > const &l1, vgl_line_segment_2d< T > const &l2)
true if the line meets the linesegment.
vgl_point_2d< Type > point2() const
The other end-point of the line segment.
bool vgl_lineseg_test_lineseg(vgl_line_segment_2d< T > const &l1, vgl_line_segment_2d< T > const &l2)
return true if the two linesegments meet.
Type & y()
Definition: vgl_point_2d.h:72
T vgl_triangle_test_discriminant(T x1, T y1, T x2, T y2, T x3, T y3)
Compute discriminant function.
vgl_point_2d< Type > point1() const
One end-point of the line segment.
bool vgl_lineseg_test_point(vgl_point_2d< T > const &p, vgl_line_segment_2d< T > const &lseg)
true if the point lies on the line segment and is between the endpoints.
Type & x()
Definition: vgl_point_2d.h:71