249 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			C#
		
	
	
	
			
		
		
	
	
			249 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			C#
		
	
	
	
using System.Collections;
 | 
						|
using System.Collections.Generic;
 | 
						|
using Godot;
 | 
						|
using System;
 | 
						|
 | 
						|
 | 
						|
 | 
						|
namespace Rokojori
 | 
						|
{
 | 
						|
  public class OcTreeCell<T,D>:OcTreeNode<T,D>
 | 
						|
  { 
 | 
						|
    OcTreeCell<T,D> _parent;
 | 
						|
    public OcTreeCell<T,D> parent => _parent;
 | 
						|
 | 
						|
    OcTree<T,D> _tree;
 | 
						|
    public OcTree<T,D> tree => _tree;
 | 
						|
 | 
						|
    List<OcTreeCell<T,D>> _cells;
 | 
						|
    public List<OcTreeCell<T,D>> cells => _cells;
 | 
						|
 | 
						|
 | 
						|
    public int numCells => _cells == null ? 0 : cells.Count;
 | 
						|
 | 
						|
    List<T> _values;
 | 
						|
    public List<T> values => _values;
 | 
						|
 | 
						|
    int _depth;
 | 
						|
    public int depth => _depth;
 | 
						|
 | 
						|
    Vector3 _center;
 | 
						|
    public Vector3 center => _center;
 | 
						|
 | 
						|
    Vector3 _size;  
 | 
						|
    public Vector3 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;
 | 
						|
 | 
						|
    Box3 _box;
 | 
						|
    public Box3 box => _box;
 | 
						|
 | 
						|
    int _rootCellIndex = -1;
 | 
						|
    public int rootCellIndex => _rootCellIndex;
 | 
						|
    
 | 
						|
 | 
						|
    public void GetInsideBox( Box3 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 OcTreeCell<T,D> Create( OcTree<T,D> tree, Vector3 min, Vector3 max, int rootIndex )
 | 
						|
    {
 | 
						|
      var cell = new OcTreeCell<T,D>();
 | 
						|
      cell._tree = tree;
 | 
						|
      cell._center = (max + min ) / 2f;
 | 
						|
      cell._size = ( max - min );
 | 
						|
      cell._depth = 0;
 | 
						|
      cell._box = Box3.Create( min, max );
 | 
						|
      cell._rootCellIndex = rootIndex;
 | 
						|
 | 
						|
      return cell;
 | 
						|
    }
 | 
						|
 | 
						|
    public static OcTreeCell<T,D> Create( OcTreeCell<T,D> parent, int depth, Vector3 min, Vector3 max )
 | 
						|
    {
 | 
						|
      var cell = new OcTreeCell<T,D>();
 | 
						|
      cell._parent = parent;
 | 
						|
      cell._tree = parent.tree;
 | 
						|
      cell._center = (max + min ) / 2f;
 | 
						|
      cell._size = ( max - min );
 | 
						|
      cell._depth = depth;
 | 
						|
      cell._box = Box3.Create( min, max );
 | 
						|
      cell._rootCellIndex = parent.rootCellIndex;
 | 
						|
 | 
						|
      return cell;
 | 
						|
    }
 | 
						|
 | 
						|
    public Vector3 GetPointWithPolarUVW( Vector3 polarUVW )
 | 
						|
    {
 | 
						|
      var halfSize = _size / 2f;
 | 
						|
 | 
						|
      return _center + halfSize * polarUVW;
 | 
						|
    }
 | 
						|
 | 
						|
    public void BoxInsert( T data, Box3 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 OcTreeCell<T,D> GetChildCellFor( Vector3 position )
 | 
						|
    {
 | 
						|
      return _cells.Find( c => c.box.ContainsPoint( position ) );
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
    public void Nest()
 | 
						|
    {
 | 
						|
      if ( _cells != null && _cells.Count == 8 )
 | 
						|
      {
 | 
						|
        return;
 | 
						|
      }
 | 
						|
 | 
						|
      _cells = new List<OcTreeCell<T,D>>();
 | 
						|
 | 
						|
      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;
 | 
						|
 | 
						|
          for ( int z = -1; z < 1; z ++ )
 | 
						|
          {
 | 
						|
            var z0 = z;
 | 
						|
            var z1 = z + 1;
 | 
						|
 | 
						|
            var min = GetPointWithPolarUVW( new Vector3( x0, y0, z0 ) );
 | 
						|
            var max = GetPointWithPolarUVW( new Vector3( x1, y1, z1 ) );
 | 
						|
 | 
						|
            _cells.Add( Create( this, depth + 1, min, max ) );
 | 
						|
          }
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
} |