# -*- python -*-
#
# Copyright INRIA - CIRAD - INRA
#
# Distributed under the Cecill-C License.
# See accompanying file LICENSE.txt or copy at
# http://www.cecill.info/licences/Licence_CeCILL-C_V1-en.html
#
# ==============================================================================
from __future__ import division, print_function, absolute_import
import json
import os
import copy
from .voxelGrid import VoxelGrid
# ==============================================================================
[docs]
class VoxelNode:
[docs]
def __init__(self, position, size, data, father):
self.position = position
self.size = size
self.data = data
self.father = father
self.sons = [None, None, None, None, None, None, None, None]
self.is_leaf = True
def __str__(self):
return f"""
OcNode:
\tposition : {self.position}
\tsize : {self.size}
\tdata: {self.data}
\tis_leaf : {self.is_leaf}
"""
def creates_sons(self):
r = self.size / 4.0
d = self.size / 2.0
x_min = self.position[0] - r
x_max = self.position[0] + r
y_min = self.position[1] - r
y_max = self.position[1] + r
z_min = self.position[2] - r
z_max = self.position[2] + r
self.sons = [
VoxelNode((x_min, y_min, z_min), d, self.data, self),
VoxelNode((x_max, y_min, z_min), d, self.data, self),
VoxelNode((x_min, y_max, z_min), d, self.data, self),
VoxelNode((x_min, y_min, z_max), d, self.data, self),
VoxelNode((x_max, y_max, z_min), d, self.data, self),
VoxelNode((x_max, y_min, z_max), d, self.data, self),
VoxelNode((x_min, y_max, z_max), d, self.data, self),
VoxelNode((x_max, y_max, z_max), d, self.data, self),
]
self.is_leaf = False
return self.sons
def get_nodes(
self,
func_if_true_add_node=lambda n: True,
func_if_true_look_in_sons=lambda n: True,
func_get=lambda n: n,
):
l = []
if func_if_true_add_node(self):
l.append(func_get(self))
if not self.is_leaf:
if func_if_true_look_in_sons(self):
for son in self.sons:
l.extend(
son.get_nodes(
func_if_true_add_node=func_if_true_add_node,
func_if_true_look_in_sons=func_if_true_look_in_sons,
func_get=func_get,
)
)
return l
def get_sons_voxels_position_with_size(self, voxels_size):
l = []
if self.data is True:
if self.size == voxels_size:
l.append(self.position)
else:
if not self.is_leaf:
for son in self.sons:
l.extend(son.get_sons_voxels_position_with_size(voxels_size))
return l
def get_leafs(self):
def func_if_true_add_node(node):
return node.is_leaf
return self.get_nodes(func_if_true_add_node=func_if_true_add_node)
def in_it(self, position):
r = self.size / 2.0
x, y, z = position
if (
self.position[0] - r <= x <= self.position[0] + r
and self.position[1] - r <= y <= self.position[1] + r
) and self.position[2] - r <= z <= self.position[2] + r:
return True
return False
def get_neighbors_positions(self):
cx, cy, cz = self.position
cx_min, cx_max = cx - self.size, cx + self.size
cy_min, cy_max = cy - self.size, cy + self.size
cz_min, cz_max = cz - self.size, cz + self.size
neighbors = [
(cx, cy, cz_max),
(cx_min, cy, cz_max),
(cx_max, cy, cz_max),
(cx, cy_min, cz_max),
(cx_min, cy_min, cz_max),
(cx_max, cy_min, cz_max),
(cx, cy_max, cz_max),
(cx_min, cy_max, cz_max),
(cx_max, cy_max, cz_max),
(cx_min, cy, cz),
(cx_max, cy, cz),
(cx, cy_min, cz),
(cx_min, cy_min, cz),
(cx_max, cy_min, cz),
(cx, cy_max, cz),
(cx_min, cy_max, cz),
(cx_max, cy_max, cz),
(cx, cy, cz_min),
(cx_min, cy, cz_min),
(cx_max, cy, cz_min),
(cx, cy_min, cz_min),
(cx_min, cy_min, cz_min),
(cx_max, cy_min, cz_min),
(cx, cy_max, cz_min),
(cx_min, cy_max, cz_min),
(cx_max, cy_max, cz_min),
]
return neighbors
def get_node_position(self, position):
if (
self.position[0] == position[0]
and self.position[1] == position[1]
and self.position[2] == position[2]
):
return self
if not self.is_leaf and self.in_it(position):
for son in self.sons:
leaf = son.get_node_position(position)
if leaf is not None:
return leaf
return None
def get_with_position(self, position):
if self.in_it(position):
if self.is_leaf:
return self
for son in self.sons:
leaf = son.find_leaf_with_position(position)
if leaf is not None:
return leaf
return None
def get_root(self):
father = self.father
if father is None:
return self
grandfather = father.father
while grandfather is not None:
father = grandfather
grandfather = father.father
return father
def get_neighbors_leaf(self):
neighbors_positions = self.get_neighbors_positions()
root = self.get_root()
neighbors_leaf = []
for position in neighbors_positions:
leaf = root.find_leaf_with_position(position)
if leaf is not None:
neighbors_leaf.append(leaf)
return neighbors_leaf
def is_surrender(self):
neighbors_positions = self.get_neighbors_positions()
if self.father is None:
return False
for node in self.father.sons:
if node is self:
continue
if node.position in neighbors_positions:
if node.data:
neighbors_positions.remove(node.position)
else:
return False
else:
return False
root = self.get_root()
for position in neighbors_positions:
leaf = root.find_leaf_with_position(position)
if leaf is None or leaf.data is False:
return False
return True
def depth(self):
if self.is_leaf:
return 0
return 1 + max(node.depth() for node in self.sons)
def insert_node(self, position, data):
if self.in_it(position):
if self.position == position:
self.data = data
return self
if self.is_leaf:
self.creates_sons()
for son in self.sons:
node = son.insert_node(position, data)
if node is not None:
return node
return None
def get_dict_nodes(self):
if self.is_leaf:
return {
"position": self.position,
"size": self.size,
"data": self.data,
"sons": None,
}
sons = []
for leaf in self.sons:
sons.append(leaf.get_dict_nodes())
return {
"position": self.position,
"size": self.size,
"data": self.data,
"sons": sons,
}
[docs]
class VoxelOctree:
[docs]
def __init__(self):
self.root = None
@classmethod
def from_voxel_node(cls, node):
octree = cls()
octree.root = node
return octree
@classmethod
def from_position(cls, position, size, data):
octree = cls()
octree.root = VoxelNode(position, size, data, None)
return octree
def get_leafs(self):
if self.root is None:
raise ValueError("No root define")
return self.root.get_leafs()
def get_voxel_nodes(
self,
func_if_true_add_node=lambda n: True,
func_if_true_look_in_sons=lambda n: True,
func_get=lambda n: n,
):
if self.root is None:
raise ValueError("No root define")
return self.root.get_nodes(
func_if_true_add_node=func_if_true_add_node,
func_if_true_look_in_sons=func_if_true_look_in_sons,
func_get=func_get,
)
def get_leafs_with_data_equal_to(self, data):
leafs = self.root.get_leafs()
return [leaf for leaf in leafs if leaf.data == data]
def get_voxel_point_cloud(self, voxels_size):
def f(node):
if node.data is True:
if node.size == voxels_size:
return True
return False
voxels_position = self.root.get_nodes(
func_if_true_add_node=f, func_get=lambda n: n.position
)
return VoxelGrid(voxels_position, voxels_size)
def get_voxels_nodes_with_size_equal_to(self, voxels_size):
def f(node):
if node.size == voxels_size and node.data is True:
return True
return False
nodes = self.root.get_nodes(func_if_true_add_node=f, func_get=lambda n: n)
return nodes
def get_node_position(self, position):
return self.root.get_node_position(position)
def get_voxels_position(self, voxels_size):
def f(node):
if node.data is True:
if node.size == voxels_size:
return True
if node.is_leaf and node.size > voxels_size:
return True
return False
nodes = self.root.get_nodes(func_if_true_add_node=f, func_get=lambda n: n)
nodes_position = []
while nodes:
node = nodes.pop()
if node.size == voxels_size:
nodes_position.append(node.position)
else:
sons = (copy.copy(node)).creates_sons()
nodes.extend(sons)
return nodes_position
def get_nodes_with_size_and_data_equal_to(self, size, data):
nodes = self.root.get_nodes_with_size_equal_to(size)
return [node for node in nodes if node.data == data]
# ==========================================================================
# READ / WRITES
# ==========================================================================
def write(self, filename):
ext = filename.split(".")[-1]
if ext == "json":
return self.write_to_json(filename)
raise ValueError("No extension")
@staticmethod
def read(filename):
ext = filename.split(".")[-1]
if ext == "json":
return VoxelOctree.read_from_json(filename)
raise ValueError("No extension")
def write_to_json(self, filename):
if self.root is None:
raise ValueError("No root define")
if os.path.dirname(filename) and not os.path.exists(os.path.dirname(filename)):
os.makedirs(os.path.dirname(filename))
dict_nodes = self.root.get_dict_nodes()
with open(filename, "w", encoding="UTF8") as f:
json.dump(dict_nodes, f)
@staticmethod
def read_from_json(filename):
with open(filename, "r", encoding="UTF8") as f:
load_dict_octree = json.load(f)
root = VoxelOctree.from_dict(load_dict_octree, None)
return VoxelOctree.from_voxel_node(root)
@staticmethod
def from_dict(dict_node, father):
position = tuple(dict_node["position"])
data = dict_node["data"]
size = dict_node["size"]
dict_sons = dict_node["sons"]
node = VoxelNode(position, size, data, father)
if dict_sons is not None:
node.is_leaf = False
for i, val in enumerate(dict_sons):
node.sons[i] = VoxelOctree.from_dict(val, node)
else:
node.is_leaf = True
return node