4x4 matrix rotation unexpected: 200°+45°=115° - swift

I would like to make a rotation using 4x4 matrix in Swift, but it has unexpected behavior: 200 degrees + 45 degrees = 115 degrees, and not 245
let degree200 = Angle(degrees: 200).radians
let degree45 = Angle(degrees: 45).radians
// 200 degrees + 45 degrees
let rotationMatrix = float4x4(simd_quatf(angle: Float(degree200+degree45), axis: SIMD3<Float>(0, 1, 0)))
// it prints 115 degree, and not 245
print(Angle(radians: Double(simd_quatf(rotationMatrix).angle)).degrees)

I assume that's a typo, and you in fact meant -115 degrees? (remainder(245, 360)) When using quaternions & Matrices to express orientations, you can only expect to see values of -180 to +180 degrees when converting those values back to Euler angles.
In general it is impossible to convert back to Euler angles from either a quaternion or matrix and get the original input values back. You either store the original Euler angles and present those to the user, or you will have to have a known starting Euler value and apply an Euler filter to obtain approximately correct results.
The only correct way to get your expected result is to NOT print the value after conversion to quats:
print((degree200 + degree45). degrees)

Well I know 115 and 245 are 360. Just a guess but maybe you're rotating the wrong way?? Maybe try negative values and see what happens.

Related

SCNNode Rotation Multiple Axes

This Question was posted, but never answered.
Similar to This Question, I am trying to understand SCNNode.rotation as a 4D vector. The prior question utilizes an example that only manipulates 1 axis, i.e.,
SCNNode.rotation = (0, 0, 1, degToRad(45)) //Rotate about z-axis by 45 degrees
which makes sense; however, what if I wanted to rotate the X axis by 20 degrees, Y axis by 45 degrees and then Z axis by 78 degrees?
SCNNode.rotation = ??
I would provide code I've tried, but I don't understand conceptually the notion of a 4D rotation vector.
Every node just has a transform with 4x4 matrix. So all the rotation operations are reflecting in the changing the transform.
In this case, if you change either of rotation, eulerAngles and orientation, you are supposed to get same value.
If rotating about three axises, I suggested using eulerAngles.
node.eulerAnges = SCNVector3(x:degToRad(20),y:degToRad(45), z:degToRad(78))
After you set this, go back and check to value of rotation:
SCNVector4(x: -0.16975601, y: 0.5943193, z: 0.786109, w: 1.448788)
This means there is an axis going through point(-0.16975601, 0.5943193, 0.786109) and origin (0,0,0), and node is rotating around it for 1.448788 (82 degree).

Angles in Matlab

i need to calculate some expression for all angles from 0 to 90 degrees increments 10 degrees (of cause expression depends on some trigonometrical function).
It looks like:
for alpha = 0:10:90
func(alpha) = c * sin(alpha)
end
Who know how to work with degrees, tell, please
It should be:
for 0:pi/18:pi/2

cardinal components to cardinal direction using arctan function

I have ocean currents data (going towards). what would be the conversion I can use?
270-(atan2(zonal,meridional)(180/pi)) or 270-(atan2(meridional,zonal)(180/)) or anything entirely different?
I have gone through [this link][1] and also [eol][2] website. I still have no idea.
using unit circle and arctan function I tried to do, like for first quadrant zonal component(x) towards east-west is positive and meridioanl component(y) north-south is positive I used arctan(x,y) to find the direction.
then for 2nd quadrant 90+arctan(x,y) ???
3rd quadrant 180+arctan(x,y) ??
4th quadrant 270+arctan(x,y) ??
please correct me if I am wrong...
Not sure what are you exactly asking, but the function atan2 already gives you the correct quadrant, so no special tricks must be done adding or substracting angles to the result.
If you write help atan2 you will see that it expects two parameters: y and x (in this order) and returns you an angle in radians with a range [-pi,+pi]
Eg.
rad2deg(atan2(1,1)) gives you 45 as result
rad2deg(atan2(-1,1)) gives you -45 as result
rad2deg(atan2(1,-1)) gives you 135 as result
rad2deg(atan2(-1,-1)) gives you -135 as result
EDIT:
if you want only positive angles, just do:
angle = atan2(Y, X);
if (angle < 0)
angle = angle + 2*pi;
end

