Calculate Image Rotation - (0° 360°) - ios

I'd like to calculate the rotation of an image in degrees (calculate affine transformation ) .
This is what I got so far:
extension Double {
var toDegrees: Double { return self * 180 / .pi }
}
let rotationAngle = Double(atan2f(Float(self.myView.transform.b), Float(self.myView.transform.a))).toDegrees
print(rotationAngle)
The "rotationAngle" I'm getting looks quite good but tbh I't is not:
But if I rotate the image about 0° or about 180° I get the same values (same for rotating the image about 90° && -90° --> values are both 45°):
EDIT: This is how I can apply rotation on my imageView:
self.ImageView.transform = CGAffineTransform(rotationAngle: CGFloat(.pi))
How can I fix this to get a unique value for every rotation angle? (0° - 360°).
EDIT:
See some more rotations (the first value is the degree value I've turned the image, the second one is the calculated rotationAngle):
EDIT 2:
0° --> rotationAngle: 0.249977666546474, transform.b: 0.004362960593833, transform.a: 0.999990482242134
-90° --> rotationAngle: -44.999557289943, transform.b: -0.999984511428548, transform.a: 0.00556568980525373
180° --> rotationAngle: 0.0352338243182017, transform.b: 0.00061494629500543, transform.a: -0.999999810920509
90° --> rotationAngle: 44.9995128937134, transform.b: 0.99998300906796, transform.a: -0.00582937178330692

Related

Detecting phone tilt with CoreMotion

I'm trying to use CoreMotion to detected whether phone is a little bit tilted in order to alert the user when the phone is not in an upright position.
Let's say that the device is in upright position when it's rotated left or right in less than 40 degrees and it's rotated backward or forward in less than 40 degrees.
Now I've used the CMMotionManager like that:
motionManager.deviceMotionUpdateInterval = 1.0 / 60.0
motionManager.showsDeviceMovementDisplay = true
motionManager.startDeviceMotionUpdates(to: OperationQueue()) { motion, error in
if let data = motion {
let pitch = data.attitude.pitch.toDegrees()
let roll = data.attitude.roll.toDegrees()
let yaw = data.attitude.yaw.toDegrees()
print("Pitch: \(pitch), roll: \(roll), yaw: \(yaw).")
}
}
extension Double {
func toDegrees() -> Double {
self * 180.0 / .pi
}
}
If I understand correctly, the pitch value will tell me that the phone is rotated left or right, and the yaw value will tell me that the phone is rotated forward or backward. Now I have looked at the printed values, and pitch seems to be fine, it is equal to 90 degrees when the phone is upright. But the yaw value is not changing as I would expected while rotating the phone.
The question is, am I doing something wrong? Which values I should use to check whether phone is not rotated forward / backward or left / right?

How to set UIView rotation by degrees

I'm trying to reflect accelerometer data in an iOS app by rotating a UIImageView object. Currently, I am rotating the object based on the difference between its current position reading and the previous position reading (e.g. if the accelerometer was at 90 degrees and is now at 80 degrees it will rotate the object -10 degrees). This method has issues though because there are unread changes in the accelerometer.
As such, I want to set the rotation of the UIImageView based on the degree orientation of the accelerometer. For example, if the accelerometer reads at 65 degrees, I want to set the orientation of the UIImageView object to 65 degrees. Is there a way to do this?
Furthermore, I would like for the rotation to be animated.
Here is my current code which rotates the image view object based on the change from the previous reading:
// UIImage view declaration
#IBOutlet weak var visualizer: UIImageView!
// Rotation code where 'deg' is the change in rotation from the previous reading
UIView.animate(withDuration: 1.0, delay: 0, options: .curveLinear, animations: { () -> Void in self.visualizer.transform = self.visualizer.transform.rotated(by: CGFloat(truncating: deg))})
Note that I would change another part of my code so that 'deg' would be the orientation of the accelerometer in degrees instead of the change in degrees.
the rotation is based on Radian, so you just need to do the math
let radian = degree * CGFloat.pi / 180
to rotate object to n degree use CGAffineTransform
view.transform = CGAffineTransform(rotationAngle: (degree * CGFloat.pi / 180))

How to calculate how much ARKit SCNNode is rotated around the y axis

i am trying to know how much SCNNode is rotated around the y axis. Everytime ARKit world is created it has different rotation, my idea is to scan QRCode, recognize if it rotated 0,90,180,270 degrees (already done), and place object always on exacly same direction, QRCode not rotated (0 degree) will point for example to North.
I was trying to get eulerAngles from pointOfView but don't know how to translate it and let to know how is rotated from (0,0,0). Any ideas?
ANSWER:
if let hitTestResult = hitTestResults.first, let camera = self.pointOfView {
let yaw = atan2f(camera.simdWorldTransform.columns.0.x, camera.simdWorldTransform.columns.1.x)
// convert yaw from [-180; 180] to 0; 360
let yawEuler = ARKitMathNormalizedDegressToCircleDegrees(Double(yaw))
// calculate angle between qrCode north rotation and current point of view
let angleToRotateTransform = ARKitMathDistanceAngleBetween(firstAngleInDegrees: yawEuler, secondAngleInDegrees: qrCodeRotation)
// make rotation matrix and apply to hit results
let rotationMatrix = self.getRotationAroundY(Float(angleToRotateTransform.degreesToRadians))
let transform = simd_mul(hitTestResult.worldTransform, rotationMatrix)
}
`

ARKit - Why is the camera's viewMatrix position changing when the device is rotated?

When I rotate my test device about a certain axis, the camera's viewMatrix's x-axis position value (column 3, row 1) is changing significantly. On the order of a meter in translation along the x-axis when only the device's rotation is changed 180 degrees. If I rotate a full 360 degrees the x position returns to it's starting 0 degree value. I am not translating the device at all (ignoring minor human error).
Is this a bug or configuration setup issue? Can someone explain why the x-axis position would change when only rotating the device? Is anyone else seeing this?
Here is the basic code setup:
#property (nonatomic, strong) ARWorldTrackingConfiguration *arSessionConfiguration;
#property (nonatomic, strong) ARSession *arSession;
- (void)setup
{
self.arSessionConfiguration = [ARWorldTrackingConfiguration new];
self.arSessionConfiguration.worldAlignment = ARWorldAlignmentGravity;
self.arSessionConfiguration.planeDetection = ARPlaneDetectionHorizontal;
self.arSession = [ARSession new];
self.arSession.delegate = self;
[self.arSession runWithConfiguration:self.arSessionConfiguration];
}
- (void)session:(ARSession *)session didUpdateFrame:(ARFrame *)frame
{
matrix_float4x4 viewMatrix = [frame.camera viewMatrixForOrientation:UIInterfaceOrientationPortrait];
NSLog(#"%0.2f, %0.2f, %0.2f", viewMatrix.columns[3][0], viewMatrix.columns[3][1], viewMatrix.columns[3][2]);
}
I am testing on an 10.5" iPad Pro running the latest iOS 11 beta.
This is due to a mis-understanding: the 4th column of the view matrix is not the camera's position.
This is because the view matrix is the inverse of the camera's transformation matrix, i.e. multiplying it by a world point transforms that point to the local basis of the camera.
For a camera with rotation matrix R (3x3) and position c, multiplying its view matrix V (4x4) with a point p is equivalent to:
We can deduce that the view matrix has the following construction:
Therefore, to obtain the actual position of the camera, we must
multiply the 4th column by [minus] the transpose / inverse
of the top-left 3x3 sub-matrix of the view matrix.
I.e., something like:
matrix_float3x3 topLeftSubMtx = /*viewMatrix[0][0] to viewMatrix[3][3]*/;
vector_float4 rightColumn = viewMatrix.columns[3];
float positionX = -[vector_float4.dotProduct topLeftSubMtx.columns[0], rightColumn];
// similarly for Y and Z
(Apologies as I don't know objective-C or ARKit specifics; hopefully you get the gist of this pseudo-ish code)
Get current transform of each frame of camera by following method
func session(_ session: ARSession, didUpdate frame: ARFrame)
{
let currentTransform = frame.camera.transform
}

Rotating a Cocos2d sprite to match a joystick

I'm using a SneakyJoystick in Cocos2d, and I'm trying to get a sprite to rotate to face the same direction as the joystick is pointed (this is top down).
I can get it to rotate to face it, but it snaps into position as the rotation is updated every frame or so.
How can I make the sprite rotate smoothly towards the target angle, without jumping to it? I wasn't able to figure out how to do this with a CCRotateTo because the angle to rotate towards could change at any time.
I ended up fixing this simply by using a rotation method that I made, which rotates the node/sprite in the correct direction at the correct amount each update.
- (void)rotateNode:(CCNode*)aNode degrees:(float)targetRotation withSpeed:(float)rotationSpeed withTimeDelta:(ccTime)dt
{
rotationSpeed = rotationSpeed * dt;
// Convert the difference between the two angles to radians
float diff = (targetRotation - aNode.rotation) * (M_PI / 180);
// Find the rotation of the vector created by the sin and cos of the difference
float rotationDifference = atan2f(sinf(diff),cosf(diff));
// Rotate the clip accordingly
aNode.rotation += MAX(
MIN(
(180/M_PI) * rotationDifference,rotationSpeed), -rotationSpeed
);
}
Have you tried:
[CCRotateBy actionWithDuration:0.5f angle:CC_DEGREES_TO_RADIANS(90.0f)];
Obtain the Angle between the last Update the current Update, also if you wanted it so the character had a set time to turn around, you can scale your duration by the amount of the angle.

Resources