计算几何-求线段交点算法和代码(C++语言)
来源:互联网 发布:逆战天梯怎么卡数据 编辑:程序博客网 时间:2024/06/01 09:31
原文地址:计算几何-求线段交点算法和代码(C++语言)
问题描述:已知两条线段P1P2和Q1Q2,判断P1P2和Q1Q2是否相交,若相交,求出交点。
两条线段的位置关系可以分为三类:有重合部分、无重合部分但有交点、无交点。
算法核心
算法的步骤如下:
1.快速排斥实验。
设以线段P1P2为对角线的矩形为R,设以线段Q1Q2为对角线的矩形为T,如果R和T不相交,则两线段不相交。
所以P1P2和Q1Q2相交的必要条件是以他们为对角线的矩形相交,即:
min(p1.x,p2.x) <= max(q1.x,q2.x) &&min(q1.x,q2.x) <= max(p1.x,p2.x) &&min(p1.y,p2.y) <= max(q1.y,q2.y) &&min(q1.y,q2.y) <= max(p1.y,p2.y);
2.跨立实验。
如果两线段相交,则两线段必然相互跨立对方。线段的跨立究竟是什么意思?向量的跨立是什么意思?
a、若P1P2跨立Q1Q2,则矢量(P1-Q1)和(P2-Q1)位于矢量(Q2-Q1)的两侧,即( P1 - Q1 ) × ( Q2 - Q1 ) * ( P2 - Q1 ) × ( Q2 - Q1 ) < 0。
等价于
(Q1.x-P1.x,Q1.y-P1.y) × ( Q1.x-Q2.x,Q1.y-Q2.y ) * ( Q1.x-P2.x,Q1.y-P2.y ) × ( Q1.x-Q2.x,Q1.y-Q2.y ) < 0
等价于((Q1.x-P1.x)*(Q1.y-Q2.y)-(Q1.y-P1.y)*( Q1.x-Q2.x)) * ((Q1.x-P2.x)*(Q1.y-Q2.y)-(Q1.y-P2.y)*(Q1.x-Q2.x)) < 0
b、若Q1Q2跨立P1P2,则矢量(Q1-P1)和(Q2-P1)位于矢量(P2-P1)的两侧,即( Q1 - P1 ) × ( P2 - P1 ) * ( Q2 - P1 ) × ( P2 - P1 ) < 0。
等价于
(P1.x-Q1.x,P1.y-Q1.y) × ( P1.x-P2.x,P1.y-P2.y ) * ( P1.x-Q2.x,P1.y-Q2.y ) × ( P1.x-P2.x,P1.y-P2.y ) < 0
等价于((P1.x-Q1.x)*(P1.y-P2.y)-(P1.y-Q1.y)*(P1.x-P2.x)) * ((P1.x-Q2.x)*(P1.y-P2.y)-(P1.y-Q2.y)*( P1.x-P2.x)) < 0
a和b两个不等式同时满足时即可判断两条线段相交。
排斥实验和跨立实验的示例如下图所示。
代码
//跨立判断bool isLineSegmentCross(const Point &P1,const Point &P2,const Point &Q1,const Point &Q2){ if( ((Q1.x-P1.x)*(Q1.y-Q2.y)-(Q1.y-P1.y)*( Q1.x-Q2.x)) * ((Q1.x-P2.x)*(Q1.y-Q2.y)-(Q1.y-P2.y)*(Q1.x-Q2.x)) < 0 || ((P1.x-Q1.x)*(P1.y-P2.y)-(P1.y-Q1.y)*(P1.x-P2.x)) * ((P1.x-Q2.x)*(P1.y-P2.y)-(P1.y-Q2.y)*( P1.x-P2.x)) < 0 ) return true; else return false;}
3.计算交点。
当判定两条线段相交后,可以进行交点的求解,求交点可以用平面几何方法,列点斜式方程来完成。但由于点斜式方程难以处理斜率为0的特殊情况,不方便求解。因而,参用向量法求解交点。
设交点为(x0,y0),则下列方程组成立:
根据以上方程组,消除参数k1和k2,得到如下方程:
然后求解(x0,y0),结果如下所示:
#include<stdio.h>#define N 10002/**算法适用于整形点,不适用于浮点型 **/typedef struct Point{ int x; int y;}Point;double min(int x, int y){ return x<y?x:y;}double max(int x, int y){ return x>y?x:y;}//排斥实验bool IsRectCross(const Point &p1,const Point &p2,const Point &q1,const Point &q2){ bool ret = min(p1.x,p2.x) <= max(q1.x,q2.x) && min(q1.x,q2.x) <= max(p1.x,p2.x) && min(p1.y,p2.y) <= max(q1.y,q2.y) && min(q1.y,q2.y) <= max(p1.y,p2.y); return ret;}/**这段代码不能得到正确答案,故注释//跨立判断bool IsLineSegmentCross(const Point &pFirst1,const Point &pFirst2,const Point &pSecond1,const Point &pSecond2){ long line1,line2; line1 = pFirst1.x * (pSecond1.y - pFirst2.y) + pFirst2.x * (pFirst1.y - pSecond1.y) + pSecond1.x * (pFirst2.y - pFirst1.y); line2 = pFirst1.x * (pSecond2.y - pFirst2.y) + pFirst2.x * (pFirst1.y - pSecond2.y) + pSecond2.x * (pFirst2.y - pFirst1.y); if (((line1 ^ line2) >= 0) && !(line1 == 0 && line2 == 0)) return false; line1 = pSecond1.x * (pFirst1.y - pSecond2.y) + pSecond2.x * (pSecond1.y - pFirst1.y) + pFirst1.x * (pSecond2.y - pSecond1.y); line2 = pSecond1.x * (pFirst2.y - pSecond2.y) + pSecond2.x * (pSecond1.y - pFirst2.y) + pFirst2.x * (pSecond2.y - pSecond1.y); if (((line1 ^ line2) >= 0) && !(line1 == 0 && line2 == 0)) return false; return true;}**///跨立判断bool IsLineSegmentCross(const Point &P1,const Point &P2,const Point &Q1,const Point &Q2){ if( ((Q1.x-P1.x)*(Q1.y-Q2.y)-(Q1.y-P1.y)*( Q1.x-Q2.x)) * ((Q1.x-P2.x)*(Q1.y-Q2.y)-(Q1.y-P2.y)*(Q1.x-Q2.x)) < 0 || ((P1.x-Q1.x)*(P1.y-P2.y)-(P1.y-Q1.y)*(P1.x-P2.x)) * ((P1.x-Q2.x)*(P1.y-P2.y)-(P1.y-Q2.y)*( P1.x-P2.x)) < 0 ) return true; else return false;}/**求线段P1P2与Q1Q2的交点。先进行快速排斥实验和跨立实验确定有交点再进行计算。交点(x,y)使用引用返回。没有验证过**/bool GetCrossPoint(const Point &p1,const Point &p2,const Point &q1,const Point &q2,long &x,long &y){ if(IsRectCross(p1,p2,q1,q2)) { if (IsLineSegmentCross(p1,p2,q1,q2)) { //求交点 long tmpLeft,tmpRight; tmpLeft = (q2.x - q1.x) * (p1.y - p2.y) - (p2.x - p1.x) * (q1.y - q2.y); tmpRight = (p1.y - q1.y) * (p2.x - p1.x) * (q2.x - q1.x) + q1.x * (q2.y - q1.y) * (p2.x - p1.x) - p1.x * (p2.y - p1.y) * (q2.x - q1.x); x = (int)((double)tmpRight/(double)tmpLeft); tmpLeft = (p1.x - p2.x) * (q2.y - q1.y) - (p2.y - p1.y) * (q1.x - q2.x); tmpRight = p2.y * (p1.x - p2.x) * (q2.y - q1.y) + (q2.x- p2.x) * (q2.y - q1.y) * (p1.y - p2.y) - q2.y * (q1.x - q2.x) * (p2.y - p1.y); y = (int)((double)tmpRight/(double)tmpLeft); return true; } } return false;}
代码2-线段求交模板
http://www.cppblog.com/wicbnu/archive/2009/08/24/94225.html
#include <stdio.h>#include <math.h>const int N = 100010;int mark[N];struct Point{ double x,y;};struct stline{ Point a,b;} line1,line2, p[N];int dblcmp(double a,double b){ if (fabs(a-b)<=1E-6) return 0; if (a>b) return 1; else return -1;}//***************点积判点是否在线段上***************double dot(double x1,double y1,double x2,double y2) //点积{ return x1*x2+y1*y2;}int point_on_line(Point a,Point b,Point c) //求a点是不是在线段bc上,>0不在,=0与端点重合,<0在。{ return dblcmp(dot(b.x-a.x,b.y-a.y,c.x-a.x,c.y-a.y),0);
- 计算几何-求线段交点算法和代码(C++语言)
- 计算几何之线段性质(二):求线段交点
- POJ 1039-Pipe(计算几何-线段相交、求交点)
- POJ3304 Segments(计算几何,线段和直线的交点)
- hdu 1086 计算几何 求线段有多少个交点
- poj 1127 计算几何入门题 求线段交点
- 计算几何 POJ 2826 An Easy Problem?! (线段位置判断并且求交点)
- HDU 1086 计算几何 求线段交点(吉大模板)
- POJ 2653 Pick-up sticks(计算几何 求线段交点)
- [从头学数学] 第265节 [计算几何] 多线段求交点(扫描线法)
- FZU 1015 土地划分 (计算几何求线段交点个数)
- 求两线段的交点(C++)
- HDU 2857 Mirror and Light (计算几何求 对称点和两直线的交点)
- [从头学数学] 第266节 [计算几何] 多线段求交点
- 【计算几何初步-线段相交】【HDU1089】线段交点
- 计算几何 点线的综合题, 精度+ 线段相交+ 求交点 + 求面积 poj 2826 An Easy Problem?! (推荐)
- 几何+线段交点+spfa(POJ1066)
- 扫描线算法-求线段交点数量
- zookeeper学习 第一章 序言
- 书的复制
- python编程基本方法之raw_input .format
- Android音视频开发进阶
- XZ_iOS之一串字符串每隔4个数字或者字符串加空格
- 计算几何-求线段交点算法和代码(C++语言)
- shell中执行没有问题的脚本,交给cron后出错,如何解决?
- 关于函数柯里化的一些理解
- 实现服务器和客户机的交互
- java连接sqlserver2016方法
- AS导入项目出现Error:Execution failed for task ':app:processDebugManifest'.错误
- 【c++基础】5.标识符、关键字、函数
- python基础内容
- GRASP设计模式