• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
re: hit detection with NSBezierPath
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

re: hit detection with NSBezierPath


  • Subject: re: hit detection with NSBezierPath
  • From: "Michael B. Johnson" <email@hidden>
  • Date: Fri, 02 Aug 2002 20:24:15 -0700

<I thought I sent this out yesterday, but my mailer held it for some reason...>


for those playing at home, here's a recap of what I'm trying to do:

-- the problem -- given a view that has some (potentially large) number of NSBezierPaths containing some (potentially large) number of line segments of varying width (put down with a Wacom pen, say) how can you most quickly determine which particular mark you're over, taking into account the visible mark (i.e. not just the bound, not just the control hull, including the corners, width, and end points).

The simple reason I wanted to do this is because I wanted to give a user immediate feedback when they drag a color swatch over the view; changing the color of the stroke they're over as they drag over so they can see what it will look like before they drop. It's also obviously useful to do picking for selection.

I got a few suggestions, including a generous offer of code to calculate line intersections. But I decided to go with a more empirical approach.

- the answer I'm using --

I just finished up coding up an alternate way, which seems to work great, and is very fast, and was pretty obvious once a few people convinced me that there wasn't something obvious I was missing in the AppKit, so I thought I'd share. It's basically the same trick you do in OpenGL when you want to see what part of a piece of geometry you're over.

The trick is to assign a unique color to each thing you care about (or in my case, a group of NSBezierPath objects), render all of them in an offscreen image, then look at the pixel value and map that pixel value back to the geometry you care about. This has the advantage that your hit detection algorithm is using the same wonderful/buggy code that the user is seeing the result of, so you don't have to get in a fight about whose line caps are right :-)

A few obvious/not so obvious things:

- Make sure to turn off antialiasing in the image you draw into, otherwise your pixel value won't map correctly on the edges. It should also be faster.
- use only opaque colors, so that you get correct values for a single piece of geometry.
- You also may want to separate your tags out a bit, so you don't get bit by rounding when going back and forth from ints and floats.
- cache the image once you make it, and make sure to dirty it when you resize or add new geometry, and recache lazily
- after you make your NSImage that you've drawn into, you may need to add an NSBitmapImageRepresentation to it so you can get the pixels.


My code looks like this:

NSBitmapImageRep* rep = nil;
NSArray* repArray = [_hitTestImage representations];
int i;
for (i = 0; i < [repArray count]; ++i) {
NSObject *imageRepresentation = [repArray objectAtIndex:i];
if ([imageRepresentation isKindOfClass:[NSBitmapImageRep class]]) {
rep = (NSBitmapImageRep*)imageRepresentation;
}
}
if (!rep) {
NSSize size = [_hitTestImage size];
NSRect rect = NSMakeRect(0, 0, size.width, size.height);
[_hitTestImage lockFocus];
rep = [[[NSBitmapImageRep alloc] initWithFocusedViewRect:rect] autorelease];
[_hitTestImage unlockFocus];
[_hitTestImage addRepresentation:rep];
}
if (rep) {
// get the pixel value and map back to your geometry

I just tried this on my PowerBook with a 1K x 1K view with a bunch of strokes in it, and I could very interactively drag a color swatch over the view and see the underlying strokes change color back and forth as I moved over them. You get a hit when you enter the view the very first time as the image gets cached, but after that it's very low cost.

Hope this is useful.



--> Michael B. Johnson, Ph.D. -- email@hidden
--> Studio Tools, Pixar Animation Studios
--> http://xenia.media.mit.edu/~wave
_______________________________________________
cocoa-dev mailing list | email@hidden
Help/Unsubscribe/Archives: http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored.

  • Follow-Ups:
    • Re: hit detection with NSBezierPath... And more....
      • From: Marco Binder <email@hidden>
  • Prev by Date: Re: InfoPlist.strings
  • Next by Date: the bloody Omni frameworks
  • Previous by thread: hit detection with NSBezierPath
  • Next by thread: Re: hit detection with NSBezierPath... And more....
  • Index(es):
    • Date
    • Thread