diff --git a/blobtree_structure/include/aabb.hpp b/blobtree_structure/include/aabb.hpp new file mode 100644 index 0000000..17120ce --- /dev/null +++ b/blobtree_structure/include/aabb.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include "primitive_descriptor.h" + +#include "utils/eigen_alias.hpp" + +struct aabb_t { + Eigen::Vector3d min{std::numeric_limits::max(), + std::numeric_limits::max(), + std::numeric_limits::max()}; + Eigen::Vector3d max{std::numeric_limits::min(), + std::numeric_limits::min(), + std::numeric_limits::min()}; + + void extend(const Eigen::Vector3d& point) + { + min = min.cwiseMin(point); + max = max.cwiseMax(point); + } + + void extend(const aabb_t& aabb) + { + min = min.cwiseMin(aabb.min); + max = max.cwiseMax(aabb.max); + } + + void offset(const Eigen::Vector3d& offset) + { + min = min + offset; + max = max + offset; + } + +}; \ No newline at end of file diff --git a/blobtree_structure/include/globals.hpp b/blobtree_structure/include/globals.hpp new file mode 100644 index 0000000..7ab1afb --- /dev/null +++ b/blobtree_structure/include/globals.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include +#include + +#include + +#include "blobtree.h" + +#include "aabb.hpp" +#include "node_operation.hpp" + +struct blobtree_t { + std::vector> nodes{}; + std::vector> leaf_index{}; +}; + +extern std::vector> structures; +extern std::vector> aabbs; +extern std::vector> primitives; +extern std::stack>> free_structure_list; \ No newline at end of file diff --git a/blobtree_structure/include/node_operation.hpp b/blobtree_structure/include/node_operation.hpp new file mode 100644 index 0000000..3449357 --- /dev/null +++ b/blobtree_structure/include/node_operation.hpp @@ -0,0 +1,236 @@ +#pragma once + +#include + +struct node_t { + uint64_t data[2]; + + constexpr node_t() : data{0, 0} {} + + constexpr node_t(const uint64_t n1, const uint64_t n2) : data{n1, n2} {} + + template > + constexpr node_t(T value) + { + data[0] = 0; + data[1] = static_cast(value); + } + + template > + constexpr operator T() const + { + return static_cast(data[1]); + } + + node_t operator>>(const uint32_t shift) const + { + if (shift == 0) { return *this; } + + node_t result = *this; + + if (shift >= 128) { + result.data[0] = 0; + result.data[1] = 0; + } else if (shift >= 64) { + result.data[1] = this->data[0] >> (shift - 64); + result.data[0] = 0; + } else { + result.data[1] = (this->data[1] >> shift) | (this->data[0] << (64 - shift)); + result.data[0] = this->data[0] >> shift; + } + + return result; + } + + node_t operator<<(const uint32_t shift) const + { + if (shift == 0) { return *this; } + + node_t result = *this; + + if (shift >= 128) { + result.data[0] = 0; + result.data[1] = 0; + } else if (shift >= 64) { + result.data[0] = this->data[1] << (shift - 64); + result.data[1] = 0; + } else { + result.data[0] = (this->data[0] << shift) | (this->data[1] >> (64 - shift)); + result.data[1] = this->data[1] << shift; + } + + return result; + } + + const node_t operator&(const node_t& other) const + { + node_t result = *this; + result.data[0] &= other.data[0]; + result.data[1] &= other.data[1]; + return result; + } + + friend const node_t operator&(node_t, const uint32_t&); + + const node_t operator|(const node_t& other) const + { + node_t result = *this; + result.data[0] |= other.data[0]; + result.data[1] |= other.data[1]; + return result; + } + + friend const node_t operator|(node_t, const uint32_t&); + + const node_t operator~() const + { + node_t result = *this; + result.data[0] = ~result.data[0]; + result.data[1] = ~result.data[1]; + return result; + } +}; + +inline const node_t operator&(node_t lhs, const uint32_t& rhs) +{ + lhs.data[1] &= rhs; + return lhs; +} + +inline const node_t operator|(node_t lhs, const uint32_t& rhs) +{ + lhs.data[1] |= rhs; + return lhs; +} + +enum class eNodeLocation : uint32_t { in = 0, out = 1, edge = 2, unset = 3 }; +enum class eNodeOperation : uint32_t { unionOp = 0, intersectionOp = 1, differenceOp = 2, unsetOp = 3 }; + +/* getter/setter for node_t */ +template +struct node_proxy { + constexpr node_proxy() = default; + + constexpr node_proxy(node_t& _data, uint32_t _offset, node_t _mask) : data(&_data), offset(_offset), mask(_mask) {} + + void reinit(node_t& _data, uint32_t _offset, node_t _mask) + { + data = &_data; + offset = _offset; + mask = _mask; + } + + void reinit(node_proxy&& other) + { + data = std::move(other.data); + offset = std::move(other.offset); + mask = std::move(other.mask); + } + + node_proxy(const node_proxy&) = delete; + node_proxy(node_proxy&&) = delete; + + constexpr node_proxy& operator=(const node_proxy& other) + { + const auto _mask = mask << offset; + *data = (*data & ~_mask) | (other.data & _mask); + return *this; + } + + constexpr node_proxy& operator=(node_proxy&& other) + { + const auto _mask = mask << offset; + *data = (*data & ~_mask) | (std::forward(other.data) & _mask); + return *this; + } + + template >> + constexpr node_proxy& operator=(_Fp&& other) + { + const auto _mask = mask << offset; + if constexpr (std::is_enum_v<_Fp>) { + const auto offset_value = static_cast>(std::forward<_Fp>(other)) << offset; + *data = (*data & ~_mask) | (_mask & offset_value); + } else if constexpr (std::is_same_v<_Fp, bool>) { + const auto offset_value = static_cast(std::forward<_Fp>(other)) << offset; + *data = (*data & ~_mask) | (_mask & offset_value); + } else { + const auto offset_value = std::forward<_Fp>(other) << offset; + *data = (*data & ~_mask) | (_mask & offset_value); + } + return *this; + } + + template && // + !std::is_enum_v<_Fp> && // + !std::is_same_v<_Fp, bool>>> + constexpr node_proxy& operator+=(_Fp&& other) + { + const auto _mask = mask << offset; + const _Fp low_data = (*data) >> offset; + const auto low_result = std::forward<_Fp>(other) + low_data; + *data = (*data & ~_mask) | (_mask & (low_result << offset)); + return *this; + } + + constexpr operator _Tp() const { return static_cast<_Tp>(((*data) >> offset) & mask); } + +protected: + node_t* data; + uint32_t offset{}; + node_t mask{}; +}; + +template +struct const_node_proxy { + constexpr const_node_proxy(const node_t& _data, uint32_t _offset, node_t _mask) : data(&_data), offset(_offset), mask(_mask) + { + } + + const_node_proxy(const const_node_proxy&) = delete; + const_node_proxy(const_node_proxy&&) = delete; + + constexpr operator _Tp() const { return static_cast<_Tp>(((*data) >> offset) & mask); } + +protected: + const node_t* data; + uint32_t offset{}; + node_t mask{}; +}; + +// 0 for internal node, 1 for primitive node +static constexpr inline auto node_fetch_is_primitive(node_t& node) { return node_proxy(node, 127u, 0x01u); } + +// 0 for union, 1 for intersection, 2 for difference, 3 for unset +static constexpr inline auto node_fetch_operation(node_t& node) { return node_proxy(node, 125u, 0x03u); } + +// 0 for in, 1 for out, 2 for on edge, 3 for unset +static constexpr inline auto node_fetch_in_out(node_t& node) { return node_proxy(node, 123u, 0x03u); } + +// If primitive node, the index to the primitive information +static constexpr inline auto node_fetch_primitive_index(node_t& node) { return node_proxy(node, 96u, 0xFFFFFFu); } + +static constexpr inline auto node_is_parent_null(const node_t& node) +{ + return const_node_proxy(node, 96u, 0xFFFFFFu) == 0xFFFFFFFFu; +} + +// Parent node index +static constexpr inline auto node_fetch_parent_index(node_t& node) { return node_proxy(node, 64u, 0xFFFFFFFFu); } + +// Left child node index +static constexpr inline auto node_fetch_left_child_index(node_t& node) { return node_proxy(node, 32u, 0xFFFFFFFFu); } + +static constexpr inline auto node_is_left_child_null(const node_t& node) +{ + return const_node_proxy(node, 32u, 0xFFFFFFFFu) == 0xFFFFFFFFu; +} + +// Right child node index +static constexpr inline auto node_fetch_right_child_index(node_t& node) { return node_proxy(node, 0u, 0xFFFFFFFFu); } + +static constexpr inline auto node_is_right_child_null(const node_t& node) +{ + return const_node_proxy(node, 0u, 0xFFFFFFFFu) == 0xFFFFFFFFu; +} \ No newline at end of file diff --git a/blobtree_structure/interface/internal_api.hpp b/blobtree_structure/interface/internal_api.hpp index 69fa4d1..20f43e6 100644 --- a/blobtree_structure/interface/internal_api.hpp +++ b/blobtree_structure/interface/internal_api.hpp @@ -24,6 +24,16 @@ BPE_API double evaluate(const extrude_descriptor_t& desc, const Eigen::Ref>& get_primitives() noexcept; + +BPE_API void free_sub_blobtree(uint32_t index) noexcept; + // Geometry Generation /** @@ -88,12 +98,6 @@ BPE_API virtual_node_t blobtree_new_virtual_node(const extrude_descriptor_t& des */ BPE_API void blobtree_free_virtual_node(virtual_node_t* node); -/** - * @brief Get all primitive nodes - * @return Primitive array - */ -BPE_API std::vector>& get_primitives() noexcept; - // Geometry Operations /** diff --git a/blobtree_structure/src/blobtree.cpp b/blobtree_structure/src/blobtree.cpp index 5150608..798274a 100644 --- a/blobtree_structure/src/blobtree.cpp +++ b/blobtree_structure/src/blobtree.cpp @@ -1,337 +1,25 @@ #include -#include -#include #include "internal_api.hpp" -/* internal global variables for blobtree */ -typedef struct _node_t { - uint64_t data[2]; - - constexpr _node_t() : data{0, 0} {} - - constexpr _node_t(const uint64_t n1, const uint64_t n2) : data{n1, n2} {} - - template > - constexpr _node_t(T value) - { - data[0] = 0; - data[1] = static_cast(value); - } - - template > - constexpr operator T() const - { - return static_cast(data[1]); - } - - _node_t operator>>(const uint32_t shift) const - { - if (shift == 0) { return *this; } - - _node_t result = *this; - - if (shift >= 128) { - result.data[0] = 0; - result.data[1] = 0; - } else if (shift >= 64) { - result.data[1] = this->data[0] >> (shift - 64); - result.data[0] = 0; - } else { - result.data[1] = (this->data[1] >> shift) | (this->data[0] << (64 - shift)); - result.data[0] = this->data[0] >> shift; - } - - return result; - } - - _node_t operator<<(const uint32_t shift) const - { - if (shift == 0) { return *this; } - - _node_t result = *this; - - if (shift >= 128) { - result.data[0] = 0; - result.data[1] = 0; - } else if (shift >= 64) { - result.data[0] = this->data[1] << (shift - 64); - result.data[1] = 0; - } else { - result.data[0] = (this->data[0] << shift) | (this->data[1] >> (64 - shift)); - result.data[1] = this->data[1] << shift; - } - - return result; - } - - const _node_t operator&(const _node_t& other) const - { - _node_t result = *this; - result.data[0] &= other.data[0]; - result.data[1] &= other.data[1]; - return result; - } - - const _node_t operator&(const uint32_t other) const - { - _node_t result = *this; - result.data[1] &= other; - return result; - } - - const _node_t operator|(const _node_t& other) const - { - _node_t result = *this; - result.data[0] |= other.data[0]; - result.data[1] |= other.data[1]; - return result; - } - - const _node_t operator|(const uint32_t other) const - { - _node_t result = *this; - result.data[1] |= other; - return result; - } - - const _node_t operator~() const - { - _node_t result = *this; - result.data[0] = ~result.data[0]; - result.data[1] = ~result.data[1]; - return result; - } - -} node_t; - -const raw_vector3d_t operator+(const raw_vector3d_t& point1, const raw_vector3d_t& point2) -{ - raw_vector3d_t result; - result.x = point1.x + point2.x; - result.y = point1.y + point2.y; - result.z = point1.z + point2.z; - return result; -} - -const raw_vector3d_t operator-(const raw_vector3d_t& point1, const raw_vector3d_t& point2) -{ - raw_vector3d_t result; - result.x = point1.x - point2.x; - result.y = point1.y - point2.y; - result.z = point1.z - point2.z; - return result; -} - -const raw_vector3d_t operator+(const raw_vector3d_t& point, const double value) -{ - raw_vector3d_t result; - result.x = point.x + value; - result.y = point.y + value; - result.z = point.z + value; - return result; -} - -const raw_vector3d_t operator-(const raw_vector3d_t& point, const double value) -{ - raw_vector3d_t result; - result.x = point.x - value; - result.y = point.y - value; - result.z = point.z - value; - return result; -} - -typedef struct _aabb_t { - raw_vector3d_t min; - raw_vector3d_t max; - - _aabb_t() - { - min.x = std::numeric_limits::max(); - min.y = std::numeric_limits::max(); - min.z = std::numeric_limits::max(); - max.x = std::numeric_limits::min(); - max.y = std::numeric_limits::min(); - max.z = std::numeric_limits::min(); - } - - _aabb_t(const raw_vector3d_t& min, const raw_vector3d_t& max) : min(min), max(max) {} - - void extend(const raw_vector3d_t& point) - { - min.x = std::min(min.x, point.x); - min.y = std::min(min.y, point.y); - min.z = std::min(min.z, point.z); - max.x = std::max(max.x, point.x); - max.y = std::max(max.y, point.y); - max.z = std::max(max.z, point.z); - } - - void extend(const _aabb_t& aabb) - { - min.x = std::min(min.x, aabb.min.x); - min.y = std::min(min.y, aabb.min.y); - min.z = std::min(min.z, aabb.min.z); - max.x = std::max(max.x, aabb.max.x); - max.y = std::max(max.y, aabb.max.y); - max.z = std::max(max.z, aabb.max.z); - } - - void offset(const raw_vector3d_t& offset) - { - min = min + offset; - max = max + offset; - } - -} aabb_t; - -struct blobtree_t { - std::vector> nodes{}; - std::vector> leaf_index{}; -}; +#include "globals.hpp" +#include "aabb.hpp" +#include "node_operation.hpp" +/* internal global variables for blobtree */ std::vector> structures{}; std::vector> aabbs{}; std::vector> primitives{}; std::stack>> free_structure_list{}; -/* getter/setter for node_t */ -template -struct node_proxy { - constexpr node_proxy(node_t& _data, uint32_t _offset, node_t _mask) : data(&_data), offset(_offset), mask(_mask) {} - - node_proxy(const node_proxy&) = delete; - node_proxy(node_proxy&&) = delete; - - constexpr node_proxy& operator=(const node_proxy& other) - { - const auto _mask = mask << offset; - *data = (*data & ~_mask) | (other.data & _mask); - return *this; - } - - constexpr node_proxy& operator=(node_proxy&& other) - { - const auto _mask = mask << offset; - *data = (*data & ~_mask) | (std::forward(other.data) & _mask); - return *this; - } - - template - constexpr node_proxy& operator=(_Fp&& other) - { - const auto _mask = mask << offset; - *data = (*data & ~_mask) | (std::forward<_Fp>(other) & _mask); - return *this; - } - - constexpr operator _Tp() const { return static_cast<_Tp>(((*data) >> offset) & mask); } - -protected: - node_t* data; - uint32_t offset{}; - node_t mask{}; -}; - -#define NODE_LOCATION_IN 0 -#define NODE_LOCATION_OUT 1 -#define NODE_LOCATION_EDGE 2 -#define NODE_LOCATION_UNSET 3 - -#define OP_UNION 0 -#define OP_INTERSECTION 1 -#define OP_DIFFERENCE 2 -#define OP_UNSET 3 - -// 0 for internal node, 1 for primitive node -static constexpr inline auto node_fetch_is_primitive(node_t& node) { return node_proxy(node, 127u, 0x01u); } - -// 0 for union, 1 for intersection, 2 for difference, 3 for unset -static constexpr inline auto node_fetch_operation(node_t& node) { return node_proxy(node, 125u, 0x03u); } - -// 0 for in, 1 for out, 2 for on edge, 3 for unset -static constexpr inline auto node_fetch_in_out(node_t& node) { return node_proxy(node, 123u, 0x03u); } - -// If primitive node, the index to the primitive information -static constexpr inline auto node_fetch_primitive_index(node_t& node) { return node_proxy(node, 96u, 0xFFFFFFu); } - -// Parent node index -static constexpr inline auto node_fetch_parent_index(node_t& node) { return node_proxy(node, 64u, 0xFFFFFFFFu); } - -// Left child node index -static constexpr inline auto node_fetch_left_child_index(node_t& node) { return node_proxy(node, 32u, 0xFFFFFFFFu); } - -// Right child node index -static constexpr inline auto node_fetch_right_child_index(node_t& node) { return node_proxy(node, 0u, 0xFFFFFFFFu); } - -/* basic functionalities */ +/* ============================================================================================= + * basic functionalities + * ============================================================================================= */ BPE_API std::vector>& get_primitives() noexcept { return primitives; } void shrink_primitives() { primitives.shrink_to_fit(); } -bool is_primitive_node(node_t& node) { return node_fetch_is_primitive(node) == 1; } - -bool is_parent_null(node_t& node) { return node_fetch_parent_index(node) == 0xFFFFFFFFu; } - -bool is_left_null(node_t& node) { return node_fetch_left_child_index(node) == 0xFFFFFFFFu; } - -bool is_right_null(node_t& node) { return node_fetch_right_child_index(node) == 0xFFFFFFFFu; } - -void set_is_primitive(node_t& node, const bool flag) -{ - node_t temp; - temp.data[0] = flag; - temp.data[0] = temp.data[0] << 63; - node_fetch_is_primitive(node) = temp; -} - -void set_operation(node_t& node, const uint32_t op) -{ - node_t temp; - temp.data[0] = op; - temp.data[0] = temp.data[0] << 61; - node_fetch_operation(node) = temp; -} - -void set_in_out(node_t& node, const uint32_t in_out) -{ - node_t temp; - temp.data[0] = in_out; - temp.data[0] = temp.data[0] << 59; - node_fetch_in_out(node) = temp; -} - -void set_primitive_index(node_t& node, const uint32_t index) -{ - node_t temp; - temp.data[0] = index; - temp.data[0] = temp.data[0] << 32; - node_fetch_primitive_index(node) = temp; -} - -void set_parent_index(node_t& node, const uint32_t index) -{ - node_t temp; - temp.data[0] = index; - node_fetch_parent_index(node) = temp; -} - -void set_left_child_index(node_t& node, const uint32_t index) -{ - node_t temp; - temp.data[1] = index; - temp.data[1] = temp.data[1] << 32; - node_fetch_left_child_index(node) = temp; -} - -void set_right_child_index(node_t& node, const uint32_t index) -{ - node_t temp; - temp.data[1] = index; - node_fetch_right_child_index(node) = temp; -} - virtual_node_t copy(virtual_node_t old_node, virtual_node_t new_node) { assert(old_node.main_index != new_node.main_index); @@ -340,17 +28,13 @@ virtual_node_t copy(virtual_node_t old_node, virtual_node_t new_node) auto temp = structures[old_node.main_index]; // Update all index - int size = structures[new_node.main_index].nodes.size(); - for (int i = 0; i < temp.nodes.size(); i++) { - if (!is_parent_null(temp.nodes[i])) { set_parent_index(temp.nodes[i], node_fetch_parent_index(temp.nodes[i]) + size); } - if (!is_left_null(temp.nodes[i])) { - set_left_child_index(temp.nodes[i], node_fetch_left_child_index(temp.nodes[i]) + size); - } - if (!is_right_null(temp.nodes[i])) { - set_right_child_index(temp.nodes[i], node_fetch_right_child_index(temp.nodes[i]) + size); - } + const auto size = static_cast(structures[new_node.main_index].nodes.size()); + for (uint32_t i = 0; i < temp.nodes.size(); i++) { + if (!node_is_parent_null(temp.nodes[i])) node_fetch_parent_index(temp.nodes[i]) += size; + if (!node_is_left_child_null(temp.nodes[i])) node_fetch_left_child_index(temp.nodes[i]) += size; + if (!node_is_right_child_null(temp.nodes[i])) node_fetch_right_child_index(temp.nodes[i]) += size; } - for (int i = 0; i < temp.leaf_index.size(); i++) { temp.leaf_index[i] += size; } + for (uint32_t i = 0; i < temp.leaf_index.size(); i++) { temp.leaf_index[i] += size; } // Copy the updated index tree to the array at the new location structures[new_node.main_index].nodes.insert(structures[new_node.main_index].nodes.end(), @@ -363,12 +47,11 @@ virtual_node_t copy(virtual_node_t old_node, virtual_node_t new_node) return virtual_node_t{new_node.main_index, old_node.inner_index + size}; } -void offset_primitive(primitive_node_t& node, const raw_vector3d_t& offset) +void offset_primitive(primitive_node_t& node, const Eigen::Vector3d& offset) { - auto offset_point = [](raw_vector3d_t* point, const raw_vector3d_t& offset) { - point->x += offset.x; - point->y += offset.y; - point->z += offset.z; + auto offset_point = [](raw_vector3d_t& point, const Eigen::Vector3d& offset) { + Eigen::Map point_map(&point.x); + point_map += offset; }; auto type = node.type; @@ -378,39 +61,39 @@ void offset_primitive(primitive_node_t& node, const raw_vector3d_t& offset) } case PRIMITIVE_TYPE_PLANE: { auto desc = static_cast(node.desc); - offset_point(&desc->point, offset); + offset_point(desc->point, offset); break; } case PRIMITIVE_TYPE_SPHERE: { auto desc = static_cast(node.desc); - offset_point(&desc->center, offset); + offset_point(desc->center, offset); break; } case PRIMITIVE_TYPE_CYLINDER: { auto desc = static_cast(node.desc); - offset_point(&desc->bottom_origion, offset); + offset_point(desc->bottom_origion, offset); break; } case PRIMITIVE_TYPE_CONE: { auto desc = static_cast(node.desc); - offset_point(&desc->top_point, offset); - offset_point(&desc->bottom_point, offset); + offset_point(desc->top_point, offset); + offset_point(desc->bottom_point, offset); break; } case PRIMITIVE_TYPE_BOX: { auto desc = static_cast(node.desc); - offset_point(&desc->center, offset); + offset_point(desc->center, offset); break; } case PRIMITIVE_TYPE_MESH: { auto desc = static_cast(node.desc); - for (int i = 0; i < desc->point_number; i++) { offset_point(&desc->points[i], offset); } + for (int i = 0; i < desc->point_number; i++) { offset_point(desc->points[i], offset); } break; } case PRIMITIVE_TYPE_EXTRUDE: { auto desc = static_cast(node.desc); - for (int i = 0; i < desc->edges_number; i++) { offset_point(&desc->points[i], offset); } + for (int i = 0; i < desc->edges_number; i++) { offset_point(desc->points[i], offset); } break; } default: { @@ -419,7 +102,7 @@ void offset_primitive(primitive_node_t& node, const raw_vector3d_t& offset) } } -void free_sub_blobtree(uint32_t index) +BPE_API void free_sub_blobtree(uint32_t index) noexcept { // 这里尽量打标记,延迟修改和删除 free_structure_list.push(index); @@ -435,37 +118,38 @@ bool upward_propagation(blobtree_t& tree, const int leaf_node_index, const int r auto& left_child = tree.nodes[node_fetch_left_child_index(node)]; auto& right_child = tree.nodes[node_fetch_right_child_index(node)]; - if (node_fetch_in_out(node) != NODE_LOCATION_UNSET) { return false; } + auto node_in_out_flag = node_fetch_in_out(node); + eNodeLocation left_child_in_out_flag = node_fetch_in_out(left_child); + eNodeLocation right_child_in_out_flag = node_fetch_in_out(right_child); + if (node_in_out_flag != eNodeLocation::unset) { return false; } switch (node_fetch_operation(node)) { - case OP_UNION: { - if (node_fetch_in_out(left_child) == NODE_LOCATION_IN || node_fetch_in_out(right_child) == NODE_LOCATION_IN) { - set_in_out(node, NODE_LOCATION_IN); - } else if (node_fetch_in_out(left_child) == NODE_LOCATION_OUT - && node_fetch_in_out(right_child) == NODE_LOCATION_OUT) { - set_in_out(node, NODE_LOCATION_OUT); + case eNodeOperation::unionOp: { + if (left_child_in_out_flag == eNodeLocation::in || right_child_in_out_flag == eNodeLocation::in) { + node_in_out_flag = eNodeLocation::in; + } else if (left_child_in_out_flag == eNodeLocation::out && right_child_in_out_flag == eNodeLocation::out) { + node_in_out_flag = eNodeLocation::out; } else { return false; } break; } - case OP_INTERSECTION: { - if (node_fetch_in_out(left_child) == NODE_LOCATION_IN && node_fetch_in_out(right_child) == NODE_LOCATION_IN) { - set_in_out(node, NODE_LOCATION_IN); - } else if (node_fetch_in_out(left_child) == NODE_LOCATION_OUT - || node_fetch_in_out(right_child) == NODE_LOCATION_OUT) { - set_in_out(node, NODE_LOCATION_OUT); + case eNodeOperation::intersectionOp: { + if (left_child_in_out_flag == eNodeLocation::in && right_child_in_out_flag == eNodeLocation::in) { + node_in_out_flag = eNodeLocation::in; + } else if (left_child_in_out_flag == eNodeLocation::out || right_child_in_out_flag == eNodeLocation::out) { + node_in_out_flag = eNodeLocation::out; } else { return false; } break; } - case OP_DIFFERENCE: { - if (node_fetch_in_out(left_child) == NODE_LOCATION_IN && node_fetch_in_out(right_child) == NODE_LOCATION_OUT) { - set_in_out(node, NODE_LOCATION_IN); + case eNodeOperation::differenceOp: { + if (left_child_in_out_flag == eNodeLocation::in && right_child_in_out_flag == eNodeLocation::out) { + node_in_out_flag = eNodeLocation::in; } - if (node_fetch_in_out(left_child) == NODE_LOCATION_OUT || node_fetch_in_out(right_child) == NODE_LOCATION_IN) { - set_in_out(node, NODE_LOCATION_OUT); + if (left_child_in_out_flag == eNodeLocation::out || right_child_in_out_flag == eNodeLocation::in) { + node_in_out_flag = eNodeLocation::out; } else { return false; } @@ -483,18 +167,18 @@ bool upward_propagation(blobtree_t& tree, const int leaf_node_index, const int r } } -int evaluate(const virtual_node_t& node, const raw_vector3d_t& point) +eNodeLocation evaluate(const virtual_node_t& node, const raw_vector3d_t& point) { auto temp = structures[node.main_index]; auto& leaf_index = temp.leaf_index; - for (int i = 0; i < leaf_index.size(); i++) { - auto sdf = evaluate(primitives[leaf_index[i]], point); - if (sdf <= 0.0) { - set_in_out(temp.nodes[leaf_index[i]], NODE_LOCATION_IN); - } else { - set_in_out(temp.nodes[leaf_index[i]], NODE_LOCATION_OUT); - } + for (size_t i = 0; i < leaf_index.size(); i++) { + auto sdf = evaluate(primitives[leaf_index[i]], point); + auto leaf_node_in_out = node_fetch_in_out(temp.nodes[leaf_index[i]]); + if (sdf <= 0.0) + leaf_node_in_out = eNodeLocation::in; + else + leaf_node_in_out = eNodeLocation::out; if (upward_propagation(temp, leaf_index[i], node.inner_index)) { break; } } @@ -513,325 +197,145 @@ aabb_t get_aabb(const virtual_node_t& node) return result; } -uint32_t get_closest_common_parent(const std::vector& mask, const int main_index) -{ - // Copy tree structure - auto tree = structures[main_index]; - - // Count how many geometries are queried - int count = 0; - for (int i = 0; i < mask.size(); i++) { - if (mask[i] == 1) { count++; } - } - - uint32_t result = 0xFFFFFFFFu; - for (uint32_t i = 0; i < mask.size(); i++) { - if (mask[i] == 0) { continue; } - - for (auto& iter : tree.leaf_index) { - // Find the location of the current query geometry in the tree - if (node_fetch_primitive_index(tree.nodes[iter]) != i) { continue; } - - // Traverse from bottom to top and increase the count of all nodes by 1 - uint32_t now = iter; - while (true) { - now = node_fetch_parent_index(tree.nodes[now]); - - // now is root - if (now == 0xFFFFFFFFu) { break; } - - // Use the primitive index of the internal node to count - if (node_fetch_primitive_index(tree.nodes[now]) == 0xFFFFFFu) { - set_primitive_index(tree.nodes[now], 1); - } else { - set_primitive_index(tree.nodes[now], node_fetch_primitive_index(tree.nodes[now]) + 1); - } +// uint32_t get_closest_common_parent(const std::vector& mask, const int main_index) +// { +// // Copy tree structure +// auto tree = structures[main_index]; - if (node_fetch_primitive_index(tree.nodes[now]) == count) { - result = now; - break; - } - } +// // Count how many geometries are queried +// int count = 0; +// for (int i = 0; i < mask.size(); i++) { +// if (mask[i] == 1) { count++; } +// } - break; - } - } +// uint32_t result = 0xFFFFFFFFu; +// for (uint32_t i = 0; i < mask.size(); i++) { +// if (mask[i] == 0) { continue; } - return result; -} +// for (auto& iter : tree.leaf_index) { +// // Find the location of the current query geometry in the tree +// if (node_fetch_primitive_index(tree.nodes[iter]) != i) { continue; } -/* Geometry Generation */ +// // Traverse from bottom to top and increase the count of all nodes by 1 +// uint32_t now = iter; +// while (true) { +// now = node_fetch_parent_index(tree.nodes[now]); -static constexpr node_t standard_new_node = {(uint64_t)0xFFFFFFFFFFFFFFFFu, (uint64_t)0xFFFFFFFFFFFFFFFFu}; +// // now is root +// if (now == 0xFFFFFFFFu) { break; } -virtual_node_t push_primitive_node(primitive_node_t&& primitive_node, const aabb_t&& aabb) -{ - aabbs.emplace_back(aabb); - primitives.emplace_back(primitive_node); +// // Use the primitive index of the internal node to count +// if (node_fetch_primitive_index(tree.nodes[now]) == 0xFFFFFFu) { +// set_primitive_index(tree.nodes[now], 1); +// } else { +// set_primitive_index(tree.nodes[now], node_fetch_primitive_index(tree.nodes[now]) + 1); +// } - node_t node = standard_new_node; - set_primitive_index(node, static_cast(primitives.size() - 1)); +// if (node_fetch_primitive_index(tree.nodes[now]) == count) { +// result = now; +// break; +// } +// } - blobtree_t tree; - tree.nodes.emplace_back(node); - tree.leaf_index.push_back(0); +// break; +// } +// } - structures.push_back(tree); - - return virtual_node_t{static_cast(structures.size() - 1), 0}; -} - -BPE_API virtual_node_t blobtree_new_virtual_node(const constant_descriptor_t& desc) -{ - primitive_node_t node{PRIMITIVE_TYPE_CONSTANT, malloc(sizeof(constant_descriptor_t))}; - *((constant_descriptor_t*)node.desc) = std::move(desc); - aabb_t aabb{}; - return push_primitive_node(std::move(node), std::move(aabb)); -} - -BPE_API virtual_node_t blobtree_new_virtual_node(const plane_descriptor_t& desc) -{ - primitive_node_t node{PRIMITIVE_TYPE_PLANE, malloc(sizeof(plane_descriptor_t))}; - *((plane_descriptor_t*)node.desc) = std::move(desc); - - aabb_t aabb{}; - return push_primitive_node(std::move(node), std::move(aabb)); -} - -BPE_API virtual_node_t blobtree_new_virtual_node(const sphere_descriptor_t& desc) -{ - primitive_node_t node{PRIMITIVE_TYPE_SPHERE, malloc(sizeof(sphere_descriptor_t))}; - *((sphere_descriptor_t*)node.desc) = std::move(desc); - - raw_vector3d_t min = desc.center - desc.radius; - raw_vector3d_t max = desc.center + desc.radius; - aabb_t aabb{min, max}; - return push_primitive_node(std::move(node), std::move(aabb)); -} - -BPE_API virtual_node_t blobtree_new_virtual_node(const cylinder_descriptor_t& desc) -{ - primitive_node_t node{PRIMITIVE_TYPE_CYLINDER, malloc(sizeof(cylinder_descriptor_t))}; - *((cylinder_descriptor_t*)node.desc) = std::move(desc); - - // NOTE: A rough AABB bounding box - aabb_t aabb{}; - aabb.extend(desc.bottom_origion + desc.radius); - aabb.extend(desc.bottom_origion - desc.radius); - aabb.extend(desc.bottom_origion + desc.offset + desc.radius); - aabb.extend(desc.bottom_origion + desc.offset - desc.radius); - return push_primitive_node(std::move(node), std::move(aabb)); -} - -BPE_API virtual_node_t blobtree_new_virtual_node(const cone_descriptor_t& desc) -{ - primitive_node_t node{PRIMITIVE_TYPE_CONE, malloc(sizeof(cone_descriptor_t))}; - *((cone_descriptor_t*)node.desc) = std::move(desc); - - // NOTE: A rough AABB bounding box - aabb_t aabb{}; - aabb.extend(desc.top_point + desc.radius1); - aabb.extend(desc.top_point - desc.radius1); - aabb.extend(desc.bottom_point + desc.radius2); - aabb.extend(desc.bottom_point - desc.radius2); - return push_primitive_node(std::move(node), std::move(aabb)); -} - -BPE_API virtual_node_t blobtree_new_virtual_node(const box_descriptor_t& desc) -{ - primitive_node_t node{PRIMITIVE_TYPE_BOX, malloc(sizeof(box_descriptor_t))}; - *((box_descriptor_t*)node.desc) = std::move(desc); - - raw_vector3d_t min = desc.center - desc.half_size; - raw_vector3d_t max = desc.center + desc.half_size; - aabb_t aabb{min, max}; - return push_primitive_node(std::move(node), std::move(aabb)); -} - -BPE_API virtual_node_t blobtree_new_virtual_node(const mesh_descriptor_t& desc) -{ - primitive_node_t node{PRIMITIVE_TYPE_MESH, malloc(sizeof(mesh_descriptor_t))}; - *((mesh_descriptor_t*)node.desc) = std::move(desc); - - aabb_t aabb{}; - for (int i = 0; i < desc.point_number; i++) { aabb.extend(desc.points[i]); } - - return push_primitive_node(std::move(node), std::move(aabb)); -} - -BPE_API virtual_node_t blobtree_new_virtual_node(const extrude_descriptor_t& desc) -{ - primitive_node_t node{PRIMITIVE_TYPE_EXTRUDE, malloc(sizeof(extrude_descriptor_t))}; - *((extrude_descriptor_t*)node.desc) = std::move(desc); - - aabb_t aabb{}; - // NOTE: Currently only straight edges are considered - for (int i = 0; i < desc.edges_number; i++) { - aabb.extend(desc.points[i]); - aabb.extend(desc.points[i] + desc.extusion); - } - - return push_primitive_node(std::move(node), std::move(aabb)); -} - -BPE_API void blobtree_free_virtual_node(virtual_node_t* node) { free_sub_blobtree(node->main_index); } - -/* Geometry Operations */ - -BPE_API void virtual_node_boolean_union(virtual_node_t* node1, virtual_node_t* node2) -{ - auto new_node2 = copy(*node2, *node1); +// return result; +// } - node_t temp = standard_new_node; - set_is_primitive(temp, false); - set_operation(temp, 0); - set_left_child_index(temp, node1->inner_index); - set_right_child_index(temp, new_node2.inner_index); +/* ============================================================================================= + * tree node operations + * ============================================================================================= */ - structures[node1->main_index].nodes.push_back(temp); - uint32_t parent_index = structures[node1->main_index].nodes.size() - 1; - - set_parent_index(structures[node1->main_index].nodes[node1->inner_index], parent_index); - set_parent_index(structures[new_node2.main_index].nodes[new_node2.inner_index], parent_index); - - node1->inner_index = parent_index; -} - -BPE_API void virtual_node_boolean_intersect(virtual_node_t* node1, virtual_node_t* node2) -{ - auto new_node2 = copy(*node2, *node1); - - node_t temp = standard_new_node; - set_is_primitive(temp, false); - set_operation(temp, 1); - set_left_child_index(temp, node1->inner_index); - set_right_child_index(temp, new_node2.inner_index); - - structures[node1->main_index].nodes.push_back(temp); - uint32_t parent_index = structures[node1->main_index].nodes.size() - 1; - - set_parent_index(structures[node1->main_index].nodes[node1->inner_index], parent_index); - set_parent_index(structures[new_node2.main_index].nodes[new_node2.inner_index], parent_index); - - node1->inner_index = parent_index; -} - -BPE_API void virtual_node_boolean_difference(virtual_node_t* node1, virtual_node_t* node2) -{ - auto new_node2 = copy(*node2, *node1); - - node_t temp = standard_new_node; - set_is_primitive(temp, false); - set_operation(temp, 2); - set_left_child_index(temp, node1->inner_index); - set_right_child_index(temp, new_node2.inner_index); - - structures[node1->main_index].nodes.push_back(temp); - uint32_t parent_index = structures[node1->main_index].nodes.size() - 1; - - set_parent_index(structures[node1->main_index].nodes[node1->inner_index], parent_index); - set_parent_index(structures[new_node2.main_index].nodes[new_node2.inner_index], parent_index); - - node1->inner_index = parent_index; -} - -BPE_API void virtual_node_offset(virtual_node_t* node, const raw_vector3d_t& direction, const double length) -{ - raw_vector3d_t offset = {direction.x * length, direction.y * length, direction.z * length}; - virtual_node_offset(node, offset); -} - -BPE_API void virtual_node_offset(virtual_node_t* node, const raw_vector3d_t& offset) +BPE_API bool virtual_node_set_parent(virtual_node_t* node, virtual_node_t* parent) { - auto& all_leaf = structures[node->main_index].leaf_index; - for (int i = 0; i < all_leaf.size(); i++) { - offset_primitive(primitives[node_fetch_primitive_index(structures[node->main_index].nodes[all_leaf[i]])], offset); + auto& node_in_tree = structures[node->main_index].nodes[node->inner_index]; + // The node's parent is not empty + if (!node_is_parent_null(node_in_tree)) { return false; } - aabbs[node_fetch_primitive_index(structures[node->main_index].nodes[all_leaf[i]])].offset(offset); + auto& parent_in_tree = structures[parent->main_index].nodes[parent->inner_index]; + auto parent_inner_index = parent->inner_index; + // not on the same tree + if (node->main_index != parent->main_index) { + auto new_parent = copy(*parent, *node); + parent_in_tree = structures[new_parent.main_index].nodes[new_parent.inner_index]; + parent_inner_index = new_parent.inner_index; } -} + auto parent_left_child = node_fetch_left_child_index(parent_in_tree); + auto parent_right_child = node_fetch_right_child_index(parent_in_tree); -BPE_API void virtual_node_split(virtual_node_t* node, raw_vector3d_t base_point, raw_vector3d_t normal) -{ - plane_descriptor_t descriptor; - descriptor.normal = raw_vector3d_t{normal.x * -1, normal.y * -1, normal.z * -1}; - descriptor.point = base_point; - auto plane = blobtree_new_virtual_node(descriptor); - - virtual_node_boolean_intersect(node, &plane); -} - -/* Tree Node Operations */ - -BPE_API bool virtual_node_set_parent(virtual_node_t* node, virtual_node_t* parent) -{ - // The node's parent is not empty - if (!is_parent_null(structures[node->main_index].nodes[node->inner_index])) { return false; } + // set parent index + node_fetch_parent_index(node_in_tree) = parent_inner_index; // The parent's left child is empty - if (is_left_null(structures[parent->main_index].nodes[parent->inner_index])) { - // On the same tree - if (node->main_index == parent->main_index) { - set_parent_index(structures[node->main_index].nodes[node->inner_index], parent->inner_index); - set_left_child_index(structures[parent->main_index].nodes[parent->inner_index], node->inner_index); - } else { - auto new_parent = copy(*parent, *node); - set_parent_index(structures[node->main_index].nodes[node->inner_index], new_parent.inner_index); - set_left_child_index(structures[new_parent.main_index].nodes[new_parent.inner_index], node->inner_index); - } + if (node_is_left_child_null(node_in_tree)) { + parent_left_child = node->inner_index; + return true; } // The parent's right child is empty - else if (is_right_null(structures[parent->main_index].nodes[parent->inner_index])) { - // On the same tree - if (node->main_index == parent->main_index) { - set_parent_index(structures[node->main_index].nodes[node->inner_index], parent->inner_index); - set_right_child_index(structures[parent->main_index].nodes[parent->inner_index], node->inner_index); - } else { - auto new_parent = copy(*parent, *node); - set_parent_index(structures[node->main_index].nodes[node->inner_index], new_parent.inner_index); - set_right_child_index(structures[new_parent.main_index].nodes[new_parent.inner_index], node->inner_index); - } - } else { - return false; + else if (node_is_right_child_null(node_in_tree)) { + parent_right_child = node->inner_index; + return true; } + + return false; } BPE_API bool virtual_node_set_left_child(virtual_node_t* node, virtual_node_t* child) { + auto& node_in_tree = structures[node->main_index].nodes[node->inner_index]; + // The child's parent is not empty - if (!is_parent_null(structures[child->main_index].nodes[child->inner_index])) { return false; } + if (!node_is_parent_null(node_in_tree)) { return false; } // The node's left child is not empty - if (!is_left_null(structures[node->main_index].nodes[node->inner_index])) { return false; } + if (!node_is_left_child_null(node_in_tree)) { return false; } + + auto node_left_child = node_fetch_left_child_index(node_in_tree); + auto node_right_child = node_fetch_right_child_index(node_in_tree); // On the same tree if (node->main_index == child->main_index) { - set_parent_index(structures[child->main_index].nodes[child->inner_index], node->inner_index); - set_left_child_index(structures[node->main_index].nodes[node->inner_index], child->inner_index); + auto& child_in_tree = structures[child->main_index].nodes[child->inner_index]; + node_fetch_parent_index(child_in_tree) = node->inner_index; + node_left_child = child->inner_index; } else { - auto new_child = copy(*child, *node); - set_parent_index(structures[new_child.main_index].nodes[new_child.inner_index], node->inner_index); - set_left_child_index(structures[node->main_index].nodes[node->inner_index], new_child.inner_index); + auto new_child = copy(*child, *node); + auto& child_in_tree = structures[new_child.main_index].nodes[new_child.inner_index]; + node_fetch_parent_index(child_in_tree) = node->inner_index; + node_left_child = new_child.inner_index; } + + return true; } BPE_API bool virtual_node_set_right_child(virtual_node_t* node, virtual_node_t* child) { + auto& node_in_tree = structures[node->main_index].nodes[node->inner_index]; + // The child's parent is not empty - if (!is_parent_null(structures[child->main_index].nodes[child->inner_index])) { return false; } + if (!node_is_parent_null(node_in_tree)) { return false; } // The node's right child is not empty - if (!is_right_null(structures[node->main_index].nodes[node->inner_index])) { return false; } + if (!node_is_right_child_null(node_in_tree)) { return false; } + + auto node_left_child = node_fetch_left_child_index(node_in_tree); + auto node_right_child = node_fetch_right_child_index(node_in_tree); // On the same tree if (node->main_index == child->main_index) { - set_parent_index(structures[child->main_index].nodes[child->inner_index], node->inner_index); - set_right_child_index(structures[node->main_index].nodes[node->inner_index], child->inner_index); + auto& child_in_tree = structures[child->main_index].nodes[child->inner_index]; + node_fetch_parent_index(child_in_tree) = node->inner_index; + node_right_child = child->inner_index; } else { - auto new_child = copy(*child, *node); - set_parent_index(structures[new_child.main_index].nodes[new_child.inner_index], node->inner_index); - set_right_child_index(structures[node->main_index].nodes[node->inner_index], new_child.inner_index); + auto new_child = copy(*child, *node); + auto& child_in_tree = structures[new_child.main_index].nodes[new_child.inner_index]; + node_fetch_parent_index(child_in_tree) = node->inner_index; + node_right_child = new_child.inner_index; } + + return true; } BPE_API bool virtual_node_add_child(virtual_node_t* node, virtual_node_t* child) @@ -840,303 +344,97 @@ BPE_API bool virtual_node_add_child(virtual_node_t* node, virtual_node_t* child) return true; } else if (virtual_node_set_right_child(node, child)) { return true; - } else { - return false; } + + return false; } BPE_API bool virtual_node_remove_child(virtual_node_t* node, virtual_node_t* child) { if (node->main_index != child->main_index) { return false; } - if (node_fetch_left_child_index(structures[node->main_index].nodes[node->inner_index]) == child->inner_index) { - set_left_child_index(structures[node->main_index].nodes[node->inner_index], 0xFFFFFFFFu); + auto& node_in_tree = structures[node->main_index].nodes[node->inner_index]; + auto node_left_child = node_fetch_left_child_index(node_in_tree); + auto node_right_child = node_fetch_right_child_index(node_in_tree); + + if (node_left_child == child->inner_index) { + node_left_child = 0xFFFFFFFFu; blobtree_free_virtual_node(child); return true; - } else if (node_fetch_right_child_index(structures[node->main_index].nodes[node->inner_index]) == child->inner_index) { - set_right_child_index(structures[node->main_index].nodes[node->inner_index], 0xFFFFFFFFu); + } else if (node_right_child == child->inner_index) { + node_right_child = 0xFFFFFFFFu; blobtree_free_virtual_node(child); return true; - } else { - return false; } -} - -/* Node Replacement Operation */ -BPE_API bool virtual_node_replace_primitive(virtual_node_t* node, const constant_descriptor_t& desc) -{ - if (!is_primitive_node(structures[node->main_index].nodes[node->inner_index])) { return false; } - *((constant_descriptor_t*)primitives[node_fetch_primitive_index(structures[node->main_index].nodes[node->inner_index])] - .desc) = std::move(desc); - primitives[node_fetch_primitive_index(structures[node->main_index].nodes[node->inner_index])].type = - PRIMITIVE_TYPE_CONSTANT; - aabbs[node_fetch_primitive_index(structures[node->main_index].nodes[node->inner_index])] = aabb_t{}; - return true; + return false; } -BPE_API bool virtual_node_replace_primitive(virtual_node_t* node, const plane_descriptor_t& desc) -{ - if (!is_primitive_node(structures[node->main_index].nodes[node->inner_index])) { return false; } - *((plane_descriptor_t*)primitives[node_fetch_primitive_index(structures[node->main_index].nodes[node->inner_index])].desc) = - std::move(desc); - primitives[node_fetch_primitive_index(structures[node->main_index].nodes[node->inner_index])].type = PRIMITIVE_TYPE_PLANE; - aabbs[node_fetch_primitive_index(structures[node->main_index].nodes[node->inner_index])] = aabb_t{}; - return true; -} +/* ============================================================================================= + * geometry operations + * ============================================================================================= */ -BPE_API bool virtual_node_replace_primitive(virtual_node_t* node, const sphere_descriptor_t& desc) -{ - if (!is_primitive_node(structures[node->main_index].nodes[node->inner_index])) { return false; } - *((sphere_descriptor_t*)primitives[node_fetch_primitive_index(structures[node->main_index].nodes[node->inner_index])] - .desc) = std::move(desc); - primitives[node_fetch_primitive_index(structures[node->main_index].nodes[node->inner_index])].type = PRIMITIVE_TYPE_SPHERE; +static constexpr node_t standard_new_node = {(uint64_t)0xFFFFFFFFFFFFFFFFu, (uint64_t)0xFFFFFFFFFFFFFFFFu}; - raw_vector3d_t min = desc.center - desc.radius; - raw_vector3d_t max = desc.center + desc.radius; - aabb_t aabb{min, max}; - aabbs[node_fetch_primitive_index(structures[node->main_index].nodes[node->inner_index])] = aabb; +static inline void virtual_node_boolean_op(virtual_node_t* node1, virtual_node_t* node2, eNodeOperation op) +{ + auto new_node2 = copy(*node2, *node1); - return true; -} + auto& inserted_node = structures[node1->main_index].nodes.emplace_back(standard_new_node); + node_fetch_is_primitive(inserted_node) = false; + // weird bug: need to force cast, or it will be treated as uint32_t instead of eNodeOperation + node_fetch_operation(inserted_node) = (eNodeOperation)op; + node_fetch_left_child_index(inserted_node) = node1->inner_index; + node_fetch_right_child_index(inserted_node) = new_node2.inner_index; -BPE_API bool virtual_node_replace_primitive(virtual_node_t* node, const cylinder_descriptor_t& desc) -{ - if (!is_primitive_node(structures[node->main_index].nodes[node->inner_index])) { return false; } - *((cylinder_descriptor_t*)primitives[node_fetch_primitive_index(structures[node->main_index].nodes[node->inner_index])] - .desc) = std::move(desc); - primitives[node_fetch_primitive_index(structures[node->main_index].nodes[node->inner_index])].type = - PRIMITIVE_TYPE_CYLINDER; - - // NOTE: A rough AABB bounding box - aabb_t aabb{}; - aabb.extend(desc.bottom_origion + desc.radius); - aabb.extend(desc.bottom_origion - desc.radius); - aabb.extend(desc.bottom_origion + desc.offset + desc.radius); - aabb.extend(desc.bottom_origion + desc.offset - desc.radius); - aabbs[node_fetch_primitive_index(structures[node->main_index].nodes[node->inner_index])] = aabb; + uint32_t parent_index = structures[node1->main_index].nodes.size() - 1; + node_fetch_parent_index(structures[node1->main_index].nodes[node1->inner_index]) = parent_index; + node_fetch_parent_index(structures[new_node2.main_index].nodes[new_node2.inner_index]) = parent_index; - return true; + node1->inner_index = parent_index; } -BPE_API bool virtual_node_replace_primitive(virtual_node_t* node, const cone_descriptor_t& desc) +BPE_API void virtual_node_boolean_union(virtual_node_t* node1, virtual_node_t* node2) { - if (!is_primitive_node(structures[node->main_index].nodes[node->inner_index])) { return false; } - *((cone_descriptor_t*)primitives[node_fetch_primitive_index(structures[node->main_index].nodes[node->inner_index])].desc) = - std::move(desc); - primitives[node_fetch_primitive_index(structures[node->main_index].nodes[node->inner_index])].type = PRIMITIVE_TYPE_CONE; - - // NOTE: A rough AABB bounding box - aabb_t aabb{}; - aabb.extend(desc.top_point + desc.radius1); - aabb.extend(desc.top_point - desc.radius1); - aabb.extend(desc.bottom_point + desc.radius2); - aabb.extend(desc.bottom_point - desc.radius2); - aabbs[node_fetch_primitive_index(structures[node->main_index].nodes[node->inner_index])] = aabb; - return true; + virtual_node_boolean_op(node1, node2, eNodeOperation::unionOp); } -BPE_API bool virtual_node_replace_primitive(virtual_node_t* node, const box_descriptor_t& desc) +BPE_API void virtual_node_boolean_intersect(virtual_node_t* node1, virtual_node_t* node2) { - if (!is_primitive_node(structures[node->main_index].nodes[node->inner_index])) { return false; } - *((box_descriptor_t*)primitives[node_fetch_primitive_index(structures[node->main_index].nodes[node->inner_index])].desc) = - std::move(desc); - primitives[node_fetch_primitive_index(structures[node->main_index].nodes[node->inner_index])].type = PRIMITIVE_TYPE_BOX; - - raw_vector3d_t min = desc.center - desc.half_size; - raw_vector3d_t max = desc.center + desc.half_size; - aabb_t aabb{min, max}; - aabbs[node_fetch_primitive_index(structures[node->main_index].nodes[node->inner_index])] = aabb; - return true; + virtual_node_boolean_op(node1, node2, eNodeOperation::intersectionOp); } -BPE_API bool virtual_node_replace_primitive(virtual_node_t* node, const mesh_descriptor_t& desc) +BPE_API void virtual_node_boolean_difference(virtual_node_t* node1, virtual_node_t* node2) { - if (!is_primitive_node(structures[node->main_index].nodes[node->inner_index])) { return false; } - *((mesh_descriptor_t*)primitives[node_fetch_primitive_index(structures[node->main_index].nodes[node->inner_index])].desc) = - std::move(desc); - primitives[node_fetch_primitive_index(structures[node->main_index].nodes[node->inner_index])].type = PRIMITIVE_TYPE_MESH; - - aabb_t aabb{}; - for (int i = 0; i < desc.point_number; i++) { aabb.extend(desc.points[i]); } - - aabbs[node_fetch_primitive_index(structures[node->main_index].nodes[node->inner_index])] = aabb; - return true; + virtual_node_boolean_op(node1, node2, eNodeOperation::differenceOp); } -BPE_API bool virtual_node_replace_primitive(virtual_node_t* node, const extrude_descriptor_t& desc) +BPE_API void virtual_node_offset(virtual_node_t* node, const raw_vector3d_t& direction, const double length) { - if (!is_primitive_node(structures[node->main_index].nodes[node->inner_index])) { return false; } - *((extrude_descriptor_t*)primitives[node_fetch_primitive_index(structures[node->main_index].nodes[node->inner_index])] - .desc) = std::move(desc); - primitives[node_fetch_primitive_index(structures[node->main_index].nodes[node->inner_index])].type = PRIMITIVE_TYPE_EXTRUDE; - - aabb_t aabb{}; - // NOTE: Currently only straight edges are considered - for (int i = 0; i < desc.edges_number; i++) { - aabb.extend(desc.points[i]); - aabb.extend(desc.points[i] + desc.extusion); - } - aabbs[node_fetch_primitive_index(structures[node->main_index].nodes[node->inner_index])] = aabb; - return true; + raw_vector3d_t offset = {direction.x * length, direction.y * length, direction.z * length}; + virtual_node_offset(node, offset); } -#ifdef _DEBUG - -void output_primitive_node(const primitive_node_t& node) +BPE_API void virtual_node_offset(virtual_node_t* node, const raw_vector3d_t& offset) { - auto output_point = [](const raw_vector3d_t& point) { - std::cout << "( " << point.x << ", " << point.y << ", " << point.z << " )" << std::endl; - }; + Eigen::Map offset_(&offset.x); - auto type = node.type; - switch (type) { - case PRIMITIVE_TYPE_CONSTANT: { - auto desc = static_cast(node.desc); - std::cout << "constant:" << std::endl; - std::cout << "\tvalue: " << desc->value << std::endl << std::endl; - break; - } - case PRIMITIVE_TYPE_PLANE: { - auto desc = static_cast(node.desc); - std::cout << "plane:" << std::endl; - std::cout << "\tbase point: "; - output_point(desc->point); - std::cout << "\tnormal: "; - output_point(desc->normal); - std::cout << std::endl; - break; - } - case PRIMITIVE_TYPE_SPHERE: { - auto desc = static_cast(node.desc); - std::cout << "sphere:" << std::endl; - std::cout << "\tcenter: "; - output_point(desc->center); - std::cout << "\tradius: " << desc->radius << std::endl << std::endl; - break; - } - case PRIMITIVE_TYPE_CYLINDER: { - auto desc = static_cast(node.desc); - std::cout << "cylinder:" << std::endl; - std::cout << "\tbottom point: "; - output_point(desc->bottom_origion); - std::cout << "\tradius: " << desc->radius << std::endl << std::endl; - std::cout << "\toffset: "; - output_point(desc->offset); - break; - } - case PRIMITIVE_TYPE_CONE: { - auto desc = static_cast(node.desc); - std::cout << "cone:" << std::endl; - std::cout << "\tbottom point: "; - output_point(desc->bottom_point); - std::cout << "\ttop point: "; - output_point(desc->top_point); - std::cout << "\tradius1: " << desc->radius1 << std::endl; - std::cout << "\tradius2: " << desc->radius2 << std::endl << std::endl; - break; - } - case PRIMITIVE_TYPE_BOX: { - auto desc = static_cast(node.desc); - std::cout << "box:" << std::endl; - std::cout << "\tcenter: "; - output_point(desc->center); - std::cout << "\thalf_size "; - output_point(desc->half_size); - break; - } - case PRIMITIVE_TYPE_MESH: { - auto desc = static_cast(node.desc); - std::cout << "mesh:" << std::endl; - std::cout << "\tpoint number: " << desc->point_number << std::endl; - for (int i = 0; i < desc->point_number; i++) { - std::cout << "\t\t( " << desc->points[i].x << ", " << desc->points[i].y << ", " << desc->points[i].z << " )" - << std::endl; - } - - std::cout << "\tfaces number: " << desc->face_number << std::endl; - for (int i = 0; i < desc->face_number; i++) { - auto begin = desc->faces[i][0]; - auto length = desc->faces[i][1]; - std::cout << "\t\t<" << begin << ", " << length << "> : "; - for (int j = begin; j < begin + length; j++) { std::cout << desc->indexs[j] << " "; } - std::cout << std::endl; - } - break; - } - case PRIMITIVE_TYPE_EXTRUDE: { - auto desc = static_cast(node.desc); - std::cout << "extrude:" << std::endl; - std::cout << "\tedges number: " << desc->edges_number << std::endl; - std::cout << "\textusion: "; - output_point(desc->extusion); - - std::cout << "\tpoints: " << std::endl; - for (int i = 0; i < desc->edges_number; i++) { - std::cout << "\t\t( " << desc->points[i].x << ", " << desc->points[i].y << ", " << desc->points[i].z << " )" - << std::endl; - } + auto& all_leaf = structures[node->main_index].leaf_index; + for (const auto& leaf_index : structures[node->main_index].leaf_index) { + auto& primitive_node = structures[node->main_index].nodes[leaf_index]; + const uint32_t primitive_index = node_fetch_primitive_index(primitive_node); - std::cout << "\tbulges: " << std::endl; - for (int i = 0; i < desc->edges_number; i++) { std::cout << "\t\t" << desc->bulges[i] << std::endl; } - break; - } - default: { - break; - } + offset_primitive(primitives[primitive_index], offset_); + aabbs[primitive_index].offset(offset_); } } -void output_blobtree(virtual_node_t node) +BPE_API void virtual_node_split(virtual_node_t* node, raw_vector3d_t base_point, raw_vector3d_t normal) { - std::map index; - index[0] = "constant"; - index[1] = "plane"; - index[2] = "sphere"; - index[3] = "cylinder"; - index[4] = "cone"; - index[5] = "box"; - index[6] = "mesh"; - index[7] = "extrude"; - - auto root = structures[node.main_index].nodes[node.inner_index]; - std::queue now, next; - now.push(root); - - std::vector temp; - - while (!now.empty()) { - auto begin = now.front(); - now.pop(); - - if (is_primitive_node(begin)) { - std::cout << index[primitives[node_fetch_primitive_index(begin)].type] << "\t\t"; - temp.push_back(primitives[node_fetch_primitive_index(begin)]); - } else { - auto op = (uint32_t)node_fetch_operation(begin); - if (op == 0) { - std::cout << "or" - << "\t\t"; - } else if (op == 1) { - std::cout << "and" - << "\t\t"; - } else if (op == 2) { - std::cout << "sub" - << "\t\t"; - } - } - - if (!is_left_null(begin)) { next.push(structures[node.main_index].nodes[node_fetch_left_child_index(begin)]); } - if (!is_right_null(begin)) { next.push(structures[node.main_index].nodes[node_fetch_right_child_index(begin)]); } - - if (now.empty()) { - now = next; - while (!next.empty()) { next.pop(); } - std::cout << std::endl; - } - } - std::cout << std::endl; + plane_descriptor_t descriptor; + descriptor.normal = raw_vector3d_t{normal.x * -1, normal.y * -1, normal.z * -1}; + descriptor.point = base_point; + auto plane = blobtree_new_virtual_node(descriptor); - for (int i = 0; i < temp.size(); i++) { output_primitive_node(temp[i]); } -} -#endif // _DEBUG + virtual_node_boolean_intersect(node, &plane); +} \ No newline at end of file diff --git a/blobtree_structure/src/debug.cpp b/blobtree_structure/src/debug.cpp new file mode 100644 index 0000000..2a0f1ee --- /dev/null +++ b/blobtree_structure/src/debug.cpp @@ -0,0 +1,169 @@ +#include + +#include "primitive_descriptor.h" + +#include "globals.hpp" + +#ifdef _DEBUG + +void output_primitive_node(const primitive_node_t& node) +{ + auto output_point = [](const raw_vector3d_t& point) { + std::cout << "( " << point.x << ", " << point.y << ", " << point.z << " )" << std::endl; + }; + + auto type = node.type; + switch (type) { + case PRIMITIVE_TYPE_CONSTANT: { + auto desc = static_cast(node.desc); + std::cout << "constant:" << std::endl; + std::cout << "\tvalue: " << desc->value << std::endl << std::endl; + break; + } + case PRIMITIVE_TYPE_PLANE: { + auto desc = static_cast(node.desc); + std::cout << "plane:" << std::endl; + std::cout << "\tbase point: "; + output_point(desc->point); + std::cout << "\tnormal: "; + output_point(desc->normal); + std::cout << std::endl; + break; + } + case PRIMITIVE_TYPE_SPHERE: { + auto desc = static_cast(node.desc); + std::cout << "sphere:" << std::endl; + std::cout << "\tcenter: "; + output_point(desc->center); + std::cout << "\tradius: " << desc->radius << std::endl << std::endl; + break; + } + case PRIMITIVE_TYPE_CYLINDER: { + auto desc = static_cast(node.desc); + std::cout << "cylinder:" << std::endl; + std::cout << "\tbottom point: "; + output_point(desc->bottom_origion); + std::cout << "\tradius: " << desc->radius << std::endl << std::endl; + std::cout << "\toffset: "; + output_point(desc->offset); + break; + } + case PRIMITIVE_TYPE_CONE: { + auto desc = static_cast(node.desc); + std::cout << "cone:" << std::endl; + std::cout << "\tbottom point: "; + output_point(desc->bottom_point); + std::cout << "\ttop point: "; + output_point(desc->top_point); + std::cout << "\tradius1: " << desc->radius1 << std::endl; + std::cout << "\tradius2: " << desc->radius2 << std::endl << std::endl; + break; + } + case PRIMITIVE_TYPE_BOX: { + auto desc = static_cast(node.desc); + std::cout << "box:" << std::endl; + std::cout << "\tcenter: "; + output_point(desc->center); + std::cout << "\thalf_size "; + output_point(desc->half_size); + break; + } + case PRIMITIVE_TYPE_MESH: { + auto desc = static_cast(node.desc); + std::cout << "mesh:" << std::endl; + std::cout << "\tpoint number: " << desc->point_number << std::endl; + for (int i = 0; i < desc->point_number; i++) { + std::cout << "\t\t( " << desc->points[i].x << ", " << desc->points[i].y << ", " << desc->points[i].z << " )" + << std::endl; + } + + std::cout << "\tfaces number: " << desc->face_number << std::endl; + for (int i = 0; i < desc->face_number; i++) { + auto begin = desc->faces[i][0]; + auto length = desc->faces[i][1]; + std::cout << "\t\t<" << begin << ", " << length << "> : "; + for (int j = begin; j < begin + length; j++) { std::cout << desc->indexs[j] << " "; } + std::cout << std::endl; + } + break; + } + case PRIMITIVE_TYPE_EXTRUDE: { + auto desc = static_cast(node.desc); + std::cout << "extrude:" << std::endl; + std::cout << "\tedges number: " << desc->edges_number << std::endl; + std::cout << "\textusion: "; + output_point(desc->extusion); + + std::cout << "\tpoints: " << std::endl; + for (int i = 0; i < desc->edges_number; i++) { + std::cout << "\t\t( " << desc->points[i].x << ", " << desc->points[i].y << ", " << desc->points[i].z << " )" + << std::endl; + } + + std::cout << "\tbulges: " << std::endl; + for (int i = 0; i < desc->edges_number; i++) { std::cout << "\t\t" << desc->bulges[i] << std::endl; } + break; + } + default: { + break; + } + } +} + +void output_blobtree(virtual_node_t node) +{ + std::map index; + index[0] = "constant"; + index[1] = "plane"; + index[2] = "sphere"; + index[3] = "cylinder"; + index[4] = "cone"; + index[5] = "box"; + index[6] = "mesh"; + index[7] = "extrude"; + + auto root = structures[node.main_index].nodes[node.inner_index]; + std::queue now, next; + now.push(root); + + std::vector temp; + + while (!now.empty()) { + auto begin = now.front(); + now.pop(); + + if (is_primitive_node(begin)) { + std::cout << index[primitives[node_fetch_primitive_index(begin)].type] << "\t\t"; + temp.push_back(primitives[node_fetch_primitive_index(begin)]); + } else { + auto op = (uint32_t)node_fetch_operation(begin); + if (op == 0) { + std::cout << "or" + << "\t\t"; + } else if (op == 1) { + std::cout << "and" + << "\t\t"; + } else if (op == 2) { + std::cout << "sub" + << "\t\t"; + } + } + + if (!node_is_left_child_null(begin)) { + next.push(structures[node.main_index].nodes[node_fetch_left_child_index(begin)]); + } + if (!node_is_right_child_null(begin)) { + next.push(structures[node.main_index].nodes[node_fetch_right_child_index(begin)]); + } + + if (now.empty()) { + now = next; + while (!next.empty()) { next.pop(); } + std::cout << std::endl; + } + } + std::cout << std::endl; + + for (int i = 0; i < temp.size(); i++) { output_primitive_node(temp[i]); } +} +#endif // _DEBUG diff --git a/blobtree_structure/src/primitive_node_build.cpp b/blobtree_structure/src/primitive_node_build.cpp new file mode 100644 index 0000000..dde8047 --- /dev/null +++ b/blobtree_structure/src/primitive_node_build.cpp @@ -0,0 +1,130 @@ +#include "internal_api.hpp" + +#include "globals.hpp" +#include "aabb.hpp" +#include "node_operation.hpp" + +/* Geometry Generation */ + +static constexpr node_t standard_new_node = {(uint64_t)0xFFFFFFFFFFFFFFFFu, (uint64_t)0xFFFFFFFFFFFFFFFFu}; + +virtual_node_t push_primitive_node(primitive_node_t&& primitive_node, const aabb_t&& aabb) +{ + aabbs.emplace_back(aabb); + primitives.emplace_back(primitive_node); + + node_t node = standard_new_node; + node_fetch_primitive_index(node) = static_cast(primitives.size() - 1); + + blobtree_t tree; + tree.nodes.emplace_back(node); + tree.leaf_index.push_back(0); + + structures.push_back(tree); + + return virtual_node_t{static_cast(structures.size() - 1), 0}; +} + +BPE_API virtual_node_t blobtree_new_virtual_node(const constant_descriptor_t& desc) +{ + primitive_node_t node{PRIMITIVE_TYPE_CONSTANT, malloc(sizeof(constant_descriptor_t))}; + *((constant_descriptor_t*)node.desc) = std::move(desc); + + aabb_t aabb{}; + return push_primitive_node(std::move(node), std::move(aabb)); +} + +BPE_API virtual_node_t blobtree_new_virtual_node(const plane_descriptor_t& desc) +{ + primitive_node_t node{PRIMITIVE_TYPE_PLANE, malloc(sizeof(plane_descriptor_t))}; + *((plane_descriptor_t*)node.desc) = std::move(desc); + + aabb_t aabb{}; + return push_primitive_node(std::move(node), std::move(aabb)); +} + +BPE_API virtual_node_t blobtree_new_virtual_node(const sphere_descriptor_t& desc) +{ + primitive_node_t node{PRIMITIVE_TYPE_SPHERE, malloc(sizeof(sphere_descriptor_t))}; + + Eigen::Map center(&desc.center.x); + + aabb_t aabb{center.array() - desc.radius, center.array() + desc.radius}; + + *((sphere_descriptor_t*)node.desc) = std::move(desc); + return push_primitive_node(std::move(node), std::move(aabb)); +} + +BPE_API virtual_node_t blobtree_new_virtual_node(const cylinder_descriptor_t& desc) +{ + primitive_node_t node{PRIMITIVE_TYPE_CYLINDER, malloc(sizeof(cylinder_descriptor_t))}; + + // NOTE: A rough AABB bounding box + aabb_t aabb{}; + Eigen::Map bottom_center(&desc.bottom_origion.x), offset(&desc.offset.x); + aabb.extend(bottom_center.array() + desc.radius); + aabb.extend(bottom_center.array() - desc.radius); + aabb.extend(bottom_center.array() + offset.array() + desc.radius); + aabb.extend(bottom_center.array() + offset.array() - desc.radius); + + *((cylinder_descriptor_t*)node.desc) = std::move(desc); + return push_primitive_node(std::move(node), std::move(aabb)); +} + +BPE_API virtual_node_t blobtree_new_virtual_node(const cone_descriptor_t& desc) +{ + primitive_node_t node{PRIMITIVE_TYPE_CONE, malloc(sizeof(cone_descriptor_t))}; + + // NOTE: A rough AABB bounding box + aabb_t aabb{}; + Eigen::Map top_point(&desc.top_point.x), bottom_point(&desc.bottom_point.x); + aabb.extend(top_point.array() + desc.radius1); + aabb.extend(top_point.array() - desc.radius1); + aabb.extend(bottom_point.array() + desc.radius2); + aabb.extend(bottom_point.array() - desc.radius2); + + *((cone_descriptor_t*)node.desc) = std::move(desc); + return push_primitive_node(std::move(node), std::move(aabb)); +} + +BPE_API virtual_node_t blobtree_new_virtual_node(const box_descriptor_t& desc) +{ + primitive_node_t node{PRIMITIVE_TYPE_BOX, malloc(sizeof(box_descriptor_t))}; + + Eigen::Map center(&desc.center.x), half_size(&desc.half_size.x); + + aabb_t aabb{center - half_size, center + half_size}; + + *((box_descriptor_t*)node.desc) = std::move(desc); + return push_primitive_node(std::move(node), std::move(aabb)); +} + +BPE_API virtual_node_t blobtree_new_virtual_node(const mesh_descriptor_t& desc) +{ + primitive_node_t node{PRIMITIVE_TYPE_MESH, malloc(sizeof(mesh_descriptor_t))}; + + aabb_t aabb{}; + for (int i = 0; i < desc.point_number; i++) { aabb.extend(Eigen::Map(&desc.points[i].x)); } + + *((mesh_descriptor_t*)node.desc) = std::move(desc); + return push_primitive_node(std::move(node), std::move(aabb)); +} + +BPE_API virtual_node_t blobtree_new_virtual_node(const extrude_descriptor_t& desc) +{ + primitive_node_t node{PRIMITIVE_TYPE_EXTRUDE, malloc(sizeof(extrude_descriptor_t))}; + + aabb_t aabb{}; + Eigen::Map e(&desc.extusion.x); + // NOTE: Currently only straight edges are considered + for (int i = 0; i < desc.edges_number; i++) { + Eigen::Map p(&desc.points[i].x); + aabb.extend(p); + aabb.extend(p + e); + } + + *((extrude_descriptor_t*)node.desc) = std::move(desc); + return push_primitive_node(std::move(node), std::move(aabb)); +} + +BPE_API void blobtree_free_virtual_node(virtual_node_t* node) { free_sub_blobtree(node->main_index); } diff --git a/blobtree_structure/src/primitive_node_replace.cpp b/blobtree_structure/src/primitive_node_replace.cpp new file mode 100644 index 0000000..f7c390e --- /dev/null +++ b/blobtree_structure/src/primitive_node_replace.cpp @@ -0,0 +1,159 @@ +#include "internal_api.hpp" + +#include "globals.hpp" +#include "aabb.hpp" +#include "node_operation.hpp" + +BPE_API bool virtual_node_replace_primitive(virtual_node_t* node, const constant_descriptor_t& desc) +{ + auto& node_in_tree = structures[node->main_index].nodes[node->inner_index]; + + if (!node_fetch_is_primitive(node_in_tree)) { return false; } + + const uint32_t primitive_index = node_fetch_primitive_index(node_in_tree); + *((constant_descriptor_t*)primitives[primitive_index].desc) = std::move(desc); + primitives[primitive_index].type = PRIMITIVE_TYPE_CONSTANT; + aabbs[primitive_index] = aabb_t{}; + + return true; +} + +BPE_API bool virtual_node_replace_primitive(virtual_node_t* node, const plane_descriptor_t& desc) +{ + auto& node_in_tree = structures[node->main_index].nodes[node->inner_index]; + + if (!node_fetch_is_primitive(node_in_tree)) { return false; } + + const uint32_t primitive_index = node_fetch_primitive_index(node_in_tree); + *((plane_descriptor_t*)primitives[primitive_index].desc) = std::move(desc); + primitives[primitive_index].type = PRIMITIVE_TYPE_PLANE; + aabbs[primitive_index] = aabb_t{}; + + return true; +} + +BPE_API bool virtual_node_replace_primitive(virtual_node_t* node, const sphere_descriptor_t& desc) +{ + auto& node_in_tree = structures[node->main_index].nodes[node->inner_index]; + + if (!node_fetch_is_primitive(node_in_tree)) { return false; } + + const uint32_t primitive_index = node_fetch_primitive_index(node_in_tree); + + Eigen::Map center(&desc.center.x); + + aabb_t aabb{center.array() - desc.radius, center.array() + desc.radius}; + + *((sphere_descriptor_t*)primitives[primitive_index].desc) = std::move(desc); + primitives[primitive_index].type = PRIMITIVE_TYPE_SPHERE; + aabbs[primitive_index] = std::move(aabb); + + return true; +} + +BPE_API bool virtual_node_replace_primitive(virtual_node_t* node, const cylinder_descriptor_t& desc) +{ + auto& node_in_tree = structures[node->main_index].nodes[node->inner_index]; + + if (!node_fetch_is_primitive(node_in_tree)) { return false; } + + const uint32_t primitive_index = node_fetch_primitive_index(node_in_tree); + + // NOTE: A rough AABB bounding box + aabb_t aabb{}; + Eigen::Map bottom_center(&desc.bottom_origion.x), offset(&desc.offset.x); + aabb.extend(bottom_center.array() + desc.radius); + aabb.extend(bottom_center.array() - desc.radius); + aabb.extend(bottom_center.array() + offset.array() + desc.radius); + aabb.extend(bottom_center.array() + offset.array() - desc.radius); + + *((cylinder_descriptor_t*)primitives[primitive_index].desc) = std::move(desc); + primitives[primitive_index].type = PRIMITIVE_TYPE_CYLINDER; + aabbs[primitive_index] = std::move(aabb); + + return true; +} + +BPE_API bool virtual_node_replace_primitive(virtual_node_t* node, const cone_descriptor_t& desc) +{ + auto& node_in_tree = structures[node->main_index].nodes[node->inner_index]; + + if (!node_fetch_is_primitive(node_in_tree)) { return false; } + + const uint32_t primitive_index = node_fetch_primitive_index(node_in_tree); + + // NOTE: A rough AABB bounding box + aabb_t aabb{}; + Eigen::Map top_point(&desc.top_point.x), bottom_point(&desc.bottom_point.x); + aabb.extend(top_point.array() + desc.radius1); + aabb.extend(top_point.array() - desc.radius1); + aabb.extend(bottom_point.array() + desc.radius2); + aabb.extend(bottom_point.array() - desc.radius2); + + *((cone_descriptor_t*)primitives[primitive_index].desc) = std::move(desc); + primitives[primitive_index].type = PRIMITIVE_TYPE_CONE; + aabbs[primitive_index] = std::move(aabb); + + return true; +} + +BPE_API bool virtual_node_replace_primitive(virtual_node_t* node, const box_descriptor_t& desc) +{ + auto& node_in_tree = structures[node->main_index].nodes[node->inner_index]; + + if (!node_fetch_is_primitive(node_in_tree)) { return false; } + + const uint32_t primitive_index = node_fetch_primitive_index(node_in_tree); + + Eigen::Map center(&desc.center.x), half_size(&desc.half_size.x); + + aabb_t aabb{center - half_size, center + half_size}; + + *((box_descriptor_t*)primitives[primitive_index].desc) = std::move(desc); + primitives[primitive_index].type = PRIMITIVE_TYPE_BOX; + aabbs[primitive_index] = std::move(aabb); + + return true; +} + +BPE_API bool virtual_node_replace_primitive(virtual_node_t* node, const mesh_descriptor_t& desc) +{ + auto& node_in_tree = structures[node->main_index].nodes[node->inner_index]; + + if (!node_fetch_is_primitive(node_in_tree)) { return false; } + + const uint32_t primitive_index = node_fetch_primitive_index(node_in_tree); + + aabb_t aabb{}; + for (int i = 0; i < desc.point_number; i++) { aabb.extend(Eigen::Map(&desc.points[i].x)); } + + *((mesh_descriptor_t*)primitives[primitive_index].desc) = std::move(desc); + primitives[primitive_index].type = PRIMITIVE_TYPE_MESH; + aabbs[primitive_index] = std::move(aabb); + + return true; +} + +BPE_API bool virtual_node_replace_primitive(virtual_node_t* node, const extrude_descriptor_t& desc) +{ + auto& node_in_tree = structures[node->main_index].nodes[node->inner_index]; + + if (!node_fetch_is_primitive(node_in_tree)) { return false; } + + const uint32_t primitive_index = node_fetch_primitive_index(node_in_tree); + + aabb_t aabb{}; + Eigen::Map e(&desc.extusion.x); + // NOTE: Currently only straight edges are considered + for (int i = 0; i < desc.edges_number; i++) { + Eigen::Map p(&desc.points[i].x); + aabb.extend(p); + aabb.extend(p + e); + } + + *((extrude_descriptor_t*)primitives[primitive_index].desc) = std::move(desc); + primitives[primitive_index].type = PRIMITIVE_TYPE_EXTRUDE; + aabbs[primitive_index] = std::move(aabb); + + return true; +} \ No newline at end of file diff --git a/frontend/src/implicit_surface_network_processor.cpp b/frontend/src/implicit_surface_network_processor.cpp index 9e0eccd..3084ca8 100644 --- a/frontend/src/implicit_surface_network_processor.cpp +++ b/frontend/src/implicit_surface_network_processor.cpp @@ -52,6 +52,7 @@ bool ImplicitSurfaceNetworkProcessor::run(labelled_timers_manager& timers_manage // 2. filter active functions in each tetrahedron // 3. compute arrangement in each tet (skip robust test) // 4. compute incident tets for degenerate vertices + // CAUTION: during process, always keep positive signs as inside (sdf), and this is reversed as usual // stl_vector_mp sample_function_label(num_funcs, false); stl_vector_mp> vertex_scalar_values(num_vert, stl_vector_mp(num_funcs)); stl_vector_mp active_functions_in_tet{}; // active function indices in CRS vector format @@ -89,7 +90,8 @@ bool ImplicitSurfaceNetworkProcessor::run(labelled_timers_manager& timers_manage } }; - auto scalar_field_sign = [](double x) -> int8_t { return (x > 0) ? 1 : ((x < 0) ? -1 : 0); }; + // auto scalar_field_sign = [](double x) -> int8_t { return (x > 0) ? 1 : ((x < 0) ? -1 : 0); }; + auto scalar_field_sign = [](double x) -> int8_t { return (x < 0) ? 1 : ((x > 0) ? -1 : 0); }; auto get_or_init_vertex_info = [&, this](uint32_t vert_index, uint32_t tet_index) { std::call_once(vertex_sign_constructed[vert_index], [&, this] { const auto& vertex = background_vertices[vert_index]; @@ -137,7 +139,7 @@ bool ImplicitSurfaceNetworkProcessor::run(labelled_timers_manager& timers_manage if (auto sign = vi0.signs[j] + vi1.signs[j] + vi2.signs[j] + vi3.signs[j]; -4 < sign && sign < 4) { index = curr_active_func_index.fetch_add(1, std::memory_order_acq_rel) + 1; active_functions_in_tet[index - 1] = static_cast(j); - planes.emplace_back(plane_t{vs0[j], vs1[j], vs2[j], vs3[j]}); + planes.emplace_back(plane_t{-vs0[j], -vs1[j], -vs2[j], -vs3[j]}); } }); @@ -229,11 +231,16 @@ bool ImplicitSurfaceNetworkProcessor::run(labelled_timers_manager& timers_manage } // compute order of patches around chains - // pair : pair (iso-face index, iso-face orientation) - stl_vector_mp> half_patch_pair_list{}; + // (patch i, 1) <--> 2i, (patch i, -1) <--> 2i+1 + // compute half-patch adjacency list + // stl_vector_mp> half_patch_pair_list{}; + stl_vector_mp> half_patch_adj_list(2 * patches.size()); + // HINT: always keep positive sign inside + stl_vector_mp> patch_func_signs(2 * patches.size(), dynamic_bitset_mp<>(num_funcs, false)); + for (uint32_t i = 0; i < num_funcs; ++i) patch_func_signs[i][i] = true; { timers_manager.push_timer("compute order of patches around chains"); - half_patch_pair_list.resize(chains.size()); + // half_patch_pair_list.resize(chains.size()); // order iso-faces incident to each representative iso-edge for (uint32_t i = 0; i < chains.size(); i++) { // pick first iso-edge from each chain as representative @@ -248,7 +255,9 @@ bool ImplicitSurfaceNetworkProcessor::run(labelled_timers_manager& timers_manage start_index_of_tet, incident_tets, patch_of_face, - half_patch_pair_list[i]); + half_patch_adj_list, + patch_func_signs); + // half_patch_pair_list[i]); } timers_manager.pop_timer("compute order of patches around chains"); } @@ -261,8 +270,8 @@ bool ImplicitSurfaceNetworkProcessor::run(labelled_timers_manager& timers_manage stl_vector_mp component_of_patch{}; { timers_manager.push_timer("group patches into shells and components"); - compute_shells_and_components(static_cast(patches.size()), - half_patch_pair_list, + compute_shells_and_components(half_patch_adj_list, + patch_func_signs, shells, shell_of_half_patch, components, diff --git a/implicit_arrangements/interface/implicit_arrangement.hpp b/implicit_arrangements/interface/implicit_arrangement.hpp index 33892ee..e28ee2f 100644 --- a/implicit_arrangements/interface/implicit_arrangement.hpp +++ b/implicit_arrangements/interface/implicit_arrangement.hpp @@ -33,9 +33,9 @@ struct arrangement_t { struct face_descriptor { stl_vector_mp vertices{}; ///< An ordered list of boundary vertices. The face is always oriented ///< counterclockwise when viewed from the positive side of the supporting plane. - uint32_t supporting_plane{INVALID_INDEX}; ///< A set of supporting planes' indices for each edge. - uint32_t positive_cell{INVALID_INDEX}; ///< A set of positive side cells' indices for each edge. - uint32_t negative_cell{INVALID_INDEX}; ///< A set of negative side cells' indices for each edge. + uint32_t supporting_plane{INVALID_INDEX}; ///< Plane index of the supporting plane. + uint32_t positive_cell{INVALID_INDEX}; ///< The cell index on the positive side of this face. + uint32_t negative_cell{INVALID_INDEX}; ///< The cell index on the negative side of this face. }; stl_vector_mp faces{}; ///< A set of boundary vertex indices in no particular order. diff --git a/network_process/interface/pair_faces.hpp b/network_process/interface/pair_faces.hpp index af80438..9ae75d8 100644 --- a/network_process/interface/pair_faces.hpp +++ b/network_process/interface/pair_faces.hpp @@ -1,12 +1,14 @@ #pragma once #include +#include #include // compute neighboring pair of half-patches around an iso-edge // output: -// pair : pair (iso-face index, iso-face orientation) +// half-patch adjacency list : (patch i, 1) <--> 2i, (patch i, -1) <--> 2i+1 +// half-patch function signs ISNP_API void compute_patch_order(const iso_edge_t &iso_edge, const stl_vector_mp &tets, const stl_vector_mp &iso_verts, @@ -16,18 +18,20 @@ ISNP_API void compute_patch_order(const iso_edge_t const stl_vector_mp &start_index_of_tet, const parallel_flat_hash_map_mp> &incident_tets, const stl_vector_mp &patch_of_face_mapping, - stl_vector_mp &ordered_patch_pairs); + stl_vector_mp> &half_patch_adj_list, + stl_vector_mp> &patch_func_signs); // compute neighboring pair of half-patches around an iso-edge in a tetrahedron -// pair : pair (iso-face index, iso-face orientation) -ISNP_API void pair_patches_in_one_tet(const arrangement_t &tet_cut_result, - const stl_vector_mp &iso_faces, - const iso_edge_t &iso_edge, - const stl_vector_mp &patch_of_face_mapping, - stl_vector_mp &ordered_patch_pairs); +// half-patch adjacency list : (patch i, 1) <--> 2i, (patch i, -1) <--> 2i+1 +ISNP_API void pair_patches_in_one_tet(const arrangement_t &tet_cut_result, + const stl_vector_mp &iso_faces, + const iso_edge_t &iso_edge, + const stl_vector_mp &patch_of_face_mapping, + stl_vector_mp> &half_patch_adj_list, + stl_vector_mp> &patch_func_signs); // compute neighboring pair of half-patches around an iso-edge in multiple tetrahedrons -// pair : pair (iso-face index, iso-face orientation) +// half-patch adjacency list : (patch i, 1) <--> 2i, (patch i, -1) <--> 2i+1 ISNP_API void pair_patches_in_tets(const iso_edge_t &iso_edge, const stl_vector_mp &containing_simplex, const stl_vector_mp &containing_tetIds, @@ -37,4 +41,5 @@ ISNP_API void pair_patches_in_tets(const iso_edge_t const stl_vector_mp &func_in_tet, const stl_vector_mp &start_index_of_tet, const stl_vector_mp &patch_of_face_mapping, - stl_vector_mp &ordered_patch_pairs); \ No newline at end of file + stl_vector_mp> &half_patch_adj_list, + stl_vector_mp> &patch_func_signs); \ No newline at end of file diff --git a/network_process/interface/patch_connectivity.hpp b/network_process/interface/patch_connectivity.hpp index 3c9aad8..f14cb91 100644 --- a/network_process/interface/patch_connectivity.hpp +++ b/network_process/interface/patch_connectivity.hpp @@ -1,5 +1,7 @@ #pragma once +#include + #include /// Compute iso-edges and edge-face connectivity @@ -57,19 +59,18 @@ ISNP_API void compute_chains(const stl_vector_mp& patch /// each shell is a list of half-patches /// each component is a list of patches /// we also build maps: half-patch --> shell, patch --> component -///@param[in] num_patch Patch number -///@param[in] half_patch_pair_list The list of half patch represented as (patch i, 1) and (patch i, -1); Maps to a -/// single half-patch index: (patch i, 1) <--> 2i, (patch i, -1) <--> 2i+1 +/// @param[in] half_patch_adj_list The adjacency list of half-patches +/// @param[in] patch_func_signs The function signs' array of half-patches /// /// @param[out] shell_of_patch Map: half-patch --> shell /// @param[out] component Connected componeent represented as a list of patches /// @param[out] component_of_patch Map: patch --> component -ISNP_API void compute_shells_and_components(uint32_t num_patch, - const stl_vector_mp>& half_patch_pair_list, - stl_vector_mp>& shells, - stl_vector_mp& shell_of_half_patch, - stl_vector_mp>& components, - stl_vector_mp& component_of_patch); +ISNP_API void compute_shells_and_components(const stl_vector_mp>& half_patch_adj_list, + const stl_vector_mp>& patch_func_signs, + stl_vector_mp>& shells, + stl_vector_mp& shell_of_half_patch, + stl_vector_mp>& components, + stl_vector_mp& component_of_patch); /// group shells into arrangement cells /// diff --git a/network_process/src/pair_faces.cpp b/network_process/src/pair_faces.cpp index af4b92b..29b65f9 100644 --- a/network_process/src/pair_faces.cpp +++ b/network_process/src/pair_faces.cpp @@ -14,7 +14,8 @@ ISNP_API void compute_patch_order(const iso_edge_t const stl_vector_mp &start_index_of_tet, const parallel_flat_hash_map_mp> &incident_tets, const stl_vector_mp &patch_of_face_mapping, - stl_vector_mp &ordered_patch_pairs) + stl_vector_mp> &half_patch_adj_list, + stl_vector_mp> &patch_func_signs) { using unordered_set_mp_of_index_t = std::unordered_set, std::equal_to, ScalableMemoryPoolAllocator>; @@ -31,7 +32,12 @@ ISNP_API void compute_patch_order(const iso_edge_t if (containing_tets.size() == 1) { // std::cout << ">>>>>>>> iso-edge in tet" << std::endl; auto tet_id = *containing_tets.begin(); - pair_patches_in_one_tet(*cut_results[tet_id].get(), iso_faces, iso_edge, patch_of_face_mapping, ordered_patch_pairs); + pair_patches_in_one_tet(*cut_results[tet_id].get(), + iso_faces, + iso_edge, + patch_of_face_mapping, + half_patch_adj_list, + patch_func_signs); } else { const auto v1 = iso_edge.v1; const auto v2 = iso_edge.v2; @@ -79,7 +85,8 @@ ISNP_API void compute_patch_order(const iso_edge_t func_in_tet, start_index_of_tet, patch_of_face_mapping, - ordered_patch_pairs); + half_patch_adj_list, + patch_func_signs); } else { // std::cout << ">>>>>>>> iso-edge on tet face" << std::endl; // iso_edge lies on a tet boundary face @@ -102,18 +109,20 @@ ISNP_API void compute_patch_order(const iso_edge_t func_in_tet, start_index_of_tet, patch_of_face_mapping, - ordered_patch_pairs); + half_patch_adj_list, + patch_func_signs); } } } // =============================================================================================== -ISNP_API void pair_patches_in_one_tet(const arrangement_t &tet_cut_result, - const stl_vector_mp &iso_faces, - const iso_edge_t &iso_edge, - const stl_vector_mp &patch_of_face_mapping, - stl_vector_mp &ordered_patch_pairs) +ISNP_API void pair_patches_in_one_tet(const arrangement_t &tet_cut_result, + const stl_vector_mp &iso_faces, + const iso_edge_t &iso_edge, + const stl_vector_mp &patch_of_face_mapping, + stl_vector_mp> &half_patch_adj_list, + stl_vector_mp> &patch_func_signs) { // find tet faces that are incident to the iso_edge stl_vector_mp is_incident_faces(tet_cut_result.faces.size(), false); @@ -169,9 +178,15 @@ ISNP_API void pair_patches_in_one_tet(const arrangement_t &tet_c info2.face_sign = -1; } // add (face1, face2) to the list of face pairs - info2.iso_face_id = iso_face_Id_of_face[info2.face_id]; - ordered_patch_pairs.emplace_back(half_patch_t{patch_of_face_mapping[info1.iso_face_id], info1.face_sign}, - half_patch_t{patch_of_face_mapping[info2.iso_face_id], info1.face_sign}); + info2.iso_face_id = iso_face_Id_of_face[info2.face_id]; + const auto half_patch_index1 = info1.face_sign > 0 ? 2 * patch_of_face_mapping[info1.iso_face_id] + : 2 * patch_of_face_mapping[info1.iso_face_id] + 1; + const auto half_patch_index2 = info2.face_sign > 0 ? 2 * patch_of_face_mapping[info2.iso_face_id] + : 2 * patch_of_face_mapping[info2.iso_face_id] + 1; + half_patch_adj_list[half_patch_index1].emplace_back(half_patch_index2); + half_patch_adj_list[half_patch_index2].emplace_back(half_patch_index1); + if (info2.face_sign > 0) patch_func_signs[half_patch_index1 >> 1][half_patch_index2 >> 1] = true; + if (info1.face_sign > 0) patch_func_signs[half_patch_index2 >> 1][half_patch_index1 >> 1] = true; // update face1 and clear face2 info1.move_update(std::move(info2)); } @@ -205,7 +220,8 @@ ISNP_API void pair_patches_in_tets(const iso_edge_t const stl_vector_mp &func_in_tet, const stl_vector_mp &start_index_of_tet, const stl_vector_mp &patch_of_face_mapping, - stl_vector_mp &ordered_patch_pairs) + stl_vector_mp> &half_patch_adj_list, + stl_vector_mp> &patch_func_signs) { //// pre-processing // collect all iso-faces incident to the iso-edge @@ -518,8 +534,16 @@ ISNP_API void pair_patches_in_tets(const iso_edge_t } get_half_iso_face(face_curr, orient_curr, iso_face_curr, iso_orient_curr); get_half_iso_face(face_next, orient_next, iso_face_next, iso_orient_next); - ordered_patch_pairs.emplace_back(half_patch_t{patch_of_face_mapping[iso_face_curr], iso_orient_curr}, - half_patch_t{patch_of_face_mapping[iso_face_next], iso_orient_next}); + // + const auto half_patch_index1 = + iso_orient_curr > 0 ? 2 * patch_of_face_mapping[iso_face_curr] : 2 * patch_of_face_mapping[iso_face_curr] + 1; + const auto half_patch_index2 = + iso_orient_next > 0 ? 2 * patch_of_face_mapping[iso_face_next] : 2 * patch_of_face_mapping[iso_face_next] + 1; + half_patch_adj_list[half_patch_index1].emplace_back(half_patch_index2); + half_patch_adj_list[half_patch_index2].emplace_back(half_patch_index1); + if (iso_orient_next > 0) patch_func_signs[half_patch_index1 >> 1][half_patch_index2 >> 1] = true; + if (iso_orient_curr > 0) patch_func_signs[half_patch_index2 >> 1][half_patch_index1 >> 1] = true; + // face_curr = face_next; orient_curr = -orient_next; } diff --git a/network_process/src/patch_connectivity.cpp b/network_process/src/patch_connectivity.cpp index d7fe1b4..cd19a28 100644 --- a/network_process/src/patch_connectivity.cpp +++ b/network_process/src/patch_connectivity.cpp @@ -126,27 +126,14 @@ ISNP_API void compute_chains(const stl_vector_mp& patch } } -ISNP_API void compute_shells_and_components(uint32_t num_patch, - const stl_vector_mp>& half_patch_pair_list, - stl_vector_mp>& shells, - stl_vector_mp& shell_of_half_patch, - stl_vector_mp>& components, - stl_vector_mp& component_of_patch) +ISNP_API void compute_shells_and_components(const stl_vector_mp>& half_patch_adj_list, + const stl_vector_mp>& patch_func_signs, + stl_vector_mp>& shells, + stl_vector_mp& shell_of_half_patch, + stl_vector_mp>& components, + stl_vector_mp& component_of_patch) { - // (patch i, 1) <--> 2i, (patch i, -1) <--> 2i+1 - // compute half-patch adjacency list - stl_vector_mp> half_patch_adj_list(2 * num_patch); - for (const auto& half_patch_pairs : half_patch_pair_list) { - for (uint32_t i = 0; i < half_patch_pairs.size(); i++) { - const auto& [hp1, hp2] = half_patch_pairs[i]; - // half-patch index of hp1 - const auto hp_Id1 = (hp1.orientation == 1) ? 2 * hp1.index : (2 * hp1.index + 1); - // half-patch index of hp2 - const auto hp_Id2 = (hp2.orientation == 1) ? 2 * hp2.index : (2 * hp2.index + 1); - half_patch_adj_list[hp_Id1].emplace_back(hp_Id2); - half_patch_adj_list[hp_Id2].emplace_back(hp_Id1); - } - } + const auto num_patch = half_patch_adj_list.size() / 2; // find connected component of half-patch adjacency graph // each component is a shell stl_vector_mp visited_flags(2 * num_patch, false); diff --git a/shared_module/container/dynamic_bitset.hpp b/shared_module/container/dynamic_bitset.hpp index e51c9d7..b96d592 100644 --- a/shared_module/container/dynamic_bitset.hpp +++ b/shared_module/container/dynamic_bitset.hpp @@ -8,7 +8,8 @@ template using dynamic_bitset = detail::dynamic_bitset::template type, T>; template -using dynamic_bitset_mp = detail::dynamic_bitset::template type, T>; +using dynamic_bitset_mp = detail::dynamic_bitset::template type, T>; +// using dynamic_bitset_mp = detail::dynamic_bitset::template type, T>; template using small_dynamic_bitset = detail::dynamic_bitset::template type, T>;