243 lines
4.7 KiB
C#
243 lines
4.7 KiB
C#
![]() |
using System.Collections;
|
||
|
using System.Collections.Generic;
|
||
|
using Godot;
|
||
|
using System;
|
||
|
|
||
|
|
||
|
|
||
|
namespace Rokojori
|
||
|
{
|
||
|
public class QuadTreeCell<T>:QuadTreeNode<T>
|
||
|
{
|
||
|
QuadTreeCell<T> _parent;
|
||
|
public QuadTreeCell<T> parent => _parent;
|
||
|
|
||
|
QuadTree<T> _tree;
|
||
|
public QuadTree<T> tree => _tree;
|
||
|
|
||
|
List<QuadTreeCell<T>> _cells;
|
||
|
public List<QuadTreeCell<T>> cells => _cells;
|
||
|
|
||
|
|
||
|
public int numCells => _cells == null ? 0 : cells.Count;
|
||
|
|
||
|
List<T> _values;
|
||
|
public List<T> values => _values;
|
||
|
|
||
|
int _depth;
|
||
|
public int depth => _depth;
|
||
|
|
||
|
Vector2 _center;
|
||
|
public Vector2 center => _center;
|
||
|
|
||
|
Vector2 _size;
|
||
|
public Vector2 size => _size;
|
||
|
|
||
|
bool _isCombined = false;
|
||
|
public bool isCombined => _isCombined;
|
||
|
public bool canBeCombined => ! isLeaf && ! isCombined && numCells > 0;
|
||
|
|
||
|
|
||
|
public bool isRoot => _parent == null;
|
||
|
public bool isEmpty => _cells == null || _cells.Count == 0;
|
||
|
public bool isLeaf => _depth == tree.maxDepth;
|
||
|
|
||
|
Box2 _box;
|
||
|
public Box2 box => _box;
|
||
|
|
||
|
int _rootCellIndex = -1;
|
||
|
public int rootCellIndex => _rootCellIndex;
|
||
|
|
||
|
|
||
|
public void GetInsideBox( Box2 box, List<T> list )
|
||
|
{
|
||
|
if ( ! _box.Overlaps( box ) )
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if ( _values != null )
|
||
|
{
|
||
|
list.AddRange( _values );
|
||
|
}
|
||
|
|
||
|
if ( _cells == null )
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
_cells.ForEach( c => c.GetInsideBox( box, list ) );
|
||
|
|
||
|
}
|
||
|
|
||
|
public static QuadTreeCell<T> Create( QuadTree<T> tree, Vector2 min, Vector2 max, int rootIndex )
|
||
|
{
|
||
|
var cell = new QuadTreeCell<T>();
|
||
|
cell._tree = tree;
|
||
|
cell._center = (max + min ) / 2f;
|
||
|
cell._size = ( max - min );
|
||
|
cell._depth = 0;
|
||
|
cell._box = Box2.Create( min, max );
|
||
|
cell._rootCellIndex = rootIndex;
|
||
|
|
||
|
return cell;
|
||
|
}
|
||
|
|
||
|
public static QuadTreeCell<T> Create( QuadTreeCell<T> parent, int depth, Vector2 min, Vector2 max )
|
||
|
{
|
||
|
var cell = new QuadTreeCell<T>();
|
||
|
cell._parent = parent;
|
||
|
cell._tree = parent.tree;
|
||
|
cell._center = (max + min ) / 2f;
|
||
|
cell._size = ( max - min );
|
||
|
cell._depth = depth;
|
||
|
cell._box = Box2.Create( min, max );
|
||
|
cell._rootCellIndex = parent.rootCellIndex;
|
||
|
|
||
|
return cell;
|
||
|
}
|
||
|
|
||
|
public Vector2 GetPointWithPolarUV( Vector2 polarUV )
|
||
|
{
|
||
|
var halfSize = _size / 2f;
|
||
|
|
||
|
return _center + halfSize * polarUV;
|
||
|
}
|
||
|
|
||
|
public void BoxInsert( T data, Box2 box )
|
||
|
{
|
||
|
if ( ! _box.Overlaps( box ) )
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if ( isLeaf )
|
||
|
{
|
||
|
if ( _values == null )
|
||
|
{
|
||
|
_values = new List<T>();
|
||
|
}
|
||
|
|
||
|
values.Add( data );
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
Nest();
|
||
|
|
||
|
cells.ForEach( c => c.BoxInsert( data, box ) );
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
|
||
|
public bool Insert( T data )
|
||
|
{
|
||
|
if ( isLeaf )
|
||
|
{
|
||
|
if ( _values == null )
|
||
|
{
|
||
|
_values = new List<T>();
|
||
|
}
|
||
|
|
||
|
values.Add( data );
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
Nest();
|
||
|
|
||
|
var position = tree.GetPosition( data );
|
||
|
|
||
|
var cell = GetChildCellFor( position );
|
||
|
|
||
|
if ( cell == null )
|
||
|
{
|
||
|
RJLog.Log( "No cell found in:", this.depth, this.center, ">> for: ", position );
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return cell.Insert( data );
|
||
|
}
|
||
|
|
||
|
public void SmoothDown( float amount )
|
||
|
{
|
||
|
if ( isLeaf || cells == null )
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
cells.ForEach(
|
||
|
( c )=>
|
||
|
{
|
||
|
c._values = tree.SmoothPoints( c.values, values, amount );
|
||
|
}
|
||
|
);
|
||
|
|
||
|
}
|
||
|
|
||
|
public void Combine()
|
||
|
{
|
||
|
if ( isLeaf || isCombined )
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if ( numCells == 0 )
|
||
|
{
|
||
|
_isCombined = true;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
var cellPoints = new List<T>();
|
||
|
cells.ForEach(
|
||
|
c =>
|
||
|
{
|
||
|
if ( c.values == null )
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
cellPoints.AddRange( c.values );
|
||
|
}
|
||
|
);
|
||
|
|
||
|
_values = tree.CombinePoints( cellPoints );
|
||
|
_isCombined = true;
|
||
|
}
|
||
|
|
||
|
public QuadTreeCell<T> GetChildCellFor( Vector2 position )
|
||
|
{
|
||
|
return _cells.Find( c => c.box.ContainsPoint( position ) );
|
||
|
}
|
||
|
|
||
|
|
||
|
public void Nest()
|
||
|
{
|
||
|
if ( _cells != null && _cells.Count == 8 )
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
_cells = new List<QuadTreeCell<T>>();
|
||
|
|
||
|
for ( int x = -1; x < 1; x ++ )
|
||
|
{
|
||
|
var x0 = x;
|
||
|
var x1 = x + 1;
|
||
|
|
||
|
for ( int y = -1; y < 1; y ++ )
|
||
|
{
|
||
|
var y0 = y;
|
||
|
var y1 = y + 1;
|
||
|
|
||
|
|
||
|
var min = GetPointWithPolarUV( new Vector2( x0, y0 ) );
|
||
|
var max = GetPointWithPolarUV( new Vector2( x1, y1 ) );
|
||
|
|
||
|
_cells.Add( Create( this, depth + 1, min, max ) );
|
||
|
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|