This repository has been archived on 2025-09-23. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
XericLibrary-OLD/Runtime/MicroLibrary/NeighborGrid.cs

754 lines
18 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using XericLibrary.Runtime.MacroLibrary;
using XericLibrary.Runtime.Type;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.Runtime.CompilerServices;
using UnityEngine;
using UnityEngine.UIElements;
namespace XericLibrary.Runtime.MacroLibrary
{
public class NeighborGrid<T> : WeaklyObject,
IEnumerable<KeyValuePair<int, List<T>>>
{
#region
private Vector3 position;
private Vector3 cellSize;
private Vector3Int numCells;
private int maxNeighbor = 8;
public Vector3 Position
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => position;
}
public Vector3 CellSize
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => cellSize;
}
public Vector3Int NumCells
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => numCells;
}
internal System.Random random = new System.Random();
private int NeighborRandomIndex
{
get => random.Next(maxNeighbor);
}
/// <summary>
/// 网格系统存储地
/// </summary>
private Dictionary<int, List<T>> grid = new Dictionary<int, List<T>>();
/// <summary>
/// 网格的总尺寸
/// </summary>
public Vector3 Fullsize
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => cellSize.Mul(numCells);
}
/// <summary>
/// 此网格系统转为盒体范围
/// </summary>
public Bounds GridBounds
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => new Bounds(position, Fullsize / 2);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set
{
position = value.center;
cellSize = (value.size * 2).Div(numCells);
}
}
#endregion
#region
/// <summary>
/// 临近网格
/// </summary>
/// <param name="position">网格原点坐标</param>
/// <param name="cellSize">网格晶格尺寸</param>
/// <param name="fullSize">网格总尺寸</param>
/// <param name="maxNeighbor">单个晶格内最大邻居数量</param>
public NeighborGrid(Vector3 position, Vector3 cellSize, Vector3 fullSize, int maxNeighbor = 8)
{
this.position = position;
this.cellSize = cellSize;
this.numCells = fullSize.Div(cellSize).FloorToInt().Max(Vector3Int.one);
this.maxNeighbor = maxNeighbor;
Debug.Log($"原点:{position} 晶格尺寸{cellSize} 数量:{numCells}");
}
#endregion
#region
/// <summary>
/// 网格索引
/// </summary>
public struct NeighborGridIndex
{
#region
private NeighborGrid<T> grid;
private NeighborGridSpace drivenSpace;
private object drivenIndex;
#endregion
#region
public NeighborGridIndex(NeighborGrid<T> grid)
{
this.grid = grid;
drivenSpace = (NeighborGridSpace)(-1);
drivenIndex = null;
}
#endregion
#region
/// <summary>
/// 获取为 世界空间
/// </summary>
/// <param name="world"></param>
public Vector3 GetDrivenAsWorld()
{
DrivenTransformTo(NeighborGridSpace.World);
return (Vector3)drivenIndex;
}
/// <summary>
/// 获取为 网格系统本地坐标空间
/// </summary>
/// <param name="simulation"></param>
public Vector3 GetDrivenAsSimulation()
{
DrivenTransformTo(NeighborGridSpace.Simulation);
return (Vector3)drivenIndex;
}
/// <summary>
/// 获取为 网格系统本地单位空间
/// </summary>
/// <param name="unit"></param>
public Vector3 GetDrivenAsUnit()
{
DrivenTransformTo(NeighborGridSpace.Unit);
return (Vector3)drivenIndex;
}
/// <summary>
/// 获取为 三维索引
/// </summary>
/// <param name="world"></param>
public Vector3Int GetDrivenAsIndex()
{
DrivenTransformTo(NeighborGridSpace.Index);
return (Vector3Int)drivenIndex;
}
/// <summary>
/// 获取为 线性索引
/// </summary>
/// <param name="world"></param>
public int GetDrivenAsLinear()
{
DrivenTransformTo(NeighborGridSpace.Linear);
return (int)drivenIndex;
}
/// <summary>
/// 设置为 世界空间
/// </summary>
/// <param name="world"></param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public NeighborGridIndex SetDrivenAsWorld(Vector3 world)
{
drivenIndex = world;
drivenSpace = NeighborGridSpace.World;
return this;
}
/// <summary>
/// 设置为 网格系统本地坐标空间
/// </summary>
/// <param name="simulation"></param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public NeighborGridIndex SetDrivenAsSimulation(Vector3 simulation)
{
drivenIndex = simulation;
drivenSpace = NeighborGridSpace.Simulation;
return this;
}
/// <summary>
/// 设置为 网格系统本地单位空间
/// </summary>
/// <param name="unit"></param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public NeighborGridIndex SetDrivenAsUnit(Vector3 unit)
{
drivenIndex = unit;
drivenSpace = NeighborGridSpace.Unit;
return this;
}
/// <summary>
/// 设置为 三维索引
/// </summary>
/// <param name="world"></param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public NeighborGridIndex SetDrivenAsIndex(Vector3Int index)
{
drivenIndex = index;
drivenSpace = NeighborGridSpace.Index;
return this;
}
/// <summary>
/// 设置为 线性索引
/// </summary>
/// <param name="world"></param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public NeighborGridIndex SetDrivenAsLinear(int linear)
{
drivenIndex = linear;
drivenSpace = NeighborGridSpace.Linear;
return this;
}
/// <summary>
/// 转换当前索引到目标空间
/// </summary>
/// <param name="targetSpace"></param>
public NeighborGridIndex DrivenTransformTo(NeighborGridSpace targetSpace)
{
switch(targetSpace)
{
case NeighborGridSpace.World:
TransformToWorld();
break;
case NeighborGridSpace.Simulation:
TransformToSimulation();
break;
case NeighborGridSpace.Unit:
TransformToUnit();
break;
case NeighborGridSpace.Index:
TransformToIndex();
break;
case NeighborGridSpace.Linear:
TransformToLiear();
break;
default:
throw new System.Exception("转换空间是无效的");
}
return this;
}
/// <summary>
/// 将当前的目标转换到世界空间
/// </summary>
private void TransformToWorld()
{
switch(drivenSpace)
{
case NeighborGridSpace.World:
drivenSpace = NeighborGridSpace.World;
break;
case NeighborGridSpace.Simulation:
drivenIndex = grid.SimulationToWorld((Vector3)drivenIndex);
goto case NeighborGridSpace.World;
case NeighborGridSpace.Unit:
drivenIndex = grid.UnitToSimulation((Vector3)drivenIndex);
goto case NeighborGridSpace.Simulation;
case NeighborGridSpace.Index:
drivenIndex = grid.IndexToUnit((Vector3Int)drivenIndex);
goto case NeighborGridSpace.Unit;
case NeighborGridSpace.Linear:
drivenIndex = grid.LinearToIndex((int)drivenIndex);
goto case NeighborGridSpace.Index;
default:
throw new System.Exception("转换空间是无效的");
}
}
/// <summary>
/// 将当前的目标转换到本地空间
/// </summary>
private void TransformToSimulation()
{
switch(drivenSpace)
{
case NeighborGridSpace.World:
drivenIndex = grid.WorldToSimulation((Vector3)drivenIndex);
goto case NeighborGridSpace.Simulation;
case NeighborGridSpace.Simulation:
drivenSpace = NeighborGridSpace.Simulation;
break;
case NeighborGridSpace.Unit:
drivenIndex = grid.UnitToSimulation((Vector3)drivenIndex);
goto case NeighborGridSpace.Simulation;
case NeighborGridSpace.Index:
drivenIndex = grid.IndexToUnit((Vector3Int)drivenIndex);
goto case NeighborGridSpace.Unit;
case NeighborGridSpace.Linear:
drivenIndex = grid.LinearToIndex((int)drivenIndex);
goto case NeighborGridSpace.Index;
default:
throw new System.Exception("转换空间是无效的");
}
}
/// <summary>
/// 将当前的目标转换到单位空间
/// </summary>
private void TransformToUnit()
{
switch(drivenSpace)
{
case NeighborGridSpace.World:
drivenIndex = grid.WorldToSimulation((Vector3)drivenIndex);
goto case NeighborGridSpace.Simulation;
case NeighborGridSpace.Simulation:
drivenIndex = grid.SimulationToUnit((Vector3)drivenIndex);
goto case NeighborGridSpace.Unit;
case NeighborGridSpace.Unit:
drivenSpace = NeighborGridSpace.Unit;
break;
case NeighborGridSpace.Index:
drivenIndex = grid.IndexToUnit((Vector3Int)drivenIndex);
goto case NeighborGridSpace.Unit;
case NeighborGridSpace.Linear:
drivenIndex = grid.LinearToIndex((int)drivenIndex);
goto case NeighborGridSpace.Index;
default:
throw new System.Exception("转换空间是无效的");
}
}
/// <summary>
/// 将当前的目标转换到三维索引
/// </summary>
private void TransformToIndex()
{
switch(drivenSpace)
{
case NeighborGridSpace.World:
drivenIndex = grid.WorldToSimulation((Vector3)drivenIndex);
goto case NeighborGridSpace.Simulation;
case NeighborGridSpace.Simulation:
drivenIndex = grid.SimulationToUnit((Vector3)drivenIndex);
goto case NeighborGridSpace.Unit;
case NeighborGridSpace.Unit:
drivenIndex = grid.UnitToIndex((Vector3)drivenIndex);
goto case NeighborGridSpace.Index;
case NeighborGridSpace.Index:
drivenSpace = NeighborGridSpace.Index;
break;
case NeighborGridSpace.Linear:
drivenIndex = grid.LinearToIndex((int)drivenIndex);
goto case NeighborGridSpace.Index;
default:
throw new System.Exception("转换空间是无效的");
}
}
/// <summary>
/// 将当前的目标转换到线性索引
/// </summary>
private void TransformToLiear()
{
switch(drivenSpace)
{
case NeighborGridSpace.World:
drivenIndex = grid.WorldToSimulation((Vector3)drivenIndex);
goto case NeighborGridSpace.Simulation;
case NeighborGridSpace.Simulation:
drivenIndex = grid.SimulationToUnit((Vector3)drivenIndex);
goto case NeighborGridSpace.Unit;
case NeighborGridSpace.Unit:
drivenIndex = grid.UnitToIndex((Vector3)drivenIndex);
goto case NeighborGridSpace.Index;
case NeighborGridSpace.Index:
drivenIndex = grid.IndexToLinear((Vector3Int)drivenIndex);
break;
case NeighborGridSpace.Linear:
drivenSpace = NeighborGridSpace.Linear;
break;
default:
throw new System.Exception("转换空间是无效的");
}
}
#endregion
}
/// <summary>
/// 临近网络空间枚举
/// </summary>
public enum NeighborGridSpace
{
World,
Simulation,
Unit,
Index,
Linear
}
#endregion
#region
/// <summary>
/// 世界空间 变换为 网格系统本地坐标空间
/// </summary>
/// <param name="world">项目的世界空间坐标</param>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector3 WorldToSimulation(Vector3 world)
=> world - position - (-Fullsize / 2);
/// <summary>
/// 网格系统本地坐标空间 变换为 世界空间
/// </summary>
/// <param name="world">项目的世界空间坐标</param>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector3 SimulationToWorld(Vector3 simulation)
=> simulation + position + (-Fullsize / 2);
/// <summary>
/// 网格系统本地坐标空间 变换为 网格系统本地单位空间
/// </summary>
/// <param name="simulation">网格系统本地坐标空间</param>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector3 SimulationToUnit(Vector3 simulation)
=> simulation.Div(Fullsize);
/// <summary>
/// 网格系统本地坐标空间 变换为 网格系统本地单位空间
/// </summary>
/// <param name="simulation">网格系统本地坐标空间</param>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector3 UnitToSimulation(Vector3 unit)
=> unit.Mul(Fullsize);
/// <summary>
/// 网格系统本地单位空间 变换为 三维索引
/// </summary>
/// <param name="unit">网格系统本地单位空间</param>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector3Int UnitToIndex(Vector3 unit)
=> unit.IsInUnit() ? unit.Mul(numCells).FloorToInt() : MacroMath.Vector3Int_Negate;
/// <summary>
/// 三维索引 变换为 网格系统本地单位空间
/// </summary>
/// <param name="index">三维索引</param>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector3 IndexToUnit(Vector3Int index)
{
if(index.IsValid())
{
Vector3 unit = ((Vector3)index).Div(numCells);
unit.x = numCells.x == 1 && unit.x <= 0 ? .5f : unit.x;
unit.y = numCells.y == 1 && unit.y <= 0 ? .5f : unit.y;
unit.z = numCells.z == 1 && unit.z <= 0 ? .5f : unit.z;
return unit;
}
return MacroMath.Vector3Int_Negate;
}
/// <summary>
/// 网格系统本地单位空间 变换为 线性索引
/// </summary>
/// <param name="unit">网格系统本地坐标空间</param>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int UnitToLinear(Vector3 unit)
{
if(unit.IsInUnit())
{
return IndexToLinear(UnitToIndex(unit));
}
return -1;
}
/// <summary>
/// 三维索引 变换为 线性索引
/// </summary>
/// <param name="index">三维索引</param>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int IndexToLinear(Vector3Int index)
{
if(index.IsValid() && index.IsInIndexRange(numCells))
{
return (int)(index.x +
(index.y * numCells.x) +
(index.z * numCells.y * numCells.x));
}
return -1;
}
/// <summary>
/// 根据线性索引获取网格中索引偏移量
/// </summary>
/// <param name="linear">线性索引</param>
/// <param name="side">边长</param>
/// <returns></returns>
public Vector3Int LinearToGridIndex(int linear, int side)
{
return new Vector3Int(linear % side, linear / side, linear / side.Quad());
}
/// <summary>
/// 线性索引 变换为 三维索引
/// </summary>
/// <param name="linear">线性索引</param>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector3Int LinearToIndex(int linear)
{
int z = linear / (numCells.x * numCells.y);
int y = (linear - (z * numCells.x * numCells.y)) / numCells.x;
int x = linear - (z * numCells.x * numCells.y) - (y * numCells.x);
return new Vector3Int(x, y, z);
}
/// <summary>
/// 线性索引 变换为 网格系统本地单位空间
/// </summary>
/// <param name="linear">线性索引</param>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector3 LinearToUnit(int linear)
{
Debug.Log($"线性转索引空间{LinearToIndex(linear)},再转单位");
return IndexToUnit(LinearToIndex(linear));
}
#endregion
#region
/// <summary>
/// 清空网格
/// </summary>
public void Clean()
{
grid.Clear();
}
/// <summary>
/// 在给定索引处添加一个项目
/// </summary>
/// <param name="linear">索引</param>
/// <returns>返回是否添加成功</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Insert(int linear, T obj)
{
if(linear < 0)
return false;
if(grid.ContainsKey(linear))
{
int index = grid[linear].IndexOf(obj);
if(index < 0)
{
grid[linear].Add(obj);
return true;
}
return false;
}
else
{
grid.Add(linear, new List<T> { obj });
return true;
}
}
/// <summary>
/// 移除给定索引处的项目
/// </summary>
/// <param name="linear">索引</param>
/// <param name="obj">项目</param>
/// <returns>返回是否移除成功</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Remove(int linear, T obj)
{
if(grid.ContainsKey(linear))
{
bool resualt = grid[linear].Remove(obj);
if(grid[linear].Count <= 0)
grid.Remove(linear);
return resualt;
}
return false;
}
/// <summary>
/// 移除给定索引下所有项目
/// </summary>
/// <param name="linear">索引</param>
/// <returns>返回是否移除成功</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Remove(int linear)
{
if(grid[linear] is not null)
{
grid[linear].Clear();
}
}
/// <summary>
/// 查询给定索引处是否存在项目
/// </summary>
/// <param name="linear">索引</param>
/// <param name="obj">项目</param>
/// <returns>返回项目是否存在</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Contains(int linear, T obj)
{
if(grid[linear] is not null)
{
return grid[linear].Contains(obj);
}
return false;
}
/// <summary>
/// 忽略限制获取所有的邻居
/// <code>
/// 警告:潜在的高性能开销
/// </code>
/// </summary>
/// <param name="linear"></param>
/// <returns></returns>
public bool GetAllNeighbor(int linear, out List<T> values)
{
return grid.TryGetValue(linear, out values);
}
/// <summary>
/// 获取允许范围内的邻居
/// </summary>
/// <param name="linear">所在位置的索引</param>
/// <returns></returns>
public IEnumerable<T> GetNeighbor(int linear)
{
int startIndex = NeighborRandomIndex;
int count = grid[linear].Count;
for(int i = 0; i < maxNeighbor; i++)
{
yield return grid[linear][(startIndex + i) % count];
}
}
/// <summary>
/// 获取半径内所有允许的邻居
/// </summary>
/// <param name="linear">所在位置的索引</param>
/// <param name="range">检查的范围</param>
/// <returns></returns>
public IEnumerable<T> GetNeighbor(int linear, int radius)
{
int side = radius * 2 + 1;
int length = side.Cubic();
Vector3Int index = LinearToIndex(linear);
index = index.Sub(radius);
for(int i = 0; i < length; i++)
{
var neighbor = GetNeighbor(IndexToLinear(index +
LinearToGridIndex(i, side)))
.GetEnumerator();
while(neighbor.MoveNext())
{
yield return neighbor.Current;
}
}
}
#endregion
#region
public IEnumerator<KeyValuePair<int, List<T>>> GetEnumerator()
{
foreach(var list in grid)
{
yield return list;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
#endregion
}
}