http://www.cnblogs.com/devymex/archive/2010/08/19/1803885.html

概念

平面内两条线段位置关系的判定在很多领域都有着广泛的应用,比如游戏、CAD、图形处理等,而两线段交点的求解又是该算法中重要的一环。本文将尽可能用通俗的语言详细的描述一种主流且性能较高的判定算法。

外积,又称叉积,是向量代数(解析几何)中的一个概念。两个二维向量v1(x1, y1)和v2(x2, y2)的外积v1×v2=x1y2-y1x2。如果由v1到v2是顺时针转动,外积为负,反之为正,为0表示二者方向相同(平行)。此外,文中涉及行例式和方程组的概念,请参阅线性代数的相关内容。

为方便计算,对坐标点的大小比较作如下定义:x坐标较大的点为大,x坐标相等但y坐标较大的为大,x与y都相等的点相等。一条线段中较小的一端为起点,较大的一端为终点。

问题

给定两条线段的端点坐标,求其位置关系,并求出交点(如果存在)。

分析

两条线段的位置关系大体上可以分为三类:有重合部分、无重合部分但有交点(相交)、无交点。为避免精度问题,首先要将所有存在重合的情况排除。

重合可分为:完全重合、一端重合、部分重合三种情况。显然,两条线段的起止点都相同即为完全重合;只有起点相同或只有终点相同的为一端重合(注意:坐标较小的一条线段的终点与坐标较大的一条线段的起点相同时应判定为相交)。要判断是否部分重合,必须先判断是否平行。设线段L1(p1->p2)和L2(p3->p4),其中p1(x1, y1)为第一条线段的起点,p2(x2, y2)为第一条线段的终点,p3(x3, y3)为第二条线段的起点,p4(x4, y4)为第二段线段的终点,由此可构造两个向量:

  • v1(x2-x1, y2-y1),v2(x4-x3, y4-y3)

若v1与v2的外积v1×v2为0,则两条线段平行,有可能存在部分重合。再判断两条平行线段是否共线,方法是用L1的一端和L2的一端构成向量vs并与v2作外积,如果vs与v2也平行则两线段共线(三点共线)。在共线的前提下,若起点较小的线段终点大于起点较大的线段起点,则判定为部分重合。

没有重合,就要判定两条线是否相交,主要的算法还是依靠外积。然而外积的计算开销比较大,如果不相交的情况比较多,可先做快速排斥实验:将两条线段视为两个矩形的对角线,并构造出这两个矩形。如果这两个矩形没有重叠部分(x坐标相离或y坐标相离)即可判定为不相交。

然后执行跨立试验。两条相交的线段必然相互跨立,简单的讲就是p1和p2两点位于L2的两侧且p3和p4两点位于L1的两侧,这样就可利用外积做出判断了。分别构造向量s1(p3, p1), s2(p3, p2),如果s1×v2与s2×v2异号(s1->v2与s2->v2转动的方向相反),则说明p1和p2位于L2的两侧。同理可判定p3和p4是否跨立L1。如果上述四个叉积中任何一个等于0,则说明一条线段的端点在另一条线上。

当判定两条线段相交后,就可以进行交点的求解了。当然,求交点可以用平面几何方法,列点斜式方程来完成。但这样作会难以处理斜率为0的特殊情况,且运算中会出现多次除法,很难保证精度。这里将使用向量法求解。

设交点为(x0, y0),则下列方程组必然成立:

  1. x0-x1=k1(x2-x1)
  2. y0-y1=k1(y2-y1)
  3. x0-x3=k2(x4-x3)
  4. y0-y3=k2(y4-y3)

其中k1和k2为任意不为0的常数(若为0,则说明有重合的端点,这种情况在上面已经被排除了)。1式与2式联系,3式与4式联立,消去k1和k2可得:

  1. x0(y2-y1)-x1(y2-y1)=y0(x2-x1)-y1(x2-x1)
  2. x0(y4-y3)-x3(y4-y3)=y0(x4-x3)-y3(x4-x3)

将含有未知数x0和y0的项移到左边,常数项移动到右边,得:

  1. (y2-y1)x0+(x1-x2)y0=(y2-y1)x1+(x1-x2)y1
  2. (y4-y3)x0+(x3-x4)y0=(y4-y3)x3+(x3-x4)y3

