iDevGames Forums
CGContextRotateCTM and collision - Printable Version

+- iDevGames Forums (http://www.idevgames.com/forums)
+-- Forum: Development Zone (/forum-3.html)
+--- Forum: Graphics & Audio Programming (/forum-9.html)
+--- Thread: CGContextRotateCTM and collision (/thread-9207.html)



CGContextRotateCTM and collision - ipeku - Jul 21, 2011 03:46 PM

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?


RE: CGContextRotateCTM and collision - ipeku - Jul 21, 2011 05:48 PM

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...


RE: CGContextRotateCTM and collision - ipeku - Jul 21, 2011 06:46 PM

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

....

}}


RE: CGContextRotateCTM and collision - SethWillits - Jul 21, 2011 06:52 PM

Or…

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


// Drawing is:
[path fill];


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



RE: CGContextRotateCTM and collision - ipeku - Jul 22, 2011 08:15 AM

(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....


RE: CGContextRotateCTM and collision - ipeku - Jul 22, 2011 10:06 AM

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.


RE: CGContextRotateCTM and collision - ipeku - Oct 31, 2011 07:37 AM

(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.