求直线与直线、直线与圆、直线与矩形的交点
- 直线与直线的交点:a1x + b1x + c1x = 0 与 a2x + b2x + c2x = 0的交点坐标可直接根据公式x = (b1c2 - b2c1)/(a1b2 - a2b1),y = (a2c1 - a1c2)/(a1b2 - a2b1)得出,其中a1b2 - a2b1 == 0时,代表两条直线重合或平行
- 直线与圆的交点:通过将圆心到直线的距离d与半径r大小对比分三种情况讨论:1)d>r,没有交点 2)d=r,一个交点 3)d<r,两个交点,具体设计可参考下图(此图是在网上搜方法看到的,原地址找不到了,如有侵犯还请原谅,感谢原主的帮助):
- 直线与矩形的交点:问题可以简化为求直线与构成矩形的四条线段的交点,方法为:假设求直线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("直线与矩形没有交点");
}
}
结果截屏:
第一次写博客,决定写博客是因为自己写程序时会出现很多不懂得地方,搞懂了后会很多的感想,于是就希望记录下来加深印象,同时希望这篇博客能给大家带来帮助!大家如果有什么更好的方法欢迎留言,谢谢!