How to rotate an image by its bottom center? - ios

I tried to rotate an image by its bottom center by setting the anchorPoint property of the views layer to CGPointMake(0.5, 1).It did rotate based on the bottom center,but the image views bottom center was translated to the image views center position and thus the whole image was translated up by half the height of the image.How to have the image view retain its center but still rotate about its bottom center?
Has anyone ever encountered this issue before?
Hey guys heres a pictorial demonstration of how i want the rotation to work on the images!
This is the original untransformed image!
As you can see i have put a red dot to indicate the bottom center of the image.
Here is the rotated image.The image has been rotated clockwise by a few degrees.This has been rotated about by its center which is again not what i want!!
Image obtained after applying tranforms posted in Calebs answer..Note: The transforms were applied on an image view that houses the above vertical image!As you can see the flaws in the rotation the bottom center has gone up and even the rotation was different.It took sort of 180 degree rotation and the whole image translated up by some distance.
To reiterate,I just want the image to rotate like a needle of a clock but about its bottom center
Thank you!

Assuming that you want to rotate the view in which the image is drawn, the usual way to do it is to compose a transformation matrix from three separate matrices. The first one translates the image left by half its width. The second rotates the view. The third translates the image right by half its width (i.e. it's the inverse of the first). When you put these three together, you get a matrix that rotates the image about its bottom center.
For example, if you have:
CGFloat x = imageWidth/2.0;
CGFloat r = 1.0; // some value in radians;
you can set up a transform like this:
CGAffineTransform t1 = CGAffineTransformMakeTranslation(-x, 0);
CGAffineTransform t2 = CGAffineTransformRotate(t1, r);
CGAffineTransform t3 = CGAffineTransformTranslate(t2, x, 0);
t3 is the final transform that will translate, rotate, and translate back all in one step. If you set t3 as the transform for an image view, you'll find the view rotated by 1.0 radians (or whatever you set r to) about the bottom center.
In addition to correcting my earlier error, Peter Hosey's comment points out that another option is to rotate the layer instead of the view. I don't think this is what you're looking for, but if it is you should know that transformations on a layer take place about it's anchorPoint, which by default is set to the center of its bounds rectangle. To rotate about the bottom center of the bounds rect, you could set the anchor point to the bottom center first, and then apply a rotation transform. (Note that the transform property of a layer is a CATransform3D; if you want to use an affine transform as above, use the setAffineTransform: method.)

Related

How to rotate CATextLayer and preserve it's size?

I have a custom view, which I use for markup (draw lines and other figures on it). The view controller recognizes touches and gestures and passes info to the view so it can draw itself properly. Each figure has a label (CATextLayer) with some figure info on it (line length for example).
I added a rotation gesture recognizer to the view controller to rotate this drawing view. I want to rotate the view, but prevent labels from rotation (so they stay 0.0 degrees relative to the superview). For this I calculate the new drawing view's angle relative to the superview and set label's angle property to the negative value, so I can rotate them oppositely. For example, the view is rotated 30 degrees, then I rotate labels -30 degrees.
In the view drawing method which is responsible for drawing figures and setting the labels, I create new transform for each label each time the view needs to be redrawn:
CGAffineTransform transform = CGAffineTransformIdentity;
transform = CGAffineTransformRotate(transform, self.angle); //self.angle - rotation angle in radians
transform = CGAffineTransformScale(transform, scale, scale); //scale label (need this for pinch gesture, works as expected)
label.transform = transform;
All this stuff works if I rotate labels 90 degrees. If the degree is not 0, 90, 180, etc, the label's frame changes: shrinks or enlarges, with large angles it even disappears. I understand, that when you rotate the rectangle, it's frame should get bigger as it's pointed here: Why after rotating UIImageView size is getting changed?
Is there a way to prevent CATextLayer from changing its shape when rotating?
Normal position of label:
When rotated 90 degrees (everything is nice)
Rotated to some arbitrary angle (label frame is misshapen)
The issue was occurring because I was resetting CATextLayer's origin after setting its transform. According to the transform property documentation:
When the value of this property is anything other than the identity transform, the value in the frame property is undefined and should be ignored.
To change the position of a layer, use its position property.
The frame isn't that what you expected after a non-rectangular rotation.
I see three possible solutions for your problem:
Calculate the correct size of your text, and set the frame by assigning appropriate values to position and bounds.
Create a plain CALayer for the background of each text layer, if the first solution doesn't help.
But it should be much easier if you're rotate the image only and keep the rotation of the text layers unchanged. You can achieve this by adding the text layers to the super layer of the image layer. With this setup you have just to calculate the new position of the text layers after rotation.
I'm very unsure whether the first two solutions are practicable, and I would prefer the third one.

iOS Animate Translation of a rotated view

I have a view that is slanted as in rotated by an angle. To rotate I used CGAffineTransformMakeRotation. Now I want to animate it going up vertically or in other words in negative y axis relative to the root view for 100 px. But my view needs to know X and Y components of that 100 px in terms of its own X and Y system. I use trigonometry to find those values and its works fine but the problem is that when I animate it using CGAffineTransformTranslate , it moves the view in the X direction first (non animated, jumps) then in Y (animated). How can I make it translate properly in both dimensions together?
From Apple
https://developer.apple.com/library/ios/documentation/WindowsViews/Conceptual/ViewPG_iPhoneOS/WindowsandViews/WindowsandViews.html#//apple_ref/doc/uid/TP40009503-CH2-SW6
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIView_Class/index.html#//apple_ref/occ/instp/UIView/frame
The value in the center property is always valid, even if scaling or
rotation factors have been added to the view’s transform. The same is
not true for the value in the frame property, which is considered
invalid if the view’s transform is not equal to the identity
transform.
So when you applies non identity transform like rotation the frames becomes invalid. You should not use frame for transformed view. Instead you can use center property for repositioning view.

SpriteKit sprites are cropped in portrait orientation

I am having trouble understanding the co-ordinate system in SpriteKit.
The documentation states that a scene size is 1024x768 and the anchor point for the scene is CGPointZero (i.e. the bottom left of the scene). So in Landscape orientation the scene's CGPoint(0,0) is on the bottom left of the view - all good.
However, if the ScaleMode is AspectFill then (as the documentation describes) some of the scene is cropped in portrait orientation - again that makes sense.
Where I am confused is that the cropping appears to be based on an AnchorPoint of CGPoint(0.5,0.5). I.e. a sprite with AnchorPoint CGPoint(0,0) that is drawn at scene position CGPoint(0,0) is cropped in portrait orientation.
My question is: "If the scene's anchor point is CGPoint(0,0) and the ScaleMode is AspectFill, why does this the node at CGPoint(0,0) cropped? Shouldn't it ensure that the bottom left of the scene is always at the bottom left of the view?"
Do not confuse your scene with your view.
Yes, for your scene, the default is bottom left. But scaling applies from the scene to the view. By default, your scene is added to the center of the view.
As far as scaling goes, imagine it being like a balloon that you are going to wrap around a box.
You pull it from all ends evenly till the entire balloon fits around the edges of the box.
Then you take Aspect fill into consideration by taking 2 rectangle boxes, and placing them on the sides so that your box top turns into the desired shape.
This is why (0,0) ends up getting cropped off.
The anchor point applies to what happens inside the scene, not outside.
You would need to change the views anchor point (Not possible that I know of) to achieve what you want, or just shift the scene to the right by the difference of (sceneWidth * scaleFactor) - viewWidth

Rotate Image on Slider Value in iOS

I am rotating the image on slider value -
I am using this code for rotation -
editingView.transform = CGAffineTransformRotate(editingView.transform,sliderVal);
its Rotating properly but if i am trying to move or resize after rotation,The editingView is resizing with unexpected behavior and view disappears from screen.
Please suggest me what i am doing wrong.
Well whenever you rotate a view which is inside a superview, you should preserve the position of the view. If you are not rotating any view across the origin then, you should first translate the view's origin to the superview's origin and then rotate and then again translate back to the original point.
Find the coordinate if the view you want to rotate with respect to its superview, say it (x,y).
Translate the view to the origin as;
view.transform = CGAffineTransformMakeTranslation(x,y)
Rotate the view by some angle, say PI,
view.transform = CGAffineTransformMakeRotation(PI)
After rotation translate back to the original point as;
view.transform = CGAffineTransformMakeTranslation(-x,-y)
And that's it. It should work with all the different rotation.
Have a look at this question.
Since you do not show any code on how you do the move or resizing, I suspect you are not properly concatenating the transforms. Furthermore, after you did the rotation, a translation will possibly work on the rotated coordinate system, therefore leading to unexpected behaviour.
Changing transform value affecting the frame value of UIView. As Apple says:
Warning: If this property is not the identity transform, the value of
the frame property is undefined and therefore should be ignored.
Apple docs
So, if you are moving or resizing your view using frame property, try do this with bounds, center properties

Move a UIImageView after applying CGAffineTransformRotate behave incorrect

I'm trying to rotate UIImageView for certain degrees with CGAffineTransformMakeRotation() function, but it end with imageView only rotates, but when I moved to another coordinates then imageView stretched or change height and width. I have no clue why this happens.
Here is a code:
double a = atan2(dx,dy);
bowImageView.transform = CGAffineTransformMakeRotation(a);
WHen you apply a transform to a view the geometry changes. If you wish to move that view rotated, the simplest solution is to set the transform back to CGAffineTransformIdentity, move the view and reapply the rotation.
The other way is to work out the movement based on the current rotation.....but I find the first solution easier!

Resources