【问题标题】:How to get the distance to a CGPath for hit-testing?如何获得到 CGPath 的距离以进行命中测试?
【发布时间】:2013-10-19 06:53:31
【问题描述】:

我有一个开放的 CGPath/UIBezierPath,我想检测用户是否触摸它,即一个点是否在距离路径一定距离内。路径是开放的(即一条线/曲线,而不是一个形状)。它可以包含直线和曲线元素。如何获取到路径的距离以进行命中测试?

【问题讨论】:

    标签: objective-c core-graphics cgpath


    【解决方案1】:

    CGPath/UIBezierPath 似乎都没有这样做的功能。编辑:根据@nielsbot 的建议,您可以使用CGPathApply(…) 编写自定义实现。不过,计算到弯曲部分的距离并不是那么简单。

    但是,我找到了一种巧妙的方法来实现我最初的目标,即命中测试路径:CGPathCreateCopyByStrokingPath(…)

    - (BOOL)isPoint:(CGPoint)p withinDistance:(CGFloat)distance ofPath:(CGPathRef)path
    {
        CGPathRef hitPath = CGPathCreateCopyByStrokingPath(path, NULL, distance*2, kCGLineCapRound, kCGLineJoinRound, 0);
        BOOL isWithinDistance = CGPathContainsPoint(hitPath, NULL, p, false);
        CGPathRelease(hitPath);
        return isWithinDistance;
    }
    

    为了获得更好的性能,您可以缓存 hitPath。通过使用CGPathAddPath(…)将原始路径添加到hitPath,也可以用于封闭路径

    【讨论】:

    • 您可以遍历路径中的所有绘制命令(移动、直线到、曲线到)。那不会让您实现自己的距离路径功能吗?
    • 看起来 CGPathApply() 可能是您需要的。
    • @nielsbot:谢谢,这是一个有用的功能。然而,计算到曲线的距离有些复杂(需要数值迭代)。答案已更新。
    • 是以米为单位的距离?
    • @SjoerdPerfors 它是原始路径所在的任何单位(因为 CGPath 本身是无单位的),所以这取决于你从哪里得到它。
    【解决方案2】:

    对于 Swift 3.0:

    final func isPoint(point: CGPoint, withinDistance distance: CGFloat, ofPath path: CGPath) -> Bool {
    
        if let hitPath = CGPath( __byStroking: path,
                                 transform: nil,
                                 lineWidth: distance,
                                 lineCap: CGLineCap.round,
                                 lineJoin: CGLineJoin.miter,
                                 miterLimit: 0) {
    
            let isWithinDistance = hitPath.contains(point)
            return isWithinDistance
        }
        return false
    }
    

    使用:

    let inside = self.isPoint(point: location, withinDistance: 4, ofPath: myPath!)
    if inside{...
    

    当然,正如 Patrick 所指出的,最好缓存 hitPath,而不是每次都创建它。如果您有 UIBezierPath,只需:

     let inside = self.isPoint(point: location, withinDistance: 4, ofPath: myUIPath.cgPath!)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多