I have a UIView subclass that I'm drawing a PDF onto (using a CATiledLayer). I also need to draw on a specific region of that PDF, however the coordinate plane of the CATiledLayer when using CG to draw is way screwy.
See image:
I have a point (200,200), that I need to convert to the CATiledLayer's coordinate system, which is the 2nd plane shown above. I've tried doing this with some transforms, but nothing seems to work.
Thanks!
Here is what I had to do (using the example points/plane above):
//rotatation origin
CGPoint rotateOrigin = CGPointMake(0,0);
//rotatation transform
CGAffineTransform translateTransform = CGAffineTransformMakeTranslation(rotateOrigin.x, rotateOrigin.y);
//rotate the plane 90 degrees
float radians = 90 * (M_PI / 180);
CGAffineTransform rotationTransform = CGAffineTransformMakeRotation(radians); CGAffineTransform customRotation = CGAffineTransformConcat(CGAffineTransformConcat( CGAffineTransformInvert(translateTransform), rotationTransform), translateTransform);
CGAffineTransform m1 = CGAffineTransformIdentity;
CGPoint startPoint = CGPointApplyAffineTransform(CGPointMake(200,200),m1);
//rotated point
CGPoint rotatedPoint = CGPointApplyAffineTransform(startPoint, customRotation);
//final rotated point- after adjusting for the rotation
rotatedPoint = CGPointApplyAffineTransform(rotatedPoint, CGAffineTransformMakeTranslation(500,-500));
Related
I want to transform a view from a plane that is parallel to the ground to a plane that is perpendicular to the ground.
Any ideas?
To rotate a view in 3D, you need to modify the transform property of the view's layer.
It sounds like you want to rotate the view around the X axis. And I guess you want perspective, where the edge closer to the viewer appears larger and the edge farther from the viewer appears smaller.
We'll write a helper function that makes the transform. We start with the identity transform:
static CATransform3D transformWithAngle(CGFloat angle) {
CATransform3D transform = CATransform3DIdentity;
Then set the m34 component of the transform based on the distance from the viewer to the view:
transform.m34 = -1.0f / 300.0f;
If you use a number larger than 300, the perspective will be weaker. If you use a number smaller than 300, the perspective will be stronger.
Next, add the rotation:
transform = CATransform3DRotate(transform, angle, 1, 0, 0);
Then return the transform:
return transform;
}
Let's say you want to apply this to a view named self.riseView. You probably want the rotation to be around the bottom edge of the view, so set the layer's anchor point to the bottom edge:
- (void)viewDidLoad {
CGRect frame = self.riseView.frame;
self.riseView.layer.anchorPoint = CGPointMake(0.5f, 1.0f);
self.riseView.frame = frame;
and initialize the layer's transform with an angle of 0:
self.riseView.layer.transform = transformWithAngle(0);
}
You can make the view “set” (rotate down to the ground plane) by rotating it to an angle of -M_PI_2:
- (IBAction)setButtonWasTapped:(id)sender {
[self animateRiseViewToAngle:-M_PI_2];
}
and you can make it “rise” (rotate up) by rotating it to an angle of zero:
- (IBAction)riseButtonWasTapped:(id)sender {
[self animateRiseViewToAngle:0];
}
Here's how we actually do the animation:
- (void)animateRiseViewToAngle:(CGFloat)angle {
[UIView animateWithDuration:2 animations:^{
self.riseView.layer.transform = transformWithAngle(angle);
}];
}
I have a sublclass of a CCSprite that rotates throughout the game and there is a shield that has to rotate around the sprite according to the sprite's rotation. So if the sprite's rotation is 75 degrees there should be a CGRect located at 75 degrees. The dimensions of the CGRect are subordinate as it almost resembles a square.
What I did is:
I subclassed CCSprite and added a property called shieldArea.
Upon initialization I set this rect to be
self.shieldArea = CGRectMake(self.position.x-30, self.position.y, 8, 10);
Then I rotate the sprite itself, however, the rect stays at its initial position.
I hoped that the CGrect would be affected by the rotation, but I kind of expected it not to affect it, of course, why should it ? So, my question is, how do I rotate a CGRect at all ? Or do I have to add a new CGRect all the time ?
Side notes: I do not want to use Box2d or anything the like. I handle collision detection myself.
Have you tried CGAffineTransform?
Something like this:
float centerX = myOldRect.origin.x + (myOldRect.size.width / 2.0);
float centerY = myOldRect.origin.y + (myOldRect.size.height / 2.0);
CGAffineTransform rotation = CGAffineTransformMakeRotation(someAngleInRadians);
CGAffineTransform moveAnchor = CGAffineTransformMakeTranslation(centerX, centerY);
CGAffineTransform centeredRotation = CGAffineTransformConcat(moveAnchor, rotation);
CGRect rotatedRect = CGRectApplyAffineTransform(myOldRect, centeredRotation);
Note, this is NOT tested. Use at your own risk :p
I want to rotate a CGPoint(red rect) around another CGPoint(blue rect) but it changes distance from the origin(blue rect)...when i give 270 in angle it creates the point right above the origin but when i give 90 as angle value it comes down the origin BUT CHANGES THE DISTANCE ALSO almost three times more....I want to keep the distance same and want to rotate CGPoint around another. Please guide any approach for rotation of cgpoints...
distance = 100;
angle = 270*M_PI/180;
rotatedPoint.x = initialPoint.x+distance*cos(angle);
rotatedPoint.y = initialPoint.y+distance*sin(angle);
//rotatedPoint.x = initialPoint.x+tan(angle);
[test setCenter:rotatedPoint];
[test setBackgroundColor:[UIColor redColor]];
Thanks
CGAffineTransform is a handy tool when it comes to rotation, translation, and scaling. To make sure a point is rotated properly, you must translate it to the origin, rotate it, and then translate it back.
To complete your transformation, something like the following should do the trick:
CGPoint pointToRotate = CGPointMake(30, 30);
float angleInRadians = DEGREES_TO_RADIANS(90);
CGPoint distanceFromOrigin = CGPointMake(0 - pointToRotate.x, 0 - pointToRotate.y);
CGAffineTransform translateToOrigin = CGAffineTransformMakeTranslation(distanceFromOrigin.x, distanceFromOrigin.y);
CGAffineTransform rotationTransform = CGAffineTransformMakeRotation(angleInRadians);
CGAffineTransform translateBackFromOrigin = CGAffineTransformInvert(translateToOrigin);
CGAffineTransform totalTransform = CGAffineTransformConcat(translateToOrigin, rotationTransform);
totalTransform = CGAffineTransformConcat(totalTransform, translateBackFromOrigin);
pointToRotate = CGPointApplyAffineTransform(pointToRotate, totalTransform);
And here is the documentation on CGAffineTransform, if you'd like to review it further: http://developer.apple.com/library/mac/#documentation/GraphicsImaging/Reference/CGAffineTransform/Reference/reference.html
Please let me know if you need anything else if this doesn't solve your problem!
I want to rotate a button randomly on a screen. No specific path defined it can move randomly on a view.
I dont want to use CAKeyframeAnimation. It should be clean and simple.
Can anyone guide me ?
CGAffineTransform cachedTransform = transformedView.transform;
transformedView.transform = CGAffineTransformIdentity;
// Note each of the (untransformed) points of interest.
CGPoint topLeft = CGPointMake(0, 0);
CGPoint bottomLeft = CGPointMake(0, transformedView.frame.size.height);
CGPoint bottomRight = CGPointMake(transformedView.frame.size.width, transformedView.frame.size.height);
CGPoint topRight = CGPointMake(transformedView.frame.size.width, 0);
// Re-apply the transform.
transformedView.transform = cachedTransform;
// Use handy built-in UIView methods to convert the points.
topLeft = [transformedView convertPoint:topLeft toView:parentView];
bottomLeft = [transformedView convertPoint:bottomLeft toView:parentView];
bottomRight = [transformedView convertPoint:bottomRight toView:parentView];
topRight = [transformedView convertPoint:topRight toView:parentView];
Also see if this link is useful to you : Moving UIButton
Animate the button's transform property using CGAffineTransformMakeRotation() and combine it with an NSTimer with a random time interval.
#define RADIANS(degrees) ((degrees * M_PI) / 180.0)
CGAffineTransform rotateTransform = CGAffineTransformRotate(CGAffineTransformIdentity,
RADIANS(30.0));
myButton.transform = rotateTransform;
Use NSTimer to carry this process and use arc4random to randomly generate the angle in radians.
How does one get the 4 coordinates for a UIImageView?
I know the CGRect can be obtained and the origin.x and origin.y, but how can all 4 corners be found?
EDIT: I am rotating the UIImageViews, thats why I asked :P
You could add width and height of the rectangle to get the coordinates of the other 3 points.
CGRect rect = view.bounds;
CGPoint topLeft = rect.origin;
CGPoint topRight = CGPointMake(rect.origin.x + rect.size.width, rect.origin.y);
CGPoint bottomLeft =CGPointMake(rect.origin.x, rect.origin.y + rect.size.height);
CGPoint bottomRight = CGPointMake(rect.origin.x + rect.size.width,
rect.origin.y + rect.size.height);
Then you could use CGPointApplyAffineTransform to get the transformed coordinates of them under your specified transform.
CGPoint center = view.center;
CGAffineTransform transf = CGAffineTransformMakeTranslation(-rect.size.width/2,
-rect.size.height/2);
transf = CGAffineTransformConcat(transf, view.transform);
transf = CGAffineTransformTranslate(transf, center.x, center.y);
topLeft = CGPointApplyAffineTransform(topLeft, transf);
//...
(note: not tested.)
This is my solution:
[self] is a subclass of UIImageView
[self.transform] is the transform i make on [self]:
CGAffineTransform transform = CGAffineTransformMakeTranslation(-center.x, -center.y);
transform = CGAffineTransformConcat(transform, self.transform);
CGAffineTransform transform1 = CGAffineTransformMakeTranslation(center.x, center.y);
transform = CGAffineTransformConcat(transform, transform1);
CGPoint leftTopPoint = CGPointApplyAffineTransform(leftTopPoint, transform);
CGPoint rightTopPoint = CGPointApplyAffineTransform(rightTopPoint, transform);
CGPoint rightBottomPoint = CGPointApplyAffineTransform(rightBottomPoint, transform);
CGPoint leftBottomPoint = CGPointApplyAffineTransform(leftBottomPoint, transform);
You can get the size.width and size.height. Adding those to the x and y will give you the other coordinates.
Whilst these are (of course) relative to the superview, you can use the frame property to obtain a CGRect containing the origin and size of the UIImageView. You can then simply add the relevant size to the relevant origin point to obtain the full set of coordinates.
See the frame section in the UIView class reference for more information.
Construct a rotation matrix http://en.wikipedia.org/wiki/Rotation_matrix. You should calculate the initial positions of the corners relative to the point which is the center of rotation. Store those positions in an array and keep them all the time. You calculate new positions by passing the angle in a 2x2 rotation matrix and multiplying them with initial positions.
Well, given you know the angle of rotation, this is the maths to get the y coordinate of the top right corner:
Sin (angle of rotation) = height difference y / width
Therefore if you're rotating the rectangle by 10 deg and it has a width of 20pt:
Sin 10 = yDiff / 20
Which means you can do this:
yDiff = Sin 10 * 20
This gives you the difference in y from the y coordinate of the origin to the y coordinate of the top right corner. Add this value to the current y origin of your rectangle to get the actual y coordinate of your top right corner. The next step is to use pythagoras on your width and the yDiff to get the xDiff and do the same (add it to the x coordinate) to get the x coordinate of your right hand corner. I hope this makes sense.
Now you just need to do it again for each other corner - imagine, if you will, that the rectangle has rotated through 90 deg, you can just reapply the logic, however x is y and vice versa. :) etc