using System; using System.Buffers; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Net.Http.Headers; using System.Threading; using System.Threading.Tasks; using BITKit; using Unity.Burst; using Unity.Mathematics; namespace Net.BITKit.Quadtree { public class Quadtree { public QuadtreeNode Root { get; private set; } public IDictionary Positions { get { Expansion(); return _positions; } } public IDictionary Sizes => _sizes; private readonly Dictionary _positions; private Memory _memory; private readonly ConcurrentQueue<(int, float2)> _queue; private readonly Dictionary _sizes; public Quadtree(float2 center, float2 size) { _sizes = new Dictionary(); _memory = new int[(int)math.max(size.x, size.y)]; _positions = new Dictionary(); _queue = new ConcurrentQueue<(int, float2)>(); Root = new QuadtreeNode(this,center, size); } public void Insert(in int objectId,in float2 position,in float2 size = default) { _queue.Enqueue((objectId, position)); if (size.x is not 0) { _sizes.TryAdd(objectId, size); } else { var root = Root; InsertRecursive(ref root,in objectId,in position); } } private static void InsertRecursive(ref QuadtreeNode node,in int objectId,in float2 position) { if (!node.Contains(position)) return; if (node.Objects.Count < 4 || node.Size.x <= 1f) // 假设最小节点大小为1 { node.Objects.Add(objectId); } else { if (node.Children[0].Size.x == 0) // 如果子节点未初始化 { node.Split(); } for (var i = 0; i < 4; i++) { InsertRecursive(ref node.Children[i], objectId, position); } } } public Memory Query(float2 position, float radius) { Expansion(); var index = 0; var root = Root; QueryRecursive(in root,in position,in radius, _memory.Span, ref index); foreach (var (key,size) in _sizes) { var pos = _positions[key]; if (IsCircleInRect(pos, radius, position, size)) { _memory.Span[index] = key; index++; } } return _memory[..index]; } [BurstCompile] private static bool IsCircleInRect(float2 point, float radius, float2 pos, float2 size) { var halfSize = size * 0.5f; var min = pos - halfSize; // 矩形左下角 var max = pos + halfSize; // 矩形右上角 // 计算扩展后的包围盒 var expandedMin = min - radius; var expandedMax = max + radius; // 检查点是否在扩展的矩形内 return point.x >= expandedMin.x && point.x <= expandedMax.x && point.y >= expandedMin.y && point.y <= expandedMax.y; } private void Expansion() { while (_queue.TryDequeue(out var item)) { _positions.TryAdd(item.Item1, item.Item2); } if (_positions.Count > _memory.Length) { _memory = new int[_positions.Count*2]; } } [BurstCompile] private void QueryRecursive(in QuadtreeNode node,in float2 position,in float radius,Span result,ref int index) { if (!Intersects(node.Center, node.Size, position, radius)) return; foreach (var obj in node.Objects) { // 直接 TryGetValue,避免 `Positions[obj]` 可能的重复哈希查找 if (!_positions.TryGetValue(obj, out var objPos)) continue; // 计算平方距离,避免额外变量 if (math.dot(objPos - position, objPos - position) > radius * radius) continue; // 直接写入 result result[index] = obj; index++; } for (var i = 0; i < 4; i++) { if (node.Children[i].Size.x > 0) { QueryRecursive(in node.Children[i],in position,in radius,result,ref index); } } } [BurstCompile] private static bool Intersects(in float2 center,in float2 size,in float2 position,in float radius) { // 计算 AABB 的最小/最大点 var min = center - size * 0.5f; var max = center + size * 0.5f; // 找到圆心到 AABB 的最近点 var closest = math.clamp(position, min, max); // 计算圆心到最近点的距离 var delta = position - closest; var distanceSq = math.dot(delta, delta); // 相交条件:如果距离平方 <= 半径平方 return distanceSq <= (radius * radius); } // 删除对象 public bool Remove(int objectId) { Expansion(); if (_positions.TryGetValue(objectId, out var position) is false) return false; _sizes.TryRemove(objectId); var root = Root; if (RemoveRecursive(ref root, objectId, position) is false) return false; _positions.Remove(objectId); return true; } private static bool RemoveRecursive(ref QuadtreeNode node, int objectId, float2 position) { if (!node.Contains(position)) return false; // 尝试从当前节点删除 if (node.Objects.Remove(objectId)) { return true; } // 如果当前节点是叶子节点且未找到对象,返回false if (node.IsLeaf()) { return false; } // 递归从子节点删除 for (var i = 0; i < 4; i++) { if (RemoveRecursive(ref node.Children[i], objectId, position)) { // 检查子节点是否需要合并 TryMerge(ref node); return true; } } return false; } // 尝试合并子节点 private static void TryMerge(ref QuadtreeNode node) { if (node.IsLeaf()) return; var totalObjects = node.Objects.Count; for (var i = 0; i < 4; i++) { totalObjects += node.Children[i].Objects.Count; } // 如果所有子节点的对象数量加上当前节点的对象数量小于等于4,则合并 if (totalObjects <= 4) { for (var i = 0; i < 4; i++) { node.Objects.UnionWith(node.Children[i].Objects); node.Children[i] = new QuadtreeNode(); // 清空子节点 } } } } }