Как найти ближайшую точку на линии?
У меня есть точка (A) и вектор (V) (предположим, что это бесконечная длина), и я хочу найти ближайшую точку (B) на линии к моей исходной точке (A). Какое простейшее выражение использует Unity Vector2 или Vector3, чтобы получить это?
6 ответов
Бесконечная длина:
Если у вас есть линия бесконечной длины с началом и направлением, вычислите произведение точки на направление линии, затем умножьте ее на направление и добавьте к ней начальную точку.
public Vector2 FindNearestPointOnLine(Vector2 origin, Vector2 direction, Vector2 point)
{
direction.Normalize();
Vector2 lhs = point - origin;
float dotP = Vector2.Dot(lhs, direction);
return origin + direction * dotP;
}
Конечная длина:
Если у вас есть линия с конечной длиной с начальными и конечными позициями, получите заголовок выполнения проекции от начальной точки до. Также используйте Mathf.Clamp
хлопать на всякий случай, если линия отключена.
public Vector2 FindNearestPointOnLine(Vector2 origin, Vector2 end, Vector2 point)
{
//Get heading
Vector2 heading = (end - origin);
float magnitudeMax = heading.magnitude;
heading.Normalize();
//Do projection from the point but clamp it
Vector2 lhs = point - origin;
float dotP = Vector2.Dot(lhs, heading);
dotP = Mathf.Clamp(dotP, 0f, magnitudeMax);
return origin + heading * dotP;
}
// For finite lines:
Vector3 GetClosestPointOnFiniteLine(Vector3 point, Vector3 line_start, Vector3 line_end)
{
Vector3 line_direction = line_end - line_start;
float line_length = line_direction.magnitude;
line_direction.Normalize();
float project_length = Mathf.Clamp(Vector3.Dot(point - line_start, line_direction), 0f, line_length);
return line_start + line_direction * project_length;
}
// For infinite lines:
Vector3 GetClosestPointOnInfiniteLine(Vector3 point, Vector3 line_start, Vector3 line_end)
{
return line_start + Vector3.Project(point - line_start, line_end - line_start);
}
Vector3 GetPoint(Vector3 p, Vector3 a, Vector3 b)
{
return a + Vector3.Project(p - a, b - a);
}
Для бесконечных строк
private Vector3 GetPointOnLine(Vector3 lineOrigin, Vector3 lineDirection, Vector3 point)
=> lineOrigin - point - Vector3.Dot(lineOrigin - point, lineDirection) * lineDirection;
Укажите начало и направление вашей линии, а также точку, к которой вы хотите найти ближайшую точку, и вуаля...
Я предполагаю, что вы не знаете местоположения обеих точек, поскольку решение, чтобы найти расстояние между двумя известными точками - простое вычитание. Если вы хотите найти расстояние динамически, я бы предложил использовать raycasting
,
Добавление такого сценария в GameObject, который вы считаете pointA
может работать на вас:
using UnityEngine;
public class Raycasting : MonoBehaviour
{
[SerializeField]
private LayerMask pointMask; //Set this to the same tag as any GameObject you consider a "point"
private Vector2 pointA, distance;
private void Update()
{
CheckForPoint();
Debug.Log(distance);
}
private void CheckForPoint()
{
pointA = transform.position; //The GameObject's current position in the world
RaycastHit2D pointB = Physics2D.Raycast(pointA, Vector2.right * Mathf.Sign(transform.localScale.x), Mathf.Infinity, pointMask);
//Draws a visible ray in the game view (must have gizmos enabled)
Debug.DrawRay(pointA, Vector2.right * Mathf.Sign(transform.localScale.x), Color.green);
if (pointB)
{
distance = (Vector2)pointB.transform.position - pointA;
}
}
}
Убедитесь, что на точках, которые вы ищете, есть коллайдер; Затем вы можете установить расстояние от Raycast до Mathf.Infinity
(или любой другой длины, которую вы хотите), и pointB
будет первым объектом, с которым сталкивается луч.
Вы можете прочитать больше о Physics2D.Raycast
API здесь, хотя тот же подход будет работать и в 3D.
public Vector2 FindNearestPointOnLine(Vector2 origin, Vector2 end, Vector2 point)
{
//Get heading
Vector2 heading = (end - origin);
float magnitudeMax = heading.magnitude();
heading = Vector2.Normalize(heading);
//Do projection from the point but clamp it
Vector2 lhs = point - origin;
float dotP = Vector2.Dot(lhs, heading);
dotP = UnityEngine.Mathf.Clamp(dotP, 0f, magnitudeMax);
return origin + heading * dotP;
}
vector2.величина не найдена