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;
}
}
}