How can I find a circle angle from x and y axis - c#

Feel free to mark my question duplicated. Because I know absolute nothing about COS, SIN, and TAN and someone else probably already ask this question.
So, I was try to set the circular progress bar based on x and y axis that can get from gamepad input. The progress bar put it simple is just a Minimum of 0 and maximum of 360.
I did try to search a bit, but my best understanding is that it work with only 180 degree and positive x and y. But the input I get from the controller is and y from -1 to 1 (where x -1 is left and 1 is right, y -1 is bottom and 1 is top)
Here is my code so far.
var controller = Windows.Gaming.Input.Gamepad.Gamepads[0].GetCurrentReading();
x = controller.LeftThumbstickX
y = controller.LeftThumbstickY
//what do I have to do from here?
progress.Value = angle; //?

The trigonometric function atan2 is the tool for this job. In C#, this is implemented by Math.Atan2 :
double angleInRadians = Math.Atan2(y, x);
double angleInDegrees = (180 / Math.PI) * angleInRadians;
Using this formula with (for instance) parameters (1,1), you'll get a result of 45.
However, in terms of polar alignment, this angle measures anti-clockwise from "east". To convert this to an angle that measures clockwise from "north":
double compassRadians = Math.PI / 2 - angleInRadians;
double compassDegrees = (180 / Math.PI) * compassRadians;
but now we may encounter negative values, so we can normalize them with the following method:
double normalizeDegrees(double a) => ((a % 360) + 360) % 360; //convert to 0-360
then
var compassAngle = normalizeDegrees(compassDegrees);

The method you want is Math.Atan2. This takes two arguments - the y-value first, then the x-value - and it gives you an angle in radians.
Since you want an angle in degrees, you'll need to convert - the conversion factor is 180 / Math.PI. So you'll be using something like:
var radiansToDegrees = 180 / Math.PI;
progress.Value = Math.Atan2(y,x) * radiansToDegrees;
Depending exactly what combination of x and y needs to correspond to 0 you might need to add a number of degrees on afterwards. This as-is will give you 0 degrees for x = 1, y = 0, and 90 degrees for x = 0, y = 1, etc.

Related

Atan2 is giving the false angle when object's y or z change in Unity

I wrote a algorithm. Its normally working.
Just i can not get right angle of x when y or z changes
float x = Mathf.Atan2(transform.forward.y, transform.forward.z) * Mathf.Rad2Deg
This code is giving the right angle when my object angles are (x,0,0).
But when the y or z change(x,35,46), this code is giving false angle.
By the way i want to get 0-360 angle.
If i get this angle, code will work(i tested it).
So i am trying to get the rotation of x axis 0-360.
But the atan2 is not giving the right value.
Maybe i can use Vector3.Angle but it doesn't work that i want.
I don't ask too many questions in stackoverflow so if you didn't understand please tell me which part didn't you get it?
If I understand you correct you want the objects rotation around the X axis (global or local).
You could probably simply use Transform.eulerAngles something like
var x = transform.eulerAngles.x;
if(x < 0) angle += 360;
Or if you want the local rotation (relative to the parent) Transform.localEulerAngles
var x = transform.localEulerAngles.x;
if(x < 0) angle += 360;
No, I wouldn't figured out
int sign = (transform.forward.y<0) ? 1 : -1;
float x = (Vector3.Angle(transform.position, transform.forward) - 38) * sign * 180 / 100;
This code is just working on 0,90,0 angle
I still can not reach the right angle when the rotation change
I found some code with the combination of Cross,Dot,Angle:
float Angle360(Vector3 v1, Vector3 v2, Vector3 n)
{
float angle = Vector3.Angle(v1,v2);
float sign = Mathf.Sign(Vector3.Dot(n, Vector3.Cross(v1, v2)));
float signed_angle = angle * sign;
return (signed_angle + 180) % 360;
}
This code is not working too
It will be made probably with Vector3.Angle or Dot vs.
How can i find right angle with Vector3.Angle,
The value 38 is changing
Vector3.Angle(transform.position, transform.forward)
This code is showing the angle but when the rotation change it gives false value.
how can i get the angle of x when objects look change.
So this code is giving right when the value is x,0,0.
Mathf.Atan2(transform.forward.y, transform.forward.z) * Mathf.Rad2Deg
I think i am not using Vector3.Angle Correctly
I need to get the x value when the y and z values are different

