mirror of
https://gitee.com/jisol/jisol-game/
synced 2025-06-26 19:34:47 +00:00
137 lines
4.6 KiB
C#
137 lines
4.6 KiB
C#
using System;
|
||
// using JNGame.Collision2D;
|
||
using JNGame.Math;
|
||
// using Debug = JNGame.Logging.Debug;
|
||
|
||
namespace JNGame.PathFinding
|
||
{
|
||
/// <summary>
|
||
/// 导航三角形在二叉空间分割树中的引用
|
||
/// <para>一个导航三角形可能会被树分割为多个三角形引用</para>
|
||
/// </summary>
|
||
public class TriangleRef
|
||
{
|
||
/// <summary>
|
||
/// 当前三角形引用关联的导航三角形索引
|
||
/// </summary>
|
||
public int index;
|
||
/// <summary>
|
||
/// 三角形顶点A
|
||
/// </summary>
|
||
public LVector2 vertexA;
|
||
/// <summary>
|
||
/// 三角形顶点B
|
||
/// </summary>
|
||
public LVector2 vertexB;
|
||
/// <summary>
|
||
/// 三角形顶点C
|
||
/// </summary>
|
||
public LVector2 vertexC;
|
||
|
||
/// <summary>
|
||
/// 是否是分割的三角形
|
||
/// </summary>
|
||
public bool IsSplit { get; private set; } = false;
|
||
/// <summary>
|
||
/// 三角形的边框
|
||
/// </summary>
|
||
public SplitLine[] borders;
|
||
|
||
/// <summary>
|
||
/// 根据下标获取三角形的顶点,合法下标0/1/2
|
||
/// </summary>
|
||
/// <param name="index"></param>
|
||
/// <returns></returns>
|
||
/// <exception cref="IndexOutOfRangeException"></exception>
|
||
public LVector2 this[int index]
|
||
{
|
||
get
|
||
{
|
||
return index switch
|
||
{
|
||
0 => vertexA,
|
||
1 => vertexB,
|
||
2 => vertexC,
|
||
_ => throw new IndexOutOfRangeException("vector idx invalid" + index),
|
||
};
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 根据原始导航三角形创建引用
|
||
/// <para>由此构造的三角形引用认为是未切割过的三角形</para>
|
||
/// </summary>
|
||
/// <param name="srcTriangle">原始的导航三角形</param>
|
||
public TriangleRef(NavTriangle srcTriangle)
|
||
: this(srcTriangle.vertexA.ToLVector2XZ(), srcTriangle.vertexB.ToLVector2XZ(), srcTriangle.vertexC.ToLVector2XZ(), srcTriangle.index)
|
||
{ }
|
||
|
||
/// <summary>
|
||
/// 根据分割的三个顶点和原始导航三角形创建引用
|
||
/// <para>由此构造的三角形引用认为是切割过的三角形</para>
|
||
/// </summary>
|
||
/// <param name="vertexA">三角形顶点A</param>
|
||
/// <param name="vertexB">三角形顶点B</param>
|
||
/// <param name="vertexC">三角形顶点C</param>
|
||
/// <param name="srcTriangle">原始的导航三角形</param>
|
||
public TriangleRef(in LVector2 vertexA, in LVector2 vertexB, in LVector2 vertexC, TriangleRef srcTriangle)
|
||
: this(vertexA, vertexB, vertexC, srcTriangle.index)
|
||
{
|
||
IsSplit = true;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 私有构造
|
||
/// </summary>
|
||
/// <param name="vertexA">三角形顶点A</param>
|
||
/// <param name="vertexB">三角形顶点B</param>
|
||
/// <param name="vertexC">三角形顶点C</param>
|
||
/// <param name="idx">引用的导航三角形索引</param>
|
||
private TriangleRef(in LVector2 vertexA, in LVector2 vertexB, in LVector2 vertexC, int idx)
|
||
{
|
||
this.vertexA = vertexA;
|
||
this.vertexB = vertexB;
|
||
this.vertexC = vertexC;
|
||
index = idx;
|
||
borders = new SplitLine[]
|
||
{
|
||
new SplitLine(vertexA, vertexB),
|
||
new SplitLine(vertexB, vertexC),
|
||
new SplitLine(vertexC, vertexA)
|
||
};
|
||
//check valid
|
||
CheckValid();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 三角形三点不可重合
|
||
/// </summary>
|
||
private void CheckValid()
|
||
{
|
||
for (int i = 0; i < 3; i++)
|
||
{
|
||
if (borders[i].Direction == LVector2.Zero)
|
||
{
|
||
// Debug.Assert(false);
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 判断点是否在此三角形内
|
||
/// </summary>
|
||
/// <param name="pos"></param>
|
||
/// <returns></returns>
|
||
public bool Contain(in LVector2 pos)
|
||
{
|
||
// ABC三个顶点绕序为顺时针,三个叉积都需要为负,则点在三角形内
|
||
var isRightA = LVector2.Cross(vertexB - vertexA, pos - vertexA) > 0;
|
||
if (isRightA) return false;
|
||
var isRightB = LVector2.Cross(vertexC - vertexB, pos - vertexB) > 0;
|
||
if (isRightB) return false;
|
||
var isRightC = LVector2.Cross(vertexA - vertexC, pos - vertexC) > 0;
|
||
if (isRightC) return false;
|
||
return true;
|
||
}
|
||
}
|
||
} |