Java 检查点(x,y)是否位于直线上绘制的两点之间
我已经在两点a(x,y)-B(x,y)之间画了一条线 现在我有第三个点C(x,y)。我想知道,如果C位于A和B之间的直线上。 我想用java语言来做。我发现了两个类似的答案。但是,所有人都有一些问题,没有人是完美的Java 检查点(x,y)是否位于直线上绘制的两点之间,java,line,Java,Line,我已经在两点a(x,y)-B(x,y)之间画了一条线 现在我有第三个点C(x,y)。我想知道,如果C位于A和B之间的直线上。 我想用java语言来做。我发现了两个类似的答案。但是,所有人都有一些问题,没有人是完美的 if (distance(A, C) + distance(B, C) == distance(A, B)) return true; // C is on the line. return false; // C is not on the line. 或者只是:
if (distance(A, C) + distance(B, C) == distance(A, B))
return true; // C is on the line.
return false; // C is not on the line.
或者只是:
return distance(A, C) + distance(B, C) == distance(A, B);
其工作方式相当简单。如果C位于AB
行,您将得到以下场景:
A-C------B
而且,不管它位于那条线上的什么位置,dist(AC)+dist(CB)==dist(AB)
。对于任何其他情况,您有一个描述为“dist(AC)+dist(CB)>dist(AB)”的三角形:
事实上,如果C位于外推线上,这一点也有效:
C---A-------B
只要距离保持无符号。距离dist(AB)
可计算为:
___________________________
/ 2 2
V (A.x - B.x) + (A.y - B.y)
请记住浮点运算的固有限制(有限精度)。您可能需要选择一个“足够接近”的测试(比如,小于百万分之一的错误)来确保等式的正确运行。注意!只有数学强> 你可以试试这个公式。把你的
A(x1,y1)
和B(x2,y2)
坐标放到公式中,你会得到如下结果
y = k*x + b; // k and b - numbers
那么,满足这个方程的任何一点,都位于你的直线上。
要检查C(x,y)
是否介于A(x1,y1)
和B(x2,y2)
之间,请检查此项:(x1y2)
示例
A(2,3) B(6,5)
直线方程:
(y - 3)/(5 - 3) = (x - 2)/(6 - 2)
(y - 3)/2 = (x - 2)/4
4*(y - 3) = 2*(x - 2)
4y - 12 = 2x - 4
4y = 2x + 8
y = 1/2 * x + 2; // equation of line. k = 1/2, b = 2;
让我们检查C(4,4)
是否位于此行
2<4<6 & 3<4<5 // C between A and B
PS:正如@paxdiablo所写,在计算之前,您需要检查直线是水平的还是垂直的。检查一下
y1 == y2 || x1 == x2
我相信最简单的是
// is BC inline with AC or visa-versa
public static boolean inLine(Point A, Point B, Point C) {
// if AC is vertical
if (A.x == C.x) return B.x == C.x;
// if AC is horizontal
if (A.y == C.y) return B.y == C.y;
// match the gradients
return (A.x - C.x)*(A.y - C.y) == (C.x - B.x)*(C.y - B.y);
}
可以通过将x值的差值除以y值的差值来计算渐变
注意:如果在屏幕上绘制C,则有一个不同的测试来查看C是否出现在a和B之间的线上。数学假设A、B、C是无限小点。事实上,误差非常小。上述答案不必要地复杂。最简单的方法如下
希望这个答案有帮助 我认为这里所有的方法都有一个陷阱,因为它们没有尽可能严格地处理舍入错误。基本上,所描述的方法将告诉您,使用一些简单的算法,您的点是否足够接近直线,并且它将或多或少精确 为什么精确性很重要?因为这正是op提出的问题。对于一个计算机程序来说,直线上没有点,只有一条直线的ε内的点,而ε是什么需要记录下来 让我们来说明这个问题。使用距离比较算法: 假设一段从(0,0)到(0,2000),我们在应用程序中使用浮点(精度约为7位小数),我们测试(1E-61000)上的一点是否在直线上 从管段两端到该点的距离为1000.0000000005或1000+5E-10,因此,与该点之间距离相加的差值约为1E-9。但是这些值都不能以足够的精度存储在浮点上,该方法将返回
true
如果我们使用更精确的方法,比如计算到直线上最近点的距离,它会返回一个浮点值,该值具有足够的精度来存储,并且根据可接受的ε,我们可能会返回false
我在示例中使用了浮点,但这同样适用于任何浮点类型,例如double
一种解决方案是使用BigDecimal,如果性能和内存不受影响,则可以使用任何方法
一种比比较浮点距离更精确的方法,更重要的是,始终如一地精确,尽管计算成本更高,但计算到直线上最近点的距离
看起来我在吹毛求疵,但我以前不得不处理这个问题。这是链接几何操作时的一个问题。如果你不能控制你正在处理的精度损失类型,最终你会遇到困难的错误,这将迫使你对代码进行严格的推理以修复它们。一个简单的方法是检查3个点形成的角度。
如果角度ACB为180度(或接近它,取决于您希望的精确度),则点C位于A和B之间。我认为这可能会有所帮助
def DistBetwPoints(p1, p2):
return math.sqrt( (p2[0] - p1[0])**2 + (p2[1] - p1[1])**2 )
# "Check if point C is between line endpoints A and B"
def PointBetwPoints(A, B, C):
dist_line_endp = DistBetwPoints(A,B)
if DistBetwPoints(A,C)>dist_line_endp: return 1
elif DistBetwPoints(B,C)>dist_line_endp: return 1
else: return 0
该解决方案只使用整数,因为您只提供整数,这也消除了一些陷阱这是我的C#解决方案。我相信Java等价物将几乎相同
注:
/// <summary>
/// Check if Point C is on the line AB
/// </summary>
public static bool IsOnLine(Point A, Point B, Point C, double tolerance)
{
double minX = Math.Min(A.X, B.X) - tolerance;
double maxX = Math.Max(A.X, B.X) + tolerance;
double minY = Math.Min(A.Y, B.Y) - tolerance;
double maxY = Math.Max(A.Y, B.Y) + tolerance;
//Check C is within the bounds of the line
if (C.X >= maxX || C.X <= minX || C.Y <= minY || C.Y >= maxY)
{
return false;
}
// Check for when AB is vertical
if (A.X == B.X)
{
if (Math.Abs(A.X - C.X) >= tolerance)
{
return false;
}
return true;
}
// Check for when AB is horizontal
if (A.Y == B.Y)
{
if (Math.Abs(A.Y - C.Y) >= tolerance)
{
return false;
}
return true;
}
// Check istance of the point form the line
double distFromLine = Math.Abs(((B.X - A.X)*(A.Y - C.Y))-((A.X - C.X)*(B.Y - A.Y))) / Math.Sqrt((B.X - A.X) * (B.X - A.X) + (B.Y - A.Y) * (B.Y - A.Y));
if (distFromLine >= tolerance)
{
return false;
}
else
{
return true;
}
}
//
///检查点C是否在AB线上
///
公共静态边界线(点A、点B、点C、双公差)
{
双最小值=数学最小值(A.X,B.X)-公差;
double maxX=数学最大值(A.X,B.X)+公差;
双最小值=数学最小值(A.Y,B.Y)-公差;
双最大值=数学最大值(A.Y,B.Y)+公差;
//检查C是否在该行的范围内
如果(C.X>=ma
def DistBetwPoints(p1, p2):
return math.sqrt( (p2[0] - p1[0])**2 + (p2[1] - p1[1])**2 )
# "Check if point C is between line endpoints A and B"
def PointBetwPoints(A, B, C):
dist_line_endp = DistBetwPoints(A,B)
if DistBetwPoints(A,C)>dist_line_endp: return 1
elif DistBetwPoints(B,C)>dist_line_endp: return 1
else: return 0
/// <summary>
/// Check if Point C is on the line AB
/// </summary>
public static bool IsOnLine(Point A, Point B, Point C, double tolerance)
{
double minX = Math.Min(A.X, B.X) - tolerance;
double maxX = Math.Max(A.X, B.X) + tolerance;
double minY = Math.Min(A.Y, B.Y) - tolerance;
double maxY = Math.Max(A.Y, B.Y) + tolerance;
//Check C is within the bounds of the line
if (C.X >= maxX || C.X <= minX || C.Y <= minY || C.Y >= maxY)
{
return false;
}
// Check for when AB is vertical
if (A.X == B.X)
{
if (Math.Abs(A.X - C.X) >= tolerance)
{
return false;
}
return true;
}
// Check for when AB is horizontal
if (A.Y == B.Y)
{
if (Math.Abs(A.Y - C.Y) >= tolerance)
{
return false;
}
return true;
}
// Check istance of the point form the line
double distFromLine = Math.Abs(((B.X - A.X)*(A.Y - C.Y))-((A.X - C.X)*(B.Y - A.Y))) / Math.Sqrt((B.X - A.X) * (B.X - A.X) + (B.Y - A.Y) * (B.Y - A.Y));
if (distFromLine >= tolerance)
{
return false;
}
else
{
return true;
}
}