首页 > 其他分享 >线段相交

线段相交

时间:2023-01-10 22:44:24浏览次数:52  
标签:AB const Point 线段 相交 CD vec times

记两线段为\(AB\)与\(CD\)

一、方法一

1. 先判断线段是否共线

依据共线向量叉乘为零来判断
\(\vec{AB}\)与\(\vec{CD}\)叉乘是否为0,如果为0则共线

2. 在不共线情况下判断是否相交

依据\(0 \leq t \leq 1\)且\(0 \leq u \leq 1\)来判断,其中\(t\)和\(u\)的推导过程如下:

假设交点为\(P\),则有\(P = A + \vec{AB} * t, \quad t \in [0, 1]\)且 \(P = C + \vec{CD} * u, \quad u \in [0, 1]\)

\(A + \vec{AB} * t = C + \vec{CD} * u \quad ==> \quad \vec{AB} * t = \vec{AC} + \vec{CD}*u\)

由于向量自身的叉乘为0,所以上式两边同时叉乘\(\vec{CD}\)可得:

\(\vec{CD} \times \vec{AB} * t = \vec{CD} \times \vec{AC}\),

变形可得:

\(t = \frac{\vec{CD} \times \vec{AC}}{\vec{CD} \times \vec{AB}}, t \in [0, 1]\)

同理,两边同时叉乘\(\vec{AB}\)可得:\(-\vec{AB} \times \vec{CD} * u = \vec{AB} \times \vec{AC}\),所以:

\(u = \frac{\vec{AB} \times \vec{AC}}{\vec{CD} \times \vec{AB}}, u \in [0, 1]\)

3. 在相交的情况下计算交点

依据第2步计算的\(t\)和\(u\),代入:\(P = A + \vec{AB} * t, \quad t \in [0, 1]\)且 \(P = C + \vec{CD} * u, \quad u \in [0, 1]\)即可求出交点\(P\)的坐标

代码实现

struct Point {
  float x, y;
  Point(const float& px = 0, const float& py = 0) : x(px), y(py) {}
  Point operator+(const Point& p) const {
    return Point(x + p.x, y + p.y);
  }
  Point& operator+=(const Point& p) {
    x += p.x;
    y += p.y;
    return *this;
  }
  Point operator-(const Point& p) const {
    return Point(x - p.x, y - p.y);
  }
  Point operator*(const float coeff) const {
    return Point(x * coeff, y * coeff);
  }
};

float Dot2d(const Point & A, const Point & B) {
  return A.x * B.x + A.y * B.y;
}
 
float Cross2d(const Point & A, const Point & B) {
  return A.x * B.y - B.x * A.y;
}

bool IsInsert(const Point& A, const Point& B, const Point& C, const Point&D)
{
     Point AB = B - A;
     Point CD = D - C;
     float det = Cross2d(CD , AB);

      // This takes care of parallel lines
      if (std::fabs(det) <= 1e-14) {
        return false;
      }

      Point AC= C - A;

      double t = Cross2d(CD, AC) / det;
      double u = Cross2d(AB, AC) / det;

      if (t > -EPS && t < 1.0f + EPS && u > -EPS && u < 1.0f + EPS) {
         return true;
         // intersections P = A + AB * t;
      }
}

二、方法二

1. 先判断线段是否共线

同方法一

2. 在不共线情况下判断是否相交

依据线段相交则一条线段两端点位于另一线段两侧来判断
相交情况下有如下两种情形:

判断是否在两侧可以依据两个向量的叉乘(右手法则),如下:

\(\vec{OA} \times \vec{OB} > 0\),则\(\vec{OB}\)在\(\vec{OA}\)的逆时针方向
\(\vec{OB} \times \vec{OA} < 0\),则\(\vec{OA}\)在\(\vec{OB}\)的顺时针方向

所以在相交的两种情况下有:

  • 情况1
    点\(C\)和\(D\)在\(AB\)两侧,则有:

\((\vec{AC} \times \vec{AB}) \cdot (\vec{AD} \times \vec{AB}) < 0\)

点\(A\)和\(B\)在\(CD\)两侧,则有:

