CGAffineTransform problem - iphone

I have a UIImageView that I applied a:
CGAffineTransformConcat(scaleTransform, rotateTransform);
Now I need to get the actual scale value and rotation degrees. I can get the rotation degrees, but the problem comes when getting the scale value. The scale value I get is not the right one, unless I rotate the view to 0.0;
I think this is happening because the matrix is now multiplied (scale * rotation).
Any ideas on how to get the right scale value?

I solved me problem.
To get the Angle:
float angle = atan2(imageView.transform.b, imageView.transform.a);
The scale transform applied to the imageView was uniform, so to get the Scale Value:
CATransform3D localScaleTransform = [(CALayer *)[imageView.layer presentationLayer] transform];
float scale = sqrt(pow(localScaleTransform.m11, 2) + pow(localScaleTransform.m12, 2));
If you applied different scale values follow this:
scaleInX = sqrt(M11^2 + M12^2)
scaleInY = sqrt(M21^2 + M22^2)

Related

Rotating rotation value by different normalized vector directions

I have written a script in Unity which takes a SkinnedMeshRenderer and AnimationClip and rotates the vertices in each by a specified number of degrees. It looks mostly correct except that rotations seem to be incorrect. Here is an example bone rotation (in euler angles) in the skeleton along with the correct values that would be needed for the animation to look correct.
With no rotation: (0, 0, -10)
Rotated 90 degrees: (-10, 0, 0)
Rotate 180 degrees: (0, 0, 10)
I have been trying to find a way to rotate these bones to make this conversion make sense with the data I have here, but have come up short. I know I want to rotate these values around the Y axis, but don't actually want the Y value in the euler angle to change. I am aware I could just reorient the root bone around the Y axis and the problem would be solved, but I want to have no rotation in the Y axis. I am "fixing" some older animations that have unnecessary rotation values in them.
var localBoneRotation = new Quaternion(keysX[j].value, keysY[j].value, keysZ[j].value, keysW[j].value).eulerAngles;
var reorientedForward = Quaternion.AngleAxis(rotation, Vector3.up) * Vector3.forward;
localBoneRotation.x *= reorientedForward.x;
localBoneRotation.y *= reorientedForward.y;
localBoneRotation.z *= reorientedForward.z;
var finalRotation = Quaternion.Euler(localBoneRotation);
keysX[j].value = finalRotation.x;
keysY[j].value = finalRotation.y;
keysZ[j].value = finalRotation.z;
keysW[j].value = finalRotation.w;
I have also tried using a matrix and Vector3 but most of the time I end up with values in the Y. Perhaps I am going about this incorrectly. I just need to be able to specify an angle rotation and then have the input data match the final euler angles with each of these data points.

Change transform rotation from X to Z axis

I have a transform which is being rotated around the X axis. But while transferring this rotation to another transform, i want it to do the exact same rotation. But then around the Z axis.
However, this rotation is not a "rotation" it is just a transform which rotation gets edited from the outside. So i have to rotate the original transform to match the 2nd transform, but take the rotation into account.
Axis in below images: RED = X, GREEN = Y, BLUE = Z
Rotation original:
Rotation it should have after:
What would be the correct way to go about this frame by frame?
Thanks in advance,
Smiley
I can give you an answer that solves the general problem of changing the rotation from one axis to another.
Each transform object has a transform.localRotation property that represents the orientation of the transform, relative to the parent's orientation. If the transform has no parent, than this orientation is relative to World Space.
Quaternion is the data type used to represent rotations, and it has a useful method called ToAngleAxis.
float angle;
Vector3 axis;
transform.localRotation.ToAngleAxis(out angle, out axis);
Will set the variables angle and axis to the angle and axis of localRotation. The out part means that you're passing in a variable meant to be set by the function, rather than to be used as input.
In this case, the angle variable is the part you want to actually use. If you use Quaternion.AngleAxis, providing this angle value and your desired axis, you'll get a new rotation that will match your desired parameters.
For example: To change any rotation of transform1 to a Z-axis rotation on transform2, you would use
float angle;
float axis;
transform1.localRotation.ToAngleAxis(out angle, out axis);
transform2.localRotation = Quaternion.AngleAxis(angle, Vector3.forward);
Hope this helps

