From 5a9224bdae163aa170ef1cdc14d23a95ad68a4c4 Mon Sep 17 00:00:00 2001 From: EKNr1 Date: Thu, 29 Aug 2024 15:18:15 +0200 Subject: [PATCH] Added sparse voxel octree system. --- math/spvo.py | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 math/spvo.py diff --git a/math/spvo.py b/math/spvo.py new file mode 100644 index 0000000..5b27c72 --- /dev/null +++ b/math/spvo.py @@ -0,0 +1,80 @@ +#!/usr/bin/python3 + +""" +SPVO = Sparse Voxel Octree + +A Sparse Voxel Octree is a way of storing multidimensional data. (In this case it is 3D Data.) +It works similarly to a Sparse Voxel Matrix, but it is a bit compressed. +In a Sparse Voxel Octree, you have a root-node. The root node gets split up into 8 child nodes, +which can be all split up into 8 more child nodes which can be split up too and so on. +Thanks to this "compression", there are no zero values on places where there is just air unlike as in a normal matrix. +""" + + +class Node: + def __init__(self): + self.children = [None] * 8 + self.leaf = True + + +class SparseVoxelOctree: + def __init__(self, data=None): + self.root_node = Node() + self.origin = (0, 0, 0) + + self.data = data + + def _get_child_index(self, x, y, z, size): + index = 0 + + if x >= size // 2: + index |= 1 + x -= size // 2 + + if y >= size // 2: + index |= 2 + y -= size // 2 + + if z >= size // 2: + index |= 4 + z -= size // 2 + + return index, x, y, z + + def _extend_tree(self, x, y, z): + new_root = Node() + new_root.leaf = False + + index, nx, ny, nz = self._get_child_index(x, y, z, 2) + new_root.children[index] = self.root_node + self.root_node = new_root + + self.origin = ( + self.origin[0] - (x >= 0) * 2 + 1, + self.origin[1] - (y >= 0) * 2 + 1, + self.origin[2] - (z >= 0) * 2 + 1 + ) + + def _insert(self, node, x, y, z, size): + while not size == 1: + index, x, y, z = self._get_child_index(x, y, z, size) + + if node.children[index] is None: + node.children[index] = Node() + + size //= 2 + + node.leaf = True + + def insert(self, x, y, z): + # move origin if necessary + while not (0 <= x < 2 ** 30 and 0 <= y < 2 ** 30 and 0 <= z < 2 ** 30): + self._extend_tree(x, y, z) + + x, y, z = ( + x - self.origin[0], + y - self.origin[1], + z - self.origin[2] + ) + + self._insert(self.root_node, x, y, z, 2 ** 30)