Calculate point/coordinate from distance and bearing

Maths is not my strong suit and I think I have something mixed up here but I cannot figure out what.
I'm just trying to populate 2 new coordinates given a number of variables and constants.
if I make Origin coordinate 5,5 and Destination coordinate 10,5, I can work out that distance =5 and that the bearing from Origin to Destination is 90 using these two functions:
private static double GetDistance(PointF point1, PointF point2)
{
double a = (double)(point2.X - point1.X);
double b = (double)(point2.Y - point1.Y);
return Math.Sqrt(a * a + b * b);
}
public static double GetBearing(PointF coord1, PointF coord2)
{
double result = 0.0;
result = Math.Atan2(coord2.X - coord1.X, coord2.Y - coord1.Y) * (180 / Math.PI); //- Math.Atan2(coord4.y - coord3.y, coord4.x - coord3.x))
if (result < 0)
{
result = result + 360;
}
return result;
}
What I want to be able to do given an offset Distance of xd=1 and an offset bearing of 180(ie directly opposite direction to the destination) is plot the location 4,5. I'd also like to be able to feed a different offset bearing in of say 90 and plot 5,6.
Here's what I've tried but I get completely nonsensical values.
public static PointF CalculateCoordinate(double Angle, double Distance)
{
PointF coord = new PointF(Convert.ToSingle(Distance * Math.Cos(Angle)), Convert.ToSingle(Distance * Math.Sin(Angle)));
return coord;
}
and CalculateCoordinate(GetBearing(Destination, Origin),1) to reverse the bearing directly 180. I've tried this CalculateCoordinate(90,1) to calculate an offset to the side but that's not working either.
Where have I gone wrong, I'm sure it's something pretty stupid and simple.
There's two mistakes that I can see. First, Atan2 takes the Y value for the first parameter and the X value for the second:
Math.Atan2(coord2.Y - coord1.Y, coord2.X - coord1.X) * (180 / Math.PI);
Secondly, you're converting from radians to degrees in GetBearing, but you're not converting Angle from degrees to radians inside CalculateCoordinate e.g:
Math.Cos(Angle * (Math.PI / 180))

Calculating the angle of an orthogonal triangle using the Arcsin in C#

I have the following code:
double x = sw.bonePos[0, (int)Bones.HipCenter].x;
double z = sw.bonePos[0, (int)Bones.HipCenter].z;
double hypotenusePower2 = Math.Pow(x, 2) + Math.Pow(z, 2);
double hypotenuse = Math.Sqrt(hypotenusePower2);
double angle = Math.Asin(z / hypotenuse);
I know that x,z, hypotenuse are correct and z / hypotenuse is correct because its always between -1 and 1. So I want to find the angle using the ArcSin like this but when I am printing for example Math.Asin(1) the result is 1.5707...
Am I using the wrong function? Is there any function in C# that returns the angle?
Example of input/output:
x: -0.000844396417960525
z: 0.857428431510925
hypotenuse: 0.857428847292063
angle: 1.5698115260652
x: 0.0198930986225605
z: 0.849016189575195
hypotenus: 0.849249212854266
angle: 1.54736984845028
The result you get is correct - asin of 1 is half of π, or approximately 1.5707 radians.
Functions returning angles usually return the results in radians. If you need the result in degrees, you need to convert the result as follows:
double degrees = angle * ( 180 / Math.Pi );
That's the right answer. The resulting angle is measured in radians. Math.Asin(1) should therefore be equal to π/2 &approx; 1.5707 radians, which matches your result.
If you wanted the value in degrees, multiply by 180/π. In this case, π/2 * 180/π would give you 90 degrees:
double degrees = radians * (180 / Math.Pi);

I understand that Sin and Cos are in radians, but why I am still off by 90 degrees?

