How to check a Vector3 position is between two other Vector3 along a line

Hello

I am struck trying to work out how to check if a Vector3 is between two other Vector3 points.

I get the cross product between the 3 vectors and check the sum is == Vector3.zero thus proving they are on the same line.

But how can i check that Position C is between Position A and B from that ? It’s easy for straight lines but if the line is diagonal i don’t know how to check.

So this is what i got:

///Test Data
        A = (Vector3.right + Vector3.forward) * 5;
        B = (Vector3.forward + Vector3.right) * 10;
        C = (Vector3.forward + Vector3.right) * 2;

// logic below not actual C#:
        onLine = Vector3.Cross(A, B) + Vector3.(A, C) + Vector3(B, C);
        if(onLine == 0)
        {
            // all 3 points are on the same line
            // now check if C is between A and B [ Stuck here ]
        }

Sounds like you want a point to line segment distance test.

1 Like

This will check if point C is between points A and B:

bool IsCBetweenAB ( Vector3 A , Vector3 B , Vector3 C ) {
    return Vector3.Dot( (B-A).normalized , (C-B).normalized )<0f && Vector3.Dot( (A-B).normalized , (C-A).normalized )<0f;
}

Nah

And this will check if points A, B, C are on the same line :

bool AreABCOneTheSameLine ( Vector3 A , Vector3 B , Vector3 C ) {
    return Mathf.Approximately(
        Vector3.Project( A-B , A-C ).magnitude ,
        (A-B).magnitude
    );
}

My thinking here was that when I project one vector onto another it’s magnitude will not change only when it’s parallel to that other vector.
So let’s image that these 3 points are just two separate lines AB and AC and test are they parallel using this method. If that is the case then all 3 points lie on a single line.
Cons:

  • no approximation margin

Another idea (not tested):

bool AreABCOneTheSameLine ( Vector3 A , Vector3 B , Vector3 C ) {
    float precision = 1f / 90f;
    float dotProduct = Vector3.Dot( (A-B).normalized , (A-C).normalized );
    return 1f-dotProduct<precision || 1f-dotProduct > 2f-precision;
}

Pros:

  • approximation margin
5 Likes

This is the answer. It allows you to use a margin of error that you pick, which you will need given that the result for an operation like this will never be perfectly 0.

Unity-ified 3d version of the link I posted, with some error checking.

// Distance to point (p) from line segment (end points a b)
float DistanceLineSegmentPoint( Vector3 a, Vector3 b, Vector3 p )
{
    // If a == b line segment is a point and will cause a divide by zero in the line segment test.
    // Instead return distance from a
    if (a == b)
        return Vector3.Distance(a, p);
      
    // Line segment to point distance equation
    Vector3 ba = b - a;
    Vector3 pa = a - p;
    return (pa - ba * (Vector3.Dot(pa, ba) / Vector3.Dot(ba, ba))).magnitude;
}

note: I’ve not actually tested this, so there might be a typo. :stuck_out_tongue:

3 Likes

Bit confused by this method, if i am checking its on the same line and between A and B what would the float represent ? If the result is a float, wouldn’t 0 mean its distance from the line is 0 and thus it’s on the line?

I should of mentioned, thank fully i don’t need approximation as my vectors are snapped to nearest grid position beforehand.

It’s how close a point is to a line that starts at a and ends at b. If the returned value is zero it is on the line exactly. If your two points are always exactly on the grid, and always aligned along axis, then it’s possible you won’t need any approximation. If the line between the two points is ever at all diagonal, even if their positions are on a grid, then you will need a small amount of slop. How much depends on the distance from 0,0,0, but realistically it can be a really, really small number (like 0.00001).

If you’re worried about that slop allowing points that aren’t between the two points, you can always inset the points towards each other by the slop amount.

Sorry for necrobumping but isn’t this what Epsilon is supposed to solve?

Indeed epsilon is used to solve these kinds of issues. But shaders don’t use any epsilon in the math by default, so you have to implement it yourself if there’s a case where it’s needed. Like this one where you might accidentally divide by zero without it (which would also fail in c++ and c# where Epsilon is used frequently).

1 Like

The link you gave is outdated. Can you explain more about your function. Especially the last line

Why you dot ba with itself?

Thanks in advance.

There are plenty of sites that explain the math behind a point to line segment distance check. If you really want to see that link, try archive.org.
https://web.archive.org/web/20180711090116/http://www.randygaul.net/2014/07/23/distance-point-to-line-segment/

As for doing a dot product of a vector with itself, that’s the equivalent of getting the square magnitude of a vector. But I was directly translating the function from that page rather than thinking about what it was doing.

1 Like

This code doesn’t work (didn’t take the time to figure out why).

I found another function that works:

public static float DistanceLineSegmentPoint(Vector3 start, Vector3 end, Vector3 point)
        {
            var wander = point - start;
            var span = end - start;

            // Compute how far along the line is the closest approach to our point.
            float t = Vector3.Dot(wander, span) / span.sqrMagnitude;

            // Restrict this point to within the line segment from start to end.
            t = Mathf.Clamp01(t);

            Vector3 nearest = start + t * span;
            return (nearest - point).magnitude;
        }

Source: https://gamedev.stackexchange.com/questions/172001/shortest-distance-to-chain-of-line-segments