需求 需要计算地图上点到线段的实际距离,此时有 2 种分布情况(不考虑点与线段在同一条直线上):
A 分布:
B 分布:
最开始的思路 可参考:
計算 CGPoint 兩點距離的 hypotf & hypot
计算点到线段的最近距离
计算点到线段最短距离—矢量法
数学——点到线段的最短距离
采用这种方法,无论是 A 分布还是 B 分布,都能直接算出距离。
转换成 Swift 代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 func getDistanceOfPointToSegment (point0 : MKMapPoint , point1 : MKMapPoint , point2 : MKMapPoint ) -> Float { let k = - ((point1.x - point0.x) * (point2.x - point1.x) + (point1.y - point0.y) * (point2.y - point1.y)) / ((point1.x - point2.x) * (point1.x - point2.x) + (point1.y - point2.y) * (point1.y - point2.y)) if k <= 0 { let length1 = Float (point1.x - point0.x) let length2 = Float (point1.y - point0.y) return sqrtf(pow(length1, 2 ) + pow(length2, 2 )) } else if k >= 1 { let length1 = Float (point2.x - point0.x) let length2 = Float (point2.y - point0.y) return sqrtf(pow(length1, 2 ) + pow(length2, 2 )) } else { let xf = k * (point2.x - point1.x) + point1.x let yf = k * (point2.y - point1.y) + point1.y return sqrtf(pow(Float (xf - point0.x), 2 ) + pow(Float (yf - point0.y), 2 )) } }
使用:
1 2 3 4 5 6 let point0: MKMapPoint = MKMapPoint (dot0)let point1: MKMapPoint = MKMapPoint (dot1)let point2: MKMapPoint = MKMapPoint (dot2)let distance = getDistanceOfPointToSegment(point0: point0, point1: point1, point2: point2)
不过这样存在问题,这里得出来的 distance 并非实际距离 ,应该是类似 CG 距离之类的。而实际上需要用到的是 CLLocationDistance。
新思路 AB 分布分开讨论。
首先要区分 AB 分布:可以发现 B 分布下点与线段端点的夹角大于 90 度;而 A 分布下点与线段端点的夹角均小于等于 90 度。
所以可以通过计算点与线段端点的夹角来确定是 A 分布还是 B 分布。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 func getAnglesWithThreePoints (point1 : MKMapPoint , point2 : MKMapPoint , point3 : MKMapPoint ) -> Double { if (point1.x == point2.x && point2.x == point3.x) || ( point1.y == point2.x && point2.x == point3.x){ return 0 } let a = fabs(point1.x - point2.x) let b = fabs(point1.y - point2.y) let c = fabs(point3.x - point2.x) let d = fabs(point3.y - point2.y) if (a < 1.0 && b < 1.0 ) || (c < 1.0 && d < 1.0 ){ return 0 } let e = a* c+ b* d let f = sqrt(a* a+ b* b) let g = sqrt(c* c+ d* d) let r = Double (acos(e/ (f* g))) return (180 * r/Double.pi) / / 角度值 }
参考:Swift 计算三角形角度、两条边夹角
A 分布
此时,点到线段的距离为从点出发的三角形垂线距离。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 func getVerticalVal (point1 : MKMapPoint , point2 : MKMapPoint , center : MKMapPoint ) -> Double { let a = point1.distance(to: point2) let b = center.distance(to: point1) let c = center.distance(to: point2) let p = (a + b + c) / 2.0 let s = sqrt(p * (p- a) * (p- b) * (p- c)) return s * 2.0 / a }
参考:
海伦公式求三角形垂线长度
已知三角形三点坐标求一边上的高(海伦公式和坐标推导)
B 分布 计算「钝角端点」与点的距离即可。