4 changed files with 833 additions and 18 deletions
@ -1,25 +1,66 @@ |
|||||
#pragma once |
#pragma once |
||||
|
|
||||
#include "primitive_descriptor.h" |
#include "primitive_descriptor.h" |
||||
|
|
||||
typedef struct Blobtree blobtree_t; // fixed complete binary tree of 16 layers
|
// double node in the tree
|
||||
typedef struct Node node_t; // real node in the tree
|
typedef struct _node_t { |
||||
typedef struct VirtualNode virtual_node_t; // almost same as node_t, but has parent's and children's pointers to indicate the
|
unsigned int non_null : 1; // 0 for null pointer, 1 for non-null nodes
|
||||
// hierarchy, and it is outside of the tree
|
unsigned int primitive : 1; // 0 for internal node, 1 for primitive node
|
||||
|
unsigned int operate : 2; // 0 for union, 1 for intersection, 2 for difference, 3 for unset
|
||||
|
unsigned int cross : 2; // 0 for no cross, 1 for cross to parent, 2 for cross left child, 3 for cross right child
|
||||
|
unsigned int |
||||
|
index : 16; // If primitive node, the index to the primitive information, if cross node, the index to the cross node
|
||||
|
unsigned int main_index : 8; // use in cross node
|
||||
|
unsigned int placeholder : 2; // unused
|
||||
|
} node_t; |
||||
|
|
||||
|
typedef struct _primitive_node_t { |
||||
|
descriptor type; |
||||
|
void* desc; // Type conversion when using
|
||||
|
} primitive_node_t; |
||||
|
|
||||
|
// almost same as node_t, but has parent's and children's pointers to indicate
|
||||
|
// the hierarchy, and it is outside of the tree
|
||||
|
typedef struct _virtual_node_t { |
||||
|
unsigned int main_index : 16; |
||||
|
unsigned int inner_index : 16; |
||||
|
} virtual_node_t; |
||||
|
|
||||
|
// fixed complete binary tree of 16 layers
|
||||
|
typedef struct _blobtree_t { |
||||
|
node_t** structure; |
||||
|
int structure_size; |
||||
|
primitive_node_t* primitive; |
||||
|
int primitive_size; |
||||
|
} blobtree_t; |
||||
|
|
||||
EXTERN_C_BEGIN |
EXTERN_C_BEGIN |
||||
|
|
||||
API blobtree_t* create_blobtree(); |
API blobtree_t* create_blobtree(); |
||||
API void free_blobtree(blobtree_t* blobtree); |
API void free_blobtree(blobtree_t* blobtree); |
||||
|
|
||||
API virtual_node_t* blobtree_new_virtual_node(const constant_descriptor_t* desc); |
API virtual_node_t blobtree_new_virtual_node_constant(const constant_descriptor_t* desc, blobtree_t* blobtree); |
||||
API void blobtree_free_virtual_node(virtual_node_t* node); |
API virtual_node_t blobtree_new_virtual_node_plane(const plane_descriptor_t* desc, blobtree_t* blobtree); |
||||
|
API virtual_node_t blobtree_new_virtual_node_sphere(const sphere_descriptor_t* desc, blobtree_t* blobtree); |
||||
|
API virtual_node_t blobtree_new_virtual_node_cylinder(const cylinder_descriptor_t* desc, blobtree_t* blobtree); |
||||
|
API virtual_node_t blobtree_new_virtual_node_cone(const cone_descriptor_t* desc, blobtree_t* blobtree); |
||||
|
API virtual_node_t blobtree_new_virtual_node_box(const box_descriptor_t* desc, blobtree_t* blobtree); |
||||
|
API virtual_node_t blobtree_new_virtual_node_mesh(const mesh_descriptor_t* desc, blobtree_t* blobtree); |
||||
|
API virtual_node_t blobtree_new_virtual_node_extrude(const extrude_descriptor_t* desc, blobtree_t* blobtree); |
||||
|
API void blobtree_free_virtual_node(virtual_node_t* node); |
||||
|
|
||||
|
API bool virtual_node_set_parent(virtual_node_t* node, virtual_node_t* parent, blobtree_t* blobtree); |
||||
|
API bool virtual_node_set_left_child(virtual_node_t* node, virtual_node_t* child, blobtree_t* blobtree); |
||||
|
API bool virtual_node_set_right_child(virtual_node_t* node, virtual_node_t* child, blobtree_t* blobtree); |
||||
|
API bool virtual_node_add_child(virtual_node_t* node, virtual_node_t* child, blobtree_t* blobtree); |
||||
|
API bool virtual_node_remove_child(virtual_node_t* node, virtual_node_t* child, blobtree_t* blobtree); |
||||
|
|
||||
API void virtual_node_set_parent(virtual_node_t* node, virtual_node_t* parent); |
API bool virtual_node_replace_primitive_constant(virtual_node_t* node, const constant_descriptor_t* desc, blobtree_t* blobtree); |
||||
API void virtual_node_set_left_child(virtual_node_t* node, virtual_node_t* child); |
API bool virtual_node_replace_primitive_plane(virtual_node_t* node, const plane_descriptor_t* desc, blobtree_t* blobtree); |
||||
API void virtual_node_set_right_child(virtual_node_t* node, virtual_node_t* child); |
API bool virtual_node_replace_primitive_sphere(virtual_node_t* node, const sphere_descriptor_t* desc, blobtree_t* blobtree); |
||||
API void virtual_node_add_child(virtual_node_t* node, virtual_node_t* child); |
API bool virtual_node_replace_primitive_cylinder(virtual_node_t* node, const cylinder_descriptor_t* desc, blobtree_t* blobtree); |
||||
API void virtual_node_remove_child(virtual_node_t* node, virtual_node_t* child); |
API bool virtual_node_replace_primitive_cone(virtual_node_t* node, const cone_descriptor_t* desc, blobtree_t* blobtree); |
||||
API void virtual_node_replace_primitive(virtual_node_t* node, const constant_descriptor_t* desc); |
API bool virtual_node_replace_primitive_box(virtual_node_t* node, const box_descriptor_t* desc, blobtree_t* blobtree); |
||||
|
API bool virtual_node_replace_primitive_mesh(virtual_node_t* node, const mesh_descriptor_t* desc, blobtree_t* blobtree); |
||||
|
API bool virtual_node_replace_primitive_extrude(virtual_node_t* node, const extrude_descriptor_t* desc, blobtree_t* blobtree); |
||||
|
|
||||
EXTERN_C_END |
EXTERN_C_END |
@ -0,0 +1,462 @@ |
|||||
|
#include "blobtree.h" |
||||
|
#include <cstdlib> |
||||
|
|
||||
|
constexpr auto tree_vector_length = 65535; |
||||
|
|
||||
|
void create_new_sub_blobtree(blobtree_t* blobtree) |
||||
|
{ |
||||
|
blobtree->structure_size += 1; |
||||
|
blobtree->structure = static_cast<node_t**>(realloc(blobtree->structure, blobtree->structure_size * sizeof(node_t*))); |
||||
|
if (blobtree->structure == nullptr) { throw std::runtime_error("Memory allocation failed."); } |
||||
|
|
||||
|
blobtree->structure[blobtree->structure_size - 1] = static_cast<node_t*>(malloc(tree_vector_length * sizeof(node_t))); |
||||
|
if (blobtree->structure[blobtree->structure_size - 1] == nullptr) { throw std::runtime_error("Memory allocation failed."); } |
||||
|
memset(blobtree->structure[blobtree->structure_size - 1], 0.0, tree_vector_length * sizeof(node_t)); |
||||
|
} |
||||
|
|
||||
|
void free_sub_blobtree(blobtree_t* blobtree, const int index) |
||||
|
{ |
||||
|
free(blobtree->structure[index]); |
||||
|
blobtree->structure[index] = nullptr; |
||||
|
} |
||||
|
|
||||
|
int get_next_available_index(blobtree_t* blobtree) |
||||
|
{ |
||||
|
for (int i = 0; i < blobtree->structure_size; i++) { |
||||
|
if (blobtree->structure[i] == nullptr) { |
||||
|
blobtree->structure[i] = static_cast<node_t*>(malloc(tree_vector_length * sizeof(node_t))); |
||||
|
if (blobtree->structure[i] == nullptr) { throw std::runtime_error("Memory allocation failed."); } |
||||
|
memset(blobtree->structure[i], 0.0, tree_vector_length * sizeof(node_t)); |
||||
|
return i; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
create_new_sub_blobtree(blobtree); |
||||
|
return blobtree->structure_size - 1; |
||||
|
} |
||||
|
|
||||
|
blobtree_t* create_blobtree() |
||||
|
{ |
||||
|
blobtree_t* blobtree = static_cast<blobtree_t*>(malloc(sizeof(blobtree_t))); |
||||
|
if (blobtree == nullptr) { throw std::runtime_error("Memory allocation failed."); } |
||||
|
|
||||
|
blobtree->structure = static_cast<node_t**>(malloc(sizeof(node_t*))); |
||||
|
if (blobtree->structure == nullptr) { throw std::runtime_error("Memory allocation failed."); } |
||||
|
blobtree->structure_size = 0; |
||||
|
|
||||
|
blobtree->primitive = static_cast<primitive_node_t*>(malloc(sizeof(primitive_node_t))); |
||||
|
if (blobtree->primitive == nullptr) { throw std::runtime_error("Memory allocation failed."); } |
||||
|
blobtree->primitive_size = 0; |
||||
|
|
||||
|
return blobtree; |
||||
|
} |
||||
|
|
||||
|
void free_blobtree(blobtree_t* blobtree) |
||||
|
{ |
||||
|
for (int i = 0; i < blobtree->structure_size; i++) { free(blobtree->structure[i]); } |
||||
|
free(blobtree->structure); |
||||
|
free(blobtree->primitive); |
||||
|
free(blobtree); |
||||
|
} |
||||
|
|
||||
|
virtual_node_t push_primitive_node(blobtree_t* blobtree, const primitive_node_t& primitive_node) |
||||
|
{ |
||||
|
blobtree->primitive_size += 1; |
||||
|
blobtree->primitive = |
||||
|
static_cast<primitive_node_t*>(realloc(blobtree->primitive, (blobtree->primitive_size) * sizeof(primitive_node_t))); |
||||
|
if (blobtree->primitive == nullptr) { throw std::runtime_error("Memory allocation failed."); } |
||||
|
blobtree->primitive[blobtree->primitive_size - 1] = primitive_node; |
||||
|
|
||||
|
node_t new_node; |
||||
|
new_node.non_null = 1; |
||||
|
new_node.primitive = 1; |
||||
|
new_node.operate = 3; |
||||
|
new_node.cross = 0; |
||||
|
new_node.index = blobtree->primitive_size - 1; |
||||
|
new_node.main_index = 0; |
||||
|
|
||||
|
blobtree->structure[0] = static_cast<node_t*>(realloc(blobtree->structure[0], (blobtree->primitive_size) * sizeof(node_t))); |
||||
|
if (blobtree->primitive == nullptr) { throw std::runtime_error("Memory allocation failed."); } |
||||
|
blobtree->structure[0][blobtree->primitive_size - 1] = new_node; |
||||
|
|
||||
|
virtual_node_t virtual_node; |
||||
|
virtual_node.main_index = 0; |
||||
|
virtual_node.inner_index = blobtree->primitive_size - 1; |
||||
|
return virtual_node; |
||||
|
} |
||||
|
|
||||
|
virtual_node_t blobtree_new_virtual_node_constant(const constant_descriptor_t* desc, blobtree_t* blobtree) |
||||
|
{ |
||||
|
primitive_node_t primitive_node; |
||||
|
primitive_node.desc = (void*)desc; |
||||
|
primitive_node.type = constant; |
||||
|
return push_primitive_node(blobtree, primitive_node); |
||||
|
} |
||||
|
|
||||
|
virtual_node_t blobtree_new_virtual_node_plane(const plane_descriptor_t* desc, blobtree_t* blobtree) |
||||
|
{ |
||||
|
primitive_node_t primitive_node; |
||||
|
primitive_node.desc = (void*)desc; |
||||
|
primitive_node.type = plane; |
||||
|
return push_primitive_node(blobtree, primitive_node); |
||||
|
} |
||||
|
|
||||
|
virtual_node_t blobtree_new_virtual_node_sphere(const sphere_descriptor_t* desc, blobtree_t* blobtree) |
||||
|
{ |
||||
|
primitive_node_t primitive_node; |
||||
|
primitive_node.desc = (void*)desc; |
||||
|
primitive_node.type = sphere; |
||||
|
return push_primitive_node(blobtree, primitive_node); |
||||
|
} |
||||
|
|
||||
|
virtual_node_t blobtree_new_virtual_node_cylinder(const cylinder_descriptor_t* desc, blobtree_t* blobtree) |
||||
|
{ |
||||
|
primitive_node_t primitive_node; |
||||
|
primitive_node.desc = (void*)desc; |
||||
|
primitive_node.type = cylinder; |
||||
|
return push_primitive_node(blobtree, primitive_node); |
||||
|
} |
||||
|
|
||||
|
virtual_node_t blobtree_new_virtual_node_cone(const cone_descriptor_t* desc, blobtree_t* blobtree) |
||||
|
{ |
||||
|
primitive_node_t primitive_node; |
||||
|
primitive_node.desc = (void*)desc; |
||||
|
primitive_node.type = cone; |
||||
|
return push_primitive_node(blobtree, primitive_node); |
||||
|
} |
||||
|
|
||||
|
virtual_node_t blobtree_new_virtual_node_box(const box_descriptor_t* desc, blobtree_t* blobtree) |
||||
|
{ |
||||
|
primitive_node_t primitive_node; |
||||
|
primitive_node.desc = (void*)desc; |
||||
|
primitive_node.type = box; |
||||
|
return push_primitive_node(blobtree, primitive_node); |
||||
|
} |
||||
|
|
||||
|
virtual_node_t blobtree_new_virtual_node_mesh(const mesh_descriptor_t* desc, blobtree_t* blobtree) |
||||
|
{ |
||||
|
primitive_node_t primitive_node; |
||||
|
primitive_node.desc = (void*)desc; |
||||
|
primitive_node.type = mesh; |
||||
|
return push_primitive_node(blobtree, primitive_node); |
||||
|
} |
||||
|
|
||||
|
virtual_node_t blobtree_new_virtual_node_extrude(const extrude_descriptor_t* desc, blobtree_t* blobtree) |
||||
|
{ |
||||
|
primitive_node_t primitive_node; |
||||
|
primitive_node.desc = (void*)desc; |
||||
|
primitive_node.type = extrude; |
||||
|
return push_primitive_node(blobtree, primitive_node); |
||||
|
} |
||||
|
|
||||
|
void blobtree_free_virtual_node(virtual_node_t* node) { ; } |
||||
|
|
||||
|
virtual_node_t get_left_child_index(virtual_node_t node, blobtree_t* blobtree) |
||||
|
{ |
||||
|
int left_child_index = 2 * node.inner_index + 1; |
||||
|
auto temp = blobtree->structure[node.main_index][left_child_index]; |
||||
|
if (temp.cross == 2) { |
||||
|
return virtual_node_t{temp.main_index, temp.index}; |
||||
|
} else if (left_child_index >= tree_vector_length) { |
||||
|
auto main_index = get_next_available_index(blobtree); |
||||
|
return virtual_node_t{(unsigned int)main_index, 0}; |
||||
|
} else { |
||||
|
return virtual_node_t{node.main_index, (unsigned int)left_child_index}; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
virtual_node_t get_right_child_index(virtual_node_t node, blobtree_t* blobtree) |
||||
|
{ |
||||
|
int right_child_index = 2 * node.inner_index + 2; |
||||
|
auto temp = blobtree->structure[node.main_index][right_child_index]; |
||||
|
if (temp.cross == 3) { |
||||
|
return virtual_node_t{temp.main_index, temp.index}; |
||||
|
} else if (right_child_index >= tree_vector_length) { |
||||
|
auto main_index = get_next_available_index(blobtree); |
||||
|
return virtual_node_t{(unsigned int)main_index, 0}; |
||||
|
} else { |
||||
|
return virtual_node_t{node.main_index, (unsigned int)right_child_index}; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
virtual_node_t get_parent_index(virtual_node_t node, blobtree_t* blobtree) |
||||
|
{ |
||||
|
int parent_child_index = (node.inner_index - 1) / 2; |
||||
|
auto temp = blobtree->structure[node.main_index][parent_child_index]; |
||||
|
if (temp.cross == 1) { |
||||
|
return virtual_node_t{temp.main_index, temp.index}; |
||||
|
} else { |
||||
|
return virtual_node_t{node.main_index, (unsigned int)parent_child_index}; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
bool is_primitive_node(node_t node) { return node.primitive == 1; } |
||||
|
|
||||
|
bool is_null_node(node_t node) { return node.non_null == 0; } |
||||
|
|
||||
|
bool is_left_node(const int index) { return index % 2 == 1; } |
||||
|
|
||||
|
bool is_right_node(const int index) { return index % 2 == 0; } |
||||
|
|
||||
|
bool is_root_node(const int index) { return index == 0; } |
||||
|
|
||||
|
bool update_inner(virtual_node_t old_node, virtual_node_t new_node, blobtree_t* blobtree) |
||||
|
{ |
||||
|
if (is_null_node(blobtree->structure[old_node.main_index][old_node.inner_index])) { return true; } |
||||
|
|
||||
|
if (new_node.inner_index >= tree_vector_length) { return false; } |
||||
|
|
||||
|
if (!is_null_node(blobtree->structure[new_node.main_index][new_node.inner_index])) { return false; } |
||||
|
|
||||
|
if (is_primitive_node(blobtree->structure[new_node.main_index][new_node.inner_index])) { |
||||
|
blobtree->structure[new_node.main_index][new_node.inner_index] = |
||||
|
blobtree->structure[old_node.main_index][old_node.inner_index]; |
||||
|
blobtree->structure[old_node.main_index][old_node.inner_index].non_null = 0; |
||||
|
return true; |
||||
|
} else { |
||||
|
if (!update_inner(get_left_child_index(old_node, blobtree), get_left_child_index(new_node, blobtree), blobtree)) { |
||||
|
return false; |
||||
|
} |
||||
|
if (!update_inner(get_right_child_index(old_node, blobtree), get_right_child_index(new_node, blobtree), blobtree)) { |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
blobtree->structure[new_node.main_index][new_node.inner_index] = |
||||
|
blobtree->structure[old_node.main_index][old_node.inner_index]; |
||||
|
blobtree->structure[old_node.main_index][old_node.inner_index].non_null = 0; |
||||
|
return true; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void copy_sub_blobtree(const int dst_main_index, const int src_main_index, blobtree_t* blobtree) |
||||
|
{ |
||||
|
memcpy(blobtree->structure[dst_main_index], blobtree->structure[src_main_index], tree_vector_length * sizeof(node_t)); |
||||
|
} |
||||
|
|
||||
|
bool update(virtual_node_t old_node, virtual_node_t new_node, blobtree_t* blobtree) |
||||
|
{ |
||||
|
// Virtual update, check for out-of-bounds
|
||||
|
auto temp_mian_index = get_next_available_index(blobtree); |
||||
|
copy_sub_blobtree(temp_mian_index, new_node.main_index, blobtree); |
||||
|
|
||||
|
if (update_inner(old_node, virtual_node_t{(unsigned)temp_mian_index, new_node.inner_index}, blobtree)) { |
||||
|
copy_sub_blobtree(new_node.main_index, temp_mian_index, blobtree); |
||||
|
free_sub_blobtree(blobtree, temp_mian_index); |
||||
|
return true; |
||||
|
} else { |
||||
|
free_sub_blobtree(blobtree, temp_mian_index); |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
bool virtual_node_boolean_union(virtual_node_t* node1, virtual_node_t* node2, blobtree_t* blobtree) { return false; } |
||||
|
|
||||
|
bool virtual_node_boolean_union_save_mode(virtual_node_t* node1, virtual_node_t* node2, blobtree_t* blobtree) { return false; } |
||||
|
|
||||
|
bool check(virtual_node_t node, blobtree_t* blobtree) |
||||
|
{ |
||||
|
if (is_null_node(blobtree->structure[node.main_index][node.inner_index])) { return false; } |
||||
|
|
||||
|
if (is_primitive_node(blobtree->structure[node.main_index][node.inner_index])) { return true; } |
||||
|
|
||||
|
if (!check(get_left_child_index(node, blobtree), blobtree)) { return false; } |
||||
|
if (!check(get_right_child_index(node, blobtree), blobtree)) { return false; } |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
bool virtual_node_set_parent(virtual_node_t* node, virtual_node_t* parent, blobtree_t* blobtree) |
||||
|
{ |
||||
|
if (node->main_index == 0) { return false; } |
||||
|
|
||||
|
auto parent_index = get_parent_index(*node, blobtree); |
||||
|
if (!is_root_node(parent_index.inner_index) |
||||
|
&& !is_null_node(blobtree->structure[parent_index.main_index][parent_index.inner_index])) { |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
auto left_child_index = get_left_child_index(*parent, blobtree); |
||||
|
auto right_child_index = get_right_child_index(*parent, blobtree); |
||||
|
if (is_left_node(node->inner_index) |
||||
|
&& is_null_node(blobtree->structure[left_child_index.main_index][left_child_index.inner_index])) { |
||||
|
if (is_root_node(node->inner_index)) { |
||||
|
if (!update(*node, get_left_child_index(*node, blobtree), blobtree)) { return false; } |
||||
|
} |
||||
|
if (!update(*parent, get_parent_index(*node, blobtree), blobtree)) { return false; } |
||||
|
return true; |
||||
|
} else if (is_right_node(node->inner_index) |
||||
|
&& is_null_node(blobtree->structure[right_child_index.main_index][right_child_index.inner_index])) { |
||||
|
if (is_root_node(node->inner_index)) { |
||||
|
if (!update(*node, get_right_child_index(*node, blobtree), blobtree)) { return false; } |
||||
|
} |
||||
|
if (!update(*parent, get_parent_index(*node, blobtree), blobtree)) { return false; } |
||||
|
return true; |
||||
|
} else { |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
bool virtual_node_set_left_child(virtual_node_t* node, virtual_node_t* child, blobtree_t* blobtree) |
||||
|
{ |
||||
|
int parent_index = get_parent_index(*child, blobtree).inner_index; |
||||
|
int left_child_index = get_left_child_index(*node, blobtree).inner_index; |
||||
|
|
||||
|
if (!is_root_node(child->inner_index) && !is_null_node(blobtree->structure[child->main_index][parent_index])) { |
||||
|
return false; |
||||
|
} |
||||
|
if (!is_null_node(blobtree->structure[node->main_index][left_child_index])) { return false; } |
||||
|
|
||||
|
if (update(*child, virtual_node_t{node->main_index, (unsigned int)left_child_index}, blobtree)) { |
||||
|
*child = *node; |
||||
|
return true; |
||||
|
} else { |
||||
|
blobtree->structure[node->main_index][left_child_index].non_null = 1; |
||||
|
blobtree->structure[node->main_index][left_child_index].cross = 2; |
||||
|
blobtree->structure[node->main_index][left_child_index].main_index = child->main_index; |
||||
|
blobtree->structure[node->main_index][left_child_index].index = child->inner_index; |
||||
|
|
||||
|
blobtree->structure[child->main_index][parent_index].non_null = 1; |
||||
|
blobtree->structure[child->main_index][parent_index].cross = 1; |
||||
|
blobtree->structure[child->main_index][parent_index].main_index = node->main_index; |
||||
|
blobtree->structure[child->main_index][parent_index].index = node->inner_index; |
||||
|
return true; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
bool virtual_node_set_right_child(virtual_node_t* node, virtual_node_t* child, blobtree_t* blobtree) |
||||
|
{ |
||||
|
int parent_index = get_parent_index(*child, blobtree).inner_index; |
||||
|
int right_child_index = get_right_child_index(*node, blobtree).inner_index; |
||||
|
|
||||
|
if (!is_root_node(child->inner_index) && !is_null_node(blobtree->structure[child->main_index][parent_index])) { |
||||
|
return false; |
||||
|
} |
||||
|
if (!is_null_node(blobtree->structure[node->main_index][right_child_index])) { return false; } |
||||
|
|
||||
|
if (update(*child, virtual_node_t{node->main_index, (unsigned int)right_child_index}, blobtree)) { |
||||
|
*child = *node; |
||||
|
return true; |
||||
|
} else { |
||||
|
blobtree->structure[node->main_index][right_child_index].non_null = 1; |
||||
|
blobtree->structure[node->main_index][right_child_index].cross = 3; |
||||
|
blobtree->structure[node->main_index][right_child_index].main_index = child->main_index; |
||||
|
blobtree->structure[node->main_index][right_child_index].index = child->inner_index; |
||||
|
|
||||
|
blobtree->structure[child->main_index][parent_index].non_null = 1; |
||||
|
blobtree->structure[child->main_index][parent_index].cross = 1; |
||||
|
blobtree->structure[child->main_index][parent_index].main_index = node->main_index; |
||||
|
blobtree->structure[child->main_index][parent_index].index = node->inner_index; |
||||
|
return true; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
bool virtual_node_add_child(virtual_node_t* node, virtual_node_t* child, blobtree_t* blobtree) |
||||
|
{ |
||||
|
auto parent_index = get_parent_index(*child, blobtree).inner_index; |
||||
|
if (!is_root_node(child->inner_index) && !is_null_node(blobtree->structure[child->main_index][parent_index])) { |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
if (is_null_node(blobtree->structure[node->main_index][get_left_child_index(*node, blobtree).inner_index])) { |
||||
|
virtual_node_set_left_child(node, child, blobtree); |
||||
|
return true; |
||||
|
} else if (is_null_node(blobtree->structure[node->main_index][get_right_child_index(*node, blobtree).inner_index])) { |
||||
|
virtual_node_set_right_child(node, child, blobtree); |
||||
|
return true; |
||||
|
} else { |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void remove(virtual_node_t node, blobtree_t* blobtree) |
||||
|
{ |
||||
|
if (is_null_node(blobtree->structure[node.main_index][node.inner_index])) { return; } |
||||
|
|
||||
|
blobtree->structure[node.main_index][node.inner_index].non_null = 0; |
||||
|
|
||||
|
if (is_primitive_node(blobtree->structure[node.main_index][node.inner_index])) { return; } |
||||
|
|
||||
|
remove(get_left_child_index(node, blobtree), blobtree); |
||||
|
remove(get_right_child_index(node, blobtree), blobtree); |
||||
|
} |
||||
|
|
||||
|
bool operator==(const virtual_node_t& node1, const virtual_node_t& node2) |
||||
|
{ |
||||
|
return node1.main_index == node2.main_index && node1.inner_index == node2.inner_index; |
||||
|
} |
||||
|
|
||||
|
bool virtual_node_remove_child(virtual_node_t* node, virtual_node_t* child, blobtree_t* blobtree) |
||||
|
{ |
||||
|
if (get_left_child_index(*node, blobtree) == *child) { |
||||
|
remove(*child, blobtree); |
||||
|
return true; |
||||
|
} else if (get_right_child_index(*node, blobtree) == *child) { |
||||
|
remove(*child, blobtree); |
||||
|
return true; |
||||
|
} else { |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
bool virtual_node_replace_primitive_constant(virtual_node_t* node, const constant_descriptor_t* desc, blobtree_t* blobtree) |
||||
|
{ |
||||
|
if (!is_primitive_node(blobtree->structure[node->main_index][node->inner_index])) { return false; } |
||||
|
blobtree->primitive[blobtree->structure[node->main_index][node->inner_index].index].desc = (void*)desc; |
||||
|
blobtree->primitive[blobtree->structure[node->main_index][node->inner_index].index].type = constant; |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
bool virtual_node_replace_primitive_plane(virtual_node_t* node, const plane_descriptor_t* desc, blobtree_t* blobtree) |
||||
|
{ |
||||
|
if (!is_primitive_node(blobtree->structure[node->main_index][node->inner_index])) { return false; } |
||||
|
blobtree->primitive[blobtree->structure[node->main_index][node->inner_index].index].desc = (void*)desc; |
||||
|
blobtree->primitive[blobtree->structure[node->main_index][node->inner_index].index].type = plane; |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
bool virtual_node_replace_primitive_sphere(virtual_node_t* node, const sphere_descriptor_t* desc, blobtree_t* blobtree) |
||||
|
{ |
||||
|
if (!is_primitive_node(blobtree->structure[node->main_index][node->inner_index])) { return false; } |
||||
|
blobtree->primitive[blobtree->structure[node->main_index][node->inner_index].index].desc = (void*)desc; |
||||
|
blobtree->primitive[blobtree->structure[node->main_index][node->inner_index].index].type = sphere; |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
bool virtual_node_replace_primitive_cylinder(virtual_node_t* node, const cylinder_descriptor_t* desc, blobtree_t* blobtree) |
||||
|
{ |
||||
|
if (!is_primitive_node(blobtree->structure[node->main_index][node->inner_index])) { return false; } |
||||
|
blobtree->primitive[blobtree->structure[node->main_index][node->inner_index].index].desc = (void*)desc; |
||||
|
blobtree->primitive[blobtree->structure[node->main_index][node->inner_index].index].type = cylinder; |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
bool virtual_node_replace_primitive_cone(virtual_node_t* node, const cone_descriptor_t* desc, blobtree_t* blobtree) |
||||
|
{ |
||||
|
if (!is_primitive_node(blobtree->structure[node->main_index][node->inner_index])) { return false; } |
||||
|
blobtree->primitive[blobtree->structure[node->main_index][node->inner_index].index].desc = (void*)desc; |
||||
|
blobtree->primitive[blobtree->structure[node->main_index][node->inner_index].index].type = cone; |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
bool virtual_node_replace_primitive_box(virtual_node_t* node, const box_descriptor_t* desc, blobtree_t* blobtree) |
||||
|
{ |
||||
|
if (!is_primitive_node(blobtree->structure[node->main_index][node->inner_index])) { return false; } |
||||
|
blobtree->primitive[blobtree->structure[node->main_index][node->inner_index].index].desc = (void*)desc; |
||||
|
blobtree->primitive[blobtree->structure[node->main_index][node->inner_index].index].type = box; |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
bool virtual_node_replace_primitive_mesh(virtual_node_t* node, const mesh_descriptor_t* desc, blobtree_t* blobtree) |
||||
|
{ |
||||
|
if (!is_primitive_node(blobtree->structure[node->main_index][node->inner_index])) { return false; } |
||||
|
blobtree->primitive[blobtree->structure[node->main_index][node->inner_index].index].desc = (void*)desc; |
||||
|
blobtree->primitive[blobtree->structure[node->main_index][node->inner_index].index].type = mesh; |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
bool virtual_node_replace_primitive_extrude(virtual_node_t* node, const extrude_descriptor_t* desc, blobtree_t* blobtree) |
||||
|
{ |
||||
|
if (!is_primitive_node(blobtree->structure[node->main_index][node->inner_index])) { return false; } |
||||
|
blobtree->primitive[blobtree->structure[node->main_index][node->inner_index].index].desc = (void*)desc; |
||||
|
blobtree->primitive[blobtree->structure[node->main_index][node->inner_index].index].type = extrude; |
||||
|
return true; |
||||
|
} |
@ -0,0 +1,266 @@ |
|||||
|
#include "primitive_descriptor.h" |
||||
|
|
||||
|
typedef raw_vector3d_t vec3; |
||||
|
|
||||
|
vec3 add(const vec3& point1, const vec3& point2) { return vec3{point1.x + point2.x, point1.y + point2.y, point1.z + point2.z}; } |
||||
|
|
||||
|
vec3 operator+(const vec3& point1, const vec3& point2) { return add(point1, point2); } |
||||
|
|
||||
|
vec3 sub(const vec3& point1, const vec3& point2) { return vec3{point1.x - point2.x, point1.y - point2.y, point1.z - point2.z}; } |
||||
|
|
||||
|
vec3 operator-(const vec3& point1, const vec3& point2) { return sub(point1, point2); } |
||||
|
|
||||
|
vec3 mul(const vec3& vector, const double scalar) { return vec3{vector.x * scalar, vector.y * scalar, vector.z * scalar}; } |
||||
|
|
||||
|
vec3 operator*(const vec3& point1, const double scalar) { return mul(point1, scalar); } |
||||
|
|
||||
|
vec3 div(const vec3& vector, const double scalar) |
||||
|
{ |
||||
|
if (scalar == 0) { throw std::runtime_error("Division by zero error."); } |
||||
|
return vec3{vector.x / scalar, vector.y / scalar, vector.z / scalar}; |
||||
|
} |
||||
|
|
||||
|
vec3 operator/(const vec3& point1, const double scalar) { return div(point1, scalar); } |
||||
|
|
||||
|
double dot(const vec3& vector1, const vec3& vector2) |
||||
|
{ |
||||
|
return vector1.x * vector2.x + vector1.y * vector2.y + vector1.z * vector2.z; |
||||
|
} |
||||
|
|
||||
|
double dot2(const vec3& vector) { return dot(vector, vector); } |
||||
|
|
||||
|
vec3 cross(const vec3& vector1, const vec3& vector2) |
||||
|
{ |
||||
|
return vec3{vector1.y * vector2.z - vector1.z * vector2.y, |
||||
|
vector1.z * vector2.x - vector1.x * vector2.z, |
||||
|
vector1.x * vector2.y - vector1.y * vector2.x}; |
||||
|
} |
||||
|
|
||||
|
double len(const vec3& vector) { return sqrt(dot(vector, vector)); } |
||||
|
|
||||
|
double dis(const vec3& point1, const vec3& point2) { return len(sub(point1, point2)); } |
||||
|
|
||||
|
double clamp(const double t, const double min, const double max) |
||||
|
{ |
||||
|
if (t <= min) { return min; } |
||||
|
if (t >= max) { return max; } |
||||
|
return t; |
||||
|
} |
||||
|
|
||||
|
double sign(const double t) { return t >= 0.0 ? 1.0 : -1.0; } |
||||
|
|
||||
|
vec3 normalize(const vec3& vector) |
||||
|
{ |
||||
|
double temp = len(vector); |
||||
|
if (abs(temp) < 1e-8) { throw std::runtime_error("Cannot normalize a zero-length vector."); } |
||||
|
temp = 1.0 / temp; |
||||
|
return vec3{vector.x * temp, vector.y * temp, vector.z * temp}; |
||||
|
} |
||||
|
|
||||
|
double evaluate_constant(constant_descriptor_t* desc, raw_vector3d_t point) { return desc->value; } |
||||
|
|
||||
|
double evaluate_plane(plane_descriptor_t* desc, raw_vector3d_t point) { return dot(point - desc->point, desc->normal); } |
||||
|
|
||||
|
double evaluate_sphere(sphere_descriptor_t* desc, raw_vector3d_t point) { return dis(point, desc->center) - desc->radius; } |
||||
|
|
||||
|
double evaluate_cylinder(cylinder_descriptor_t* desc, raw_vector3d_t point) |
||||
|
{ |
||||
|
vec3& b = desc->bottom_origion; |
||||
|
vec3 a = b + desc->offset; |
||||
|
vec3& p = point; |
||||
|
double r = desc->radius; |
||||
|
|
||||
|
vec3 ba = b - a; |
||||
|
vec3 pa = p - a; |
||||
|
double baba = dot(ba, ba); |
||||
|
double paba = dot(pa, ba); |
||||
|
double x = len(pa * baba - ba * paba) - r * baba; |
||||
|
double y = abs(paba - baba * 0.5) - baba * 0.5; |
||||
|
double x2 = x * x; |
||||
|
double y2 = y * y * baba; |
||||
|
double d = (fmax(x, y) < 0.0) ? -fmin(x2, y2) : (((x > 0.0) ? x2 : 0.0) + ((y > 0.0) ? y2 : 0.0)); |
||||
|
return sign(d) * sqrt(abs(d)) / baba; |
||||
|
} |
||||
|
|
||||
|
double evaluate_cone(cone_descriptor_t* desc, raw_vector3d_t point) |
||||
|
{ |
||||
|
vec3& a = desc->top_point; |
||||
|
vec3& b = desc->bottom_point; |
||||
|
vec3& p = point; |
||||
|
double ra = desc->radius1; |
||||
|
double rb = desc->radius2; |
||||
|
|
||||
|
double rba = rb - ra; |
||||
|
double baba = dot(b - a, b - a); |
||||
|
double papa = dot(p - a, p - a); |
||||
|
double paba = dot(p - a, b - a) / baba; |
||||
|
double x = sqrt(papa - paba * paba * baba); |
||||
|
double cax = fmax(0.0, x - ((paba < 0.5) ? ra : rb)); |
||||
|
double cay = abs(paba - 0.5) - 0.5; |
||||
|
double k = rba * rba + baba; |
||||
|
double f = clamp((rba * (x - ra) + paba * baba) / k, 0.0, 1.0); |
||||
|
double cbx = x - ra - f * rba; |
||||
|
double cby = paba - f; |
||||
|
double s = (cbx < 0.0 && cay < 0.0) ? -1.0 : 1.0; |
||||
|
return s * sqrt(fmin(cax * cax + cay * cay * baba, cbx * cbx + cby * cby * baba)); |
||||
|
} |
||||
|
|
||||
|
double evaluate_box(box_descriptor_t* desc, raw_vector3d_t point) |
||||
|
{ |
||||
|
// Get the minimum and maximum bounding coordinates of the box
|
||||
|
auto min_point = desc->left_bottom_point; |
||||
|
auto max_point = min_point + vec3{desc->length, desc->width, desc->height}; |
||||
|
|
||||
|
// Point in the box
|
||||
|
if (point.x >= min_point.x && point.x <= max_point.x && point.y >= min_point.y && point.y <= max_point.y |
||||
|
&& point.z >= min_point.z && point.z <= max_point.z) { |
||||
|
double min = fmin(point.x - min_point.x, max_point.x - point.x); |
||||
|
min = fmin(min, fmin(point.y - min_point.y, max_point.y - point.y)); |
||||
|
min = fmin(min, fmin(point.z - min_point.y, max_point.z - point.z)); |
||||
|
return -min; |
||||
|
} else { |
||||
|
// Calculate the closest distance from the point to the border of each dimension of the box
|
||||
|
double dx = fmax(fmax(min_point.x - point.x, point.x - max_point.x), 0.0); |
||||
|
double dy = fmax(fmax(min_point.y - point.y, point.y - max_point.y), 0.0); |
||||
|
double dz = fmax(fmax(min_point.z - point.z, point.z - max_point.z), 0.0); |
||||
|
return sqrt(dx * dx + dy * dy + dz * dz); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
double triangle_sdf(const vec3& p, const vec3& a, const vec3& b, const vec3& c) |
||||
|
{ |
||||
|
vec3 ba = b - a; |
||||
|
vec3 pa = p - a; |
||||
|
vec3 cb = c - b; |
||||
|
vec3 pb = p - b; |
||||
|
vec3 ac = a - c; |
||||
|
vec3 pc = p - c; |
||||
|
vec3 nor = cross(ba, ac); |
||||
|
|
||||
|
return sqrt((sign(dot(cross(ba, nor), pa)) + sign(dot(cross(cb, nor), pb)) + sign(dot(cross(ac, nor), pc)) < 2.0) |
||||
|
? fmin(fmin(dot2(ba * clamp(dot(ba, pa) / dot2(ba), 0.0, 1.0) - pa), |
||||
|
dot2(cb * clamp(dot(cb, pb) / dot2(cb), 0.0, 1.0) - pb)), |
||||
|
dot2(ac * clamp(dot(ac, pc) / dot2(ac), 0.0, 1.0) - pc)) |
||||
|
: dot(nor, pa) * dot(nor, pa) / dot2(nor)); |
||||
|
} |
||||
|
|
||||
|
bool ray_intersects_triangle(const vec3& point, const vec3& dir, const vec3& v0, const vec3& v1, const vec3& v2) |
||||
|
{ |
||||
|
vec3 e1 = v1 - v0; |
||||
|
vec3 e2 = v2 - v0; |
||||
|
vec3 s = point - v0; |
||||
|
vec3 s1 = cross(dir, e2); |
||||
|
vec3 s2 = cross(s, e1); |
||||
|
double coeff = 1.0 / dot(s1, e1); |
||||
|
double t = coeff * dot(s2, e2); |
||||
|
double b1 = coeff * dot(s1, s); |
||||
|
double b2 = coeff * dot(s2, dir); |
||||
|
return t >= 0 && b1 >= 0 && b2 >= 0 && (1 - b1 - b2) >= 0; |
||||
|
} |
||||
|
|
||||
|
double evaluate_mesh(mesh_descriptor_t* desc, raw_vector3d_t point) |
||||
|
{ |
||||
|
// Note: There is no check for out-of-bounds access to points, indexes and faces
|
||||
|
auto points = desc->points; |
||||
|
auto indexs = desc->indexs; |
||||
|
auto face = desc->faces; |
||||
|
|
||||
|
double min_distance = std::numeric_limits<double>::infinity(); |
||||
|
int count = 0; |
||||
|
for (int i = 0; i < desc->face_number; i++) { |
||||
|
int begin_index = face[i][0]; |
||||
|
int length = face[i][1]; |
||||
|
|
||||
|
auto& point0 = points[indexs[begin_index]]; |
||||
|
bool flag = false; |
||||
|
for (int j = 1; j < length - 1; j++) { |
||||
|
double temp = triangle_sdf(point, point0, points[indexs[j]], points[indexs[j + 1]]); |
||||
|
min_distance = fmin(min_distance, temp); |
||||
|
if (!flag |
||||
|
&& ray_intersects_triangle(point, vec3{1.0, 0.0, 0.0}, point0, points[indexs[j]], points[indexs[j + 1]])) { |
||||
|
flag = true; |
||||
|
} |
||||
|
} |
||||
|
if (flag) { count++; } |
||||
|
} |
||||
|
|
||||
|
if (min_distance < 1e-8) { return 0; } |
||||
|
if (count % 2 == 1) { |
||||
|
return -min_distance; |
||||
|
} else { |
||||
|
return min_distance; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
double evaluate_extrude(extrude_descriptor_t* desc, raw_vector3d_t point) |
||||
|
{ |
||||
|
// Note: There is no check for out-of-bounds access to points and bulges
|
||||
|
auto points = desc->points; |
||||
|
auto bulges = desc->bulges; |
||||
|
auto extusion = desc->extusion; |
||||
|
|
||||
|
double min_distance = std::numeric_limits<double>::infinity(); |
||||
|
int count = 0; |
||||
|
|
||||
|
// Note: Currently only straight edges are considered, the bottom and top surfaces are polygons
|
||||
|
auto& point0 = points[0]; |
||||
|
bool flag1 = false; |
||||
|
bool flag2 = false; |
||||
|
for (int i = 1; i < desc->edges_number - 1; i++) { |
||||
|
// Bottom
|
||||
|
double temp = triangle_sdf(point, point0, points[i], points[i + 1]); |
||||
|
min_distance = fmin(min_distance, temp); |
||||
|
if (!flag1 && ray_intersects_triangle(point, vec3{1.0, 0.0, 0.0}, point0, points[i], points[i + 1])) { flag1 = true; } |
||||
|
|
||||
|
// Top
|
||||
|
temp = triangle_sdf(point, point0 + extusion, points[i] + extusion, points[i + 1] + extusion); |
||||
|
min_distance = fmin(min_distance, temp); |
||||
|
if (!flag2 |
||||
|
&& ray_intersects_triangle(point, |
||||
|
vec3{1.0, 0.0, 0.0}, |
||||
|
point0 + extusion, |
||||
|
points[i] + extusion, |
||||
|
points[i + 1] + extusion)) { |
||||
|
flag2 = true; |
||||
|
} |
||||
|
} |
||||
|
if (flag1) { count++; } |
||||
|
if (flag2) { count++; } |
||||
|
|
||||
|
// Side
|
||||
|
for (int i = 0; i < desc->edges_number; i++) { |
||||
|
auto& point1 = points[i]; |
||||
|
vec3 point2; |
||||
|
if (i + 1 == desc->edges_number) { |
||||
|
point2 = points[0]; |
||||
|
} else { |
||||
|
point2 = points[i + 1]; |
||||
|
} |
||||
|
auto point3 = point2 + extusion; |
||||
|
auto point4 = point1 + extusion; |
||||
|
|
||||
|
auto bulge = bulges[i]; |
||||
|
if (abs(bulge) < 1e-8) { |
||||
|
// Straight Edge
|
||||
|
bool flag = false; |
||||
|
|
||||
|
double temp = triangle_sdf(point, point1, point2, point3); |
||||
|
min_distance = fmin(min_distance, temp); |
||||
|
if (!flag && ray_intersects_triangle(point, vec3{1.0, 0.0, 0.0}, point1, point2, point3)) { flag = true; } |
||||
|
|
||||
|
temp = triangle_sdf(point, point1, point3, point4); |
||||
|
min_distance = fmin(min_distance, temp); |
||||
|
if (!flag && ray_intersects_triangle(point, vec3{1.0, 0.0, 0.0}, point1, point3, point4)) { flag = true; } |
||||
|
|
||||
|
if (flag) { count++; } |
||||
|
} else { |
||||
|
// Curved Edge
|
||||
|
// TODO
|
||||
|
} |
||||
|
} |
||||
|
if (count % 2 == 1) { |
||||
|
return -min_distance; |
||||
|
} else { |
||||
|
return min_distance; |
||||
|
} |
||||
|
} |
Loading…
Reference in new issue