Search code examples
iosobjective-ccgaffinetransform

Manually rotate the coordinate system for landscape mode left


I am aware that the upper left corner of the screen (assuming phone is held in landscape left) is (0,0). However, if I wanted my (0,0) point to be the bottom left corner instead of the upper left corner, how would I do it?

I'm trying to draw objects using OpenGL in the specified location I am currently touching on the screen but the y value is being drawn on the wrong side of the screen. Heres a picture example of the issue if it helps. Note that the whited out spot is where I 'touch' the screen and the purple stuff is the particle system I am drawing using OpenGL.

https://www.dropbox.com/s/n2lhzfdbp4audi2/iOS%20Simulator%20Screen%20shot%20Apr%2023%2C%202013%206.25.49%20PM.png

https://www.dropbox.com/s/foueopvlgfu03vs/iOS%20Simulator%20Screen%20shot%20Apr%2023%2C%202013%206.25.53%20PM.png

I set my supported interface like this:

- (NSUInteger)application:(UIApplication*)application supportedInterfaceOrientationsForWindow:(UIWindow*)window
{
    return UIInterfaceOrientationMaskAllButUpsideDown;
}

- (NSUInteger)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskLandscapeLeft;
}

In my drawFrame method:

glViewport(0, 0, 480, 320);

glMatrixMode(GL_PROJECTION);
glLoadIdentity();

glOrthof(0.0f, 480, 0.0f, 320, -100.0f, 100.0f);

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

//render the particles being drawn, etc

In my touchesBegan method:

UITouch *touch = [[event allTouches] anyObject];
CGPoint location = [touch locationInView:touch.view];

if (pe.active != YES)
{
    pe.active = YES;

    NSLog(@"x: %f y: %f", location.x, location.y);

    pe.sourcePosition = Vector2fMake(location.x, location.y);
}

I then tried to manually rotate the coordinate system 90 degrees by doing this in my viewWillAppear method:

self.view.transform = CGAffineTransformIdentity;
self.view.transform = CGAffineTransformMakeRotation((M_PI * (-90) / 180.0));
self.view.bounds = CGRectMake(0.0, 0.0, 480, 320);

Specifying CGAffineTransformMakeRotation call with -90 degrees as shown above should alter the coordinate system but it doesn't.

Any help is greatly appreciated.


Solution

  • In general, you should avoid setting a VC's view frame, bounds, and transform. These are automatically set by UIKit to handle things like rotation and resizing (e.g. for the in-call status bar).

    There are two simple fixes:

    • Transform the touch points (location.x, height-location.y)
    • Use a top-left origin in the projection matrix (glOrthof(0, width, height, 0, ...)). You might have to worry about the handedness of the coordinate system.

    I currently prefer the second option: Things are much less messy when there are as few coordinate systems in use as possible.

    Other minor issues

    • You should use the actual width and height instead of hard-coding 320 and 480. Remember to check on "Retina" and "Retina 4-inch" as well.
    • self.view.transform = CGAffineTransformIdentity; is pointless since you immediately clobber it with a write. on the next line.

    If you really need to set the transform of the view, make it a subview of the VC's view. Also note that some views don't work properly if you set their transform (e.g. UITableView on some versions of iOS uses its frame to decide how wide cells should be when it should use its bounds). It's not uncommon to need a view structure like this:

    • Outer container (whose frame/transform is set by e.g. UIKit)
      • Inner container (this is where you set the transform)
        • The actual view you care about (e.g. UITableView) whose transform you do not set.

    Needless to say, I try to avoid this whenever possible.