【计算几何】判断一条线段和一段圆弧是否相交 & C++代码实现

这篇具有很好参考价值的文章主要介绍了【计算几何】判断一条线段和一段圆弧是否相交 & C++代码实现。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


一、前言

最近做项目,需要判断一条线段是否和一段圆弧相交,网上也没找到很好的解答(最主要是没有直接可以搬来用的代码,或者思路写得太过高深,我看不懂),于是决定自己想一个方法,写一个博客,将实现思路和完整代码都分享出来


二、线段与圆弧的代码表示

2.1 线段代码表示

线段可用两个点表示,点的对象如下所示,包含x和y坐标信息:

class Point {
public:
    Point(double px=0.0, double py=0.0) {
        x = px;
        y = py;
    }
    double x;
    double y;
};

2.2 圆弧代码表示

圆弧由圆心坐标、半径、起始和终止角度组成:

class Arc
{
public:
	Point centerpoint; // 圆心
	double radius; // 圆弧半径
	double bangle; // 起点角度
	double eangle; // 终点角度
};

三、实现思路及数学推导

3.1 第一步(粗略判断)

第一步(粗略判断):将线段当成直线,将圆弧当成圆,如果直线和圆不相交,则线段和圆弧必然不相交,否则进行下一步判断

首先,将线段扩展成一条直线,它的方程为: y = k x + c y=kx+c y=kx+c

根据线段的两个点(假设为 p 1 p_1 p1 p 2 p_2 p2,且 p 1 . x ≤ p 2 . x p_1.x\le p_2.x p1.xp2.x)信息,我们可以很轻易求出 k k k c c c 的取值

p 1 p_1 p1 p 2 p_2 p2 代入直线方程:

