Created
July 28, 2019 23:26
-
-
Save HurricanKai/c1402effac601125be2d365aea3b2924 to your computer and use it in GitHub Desktop.
Integer Octree implementation. Could be used for any struct
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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