我画了两点A(x,y)--- B(x,y)之间的一条线 现在我有第三个点C(x,y)。我想知道如果C位于A和B之间的线上。 我想用java语言做。我找到了几个类似的答案。但是,都有一些问题,没有人是完美的。
答案 0 :(得分:69)
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)':
A-----B
\ /
\ /
C
事实上,如果C位于外推线上,这甚至可以起作用:
C---A-------B
如果距离保持不合格。距离dist(AB)
可以计算为:
___________________________
/ 2 2
V (A.x - B.x) + (A.y - B.y)
请记住浮点运算的固有限制(有限精度)。您可能需要选择“足够接近”的测试(例如,小于百万分之一的错误)以确保平等的正确运行。
答案 1 :(得分:9)
<强>注意!数学只!
你可以尝试这个公式。将A(x1, y1)
和B(x2, y2)
坐标放到公式中,然后就会得到类似
y = k*x + b; // k and b - numbers
然后,任何满足这个等式的点都会在你的线上。
要检查C(x, y)
是否在A(x1, y1)
和B(x2, y2)
之间,请检查:(x1<x<x2 && y1<y<y2) || (x1>x>x2 && y1>y>y2)
。
示例强>
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
现在将C坐标放入等式:
4 = 1/2 * 4 + 2
4 = 2 + 2 // equal, C is on line AB
PS:如@paxdiablo所写,你需要在计算之前检查线是水平还是垂直。请检查
y1 == y2 || x1 == x2
答案 2 :(得分:7)
我认为最简单的是
// 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,则会有不同的测试来查看A是否出现在A和B之间的线上。数学假设A,B,C是无限小点。实际上非常小到表示错误。
答案 3 :(得分:2)
以上答案不必要地复杂化。最简单的如下。
如果(x-x1)/(x2-x1)=(y-y1)/(y2-y1)= alpha(常数),则点C(x,y)将位于第1和第1点之间的界限2。
如果alpha&lt; 0.0,然后C在点1的外部。
希望这个答案有所帮助。
答案 4 :(得分:1)
我认为一个简单的方法是检查3个点形成的角度。 如果ACB角为180度(或接近于此,取决于您想要的精度),则点C在A和B之间。
答案 5 :(得分:1)
我认为这可能有帮助
How to check if a point lies on a line between 2 other points
该解决方案仅使用整数,因为您只需提供整数即可消除一些陷阱
答案 6 :(得分:0)
我认为这里的所有方法都存在缺陷,因为它们并没有尽可能严格地处理舍入错误。基本上,所描述的方法将使用一些简单的算法告诉您您的点是否足够接近线,并且它将或多或少精确。
为什么精确度很重要?因为这是op提出的问题。对于一个计算机程序来说,没有一个点在一条线上,一条线的epsilon中只有一点,需要记录这个epsilon。
让我们来说明问题所在。使用距离比较算法:
让我们说段从(0,0)到(0,2000),我们在我们的应用程序中使用浮点数(它有大约7位小数的精度),我们测试是否有点( 1E-6,1000)是否在线。
从段的任一端到该点的距离是1000.0000000005或1000 + 5E-10,因此,与该点之间的距离的增加之间的差异是大约1E-9。但是这些值都不能存储在具有足够精确度的浮点数上,并且该方法将返回true
。
如果我们使用更精确的方法,比如计算到线中最近点的距离,它会返回一个值,浮动具有足够的精度来存储,我们可以根据可接受的epsilon返回false。
我在示例中使用了浮点数,但同样适用于任何浮点类型,例如double。
一种解决方案是使用BigDecimal以及您想要的任何方法,如果性能和内存命中不是问题。
比比较浮点距离更精确的方法,更重要的是,始终精确,尽管计算成本较高,但计算距离线中最近点的距离。
Shortest distance between a point and a line segment
看起来我分裂了头发,但我之前不得不处理这个问题。链接几何运算时会出现问题。如果你不能控制你正在处理什么样的预防损失,最终你会遇到困难的错误,这会导致你严格地对代码进行推理以解决问题。
答案 7 :(得分:0)
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
答案 8 :(得分:0)
这是我的 C# 解决方案。我相信 Java 等价物将几乎相同。
注意事项:
只有当点在直线的边界内时,方法才会返回 true(它不假设一条无限长的直线)。
它将处理垂直或水平线。
它计算要检查的点与线的距离,以便将容差传递给该方法。
/// <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;
}
}
答案 9 :(得分:0)
这是我制作的一个 JavaScript 函数。您向它传递三个点(具有 x 和 y 属性的三个对象)。点 1 和点 2 定义您的线,点 3 是您要测试的点。
您将收到一个带有一些有用信息的对象:
on_projected_line
- 如果 pt3
位于线上的任意位置,包括点之外。on_line
- 如果 pt3
位于线上以及 pt1
和 pt2
之间或之上。x_between
- 如果 pt3
在 x 边界之间或之上。y_between
- 如果 pt3
在 y 边界之间或之上。between
- 如果 x_between
和 y_between
都为真。/**
* @description Check if pt3 is on line defined by pt1 and pt2.
* @param {Object} pt1 The first point defining the line.
* @param {float} pt1.x
* @param {float} pt1.y
* @param {Object} pt2 The second point defining the line.
* @param {float} pt2.x
* @param {float} pt2.y
* @param {Object} pt3 The point to test.
* @param {float} pt3.x
* @param {float} pt3.y
*/
function pointOnLine(pt1, pt2, pt3) {
const result = {
on_projected_line: true,
on_line: false,
between_both: false,
between_x: false,
between_y: false,
};
// Determine if on line interior or exterior
const x = (pt3.x - pt1.x) / (pt2.x - pt1.x);
const y = (pt3.y - pt1.y) / (pt2.y - pt1.y);
// Check if on line equation
result.on_projected_line = x === y;
// Check within x bounds
if (
(pt1.x <= pt3.x && pt3.x <= pt2.x) ||
(pt2.x <= pt3.x && pt3.x <= pt1.x)
) {
result.between_x = true;
}
// Check within y bounds
if (
(pt1.y <= pt3.y && pt3.y <= pt2.y) ||
(pt2.y <= pt3.y && pt3.y <= pt1.y)
) {
result.between_y = true;
}
result.between_both = result.between_x && result.between_y;
result.on_line = result.on_projected_line && result.between_both;
return result;
}
console.log("pointOnLine({x: 0, y: 0}, {x: 1, y: 1}, {x: 2, y: 2})")
console.log(pointOnLine({x: 0, y: 0}, {x: 1, y: 1}, {x: 2, y: 2}))
console.log("pointOnLine({x: 0, y: 0}, {x: 1, y: 1}, {x: 0.5, y: 0.5})")
console.log(pointOnLine({x: 0, y: 0}, {x: 1, y: 1}, {x: 0.5, y: 0.5}))