1

I am trying to determine if a UIBezierPath that I draw intersects with another one.

if path.containsPoint(touchPoint){
       println("captured \(touchPoint) ")              
}

However, containsPoint(CGPoint:) doesn't work for me, because it returns true if

the point is considered to be within the path’s enclosed area or false if it is not.

Just to provide a graphical example, this returns true (I'm drawing the dashed path):

So the question is: how can I check if my touchPoint belongs to a UIBezierPath, in the sense that it hits a specific point of that path?

Thanks in advance

ABakerSmith
  • 22,759
  • 9
  • 68
  • 78
diningphil
  • 416
  • 5
  • 18
  • 1
    There is (as far as I know) no built-in function that checks if two general bezier paths intersect. If the path consists only of line segments then you can check each segment (a very simple implementation is here: http://stackoverflow.com/questions/13999249/uibezierpath-intersect). For arbitrary cubic bezier paths this becomes non-trivial maths :) – Martin R Apr 26 '15 at 10:46
  • What do you think about maintaining a list of points for every path and do a linear scan every time i need to do the checking? In my project i have many arbitrary paths, scan every path during every touchesMove method seems expensive, but i'm just asking :) – diningphil Apr 26 '15 at 10:54
  • So you would approximate the path by a sequence of line segments? If each path is split into N segments then you have N^2 comparisons, so the naive method could be slow (this could be improved by sorting the segments first). – I am sure that this has already been implemented somewhere, and I remember to have seen it. But I have no practical experience myself with this topic. Try to search for "bezier curve intersection". – Martin R Apr 26 '15 at 11:01
  • Instead, considering only the last point of the path that i'm drawing, i need N comparisons for each path, if i'm not wrong, and in my case it could work. Thank you, i'll keep searching before implementing. – diningphil Apr 26 '15 at 11:04

2 Answers2

1

If it is just a touch point that you want to determine lies within the stroke of a bezier path or not you can use CGPathCreateCopyByStrokingPath to create a closed path version of your original open path you are trying to hit test. Then with that newly created closed path you can use the containsPoint method to do the check.

The technique is described in this blog post in detail. http://oleb.net/blog/2012/02/cgpath-hit-testing/

You may need to expand this width of the copied stroke to allow for fat fingers. In the blog post, for example, he makes the hit test path at least 35 points.

Ray Fix
  • 5,575
  • 3
  • 28
  • 30
0

I'm a bit late to this question, but I had to solve something similar recently and this might help for others who stumble in here:

Is point close to the line?

I've just recently open sourced ClippingBezier which may help. It includes a category method on UIBezierPath to determine how close an input point is to the path:

CGPoint pointOnPath = [path closestPointOnPathTo:touchPoint];
if(distance(pointOnPath, touchPoint) < 30){
   // point is close to path
}

This gives you a solution that's similar to Ray's answer. I don't know the performance of CGPathCreateCopyByStrokingPath, but if you need to do this realtime with the gesture, you might want to compare to ClippingBezier as well - it's designed for this sort of realtime use case.

Is point inside minimum bounding box?

Instead, if you want to determine if the point is within the minimum bounding box of the Bezier path, not just 'close' to the path, then that's a bit trickier.

The UIBezierPath's bounds property isn't necessarily the minimum bounding box, it's just a bounding box. To find the minimum, I think you'd have to:

  1. Incrementally rotate the path around its center, checking for the smallest bounds through each degree of 90 degrees of rotation
  2. Once you've found the smallest rotation, then apply that same transform to the touchPoint
  3. Then check that transformed touchPoint to the transformed path's bounds

This won't get you the exact minimum bounding box, but it'll be close enough in practice. To get the exact minimum bounding box, it'd take a lot more math, as described in this SO answer.

Community
  • 1
  • 1
adam.wulf
  • 2,149
  • 20
  • 27