写在前面
这两天做开发的时候,有个小伙伴问我怎么计算点到直线的最短距离,看样子困扰了他挺久,所以借这个机会吧这个问题记录下来,让更多小伙伴能涨一下姿势。
先看图:已知条件如下,p1、p2、target三个点,求红色线段的距离。
解题思路
思路1:向量投影法
这个方法核心问题是计算出target到p12向量上距离最短的点,然后通过Vector3.Distance方法计算得出最短距离。
那么如何找到这个点呢?这里,我用了向量投影。
1.先计算出target到p1的向量(蓝色线段)
2.再计算出p2到p1的向量(绿色线段)
3.通过Vector3.Project方法,计算出蓝色线段在绿色线段上的投影,这个投影就是p1F向量
4.将计算出来的投影向量再加上p1点的坐标,即使F点的坐标。
5.最后Vector3.Distance(target,F)即可计算出距离
代码如下:
/// <summary>
/// 向量投影法
/// </summary>
public void ProjectFunc(Vector3 p1, Vector3 p2, Vector3 target)
{
//p1->p2的向量
Vector3 p1_2 = p2 - p1;
//p1->target向量
Vector3 p1_target = target - p1;
//计算投影p1->f
Vector3 p1f = Vector3.Project(p1_target, p1_2);
//加上p1坐标 然后计算距离
float distance = Vector3.Distance(target, p1f + p1);
Debug.Log("向量投影法:" + distance);
}
思路2:三角函数法
这个方法,就是通过Sin(夹角)*斜边长度计算直角边的距离
1.先计算出target到p1的向量(蓝色线段)
2.再计算出p2到p1的向量(绿色线段)
3.计算前面两个向量的夹角Vector3.Angle(p1_2, p1_target);
4.获取斜边长度(蓝色线段)
5.通过Sin函数*斜边长度计算出距离
代码如下:
/// <summary>
/// 三角函数
/// </summary>
public void TriangleFunc(Vector3 p1, Vector3 p2, Vector3 target)
{
//p1->p2的向量
Vector3 p1_2 = p2 - p1;
//p1->target向量
Vector3 p1_target = target - p1;
//前面两个向量的夹角
float angle = Vector3.Angle(p1_2, p1_target);
//获取斜边的长度
float distance_p1_target = p1_target.magnitude;
//Sin函数计算距离
float distance = Mathf.Sin(angle * Mathf.Deg2Rad) * distance_p1_target;
Debug.Log("三角函数法:" + distance);
}
思路3:面积法
这个方法主要是通过平行四边形面积公式来计算出该距离 底 * 高 = 面积
现在我们知道了一条底边的长度(绿色线段),还差面积不知道
这里通过向量叉乘,获取叉乘结果的模就可以(叉乘出来的结果是个向量,向量的长度即为两个叉乘向量所形成的平行四边形的面积)
1.先计算出target到p1的向量(蓝色线段)
2.再计算出p2到p1的向量(绿色线段)
3.两个向量叉乘,获取的结果取长度,即为平行四边形的面积
4.然后 高 = 面积 / 底 得出距离
代码如下:
/// <summary>
/// 叉乘面积
/// </summary>
public void CrossAreaFunc(Vector3 p1, Vector3 p2, Vector3 target)
{
//p1->p2的向量
Vector3 p1_2 = p2 - p1;
//p1->target向量
Vector3 p1_target = target - p1;
//两个向量叉乘结果取长度 用做面积
float area = Vector3.Cross(p1_2, p1_target).magnitude;
//面积/底边计算出高度
float distance = area / p1_2.magnitude;
Debug.Log("叉乘面积法:" + distance);
}
最后
这里展示了三种获取点到线的最短距离的方式方法,运行结果也都一致,这里做一个记录,希望能帮助到需要帮助的小伙伴。