设两个常数项分别为b1和b2

  • b1=(y2-y1)x1+(x1-x2)y1
  • b2=(y4-y3)x3+(x3-x4)y3

系数行列式为D,用b1和b2替换x0的系数所得系数行列式为D1,替换y0的系数所得系数行列式为D2,则有:

  • |D|=(x2-x1)(y4-y3)-(x4-x3)(y2-y1)
  • |D1|=b2(x2-x1)-b1(x4-x3)
  • |D2|=b2(y2-y1)-b1(y4-y3)

由此,可求得交点坐标为:

  • x0=|D1|/|D|, y0=|D2|/|D|

解毕。

判断两线段相交
经典方法,就是跨立试验了,即如果一条线段跨过另一条线段,则线段的两个端点分别在另一条线段的两侧。但是,还需要检测边界情况,即两条线段中可能某条线段的某个端点正好落在另一条线段上。这也是算法导论中介绍的算法。
程序模拟如下:

  1. int direction(point* pi, point* pj, point* pk){
  2. point p1, p2;
  3. p1.x = pk->x - pi->x;
  4. p1.y = pk->y - pi->y;
  5. p2.x = pj->x - pi->x;
  6. p2.y = pj->y - pi->y;
  7. return crossProduct(&p1, &p2);
  8. }
  9. int onSegment(point* pi, point* pj, point* pk){
  10. int minx, miny, maxx, maxy;
  11. if (pi->x > pj->x){
  12. minx = pj->x;
  13. maxx = pi->x;
  14. }
  15. else{
  16. minx = pi->x;
  17. maxx = pj->x;
  18. }
  19. if (pi->y > pj->y){
  20. miny = pj->y;
  21. maxy = pi->y;
  22. }
  23. else{
  24. miny = pi->y;
  25. maxy = pj->y;
  26. }
  27. if (minx <= pk->x && pk->x <= maxx && miny <= pk->y && pk->y <= maxy)
  28. return 1;
  29. else
  30. return 0;
  31. }
  32. int segmentIntersect(point* p1, point* p2, point* p3, point* p4){
  33. int d1 = direction(p3, p4, p1);
  34. int d2 = direction(p3, p4, p2);
  35. int d3 = direction(p1, p2, p3);
  36. int d4 = direction(p1, p2, p4);
  37. if (d1 * d2 < 0 && d3 * d4 < 0)
  38. return 1;
  39. else if (!d1 && onSegment(p3, p4, p1))
  40. return 1;
  41. else if (!d2 && onSegment(p3, p4, p2))
  42. return 1;
  43. else if (!d3 && onSegment(p1, p2, p3))
  44. return 1;
  45. else if (!d4 && onSegment(p1, p2, p4))
  46. return 1;
  47. else
  48. return 0;
  49. }

