Search code examples
swiftuibezierpath

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


enter image description here

I have a path like this (red middle line), which is created from

   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
    }

Because I have multiple Lines so I have to detect which one I'm touching with this

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

Problem is if my point1/point2 y is 450, and my touchPoint.y is 450.00001 then it won't be detected. There is only like 1% that I can't tap on the perfect spot.

Tested with this:

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

Is there anyway that I can detect the path within shapeLayer.lineWidth = 10?


Solution

  • this is more universal way

    works for any kinds of straight line,

    by calculating the distance from touch point to the destination line

    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)
        }
        
    }