判断两条线段是否相交(三种算法)

??

  1. ///----------alg 1------------
  2. struct Point
  3. {
  4. double x, y;
  5. };
  6. bool between(double a, double X0, double X1)
  7. {
  8. double temp1= a-X0;
  9. double temp2= a-X1;
  10. if ( ( temp1<1e-8 && temp2>-1e-8 ) || ( temp2<1e-6 && temp1>-1e-8 ) )
  11. {
  12. return true;
  13. }
  14. else
  15. {
  16. return false;
  17. }
  18. }
  19. // 判断两条直线段是否有交点,有则计算交点的坐标
  20. // p1,p2是直线一的端点坐标
  21. // p3,p4是直线二的端点坐标
  22. bool detectIntersect(Point p1, Point p2, Point p3, Point p4)
  23. {
  24. double line_x,line_y; //交点
  25. if ( (fabs(p1.x-p2.x)<1e-6) && (fabs(p3.x-p4.x)<1e-6) )
  26. {
  27. return false;
  28. }
  29. else if ( (fabs(p1.x-p2.x)<1e-6) ) //如果直线段p1p2垂直与y轴
  30. {
  31. if (between(p1.x,p3.x,p4.x))
  32. {
  33. double k = (p4.y-p3.y)/(p4.x-p3.x);
  34. line_x = p1.x;
  35. line_y = k*(line_x-p3.x)+p3.y;
  36. if (between(line_y,p1.y,p2.y))
  37. {
  38. return true;
  39. }
  40. else
  41. {
  42. return false;
  43. }
  44. }
  45. else
  46. {
  47. return false;
  48. }
  49. }
  50. else if ( (fabs(p3.x-p4.x)<1e-6) ) //如果直线段p3p4垂直与y轴
  51. {
  52. if (between(p3.x,p1.x,p2.x))
  53. {
  54. double k = (p2.y-p1.y)/(p2.x-p1.x);
  55. line_x = p3.x;
  56. line_y = k*(line_x-p2.x)+p2.y;
  57. if (between(line_y,p3.y,p4.y))
  58. {
  59. return true;
  60. }
  61. else
  62. {
  63. return false;
  64. }
  65. }
  66. else
  67. {
  68. return false;
  69. }
  70. }
  71. else
  72. {
  73. double k1 = (p2.y-p1.y)/(p2.x-p1.x);
  74. double k2 = (p4.y-p3.y)/(p4.x-p3.x);
  75. if (fabs(k1-k2)<1e-6)
  76. {
  77. return false;
  78. }
  79. else
  80. {
  81. line_x = ((p3.y - p1.y) - (k2*p3.x - k1*p1.x)) / (k1-k2);
  82. line_y = k1*(line_x-p1.x)+p1.y;
  83. }
  84. if (between(line_x,p1.x,p2.x)&&between(line_x,p3.x,p4.x))
  85. {
  86. return true;
  87. }
  88. else
  89. {
  90. return false;
  91. }
  92. }
  93. }
  94. ///------------alg 1------------
///----------alg 1------------ struct Point { double x, y; }; bool between(double a, double X0, double X1) { double temp1= a-X0; double temp2= a-X1; if ( ( temp1<1e-8 && temp2>-1e-8 ) || ( temp2<1e-6 && temp1>-1e-8 ) ) { return true; } else { return false; } } // 判断两条直线段是否有交点,有则计算交点的坐标 // p1,p2是直线一的端点坐标 // p3,p4是直线二的端点坐标 bool detectIntersect(Point p1, Point p2, Point p3, Point p4) { double line_x,line_y; //交点 if ( (fabs(p1.x-p2.x)<1e-6) && (fabs(p3.x-p4.x)<1e-6) ) { return false; } else if ( (fabs(p1.x-p2.x)<1e-6) ) //如果直线段p1p2垂直与y轴 { if (between(p1.x,p3.x,p4.x)) { double k = (p4.y-p3.y)/(p4.x-p3.x); line_x = p1.x; line_y = k*(line_x-p3.x)+p3.y; if (between(line_y,p1.y,p2.y)) { return true; } else { return false; } } else { return false; } } else if ( (fabs(p3.x-p4.x)<1e-6) ) //如果直线段p3p4垂直与y轴 { if (between(p3.x,p1.x,p2.x)) { double k = (p2.y-p1.y)/(p2.x-p1.x); line_x = p3.x; line_y = k*(line_x-p2.x)+p2.y; if (between(line_y,p3.y,p4.y)) { return true; } else { return false; } } else { return false; } } else { double k1 = (p2.y-p1.y)/(p2.x-p1.x); double k2 = (p4.y-p3.y)/(p4.x-p3.x); if (fabs(k1-k2)<1e-6) { return false; } else { line_x = ((p3.y - p1.y) - (k2*p3.x - k1*p1.x)) / (k1-k2); line_y = k1*(line_x-p1.x)+p1.y; } if (between(line_x,p1.x,p2.x)&&between(line_x,p3.x,p4.x)) { return true; } else { return false; } } } ///------------alg 1------------


