我正在寻找一种方法来计算 CGPoint 是否在线段上。 Swift 或 Apple 的任何库中是否有内置方法?
我不介意转换为不同的类型,只要它是 Apple 代码的一部分(例如类似于 instead of performing complex calculations on double4x4 matrix, you can convert it to an SCNNode )。
我很快就想出了强力解决方案,但它既不优雅,也不准确(考虑到到处都是浮点比较):
extension CGPoint {
func isOnLineSegment(start: CGPoint, end: CGPoint) -> Bool {
func value(_ value: CGFloat, isBetween one: CGFloat, and two: CGFloat) -> Bool {
let a = [one, two].sorted()
return a[0] <= value && value <= a[1]
}
let slope = (end.y - start.y) / (end.x - start.x)
if slope.isInfinite {
let isOnLine = x.isNearlyEqual(to: start.x)
let isWithinYValues = value(y, isBetween: start.y, and: end.y)
return isOnLine && isWithinYValues
}
let isOnLine = y.isNearlyEqual(to: slope * (x - start.x) + start.y) // y = m * (x - x1) + y1
let isWithinXValues = value(x, isBetween: start.x, and: end.x)
return isOnLine && isWithinXValues
}
}
最佳答案
一种可能的方法是变换整个配置,使得线段的起点变换为原点,终点变换为点(1, 0)。这可以通过 CGAffineTransformation 来完成。然后,问题就简化为确定给定点是否位于 (0, 0) 和 (1,0) 之间的线段上。这是一个可能的实现:
extension CGPoint {
func isOnLineSegment(start: CGPoint, end: CGPoint) -> Bool {
// Transformation which maps (0,0) to start and (1, 0) to end:
let t = CGAffineTransform(a: end.x - start.x, b: end.y - start.y,
c: start.y - end.y, d: end.x - start.x,
tx: start.x, ty: start.y)
// Apply the inverse transformation to our point:
let q = self.applying(t.inverted())
// Check (with some tolerance) if q is on the segment from (0, 0) to (1, 0):
let eps = CGFloat.ulpOfOne.squareRoot()
return q.x > -eps && q.x < 1.0 + eps && q.y.magnitude < eps
}
}
作为容差,我选择 .ulpOfOne
的平方根(如建议的 here ),但您可以根据您的需要进行调整。
另一种方法是利用点 P 正好位于从 P1 到 P2 的线段上这一事实
| P - P1 | + | P - P2 | = | P1 - P2 |
其中| 。 |
表示(欧几里德)距离:
extension CGPoint {
func distance(to p: CGPoint) -> CGFloat {
return hypot(p.x - self.x, p.y - self.y)
}
func isOnLineSegment(start: CGPoint, end: CGPoint) -> Bool {
let eps = CGFloat.ulpOfOne.squareRoot()
return self.distance(to: start) + self.distance(to: end) <= start.distance(to: end) + eps
}
}
关于ios - 计算CGPoint是否在线段上?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70105593/