题目:给定两条线段(表示为起点start = {X1, Y1}和终点end = {X2, Y2}),如果它们有交点,请计算其交点,没有交点则返回空值。
要求浮点型误差不超过10^-6。若有多个交点(线段重叠)则返回 X 值最小的点,X 坐标相同则返回 Y 值最小的点。
示例 1:
输入:
line1 = {0, 0}, {1, 0}
line2 = {1, 1}, {0, -1}
输出: {0.5, 0}
示例 2:
输入:
line1 = {0, 0}, {3, 3}
line2 = {1, 1}, {2, 2}
输出: {1, 1}
示例 3:
输入:
line1 = {0, 0}, {1, 1}
line2 = {1, 0}, {2, 1}
输出: {},两条线段没有交点
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/intersection-lcci
思路:用纯数学的方法分析,分类讨论直线的斜率存在的情况。题目中所说的是线段,是有边界的,不能简单认为求出交点,交点就一定存在。
代码:
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
double* intersection(int* start1, int start1Size, int* end1, int end1Size, int* start2, int start2Size, int* end2, int end2Size, int* returnSize)
{
double k1,k2,b1,b2,x,y,*res,temp1x,temp1y,temp2x,temp2y;
if(start1[0]==end1[0]&&start2[0]==end2[0])
/*两直线斜率均不存在时,l1的x1≠l2的x1就可以判断两线段不
重合。还有一种特殊情况,就是l2的y1刚好在l1的y2上方,这
种情况也是没有交点的*/
{
if(start1[0]!=start2[0]||start2[1]>end1[1])
{
*returnSize=0;
return 0;
}
else
{
*returnSize=2;
res=(double*)malloc(2*sizeof(double));
res[0]=start1[0];
res[1]=start1[1]<=start2[1]?start2[1]:start1[1];
return res;
}
}
else if(start1[0]==end1[0]&&start2[0]!=end2[0])
/*l1斜率不存在而l2斜率存在时,只要保证交点y坐标
在l2的约束范围内,就有交点*/
{
k2=(double)(end2[1]-start2[1])/(end2[0]-start2[0]);
b2=start2[1]-k2*start2[0];
x=start1[0];
y=k2*x+b2;
if(y<=end1[1]&&y>=start1[1]&&y<=end2[1]&&y>=start2[1])
{
*returnSize=2;
res=(double*)malloc(2*sizeof(double));
res[0]=x;
res[1]=y;
return res;
}
else
{
*returnSize=0;
return 0;
}
}
else if(start1[0]!=end1[0]&&start2[0]==end2[0])
/*l1斜率存在,l2斜率不存在*/
{
k1=(double)(end1[1]-start1[1])/(end1[0]-start1[0]);
b1=start1[1]-k2*start1[0];
x=start2[0];
y=k1*x+b1;
if(y<=end1[1]&&y>=start1[1]&&y<=end2[1]&&y>=start2[1])
{
*returnSize=2;
res=(double*)malloc(2*sizeof(double));
res[0]=x;
res[1]=y;
return res;
}
else
{
*returnSize=0;
return 0;
}
}
else//斜率都存在时
{
k1=(double)(end1[1]-start1[1])/(end1[0]-start1[0]);
k2=(double)(end2[1]-start2[1])/(end2[0]-start2[0]);
b1=start1[1]-k1*start1[0];
b2=start2[1]-k2*start2[0];
if(k1==k2)
{//两直线平行时
if(b1==b2)
{//重合
if(start2[0]>=start1[0]&&start2[0]<=end1[0])
{
*returnSize=2;
res=(double*)malloc(2*sizeof(double));
res[0]=start2[0];
res[1]=start2[1];
return res;
}
else if(start1[0]>=start2[0]&&start1[0]<=end2[0])
{
*returnSize=2;
res=(double*)malloc(2*sizeof(double));
res[0]=start1[0];
res[1]=start1[1];
return res;
}
}
else
{
*returnSize=0;
return 0;
}
}
else
{
x=(double)(b1-b2)/(k2-k1);
y=(double)(k2*b1-k1*b2)/(k2-k1);
if(start1[0]>end1[0])
{//考虑到输入的顺序,这里规定线段方向为从左到右
temp1x=start1[0];
start1[0]=end1[0];
end1[0]=temp1x;
temp1y=start1[1];
start1[1]=end1[1];
end1[1]=temp1y;
}
if(start2[0]>end2[0])
{
temp2x=start2[0];
start2[0]=end2[0];
end2[0]=temp2x;
temp2y=start2[1];
start2[1]=end2[1];
end2[1]=temp2y;
}
if(x>=start1[0]&&x<=end1[0]&&x>=start2[0]&&x<=end2[0])
{
*returnSize=2;
res=(double*)malloc(2*sizeof(double));
res[0]=x;
res[1]=y;
return res;
}
else
{
*returnSize=0;
return 0;
}
}
}
return 0;
}