core/vgl/vgl_lineseg_test.txx
Go to the documentation of this file.
00001 // This is core/vgl/vgl_lineseg_test.txx
00002 #ifndef vgl_lineseg_test_txx_
00003 #define vgl_lineseg_test_txx_
00004 //:
00005 // \file
00006 // \author fsm
00007 
00008 #include "vgl_lineseg_test.h"
00009 #include <vgl/vgl_tolerance.h>
00010 #include <vgl/vgl_triangle_test.h>
00011 #include <vcl_cmath.h>
00012 
00013 template <class T>
00014 bool vgl_lineseg_test_line(T x1, T y1, T x2, T y2, T x3, T y3, T x4, T y4)
00015 {
00016   T a = vgl_triangle_test_discriminant(x1, y1, x2, y2, x3, y3);
00017   T b = vgl_triangle_test_discriminant(x1, y1, x2, y2, x4, y4);
00018   // this condition just says that [3] and [4] lie on opposite
00019   // sides of the line joining [1], [2].
00020   return (a<=0 && b>=0) || (a>=0 && b<=0);
00021 }
00022 
00023 // Returns true iif (x3,y3) lies inbetween (x1,y1) and (x2,y2);
00024 // all three points are assumed to be collinear
00025 template <class T>
00026 static inline
00027 bool inbetween(T x1, T y1, T x2, T y2, T x3, T y3)
00028 {
00029   return (x1-x3)*(x2-x3)<=0 && (y1-y3)*(y2-y3)<=0;
00030 }
00031 
00032 template <class T>
00033 bool vgl_lineseg_test_lineseg(T x1, T y1, T x2, T y2, T x3, T y3, T x4, T y4)
00034 {
00035   // reduce precision of inputs so that signs of vgl_triangle_test_discriminants
00036   // `a', `b', `c', and `d' are more stable when they are very close to zero.
00037 
00038   double px1 = x1;
00039   double py1 = y1;
00040   double px2 = x2;
00041   double py2 = y2;
00042   double px3 = x3;
00043   double py3 = y3;
00044   double px4 = x4;
00045   double py4 = y4;
00046 
00047   px1 = (px1 + px1*1e4) - px1*1e4;
00048   py1 = (py1 + py1*1e4) - py1*1e4;
00049   px2 = (px2 + px2*1e4) - px2*1e4;
00050   py2 = (py2 + py2*1e4) - py2*1e4;
00051   px3 = (px3 + px3*1e4) - px3*1e4;
00052   py3 = (py3 + py3*1e4) - py3*1e4;
00053   px4 = (px4 + px4*1e4) - px4*1e4;
00054   py4 = (py4 + py4*1e4) - py4*1e4;
00055 
00056   // two lines intersect if p1 and p2 are on two opposite sides of the line p3-p4
00057   // and p3 and p4 are on two opposite sides of line p1-p2
00058   // degenerate cases (collinear points) are tricky to handle
00059 
00060   double a = vgl_triangle_test_discriminant(px1, py1, px2, py2, px3, py3);
00061   double b = vgl_triangle_test_discriminant(px1, py1, px2, py2, px4, py4);
00062   double c = vgl_triangle_test_discriminant(px3, py3, px4, py4, px1, py1);
00063   double d = vgl_triangle_test_discriminant(px3, py3, px4, py4, px2, py2);
00064 
00065   // force to be zero when they're close to zero
00066   a = (vcl_abs(a) < 1e-12) ? 0 : a;
00067   b = (vcl_abs(b) < 1e-12) ? 0 : b;
00068   c = (vcl_abs(c) < 1e-12) ? 0 : c;
00069   d = (vcl_abs(d) < 1e-12) ? 0 : d;
00070 
00071   return
00072     ( ( (a<=0 && b>0) || (a>=0 && b<0) || (a<0 && b>=0) || (a>0 && b<=0) ) &&
00073       ( (c<=0 && d>0) || (c>=0 && d<0) || (c<0 && d>=0) || (c>0 && d<=0) ) )
00074     ||
00075     ( // the above two conditions are only sufficient for noncollinear line segments! - PVr
00076       a == 0 && b == 0 && c == 0 && d == 0 &&
00077       ( inbetween(px1, py1, px2, py2, px3, py3) ||
00078         inbetween(px1, py1, px2, py2, px4, py4) ||
00079         inbetween(px3, py3, px4, py4, px1, py1) ||
00080         inbetween(px3, py3, px4, py4, px2, py2) )
00081     );
00082 }
00083 
00084 //: true if the point lies on the line segment and is between the endpoints
00085 // \relatesalso vgl_point_2d
00086 // \relatesalso vgl_line_segment_2d
00087 template <class T>
00088 bool vgl_lineseg_test_point(vgl_point_2d<T> const& p,
00089                             vgl_line_segment_2d<T> const& lseg)
00090 {
00091   vgl_point_2d<T> p1 = lseg.point1(), p2 = lseg.point2();
00092   T x1 = p1.x(), y1 = p1.y(),
00093     x2 = p2.x(), y2 = p2.y(),
00094     xp = p.x(),  yp = p.y();
00095   // compute squared distances
00096   T d1p = (xp-x1)*(xp-x1) + (yp-y1)*(yp-y1);
00097   T d2p = (xp-x2)*(xp-x2) + (yp-y2)*(yp-y2);
00098   T d12 = (x2-x1)*(x2-x1) + (y2-y1)*(y2-y1);
00099   double diff = vcl_sqrt(d1p) + vcl_sqrt(d2p) - vcl_sqrt(d12);
00100   // diff is always >= 0 (triangle inequality)
00101   return diff <= vgl_tolerance<double>::position;
00102 }
00103 
00104 //--------------------------------------------------------------------------------
00105 
00106 #undef VGL_LINESEG_TEST_INSTANTIATE
00107 #define VGL_LINESEG_TEST_INSTANTIATE(T) \
00108 template bool vgl_lineseg_test_line(T, T, T, T, T, T, T, T); \
00109 template bool vgl_lineseg_test_lineseg(T, T, T, T, T, T, T, T)
00110 
00111 #endif // vgl_lineseg_test_txx_