Re: NSBezierPath containsPoint question
Re: NSBezierPath containsPoint question
- Subject: Re: NSBezierPath containsPoint question
- From: p3consulting <email@hidden>
- Date: Tue, 27 Apr 2004 10:22:39 +0200
The example at cocoadev is interesting but soon or later you may need=20
to do hit testing for other things than NSBezierPath=85
I am currently experimenting the following and currently have=20
satisfying results, even if optimization is still to be done.
(the classic draw in a small bitmap and see if pixels have been changed=20=
after drawing each graphic object)
assuming you have a custom view where you do your drawing,
add the following variables to your sub-NSView class:
NSBitmapImageRep *fHitBitmap ;
CGContextRef fBitmapContext ;
NSImage *fHitImage =
;
unsigned *fHitPixels =
;
unsigned fHitNPixels =
;
add the following to the
- (id)initWithFrame:(NSRect)frameRect
method:
fHitBitmap =3D [[NSBitmapImageRep alloc] =
initWithBitmapDataPlanes:nil=20
pixelsWide:5 pixelsHigh:5 bitsPerSample:8 samplesPerPixel:4=20
hasAlpha:YES isPlanar:NO colorSpaceName:NSDeviceRGBColorSpace=20
bytesPerRow:0 bitsPerPixel:0];
fHitPixels =3D (unsigned *)[fHitBitmap bitmapData] =
;
fBitmapContext =3D CGBitmapContextCreate ( fHitPixels ,
=
5, 5,
=
8,
=
[fHitBitmap bytesPerRow],
=
CGColorSpaceCreateDeviceRGB(),
=
kCGImageAlphaPremultipliedLast
=
);
fHitNPixels =3D [fHitBitmap bytesPerRow] / =
sizeof(unsigned) ;
fHitImage =3D [[NSImage alloc] =
initWithSize:NSMakeSize(5.0, 5.0)] ;
(5 by 5 is arbitrary for my testing purpose you should test for your=20
purpose, make a parameter out of it, maybe make it a variable according=20=
to zoom level, etc.)
in the
- (void)dealloc
add
[fHitBitmap release] ;
[fHitImage release] ;
add the function (be warned: this is an undocumented trick...)
void setCGContextInCurrentNSGraphicsContext (CGContextRef newContext)
{
((graphicsContextInstance) [NSGraphicsContext=20
currentContext])->context =3D newContext;
}
add the following public methods:
- (void)clearHitPixels
{
int i ;
=09
for(i=3D0;i<fHitNPixels;i++)
fHitPixels[i] =3D 0 ;
}
// transparent pixels ([NSColor clearColor] =3D=3D 0x00000000) will =
never=20
be hit...
// usually what everybody expect...
- (BOOL)testHitPixels
{
int i ;
=09
for(i=3D0;i<fHitNPixels;i++)
if (fHitPixels[i])
return YES ;
=09
return NO ;
}
// SkGraphicItem, SkDocument are of course app dependant
// but what is relevant here is the logic of operations
- (SkGraphicItem *)graphicUnderPoint:(NSPoint)inPoint
{
NSEnumerator *graphics =3D [(SkDocument *)[ibWindowController=20
document] editItemsFrontToBack];
// we draw back to front but we test hit front to back
SkGraphicItem * curGraphic =3D nil ;
CGContextRef savedCGContext ;
=09
[fHitImage lockFocus] ;
=09
savedCGContext =3D [[NSGraphicsContext currentContext] =
graphicsPort];
setCGContextInCurrentNSGraphicsContext (fBitmapContext);
[[NSGraphicsContext currentContext] setShouldAntialias:NO] ; =
// we=20
should be able to move this one at init time...
=09
CGContextTranslateCTM(fBitmapContext, -(inPoint.x - 2.5), =
-(inPoint.y=20
- 2.5));
=09
NSRect frame =3D NSMakeRect(0.0, 0.0, 5.0, 5.0) ;=09
SkGraphicItem *gItem ;
=09
=09
while ((gItem =3D [graphics nextObject]) && (curGraphic =3D=3D =
nil)) { =09
[self clearHitPixels] ;
=09
if ((curGraphic =3D [gItem drawRect:frame inView:self=20
mode:EDrawingMode_Select]) !=3D nil)
break ;
// instead of break you could also draw every elements =
adding the=20
hit ones to a list
// and have a UI to help user select the right one...
// in that case graphicUnderPoint should return a list =
instead of=20
just one item
}
=09
CGContextTranslateCTM(fBitmapContext, +(inPoint.x - 2.5), =
+(inPoint.y=20
- 2.5));
setCGContextInCurrentNSGraphicsContext (savedCGContext);
=09
[fHitImage unlockFocus] ;
=09
return curGraphic;
}
- (void)mouseDown:(NSEvent *)inEvent
{
if ([inEvent clickCount] > 1) {
NSPoint curPoint =3D [self convertPoint:[inEvent =
locationInWindow]=20
fromView:nil];
SkGraphicItem *item =3D [self =
graphicUnderPoint:curPoint];
if (item) {
[item startEditing:inEvent inView:self] ;
return ;
}
}
=09
[self selectAndTrackMouseWithEvent:inEvent] ;
}
- (void)selectAndTrackMouseWithEvent:(NSEvent *)inEvent
{
NSPoint curPoint;
SkGraphicItem * item =3D nil;
BOOL extending =3D (([inEvent modifierFlags] & NSShiftKeyMask) ? =
YES=20
: NO);
curPoint =3D [self convertPoint:[inEvent locationInWindow]=20
fromView:nil];
item =3D [self graphicUnderPoint:curPoint];
=09
BOOL selected =3D (item)? [item isSelected]:NO;
=09
if (!extending && !selected) {
[self clearSelection] ;
}
=09
etc=85 (see the Apple Sketch example=85)
A drawRect:inView:mode example (from the SkPath (bezier) class):
// in general returns self in hit mode when hit is detected
// but could return any other SkGraphicItem (e.g. a SkGroup class will=20=
not return self but a group member...)
- (SkGraphicItem *)drawRect:(NSRect)inRect inView:(SkView *)inView=20
mode:(SkDrawingMode)inMode
{
NSBezierPath *b =3D [[inView scaledCTM] =
transformBezierPath:[self=20
bezierPath]] ;
=09
if (fClosed) {
[[self backColor] setFill] ;
[b fill] ;
}
=09
=09
[[self foreColor] setStroke] ;
if (inMode =3D=3D EDrawingMode_Select) {=09
// ensure a minimum width when testing for hit
float w =3D [b lineWidth] ;
=09
[b setLineWidth:min(3.0,w)] ; // 3.0 is arbitrary, =
adapt to your=20
needs, make a #define or a "global" out of it
}
[b stroke] ;
=09
return (EDrawingMode_Select =3D=3D inMode)? ([inView =
testHitPixels]?=20
(self):(nil)):(self) ;
}
Pascal Pochet
email@hidden
Le avr. 27, 2004, =E0 06:18, Allan Odgaard a =E9crit :
>
On 27. Apr 2004, at 5:54, Dominic Edward Feira wrote:
>
>
> I am trying to determine wether or not I am clicking on a =
line...below
>
> is a snippet of code. Shouldn't tempBool equal YES? [...]
>
>
No, it tells if the point is contained by the (closed) path formed by=20=
>
multiple lines in the NSBezierPath.
>
>
I have not tested it, but someone did write the functionality which=20
>
you are seeking:
>
http://cocoadev.com/index.pl?HitDetection
>
>
>
>
>
>
>
--=20
>
et al: used as an abbreviation when referring to a number of people,=20=
>
for
>
example: "It has been improved by Knuth et al." [syn: and others, et=20=
>
alii]
>
>
etc: continuing in the same way [syn: and so forth, and so on, et=20
>
cetera].
>
_______________________________________________
>
cocoa-dev mailing list | email@hidden
>
Help/Unsubscribe/Archives:=20
>
http://www.lists.apple.com/mailman/listinfo/cocoa-dev
>
Do not post admin requests to the list. They will be ignored.
[demime 0.98b removed an attachment of type application/pkcs7-signature which had a name of smime.p7s]
_______________________________________________
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.