有没有人在java中有一个函数来找到点和线段/边之间的最短距离?我找到的每个例子都是用另一种语言编写的,并使用了一堆子函数。它不能基于它们是垂直的假设。
更新
我将python函数移植到java。如果有人擅长数学并且可以验证,我将不胜感激。x 和 y 是点,其他参数是线段。
public float pDistance(float x, float y, float x1, float y1, float x2, float y2) {
float A = x - x1;
float B = y - y1;
float C = x2 - x1;
float D = y2 - y1;
float dot = A * C + B * D;
float len_sq = C * C + D * D;
float param = -1;
if (len_sq != 0) //in case of 0 length line
param = dot / len_sq;
float xx, yy;
if (param < 0) {
xx = x1;
yy = y1;
}
else if (param > 1) {
xx = x2;
yy = y2;
}
else {
xx = x1 + param * C;
yy = y1 + param * D;
}
float dx = x - xx;
float dy = y - yy;
return (float) Math.sqrt(dx * dx + dy * dy);
}
Run Code Online (Sandbox Code Playgroud)
Sal*_*lba 10
我们可以稍微简化一下。您不需要计算参数。您可以做的是找到与该线成直角的向量v。取向量 (A,B) 的点积。在 2D 中很容易找到与(C,D)正交的向量,它只是(-D,C)。
public float pDistance(float x, float y, float x1, float y1, float x2, float y2) {
float A = x - x1; // position of point rel one end of line
float B = y - y1;
float C = x2 - x1; // vector along line
float D = y2 - y1;
float E = -D; // orthogonal vector
float F = C;
float dot = A * E + B * F;
float len_sq = E * E + F * F;
return (float) Math.abs(dot) / Math.sqrt(len_sq);
}
Run Code Online (Sandbox Code Playgroud)
如果您担心性能可以更容易地使用平方距离,那么最后一行将是
return (float) dot * dot / len_sq;
Run Code Online (Sandbox Code Playgroud)
这省去了计算平方根的麻烦。所以如果你想计算最近的边,找到到每条边的平方距离并选择最小的。
此函数查找到无限线而不是线段的距离。这可能不是您想要的。题中的解与点超出线段两端的情况不同。在那里它找到到最近端点的距离。
来自http://en.wikipedia.org/wiki/Distance_from_a_point_to_a_line
点到线的距离(或垂直距离)是欧几里得几何中点到线的最短距离。它是连接点和线并垂直于线的线段的长度。
你说“不能基于它们垂直的假设”,但是点和线段之间的最短距离代表另一条与原始线垂直的线。因此,它是由 AB 和 C 形成的三角形的高度,其中 A - 点,B 和 C 是线段的端点。
我们知道所有三个点的坐标,因此我们可以获得三角形的边长。使用 Heron 公式: https: //www.mathsisfun.com/geometry/herons-formula.html我们可以从以下位置获得也等于 0.5 * b * h 的面积:https: //www.mathsisfun.com/algebra/ trig-area-triangle-without-right-angle.html
private static float distBetweenPointAndLine(float x, float y, float x1, float y1, float x2, float y2) {
// A - the standalone point (x, y)
// B - start point of the line segment (x1, y1)
// C - end point of the line segment (x2, y2)
// D - the crossing point between line from A to BC
float AB = distBetween(x, y, x1, y1);
float BC = distBetween(x1, y1, x2, y2);
float AC = distBetween(x, y, x2, y2);
// Heron's formula
float s = (AB + BC + AC) / 2;
float area = (float) Math.sqrt(s * (s - AB) * (s - BC) * (s - AC));
// but also area == (BC * AD) / 2
// BC * AD == 2 * area
// AD == (2 * area) / BC
// TODO: check if BC == 0
float AD = (2 * area) / BC;
return AD;
}
private static float distBetween(float x, float y, float x1, float y1) {
float xx = x1 - x;
float yy = y1 - y;
return (float) Math.sqrt(xx * xx + yy * yy);
}
Run Code Online (Sandbox Code Playgroud)
我不知道它有多正确,希望真正的数学家能够纠正或支持这个解决方案