CATransform3D transform - iphone

I'm trying to add perspective to a view by using CATransform3D. Currently, this is what I'm getting:
And this is what I wanna get:
I'm having a hard time doing that. I'm completely lost here. Here's my code:
CATransform3D t = CATransform3DIdentity;
t.m11 = 0.8;
t.m21 = 0.1;
t.m31 = -0.1;
t.m41 = 0.1;
[[viewWindow layer] setTransform:t];

Matrix element .m34 is responsible for perspective. It's not discussed much in the documentation, so you'll have to toy with it. This answer talks a little bit about how to use it: https://stackoverflow.com/a/7596326/1228525
To actually see the effects of that matrix you need to do two things:
1. Apply that perspective matrix to the parent view's sublayer transform
2. Rotate the child view (the one on which you want perspective) - otherwise it will remain flat and you won't be able to tell it now has a 3D perspective.
The numbers are arbitrary, make them whatever looks best:
CATransform3D t = CATransform3DIdentity;
t.m34 = .005;
parentView.layer.sublayerTransform. = t;
childview.layer.transform = CATransform3DMakeRotation(45,1,0,0);
The perspective will look different depending on where the child is in the parent view. If the child is in the center of the parent it will be like you are looking at the child view in 3D straight on. The further from the center it is, the more it will be like you are viewing from a glancing angle.
This is what I got using the above code and centering the child view: (apparently I'm not allowed to post pictures since I'm new, so you'll have to see the link) http://i.stack.imgur.com/BiYCS.png
It's very hard to tell what you're going for based on those pictures; a bit more explanation might be helpful if my answer isn't what you want. From what I can tell from the picture, the bottom one isn't perspective...

I was able to easily achieve the right CATransform3D using AGGeometryKit.
#import <AGGeometryKit/AGGeometryKit.h>
UIView *view = ...; // create a view
// setting anchorPoint to zero
view.layer.anchorPoint = CGPointZero;
view.layer.transform = CATransform3DMakeTranslation(-view.layer.bounds.size.width * .5, -view.layer.bounds.size.height * .5, 0);
// setting a trapezoid transform
AGKQuad quad = view.layer.quadrilateral;
quad.tl.x -= 10; // shift top left x-value with 10 pixels
view.layer.quadrilateral = quad; // the quad is converted to CATransform3D and applied

Related

Can 2D and 3D transforms be applied to iOS controls?

Having never actually developed with iOS before, I am investigating the possibilies with standard iOS controls such as text fields, list etc. and would like to know which transforms can be applied to them.
Do these standard controls support 2D transforms such as scale, translate and rotate?
Do these standard controls also support 3D transforms such as scale, translate and rotate which include a z axis?
If the answer is yes to either questions, what "level" of support exists? For example with a text field, if I transform it in 3D coordinate space can I still enter text into it?
Yes, and a lot. UITextField for example inherits from UIControl with inherits from UIView. This means that you have access to the view's transform property directly via its transform property:
[myTextField setTransform:CGAffineTransformMake(a, b, c, d, x, y)];
Or for 3D support, you can access the transform property of the view's layer to apply a CATransform3D:
[myTextField.layer setTransform:CATransform3DRotate(trans, theta, x, y, z)];
CATransform3D is defined as follows, and as #Xman pointed out, you'll need to import the QuartzCore framework using #import <QuartzCore/QuartzCore.h>, as well as link against it in your build phases.
struct CATransform3D
{
CGFloat m11, m12, m13, m14;
CGFloat m21, m22, m23, m24;
CGFloat m31, m32, m33, m34;
CGFloat m41, m42, m43, m44;
};
typedef struct CATransform3D CATransform3D;
In both of these cases, you can still interact with the text field after a transform has been applied to it.
More information can be found in Apple's documentation.
Check CATransform3D also,
CATransform3D yourTransform = CATransform3DIdentity;
yourTransform.m34 = 1.0 / -500;
//You can rotate the component in any angle around x,y,z axis using following line.
//Below line will rotate the component in 60 degree around y-axis.
yourTransform = CATransform3DRotate(yourTransform, DEGREES_TO_RADIANS(60), 0.0f, 1.0f, 0.0f); //#define DEGREES_TO_RADIANS(d) (d * M_PI / 180)
//You can even translate the component along x,y,z axis
//Below line will translate component by 50 on y-axis
yourTransform = CATransform3DTranslate(yourTransform, 0, 50, 0);
//apply transform to component
yourComponent.layer.transform = yourTransform;
Don't forget to import
#import <QuartzCore/QuartzCore.h>
Hope this will help you.

Draw image with CGAffineTransform and CGContextDrawImage

I want to draw UIimage with CGAffineTransform but It gives wrong output with CGContextConcatCTM
I have try with below code :
CGAffineTransform t = CGAffineTransformMake(1.67822, -1.38952, 1.38952, 1.67822, 278.684, 209.129); // transformation of uiimageview
UIGraphicsBeginImageContext(CGSizeMake(1024, 768));
CGContextRef imageContext = UIGraphicsGetCurrentContext();
CGContextDrawImage(imageContext, dragView.frame, dragView.image.CGImage);
CGContextConcatCTM(imageContext, t);
NSLog(#"\n%#\n%#", NSStringFromCGAffineTransform(t),NSStringFromCGAffineTransform(CGContextGetCTM(imageContext)));
Output :
[1.67822, -1.38952, 1.38952, 1.67822, 278.684, 209.129] // imageview transformation
[1.67822, 1.38952, 1.38952, -1.67822, 278.684, 558.871] // drawn image transformation
CGAffineTransform CGAffineTransformMake (
CGFloat a,
CGFloat b,
CGFloat c,
CGFloat d,
CGFloat tx,
CGFloat ty
);
Parameter b, d and ty changed, How to solve this?
There is no problem to solve. Your log output is correct.
Comparing the two matrixes, the difference between the two is this:
scale vertically by -1 (which affects two of the first four members)
translate vertically by 349.742 (which affects the last member)
I'm going to take a guess and say your view is about 350 points tall. Am I right? Actually, the 349.742 is weird, since you set the context's height to 768. It's almost half (perhaps because the anchor point is centered?), but well short, and cutting off the status bar wouldn't make sense here (and wouldn't account for a 68.516-point difference). So that is a puzzle. But, what follows is still true:
A vertical scale and translate is how you would flip a context. This context has gone from lower-left origin to upper-left origin, or vice versa.
That happened before you concatenated your (unexplained, hard-coded) matrix in. Assuming you didn't flip the context yourself, it probably came that way (I would guess as a UIKit implementation detail).
Concatenation (as in CGContextConcatCTM) does not replace the old transformation matrix with the new one; it is matrix multiplication. The matrix you have afterward is the product of both the matrix you started with and the one you concatenated onto it. The resulting matrix is both flipped and then… whatever your matrix does.
You can see this for yourself by simply getting the CTM before you concatenate your matrix onto it, and logging that. You should see this:
[0, -1, 0, -1, 0, 349.742]
See also “The Math Behind the Matrices” in the Quartz 2D Programming Guide.

CGAffineTransformScale modified after device rotation

I have a view that I am performing a transform on
originalTransform = self.appContainer.transform;
self.appContainer.transform = CGAffineTransformMakeScale(.8, .8);
If I do not rotate the device I can revert this back to the original by using
self.appContainer.transform = CGAffineTransformScale(originalTransform, 1, 1);
Unfortunately, if I rotate the device, the transformation matrix for the view gets modified by the view rotation and breaks the original scale. If I undo the scale after rotation I am left with the UIView not returning to its original full size.
I'm sure that I need to make calculations between the original transformation matrix and the new one but I am unsure how to do this. The only thing I have been able to do to make this work is to revert the scale back to 1 before rotation
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
self.appContainer.transform = CGAffineTransformScale(originalTransform, 1, 1);
}
And then rescale it with the newly modified transformation after the
-(void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
self.appContainer.transform = CGAffineTransformMakeScale(.8, .8);
}
This makes it work as I expect, but instead of going back to full screen, and then back to .8 scale, I'd like it to go from its new transformation to the correct .8 scale.
If you want to revert it to original, try setting the transform to CGAffineTransformIdentity.
self.appContainer.transform = CGAffineTransformIdentity;
I think you have to remove all autoresizing masks using.....
[self.appContainer setAutoresizingMask:UIViewAutoresizingNone];

How to move a node in cocos2d and cocos3d

I have a node. In this particular case, it's a CCLayer, but I'm looking for a general solution. My node is centered at point1 (let's say { 100, 100 }). I'd like it to move to point1 (say { 200, 200 }) over the course of 0.5 seconds.
Really simple stuff, right? But I'm just not finding the docs/tutorials I need to do it.
Hints?
Thanks!
Extra credit: same question with a CC3Node, if the answer is different. :)
You can move anything inherits CCNode using runAction: [CCMoveTo actionWithDuration: 0.5 position:ccp(x,y)]
http://www.cocos2d-iphone.org/wiki/doku.php/prog_guide:actions
// assuming you've already got a CCLayer called "myLayer"
[myLayer runAction:[CCMoveTo actionWithDuration:0.5 position:ccp(200,200)]];
EDIT: Changed to CCMoveTo rather than CCMoveBy after re-reading the question.
/*
Moving an entire layer including all of his children (sprites, labels etc.). Insert this code into your 'init' method which belongs to the layer you'd like to be moved to the new point. X and Y are exactly coords of the new position of the layer relative to his center.
Example: x = 0; x = 100; in this case the layer will be moving vertical.
*/
x = ?; // X value
y = ?; // Y value
[self runAction:[CCMoveTo actionWithDuration:5.0f position:ccp(x, y)]];
Are you trying to move the layer or does your layer contain sprites that you want to move? i am not sure if it is even possible to move a layer (or stacks of layers) that contain childs (ccnodes, ccsprites, etc.).
My advice would be to move the layers child elements using ccanimation/ccmoveby/ccmoveto/etc.

Rotating UILabels from any position to upright

I have a label that I rotate using
pieceBlack.transform = CGAffineTransformMakeRotation((M_PI * (180) / 180.0));
and that works perfectly, EXCEPT:
I rotate this label during the game to either right side up or upside down. How do I say, "Whatever angle you are at, go back to upright." I'm thinking maybe like an:
int PreviousAngle = ?;
pieceBlack.transform = CGAffineTransformMakeRotation(degreesToRadian(0-PreviousAngle));
so I guess what I'm asking is how you ask for the rotation angle. Or, alternately, maybe there is a sort of
pieceBlack.transform = CGAffineTransformMakeRotation(RotateToUpright);
From what I remember transform is always relative from the upright position (original), so 0.0f? So you can just do pieceBlack.transform = CGAffineTransformIdentity
What I did was to first position the (in my case) view in the "straight up" orientation. Then I used the CGAffineTransformMakeRotation to create the somewhat off-kilter view. Finally, I applied the identity transform to bring the view back to its straight-up position.
you don't want to set the transform, you want to modify it,
view.transform = CGAffineTransformRotate(view.transform, angle);
if you need to keep the old one around, then do