Jaskaran Singh
Jaskaran Singh

Reputation: 35

Can't find the angle object is moving in radians

I have been making a mod for a game called Minecraft PE and I'm using it to learn. Before I show my code I want you to know that Y is the vertical axis and X and Z is horizontal. Here is some code I used:

Math.asin(Math.sin((fPosXBeforeMoved - sPosX) /
Math.sqrt(Math.pow(fPosXBeforeMoved - sPosX, 2) + 
Math.pow(fPosZBeforeMoved - sPosZ, 2))));

I didn't use tan because sometimes it returns something like NaN at a certain angle. This code gives us the sine of the angle when I clearly used Math.asin. angle is a value between -1 and 1, and it works! I know it works, because when I go past the Z axis I was expecting and it did switch from negative to positive. However, I thought it's supposed to return radians? I read somewhere that the input is radians, but my input is not radians. I really want the answer to how my own code works and how I should have done it! I spent all day learning about trigonometry, but I'm really frustrated so now I ask the question from where I get all my answers from!

Can someone please explain how my own code works and how I should modify it to get the angle in radians? Is what I've done right? Am I actually giving it radians and just turned it into some sort of sine degrees type thing?

Upvotes: 3

Views: 392

Answers (1)

rayryeng
rayryeng

Reputation: 104504

OK, let's give a quick refresher as to what sin and asin are. Take a look at this right-angle triangle in the diagram below:

Source: Wikipedia

By taking a look at point A of this right-angle triangle, we see that there is an angle formed between the line segment AC and AB. The relationship between this angle and sin is that sin is the ratio of the length of the opposite side over the hypotenuse. In other words:

sin A = opposite / hypotenuse = a / h

This means that if we took a / h, this is equal to the sin of the angle located at A. As such, to find the actual angle, we would need to apply the inverse sine operator on both sides of this equation. As such:

A = asin(a / h)

For example, if a = 1 and h = 2 in our triangle, the sine of the angle that this right triangle makes between AC and AB is:

sin A = 1 / 2

To find the actual angle that is here, we do:

A = asin(1 / 2)

Putting this in your calculator, we get 30 degrees. Radians are another way of representing angle, where the following relationship holds:

angle_in_radians = (angle_in_degrees) * (Math.PI / 180.0)

I'm actually a bit confused with your code, because you are doing asin and then sin after. A property between asin and sin is:

arcsin is the same as asin. The above equation states that as long as x >= -Math.PI / 2, x <= Math.PI / 2 or x >= -90, x <= 90 degrees, then this relationship holds. In your code, the argument inside the sin will definitely be between -1 to 1, and so this actually simplifies to:

(fPosXBeforeMoved - sPosX) / Math.sqrt(Math.pow(fPosXBeforeMoved - sPosX, 2) + 
Math.pow(fPosZBeforeMoved - sPosZ, 2));

If you want to find the angle between the points that are moved, then you're not using the right sides of the triangle. I'll cover this more later.


Alright, so how does this relate to your question? Take a look at the equation that you have in your code. We have four points we need to take a look at:

  • fPosXBeforeMoved - The X position of your point before we moved
  • sPosX - The X position of your point after we moved
  • fPosZBeforeMoved - The Z position of your point before we moved
  • sPosZ - The Z position of your point after we moved.

We can actually represent this in a right-angle triangle like so (excuse the bad diagram):

enter image description here

We can represent the point before you moved as (fPosXBeforeMoved,fPosZBeforeMoved) on the XZ plane, and the point (sPosX,sPosZ) is when you moved after. In this diagram X would be the horizontal component, while Z would be the vertical component. Imagine that you are holding a picture up in front of you. X would be the axis going from left to right, Z would be the axis going up and down and Y would be the axis coming out towards you and going inside the picture.

We can find the length of the adjacent (AC) segment by taking the difference between the X co-ordinates and the length of the opposite (AB) segment by taking the difference between the Z co-ordinates. All we need left is to find the length of the hypotenuse (h). If you recall from school, this is simply done by using the Pythagorean theorem:

h^2 = a^2 + b^2
h = sqrt(a^2 + b^2)

Therefore, if you refer to the diagram, our hypotenuse is thus (in JavaScript):

Math.sqrt(Math.pow(fPosXBeforeMoved - sPosX, 2) + Math.pow(fPosZBeforeMoved - sPosZ, 2));

You'll recognize this as part of your code. We covered sin, but let's take a look at cos. cos is the ratio of the length of the adjacent side over the hypotenuse. In other words:

cos A = adjacent / hypotenuse = b / h

This explains this part:

(sPosX - fPosXBeforeMoved) / Math.sqrt(Math.pow(sPosX - fPosXBeforeMoved, 2) + 
Math.pow(sPosZ - fPosZBeforeMoved, 2));

Take note that I swapped the subtraction of sPosX and fPosXBeforeMoved in comparison to what you had in your code from before. The reason why is because when you are examining the point before and the point after, the point after always comes first, then the point before comes second. In the bottom when you're calculating the hypotenuse, this doesn't matter because no matter which order the values are subtracted from, we take the square of the subtraction, so you will get the same number anyway regardless of the order. I decided to swap the orders here in the hypotenuse in order to be consistent. The order does matter at the top, as the value being positive or negative when you're subtracting will make a difference when you're finding the angle in the end.

Note that this division will always be between -1 to 1 so we can certainly use the inverse trigonometric functions here. Finally, if you want to find the angle, you would apply the inverse cosine. In other words:

Math.acos((sPosX - fPosXBeforeMoved) / Math.sqrt(Math.pow(sPosX - fPosXBeforeMoved, 2)
+ Math.pow(sPosZ - fPosZBeforeMoved, 2)));

This is what I believe you should be programming. Take note that this will return the angle in radians. If you'd like this in degrees, then use the equation that I showed you above, but re-arrange it so that you are solving for degrees instead of radians. As such:

angle_in_degrees = angle_in_radians * (180.0 / Math.PI)

As for what you have now, I suspect that you are simply measuring the ratio of the adjacent and the hypotenuse, which is totally fine if you want to detect where you are crossing over each axis. If you want to find the actual angle, I would use the above code instead.


Good luck and have fun!

Upvotes: 3

Related Questions