• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

[C#] Angle without atan2

Status
Not open for further replies.

Chaosy

Tutorial Reviewer
Level 40
Joined
Jun 9, 2011
Messages
13,219
Hello, in my project I use the following method to get angle between 2 points. However I am not allowed to use Atan2 anymore since my teacher considers it to be a "shortcut method".

JASS:
        public static Vector2 GetStraightPath(Vector2 pos1, Vector2 pos2, float speed)
        {
            Vector2 vec = new Vector2();
            float atan = (float)Math.Atan2(pos2.Y - pos1.Y, pos2.X - pos1.X);
            vec.X = speed * (float)Math.Cos(atan);
            vec.Y = speed * (float)Math.Sin(atan);
            return vec;
        }
 
Level 29
Joined
Jul 29, 2007
Messages
5,174
The definition of the angle between two vectors is:
C++:
cos(theta) = (v1 dot v2) / (|v1||v2|)

theta = acos((v1 dot v2) / (|v1||v2|))

In your case the second vector is always the X axis, so it turns out as:
C++:
theta = acos(v1.x / |v1|)
Note that this will give you different signs depending on the quadrant, since it operates in the range 0 <= theta <= PI, unlike atan2 which operates correctly on the range 0 <= theta <= 2PI.

As to your function - you don't actually need the angle in the first place.
You can normalize the vector pos2-pos1, and scale it by your speed.
 

Chaosy

Tutorial Reviewer
Level 40
Joined
Jun 9, 2011
Messages
13,219
As I get it it does different things depending on the answer.. however I don't get what to do if a condition is met? you return the calculation?
JASS:
            if(Math.Acos(y / x) > 0)
            {
                 return Math.Acos(y / x);
                 //like this?
            }

edit: nvm that is wrong.. then I don't get it :-/

edit2: I read it again so now I suppose the things in the right collum represents the if block. And the left column represents the return value?
571efb70f630041f9e2b00019025171e.png

http://upload.wikimedia.org/math/5/7/1/571efb70f630041f9e2b00019025171e.png
 
Last edited:
Level 29
Joined
Jul 29, 2007
Messages
5,174
Yes to the last edit, that's a common way to write conditional things in math.

But I'll say this again - you don't actually need the angle in this specific case, you already have your vector pos2-pos1, you just need to normalize it.
C++:
velocity = normalize(pos2 - pos1) * speed
 
Level 29
Joined
Jul 29, 2007
Messages
5,174
Look at your function.
First you get the vector pos2 - pos1.
Then you get the angle of it, and construct a new vector with that angle and length=speed.
This is the same as scaling pos2 - pos1 so that it has length=1, and then scaling it by your speed so that you get length=speed.
Scaling a vector so that it has length=1 is called normalizing, and in practice it's done with:
C++:
v / |v|

// Or in other words
v / sqrt(dot(v))

// Or in other words
v / sqrt(v.x*v.x + v.y*v.y)
As in, you divide the vector by its length.

The length of any N dimensional vector can be given with Pythagoras' equation:
C++:
A² + B² = C²

// And so
sqrt(A² + B²) = C
You just need to have all the dimensions in the left side.
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,258
To further emphasise what GhostWolf is saying.

There are two forms of representing a 2D vector. You have it by dimensions (x, y) and by polar form (magnitude, angle). In reality these are both vectors, just in a different state where each dimension has a different meaning. The idea is you can convert between these two forms by passing the vector through the exponential and logarithm operations.

C^2Dvector converts a vector of from (magnitude, angle) to (x, y).
logC(2Dvector) converts a vector of form (x, y) to (magnitude, angle).

This property comes about due to how complex numbers operate. A complex number can be considered a 2Dvector of form (c, j (or i if you are from mathematics)).

What you are currently doing is...
Vector2D (diffx, diffy) = pos2 - pos1
Vector2D (magnitude, angle) = loge(Vector2D (diffx, diffy))
Vector2D (newx, newy) = e^(Vector2D (loge(speed), angle))

What Ghostwolf is proposing...
Vector2D (diffx, diffy) = pos2 - pos1
Vector2D (magnitude, angle) = loge(Vector2D (diffx, diffy))
Vector2D (newx, newy) = Vector2D (diffx, diffy) * speed / e^(magnitude)

How does this work? You know how logarithms convert the complexity of operations...
log(x^y) = y * log(x)
log(x * y) = log(x) + log(y)

The key property used is...
log(x * y) = log(x) + log(y)
log(x / y) = log(x) - log(y)

Vector2D (magnitude, angle) = loge(Vector2D (diffx, diffy))
Vector2D (0, angle) = loge(Vector2D (diffx, diffy)) - Vector2D (magnitude, 0)
Vector2D (loge(speed), angle) = loge(Vector2D (diffx, diffy)) + Vector2D (loge(speed), 0) - Vector2D (magnitude, 0)
Vector2D (loge(speed), angle) = loge(Vector2D (diffx, diffy) * e^(Vector2D (loge(speed), 0)) / e^(Vector2D (magnitude, 0)))

Substitute this in to what you are doing...
Vector2D (newx, newy) = e^(Vector2D (loge(speed), angle))
Vector2D (newx, newy) = e^(loge(Vector2D (diffx, diffy) * e^(Vector2D (loge(speed), 0)) / e^(Vector2D (magnitude, 0))))

e^loge(x) = x

Vector2D (newx, newy) = Vector2D (diffx, diffy) * e^(Vector2D (loge(speed), 0)) / e^(Vector2D (magnitude, 0))

Vectors with only the primary dimension are scalar...
Vector2D (newx, newy) = Vector2D (diffx, diffy) * e^(loge(speed)) / e^(magnitude)
Vector2D (newx, newy) = Vector2D (diffx, diffy) * speed / e^(magnitude)

Which is what Ghostwolf is doing.

e^(magnitude) is Pythagoras triangle hypotenuse length of Vector2D (diffx, diffy).
e^(magnitude) = (diffx^2 + diffy^2)^(1/2)

The reason to do this is (diffx^2 + diffy^2)^(1/2) should be mathematically simpler to compute than computing angle especially since angle is not a single number but an infinite series of numbers in theory for you see.

e^(Vector2D (magnitude, angle)) = e^(Vector2D (magnitude, angle + 2pi)) = e^(Vector2D (magnitude, angle + 4pi)) = e^(Vector2D (magnitude, angle + n * (2pi))) where n is any integer.

Any way of computing even one of these angles must be pretty complicated. When we compute angle for convenience we define it as one number, usually the closest to 0.

angle is in radians and not degrees which is why it involves 2pi and not 360.
 
Level 6
Joined
Aug 26, 2009
Messages
192
This property comes about due to how complex numbers operate. A complex number can be considered a 2Dvector of form (c, j (or i if you are from mathematics)).

This has nothing to do with complex numbers. It's linear algebra. You don't have to explain easy shit with complex stuff just to seem intelligent.

The reason to do this is (diffx^2 + diffy^2)^(1/2) should be mathematically simpler to compute than computing angle especially since angle is not a single number but an infinite series of numbers in theory for you see.
[...]
Any way of computing even one of these angles must be pretty complicated. When we compute angle for convenience we define it as one number, usually the closest to 0.

angle is in radians and not degrees which is why it involves 2pi and not 360.

In mathematics an angle is just a real number. You can define an equivalence relation on it and call 2 angles x and y equivalent if and only if x = y + 2npi for some integer n. All numbers with this property are now put into one set which is usually called an equivalence class.
 
Status
Not open for further replies.
Top