mirror of
https://gitee.com/jisol/jisol-game/
synced 2025-06-26 19:34:47 +00:00
115 lines
3.6 KiB
C#
115 lines
3.6 KiB
C#
|
using JNGame.Math;
|
|||
|
|
|||
|
namespace JNGame.PathFinding
|
|||
|
{
|
|||
|
/// <summary>
|
|||
|
/// 二叉空间树的切割线
|
|||
|
/// </summary>
|
|||
|
public struct SplitLine
|
|||
|
{
|
|||
|
/// <summary>
|
|||
|
/// 切割线起点
|
|||
|
/// </summary>
|
|||
|
public LVector2 vertexA;
|
|||
|
/// <summary>
|
|||
|
/// 切割线终点
|
|||
|
/// </summary>
|
|||
|
public LVector2 vertexB;
|
|||
|
/// <summary>
|
|||
|
/// 切割线方向
|
|||
|
/// </summary>
|
|||
|
public readonly LVector2 Direction => vertexB - vertexA;
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 构造切割线
|
|||
|
/// </summary>
|
|||
|
/// <param name="vertexA"></param>
|
|||
|
/// <param name="vertexB"></param>
|
|||
|
public SplitLine(in LVector2 vertexA, in LVector2 vertexB)
|
|||
|
{
|
|||
|
this.vertexA = vertexA;
|
|||
|
this.vertexB = vertexB;
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 获取三角形的切割结果
|
|||
|
/// </summary>
|
|||
|
/// <param name="line">切割线</param>
|
|||
|
/// <param name="tri">切割三角形</param>
|
|||
|
/// <returns>切割线左侧、右侧或经过切割线</returns>
|
|||
|
public static EnumSplitType GetSplitResult(in SplitLine line, TriangleRef tri)
|
|||
|
{
|
|||
|
var lineDir = line.Direction;
|
|||
|
// 三角形三个顶点与切割线的位置关系
|
|||
|
var valA = LVector2.Cross(lineDir, tri.vertexA - line.vertexA);
|
|||
|
var valB = LVector2.Cross(lineDir, tri.vertexB - line.vertexA);
|
|||
|
var valC = LVector2.Cross(lineDir, tri.vertexC - line.vertexA);
|
|||
|
|
|||
|
var isRight = false;
|
|||
|
if (valA != 0) isRight = valA < 0;
|
|||
|
if (valB != 0) isRight = valB < 0;
|
|||
|
if (valC != 0) isRight = valC < 0;
|
|||
|
|
|||
|
var isA = valA <= 0;
|
|||
|
var isB = valB <= 0;
|
|||
|
var isC = valC <= 0;
|
|||
|
if (isA == isB && isB == isC)
|
|||
|
{
|
|||
|
return isRight ? EnumSplitType.Right : EnumSplitType.Left;
|
|||
|
}
|
|||
|
|
|||
|
isA = valA >= 0;
|
|||
|
isB = valB >= 0;
|
|||
|
isC = valC >= 0;
|
|||
|
if (isA == isB && isB == isC)
|
|||
|
{
|
|||
|
return isRight ? EnumSplitType.Right : EnumSplitType.Left;
|
|||
|
}
|
|||
|
|
|||
|
return EnumSplitType.OnPlane;
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 获取顶点和切割线的位置关系
|
|||
|
/// </summary>
|
|||
|
/// <param name="line">切割线</param>
|
|||
|
/// <param name="vertex">顶点</param>
|
|||
|
/// <returns></returns>
|
|||
|
public static EnumSplitType ClassifyPointToPlane(in SplitLine line, in LVector2 vertex)
|
|||
|
{
|
|||
|
var val = LVector2.Cross(line.Direction, vertex - line.vertexA);
|
|||
|
if (val == 0)
|
|||
|
{
|
|||
|
return EnumSplitType.OnPlane;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
return val < 0 ? EnumSplitType.Right : EnumSplitType.Left;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 计算p0p1,p2p3的交点
|
|||
|
/// </summary>
|
|||
|
/// <param name="p0"></param>
|
|||
|
/// <param name="p1"></param>
|
|||
|
/// <param name="p2"></param>
|
|||
|
/// <param name="p3"></param>
|
|||
|
/// <returns></returns>
|
|||
|
public static LVector2 GetIntersectPoint(in LVector2 p0, in LVector2 p1, in LVector2 p2, in LVector2 p3)
|
|||
|
{
|
|||
|
var diff = p2 - p0;
|
|||
|
var d1 = p1 - p0;
|
|||
|
var d2 = p3 - p2;
|
|||
|
var demo = LMath.Cross(d1, d2); //det
|
|||
|
if (LMath.Abs(demo) < LFloat.EPSILON)
|
|||
|
{
|
|||
|
// 叉积结果为0,说明两个向量平行
|
|||
|
return p0;
|
|||
|
}
|
|||
|
|
|||
|
var t1 = LMath.Cross(diff, d2) / demo; // Cross2D(diff,-d2)
|
|||
|
return p0 + (p1 - p0) * t1;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|