点到某三角形的最短距离
程序员文章站
2021-12-23 19:42:54
...
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MathPoint2Panel : MonoBehaviour
{
public Vector3 p1 = Vector3.zero;
public Vector3 p2 = new Vector3(50, 0, 0);
public Vector3 p3 = new Vector3(50, 0, 50);
public Transform point;
public Vector3 pt = Vector3.zero;
public float t0;
public float t1;
public float test1;
public Vector3 docNormal;
public void Update()
{
Debug.DrawLine(transform.position + p1, transform.position + p2);
Debug.DrawLine(transform.position + p2, transform.position + p3);
Debug.DrawLine(transform.position + p3, transform.position + p1);
Vector3 pa = transform.position + p1;
Vector3 pb = transform.position + p2;
Vector3 pc = transform.position + p3;
// [V0, V1]
Vector3 V0 = pb - pa;
Vector3 V1 = pc - pa;
// Pt = pa + (V0 * t0 + V1 * t1) // 任意一点都能如此表达
Vector3 p = point.position;
// p - pt = p - pa - (V0 * t0 + V1 * t1)
// 法向量于V0基 垂直 为 0
// Vector3.Dot(p - pt, V0) = 0
// Vector3.Dot(p - pt, V1) = 0
// (p - pa) * V0 = V0 * V0 * t0 + V1 * V0 * t1
// (p - pa) * V1 = V0 * V1 * t0 + V1 * V1 * t1
// Pt = P0 + t0 * v0 + t1 * v1
float A = Vector3.Dot((p - pa) , V0);
float B = Vector3.Dot((p - pa) , V1);
float C = Vector3.Dot(V1, V0);
float D = Vector3.Dot(V0, V1);
float E = Vector3.Dot(V0, V0);
float F = Vector3.Dot(V1, V1);
// A = V0 * V0 * t0 + V1 * V0 * t1
// B = V0 * V1 * t0 + V1 * V1 * t1
// A = E * t0 + C * t1;
// B = D * t0 + F * t1;
// t0 = (A - C * t1) / E;
// B = D * (A - C * t1) / E + F * t1;
// B * E = D * (A - C * t1) + F * E * t1;
// B * E - D * A = F * E * t1 - D * C * t1 ;
t1 = (B * E - D * A) / (F * E - C * D);
t0 = (A - C * t1) / E;
// 判断是否在三角形内
if (t0 >= 0 && t0 <= 1 && t1 >= 0 && t1 <= 1 && t0 + t1 < 1)
{
pt = pa + (t0 * V0 + t1 * V1); // 带入公式
}
else
{
Vector3 closed1 = Vector3.zero;
Vector3 closed2 = Vector3.zero;
Vector3 closed3 = Vector3.zero;
// 分别求出对三条边的最短距离
float c1 = FindDistance2Segment(p, pa, pb, out closed1);
float c2 = FindDistance2Segment(p, pa, pc, out closed2);
float c3 = FindDistance2Segment(p, pb, pc, out closed3);
float min = Mathf.Min(c1, c2, c3);
if (min == c1)
{
pt = closed1;
}
else if(min == c2)
{
pt = closed2;
}
else
{
pt = closed3;
}
}
Debug.DrawLine(pt, p);
}
private float FindDistance2Segment(Vector3 pt, Vector3 p1, Vector3 p2, out Vector3 closedP)
{
//float radio = projection / segmentLength;
Vector3 vSegment = p2 - p1;
float radio = Vector3.Dot(vSegment, pt - p1) / vSegment.magnitude / vSegment.magnitude;
if (radio <= 0)
{
closedP = p1;
}
else if (radio >= 1)
{
closedP = p2;
}
else
{
closedP = p1 + radio * vSegment;
}
return (pt - closedP).magnitude;
}
}