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