\((\vec{CA} \times \vec{CD}) \cdot (\vec{CB} \times \vec{CD}) < 0\)

  • 情况2
    由于端点在线段上,所以有一个叉乘为0,因此:

\((\vec{AC} \times \vec{AB}) \cdot (\vec{AD} \times \vec{AB}) = 0\) 且 \((\vec{CA} \times \vec{CD}) \cdot (\vec{CB} \times \vec{CD}) = 0\)

代码实现

bool IsInsert(const Point& A, const Point& B, const Point& C, const Point&D)
{
     Point AB = B - A;
     Point CD = D - C;
     Point AC = C - A; 
     Point AD = D - A;
     Point CB = B - C;
     Point CA = -AC;  
     float det = Cross2d(CD , AB);

     // This takes care of parallel lines
     if (std::fabs(det) <= 1e-14) {
        return false;
     }

     if (Cross2D(AC, AB) * Cross2D(AD, AB) <= EPS  &&  Cross2D(CA, CD) * Cross2D(CB, CD)< EPS) {
         return true; 
     }
}

参考链接

line_intersection
Two_line_segments

标签:AB,const,Point,线段,相交,CD,vec,times
From: https://www.cnblogs.com/xiaxuexiaoab/p/16801580.html

相关文章

  • 绘制图元:线段、三角形、四边形
    技术PyOpenGL run函数请见上一篇。 绘制线段代码(py)defdrawAxis():glTranslatef(-2.0,-2.0,-6.0)#偏左下,是为了看清楚蓝色的Z轴glBegin(GL_LINES)......
  • 看透不相交的线
    导读^_^不相交的线本质是最长公共子序列问题。我们要学会透过现象看本质题目leetcode1035代码与思路题目本质绘制一些连接两个数字A[i]和B[j]的直线,只......
  • 【CF802O】April Fools' Problem (hard) 题解 (线段树模拟费用流)
    线段树模拟费用流。LG传送门。SolutionPart1根据题面,显然想到此题是费用流。建图方式亦是显然:\(S\rightarrowi\),流量为\(1\),费用为\(a_i\);\(i\rightarrowT_0\)......
  • 【开源代码】运动模糊时准确检测和定位线段,通用的帧事件特征融合网络
    以下内容来自从零开始机器人SLAM知识星球每日更新内容点击领取学习资料→机器人SLAM学习资料大礼包论文##开源代码#DetectingLineSegmentsinMotion-blurredImag......
  • 如何用线段树维护一些数学公式
    1.维护等差数列例1:洛谷P1438无聊的数列(插入等差数列,单点查询)这题有两个做法,第一个做法是用线段树维护等差数列,不过这里不多赘述,在下一个例子再详细介绍;第二个做法是用......
  • hdu:张煊的金箍棒(2)(线段树)
    ProblemDescription张煊的金箍棒升级了!升级后的金箍棒是由几根相同长度的金属棒连接而成(最开始都是铜棒,从1到N编号);张煊作为金箍棒的主人,可以对金箍棒施以任意的变换,每......
  • hdu:张煊的金箍棒(3)(线段树)
    ProblemDescription张煊的金箍棒升级了!升级后的金箍棒是由N段相同长度的金属棒连接而成(最开始每段金属棒的价值都是1,从1到N编号);张煊作为金箍棒的主人,可以对金箍棒任意......
  • 【学习笔记 / 数据结构】线段树进阶
    扫描线【洛谷模板题传送门】思想以一条法线从下往上扫描整个图形,图形面积并即为\(\sum\limits_{i=1}^{n-1}len_i\times\left(h_{i+1}-h_i\right)\),其中\(len_i\)......
  • 【Unity TIL】6. 如何判断两条线段是否相交
    AABB碰撞检测,也就是轴对齐碰撞检测,用平行于x,y轴的矩形表示物体。如何判断两个矩形是否相撞,可以通过分别判断x,y轴上的线段是否相交。假设线段分别为(s1,e1),(s2,e2),判......
  • 线段树
    概述线段树通过在原数组上建一棵二叉树,高效地处理各种结合性问题。线段树的生命就在于pushup和pushdown,更具体地,就在于结合性和差分性。操作线段树什么都支......