[Drawkit] Hit testing at high scale factor

Brad Larson larson at sonoplot.com
Mon Jun 30 17:05:52 PDT 2008


On Jun 28, 2008, at 12:59 AM, Graham Cox wrote:

>
>>
>> On 28 Jun 2008, at 8:34 am, Brad Larson wrote:
>>
>>> I've been experiencing a glitch with hit testing that I can't seem  
>>> to track down and thought I'd check to see if there was an obvious  
>>> solution to it.  What I'm experiencing is that when I click to the  
>>> up and left of an object, I select it, even though I'm a ways away  
>>> from the object.  This happens in a square starting a the object  
>>> and going up and to the left.  It does not occur below or to the  
>>> right of the object.  From logging positions, it looks like the  
>>> hit testing is marking a hit in a region up to 1.0 points to the  
>>> left and up of the object.  That is, any click within that region  
>>> is a hit on the object.  At the high scale factors (~500) we use  
>>> for our micron units, this can be a significant distance and  
>>> really complicate object selection.
>
>
> OK, I found the main problem. In DKDrawableObject, -pointHitsPath:  
> is using a test rect of size {1,1}. At very high zooms that's way  
> too large, resulting in a "point" becoming quite a substantial rect  
> that is likely to extend significantly to the right and below the  
> actual point being tested. That's why clicking above and to the left  
> of the object was counting as a hit.
>
> The fix is easy:
>
> - (BOOL)	pointHitsPath:(NSPoint) p
> {
> 	if( NSPointInRect( p, [self bounds]))
> 	{
> 		NSRect	pr = NSMakeRect( p.x, p.y, 1e-4, 1e-4 );
> 		return [self rectHitsPath:pr];
> 	}
> 	
> 	return NO;
> }
>
> Basically the size of the test rect is made very small, so the  
> precision is much greater. I'm not sure how small this should be but  
> the 1e-4 seems pretty precise and still works OK at the macro scale.  
> Going to 1e-6 stops working, so the optimum is probably somewhere  
> between the two. I suppose also to be really pedantic the test rect  
> should be centred on the point not dangling below/right.
>

That solves the problem, and seems to work well even at high scale  
factors.  Thanks.  The only weirdness with this is that for my custom  
point subclass I'm getting "_segmentIndexForElementIndex:: index (4)  
beyond bounds (2)" messages on the console when I try to drag the  
point, which no longer causes the point to move.  This probably has  
something to do with the weird path I use behind the element, so I'll  
see if I can find what's triggering that.

In terms of the overlarge bounds that were being returned, I saw this  
in DKDrawablePath:

- (NSRect)			bounds
{
	NSRect	r = NSInsetRect( [[self renderingPath] controlPointBounds],  
-3, -3 );

which would make the bounds wider and taller by 6.0 points, the size  
difference I'm seeing.  What does this provide cushioning for in the  
path: the knobs? Later on in the bounds method, it looks like the  
width of the style is taken into account.  In any case, it's an  
absolute value, not a scaled one.  Converting this to be

	NSRect	r = [[self renderingPath] controlPointBounds];

fixes the selection rectangle issues that I was seeing with my custom  
point subclass of DKDrawablePath, as well as the DKDrawablePath lines  
I'm using.


______________________
Brad Larson
SonoPlot, Inc.
3030 Laura Lane, Suite 120
Middleton, WI 53562





More information about the Drawkit mailing list