Let's say I have the values X = 0, Y = 0 and I want to calculate a new point (X1, Y1) from a vector and a magnitude. Let's say the vector is 90 degrees (not radians) and the magnitude is 10 so the code would look something like this:
x1 = X + (10 * Math.Cos(90 * (Math.PI / 180.0)));
y1 = Y + (10 * Math.Sin(90 * (Math.PI / 180.0)));
And I then draw a line to confirm the results
DrawLine(X,Y,x1,y1);
But my line is off by 90 degrees too much! If I subtract 90 from the angle that I'm passing to Cos and Sin everything works out fine. So, I guess, I can live with that.
Here's a screen shot:
I'm passing it 90 and I'm expecting the line to go west - east. I assume that 0 degrees is due north. I know that the coordinate system I'm using is X is horizontal and Y is vertical.
I'm just curious as to what I'm missing.
Unexpected integer truncation
The conversion from degrees to radians resulted in a value near pi/2, but not exactly. (Hard to do as pi is transcendental.) Math.Cos(near_pi/2) resulted in a value near 0.0, but not _exactly 0.0. Let's assume it was negative like -6.1e-17.
Assuming 'X' was a floating point number with an integer value, the result of X + small_negative_number was a number just less than the integer value. Assigning that result to x1 and giving it to the plot() routine, which certainly uses integer values caused a integer truncation down to the next lower integer.
Thus the expected straight line is 1 pixel off.
The general solution is to present plot(x,y) with integer values that are derived from rounded floating point values.
x_int = round(X_floating_point);
I don't see any problem about the x and y.
You use COS for x. COS(0) = 1 , COS(90) = 0
You use SIN for y. SIN(0) = 0 , SIN(90) = 1
And for the screen coordinate system:
x+ is left to right
y+ is top to bottom
Thats why the line goes from top to bottom.
As you can see, the line isn't nice and straight. Follow the declaration of Math.PI and you will see: public const double PI = 3.14159 (I don't know whois responsible for this, but I would fire him). That isn't very accurate! Try to replace the PI with: 3.14159265358979323846
Makes:
public const double BETTER_PI = 3,14159265358979323846
x1 = X + (10 * Math.Cos(90 * (BETTER_PI / 180.0)));
y1 = Y + (10 * Math.Sin(90 * (BETTER_PI / 180.0)));
So:
x1 = X + (10 * Math.Cos(1.57079632679)) = X + (10 * 0) = X + 0;
y1 = Y + (10 * Math.Sin(1.57079632679)) = Y + (10 * 1) = Y + 10;
UPDATE:
As Chis says, the meta data is wrong. So use the Math.PI

C# 2D Vector Movement - speed and direction

I'm doing a (probably simple) task, in which i want to make a drawed object move to a user-controlled (drawed too). All i have is the players X and Y coördinate, defined as respectively Xp and Yp. The object that has to move (after trigger, not included in code down here) to the 'player-object' has its coördinates defined in this.X and this.Y.
int xDirection = Xp - this.X;
int yDirection = Yp - this.Y;
int angleInDegrees = (int)Math.Atan2(xDirection, yDirection);
double radians = (Math.PI / 180) * angleInDegrees;
double xTmp = 3 * Math.Cos(radians);
int xSpeed = (int)xTmp;
double yTmp = 3 * Math.Sin(radians);
int ySpeed = (int)yTmp;
Console.WriteLine(xDirection);
Console.WriteLine(yDirection);
Console.WriteLine(xSpeed);
Console.WriteLine(ySpeed);
Console.ReadLine();
This doesn't give me the right figures, so i was wondering what may be wrong.
The toughest bit about this probably the fact that the object that has to move to the playerobject may be approached from all the sides (360 degrees) but there's no angle of approach available.
I hope to be complete with my question,
Tim
I'm betting the main problem you're seeing is this line:
int angleInDegrees = (int)Math.Atan2(xDirection, yDirection);
As #catflier mentioned, Math.Atan2 returns the angle in radians (so a number ranging from 0 to 2pi). However, you perform a cast to int which will truncate the decimal places. So if your angle was at 45 degrees, that's actually returning ~0.785398 radians. A cast to int will turn it into 0. Similarly, at 90 degrees, that's ~1.570796 radians, a cast to int will result in 1. That's significant round-off error. As I mentioned in my comment, consider changing all your types to doubles and only perform integer casts at the last point possible (I suppose your objects are positioned based on integers).
Math.Atan2 returns a value in radians, so are other c# trigonometric functions.
double angle = Math.Atan2(yDirection, xDirection);
Also make sure to force type casts to decimals:
3.0 * Math.Cos(radians);

Categories

Resources