直线与直线、直线与圆、直线与矩形的交点

求直线与直线、直线与圆、直线与矩形的交点

  1. 直线与直线的交点:a1x + b1x + c1x = 0 与 a2x + b2x + c2x = 0的交点坐标可直接根据公式x = (b1c2 - b2c1)/(a1b2 - a2b1),y = (a2c1 - a1c2)/(a1b2 - a2b1)得出,其中a1b2 - a2b1 == 0时,代表两条直线重合或平行
  2. 直线与圆的交点:通过将圆心到直线的距离d与半径r大小对比分三种情况讨论:1)d>r,没有交点 2)d=r,一个交点 3)d<r,两个交点,具体设计可参考下图(此图是在网上搜方法看到的,原地址找不到了,如有侵犯还请原谅,感谢原主的帮助):在这里插入图片描述
  3. 直线与矩形的交点:问题可以简化为求直线与构成矩形的四条线段的交点,方法为:假设求直线PQ与线段AB的交点,首先求A到直线PQ的带符号距离d和B到直线PQ的带符号距离d2,如果d1与d2异号或其中至少有一个为0,则交点存在,假设交点为M。D1为A到直线PQ的距离,D2为B到直线PQ的距离,求线段AM占段线AB的比例k=D1/(D1+D2);如果D1+D2==0,即D1和D2均为0,也就是说段线AB与直线PQ重合。有了线段AM点AB的比例k,就可以求出M了: M = A + (B - A) * k;如果d1与d2同号的话就表示直线与线段没有交点。

在以上方法中还有一些需要关注的细节点
1)直线在讨论的过程中需要将直线平行于x,y轴的情况单独讨论
2)求直线与矩形交点时,当交点正好是矩形的顶点时,简单求直线与四条线段的交点会造成顶点在其邻线段被重复计算,因此在计算每条线段时舍去线段的一个端点

代码如下:

/*本程序采用java语言,实现直线与直线、直线与圆、直线与矩形的交点
以(0,0)为坐标原点,建立直角坐标 
直线: a*x +b*x +c = 0  参数:a, b, c
圆 参数 :圆心坐标(x0, y0)  半径 r
矩形参数:三个顶点坐标A:(x1, y1)B:(x2, y2)C:(x3, y3)  限制∠ABC构成直角*/

package robotcup;