{ p 1 . y = k p 1 . x + c                  ( 1 ) p 2 . y = k p 2 . x + c                  ( 2 ) \begin{cases} p_1.y=kp_1.x+c\,\, \ \ \ \ \ \ \ \ \ \ \ \ \ \left( 1 \right)\\ p_2.y=kp_2.x+c\,\, \ \ \ \ \ \ \ \ \ \ \ \ \ \left( 2 \right) \end{cases} {p1.y=kp1.x+c             (1)p2.y=kp2.x+c             (2)

( 1 ) − ( 2 ) (1)-(2) (1)(2) 可得:

p 1 . y − p 2 . y = ( p 1 . x − p 2 . x ) k ⇒ k = p 1 . y − p 2 . y p 1 . x − p 2 . x               ( 3 ) p_1.y-p_2.y=\left( p_1.x-p_2.x \right) k \\ \Rightarrow k=\frac{p_1.y-p_2.y}{p_1.x-p_2.x} \ \ \ \ \ \ \ \ \ \ \ \ \ \left( 3 \right) p1.yp2.y=(p1.xp2.x)kk=p1.xp2.xp1.yp2.y             (3)

( 3 ) (3) (3) 代入 ( 1 ) (1) (1) 可得:

p 1 . y = p 1 . y − p 2 . y p 1 . x − p 2 . x p 1 . x + c ⇒ c = p 1 . y − p 1 . y − p 2 . y p 1 . x − p 2 . x p 1 . x               ( 4 ) p_1.y=\frac{p_1.y-p_2.y}{p_1.x-p_2.x}p_1.x+c \\ \Rightarrow c=p_1.y-\frac{p_1.y-p_2.y}{p_1.x-p_2.x}p_1.x \ \ \ \ \ \ \ \ \ \ \ \ \ \left( 4 \right) p1.y=p1.xp2.xp1.yp2.yp1.x+cc=p1.yp1.xp2.xp1.yp2.yp1.x             (4)

假设圆心坐标为 ( a , b ) (a,b) (a,b) ,半径为 r r r ,容易写出圆弧扩展而成的圆的方程如下所示:

( x − a ) 2 + ( y − b ) 2 = r 2               ( 5 ) (x-a)^2+(y-b)^2=r^2 \ \ \ \ \ \ \ \ \ \ \ \ \ \left( 5 \right) (xa)2+(yb)2=r2             (5)

要判断直线和圆是否相交,需要将直线方程和圆方程进行联立得:

{ y = k x + c ( x − a ) 2 + ( y − b ) 2 = r 2 ⇓ ( x − a ) 2 + ( k x + c − b ) 2 = r 2 , 令 d = c − b ⇓ x 2 + a 2 − 2 a x + k 2 x 2 + d 2 + 2 k d x = r 2 ⇓ ( 1 + k 2 ) x 2 + ( 2 k d − 2 a ) x + a 2 + d 2 − r 2 = 0               ( 6 ) \begin{cases} y=kx+c \\ (x-a)^2+(y-b)^2=r^2 \\ \end{cases} \\ \Downarrow \\ (x-a)^2+(kx+c-b)^2=r^2,令d=c-b \\ \Downarrow \\ x^2+a^2-2ax+k^2x^2+d^2+2kdx=r^2 \\ \Downarrow \\ (1+k^2)x^2+(2kd-2a)x+a^2+d^2-r^2=0 \ \ \ \ \ \ \ \ \ \ \ \ \ \left( 6 \right) {y=kx+c(xa)2+(yb)2=r2(xa)2+(kx+cb)2=r2,d=cbx2+a22ax+k2x2+d2+2kdx=r2(1+k2)x2+(2kd2a)x+a2+d2r2=0             (6)

根据韦达定理判断一元二次方程 ( 6 ) (6) (6) 是否存在实数根:

Δ = ( 2 k d − 2 a ) 2 − 4 ( 1 + k 2 ) ( a 2 + d 2 − r 2 ) ⇒ { Δ < 0 : 式 ( 6 ) 不存在实数根 Δ ≥ 0 : 式 ( 6 ) 存在实数根 \varDelta=(2kd-2a)^2-4(1+k^2)(a^2+d^2-r^2) \Rightarrow \begin{cases} \varDelta<0: 式 (6) 不存在实数根 \\ \varDelta\ge0:式 (6) 存在实数根 \end{cases} Δ=(2kd2a)24(1+k2)(a2+d2r2){Δ<0:(6)不存在实数根Δ0:(6)存在实数根

如果式 ( 6 ) (6) (6) 不存在实数根,意味着直线和圆没有交点,此时线段和圆弧必然也没有交点,程序结束。

如果式 ( 6 ) (6) (6) 存在实数根,则可以解出直线与圆的两个交点的 X X X 方向坐标 x 1 x_1 x1 x 2 x_2 x2

x 1 = − ( 2 k d − 2 a ) + Δ 2 ( 1 + k 2 )  和  x 2 = − ( 2 k d − 2 a ) − Δ 2 ( 1 + k 2 ) x_1=\frac{-(2kd-2a)+\sqrt{\varDelta}}{2(1+k^2)} \ 和 \ x_2=\frac{-(2kd-2a)-\sqrt{\varDelta}}{2(1+k^2)} x1=2(1+k2)(2kd2a)+Δ   x2=2(1+k2)(2kd2a)Δ

x 1 x_1 x1 x 2 x_2 x2 分别代入直线方程 y = k x + c y=kx+c y=kx+c 可得两个交点的 Y Y Y 方向坐标 y 1 y_1 y1 y 2 y_2 y2

y 1 = k x 1 + c  和  y 2 = k x 2 + c y_1=kx_1+c \ 和\ y_2=kx_2+c y1=kx1+c  y2=kx2+c

需要注意的是:上面我们令直线方程为 y = k x + c y=kx+c y=kx+c,但当直线垂直时, k k k 其实是不存在的,上面的公式也就不再适用了。幸运的是,在这种情况下,直线方程会变得更加简单,即 x = c x=c x=c c c c 为一个常数。要求这个直线与圆的交点,只需要将 x = c x=c x=c 代入圆的方程中即可,如下所示:
{ x = c ( x − a ) 2 + ( y − b ) 2 = r 2 ⇓ ( c − a ) 2 + ( y − b ) 2 = r 2 ⇓ ( y − b ) 2 = r 2 − ( c − a ) 2 \begin{cases} x=c \\ (x-a)^2+(y-b)^2=r^2 \\ \end{cases} \\ \Downarrow \\ (c-a)^2+(y-b)^2=r^2\\ \Downarrow \\ (y-b)^2 = r^2 - (c-a)^2\\ {x=c(xa)2+(yb)2=r2(ca)2+(yb)2=r2(yb)2=r2(ca)2
显然,当且仅当 r 2 − ( c − a ) 2 ≥ 0 r^2 - (c-a)^2\ge0 r2(ca)20 时,直线与圆存在交点,且交点的横坐标相同,即 x 1 = x 2 = c x_1=x_2=c x1=x2=c;纵坐标分别为:
y 1 = b + r 2 − ( c − a ) 2  和  y 2 = b − r 2 − ( c − a ) 2 y_1=b+\sqrt{r^2 - (c-a)^2} \ 和\ y_2=b-\sqrt{r^2 - (c-a)^2} y1=b+r2(ca)2   y2=br2(ca)2

如果直线和圆存在交点,则进行下一步判断

3.2 第二步

第二步:判断直线和圆的两个交点是否在线段上,如果不在,说明线段和圆弧必然不相交,否则进行下一步判断

线段是连续的,所以可以通过区间判断两个交点是否在线段上

详细地说,我们已经知道线段的X轴方向的区间为 [ p 1 . x   ,   p 2 . x ] [p_1.x\ ,\ p_2.x] [p1.x , p2.x]

如果 x 1 x_1 x1 不在 [ p 1 . x   ,   p 2 . x ] [p_1.x\ ,\ p_2.x] [p1.x , p2.x] 区间内,则点 ( x 1 , y 1 ) (x_1,y_1) (x1,y1) 不在线段上,也就不可能是线段和圆弧的交点

同理,如果 x 2 x_2 x2 不在 [ p 1 . x   ,   p 2 . x ] [p_1.x\ ,\ p_2.x] [p1.x , p2.x] 区间内,则点 ( x 2 , y 2 ) (x_2,y_2) (x2,y2) 也不可能是线段和圆弧的交点

如果点 ( x 1 , y 1 ) (x_1,y_1) (x1,y1) 和点 ( x 2 , y 2 ) (x_2,y_2) (x2,y2) 都不是线段和圆弧的交点,则说明线段和圆弧必然不相交

否则进行下一步判断

3.3 第三步

第三步:根据前面的推导,假设已知直线和圆的一个在线段上的交点为 ( x 1 , y 1 ) (x_1,y_1) (x1,y1),在这一步中,需要判断该点是否在圆弧上,如果在,则说明线段和圆弧相交,且交点为 ( x 1 , y 1 ) (x_1,y_1) (x1,y1)

在这一步中,需要使用圆的参数方程,为了方便表示,假设圆弧的起始角度和终止角度分别为 θ 1 \theta_1 θ1 θ 2 \theta_2 θ2,则圆弧的参数方程为:

{ x = a + r c o s θ      ( 7 ) y = b + r s i n θ      ( 8 )      , θ 1 ≤ θ ≤ θ 2 \begin{cases} x=a+rcos\theta \ \ \ \ \left( 7 \right) \\ y=b+rsin\theta \ \ \ \ \left( 8 \right) \\ \end{cases} \ \ \ \ ,\theta_1\le\theta\le\theta_2 {x=a+rcosθ    (7)y=b+rsinθ    (8)    ,θ1θθ2

( x 1 , y 1 ) (x_1,y_1) (x1,y1) 代入式 ( 7 ) (7) (7) 和式 ( 8 ) (8) (8) 中:

{ x 1 = a + r c o s θ y 1 = b + r s i n θ      , θ 1 ≤ θ ≤ θ 2 ⇓ { x 1 − a = r c o s θ      ( 9 ) y 1 − b = r s i n θ      ( 10 )      , θ 1 ≤ θ ≤ θ 2 \begin{cases} x_1=a+rcos\theta \\ y_1=b+rsin\theta \\ \end{cases} \ \ \ \ ,\theta_1\le\theta\le\theta_2 \\ \Downarrow \\ \begin{cases} x_1-a=rcos\theta \ \ \ \ \left( 9 \right) \\ y_1-b=rsin\theta \ \ \ \ \left( 10 \right) \\ \end{cases} \ \ \ \ ,\theta_1\le\theta\le\theta_2 {x1=a+rcosθy1=b+rsinθ    ,θ1θθ2{x1a=rcosθ    (9)y1b=rsinθ    (10)    ,θ1θθ2

( 10 ) (10) (10) ( 9 ) (9) (9) 可得:

y 1 − b x 1 − a = t a n θ ⇓ θ = a r c t a n ( y 1 − b x 1 − a ) \frac{y_1-b}{x_1-a}=tan\theta \\ \Downarrow \\ \theta = arctan(\frac{y_1-b}{x_1-a}) x1ay1b=tanθθ=arctan(x1ay1b)

如果解出的 θ \theta θ 不在区间 [ θ 1 , θ 2 ] [\theta_1,\theta_2] [θ1,θ2] 内,则说明点 ( x 1 , y 1 ) (x_1,y_1) (x1,y1) 不在圆弧上

否则,点 ( x 1 , y 1 ) (x_1,y_1) (x1,y1) 在圆弧上,并且是线段和圆弧的一个交点

至此,证毕!

注意:使用 a t a n atan atan 函数计算反正切值时,返回值的取值范围是 [ − π 2 , π 2 ] [-\frac{\pi}{2},\frac{\pi}{2}] [2π,2π],而 θ \theta θ 的取值是 [ 0 , 2 π ] [0,2\pi] [0,2π],所以在实际代码中需要对角度进行转换


四、完整代码

// 圆周率
#define PI acos(-1)

// lineIsIntersectArc 的辅助函数:接着第二步判断(这个函数可能存在浮点数误差问题,导致判断结果有偏差)
bool lineIsIntersectArcAuxiliaryFunction(const DL_VertexData& p1, const DL_VertexData& p2, double a, double b, double theta1, double theta2, double x1, double y1) {
	// 2.3 判断交点是否在线段上
	if (p1.x <= x1 && x1 <= p2.x) {
		// 第三步:交点(x1,y1)在线段上,再判断该点是否在圆弧上,如果在,则说明线段和圆弧相交,且交点为(x1,y1)
		double theta = atan((y1 - b) / (x1 - a)) * 180.0 / PI;
		if (theta1 > theta2) {
			if (theta2 >= 0) {
				theta1 -= 360;
			}
			else {
				theta2 += 360;
			}
		}
		if (theta1 < 0 && theta2 < 0) {
			theta1 += 360;
			theta2 += 360;
		}
		// 修正 tan 的角度
		if (x1 < a) {
			theta += 180;
		}
		if (theta < 0) {
			theta += 360;
		}
		// 判断是否在边界,在边界其实就不算相交
		if (abs(theta1 - theta) <= 1e-12 || abs(theta2 - theta) <= 1e-12) {
			return false;
		}
		// 判断 theta 是否在圆弧范围内,如果在则(x1,y1)是线段和圆弧的交点,否则不是
		return theta1 < theta && theta < theta2;
	}
	return false;
}

// 判断一个线段是否和圆弧相交
bool lineIsIntersectArc(Point p1, Point p2, Arc arc){
		// 确保 p1.x < p2.x
	if (p1.x > p2.x) {
		DL_VertexData temp = p1;
		p1 = p2;
		p2 = temp;
	}
	// 简化圆弧的相关变量表示
	double a = arc.centerpoint.x;
	double b = arc.centerpoint.y;
	double r = arc.radius;
	double theta1 = arc.bangle;
	double theta2 = arc.eangle;
	// 开始判断
	if (abs(p1.x - p2.x) < 1e-12) {
		// 特殊处理 p1.x = p2.x 的情况
		double c = p1.x;
		double temp = r * r - (c - a) * (c - a);
		if (temp >= -1e-12) {
			// 第二步:判断直线和圆的两个交点是否在线段上,如果不在,说明线段和圆弧必然不相交,否则进行下一步判断
			// 2.1 计算两个交点的坐标(x1,y1)和(x2,y2)
			double x1 = c;
			double x2 = c;
			double y1 = b + sqrt(temp);
			double y2 = b - sqrt(temp);
			// 2.2 判断两个交点是否相等3
			if (abs(y1 - y2) < 1e-12) {
				// 两个交点相等,只需要对其中任意一个点进行判断即可
				return lineIsIntersectArcAuxiliaryFunction(p1, p2, a, b, theta1, theta2, x1, y1);
			}
			else {
				// 两个交点不相等,分别进行判断,只要其中一个是线段和圆弧的交点就返回 true
				return lineIsIntersectArcAuxiliaryFunction(p1, p2, a, b, theta1, theta2, x1, y1) || lineIsIntersectArcAuxiliaryFunction(p1, p2, a, b, theta1, theta2, x2, y2);
			}
		}
	}
	else {
		// 第一步(粗略判断):将线段当成直线,将圆弧当成圆,如果直线和圆不相交,则线段和圆弧必然不相交,否则进行下一步判断
		// 1.1 根据公式,计算直线方程 y=kx+c 中的 k 和 c
		double k = (p1.y - p2.y) / (p1.x - p2.x);
		double c = p1.y - (p1.y - p2.y) / (p1.x - p2.x) * p1.x;
		// 1.2 根据韦达定理判断式(6)是否存在实数根
		double d = c - b;
		double varDelta = pow(2 * k * d - 2 * a, 2) - 4 * (1 + k * k) * (a * a + d * d - r * r);
		if (varDelta >= -1e-12) {
			// 第二步:判断直线和圆的两个交点是否在线段上,如果不在,说明线段和圆弧必然不相交,否则进行下一步判断
			// 2.1 计算两个交点的坐标(x1,y1)和(x2,y2)
			double x1 = (2 * a - 2 * k * d + sqrt(varDelta)) / (2 * (1 + k * k));
			double x2 = (2 * a - 2 * k * d - sqrt(varDelta)) / (2 * (1 + k * k));
			double y1 = k * x1 + c;
			double y2 = k * x2 + c;
			// 2.2 判断两个交点是否相等
			if (varDelta < 1e-12) {
				// 两个交点相等,只需要对其中任意一个点进行判断即可
				return lineIsIntersectArcAuxiliaryFunction(p1, p2, a, b, theta1, theta2, x1, y1);
			}
			else {
				// 两个交点不相等,分别进行判断,只要其中一个是线段和圆弧的交点就返回 true
				return lineIsIntersectArcAuxiliaryFunction(p1, p2, a, b, theta1, theta2, x1, y1) || lineIsIntersectArcAuxiliaryFunction(p1, p2, a, b, theta1, theta2, x2, y2);
			}
		}
	}
	return false;
}

五、效果展示

有了判断一条线段和一段圆弧是否相交的函数之后,就可以用来判断圆弧是否和一个多边形相交了。最简单的思路就是用圆弧和多边形的每个边依次做判断,如果多边形的任意一条边和圆弧都不相交,则圆弧与多边形必然不相交。

交叉判断前,从下图可以看到,黄色部分就是圆弧和多边形出现了交叉重叠的情况

【计算几何】判断一条线段和一段圆弧是否相交 & C++代码实现

交叉判断后,圆弧与多边形的交叉情况完全消失~

【计算几何】判断一条线段和一段圆弧是否相交 & C++代码实现文章来源地址https://www.toymoban.com/news/detail-429840.html

到了这里,关于【计算几何】判断一条线段和一段圆弧是否相交 & C++代码实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 百度地图API:JavaScript开源库几何运算判断点是否在多边形内(电子围栏)

    漏刻有时百度地图API实战开发(1)华为手机无法使用addEventListener click 的兼容解决方案 漏刻有时百度地图API实战开发(2)文本标签显示和隐藏的切换开关 漏刻有时百度地图API实战开发(3)自动获取地图多边形中心点坐标 漏刻有时百度地图API实战开发(4)显示指定区域在移动端异常的

    2024年02月07日
    浏览(66)
  • 图形几何学——圆形:圆弧与曲率

    A、B、C分别是参考线的某三个连续的离散点,abc分别是其对边。根据三角形外接圆相关性质,通过作三条边的中垂线的交点可以求得三角形的外接圆心。连接CO并延长交圆周于点D,由于 近似认为 ∣ P 1 ⃗ ∣ = ∣ P 2 P 3 ⃗ ∣ = d s |vec{P_1}| = |vec{P_2P_3}| = ds ∣ P 1 ​ ​ ∣ = ∣

    2024年04月27日
    浏览(75)
  • 阿里最新EMO:只需要提供一张照片和一段音频,即可生成会说话唱歌的AI视频

    只要一张照片加上音频,就能让你说话唱歌,阿里做到了。 最近,阿里新上线了一款AI图片-音频-视频模型技术EMO,用户只需要提供一张照片和一段任意音频文件,EMO即可生成会说话唱歌的AI视频。以及实现无缝对接的动态小视频, 最长时间可达1分30秒左右。 阿里研究团队表

    2024年03月16日
    浏览(53)
  • untiy 连接两个UI或一段固定一段跟随鼠标移动的线段

    注意,仅适用于UI,且Canvas必须是Camera模式,不能用在3D物体上,3D物体请使用LineRenender 先创建一个图片,将锚点固定在左边 然后在脚本中添加如下内容

    2024年02月13日
    浏览(44)
  • 【计算几何】判断多边形边界顺逆时针 & C++代码实现

    多边形可以由一个点集 { v 1 , v 2 , . . . , v n } {v_1,v_2,...,v_n} { v 1 ​ , v 2 ​ , ... , v n ​ } 表示,构成多边形的点集确定,多边形边界的顺序也就确定了 有关多边形边界的顺序的示意图,如下图所示: 有时候关于数据格式有规定,要求多边形边界必须为顺时针或者逆时针。 因

    2024年02月07日
    浏览(60)
  • 【计算几何】凸多面体重叠判断算法:GJK 算法详解 & C++代码实现二维情形的凸多边形重叠判断

    GJK 算法是由 Gilbert,Johnson,Keerthi 三位前辈发明的, 用来计算两个凸多面体之间的碰撞检测 ,以及最近距离。 GJK 算法可以在 O ( M + N ) O(M+N) O ( M + N ) 的时间复杂度内,检测出碰撞,算法在每次迭代的过程中,都会优先选择靠近原点的方向,因此收敛速度会很快。算法的证明

    2024年02月08日
    浏览(67)
  • 用Python判断是否为闰年并计算生肖年

    1 问题 润平年以及生肖是新的一年到来我们应该了解的信息。那么如何利用python程序计算快速计算该年为什么年? 2 方法 利用if条件判断语句实现。 代码清单 1 year = eval(input(\\\'请输入咨询的年份:\\\')) if (year % 4 == 0 and year %100 != 0) or year % 400 == 0:     print(\\\'该年是闰年\\\') else:    p

    2024年02月07日
    浏览(51)
  • 用补码计算x+y,并判断结果是否溢出问题

    作者简介 :一名后端开发人员,每天分享后端开发以及人工智能相关技术,行业前沿信息,面试宝典。 座右铭 :未来是不可确定的,慢慢来是最快的。 个人主页 :极客李华-CSDN博客 合作方式 :私聊+ 这个专栏内容 :BAT等大厂常见后端java开发面试题详细讲解,更新数目10

    2024年02月11日
    浏览(34)
  • (IP地址的计算)判断两个IP是否归属于同一子网

    目录 前言 判断依据(附示例) 问题          今天在做题的时候做到了IP地址计算这一部分的题目,太久没有看过了,忘得都差不多了,所以就查阅了资料并做了如下笔记,帮助学习理解,同时把这道题的题目与网友分享的做法分享给大家,可以一起做一做,希望能帮助

    2024年02月08日
    浏览(55)
  • 【Python实用基础整合(二)】DataFrame是否为空判断及行/列差值、变化率计算

    判断整个DataFrame是否为空的方法: 示例: 而判断具体某个元素是否为NAN,则可以使用 isna() 函数: 或者使用空值的特征判断( NAN的一大特征就是不等于本身 ): 计算DataFrame行/列的差值使用: 其中, periods :默认值是1,表示两行/列的索引之差,即平移的区间,periods为正整

    2024年02月16日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包