我需要一个基本函数来求点到线段的最短距离。你可以随意用任何你想要的语言来编写解决方案;我可以把它翻译成什么我正在使用(Javascript)。
编辑:线段由两个端点定义。线段AB由两点A (x1,y1)和B (x2,y2)定义。我要求的是这条线段到点C (x3,y3)的距离。我的几何技能生疏了,所以我看到的例子让我很困惑,我很遗憾地承认。
我需要一个基本函数来求点到线段的最短距离。你可以随意用任何你想要的语言来编写解决方案;我可以把它翻译成什么我正在使用(Javascript)。
编辑:线段由两个端点定义。线段AB由两点A (x1,y1)和B (x2,y2)定义。我要求的是这条线段到点C (x3,y3)的距离。我的几何技能生疏了,所以我看到的例子让我很困惑,我很遗憾地承认。
当前回答
如果它是一条无限大的直线,而不是一条线段,最简单的方法是这样(在ruby中),其中mx + b是直线,(x1, y1)是已知的点
(y1 - mx1 - b).abs / Math.sqrt(m**2 + 1)
其他回答
在f#中,点c到a和b之间的线段的距离为:
let pointToLineSegmentDistance (a: Vector, b: Vector) (c: Vector) =
let d = b - a
let s = d.Length
let lambda = (c - a) * d / s
let p = (lambda |> max 0.0 |> min s) * d / s
(a + p - c).Length
向量d沿着线段从a指向b。d/s与c-a的点积给出了无限直线与点c之间最接近点的参数。使用min和max函数将该参数钳制到范围0..s,使该点位于a和b之间。最后,a+p-c的长度是c到线段上最近点的距离。
使用示例:
pointToLineSegmentDistance (Vector(0.0, 0.0), Vector(1.0, 0.0)) (Vector(-1.0, 1.0))
如果它是一条无限大的直线,而不是一条线段,最简单的方法是这样(在ruby中),其中mx + b是直线,(x1, y1)是已知的点
(y1 - mx1 - b).abs / Math.sqrt(m**2 + 1)
我需要一个Godot (GDscript)的实现,所以我写了一个基于grumdrig接受的答案:
func minimum_distance(v: Vector2, w: Vector2, p: Vector2):
# Return minimum distance between line segment vw and point p
var l2: float = (v - w).length_squared() # i.e. |w-v|^2 - avoid a sqrt
if l2 == 0.0:
return p.distance_to(v) # v == w case
# Consider the line extending the segment, parameterized as v + t (w - v).
# We find projection of point p onto the line.
# It falls where t = [(p-v) . (w-v)] / |w-v|^2
# We clamp t from [0,1] to handle points outside the segment vw.
var t: float = max(0, min(1, (p - v).dot(w - v) / l2))
var projection: Vector2 = v + t * (w - v) # Projection falls on the segment
return p.distance_to(projection)
JavaScript中一个基于这个公式的更简洁的解决方案:
distToSegment: function (point, linePointA, linePointB){
var x0 = point.X;
var y0 = point.Y;
var x1 = linePointA.X;
var y1 = linePointA.Y;
var x2 = linePointB.X;
var y2 = linePointB.Y;
var Dx = (x2 - x1);
var Dy = (y2 - y1);
var numerator = Math.abs(Dy*x0 - Dx*y0 - x1*y2 + x2*y1);
var denominator = Math.sqrt(Dx*Dx + Dy*Dy);
if (denominator == 0) {
return this.dist2(point, linePointA);
}
return numerator/denominator;
}
这里它使用Swift
/* Distance from a point (p1) to line l1 l2 */
func distanceFromPoint(p: CGPoint, toLineSegment l1: CGPoint, and l2: CGPoint) -> CGFloat {
let A = p.x - l1.x
let B = p.y - l1.y
let C = l2.x - l1.x
let D = l2.y - l1.y
let dot = A * C + B * D
let len_sq = C * C + D * D
let param = dot / len_sq
var xx, yy: CGFloat
if param < 0 || (l1.x == l2.x && l1.y == l2.y) {
xx = l1.x
yy = l1.y
} else if param > 1 {
xx = l2.x
yy = l2.y
} else {
xx = l1.x + param * C
yy = l1.y + param * D
}
let dx = p.x - xx
let dy = p.y - yy
return sqrt(dx * dx + dy * dy)
}