如何获取直线上与另一点距离最小的点的坐标
How to get the coordinates of the point on a line that has the smallest distance from another point
我现在正在为这个几何问题而苦恼。
假设我们有一条由点 A(x1,y1) 和点 B(x2,y2) 定义的线
我们还有一个点 C(x3,y3).
SWIFT中写的什么函数可以给我离直线距离最小的点的坐标(X,Y)?换句话说,直线上的点是垂直线段与另一点的交点。
func getCoordsOfPointsWithSmallestDistanceBetweenLineAndPoint(lineX1: Double, lineY1: Double, lineX2: Double, lineY2: Double, pointX3: Double, pointY3: Double) -> [Double] {
// ???
return [x,y]
}
从数学的角度你可以:
先求直线的方程:
y1 = a1x1+b1
a1 = (y2-y1) / (x2-x1)
b1 = y1-a1*x1
然后计算第二行知道的梯度:
a1 * a2 = -1 <->
a2 = -1/a1
用 a2 你可以找到第二个等式的 b 值:
y3 = a2*x3 + b2 <->
b2 = y3 - a2*x3
最后计算出两条线的交点:
xi = (b2-b1) / (a1-a2)
y = a1*xi + b1
然后把它带到 swift 就很简单了:
typealias Line = (gradient:CGFloat, intercept:CGFloat)
func getLineEquation(point1:CGPoint, point2:CGPoint) -> Line {
guard point1.x != point2.x else {
if(point1.y != point2.y)
{
print("Vertical line : x = \(point1.x)")
}
return (gradient: .nan, intercept: .nan)
}
let gradient = (point2.y - point1.y)/(point2.x-point1.x)
let intercept = point1.y - gradient*point1.x
return (gradient: gradient, intercept: intercept)
}
func getPerpendicularGradient(gradient:CGFloat) -> CGFloat
{
guard gradient != 0 else {
print("horizontal line, the perpendicilar line is vertical")
return .nan
}
return -1/gradient
}
func getIntercept(forPoint point:CGPoint, withGradient gradient:CGFloat) -> CGFloat
{
return point.y - gradient * point.x
}
func getIntersectionPoint(line1:Line, line2:Line)-> CGPoint
{
guard line1.gradient != line2.gradient else {return CGPoint(x: CGFloat.nan, y: CGFloat.nan)}
let x = (line2.intercept - line1.intercept)/(line1.gradient-line2.gradient)
return CGPoint(x:x, y: line1.gradient*x + line1.intercept)
}
func getClosestIntersectionPoint(forLine line:Line, point:CGPoint) -> CGPoint
{
let line2Gradient = getPerpendicularGradient(gradient:line.gradient)
let line2 = (
gradient: line2Gradient,
intercept: getIntercept(forPoint: point, withGradient: line2Gradient))
return getIntersectionPoint(line1:line, line2:line2)
}
func getClosestIntersectionPoint(forLinePoint1 linePoint1:CGPoint, linePoint2:CGPoint, point:CGPoint) -> CGPoint
{
return getClosestIntersectionPoint(
forLine:getLineEquation(point1: linePoint1, point2: linePoint2),
point:point)
}
您可以最小化 C
到直线 AB
上一点的平方距离:
(CA + t.AB)² = t²AB² + 2t AB.CA + CA²
最低达到
t = - AB.CA / AB²
和
CP = CA + t.AB
详细说明 如果转换为函数,其形式为
func closestPnt(x: Double, y: Double, x1: Double, y1: Double, px: Double, py: Double)->[Double]{
let vx = x1 - x // vector of line
let vy = y1 - y
let ax = px - x // vector from line start to point
let ay = py - y
let u = (ax * vx + ay * vy) / (vx * vx + vy * vy) // unit distance on line
if u >= 0 && u <= 1 { // is on line segment
return [x + vx * u, y + vy * u] // return closest point on line
}
if u < 0 {
return [x, y] // point is before start of line segment so return start point
}
return [x1, y1] // point is past end of line so return end
}
注意该函数是针对线段的,如果最近的点单位距离在起点后面或超过终点则终点最近。
如果你想要一条线上的点(无限长),那么下面的方法就可以了。
func closestPnt(x: Double, y: Double, x1: Double, y1: Double, px: Double, py: Double)->[Double]{
let vx = x1 - x // vector of line
let vy = y1 - y
let ax = px - x // vector from line start to point
let ay = py - y
let u = (ax * vx + ay * vy) / (vx * vx + vy * vy) // unit distance on line
return [x + vx * u, y + vy * u] // return closest point on line
}
注意 这两个函数都假定 !(x1 == x && y1 == y)
为真。即线段的长度必须 > 0.
我现在正在为这个几何问题而苦恼。
假设我们有一条由点 A(x1,y1) 和点 B(x2,y2) 定义的线 我们还有一个点 C(x3,y3).
SWIFT中写的什么函数可以给我离直线距离最小的点的坐标(X,Y)?换句话说,直线上的点是垂直线段与另一点的交点。
func getCoordsOfPointsWithSmallestDistanceBetweenLineAndPoint(lineX1: Double, lineY1: Double, lineX2: Double, lineY2: Double, pointX3: Double, pointY3: Double) -> [Double] {
// ???
return [x,y]
}
从数学的角度你可以:
先求直线的方程:
y1 = a1x1+b1 a1 = (y2-y1) / (x2-x1) b1 = y1-a1*x1
然后计算第二行知道的梯度:
a1 * a2 = -1 <-> a2 = -1/a1
用 a2 你可以找到第二个等式的 b 值:
y3 = a2*x3 + b2 <-> b2 = y3 - a2*x3
最后计算出两条线的交点:
xi = (b2-b1) / (a1-a2) y = a1*xi + b1
然后把它带到 swift 就很简单了:
typealias Line = (gradient:CGFloat, intercept:CGFloat)
func getLineEquation(point1:CGPoint, point2:CGPoint) -> Line {
guard point1.x != point2.x else {
if(point1.y != point2.y)
{
print("Vertical line : x = \(point1.x)")
}
return (gradient: .nan, intercept: .nan)
}
let gradient = (point2.y - point1.y)/(point2.x-point1.x)
let intercept = point1.y - gradient*point1.x
return (gradient: gradient, intercept: intercept)
}
func getPerpendicularGradient(gradient:CGFloat) -> CGFloat
{
guard gradient != 0 else {
print("horizontal line, the perpendicilar line is vertical")
return .nan
}
return -1/gradient
}
func getIntercept(forPoint point:CGPoint, withGradient gradient:CGFloat) -> CGFloat
{
return point.y - gradient * point.x
}
func getIntersectionPoint(line1:Line, line2:Line)-> CGPoint
{
guard line1.gradient != line2.gradient else {return CGPoint(x: CGFloat.nan, y: CGFloat.nan)}
let x = (line2.intercept - line1.intercept)/(line1.gradient-line2.gradient)
return CGPoint(x:x, y: line1.gradient*x + line1.intercept)
}
func getClosestIntersectionPoint(forLine line:Line, point:CGPoint) -> CGPoint
{
let line2Gradient = getPerpendicularGradient(gradient:line.gradient)
let line2 = (
gradient: line2Gradient,
intercept: getIntercept(forPoint: point, withGradient: line2Gradient))
return getIntersectionPoint(line1:line, line2:line2)
}
func getClosestIntersectionPoint(forLinePoint1 linePoint1:CGPoint, linePoint2:CGPoint, point:CGPoint) -> CGPoint
{
return getClosestIntersectionPoint(
forLine:getLineEquation(point1: linePoint1, point2: linePoint2),
point:point)
}
您可以最小化 C
到直线 AB
上一点的平方距离:
(CA + t.AB)² = t²AB² + 2t AB.CA + CA²
最低达到
t = - AB.CA / AB²
和
CP = CA + t.AB
详细说明
func closestPnt(x: Double, y: Double, x1: Double, y1: Double, px: Double, py: Double)->[Double]{
let vx = x1 - x // vector of line
let vy = y1 - y
let ax = px - x // vector from line start to point
let ay = py - y
let u = (ax * vx + ay * vy) / (vx * vx + vy * vy) // unit distance on line
if u >= 0 && u <= 1 { // is on line segment
return [x + vx * u, y + vy * u] // return closest point on line
}
if u < 0 {
return [x, y] // point is before start of line segment so return start point
}
return [x1, y1] // point is past end of line so return end
}
注意该函数是针对线段的,如果最近的点单位距离在起点后面或超过终点则终点最近。
如果你想要一条线上的点(无限长),那么下面的方法就可以了。
func closestPnt(x: Double, y: Double, x1: Double, y1: Double, px: Double, py: Double)->[Double]{
let vx = x1 - x // vector of line
let vy = y1 - y
let ax = px - x // vector from line start to point
let ay = py - y
let u = (ax * vx + ay * vy) / (vx * vx + vy * vy) // unit distance on line
return [x + vx * u, y + vy * u] // return closest point on line
}
注意 这两个函数都假定 !(x1 == x && y1 == y)
为真。即线段的长度必须 > 0.