Files
2026-03-25 18:20:24 +08:00

246 lines
9.2 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using CaeGlobals;
namespace CaeResults
{
//
// https://stackoverflow.com/questions/2924795/fastest-way-to-compute-point-to-triangle-distance-in-3d
//
public class Triangle
{
// Variables
public int Id;
public readonly Edge3 EdgeAb;
public readonly Edge3 EdgeBc;
public readonly Edge3 EdgeCa;
public readonly Vec3D TriNorm;
private Plane _triPlane;
private Plane _planeAb;
private Plane _planeBc;
private Plane _planeCa;
private double _va;
private double _vb;
private double _vc;
// Properties
public Vec3D A { get { return EdgeAb.A; } }
public Vec3D B { get { return EdgeBc.A; } }
public Vec3D C { get { return EdgeCa.A; } }
public Plane TriPlane { get { return _triPlane; } }
public Plane PlaneAb { get { return _planeAb; } }
public Plane PlaneBc { get { return _planeBc; } }
public Plane PlaneCa { get { return _planeCa; } }
// Constructors
public Triangle(int id, double[] a, double[] b, double[] c, double va, double vb, double vc)
: this(id, new Vec3D(a), new Vec3D(b), new Vec3D(c), va, vb, vc)
{
}
public Triangle(int id, Vec3D a, Vec3D b, Vec3D c, double va, double vb, double vc)
{
Id = id;
EdgeAb = new Edge3(a, b);
EdgeBc = new Edge3(b, c);
EdgeCa = new Edge3(c, a);
TriNorm = Vec3D.CrossProduct(a - b, a - c);
// Values
_va = va;
_vb = vb;
_vc = vc;
// Triangle plane
_triPlane = new Plane(A, TriNorm);
_triPlane.Direction.Normalize();
// Edge planes
_planeAb = new Plane(EdgeAb.A, Vec3D.CrossProduct(TriNorm, EdgeAb.Delta));
_planeBc = new Plane(EdgeBc.A, Vec3D.CrossProduct(TriNorm, EdgeBc.Delta));
_planeCa = new Plane(EdgeCa.A, Vec3D.CrossProduct(TriNorm, EdgeCa.Delta));
}
public Triangle(Triangle triangle)
{
Id = triangle.Id;
EdgeAb = triangle.EdgeAb.DeepCopy();
EdgeBc = triangle.EdgeBc.DeepCopy();
EdgeCa = triangle.EdgeCa.DeepCopy();
TriNorm = triangle.TriNorm.DeepCopy();
_triPlane = triangle._triPlane.DeepCopy();
_planeAb = triangle._planeAb.DeepCopy();
_planeBc = triangle._planeBc.DeepCopy();
_planeCa = triangle._planeCa.DeepCopy();
_va = triangle._va;
_vb = triangle._vb;
_vc = triangle._vc;
}
// Methods
public Vec3D ClosestPointTo(Vec3D p)
{
// Find the projection of the point onto the edge
var uab = EdgeAb.Project(p);
var uca = EdgeCa.Project(p);
//
if (uca > 1 && uab < 0) return A;
//
var ubc = EdgeBc.Project(p);
//
if (uab > 1 && ubc < 0) return B;
//
if (ubc > 1 && uca < 0) return C;
//
if (0 <= uab && uab <= 1 && !_planeAb.IsAbove(p)) return EdgeAb.PointAt(uab);
//
if (0 <= ubc && ubc <= 1 && !_planeBc.IsAbove(p)) return EdgeBc.PointAt(ubc);
//
if (0 <= uca && uca <= 1 && !_planeCa.IsAbove(p)) return EdgeCa.PointAt(uca);
// The closest point is in the triangle so project to the plane to find it
return _triPlane.Project(p);
}
public bool GetClosestPointTo(Vec3D p, double len2limit, out Vec3D closestPoint, out ClosestPointTypeEnum closestPointType)
{
closestPoint = null;
closestPointType = ClosestPointTypeEnum.None;
Vec3D v = p - _triPlane.Point;
Vec3D d = _triPlane.Direction * Vec3D.DotProduct(v, _triPlane.Direction);
double d2 = d.Len2;
//
if (d2 > len2limit) return false;
else
{
// Find the projection of the point onto the edge
var uab = EdgeAb.Project(p);
var uca = EdgeCa.Project(p);
//
if (uca > 1 && uab < 0)
{
closestPoint = A;
closestPointType = ClosestPointTypeEnum.PointA;
return true;
}
//
var ubc = EdgeBc.Project(p);
//
if (uab > 1 && ubc < 0)
{
closestPoint = B;
closestPointType = ClosestPointTypeEnum.PointB;
return true;
}
//
if (ubc > 1 && uca < 0)
{
closestPoint = C;
closestPointType = ClosestPointTypeEnum.PointC;
return true;
}
//
if (0 <= uab && uab <= 1 && !_planeAb.IsAbove(p))
{
closestPoint = EdgeAb.PointAt(uab);
closestPointType = ClosestPointTypeEnum.EdgeAB;
return true;
}
//
if (0 <= ubc && ubc <= 1 && !_planeBc.IsAbove(p))
{
closestPoint = EdgeBc.PointAt(ubc);
closestPointType = ClosestPointTypeEnum.EdgeBC;
return true;
}
//
if (0 <= uca && uca <= 1 && !_planeCa.IsAbove(p))
{
closestPoint = EdgeCa.PointAt(uca);
closestPointType = ClosestPointTypeEnum.EdgeCA;
return true;
}
// The closest point is in the triangle so project to the plane to find it
closestPoint = p - d;
closestPointType = ClosestPointTypeEnum.Internal;
}
//
return true;
}
public bool GetClosestNodeTo(Vec3D p, double len2limit, out Vec3D closestPoint)
{
closestPoint = null;
double da = (A - p).Len2;
double db = (B - p).Len2;
double dc = (C - p).Len2;
//
if (da <= db && da <= dc)
{
if (da < len2limit)
{
closestPoint = A;
return true;
}
}
else if (db <= da && db <= dc)
{
if (db < len2limit)
{
closestPoint = B;
return true;
}
}
else
{
if (dc < len2limit)
{
closestPoint = C;
return true;
}
}
//
return false;
}
public double InterpolateAt(Vec3D p)
{
if (p.X == A.X && p.Y == A.Y && p.Z == A.Z) return _va;
else if (p.X == B.X && p.Y == B.Y && p.Z == B.Z) return _vb;
else if (p.X == C.X && p.Y == C.Y && p.Z == C.Z) return _vc;
//
double g;
double h;
double nx = Math.Abs(TriNorm.X);
double ny = Math.Abs(TriNorm.Y);
double nz = Math.Abs(TriNorm.Z);
//
if (nx >= ny && nx >= nz)
{
g = -(A.Z * (p.Y - C.Y) + C.Z * (A.Y - p.Y) + p.Z * (C.Y - A.Y)) /
(A.Z * (C.Y - B.Y) + B.Z * (A.Y - C.Y) + C.Z * (B.Y - A.Y));
h = (A.Z * (p.Y - B.Y) + B.Z * (A.Y - p.Y) + p.Z * (B.Y - A.Y)) /
(A.Z * (C.Y - B.Y) + B.Z * (A.Y - C.Y) + C.Z * (B.Y - A.Y));
}
else if (ny >= nx && ny >= nz)
{
g = -(A.Z * (p.X - C.X) + C.Z * (A.X - p.X) + p.Z * (C.X - A.X)) /
(A.Z * (C.X - B.X) + B.Z * (A.X - C.X) + C.Z * (B.X - A.X));
h = (A.Z * (p.X - B.X) + B.Z * (A.X - p.X) + p.Z * (B.X - A.X)) /
(A.Z * (C.X - B.X) + B.Z * (A.X - C.X) + C.Z * (B.X - A.X));
}
else
{
g = -(A.X * (p.Y - C.Y) + C.X * (A.Y - p.Y) + p.X * (C.Y - A.Y)) /
(A.X * (C.Y - B.Y) + B.X * (A.Y - C.Y) + C.X * (B.Y - A.Y));
h = (A.X * (p.Y - B.Y) + B.X * (A.Y - p.Y) + p.X * (B.Y - A.Y)) /
(A.X * (C.Y - B.Y) + B.X * (A.Y - C.Y) + C.X * (B.Y - A.Y));
}
//
return (1 - g - h) *_va + g * _vb + h * _vc;
}
//
public Triangle DeepCopy()
{
return new Triangle(this);
}
}
}