计算二条线段相交

来源:互联网 发布:韩熙雅用什么软件直播 编辑:程序博客网 时间:2024/04/30 16:05

  • 1.
    线段A(x1,y1)-B(x2,y2),所在直线L1方程为F(x,y)=0;
    线段C(x3,y3)-D(x4,y4),所在直线L2方程为G(x,y)=0;
    思路:(即问题的充要条件)
    (点A与点B在直线L2两侧) AND (点C与点D在直线L1两侧);
    方法:
    如果点P(Xp,Yp)不在直线a*x+b*y+c=0上,则a*Xp+b*Yp+c<>0;
    如果用两个点的坐标代入同一直线方程a*x+b*y+c计算出的值异号,则两点在直线两侧;
    解法:
    (G(x1,y1)*G(x2,y2)<0) AND ( F(x3,y3)*F(x4,y4)<0 )
  • 2.比较传统的方法:
    利用向量的叉积性质,当其中一条线段的两个端点在另一条线段的同一侧时,不相交。
    否则,相交。
    *向量的叉积 向量的叉积性质都忘完了……但是它可以用来判断点在直线的某侧。进而可以解决点是否在三角形内,两个矩形是否重叠等问题。向量的叉积的模表示这两个向量围成的平行四边形的面积。
    设矢量P = ( x1, y1 ),Q = ( x2, y2 ),则矢量叉积定义为由(0,0)、p1、p2和p1+p2所组成的平行四边形的带符号的面积,
  • 即:P×Q = x1*y2 - x2*y1,其结果是一个伪矢量。
    显然有性质 P × Q = - ( Q × P ) 和 P × ( - Q ) = - ( P × Q )。
    叉积的一个非常重要性质是可以通过它的符号判断两矢量相互之间的顺逆时针关系:
    若 P × Q > 0 , 则P在Q的顺时针方向。
    若 P × Q < 0 , 则P在Q的逆时针方向。
    若 P × Q = 0 , 则P与Q共线,但可能同向也可能反向。
    叉积的方向与进行叉积的两个向量都垂直,所以叉积向量即为这两个向量构成平面的法向量。
    如果向量叉积为零向量,那么这两个向量是平行关系。
    因为向量叉积是这两个向量平面的法向量,如果两个向量平行无法形成一个平面,其对应也没有平面法向量。所以,两个向量平行时,其向量叉积为零

  • 3.比较简单的计算方法:
  • 已知:由点A和点B组成的线段1, 由点C和点D组成的线段2

    方法:当点A和点B在线段2的两侧 并且点C和点D在线段1的两侧时
    两线段相交 否则不是

    算法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:

        ///------------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)<min(cc.x, dd.x) )          {              return false;          }          if ( max(aa.y, bb.y)<min(cc.y, dd.y) )          {              return false;          }          if ( max(cc.x, dd.x)<min(aa.x, bb.x) )          {              return false;          }          if ( max(cc.y, dd.y)<min(aa.y, bb.y) )          {              return false;          }          if ( mult(cc, bb, aa)*mult(bb, dd, aa)<0 )          {              return false;          }          if ( mult(aa, dd, cc)*mult(dd, bb, cc)<0 )          {              return false;          }          return true;      }      ///------------alg 2------------  

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

    <code>c-sharp    ///------------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函数测试:

        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,时间复杂度最低。

    0 0
    原创粉丝点击