I am drawing multiple NSBezierpaths, then I am trying to erase them so on MouseDown event How can I identify which bezierpath was hit? My bezierpath is custom subclass of NSObject.
1 Answers
Well, get the mouse click point from the NSEvent
in your mouseDown:
method with -locationInWindow
, convert the click point from window coordinates to your view's coordinates with -convertPoint:fromView:
, loop through the NSBezierPath
objects that you're drawing, from top to bottom, and call -containsPoint:
to test for a hit on each path. That works well if your bezier paths are closed, filled paths. If they are unclosed or stroked paths, you will need to drop down a level and use CGPathCreateCopyByStrokingPath()
, and perhaps also CGPathCreateCopyByDashingPath()
, to get the fill-style bezier path that describes the outline of the area that is filled when your original path is stroked (see How to get the path Quartz is using to stroke a NSBezierPath).
However, I'm not sure what you mean by "My bezierpath is custom subclass of NSObject"; if you are doing additional complicated things beyond just using NSBezierPath
, then you will need to describe what you're doing (and why), and post code for it.
-
If there are 10,000 bezierpaths,I need to loop through all of them and it will be very slow.What I am currently doing is creating a hitPoint like 'NSPoint hitPt = [self convertPoint:[inEvent locationInWindow] fromView:self];' and then creating a Rect from it and create another Rect from NSBezierpath bounds ,and I am checking if these two Rect intersect each other using (NSIntersectsRect(hitPointRect,bezierPathRect) ,If they do I am working only with that bezierPath.But still i have to loop through all bezierpaths.So I want to identify the bezierPath on mouseDown. – Sameer Jagtap May 20 '16 at 12:12
-
Your strategy sounds fine. You might cache the bounds of all your bezier paths, so that you're looping through an array of cached `NSRect`s instead of through the paths themselves. Looping through 10,000 `NSRect`s to do inside/outside checks should take very little time, and then if the number of potential "hits" is fairly small, doing the actual hit-test on each candidate bezier path shouldn't be a problem. If you're having to use `CGPathCreateCopyByStrokingPath()`, you might need to cache those converted paths, too, for speed, but you might not. – bhaller May 20 '16 at 13:20
-
Oh, and you probably want to use `NSPointInRect()` to do the inside/outside checks, rather than `NSIntersectsRect()`, unless I'm missing something. The hit point is a point, there's no reason to convert it to a rect. `NSPointInRect()` should be faster than `NSIntersectsRect()`. If view flipping gets in your way, `NSMouseInRect()` is specifically designed for hit-testing in views that can be flipped. – bhaller May 20 '16 at 13:22
-
If this sort of simple hit-testing is too slow even with caching of bounds rects and converted paths, then you will need to get into some kind of complicated spatial subdivision algorithm like keeping a [quadtree](https://en.wikipedia.org/wiki/Quadtree) with linked lists of the objects contained within each quad. That gets very complicated very fast, though, and Cocoa will provide little help for you in doing it. I would be very surprised if it was necessary with only 10,000 paths. Computers are fast. :-> – bhaller May 20 '16 at 13:25