平面内两条线段的位置关系(相交)判定与交点求解相关推荐

  1. c语言 两条线段位置,C++/STL实现判断平面内两条线段的位置关系代码示例

    概念 平面内两条线段位置关系的判定在很多领域都有着广泛的应用,比如游戏.CAD.图形处理等,而两线段交点的求解又是该算法中重要的一环.本文将尽可能用通俗的语言详细的描述一种主流且性能较高的判定算法. ...

  2. 位置关系C语言,C++/STL实现判断平面内两条线段的位置关系代码示例

    概念 平面内两条线段位置关系的判定在很多领域都有着广泛的应用,比如游戏.CAD.图形处理等,而两线段交点的求解又是该算法中重要的一环.本文将尽可能用通俗的语言详细的描述一种主流且性能较高的判定算法. ...

  3. 平面中点与圆的位置关系

    在平面直角坐标系中,给定一个圆的圆心坐标Ox,Oy以及半径R,在再给定一个点的坐标PX,Py,请判断这个点与圆的位置关系. 输入格式: 先输入三个正整数,分别代表圆心的横纵坐标x,Oy和半径R. 在输 ...

  4. 如何判断平面上两条线段(注意是线段)是否相交?

    看到题目,很多人想,这个问题太简单了,直接求直线方程,然后求交点,看方程组是否有解.我在网上搜索了一下,很多思路都是求直线方程,求交点或求距离,不一而足.回顾高中学的线性规划知识,下面将给出一个我认为 ...

  5. java平面内有n个矩形_JAVA 相交矩形面积  平面上有两个矩形,它们的边平行于直角坐标系的X轴或Y轴.对于每个矩形,我们给出它的一对相对顶点...

    共回答了17个问题采纳率:88.2% 100%符合你的要求,其中inputstr1/2随便你怎么弄,可以通过args传入,或者System.in传入,甚至通过文件传入. import java.mat ...

  6. 直线与圆位置关系的c语言,直线与圆的位置关系教学设计范文

    直线与圆的位置关系教学设计范文 教学目标: (一) 教学知识点: 1. 了解直线与圆的三种位置关系. 2. 了解圆的切线的概念. 3. 掌握直线与圆位置关系的性质. (二) 过程目标: 1. 通过多媒 ...

  7. 圆与圆的位置关系题目含答案_高中数学直线、圆的位置关系的测试题及答案

    高中数学直线.圆的位置关系的测试题及答案 一.选择题 1.(2009重庆理)直线与圆的位置关系为( ). A.相切 B.相交但直线不过圆心 C.直线过圆心 D.相离 考查目的:考查直线与圆的位置关系的 ...

  8. 圆与圆的位置关系题目含答案_圆中考数学题汇总附答案

    圆中考数学题汇总附答案 圆的运算是我们必须掌握的一个数学考点,为了帮助大家更好地学习圆的相关考点,百分网小编为大带来一份圆的中考数学题汇总,附答案,有需要的同学可以看一看,更多内容欢迎关注应届毕业生网 ...

  9. 双曲线和直线联立公式_谈直线和双曲线的位置关系之(1)联立方程法

    [专题九]登峰造极,唯我独尊 --谈直线和双曲线的位置关系之(1)联立 方程法 直线与双曲线的位置关系题型包括①判断交点个数②判断相切.相交.相离三种位置关系③求弦长及三角形面积等问题:用到的思想是数 ...

最新文章

  1. Marshal.ReleaseComObject
  2. 关于虚函数的应用(10个例子)
  3. NRF52832编译micro-ecc是指编译器路径
  4. java远程监控服务器配置_JAVA VirtualVM远程监控配置
  5. Android开发之自定义AlertDialog的大小
  6. 使用 Directory.Build 来消除项目文件中的重复配置
  7. (计算机组成原理)第二章数据的表示和运算-第三节3:浮点数加减运算
  8. 队列 开源 php,消息队列 - 基于think-queue消息队列 – 基于ThinkPHP和Bootstrap的极速后台开发框架...
  9. C# CRC16 在textbox中显示实时时间
  10. NPN PNP 接近开关
  11. 论文笔记——TransPose
  12. #Paper Reading# Stochastic Optimization of Sorting Networks via Continuous Relaxations
  13. ant-design-vue导航菜单a-menu的详细使用
  14. 2.开关电源中常见的控制算法
  15. 回家过年要花多少钱?算完感觉生无可恋~
  16. 中南大学汪炼成教授课题组:三维金属-半导体-金属AlN深紫外探测器
  17. Prometheus监控MongoDB数据库
  18. 通过.bat快速启动和关闭mysql服务
  19. 基于树莓派的WireGuard安装配置与使用
  20. 突发丨BSV暴涨200% 澳本聪又搞事情了!

热门文章

  1. 四十一、Vue项目上手 | 用户管理系统 实现用户修改和删除功能(完成篇)
  2. html弹窗页面控制大小,使用JS弹出新窗口,并设置窗口的大小和位置等相关属性,传递参数...
  3. 小程序实现图片的放大预览
  4. ACL 2021 | 复旦大学邱锡鹏组:面向不同NER子任务的统一生成框架
  5. ACL 2020 | 消除文本分类问题中歧视现象的研究
  6. ICLR 2020:从去噪自编码器到生成模型
  7. 低精度神经网络:从数值计算角度优化模型效率
  8. HDU2515 Yanghee 的算术
  9. 计算机丢失quartz.dll什么意思,win7系统中出现缺少quartz.dll文件的修复方法
  10. oracle 按月累计求和,SQL Cumulative Sum累积求和