c++线段与线段的交点

数学中表示直线的方式有很多种,其中参数方程式可以表示任意直线,并且其非常适合用于显示线段,表达式为用三个参数分别表示直线上的一个已知点以及参数t,即:

\left\{\begin{matrix} x = x0 + t\Delta x& & \\ y = y0 + t\Delta y& & \end{matrix}\right.

假设给定两个点(x1,y1)、(x2,y2),只需要其满足:

\left\{\begin{matrix} x = x1 + t(x2-x1) & \\ y = y1 + t(y2-y1)& \end{matrix}\right.

并且将t限制在[0,1]的范围内,就可以表示端点(x1,y1)、(x2,y2)的线段。

说明:

为了简化描述,设两条线段的端点分别为(x1,y1)、(x2,y2)以及(x3,y3)、(x4,y4)。初中数学我们学习过,平面上两条直线如果不平行,那么他们一定相交,并且有唯一的交点。下面分别从平行情况和不平行情况进行分析。

不平行情况:

对于线段1其参数方程为:

\left\{\begin{matrix} x = x1 + t1(x2-x1) & \\ y = y1 + t1(y2-y1)& \end{matrix}\right.           t1\in [0,1]

对于线段2其参数方程为:

\left\{\begin{matrix} x = x3 + t2(x4-x3) & \\ y = y3 + t2(y4-y3)& \end{matrix}\right.           t2\in [0,1]

联立两个方程组求出交点:

\left\{\begin{matrix} x1 + t1(x2-x1)= x3 + t2(x4-x3) & \\ y1 + t1(y2-y1) = y3 + t2(y4-y3)& \end{matrix}\right. 

这是一个普通的二元一次方程组,我们可以得出其解为:

\left\{\begin{matrix} t1=\frac{x3(y4-y3)+y1(x4-x3)-y3(x4-x3)-x1(y4-y3)}{(x2-x1)(y4-y3)-(x4-x3)(y2-y1)}& \\ t2=\frac{x1(y2-y1)+y3(x2-x1)-y1(x2-x1)-x3(y2-y1)}{(x4-x3)(y2-y1)-(x2-x1)(y4-y3)}& \end{matrix}\right.

判断交点是否在线段上,只需要判断0\leq t1\leq 1,0\leq t2\leq 1即可。

平行情况:

检查斜率可以判断两条直线是否平行。即当

\frac{y4-y3}{x4-x3}=\frac{y2-y1}{x2-x1}

满足时,直线平行。但当线段与y轴平行时,此时分母为0。为了避免这种情况。我们可以这么写:

(y4-y3)(x2-x1)=(y2-y1)(x4-x3)

当两条线段平行之后,会有两种情况出现;

1、两条线段不在同一条直线上,没有交点。

2、两条线段在同一条直线上,此时可能会有多个交点。但最优的交点一定是两条直线四个端点中的一个。

即我们需要判断:

1、(x3,y3)是否在线段(x1,y1)~(x2,y2)上。

2、(x4,y4)是否在线段(x1,y1)~(x2,y2)上。

3、(x1,y1)是否在线段(x3,y3)~(x4,y4)上。

4、(x2,y2)是否在线段(x3,y3)~(x4,y4)上。

c++代码实现如下:

class Solution
{
public:
	bool IsInside(cv::Point2d lineStart, cv::Point2d lineEnd, cv::Point2d point)
	{
		return (lineStart.x == lineEnd.x || (std::min(lineStart.x, lineEnd.x) <= point.x && point.x <= std::max(lineStart.x, lineEnd.x))) &&
			(lineStart.y == lineEnd.y || (std::min(lineStart.y, lineEnd.y) <= point.y && point.y <= std::max(lineStart.y, lineEnd.y)));
	}

	/// <summary>
	/// 线段与线段之间的交点
	/// </summary>
	/// <param name="line1Start">线段1起点</param>
	/// <param name="line1End">线段1终点</param>
	/// <param name="line2Start">线段2起点</param>
	/// <param name="line2End">线段2终点</param>
	/// <returns></returns>
	cv::Point2d Intersection2Lines(cv::Point2d line1Start, cv::Point2d line1End, cv::Point2d line2Start, cv::Point2d line2End)
	{
		double x1 = line1Start.x, y1 = line1Start.y;
		double x2 = line1End.x, y2 = line1End.y;
		double x3 = line2Start.x, y3 = line2Start.y;
		double x4 = line2End.x, y4 = line2End.y;

		cv::Point2d intersectP;
		// 判断是否平行
		if ((y4 - y3) * (x2 - x1) == (y2 - y1) * (x4 - x3))
		{
			// 若共线
			if ((y2 - y1) * (x3 - x1) == (y3 - y1) * (x2 - x1)) {
				// 判断 (x3, y3) 是否在「线段」(x1, y1)~(x2, y2) 上
				if (IsInside(line1Start, line1End, line2Start)) {
					return line2Start;
				}
				// 判断 (x4, y4) 是否在「线段」(x1, y1)~(x2, y2) 上
				if (IsInside(line1Start, line1End, line2End)) {
					return line2End;
				}
				// 判断 (x1, y1) 是否在「线段」(x3, y3)~(x4, y4) 上
				if (IsInside(line2Start, line2End, line1Start)) {
					return line1Start;
				}
				// 判断 (x2, y2) 是否在「线段」(x3, y3)~(x4, y4) 上
				if (IsInside(line2Start, line2End, line2End)) {
					return line2End;
				}
			}
			// 在平行时,其余的所有情况都不会有交点
		}
		else {
			// 联立方程得到 t1 和 t2 的值
			double t1 = (double)(x3 * (y4 - y3) + y1 * (x4 - x3) - y3 * (x4 - x3) - x1 * (y4 - y3)) / ((x2 - x1) * (y4 - y3) - (x4 - x3) * (y2 - y1));
			double t2 = (double)(x1 * (y2 - y1) + y3 * (x2 - x1) - y1 * (x2 - x1) - x3 * (y2 - y1)) / ((x4 - x3) * (y2 - y1) - (x2 - x1) * (y4 - y3));
			// 判断 t1 和 t2 是否均在 [0, 1] 之间
			if (t1 >= 0.0 && t1 <= 1.0 && t2 >= 0.0 && t2 <= 1.0) {
				intersectP = cv::Point2d(x1 + t1 * (x2 - x1), y1 + t1 * (y2 - y1));
			}
		}
		return intersectP;
	}
};

### 回答1: 解两线段交点一般可以通过以下步骤进行: 1.判断两线段是否相交: 对于线段AB和CD,可以通过解向量差来判断它们是否相交。假设向量差分别是v1=A-B,v2=C-D,则两线段相交的条件是当v1和v2为同向向量时,需要满足其中一个点(A或C)在另一个线段上。当v1和v2为反向向量时,需要满足两个点(B和D)分别在另一个线段的两侧。 2.确定线段交点: 若两条线段相交,则可以通过解二元一次方程组来计算它们的交点。假设两线段的方程分别为y1=k1x1+b1和y2=k2x2+b2,则可以得到以下二元一次方程组: k1x+b1=k2x+b2 y1=k1x+b1 y2=k2x+b2 通过解方程组,可以得到交点的坐标(x,y)。 以上就是解两线段交点的方法。需要注意的是,方程组的解可能不存在或有多组解,因此在实际应用中需要进行一些额外的判断和处理,以确保结果的正确性。 ### 回答2: 要两个线段交点,可以使用以下方法: 1. 首先,确定两个线段的方程。 假设线段1的两个端点为(Ax1, Ay1)和(Ax2, Ay2),线段2的两个端点为(Bx1, By1)和(Bx2, By2)。 线段1的方程为:y = ((Ay2 - Ay1) / (Ax2 - Ax1)) * (x - Ax1) + Ay1 线段2的方程为:y = ((By2 - By1) / (Bx2 - Bx1)) * (x - Bx1) + By1 2. 接下来,解方程交点。 将线段1和线段2的方程相等,即: ((Ay2 - Ay1) / (Ax2 - Ax1)) * (x - Ax1) + Ay1 = ((By2 - By1) / (Bx2 - Bx1)) * (x - Bx1) + By1 化简后得到: ((Ay2 - Ay1)(Bx2 - Bx1) - (By2 - By1)(Ax2 - Ax1))*x = (Ax1 * (Ay2 - Ay1) - Ay1 * (Bx2 - Bx1) + Bx1 * (By2 - By1)) x = (Ax1 * (Ay2 - Ay1) - Ay1 * (Bx2 - Bx1) + Bx1 * (By2 - By1)) / ((Ay2 - Ay1)(Bx2 - Bx1) - (By2 - By1)(Ax2 - Ax1)) 将x的值代入线段1或线段2的方程中,即可得到交点的y坐标。 3. 最后,检查交点是否在两个线段的范围内。 通过比较交点的x坐标和线段1和线段2的两个端点的x坐标,以及交点的y坐标和线段1和线段2的两个端点的y坐标,判断交点是否在两个线段的范围内。 以上就是解两个线段交点的方法。 ### 回答3: 两条线段交点的方法有很多种,以下我将介绍一种常用的方法。 首先,假设有两条线段AB和CD,它们的坐标分别为A(x1, y1)、B(x2, y2)和C(x3, y3)、D(x4, y4)。 步骤如下: 1. 计算线段AB和CD的方向向量: - 方向向量1为AB的向量,即u = (x2-x1, y2-y1); - 方向向量2为CD的向量,即v = (x4-x3, y4-y3)。 2. 判断两线段是否平行: - 如果方向向量1与方向向量2平行或共线(即u和v的叉乘为0),则两条线段不可能相交,直接退出; - 否则,继续下一步。 3. 使用参数方程表示两条线段: - 线段AB的参数方程为: - x = x1 + t1*(x2-x1) - y = y1 + t1*(y2-y1) - 线段CD的参数方程为: - x = x3 + t2*(x4-x3) - y = y3 + t2*(y4-y3) 4. 解参数t1和t2: - t1和t2的取值范围均为[0,1],表示点在线段内部; - 通过t1和t2解,可以得到交点在两条线段上的参数。 5. 计算交点坐标: - x = x1 + t1*(x2-x1) - y = y1 + t1*(y2-y1) 综上所述,以上方法是解两条线段交点的一种常用方法。值得注意的是,以上方法假设线段为直线段,对于曲线段交点解需要其他的方法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

call我雨雨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值