Using CGAffineTransformRotate, how to set rotation to 0

Giving the following code:
self.transform = CGAffineTransformRotate(self.transform, ?);
Is there a way to set the rotation back to 0 without knowing what the current rotation angle is? I have other transforms that I'd like to maintain, hence why I'm using CGAffineTransformRotate instead of CGAffineTransformMakeRotation.
If it's just scaling and rotation then your options are actually either (i) determine just the scale and make a brand new scaling matrix of that scale; or (ii) as you suggest, determine the rotation and adjust the transform you have by the opposite amount.
You can achieve either by looking at the components of the transform matrix. If you think about how matrix multiplication works you've got the output x axis being (transform.a, transform.b) and the output y axis being (transform.c, transform.d).
So, for (i):
// use the Pythagorean theorem to get the length of either axis;
// that's the scale, e.g.
CGFloat scale = sqrtf(
self.transform.a*self.transform.a +
self.transform.b*self.transform.b);
self.transform = CGAffineTransformMakeScale(scale, scale);
For (ii):
// use arctan to get the rotation of the x axis
CGFloat angle = atan2f(
self.transform.b*self.transform.b, self.transform.b*self.transform.a);
self.transform = CGAffineTransformRotate(self.transform, -angle);
You could also invert the transform
CGAffineTransform CGAffineTransformInvert (
CGAffineTransform t
);
eg
self.transform = CGAffineTransformInvert(CGAffineTransformRotate(self.transform, -angle));

3D Cube Problem! Part 1

I have created a 3D cube in iphone using CALayer's. Now I wanted to rotate that cube(CALayer) at 90˚ when user double taps on it.
I was able to rotate that cube(CALayer) to 90˚ once but when I double tap the cube(CALayer) is not rotating.
Here is the code that I used to rotate the cube(CALayer)
CATransform3D x = CATransform3DRotate(currentLayer.sublayerTransform, M_PI / 2, 0, 0, 1);
currentLayer.transform = x;
Can anyone help in this. What I'm doing wrong.
PS. For the people who are wondering how I got the degree sign then here is the trick
Option + K
its because you are not changing the angle of rotation .... to understand this lets say you are passing M_PI/2 each time to that method .... so CATransform3DRotate do not rotate it to next 90˚ rather it rotate the layer to the specified angle in this case its 90... so you are not getting any chage because it already at 90˚ ..... so to get correct result do this
static float angle = M_PI / 2;//dont make it static rather make it a global variable
angle += M_PI / 2;
CATransform3D x = CATransform3DRotate(currentLayer.sublayerTransform,angle, 0, 0, 1);
currentLayer.transform = x;

Getting the 'scale' from a CATransform3D

I am creating an iPad app and want to update the user with the current size of a view. I used to be doing this by calculating the scale of a CGAffineTransform and multiplying the xScale by the width (of the related view) and the yScale by the height. I'd like to keep doing this, but I'm no longer doing 2d transformations, and I'm not sure what equation to use to extract the scale information from CATransform3D.
Can you help?
To get the current scale of the layer you just perform a valueForKeyPath: on the layer:
CGFloat currentScale = [[layer valueForKeyPath: #"transform.scale"] floatValue];
Other keys can be found in Apples Core Animation Programming Guide
I'm not familiar with the API but CATransform3D looks like a regular 4x4 transformation matrix for doing 3D transformations.
Assuming that it represents nothing more than a combination of scale, rotation and translation, the scale factors can be extracted by calculating the magnitudes of either the rows or columns of the upper left 3x3 depending on whether CATransform3D is row or column major respectively.
For example, if it is row-major, the scale in the x-direction is the square root of ( m11 * m11 ) + ( m12 * m12 ) + ( m13 * m13 ). The y and z scales would similarly be the magnitudes of the second and third rows.
From the documentation for CATransform3DMakeTranslation it appears that CATransform3D is indeed row-major.
Here's an update answer for swift 4+
guard let currentScaleX = view.layer.value(forKeyPath: "transform.scale.x") as? CGFloat {
return
}
print ("the scale x is \(currentScaleX)")
guard let currentScaleY = view.layer.value(forKeyPath: "transform.scale.y") as? CGFloat {
return
}
print ("the scale y is \(currentScaleY)")