UIBelzierpath - path.contains(userTouchPoint) 只能检测 userTouchPoint.y 是否恰好位于路径 Y 位置

UIBelzierpath - path.contains(userTouchPoint) can only detect if userTouchPoint.y is exactly at path Y position

我有一个这样的路径(红色中间线),它是从

创建的
   func drawALine(point1:CGPoint,point2:CGPoint)->CAShapeLayer{
        let path = UIBezierPath()
        path.move(to: point1)
        path.addLine(to: point2)
        let shapeLayer = CAShapeLayer()
        shapeLayer.path = path.cgPath
        shapeLayer.strokeColor = UIColor.red.cgColor
        shapeLayer.lineWidth = 10
        self.layer.addSublayer(shapeLayer)
        return shapeLayer
    }

因为我有多条线,所以我必须检测我接触的是哪一条线

for each in RulerModelArray{
            if (!(each.midPath.path?.contains(touchPoint))!) {
                print("not contain")
            } else {
                print("contained",each.ID)
            }
        }

问题是如果我的 point1/point2 y 是 450,而我的 touchPoint.y 是 450.00001 那么它就不会被检测到。只有大约 1% 的地方我无法在完美的地方点击。

用这个测试:

let testPoint:CGPoint = CGPoint(x: touchPoint.x, y: touchPoint.y + 0.0001 )
        for each in RulerModelArray{
            if (!(each.midPath.contains(testPoint))) {
                print("not contain")
            } else {
                print("contained",each.ID)
            }
        }
///always return not contain

我能检测到 shapeLayer.lineWidth = 10 内的路径吗?

你可以用这个

检查 CGPoint 是否在 UIBezierPath 的范围内

适用于水平线,因为水平线的尺寸高度为 0

extension UIBezierPath{
    
    func hasForHorizontalLine(pt point: CGPoint) -> Bool{
        
        let bezierRect = bounds
        let origin = bezierRect.origin
        let size = bezierRect.size

        if origin.x <= point.x , origin.x + size.width >= point.x, origin.y - lineWidth * 0.5 <= point.y , origin.y + lineWidth * 0.5 >= point.y{
            return true
        }
        else{
            return false
        }
    }
    
}

这种方式更通用

适用于任何类型的直线,

通过计算触摸点到目标线的距离

extension CGPoint{
    
    // tolerance, should by the lineWidth of a UIBezierPath

    func contained(byStraightLine start: CGPoint,to end: CGPoint, tolerance width: CGFloat) -> Bool{

        return distance(fromLine: start, to: end) <= width * 0.5
    }
    
    
    
    func distance(fromLine start: CGPoint,to end: CGPoint) -> CGFloat{
        
        let a = end.y - start.y
        let b = start.x - end.x
        
        let c = (start.y - end.y) * start.x + ( end.x - start.x ) * start.y
        return abs(a * x + b * y + c)/sqrt(a*a + b*b)
    }
    
}