算法2:
【判断两条线段是否相交(三种算法)】
[cpp] view plain copy print ?
  1. ///------------alg 2------------
  2. //叉积
  3. double mult(Point a, Point b, Point c)
  4. {
  5. return (a.x-c.x)*(b.y-c.y)-(b.x-c.x)*(a.y-c.y);
  6. }
  7. //aa, bb为一条线段两端点 cc, dd为另一条线段的两端点 相交返回true, 不相交返回false
  8. bool intersect(Point aa, Point bb, Point cc, Point dd)
  9. {
  10. if ( max(aa.x, bb.x)
  11. {
  12. return false;
  13. }
  14. if ( max(aa.y, bb.y)
  15. {
  16. return false;
  17. }
  18. if ( max(cc.x, dd.x)
  19. {
  20. return false;
  21. }
  22. if ( max(cc.y, dd.y)
  23. {
  24. return false;
  25. }
  26. if ( mult(cc, bb, aa)*mult(bb, dd, aa)<0 )
  27. {
  28. return false;
  29. }
  30. if ( mult(aa, dd, cc)*mult(dd, bb, cc)<0 )
  31. {
  32. return false;
  33. }
  34. return true;
  35. }
  36. ///------------alg 2------------
///------------alg 2------------ //叉积 double mult(Point a, Point b, Point c) { return (a.x-c.x)*(b.y-c.y)-(b.x-c.x)*(a.y-c.y); } //aa, bb为一条线段两端点 cc, dd为另一条线段的两端点 相交返回true, 不相交返回false bool intersect(Point aa, Point bb, Point cc, Point dd) { if ( max(aa.x, bb.x)


算法3:http://dec3.jlu.edu.cn/webcourse/t000096/graphics/chapter5/01_1.
html

[c-sharp] view plain copy print ?
  1. ///------------alg 3------------
  2. double determinant(double v1, double v2, double v3, double v4)// 行列式
  3. {
  4. return (v1*v3-v2*v4);
  5. }
  6. bool intersect3(Point aa, Point bb, Point cc, Point dd)
  7. {
  8. double delta = determinant(bb.x-aa.x, cc.x-dd.x, bb.y-aa.y, cc.y-dd.y);
  9. if ( delta<=(1e-6) && delta>=-(1e-6) )// delta=0,表示两线段重合或平行
  10. {
  11. return false;
  12. }
  13. double namenda = determinant(cc.x-aa.x, cc.x-dd.x, cc.y-aa.y, cc.y-dd.y) / delta;
  14. if ( namenda>1 || namenda<0 )
  15. {
  16. return false;
  17. }
  18. double miu = determinant(bb.x-aa.x, cc.x-aa.x, bb.y-aa.y, cc.y-aa.y) / delta;
  19. if ( miu>1 || miu<0 )
  20. {
  21. return false;
  22. }
  23. return true;
  24. }
  25. ///------------alg 3------------
///------------alg 3------------ double determinant(double v1, double v2, double v3, double v4) // 行列式 { return (v1*v3-v2*v4); } bool intersect3(Point aa, Point bb, Point cc, Point dd) { double delta = determinant(bb.x-aa.x, cc.x-dd.x, bb.y-aa.y, cc.y-dd.y); if ( delta<=(1e-6) && delta>=-(1e-6) ) // delta=0,表示两线段重合或平行 { return false; } double namenda = determinant(cc.x-aa.x, cc.x-dd.x, cc.y-aa.y, cc.y-dd.y) / delta; if ( namenda>1 || namenda<0 ) { return false; } double miu = determinant(bb.x-aa.x, cc.x-aa.x, bb.y-aa.y, cc.y-aa.y) / delta; if ( miu>1 || miu<0 ) { return false; } return true; } ///------------alg 3------------


main函数测试:


[cpp] view plain copy print ?
  1. int main()
  2. {
  3. Point p1, p2, p3, p4;
  4. p1.x = 1;
  5. p1.y = 4;
  6. p2.x = 3;
  7. p2.y = 0;
  8. p3.x = 0;
  9. p3.y = 1;
  10. p4.x = 4;
  11. p4.y = 3;
  12. int i=0, j=0;
  13. bool flag = false;
  14. flag = intersect3(p1, p2, p3, p4);
  15. // alg 2
  16. time_t seconds1 = time (NULL);
  17. for ( ; i!=20000; ++i )
  18. {
  19. for ( j=0; j!=60000; ++j )
  20. {
  21. flag = detectIntersect(p1, p2, p3, p4);
  22. }
  23. }
  24. time_t seconds2 = time (NULL);
  25. cout << "Time used in alg 1:" << seconds2-seconds1 << " seconds." << endl;
  26. // alg 2
  27. time_t seconds3 = time (NULL);
  28. i=0;
  29. j=0;
  30. for ( ; i!=20000; ++i )
  31. {
  32. for ( j=0; j!=60000; ++j )
  33. {
  34. flag = intersect(p1, p2, p3, p4);
  35. }
  36. }
  37. time_t seconds4 = time (NULL);
  38. cout << "Time used in alg 2:" << seconds4-seconds3 << " seconds." << endl;
  39. // alg 3
  40. time_t seconds5 = time (NULL);
  41. i=0;
  42. j=0;
  43. for ( ; i!=20000; ++i )
  44. {
  45. for ( j=0; j!=60000; ++j )
  46. {
  47. flag = intersect3(p1, p2, p3, p4);
  48. }
  49. }
  50. time_t seconds6 = time (NULL);
  51. cout << "Time used in alg 3:" << seconds6-seconds5 << " seconds." << endl;
  52. return 0;
  53. }
int main() { Point p1, p2, p3, p4; p1.x = 1; p1.y = 4; p2.x = 3; p2.y = 0; p3.x = 0; p3.y = 1; p4.x = 4; p4.y = 3; int i=0, j=0; bool flag = false; flag = intersect3(p1, p2, p3, p4); // alg 2 time_t seconds1 = time (NULL); for ( ; i!=20000; ++i ) { for ( j=0; j!=60000; ++j ) { flag = detectIntersect(p1, p2, p3, p4); } } time_t seconds2 = time (NULL); cout << "Time used in alg 1:" << seconds2-seconds1 << " seconds." << endl; // alg 2 time_t seconds3 = time (NULL); i=0; j=0; for ( ; i!=20000; ++i ) { for ( j=0; j!=60000; ++j ) { flag = intersect(p1, p2, p3, p4); } } time_t seconds4 = time (NULL); cout << "Time used in alg 2:" << seconds4-seconds3 << " seconds." << endl; // alg 3 time_t seconds5 = time (NULL); i=0; j=0; for ( ; i!=20000; ++i ) { for ( j=0; j!=60000; ++j ) { flag = intersect3(p1, p2, p3, p4); } } time_t seconds6 = time (NULL); cout << "Time used in alg 3:" << seconds6-seconds5 << " seconds." << endl; return 0; }

VS2008编译器环境下测试结果:
Debug模式下:
alg 1: 315 seconds;
alg 2: 832 seconds;
alg 3: 195 seconds;

Release模式下:
alg 1: 157 seconds;
alg 2: 169 seconds;
alg 3: 122 seconds;


结论: 使用算法3,时间复杂度最低。


    推荐阅读