一.矢量基本知识
    因为后面的计算需要一些矢量的基本知识,这里只是简单的列举如下,如果需要更加详细的信息,可以自行搜索wikipedia或google。
1.矢量的概念:如果一条线段的端点是有次序之分的,我们把这种线段成为有向线段(directed segment)。如果有向线段p1p2的起点p1在坐标原点,我们可以把它称为矢量(vector)p2。
2.矢量加减法:设二维矢量P = ( x1, y1 ),Q = ( x2 , y2 ),则矢量加法定义为: P + Q = ( x1 + x2 , y1 + y2 ),同样的,矢量减法定义为: P - Q = ( x1 - x2 , y1 - y2 )。显然有性质 P + Q = Q + P,P - Q = - ( Q - P )。
3.矢量的叉积:计算矢量叉积是与直线和线段相关算法的核心部分。设矢量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共线,但可能同向也可能反向。
4.折线段的拐向判断:折线段的拐向判断方法可以直接由矢量叉积的性质推出。对于有公共端点的线段p0p1和p1p2,通过计算(p2 - p0) × (p1 - p0)的符号便可以确定折线段的拐向:
若(p2 - p0) × (p1 - p0) > 0,则p0p1在p1点拐向右侧后得到p1p2。
若(p2 - p0) × (p1 - p0) < 0,则p0p1在p1点拐向左侧后得到p1p2。
若(p2 - p0) × (p1 - p0) = 0,则p0、p1、p2三点共线。
这一条判断也可用来判断点在线段或直线的哪一测。
为了后文的叙述方便,先定义几个结构:
struct point{
    int x;
    int y;
};
struct v{
    point start;
    point end;
};
    计算两条直线的叉积(cross production), 这里由于定义的都是二维的情况,本质上说,在平面上两个向量的叉积应该是垂直平面的,这里函数返回的整数值即为z轴上的值:
int crossProduct(v* v1, v* v2){
    v vt1, vt2;
    int result = 0;
   
    vt1.start.x = 0;
    vt1.start.y = 0;
    vt1.end.x = v1->end.x - v1->start.x;
    vt1.end.y = v1->end.y - v1->start.y;
   
    vt2.start.x = 0;
    vt2.start.y = 0;
    vt2.end.x = v2->end.x - v2->start.x;
    vt2.end.y = v2->end.y - v2->start.y;
   
    result = vt1.end.x * vt2.end.y - vt2.end.x * vt1.end.y;
    return result;
}
二.判断两条直线相交
    先来看一个简单的情况,即判断两条直线是否相交。
第一个可能会想到的办法,就是判断斜率,这个在中学时代就学过了,不过斜率需要考虑垂直的特殊情况,比较麻烦。更好的办法或许是计算两个向量的叉积,如果为0,则是平行或者重合的,否则两直线相交。
代码就不贴了,直接调用上面的函数就ok了。
三.判断两线段相交
经典方法,就是跨立试验了,即如果一条线段跨过另一条线段,则线段的两个端点分别在另一条线段的两侧。但是,还需要检测边界情况,即两条线段中可能某条线段的某个端点正好落在另一条线段上。这也是算法导论中介绍的算法。
程序模拟如下:
int direction(point* pi, point* pj, point* pk){
    point p1, p2;
   
    p1.x = pk->x - pi->x;
    p1.y = pk->y - pi->y;
   
    p2.x = pj->x - pi->x;
    p2.y = pj->y - pi->y;
   
    return crossProduct(&p1, &p2);
}
int onSegment(point* pi, point* pj, point* pk){
    int minx, miny, maxx, maxy;
    if (pi->x > pj->x){
        minx = pj->x;
        maxx = pi->x;    
    }
    else{
        minx = pi->x;
        maxx = pj->x;
    }
   
    if (pi->y > pj->y){
        miny = pj->y;
        maxy = pi->y;    
    }
    else{
        miny = pi->y;
        maxy = pj->y;
    }
   
    if (minx <= pk->x && pk->x <= maxx && miny <= pk->y && pk->y <= maxy)
        return 1;
    else
        return 0;
}
int segmentIntersect(point* p1, point* p2, point* p3, point* p4){
    int d1 = direction(p3, p4, p1);
    int d2 = direction(p3, p4, p2);
    int d3 = direction(p1, p2, p3);
    int d4 = direction(p1, p2, p4);
    if (d1 * d2 < 0 && d3 * d4 < 0)
        return 1;
    else if (!d1 && onSegment(p3, p4, p1))
        return 1;
    else if (!d2 && onSegment(p3, p4, p2))
        return 1;
    else if (!d3 && onSegment(p1, p2, p3))
        return 1;
    else if (!d4 && onSegment(p1, p2, p4))
        return 1;
    else
        return 0;
}
实际上,如果想改进上述算法,还可以在跨立试验前加一步,就是先做快速排斥试验。那就是,先分别判断以两条线段为对角线的矩形是否相交,如果不相交,则两个线段肯定不相交。
四.判断两条线段相交,然后计算交点
设一条线段为L0=P1P2, 另一条线段或直线为L1=Q1Q2, 要计算的就是L0和L1的交点。
1.首先判断L0和L1是否相交(方法已在前文讨论过), 如果不相交则没有交点, 否则说明L0和L1一定有交点, 下面就将L0和L1都看作直线来考虑. 
2.如果P1和P2横坐标相同, 即L0平行于Y轴 
a)若L1也平行于Y轴 
    i.若P1的纵坐标和Q1的纵坐标相同, 说明L0和L1共线, 假如L1是直线的话他们有无穷的交点, 假如L1是线段的话可用"计算两条共线线段的交点"的算法求他们的交点(该方法在前文已讨论过);
    ii.否则说明L0和L1平行, 他们没有交点; 