Mathematic functions in Swift

I write this code i Swifts Playground, but the result is wrong:
import UIKit
var degree:Double = 60
var result = cos(degree)
--
The result shall be 0.5 but Playground get me the answer = -0.9524129804151563.
If I choose 30 degrees the result will be = 0.154251449887584
What is wrong??
Trigonometric functions that take angles treat values as if they are expressed in radians, not degrees. When you pass 60, you get back cosine of 60 radians, not 60 degrees. To convert degrees to radians, multiply the value by π, and divide by 180.

Is there a fast way to calculate the smallest delta between two rotation values?

There are two views:
viewA and viewB. Both are rotated.
The coordinate system for rotation is weird: It goes from 0 to 179,999999 or -179,99999 degrees. So essentially 179,99999 and -179,99999 are very close together!
I want to calculate how much degrees or radians are between these rotations.
For example:
viewA is rotated at 20 degrees
viewB is rotated at 30 degrees
I could just do: rotationB - rotationA = 10.
But the problem with this formula:
viewA is rotated at 179 degrees
viewB is rotated at -179 degrees
that would go wrong: rotationB - rotationA = -179 - 179 = -358
358 is plain wrong, because they are very close together in reality. So one thing I could do maybe is to check if the absolute result value is bigger than 180, and if so, calculate it the other way around to get the short true delta. But I feel this is plain wrong and bad, because of possible floating point errors and unprecision. So if two views are rotated essentially equally at 179,99999999999 degrees I might get a weird 180 or a 0 if I am lucky.
Maybe there's a genius-style math formular with PI, sine or other useful stuff to get around this problem?
EDIT: Original answer (with Mod) was wrong. would have given 180 - right answer in certain circumstances (angles 30 and -20 for example would give answer of 130, not correct answer of 50):
Two correct answers for all scenarios:
If A1 and A2 are two angles (between -179.99999 and 179.99999,
and Abs means take the Absolute Value,
The angular distance between them, is expressed by:
Angle between = 180 - Abs(Abs(A1 - A2) - 180)
Or, using C-style ternary operator:
Angle between = A1 < 180 + A2? A1 - A2: 360 + A1 - A2
Judging from the recent questions you've asked, you might want to read up on the unit circle. This is a fundamental concept in trigonometry, and it is how angles are calculated when doing rotations using CGAffineTransforms or CATransform3Ds.
Basically, the unit circle goes from 0 to 360 degrees, or 0 to 2 * pi (M_PI is the constant used on the iPhone) radians. Any angle greater than 360 degrees is the same as that angle minus a multiple of 360 degrees. For example, 740 degrees is the same as 380 degrees, which is the same as 20 degrees, when it comes to the ending position of something rotated by that much.
Likewise, negative degrees are the same as if you'd added a multiple of 360 degrees to them. -20 degrees is the same as 340 degrees.
There's no magic behind any of these calculations, you just have to pay attention to when something crosses the 0 / 360 degree point on the circle. In the case you describe, you can add 360 to any negative values to express them in positive angles. When subtracting angles, if the ending angle is less than the starting angle, you may also need to add 360 to the result to account for crossing the zero point on the unit circle.
Let's try this again:
There are two angles between A and B. One of them is
θ1 = A - B
The other is
θ2 = 360 - θ1
So just take the minimum of those two.
In addition to Brad Larson's excellent answer I would add that you can do:
CGFloat adjustAngle(angle) { return fmod(angle + 180.0, 360.0); }
...
CGFloat difference = fmod(adjustAngle(angle1) - adjustAngle(angle2), 360.0);
Take the difference, add 360, and mod by 360.