using OpenTK.Mathematics; using System.Windows.Forms; namespace Yw.WinFrmUI.Hydro { /// /// 射线 /// internal class Ray3 { /// /// /// public Ray3() { } /// /// /// public Ray3(Vector3 origin, Vector3 direction) { Origin = origin; Direction = direction.Normalized();//确保归一化 } /// /// 原点 /// public Vector3 Origin { get; set; } /// /// 方向 /// public Vector3 Direction { get; set; } /// /// 检测射线是否与点相交(基于容差) /// /// 目标点 /// 容差阈值(点与射线的最大允许距离 默认 0.01f) /// 最大有效距离(射线方向上的范围 默认 Float.MaxValue) /// 输出相交距离 /// 是否相交 public bool IntersectsPoint ( Vector3 point, float epsilon, float maxDistance, out float distance ) { // 计算从起点到目标点的向量 Vector3 originToPoint = point - Origin; // 计算点在射线方向上的投影长度(参数t) float t = Vector3.Dot(originToPoint, Direction); // 如果t为负数或超过最大距离,说明点在射线反方向或超出范围 if (t < 0 || t > maxDistance) { distance = float.NaN; return false; } // 计算投影点位置 Vector3 projectedPoint = Origin + Direction * t; // 计算实际点与投影点的距离(最短距离) float pointDistance = Vector3.Distance(point, projectedPoint); // 判断是否在容差范围内 if (pointDistance <= epsilon) { distance = t; // 返回射线起点到投影点的距离(若Direction是单位向量,t即实际距离) return true; } distance = float.NaN; return false; } /// /// 检测射线是否与线段相交 /// /// 线段开始点 /// 线段结束点 /// 误差(包含线段的半径) /// 射线方向的最大有效距离 /// 输出射线起点到交点的距离 /// 是否相交 public bool IntersectsLine ( Vector3 segStart, Vector3 segEnd, float epsilon, float maxDistance, out float distance ) { distance = float.MaxValue; Vector3 ab = segEnd - segStart; Vector3 ao = Origin - segStart; Vector3 n = Vector3.Cross(ab, Direction); float denom = n.Length * n.Length; if (Math.Abs(denom) < 1e-8) { return false; } Vector3 q = Vector3.Cross(ao, Direction); float s = Vector3.Dot(q, n) / denom; if (s < 0 || s > 1) { return false; } Vector3 closestPointOnSegment = segStart + Vector3.Multiply(ab, s); Vector3 v = closestPointOnSegment - Origin; float t = Vector3.Dot(v, Direction); if (t < 0) { return false; } Vector3 intersectionPoint = Origin + Vector3.Multiply(Direction, t); double distanceToSegment = (intersectionPoint - closestPointOnSegment).Length; if (distanceToSegment > epsilon) { return false; } distance = t; return true; } } }