我需要一个基本函数来求点到线段的最短距离。你可以随意用任何你想要的语言来编写解决方案;我可以把它翻译成什么我正在使用(Javascript)。
编辑:线段由两个端点定义。线段AB由两点A (x1,y1)和B (x2,y2)定义。我要求的是这条线段到点C (x3,y3)的距离。我的几何技能生疏了,所以我看到的例子让我很困惑,我很遗憾地承认。
我需要一个基本函数来求点到线段的最短距离。你可以随意用任何你想要的语言来编写解决方案;我可以把它翻译成什么我正在使用(Javascript)。
编辑:线段由两个端点定义。线段AB由两点A (x1,y1)和B (x2,y2)定义。我要求的是这条线段到点C (x3,y3)的距离。我的几何技能生疏了,所以我看到的例子让我很困惑,我很遗憾地承认。
当前回答
in R
#distance beetween segment ab and point c in 2D space
getDistance_ort_2 <- function(a, b, c){
#go to complex numbers
A<-c(a[1]+1i*a[2],b[1]+1i*b[2])
q=c[1]+1i*c[2]
#function to get coefficients of line (ab)
getAlphaBeta <- function(A)
{ a<-Re(A[2])-Re(A[1])
b<-Im(A[2])-Im(A[1])
ab<-as.numeric()
ab[1] <- -Re(A[1])*b/a+Im(A[1])
ab[2] <-b/a
if(Im(A[1])==Im(A[2])) ab<- c(Im(A[1]),0)
if(Re(A[1])==Re(A[2])) ab <- NA
return(ab)
}
#function to get coefficients of line ortogonal to line (ab) which goes through point q
getAlphaBeta_ort<-function(A,q)
{ ab <- getAlphaBeta(A)
coef<-c(Re(q)/ab[2]+Im(q),-1/ab[2])
if(Re(A[1])==Re(A[2])) coef<-c(Im(q),0)
return(coef)
}
#function to get coordinates of interception point
#between line (ab) and its ortogonal which goes through point q
getIntersection_ort <- function(A, q){
A.ab <- getAlphaBeta(A)
q.ab <- getAlphaBeta_ort(A,q)
if (!is.na(A.ab[1])&A.ab[2]==0) {
x<-Re(q)
y<-Im(A[1])}
if (is.na(A.ab[1])) {
x<-Re(A[1])
y<-Im(q)
}
if (!is.na(A.ab[1])&A.ab[2]!=0) {
x <- (q.ab[1] - A.ab[1])/(A.ab[2] - q.ab[2])
y <- q.ab[1] + q.ab[2]*x}
xy <- x + 1i*y
return(xy)
}
intersect<-getIntersection_ort(A,q)
if ((Mod(A[1]-intersect)+Mod(A[2]-intersect))>Mod(A[1]-A[2])) {dist<-min(Mod(A[1]-q),Mod(A[2]-q))
} else dist<-Mod(q-intersect)
return(dist)
}
其他回答
这是一个基于向量数学的;这个解决方案也适用于更高的维度,并报告交点(在线段上)。
def dist(x1,y1,x2,y2,px,py):
a = np.array([[x1,y1]]).T
b = np.array([[x2,y2]]).T
x = np.array([[px,py]]).T
tp = (np.dot(x.T, b) - np.dot(a.T, b)) / np.dot(b.T, b)
tp = tp[0][0]
tmp = x - (a + tp*b)
d = np.sqrt(np.dot(tmp.T,tmp)[0][0])
return d, a+tp*b
x1,y1=2.,2.
x2,y2=5.,5.
px,py=4.,1.
d, inters = dist(x1,y1, x2,y2, px,py)
print (d)
print (inters)
结果是
2.1213203435596424
[[2.5]
[2.5]]
这里解释了数学
https://brilliant.org/wiki/distance-between-point-and-line/
in R
#distance beetween segment ab and point c in 2D space
getDistance_ort_2 <- function(a, b, c){
#go to complex numbers
A<-c(a[1]+1i*a[2],b[1]+1i*b[2])
q=c[1]+1i*c[2]
#function to get coefficients of line (ab)
getAlphaBeta <- function(A)
{ a<-Re(A[2])-Re(A[1])
b<-Im(A[2])-Im(A[1])
ab<-as.numeric()
ab[1] <- -Re(A[1])*b/a+Im(A[1])
ab[2] <-b/a
if(Im(A[1])==Im(A[2])) ab<- c(Im(A[1]),0)
if(Re(A[1])==Re(A[2])) ab <- NA
return(ab)
}
#function to get coefficients of line ortogonal to line (ab) which goes through point q
getAlphaBeta_ort<-function(A,q)
{ ab <- getAlphaBeta(A)
coef<-c(Re(q)/ab[2]+Im(q),-1/ab[2])
if(Re(A[1])==Re(A[2])) coef<-c(Im(q),0)
return(coef)
}
#function to get coordinates of interception point
#between line (ab) and its ortogonal which goes through point q
getIntersection_ort <- function(A, q){
A.ab <- getAlphaBeta(A)
q.ab <- getAlphaBeta_ort(A,q)
if (!is.na(A.ab[1])&A.ab[2]==0) {
x<-Re(q)
y<-Im(A[1])}
if (is.na(A.ab[1])) {
x<-Re(A[1])
y<-Im(q)
}
if (!is.na(A.ab[1])&A.ab[2]!=0) {
x <- (q.ab[1] - A.ab[1])/(A.ab[2] - q.ab[2])
y <- q.ab[1] + q.ab[2]*x}
xy <- x + 1i*y
return(xy)
}
intersect<-getIntersection_ort(A,q)
if ((Mod(A[1]-intersect)+Mod(A[2]-intersect))>Mod(A[1]-A[2])) {dist<-min(Mod(A[1]-q),Mod(A[2]-q))
} else dist<-Mod(q-intersect)
return(dist)
}
快速实现http://paulbourke.net/geometry/pointlineplane/source.c
static func magnitude(p1: CGPoint, p2: CGPoint) -> CGFloat {
let vector = CGPoint(x: p2.x - p1.x, y: p2.y - p1.y)
return sqrt(pow(vector.x, 2) + pow(vector.y, 2))
}
/// http://paulbourke.net/geometry/pointlineplane/
/// http://paulbourke.net/geometry/pointlineplane/source.c
static func pointDistanceToLine(point: CGPoint, lineStart: CGPoint, lineEnd: CGPoint) -> CGFloat? {
let lineMag = magnitude(p1: lineEnd, p2: lineStart)
let u = (((point.x - lineStart.x) * (lineEnd.x - lineStart.x)) +
((point.y - lineStart.y) * (lineEnd.y - lineStart.y))) /
(lineMag * lineMag)
if u < 0 || u > 1 {
// closest point does not fall within the line segment
return nil
}
let intersectionX = lineStart.x + u * (lineEnd.x - lineStart.x)
let intersectionY = lineStart.y + u * (lineEnd.y - lineStart.y)
return magnitude(p1: point, p2: CGPoint(x: intersectionX, y: intersectionY))
}
2D坐标数组的Python Numpy实现:
import numpy as np
def dist2d(p1, p2, coords):
''' Distance from points to a finite line btwn p1 -> p2 '''
assert coords.ndim == 2 and coords.shape[1] == 2, 'coords is not 2 dim'
dp = p2 - p1
st = dp[0]**2 + dp[1]**2
u = ((coords[:, 0] - p1[0]) * dp[0] + (coords[:, 1] - p1[1]) * dp[1]) / st
u[u > 1.] = 1.
u[u < 0.] = 0.
dx = (p1[0] + u * dp[0]) - coords[:, 0]
dy = (p1[1] + u * dp[1]) - coords[:, 1]
return np.sqrt(dx**2 + dy**2)
# Usage:
p1 = np.array([0., 0.])
p2 = np.array([0., 10.])
# List of coordinates
coords = np.array(
[[0., 0.],
[5., 5.],
[10., 10.],
[20., 20.]
])
d = dist2d(p1, p2, coords)
# Single coordinate
coord = np.array([25., 25.])
d = dist2d(p1, p2, coord[np.newaxis, :])
WPF版本:
public class LineSegment
{
private readonly Vector _offset;
private readonly Vector _vector;
public LineSegment(Point start, Point end)
{
_offset = (Vector)start;
_vector = (Vector)(end - _offset);
}
public double DistanceTo(Point pt)
{
var v = (Vector)pt - _offset;
// first, find a projection point on the segment in parametric form (0..1)
var p = (v * _vector) / _vector.LengthSquared;
// and limit it so it lays inside the segment
p = Math.Min(Math.Max(p, 0), 1);
// now, find the distance from that point to our point
return (_vector * p - v).Length;
}
}