CGContextRotateCTM and collision

Member
Posts: 96
Joined: 2011.07
Post: #1
Let's say we have a 2D box drawn with Quartz.

Then I rotate it using CGContextRotateCTM.

How do I check if I click inside the box?

respect,
pk

iFrog is coming.
Quote this message in a reply
Member
Posts: 96
Joined: 2011.07
Post: #2
I think I know how I'll do it in theory: make an NSPoint from the current mouse coordinates. Then translate the point (CGAffineTransform looks promising) and then there's another promising function called NSPointInRect but let's see.

Another one is rotate the object corners back to zero angle together with the mouse points around the center of the box and then check if the translated mouse is inside the unrotated box. That's it.

So basically if the box is rotated 40 degrees I rotate the mouse -40 degrees around the box center and compare that to the unrotated box coordinates. Not bad - I think I can handle that...

respect,
pk

iFrog is coming.
Quote this message in a reply
Member
Posts: 96
Joined: 2011.07
Post: #3
Success!!
----
NSArray *components=[[LevelCanvasModel sharedModel] getLevelComponents];

LevelComponent *lc;

NSPoint mouseLocation=[self convertPoint:[theEvent locationInWindow] fromView:nil];

NSAffineTransform *a=[[NSAffineTransform alloc]init];

NSPoint mouseLocation2;

for (lc in components) {

//THE TRANSFORM PART:

NSPoint origin=lc.destRect.origin;
NSSize halfSize=lc.destRect.size;
halfSize.width*=0.5;
halfSize.height*=0.5;

[a translateXBy:origin.x+halfSize.width yBy:origin.y+halfSize.height];
[a rotateByDegrees:lc.angle];
[a translateXBy:-origin.x-halfSize.width yBy:-origin.y-halfSize.height];

mouseLocation2=[a transformPoint:mouseLocation];

//NOW I CAN TEST
if (mouseLocation2.x>lc.destRect.origin.x&&mouseLocation2.x<lc.destRect.origin.x+lc.destRect.size.width) {
if (mouseLocation2.y>lc.destRect.origin.y&&mouseLocation2.y<lc.destRect.origin.y+lc.destRect.size.height) {

// ITS IN THE RECT

....

}}

respect,
pk

iFrog is coming.
Quote this message in a reply
⌘-R in Chief
Posts: 1,237
Joined: 2002.05
Post: #4
Or…

Code:
NSBezierPath * path = [NSBezierPath bezierPathWithRect:rect];
[path transformUsingAffineTransform:xfm];


// Drawing is:
[path fill];


// Hit testing is:
[path containsPoint:mousePoint];
Quote this message in a reply
Member
Posts: 96
Joined: 2011.07
Post: #5
(Jul 21, 2011 06:52 PM)SethWillits Wrote:  Or…

Code:
NSBezierPath * path = [NSBezierPath bezierPathWithRect:rect];
[path transformUsingAffineTransform:xfm];


// Drawing is:
[path fill];


// Hit testing is:
[path containsPoint:mousePoint];

Wow! I'll tell you what I'm drawing and maybe we can simplify the whole thing.

Basically, what I do is the following:

I have a collection of object coords with its rotation on a sprite sheet stored into a class called LevelComponent. This is how I draw them:

Code:
LevelComponent *lc;
LevelModel *lm=gameModel.currentHouse.currentLevel;

NSMutableDictionary *objects=[lm objects];
    
    for (NSString *key in objects) {
        
        [NSGraphicsContext saveGraphicsState];
        
        lc=[[[[gameModel currentHouse] currentLevel] objects] valueForKey:key];
        
        CGContextTranslateCTM([[NSGraphicsContext currentContext] graphicsPort], lc.destRect.origin.x, lc.destRect.origin.y);
        CGContextTranslateCTM([[NSGraphicsContext currentContext] graphicsPort], lc.destRect.size.width*0.5, lc.destRect.size.height*0.5);
        
        CGContextRotateCTM([[NSGraphicsContext currentContext] graphicsPort], -lc.angle*3.1415/180);
        CGContextTranslateCTM([[NSGraphicsContext currentContext] graphicsPort], -lc.destRect.size.width*0.5, -lc.destRect.size.height*0.5);
        
        CGRect target=lc.destRect;
        
        target.origin.x=0;
        target.origin.y=0;
        
        [mainSheet drawInRect:target fromRect:lc.rect operation:NSCompositeSourceOver fraction:1.0];
        
        [NSGraphicsContext restoreGraphicsState];
    }

Now I want to drag them around with the mouse (even when they are rotated). I've cleaned up the code from yesterday a little:

Code:
-(void)mouseDown:(NSEvent *)theEvent
{
    NSArray *components=[[LevelCanvasModel sharedModel] getLevelComponents];
    
    LevelComponent *lc;
    
    NSPoint mouseLocation=[self convertPoint:[theEvent locationInWindow] fromView:nil];
    
    NSAffineTransform *a=[[NSAffineTransform alloc]init];
    
    NSPoint mouseLocation2;
    for (lc in components) {
        
        NSPoint origin=lc.destRect.origin;
        NSSize halfSize=lc.destRect.size;
        halfSize.width*=0.5;
        halfSize.height*=0.5;
        
        [a translateXBy:origin.x+halfSize.width yBy:origin.y+halfSize.height];
        [a rotateByDegrees:lc.angle];
        [a translateXBy:-origin.x-halfSize.width yBy:-origin.y-halfSize.height];
        
        mouseLocation2=[a transformPoint:mouseLocation];
        
        if (NSPointInRect(mouseLocation2, lc.destRect)){
            
            [controller setRotation:lc.angle];
            [controller setLength:lc.length];
            
            self.currentSelection=lc;
            
            lastDragLocation=lc.destRect.origin;
            
            lastDragLocation.x-=mouseLocation.x;
            lastDragLocation.y-=mouseLocation.y;
            
            dragging=YES;
            
            [[controller currentSelectionLabel] setStringValue:lc.name];
            
        }
    }
    [a release];
}
whoops I have to go! I'll think if I can simplify the check dramatically with your bezier path solution....

respect,
pk

iFrog is coming.
Quote this message in a reply
Member
Posts: 96
Joined: 2011.07
Post: #6
back... I think I'll leave my code as it is for the moment because I have deadline to catch. However, I'm a newbie in Quartz and I definitely want to learn more about how to use NSBezierPath. Thanks.

respect,
pk

iFrog is coming.
Quote this message in a reply
Member
Posts: 96
Joined: 2011.07
Post: #7
(Jul 21, 2011 06:52 PM)SethWillits Wrote:  Or…

Code:
NSBezierPath * path = [NSBezierPath bezierPathWithRect:rect];
[path transformUsingAffineTransform:xfm];


// Drawing is:
[path fill];


// Hit testing is:
[path containsPoint:mousePoint];

...or UIBezierPath on the iOS! You know, this is really handy even if you draw with OpenGL.

respect,
pk

iFrog is coming.
Quote this message in a reply
Post Reply