距离 - 求原点到直线的垂足

原理:

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;
        }
    }

}

 

posted @ 2023-11-08 23:11  yanghui01  阅读(35)  评论(0编辑  收藏  举报