Three point angle? [Solved]

This has been giving my quite a bit of trouble lately…

Take the function:

function gridRD(a,b,c)
{
var result = 0.0;

// calculating the 3 distances

var ab = Vector2.Distance(a, b);

var bc = Vector2.Distance(b, c);

var ac = Vector2.Distance(a, c);

var cosB = Mathf.Pow(ac, 2) - Mathf.Pow(ab, 2) - Mathf.Pow(bc, 2);

cosB /= (2 * ab * bc);

result = (Mathf.Acos(cosB) * 180 / Mathf.PI);

return result;
}

This function gets the angle between three points, as displayed in this graph:

If the graph DIDN’T do it for you, let me explain.

Let’s say you have three cubes, all on the same Y position.

This in essence puts us in 2D, so we don’t have to worry about the y position any more.

The three cubes are named p1, p2, and p3.

If you were to draw two lines, from p3, and p1, to p2, ou would get what looks like a geometry arc.

Then, you simply get the angle between th two lines, and viola (I am assuming that’s how you spell it), that is what the function does.

If you still don’t get what I’m saying (Not because you are stupid, but because I am a bad communicator :lol:), please ask for clarification.

If you do… Continue reading.

The problem with the equation, is that it stops at 180, and then starts going back down to 0. For instance, when the actual rotation is 270, the function would return 90. I need it to return 270, and likewise be able to make it to the full 360/359 in a rotation.

This is because it is based on the distance between all three points, and once you get to 180, the points don’t get any further apart.

Could someone present an equation that either modifies the one I have displayed above, or one that pulls of the same effect - except without the 180 degree peak?

well…
If I assume I understood your issue on the geometrical side it’s sure I can’t help for scripting.

Though, maybe could think about a track to do it.

I forget the “x and y” axis mentioned on your graph, we consider here that Y is vertical so we give it up, we’re in 2D.

So, let’s consider that p1 and p2 are aligned along X axis. Above them, Z positive values, below them Z negative values.

You actually need a condition that is if Z position of p3 is lower than Z position of p1 or not.
If it’s higher no problem, that’s the case you already solved, we’re still in our “first” 180 degrees.

If it’s lower (if p3.position.z < p1.position.z) then you must find the added value that is “contained” in the second 180 degrees (that are below the x axis).

In order to get someting that is :
180 ° + (180 - “angle”)

Where “angle” is only the regular value your script already calculates.

Example : how to get 220 ° ?

Your script should :
1/ calcultate “angle”, which would be 140°

2/ get the condition : p3.position.z < p1.position.z

3/ Substract “angle” from 180 (the “below” 180°) : 180 - 140 = 40

4/ Add the “first” 180 ° (the above ones) : 180 + 40 = 220

Hope this helps

Atan2 → Always turns out to be my best friend when attacking this kind of problem. It correctly distinguishes between positive and negative angle (-180 < alpha < 180), and you can use that to get your angle in the full range (0 < alpha < 360). :slight_smile:

For example, I tackled a similar problem (in 3d) with this:

public static float AngleSigned(Vector3 v1, Vector3 v2, Vector3 n)
    {
        return Mathf.Atan2(
            Vector3.Dot(n, Vector3.Cross(v1, v2)), 
            Vector3.Dot(v1, v2)) * Mathf.Rad2Deg;
    }

It takes two directional vectors, and finds the positive or negative angle between them, using the normal vector as the axis. The usual Vector3.Angle method only gives you 0 - 180, while this gives you -180 - 180.

2D should be simpler, but my brain isn’t working properly right now.

2 Likes

Thank you very much! It works like a charm! :smile:

I am trying to measure angles between 3 points in a similar way. I’m currently using the Vector3.Angle logic that I got here but, like you said, this returns weird angles so I thought I’d try the code above. I was wondering if you could explain which normalized Vector 3 gets passed to this function? I know how to get the two directional vectors (by subtracting positions) but not sure about this third one.

I know this post is old so I may start a new thread if this one remains buried… Thanks!

Works like a charm in 2021

why not used
Vector3.Angle
Unity - Scripting API: Vector3.Angle

A similar video: