Skip to content

Instantly share code, notes, and snippets.

@HurricanKai
Created July 28, 2019 23:26
Show Gist options
  • Select an option

  • Save HurricanKai/c1402effac601125be2d365aea3b2924 to your computer and use it in GitHub Desktop.

Select an option

Save HurricanKai/c1402effac601125be2d365aea3b2924 to your computer and use it in GitHub Desktop.
Integer Octree implementation. Could be used for any struct
using System.Linq;
public class QuadtreeNode
{
public QuadtreeNode Parent { get; } = null;
public QuadtreeNode[] Children { get; } = new QuadtreeNode[8];
public byte[,,] Values { get; private set; }
public int xMax { get; private set; }
public int yMax { get; private set; }
public int zMax { get; private set; }
public int xMin { get; private set; }
public int yMin { get; private set; }
public int zMin { get; private set; }
public bool Empty => !_allValsShouldBe.HasValue;
private int? _allValsShouldBe;
private int _nonZeroVals = 0;
public bool HasChildren { get; private set; } = false;
public QuadtreeNode(int xMax, int yMax, int zMax, int xMin = 0, int yMin = 0, int zMin = 0)
{
this.xMax = xMax;
this.yMax = yMax;
this.zMax = zMax;
this.xMin = xMin;
this.yMin = yMin;
this.zMin = zMin;
Values = new byte[xMax - xMin, yMax - yMin, zMax - zMin];
}
public byte this[int x, int y, int z]
{
get
{
if (!HasChildren)
return Values[x - xMin, y - yMin, z - zMin];
return Children.First(node
=> x >= node.xMin && x < node.xMax
&& y >= node.yMin && y < node.yMax
&& z >= node.zMin && z < node.zMax
)[x, y, z];
}
set
{
if (!HasChildren)
{
if (value == Values[x - xMin, y - yMin, z - zMin]) return;
Values[x - xMin, y - yMin, z - zMin] = value;
if (Empty && value != 0)
{
_allValsShouldBe = value;
Parent.TryValueMerge();
}
if (value == 0)
_nonZeroVals--;
else
_nonZeroVals++;
if (!Empty && _nonZeroVals == 0)
{
_allValsShouldBe = null;
Parent.TryEmptyMerge();
}
if (!Empty && value != _allValsShouldBe.Value)
Split();
}
Children.First(node
=> x >= node.xMin && x < node.xMax
&& y >= node.yMin && y < node.yMax
&& z >= node.zMin && z < node.zMax
)[x, y, z] = value;
}
}
private void Split()
{
var xHalf = (xMax - xMin) / 2;
var yHalf = (yMax - yMin) / 2;
var zHalf = (zMax - zMin) / 2;
Children[0] = new QuadtreeNode(xHalf, yHalf, zHalf, xMin, yMin, zMin);
Children[1] = new QuadtreeNode(xMax, yHalf, zHalf, xMin + xHalf, yMin, zMin);
Children[2] = new QuadtreeNode(xHalf, yMax, zHalf, xMin, yMin + yHalf, zMin);
Children[3] = new QuadtreeNode(xHalf, yHalf, zMax, xMin, yMin, zMin + zHalf);
Children[4] = new QuadtreeNode(xMax, yMax, zHalf, xMin + xHalf, yMin + yHalf, zMin);
Children[5] = new QuadtreeNode(xHalf, yMax, zMax, xMin, yMin + yHalf, zMin + zHalf);
Children[6] = new QuadtreeNode(xMax, yHalf, zMax, xMin + xHalf, yMin, zMin + zHalf);
Children[7] = new QuadtreeNode(xMax, yMax, zMax, xMin + xHalf, yMin + yHalf, zMin + zHalf);
for (var index = 0; index < Children.Length; index++)
{
var child = Children[index];
for (int x = child.xMin; x < child.xMax; x++)
{
for (int z = child.zMin; z < child.zMax; z++)
{
for (int y = child.yMin; y < child.yMax; y++)
{
child.Values[x - child.xMin, y - child.yMin, z - child.zMin] = this.Values[x, y, z];
}
}
}
Children[index] = child;
}
this.Values = null;
HasChildren = true;
_allValsShouldBe = null;
}
private void TryValueMerge()
{
int allShouldBe = 0;
foreach (var child in Children)
{
if (child.Empty)
return;
if (allShouldBe == 0)
{
allShouldBe = child._allValsShouldBe.Value;
continue;
}
if (allShouldBe != child._allValsShouldBe.Value)
return;
}
this.Values = new byte[xMax - xMin, yMax - yMin, zMax - zMin];
foreach (var child in Children)
{
for (int x = child.xMin; x < child.xMax; x++)
{
for (int z = child.zMin; x < child.zMax; z++)
{
for (int y = child.yMin; y < child.yMax; y++)
{
Values[x, y, z] = child[x, y, z];
}
}
}
}
HasChildren = false;
}
private void TryEmptyMerge()
{
if (Children.All(x => x.Empty))
{
ClearChildren();
Values = new byte[xMax - xMin, yMax - yMin, zMax - zMin];
Parent.TryEmptyMerge();
}
}
private void ClearChildren()
{
for (int i = 0; i < 8; i++)
Children[i] = null;
HasChildren = false;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment