Cocos2d angle confusion - iphone

This system is really confusing me. I'm rotating a turret to face an enemy sprite, I get the angle in radians with:
float angleRadians = atanf(yDifference / xDifference);
float angleDegrees = CC_RADIANS_TO_DEGREES(angleRadians);
That's cool, now I put the enemy in several positions to see how it plotted the angles in DEGREES:
T = Turret
-45 90 45
-0 T 0
45 -90 -45
The angle for an enemy top-right of the turret is going to be the same as the angle for an enemy bottom-left, thus I'd have to have some form of condition to distinguish the 2. That wouldn't be hard except for the fact that cocos2d's rotational angles work like this:
45 90 135
0 T +/-180
-45 -90 -135
What do I have to do to convert the angle I calculated at the start to correctly rotate the turret with this system above?

If you use:
float angleRadians = atan2f(yDifference, xDifference);
this should return an angle in radians which is in the range [-pi, pi].
This should fix yoUr problem.

Related

weapon is supposed to flip after higher than 90 degress / lower than -90 degrees so it isnt upside down (unity2d)

The weapon flips if the angle is above 90 degrees like intended but doesnt flip if the angle is bellow -90 degrees. For some reason it does flip on the Y axis if the angle is 0 or 180 degrees.
if (Weapon.transform.eulerAngles.z < 90 && Weapon.transform.eulerAngles.z > -90)
{
Weapon.GetComponent<SpriteRenderer>().flipY = false;
}
else
{
Weapon.GetComponent<SpriteRenderer>().flipY = true;
}
visualization
the weapon follows my mouse with this code:
Vector2 mouseScreenPosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
Vector2 direction = (mouseScreenPosition - (Vector2)transform.position).normalized;
transform.right = direction;
i dont have any issues with the weapon pointing towards my mouse.
I already tried it with different angles but only the positive one flipped the weapon and 0 degrees. I appreciate every answer. Thank you for your time.
Fixed it with this:
if ((Weapon.transform.eulerAngles.z < 90 && Weapon.transform.eulerAngles.z >= 0) || (Weapon.transform.eulerAngles.z > 270 && Weapon.transform.eulerAngles.z <= 360))

How to clamp a quaternion to stay within a certain angle of another

We have one head object and one body object.
These two objects are separate children of one person object.
I need to make the head object rotate freely left and right which I've done.
I also need to make the body object rotate left and right with the head object ONLY if the difference of rotation between the two quaternions is +/- 90 degrees.
In other words, I should be able to move the head freely left and right, if the difference of rotation between the head and body is less than or greater than 90 degrees, then the body will start rotating with the head and stop if the rotation is within +/- 90 degrees. The body's rotation should not snap to the head's rotation but instead make sure it stays inside an invisible 180 degree cone that the head can rotate.
While you could do something like this:
var rotation = Input.GetAxis("Mouse X") * speed * Time.deltaTime;
Head.transform.RotateAround(Vector3.up, rotation);
var angle = Quaternion.Angle(Head.transform.rotation, Body.transform.rotation);
Debug.Log(angle);
if(angle > 90)
{
Body.transform.RotateAround(Vector3.up, rotation);
}
It will also rotate when you look up or down past 90 degrees. So it might be better to have input modify the angles, clamp the body angle, and set them into the rotations.
var rotation = Input.GetAxis("Mouse X") * speed * Time.deltaTime;
headAngle = headAngle + rotation;
bodyAngle = Mathf.Clamp(bodyAngle, headAngle - 90, headAngle + 90);
Head.transform.rotation = Quaternion.AngleAxis(headAngle, Vector3.up);
Body.transform.rotation = Quaternion.AngleAxis(bodyAngle, Vector3.up);

Converting radian angle to CGVector

Using Sprite Kit I am trying to set an SKPhysicsBody moving according to a given angle, so for example if you wanted the sprite to travel to the right you would specify 1.571 radians. To turn the specified angle into a velocity I am using the method below to convert radians to a CGVector. The ORIGINAL version that I implemented from memory has the strange effect of offsetting all the angles by 90degrees. (i.e. if 0 degrees is used the sprite moves right (just like it would if you specified 90degrees)
Question:
I have fixed this in the NEW version by swapping the dx and dy assignments. My question is why does this happen, do I have it wrong in the original (there do seem to be others doing it that way on the web) or is there some reason based on the particular coordinate system being used.
// ORIGINAL
- (CGVector)convertAngleToVector:(CGFloat)radians {
CGVector vector;
vector.dx = cos(radians) * 10;
vector.dy = sin(radians) * 10;
NSLog(#"DX: %0.2f DY: %0.2f", vector.dx, vector.dy);
return vector;
}
// NEW, SWAPPED DX & DY
- (CGVector)convertAngleToVector:(CGFloat)radians {
CGVector vector;
vector.dy = cos(radians) * 10;
vector.dx = sin(radians) * 10;
NSLog(#"DX: %0.2f DY: %0.2f", vector.dx, vector.dy);
return vector;
}
NOTE: also in Sprite Kit clockwise rotations are negative, so far convertAngleToVector is doing positive clockwise rotations (i.e. 1.571 radians is right, where it should be left) I could just do cos(radians*-1) and sin(radians*-1) but there might be some underlying reason for this based on me swapping dx and dy.
Sprite Kit (SKView Coordinates):
Yeah, SpriteKit defaults to the right. The Physics Collision sample project solves this by implementing this method:
- (CGFloat)shipOrientation
{
// The ship art is oriented so that it faces the top of the scene, but Sprite Kit's rotation default is to the right.
// This method calculates the ship orientation for use in other calculations.
return self.zRotation + M_PI_2;
}
You can then just get the existing orientation by calling something like:
CGFloat shipDirection = [self shipOrientation];
And then adjust the zRotation property from there.
From the Sprite Kit Programming Guide (emphasis added):
Sprite Kit also has a standard rotation convention. Figure 4-2 shows the polar coordinate convention. An angle of 0 radians specifies the positive x axis. A positive angle is in the counterclockwise direction.
In this coordinate system, an angle of zero radians pointing to the right is correct. If you want to use a system in which a zero angle is straight up (along positive y axis) and increase clockwise, you'll want to transform your angles before converting them to vectors.

Cant Understand Angle of Inclination Calculation using Accelerometer on iPhone

double = rollingZ = acceleration.x;
double = rollingX = acceleration.y;
if (rollingZ > 0.0) {
self.centerCoordinate.inclination = atan(rollingX / rollingZ) + M_PI / 2.0; //LINE 1
}
else if (rollingZ < 0.0) {
self.centerCoordinate.inclination = atan(rollingX / rollingZ) - M_PI / 2.0; // LINE 2
}
else if (rollingX < 0) {
self.centerCoordinate.inclination = M_PI/2.0; //atan returns a radian
}
else if (rollingX >= 0) {
self.centerCoordinate.inclination = 3 * M_PI/2.0;
Im just trying to fully understand this piece of code. I'm looking to build AR apps on the iphone and this code has the function of calculating the angle of inclination of the device using the accelerometer readings.
My understanding is this:
Assuming a portrait orientation if i roll the device forward the x axis of the accelerometer increases towards a negative number of -1.0 (i.e. the device is laid flat with the screen facing up). If i tilt the device towards me the x axis value increases towards a value of 1.0 (until the device is flat facing the ground).
The y axis changes up and down its axis between -1.0 and 0.0 (0 implies the device is horizontal).
If we take some example readings say x = 0.5 (a -45 degree angle, tilting the device towards me) and y = 0.8. If i plotted this on a cartesian coordinate graph with y (rollingX as the vertical axis) and x (rollingZ as the horizontal) and draw a line between them i understand that i can use the reverse tangent function (atan) to calculate the angle. My confusion comes on line 1. I dont understand why that line adds 90 degrees (in radians) to the calculated angle given by the atan function?
I just cant seem to visualise on a graph whats going on. If someone could shed some light on this - that would be much appreciated.
I suppose that these +90 degrees or -90 degrees (in case of negative rollingZ) are added to bring inclination value to widely used Polar coordinate system with angle between -180 and 180 degrees.
Assuming that you have Z line projecting upward when you look at the screen of the device and Z line looking at you from the screen, the result of calculations above vill give you an angle between screen plane and horizontal plane.
Let us assume that acceleration value is positive when it is goes "inside" the device:
1) Device is in vertical position, we have rollingZ = 1, rollingX = 0. The code returns 90 degrees.
2) Device is tilted towards user. Let rollingZ be 0.7 and rollingX be -0.7. This will give us 45 degree angle.
3) Device is in upside-down position, now we have rollingZ = -1 and rollingX = 0, and it is -90 degrees.

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.