b)若L1不平行于Y轴, 则交点横坐标为P1的横坐标, 代入到L1的直线方程中可以计算出交点纵坐标; 
3.如果P1和P2横坐标不同, 但是Q1和Q2横坐标相同, 即L1平行于Y轴, 则交点横坐标为Q1的横坐标, 代入到L0的直线方程中可以计算出交点纵坐标; 
4.如果P1和P2纵坐标相同, 即L0平行于X轴
a)若L1也平行于X轴,
    i.若P1的横坐标和Q1的横坐标相同, 说明L0和L1共线, 假如L1是直线的话他们有无穷的交点, 假如L1是线段的话可用"计算两条共线线段的交点"的算法求他们的交点(该方法在前文已讨论过);
    ii.否则说明L0和L1平行, 他们没有交点; 
b)若L1不平行于X轴, 则交点纵坐标为P1的纵坐标, 代入到L1的直线方程中可以计算出交点横坐标; 
5.如果P1和P2纵坐标不同, 但是Q1和Q2纵坐标相同, 即L1平行于X轴, 则交点纵坐标为Q1的纵坐标, 代入到L0的直线方程中可以计算出交点横坐标; 
6.剩下的情况就是L1和L0的斜率均存在且不为0的情况 
a)计算出L0的斜率K0, L1的斜率K1;
b)如果K1 = K2 
    i.如果Q1在L0上, 则说明L0和L1共线, 假如L1是直线的话有无穷交点, 假如L1是线段的话可用"计算两条共线线段的交点"的算法求他们的交点(该方法在前文已讨论过);
    ii.如果Q1不在L0上, 则说明L0和L1平行, 他们没有交点.
c)联立两直线的方程组可以解出交点来
这个算法并不复杂, 但是要分情况讨论清楚, 尤其是当两条线段共线的情况需要单独考虑, 所以在前文将求两条共线线段的算法单独写出来. 另外, 一开始就先利用矢量叉乘判断线段与线段(或直线)是否相交, 如果结果是相交, 那么在后面就可以将线段全部看作直线来考虑. 需要注意的是, 我们可以将直线或线段方程改写为ax+by+c=0的形式, 这样一来上述过程的部分步骤可以合并, 缩短了代码长度, 但是由于先要求出参数, 这种算法将花费更多的时间.

