判断与求解平面内两线段的交点的算法与实现
来源:互联网 发布:sas数据分析软件下载 编辑:程序博客网 时间:2024/05/16 11:52
两条线段的位置关系可以大致归类为平行、相交和不平行且不相交,平行又可以分为重合,共线(不重合),部分重合,不平行且不相交的情况为线段所在直线相交,交点在线段外。
我们要判断线段的位置关系以及计算交点的位置关系,需要用到向量的相关知识,即定义两个向量p(x1, y1)和q(x2, y2),向量积系数k=p×q=x1·y2-x2·y1,若k=0则p与q平行,若k>0,则p逆时针旋转到q(这里指旋转角小于180度的情况),若k<0,则p顺时针旋转到q(相关推导请参考游戏中两个常用的数学运算推导及算法推论 中关于向量积的推导和推论)。
如下图,现在有4个点A(x1, y1)、B(x2, y2)、C(x3,y3)、D(x4, y4),若线段AB和CD存在交点,则设其交点为E(x, y),向量AB记为p1(dx1,dy1),向量CD记为p2(dx2, dy2),向量AC记为p3(dx3, dy3),如下图所示:
我们根据向量积系数为0来判断向量是否平行,即由如下算法:
float k = x1·y2-x2·y1;
if (k == 0) {
//平行
} else {
//进一步判断是否相交
}
这里对于平行中包含的共线、重合等特殊情况就不做具体讨论了,我们集中精力来考虑交点的求解算法。
我们先不考虑线段相交的情况,先来考虑直线的相交问题(要判断线段有无交点,可以先求解直线的交点,然后判断交点是否在线段内部)。
根据前面的定义我们能够得到下面的关系:
dx1=x2-x1
dy1=y2-y1
dx2=x4-x3
dy2=y4-y3
dx3=x3-x1
dy3=y3-y1
为了方便计算结果的表示,再定义下面的两个量:
t1=dx2·dy1-dx1·dy2
t2=dx1·dy3-dx3·dy1
设直线AB的斜率为k1,直线CD的斜率为k2,则有k1=(y-y1)/(x-x1)=(y2-y1)/(x2-x1)=dy1/dx1,k2=(y-y3)/(x-x3)=(y4-y3)/(x4-x3)=dy2/dx2,联立求解得:
x=(dx1·dx2·dy3-dx1·dy2·x3+dx2·dy1·x1)/(dy1·dx2-dy2·dx1)
=(dx1·dx2·dy3-dx1·dy2·x3+dx2·dy1·x3-dx2·dy1·x3+dx2·dy1·x1)/(dy1·dx2-dy2·dx1)
=x3+(dx1·dx2·dy3-dx2·dx3·dy1)/(dy1·dx2-dy2·dx1)
=x3+dx2·(dx1·dy3-dx3·dy1)/(dy1·dx2-dy2·dx1)
=x3+dx2·t2/t1
y=y3+dy2·(x-x3)/dx2=y3+dy2·t2/t1
因此,我们得到下面的求解算法(忽略具体的编程语言,只是算法的主体思路):
Struct Point {
floatx;
floaty;
}
float calculateVectorProduct(PointP1, Point P2, Point P3, Point P4) {
return(P2.x-P1.x) * (P4.y-P3.y) - (P2.y-P1.y) * (P4.x-P3.x);
}
PointcalculateIntersectionPoint(Point A, Point B, Point C, Point D) {
float t1 =calculateVectorProduct(C, D, A, B);
floatt2 = calculateVectorProduct(A, B, A, C);
float x = C.x +(D.x-C.x) * t2 / t1;
float y = C.y +(D.y-C.y) * t2 / t1;
return newPoint(x, y);
}
在得到了交点之后,我们来做进一步的判断,来确定交点是否在线段上。要确定点是否在线段上其实比较简单,因为我们求得的点一定在直线上,所以不需要去计算点是否满足直线方程,只需要判断点的横纵坐标是否在线段两个端点的横纵坐标之间即可。
算法实现比较简单:
float min(float Num1, float Num2) {
returnNum1 > Num2 ? Num2 : Num1;
}
float max(float Num1, float Num2) {
returnNum1 > Num2 ? Num1 : Num2;
}
float isBetween(float Num, floatNum1, float Num2) {
floatdeviation =0.1; // 由于浮点数的精度问题,因此引入误差防止误判
return(Num >= min(Num1, Num2)-deviation && Num <= max(Num1,Num2)+deviation;
}
bool isPointInSegment(Point P1,Point LineStart, Point LineEnd) {
return(isBetween(P1.x, LineStart.x,LineEnd.x) && isBetween(P1.y, LineStart.y,LineEnd.y));
}
当然这里isPointInSegment这个方法是基于P1在LineStart和LineEnd确定的直线上的,也就是基于P1是前面算法中求得的直线交点。要判断点是否在直线上,需要根据y=kx+t来求解出直线方程,然后验证点坐标是否满足直线方程即可。
算法如下:
bool checkIsPointOnLine(Point P1,Point LineStart, Point LineEnd) {
if(isBetween(LineStart.x-LineEnd.x, 0, 0)) {
returnisBetween(P1.x-LineStart.x, 0, 0);
}else {
floatk = (LineEnd.y-LineStart.y)/(LineEnd.x-LineStart.x);
floatcalculatedY = k * (P1.x-LineEnd.x) + LineEnd.y;
returnisBetween(P1.y-calculatedY, 0, 0);
}
}
据此我们可以对任意给出的4个点做判断:
Point A = Point(1, 1);
Point B = Point(4, 3);
Point C = Point(2, 1);
Point D = Point(4, 5);
Point E =calculateIntersectionPoint(A, B, C, D);
bool isOnSegment = isPointInSegment(E, A, B) & isPointInSegment(E, C, D);
这个算法对于模拟游戏中需要求解线段之间的交点,射线之间的交点是非常有帮助的。如果有疑问,欢迎留言~
- 判断与求解平面内两线段的交点的算法与实现
- 平面内两条线段的位置关系(相交)判定与交点求解
- 平面内两条线段的位置关系(相交)判定与交点求解
- 平面内两条线段的位置关系(相交)判定与交点求解
- 平面内两条线段的位置关系(相交)判定与交点求解
- 平面内两条线段的位置关系(相交)判定与交点求解
- 平面内两条线段的位置关系(相交)判定与交点求解
- 判断线段与圆弧的交点
- 圆与线段的交点
- 空间直线与平面的交点
- 求空间直线与平面的交点
- 三维空间中直线与平面的交点
- 空间直线与平面的交点
- 求直线与平面的交点
- 计算射线与平面的交点
- 空间直线与平面的交点
- 如何求直线与平面的交点(两种方式)
- 求空间中直线与一个平面的交点并判断交点是否在某个三角形区域内部
- eclipse添加配置Server
- 根据凸多边形顶点坐标来计算面积算法与实现
- homebrew安装python3失败的问题
- Python第七天
- RecycleView ItemTouchHelper 学习(一)
- 判断与求解平面内两线段的交点的算法与实现
- Java习题每日练(一)
- python3使用selenium登录新浪微博
- 欢迎使用CSDN-markdown编辑器
- Java Server Pages
- 游戏中两个常用的数学运算推导及算法推论
- 100!的0问题
- poj2010 Moo University - Financial Aid 二分
- 重看css权威指南 part3