1
\$\begingroup\$

You can see two points in this picture. Points are surrounded by collider which is set to trigger. Points can either be Vector3 or Vector2, shouldn't make any difference.

I need to get the coords on gray line if mouse enters the trigger, at the exact point where mouse and gray line form 90 degree angle. Gray line is just an straight line between 2 points.

All the data:

  • left point coords
  • right point coords
  • mouse coords

Is it possible with the data I have and how?


enter image description here

\$\endgroup\$
2
\$\begingroup\$

It is possible with the data you have. Let's call the line segment vw and the point p:

vec2 projection_point(vec2 v, vec2 w, vec2 p) {
  const float l2 = length_squared(v, w);  // i.e. |w-v|^2 -  avoid a sqrt
  // Consider the line extending the segment, parameterized as v + t (w - v).
  // We find projection of point p onto the line. 
  // It falls where t = [(p-v) . (w-v)] / |w-v|^2
  // We clamp t from [0,1] to handle points outside the segment vw.
  const float t = max(0, min(1, dot(p - v, w - v) / l2));
  return v + t * (w - v);  // Projection point that falls on the segment
}

This function returns the nearest point on the line segment.

The above code is derived from here: https://stackoverflow.com/questions/849211/shortest-distance-between-a-point-and-a-line-segment

\$\endgroup\$
  • \$\begingroup\$ Thanks, BTW, it returns a position, not the distance. \$\endgroup\$ – James Dunn Sep 10 '18 at 9:45
  • \$\begingroup\$ Ah, never code when you're tired I guess. I'll accept it. \$\endgroup\$ – Sir Sep 10 '18 at 9:55
  • \$\begingroup\$ Worth mentioning, the operation on assigning t a value is a simple clamping; most libraries provide a ready-made implementation of it. \$\endgroup\$ – liggiorgio Sep 10 '18 at 13:38
0
\$\begingroup\$

Here's an answer in C#.

public Vector3 NearestPointOnSegment(Vector3 start, Vector3 end, Vector3 point) {
    Vector3 dir = (end - start);
    dir.Normalize();

    Vector3 v = point - start;
    float dist = Vector3.Dot(v, dir);
    return start + dir * dist;
}

This can be unsafe if there's a chance point could be off the segment. If that's the case and you need to return the closest point on segment anyway, use clamp to either return start or end:

public Vector3 NearestPointOnSegment(Vector3 start, Vector3 end, Vector3 point) {
    Vector3 dir = (end - start);
    dir.Normalize();

    Vector3 v = point - start;
    float dist = Vector3.Dot(v, dir);

    // magnitude takes square root which could be expensive
    // use previous method if your usecase allows
    float length = dir.magnitude;
    dist = Mathf.Clamp(dist, 0f, length);

    pointOnLine = start + dir * dist;
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.