[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