可能有人问过关于查找点是否在一条线上但不是在这种情况下的问题,他们没有回答为什么各种方法都有不同的缺陷。给定点的坐标和线的坐标,准确找到点是否在一条线上的最佳方法是什么?我试图自己实现某些方法,但经过测试,它们似乎都有自己的问题。我确定还有其他方法,我知道 Java 有一种方法可以计算点与直线的距离,如果在直线上,则返回 0。Java 用什么方法判断一个点是否在一条线上?
第一种方法将 A 点到 B 点的距离与 A 点到 C 点加上 C 点到 B 点的距离进行比较。这种方法的问题在于它不精确,因为它使用 Math.sqrt。
public static boolean inLine(double x1, double y1, double x2, double y2, double x3, double y3){
if((distance(x1, y1, x3, y3) + distance(x2, y2, x3, y3)) == distance(x1, y1, x2, y2)){
return true;
}
return false;
}
public static double distance(double x1, double y1, double x2, double y2){
double base = x2 - x1;
double height = y2 - y1;
double hypotenuse = Math.sqrt((base * base) + (height * height));
return hypotenuse;
}
Run Code Online (Sandbox Code Playgroud)
这是我想到的第二种方法。它通过将点的 y 值与与该点具有相同 x 值的线上的 y 值进行比较来检查该点是否在该线上。这种方法的问题是当线条是垂直或水平时它不起作用,所以我实施了一些测试来检查它是否在线条是水平或垂直的线上。
public static boolean inLine(double x1, double y1, double x2, double y2, double x3, double y3){
//Check if X and Y Values of the point are within the range of the line
if(inBetween(x1, x2, x3) & inBetween(y1, y2, y3) ){
//Check if denominator is going to equal 0 when finding the slope and x of point has the same value
if(x1 == x2 && x2 == x3){
if(inBetween(y1, y2, y3)){
return true;
}else{
return false;
}
}else if(y1 == y2 && y2 == y3){
if(inBetween(x1, x2, x3)){
return true;
}else{
return false;
}
}else{
double slope = (y2-y1)/(x2-x1);
//Check if the y value of the line is equal to the y value of the point
if(findYIntercept(slope, x1, y1)+slope*x3 == y3){
return true;
}
}
}else{
return false;
}
return false;
}
public static double findYIntercept(double slope, double x, double y){
return y-(slope*x);
}
public static boolean inBetween(double a, double b, double c){
if(a <= c && c <= b){
return true;
}
else if(a >= c && c >= b){
return true;
}
return false;
}
Run Code Online (Sandbox Code Playgroud)
此方法类似于第二种方法,但检查斜率是否相同。如果线是水平的或垂直的,它也不起作用。如果线是水平的或垂直的,我还实现了一种情况。
public static boolean inLine(double x1, double y1, double x2, double y2, double x3, double y3){
//Check if X and Y Values of the point are within the range of the line
if(inBetween(x1, x2, x3) & inBetween(y1, y2, y3) ){
//Check if denominator is going to equal 0 when finding the slope and x of point has the same value
if(x1 == x2 && x2 == x3){
if(inBetween(y1, y2, y3)){
return true;
}else{
return false;
}
}else if(y1 == y2 && y2 == y3){
if(inBetween(x1, x2, x3)){
return true;
}else{
return false;
}
}else{
double slope1 = (y2-y1)/(x2-x1);
double slope2 = (y3-y1)/(x3-x1);
//Check if the y value of the line is equal to the y value of the point
if(slope1 == slope2){
return true;
}
}
}else{
return false;
}
return false;
}
public static double findYIntercept(double slope, double x, double y){
return y-(slope*x);
}
public static boolean inBetween(double a, double b, double c){
if(a <= c && c <= b){
return true;
}
else if(a >= c && c >= b){
return true;
}
return false;
}
Run Code Online (Sandbox Code Playgroud)
最好的方法可能是第一种。任何使用斜率的方法都是有问题的,因为垂直线具有无限斜率。
您的方法一代码的问题不是Math.sqrt,而是浮点计算不准确。因此,比较double值a和b使用==. 相反,您应该使用类似的东西Math.abs(a - b) < 0x1p-32来查看它们是否足够接近。
由于浮点计算的局限性,要正确地做这种事情是极其困难的。java.awt 做得不是很好。例如,以下程序打印 0.5,这是非常不准确的。
double a = 18981256.0;
System.out.println(new Line2D.Double(1.0, 2.0, 2.0, 4.0).ptLineDist(a, 2 * a));
Run Code Online (Sandbox Code Playgroud)