距离 - 求原点到直线的垂足
原理:
1) 求出向量ao在ab上的投影距离
2) a沿着ab方向移动投影距离就是垂足点的位置
// 获得原点到直线ab的垂点 public static Vector2 GetPerpendicularToOrigin(Vector2 a, Vector2 b) { var ab = b - a; var ao = Vector2.zero - a; float proj = Vector2.Dot(ab, ao) / ab.sqrMagnitude; //ao在ab上的投影, 这边多除了|ab| return a + ab * proj; //再把|ab|乘回来 }
直线方程方式求垂足(较慢)
// 获得原点到直线ab的垂点 - 直线方程方式 public static Vector2 GetPerpendicularToOrigin2(Vector2 a, Vector2 b) { var ab = b - a; var c = Vector2.zero; var abNormal = new Vector2(-ab.y, ab.x); var d = c + abNormal; IsTwoLineIntersect(a, b, c, d, out var point); return point; }
效果
测试代码
using System; using UnityEditor; using UnityEngine; public class PerpToOriginTest : CollideTestBase { //直线上点A, B public Transform m_A; public Transform m_B; public Vector2 m_Perp; private bool m_IsUpdateRunning = false; private Vector3 m_CubeSize = new Vector3(0.02f, 0.02f, 0.01f); void Update() { m_IsUpdateRunning = true; if (m_A && m_B) { var t1 = DateTime.Now; switch (m_ApiType) { case 1: for (int i = 0; i < m_InvokeCount; ++i) m_Perp = Shape2DHelper.GetPerpendicularToOrigin(m_A.position, m_B.position); break; case 2: for (int i = 0; i < m_InvokeCount; ++i) m_Perp = Shape2DHelper.GetPerpendicularToOrigin2(m_A.position, m_B.position); break; } CheckTimeCost(t1, 2); } } private void OnDrawGizmos() { if (m_A && m_B) { var a = (Vector2)m_A.position; var b = (Vector2)m_B.position; Gizmos.DrawLine(a, b); if (m_IsUpdateRunning) { DrawHelpLines(ref a, ref b); Gizmos.color = Color.green; float handleSize = HandleUtility.GetHandleSize(m_Perp) * 0.1f; m_CubeSize.Set(handleSize, handleSize, 0.01f); Gizmos.DrawCube(m_Perp, m_CubeSize); //垂足用矩形点表示 Gizmos.color = Color.white; } } } private void DrawHelpLines(ref Vector2 a, ref Vector2 b) { Gizmos.color = Color.gray; Gizmos.DrawLine(Vector2.zero, m_Perp); //原点到垂足的线 var ao = Vector2.zero - a; var ab = b - a; if (Vector2.Dot(ao, ab) < 0) //投影小于0, 垂足在ba方向延伸 { Gizmos.DrawLine(a, m_Perp); //垂足不在线段上, 延长线段的a return; } var bo = Vector2.zero - b; var ba = -ab; if (Vector2.Dot(bo, ba) < 0) //投影小于0, 垂足在ab方向延伸 { Gizmos.DrawLine(b, m_Perp); //垂足不在线段上, 延长线段的b return; } } }