Unity3D C#数学系列之求点到直线的距离

Unity3D C#数学系列之求点到直线的距离

2020年9月6日 0 作者 老王

1 引言

之前写的博客里面有好多坑没有填,以后慢慢填吧。
最近想到可以总结点和数学相关的东西,自己觉得挺有意思的。目前想到的可以总结点有:

  • 求空间中一点到两点所在直线的距离
  • 求空间过一点到两点所在直线的垂线
  • 求两条直线的交点
  • 已知一个圆,并给出圆上一点,求该点在圆上的切线
  • 求三点所在平面的法线方向
  • 判断一点是否在圆弧范围内
  • 判断一点是否在矩形内部
  • 判断一点是否在长方体、球体、圆柱体内部
  • 网格绘制长方体、球体、胶囊体

这里,我们先看看"求空间中一点到两点所在直线的距离"

2 分析

点到直线距离示例图
如图,已知A1、A2、B点的坐标,求B点到A1A2所在直线的距离,即BO的长度。
分析:

  1. 三个点的坐标已知,则BA2这条线段的长度已知,在代码中直接使用Vector3.Distance即可
  2. 同时A2A1、A2B这两条向量也能求出,则θ的角度值也能求出,在代码中使用点积即可
  3. 那么,BO = |A2B|*sinθ

3 代码

3.1 求两点的距离

直接使用Vector3.Distance,即可求出。

float distance = Vector3.Distance(a, b);

3.2 向量的点积求夹角

直接看公式。
向量点积公式
分解一下,要求到θ,需要以下几个步骤

  • 求点积,两个坐标相减求得向量,然后直接使用Vector3.Dot求得点积
    Vector3 a2B = m_PointB - m_PointA2;
    Vector3 a2A1 = m_PointA1 - m_PointA2;
    float dotResult = Vector3.Dot(a2B, a2A1);
  • 求向量的模,直接使用Vector3.magnitude即可,如
a2B.magnitude
  • 反Cos求出θ,直接使用Matfh.Acos
float seitaRad = Mathf.Acos(dotResult / (a2B.magnitude * a2A1.magnitude));

这里有一点要注意,Mathf.Acos求出的θ是用弧度值(rad)表示的,弧度值和我们平时喜欢用的0°、180°的关系是
Π弧度 = 180°
如下表

90° 180° 270° 360°
弧度 0 Π/2 Π 3Π/2

在代码中弧度值和角度值的换算直接乘以Mathf.Rad2Deg(弧度值转换为角度值,2表示to的意思)或Mathf.Deg2Rad(角度值转换为弧度值),如下。

// 弧度值转换为角度值
float angle = seitaRad * Mathf.Rad2Deg;
// 角度值转换为弧度值
float rad = angle * Mathf.Deg2Rad;

3.3 完整代码

private float DistanceFromPoint2Line(Vector3 p, Vector3 p1, Vector3 p2)
{
    // 求A2B的距离
    float p2pDistance = Vector3.Distance(p2, p);    // 或者使用 p2p.magnitude
    Vector3 p2p1 = p2 - p1;
    Vector3 p2p = p2 - p;
    // 求p2p1·p2p
    float dotResult = Vector3.Dot(p2p1, p2p);
    // 求θ
    float seitaRad = Mathf.Acos(dotResult / (p2p1.magnitude * p2pDistance));
    // 求p点到p1p2的距离
    float distance = p2pDistance * Mathf.Sin(seitaRad);
    return distance;
}

4 项目

效果如下。
点到直线的距离效果图
这次我们仅仅求到了BO的距离,那可否将O点的位置也求出来呢?当然是可以的。
因为OB的长度都求到了,同理可求得OA2的距离(OA2=|BA2|)或者直接使用勾股定理,然后由于A2A1的方向已知,所以O点的坐标 = A2+A2A1的单位向量*|OB|即可。
项目上传到这里啦。
链接:https://pan.baidu.com/s/1BtRYbhu_YwGS5ol8ryMO6Q
提取码:oea8