public class GetIntersection {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		pointTwoLine(1, 1, -1, 1, -1, 0);//求两直线交点   直线一:x+y-1=0  直线二:x-y=0
		pointLineCircle(1, 1, -1, 1, 1, 1);//求直线与圆的交点  直线:x+y-1=0     圆心:(1,1) r=1
		pointLineRectangular(1, 1, -0.5, 0, 1, 0, 0, 1, 0);//求直线与矩形的交点   直线:x+y-1=0   矩形 三个顶点坐标为A:(0, 1)B:(0, 0)C:(1, 0)
	}
	//求两直线交点
	public static void pointTwoLine(double a1,double b1, double c1, double a2,double b2, double c2 ){
		double x,y;
		if(a1*b2 - a2*b1 == 0){//判断直线是否重合或平行
			System.out.println("两直线重合或平行");
			return;
		}
		x = (b1*c2 - b2*c1)/(a1*b2 - a2*b1);//求交点公式
		y = (a2*c1 - a1*c2)/(a1*b2 - a2*b1);
		System.out.println("两直线交点坐标为:"+"("+ x +","+ y +")");//打印结果
	}
	//求直线与圆交点
	public static void pointLineCircle(double a,double b, double c, double x, double y, double r) {
		double d;//d为点到直线的距离
		d = (a*x+ b*y +c)/(Math.sqrt(a*a + b*b));
		d = Math.sqrt(d*d);//取d的正数
		if(d > r){
			System.out.println("直线和圆没有交点");
			return;
		}
		//直线与圆有一个交点
		else if(d == r){
			if(b == 0){//当直线平行于y轴时,交点直接位于过圆心平行x轴的方向上距离为r  直线方程可表示为: x = -c/a
				if(-c/a > x){//交点位于圆点右侧
					System.out.println("直线与圆的交点坐标为:"+"("+ (x+r) +","+ y +")");//打印结果
					return;
				}
				else {//交点位于圆点左侧
					System.out.println("直线与圆的交点坐标为:"+"("+ (x-r) +","+ y +")");//打印结果
					return;
				}
			}
			else if(a == 0){//直线平行于x轴
				if(-c/b > y)//交点位于圆点上方
					System.out.println("直线与圆的交点坐标为:"+"("+ x +","+ (y+r) +")");//打印结果
				else{//交点位于圆点下方
					System.out.println("直线与圆的交点坐标为:"+"("+ x +","+ (y-r) +")");//打印结果
				}
			}
			else {//当直线与x,y轴均不平行时
				pointLineCircle(a, b, c, a, -b, b*y-a*x);//交点为直线与过原点且垂直于直线的直线的交点
				return;
			}
		}
		//直线与圆有两个交点
		else {
			if(b == 0){//当直线平行于y轴时
				if(-c/a > x){//交点位于圆点右侧
					System.out.println("直线与圆的交点坐标为:"+"("+ (x+d) +","+ (y+Math.sqrt(r*r-d*d)) +")"+"("+ (x+d) +","+ (y-Math.sqrt(r*r-d*d)) +")");//打印结果
					return;
				}
				else{//交点位于圆点左侧
					System.out.println("直线与圆的交点坐标为:"+"("+ (x-d) +","+ (y+Math.sqrt(r*r-d*d)) +")"+"("+ (x-d) +","+ (y-Math.sqrt(r*r-d*d)) +")");//打印结果
					return;
				}
			}
			else if(a == 0){//直线平行于x轴
				if(-c/b > x){//交点位于圆点上方
					System.out.println("直线与圆的交点坐标为:"+"("+ (x+Math.sqrt(r*r-d*d)) +","+ (y+d) +")"+","+"("+ (x-Math.sqrt(r*r-d*d)) +","+ (y+d) +")");//打印结果
					return;
				}
				else{//交点位于圆点下方
					System.out.println("直线与圆的交点坐标为:"+"("+ (x+Math.sqrt(r*r-d*d)) +","+ (y-d) +")"+","+"("+ (x-Math.sqrt(r*r-d*d)) +","+ (y-d) +")");//打印结果
					return;
				}
			}
			else {//当直线与x,y轴均不平行时
				double a1, b1, c1, a2, b2, c2;
				double x3, y3;//定义圆心在直线上的投影点坐标
				double d3;//定义直线在圆内的1/2倍线段长
				d3 = Math.sqrt(r*r - d*d);
				a1 = a; b1 = b; c1 = c; 
				a2 = a; b2 = -b; c2 = b*y - a*x; 
				x3 = (b1*c2 - b2*c1)/(a1*b2 - a2*b1);//求出圆心在直线上的投影点坐标
				y3 = (a2*c1 - a1*c2)/(a1*b2 - a2*b1);
				double x0, y0, d0;//定义直线上的单位向量e(x0, y0) 以及投影点到直线上点(0, -c/b)的距离d0
				d0 = Math.sqrt(x3*x3+(y3+c/b)*(y3+c/b));
				x0 = x3/d0;
				y0 = (y3+c/b)/d0;
				System.out.println("直线与圆的交点坐标为:"+"("+ (x3+x0*d3) +","+ (y3+y0*d3) +")"+","+"("+ (x3-x0*d3) +","+ (y3-y0*d3) +")");//打印结果
			}
		}
	}
	//求(x,y)到直线的带符号距离
	public static double getSignedDistance(double a, double b, double c, double x, double y) {
		double d = (a*x+ b*y +c)/(Math.sqrt(a*a + b*b));
		d = Math.sqrt(d*d);//取d的正数
		if(b == 0){//当直线垂直于x轴时,直线的表达式可表示为:x = -c/a
			if(x <= -c/a)
				return -d;//点位于直线左侧,符号取负
			else
				return d;//点位于直线左侧,符号取正
		}
		else{
			if(y >= ((-a/b)*x - c/b))
				return d;//点位于直线上侧,符号取正
			else
				return -d;//点位于直线下侧,符号取负
		}
	}
		
	//直线与线段交点
	public static boolean pointLineSegment(double a, double b, double c, double x1, double y1, double x2, double y2) {
		double d1,d2;
		d1 = getSignedDistance(a, b, c, x1, y1);//求(x1,y1)到直线的带符号距离
		d2 = getSignedDistance(a, b, c, x2, y2);//求(x2,y2)到直线的带符号距离
		if(d1*d2 <=0){//当d1与d2异号或者其中至少有一个为0时,交点存在
			d1 = Math.sqrt(d1*d1);//去符号
			d2 = Math.sqrt(d2*d2);
			double k = d1/(d1 + d2);//求d1所占线段的比例
			if((d1 + d2 != 0) && (((x1+k*(x2-x1)) != x1)||((y1+k*(y2-y1)) != y1))){//距离都不为0且不是线段的第一个端点时(为了避免交点为矩形邻边的交点导致端点被计算两次的情况)
				System.out.println("交点:"+"("+(x1+k*(x2-x1)) +","+ (y1+k*(y2-y1)) +")");//根据向量运算以以及比例关系求出交点坐标
				return true;
			}
			else if(d1 + d2 == 0){
				System.out.println("直线与矩形的一条边重合,存在无数个交点");
				return true;
			}
		}
		else{
			return false;
		}
		return false;
	}
	//直线与矩形交点
	public static void pointLineRectangular (double a, double b, double c, double x1, double y1, double x2, double y2, double x3, double y3) {
		double x4,y4;//定义矩形第四个点的横纵坐标
		x4 = x1 + x3 - x2;
		y4 = y1 + y3 - y2;
		//接下来依次求解直线与构成矩形的四条线段的交点
		boolean m1,m2,m3,m4;//设置是否有交点的标志
		System.out.println("直线与矩形交点的计算结果为 : ");
		m1 = pointLineSegment(a, b, c, x1, y1, x2, y2); 
		m2 = pointLineSegment(a, b, c, x2, y2, x3, y3); 
		m3 = pointLineSegment(a, b, c, x3, y3, x4, y4); 
		m4 = pointLineSegment(a, b, c, x4, y4, x1, y1); 
		if(m1 == m2 == m3 == m4 == false)
			System.out.println("直线与矩形没有交点");
	}

}


结果截屏:
在这里插入图片描述
第一次写博客,决定写博客是因为自己写程序时会出现很多不懂得地方,搞懂了后会很多的感想,于是就希望记录下来加深印象,同时希望这篇博客能给大家带来帮助!大家如果有什么更好的方法欢迎留言,谢谢!

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值