You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何判断CGPoint是否在线段上?Swift有无苹果官方内置方法支持?

苹果官方没有提供直接判断CGPoint是否落在指定线段上的一步调用API,但可以通过官方框架的现有能力组合实现,完全不需要手动处理浮点数比较、边界场景兼容等问题,以下是两种主流的官方实现方案:

方案1:使用UIBezierPath/CGPath实现(兼容性最好、容差可控)

基于CoreGraphics框架的路径命中检测能力实现,所有几何计算逻辑都由官方底层处理,还可以自定义判断容差适配不同场景:

import UIKit // macOS项目替换为AppKit,使用NSBezierPath逻辑一致

extension CGPoint {
    func isOnLineSegment(start: CGPoint, end: CGPoint, tolerance: CGFloat = 1.0) -> Bool {
        // 构造线段路径
        let linePath = UIBezierPath()
        linePath.move(to: start)
        linePath.addLine(to: end)
        // 生成指定线宽的描边路径,线宽对应判断容差
        let strokedPath = linePath.cgPath.copy(
            strokingWithWidth: tolerance,
            lineCap: .round,
            lineJoin: .round,
            miterLimit: 0
        )
        // 官方提供的路径命中检测
        return strokedPath.contains(self)
    }
}
  • 无需手动处理竖线除零、浮点数精度对齐等边界问题,运算精度由官方保障
  • 可通过tolerance参数灵活调整容差,比如交互场景可将容差设为2-3,方便用户点击细线段
  • 兼容iOS 10+/macOS 10.12+,覆盖绝大多数现网设备
方案2:使用SIMD向量运算实现(性能更高、适合批量计算)

如果是高频调用场景(比如游戏、图形渲染每帧做大量判断),可以用苹果官方SIMD库的向量运算实现,性能远高于路径检测方案:

import simd

extension CGPoint {
    func isOnLineSegment(start: CGPoint, end: CGPoint, epsilon: CGFloat = 1e-5) -> Bool {
        let pointVec = SIMD2<Float>(Float(x), Float(y))
        let startVec = SIMD2<Float>(Float(start.x), Float(start.y))
        let endVec = SIMD2<Float>(Float(end.x), Float(end.y))
        
        // 官方SIMD叉乘计算,判断点是否和线段共线
        let crossValue = cross(endVec - startVec, pointVec - startVec)
        guard abs(crossValue) <= Float(epsilon) else { return false }
        
        // 官方SIMD点乘计算,判断点是否在线段区间范围内
        let dotValue = dot(pointVec - startVec, pointVec - endVec)
        return dotValue <= Float(epsilon)
    }
}
  • 纯CPU向量指令运算,性能是路径检测方案的数倍,适合批量计算场景
  • 完全规避手动计算斜率的除零、精度丢失问题,运算逻辑经过官方优化
  • 兼容所有支持SIMD的苹果系统,覆盖所有现役设备

内容的提问来源于stack exchange,提问作者Senseful

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 11:06:04