判断两条线段/直线相交,并求交点相关推荐

  1. Unity3D C#数学系列之判断两条线段是否相交并求交点

    1 引言 问题:已知三维空间中四点A.B.C.D,如何判断线段AB与CD是否相交,若相交则求出交点. 分析: AB.CD要相交,则AB.CD必须要在同一平面内 快速排斥和跨立实验判断是否相交 几何法分 ...

  2. 【数学计算】判断两条线段是否相交+计算两条线段的交点和夹角

    序言 还是那句话,学习是为了应用.书到用时方恨"用得少" 1. 计算两条直线的交点 直线一般式方程 A x + B y + C = 0 Ax+By+C = 0 Ax+By+C=0 ...

  3. 如何判断两条线段是否相交

    本篇是在 [C++笔记]如何判断2个线段相交 的基础上加上自己的理解和实践总结出的判断两线段是否相交的方法. 判断两条线段是否相交 先附上判断函数 bool judge(int Ax1,int Ay1 ...

  4. 计算几何-判断两条线段是否相交

    原理:如果两条线段相交,那么必须跨立,就是以一条线段为标准,另一条线段的两端点一定在这条线段的两段 也就是说a b两点在线段cd的两端,c d两点在线段ab的两端 struct point() {do ...

  5. 二维空间内,如何判断两条线段是否相交,相离,平行,重合,并求交点

    首先,假设有两条线段p,q,求这两条线段的空间关系. 我们把两条线段的四个顶点看为向量,用坐标表示:p1(p1x,p1y), p2(p2x,p2y), q1(q1x,q1y), q2(q2x, q2y ...

  6. 判断两条线段是否相交

    如上图,判断线段AB和线段CD相交. 分析:如果线段AB和线段CD相交,只能是图中的两种相交情况.可以用向量叉乘来判断.如果(向量AB叉乘向量AC)*(向量AB叉乘向量AD)<= 0 并且(向量 ...

  7. 判断两条线段是否相交 java_判断两个线段是否相交02

    写在前面 在其他博客中看到这方面的知识,很多都是重复,并且说的总是云里雾里的,所以这里我就自己总结一下这种问题如何求解,判断两个线段是否相交在前面我们提到了会用到叉积的一点知识,那么这里就来详细说一下 ...

  8. 【转载】判断两条线段是否相交——(向量叉乘)

    原文:https://www.cnblogs.com/tuyang1129/p/9390376.html 实现:https://blog.csdn.net/yegshun/article/detail ...

  9. 两条线段是否相交,计算交点公式。

    A本身无限长,假设B也无限长,直接求得AB的交点坐标,然后再判断该坐标是否在定长线段B的内部就可以了啊 AB本身就是两条直线,知道两端点就可以知道其直线方程,B也是一样,两个方程联立,     得到一 ...

最新文章

  1. 介绍几款浏览器兼容性测试工具
  2. asp.net core系列 38 WebAPI 返回类型与响应格式--必备
  3. 通过css类/选择器选取元素 文档结构和遍历 元素树的文档
  4. 深入探究VC —— 链接器link.exe(4)【转】http://blog.csdn.net/wangningyu/article/details/4849452...
  5. vba 指定列后插入列_Excle中的VBA介绍分享
  6. 浅析MSIL中间语言——基础篇
  7. 视频播放控制:防盗链设置与视频加密及Android中的基础应用
  8. wind7计算机控制面板在哪,联想win7系统控制面板在哪里打开
  9. 物联网需要php和嵌入式吗,物联网与嵌入式两者是什么关系
  10. 采购员小刘与费用报销的“相爱相杀”史
  11. 风能设备物流的全球与中国市场2022-2028年:技术、参与者、趋势、市场规模及占有率研究报告
  12. flutter 获取wifi名称以及Android10获取不到wifi名称<unknown ssid>
  13. JavaScript 高级程序设计
  14. cocos2d-x自代的Json库解析json(转)
  15. UE_Visibility Buffer Deferred Material
  16. 2022 届大四学长实习心得、职场经验分享、转型思考
  17. 实现按钮的长按监听(聂同学的作业)
  18. 微信小程序 DES3加密解密
  19. Oraclenbsp;X$Tables
  20. 线性代数学习笔记——克拉默法则及矩阵的秩——3. 矩阵秩的基本结论与性质

热门文章

  1. python中判断生肖和星座,python基础生肖、星座、闰年判读
  2. 程序员应该如何去设计需求
  3. Java-----出现错误 找不到或无法加载主类
  4. stm32f103c8t6通过max31865-pt100测温,软件spi通信串口1输出
  5. python小项目: 海龟库模拟弹幕古诗词
  6. 3月25日助学作业答案
  7. Cookie跨域存储问题
  8. Halcon表面检测---高度纹理图像中的mura缺陷
  9. OpenCV检测和追踪车辆
  10. AE入门篇:效果和预设