Browse Source

tidy blobtree

pull/5/head
Zhicheng Wang 8 months ago
parent
commit
aabe5654e1
  1. 33
      blobtree_structure/include/aabb.hpp
  2. 21
      blobtree_structure/include/globals.hpp
  3. 236
      blobtree_structure/include/node_operation.hpp
  4. 16
      blobtree_structure/interface/internal_api.hpp
  5. 1092
      blobtree_structure/src/blobtree.cpp
  6. 169
      blobtree_structure/src/debug.cpp
  7. 130
      blobtree_structure/src/primitive_node_build.cpp
  8. 159
      blobtree_structure/src/primitive_node_replace.cpp
  9. 25
      frontend/src/implicit_surface_network_processor.cpp
  10. 6
      implicit_arrangements/interface/implicit_arrangement.hpp
  11. 17
      network_process/interface/pair_faces.hpp
  12. 11
      network_process/interface/patch_connectivity.hpp
  13. 44
      network_process/src/pair_faces.cpp
  14. 19
      network_process/src/patch_connectivity.cpp
  15. 3
      shared_module/container/dynamic_bitset.hpp

33
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<double>::max(),
std::numeric_limits<double>::max(),
std::numeric_limits<double>::max()};
Eigen::Vector3d max{std::numeric_limits<double>::min(),
std::numeric_limits<double>::min(),
std::numeric_limits<double>::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;
}
};

21
blobtree_structure/include/globals.hpp

@ -0,0 +1,21 @@
#pragma once
#include <vector>
#include <stack>
#include <tbb/tbb.h>
#include "blobtree.h"
#include "aabb.hpp"
#include "node_operation.hpp"
struct blobtree_t {
std::vector<node_t, tbb::tbb_allocator<node_t>> nodes{};
std::vector<uint32_t, tbb::tbb_allocator<uint32_t>> leaf_index{};
};
extern std::vector<blobtree_t, tbb::tbb_allocator<blobtree_t>> structures;
extern std::vector<aabb_t, tbb::tbb_allocator<aabb_t>> aabbs;
extern std::vector<primitive_node_t, tbb::tbb_allocator<primitive_node_t>> primitives;
extern std::stack<uint32_t, std::deque<uint32_t, tbb::tbb_allocator<uint32_t>>> free_structure_list;

236
blobtree_structure/include/node_operation.hpp

@ -0,0 +1,236 @@
#pragma once
#include <type_traits>
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 <typename T, typename = std::enable_if_t<sizeof(T) <= sizeof(uint64_t)>>
constexpr node_t(T value)
{
data[0] = 0;
data[1] = static_cast<uint64_t>(value);
}
template <typename T, typename = std::enable_if_t<sizeof(T) <= sizeof(uint64_t)>>
constexpr operator T() const
{
return static_cast<T>(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 <typename _Tp>
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 <typename _Fp, typename = std::enable_if_t<!std::is_same_v<_Fp, node_proxy>>>
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::underlying_type_t<_Fp>>(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<uint32_t>(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 <typename _Fp,
typename = std::enable_if_t<!std::is_same_v<_Fp, node_proxy> && //
!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 <typename _Tp>
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<bool>(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<eNodeOperation>(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<eNodeLocation>(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<uint32_t>(node, 96u, 0xFFFFFFu); }
static constexpr inline auto node_is_parent_null(const node_t& node)
{
return const_node_proxy<uint32_t>(node, 96u, 0xFFFFFFu) == 0xFFFFFFFFu;
}
// Parent node index
static constexpr inline auto node_fetch_parent_index(node_t& node) { return node_proxy<uint32_t>(node, 64u, 0xFFFFFFFFu); }
// Left child node index
static constexpr inline auto node_fetch_left_child_index(node_t& node) { return node_proxy<uint32_t>(node, 32u, 0xFFFFFFFFu); }
static constexpr inline auto node_is_left_child_null(const node_t& node)
{
return const_node_proxy<uint32_t>(node, 32u, 0xFFFFFFFFu) == 0xFFFFFFFFu;
}
// Right child node index
static constexpr inline auto node_fetch_right_child_index(node_t& node) { return node_proxy<uint32_t>(node, 0u, 0xFFFFFFFFu); }
static constexpr inline auto node_is_right_child_null(const node_t& node)
{
return const_node_proxy<uint32_t>(node, 0u, 0xFFFFFFFFu) == 0xFFFFFFFFu;
}

16
blobtree_structure/interface/internal_api.hpp

@ -24,6 +24,16 @@ BPE_API double evaluate(const extrude_descriptor_t& desc, const Eigen::Ref<const
BPE_API double evaluate(const primitive_node_t& node, const raw_vector3d_t& point);
// Basic Operations
/**
* @brief Get all primitive nodes
* @return Primitive array
*/
BPE_API std::vector<primitive_node_t, tbb::tbb_allocator<primitive_node_t>>& 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<primitive_node_t, tbb::tbb_allocator<primitive_node_t>>& get_primitives() noexcept;
// Geometry Operations
/**

1092
blobtree_structure/src/blobtree.cpp

File diff suppressed because it is too large

169
blobtree_structure/src/debug.cpp

@ -0,0 +1,169 @@
#include <iostream>
#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<constant_descriptor_t*>(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<plane_descriptor_t*>(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<sphere_descriptor_t*>(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<cylinder_descriptor_t*>(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<cone_descriptor_t*>(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<box_descriptor_t*>(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<mesh_descriptor_t*>(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<extrude_descriptor_t*>(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<int, std::string> 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<node_t> now, next;
now.push(root);
std::vector<primitive_node_t> 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

130
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<uint32_t>(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<uint32_t>(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<const Eigen::Vector3d> 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<const Eigen::Vector3d> 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<const Eigen::Vector3d> 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<const Eigen::Vector3d> 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<const Eigen::Vector3d>(&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<const Eigen::Vector3d> e(&desc.extusion.x);
// NOTE: Currently only straight edges are considered
for (int i = 0; i < desc.edges_number; i++) {
Eigen::Map<const Eigen::Vector3d> 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); }

159
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<const Eigen::Vector3d> 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<const Eigen::Vector3d> 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<const Eigen::Vector3d> 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<const Eigen::Vector3d> 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<const Eigen::Vector3d>(&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<const Eigen::Vector3d> e(&desc.extusion.x);
// NOTE: Currently only straight edges are considered
for (int i = 0; i < desc.edges_number; i++) {
Eigen::Map<const Eigen::Vector3d> 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;
}

25
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<bool> sample_function_label(num_funcs, false);
stl_vector_mp<stl_vector_mp<double>> vertex_scalar_values(num_vert, stl_vector_mp<double>(num_funcs));
stl_vector_mp<uint32_t> 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<uint32_t>(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<uint32_t, int8_t> : pair (iso-face index, iso-face orientation)
stl_vector_mp<stl_vector_mp<half_patch_pair_t>> half_patch_pair_list{};
// (patch i, 1) <--> 2i, (patch i, -1) <--> 2i+1
// compute half-patch adjacency list
// stl_vector_mp<stl_vector_mp<half_patch_pair_t>> half_patch_pair_list{};
stl_vector_mp<small_vector_mp<uint32_t>> half_patch_adj_list(2 * patches.size());
// HINT: always keep positive sign inside
stl_vector_mp<dynamic_bitset_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<uint32_t> component_of_patch{};
{
timers_manager.push_timer("group patches into shells and components");
compute_shells_and_components(static_cast<uint32_t>(patches.size()),
half_patch_pair_list,
compute_shells_and_components(half_patch_adj_list,
patch_func_signs,
shells,
shell_of_half_patch,
components,

6
implicit_arrangements/interface/implicit_arrangement.hpp

@ -33,9 +33,9 @@ struct arrangement_t {
struct face_descriptor {
stl_vector_mp<uint32_t> 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<face_descriptor> faces{}; ///< A set of boundary vertex indices in no particular order.

17
network_process/interface/pair_faces.hpp

@ -1,12 +1,14 @@
#pragma once
#include <container/hashmap.hpp>
#include <container/dynamic_bitset.hpp>
#include <utils/fwd_types.hpp>
// compute neighboring pair of half-patches around an iso-edge
// output:
// pair<uint32_t, int8_t> : 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<tetrahedron_vertex_indices_t> &tets,
const stl_vector_mp<iso_vertex_t> &iso_verts,
@ -16,18 +18,20 @@ ISNP_API void compute_patch_order(const iso_edge_t
const stl_vector_mp<uint32_t> &start_index_of_tet,
const parallel_flat_hash_map_mp<uint32_t, stl_vector_mp<uint32_t>> &incident_tets,
const stl_vector_mp<uint32_t> &patch_of_face_mapping,
stl_vector_mp<half_patch_pair_t> &ordered_patch_pairs);
stl_vector_mp<small_vector_mp<uint32_t>> &half_patch_adj_list,
stl_vector_mp<dynamic_bitset_mp<>> &patch_func_signs);
// compute neighboring pair of half-patches around an iso-edge in a tetrahedron
// pair<uint32_t, int8_t> : 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_one_tet(const arrangement_t &tet_cut_result,
const stl_vector_mp<polygon_face_t> &iso_faces,
const iso_edge_t &iso_edge,
const stl_vector_mp<uint32_t> &patch_of_face_mapping,
stl_vector_mp<half_patch_pair_t> &ordered_patch_pairs);
stl_vector_mp<small_vector_mp<uint32_t>> &half_patch_adj_list,
stl_vector_mp<dynamic_bitset_mp<>> &patch_func_signs);
// compute neighboring pair of half-patches around an iso-edge in multiple tetrahedrons
// pair<uint32_t, int8_t> : 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<uint32_t> &containing_simplex,
const stl_vector_mp<uint32_t> &containing_tetIds,
@ -37,4 +41,5 @@ ISNP_API void pair_patches_in_tets(const iso_edge_t
const stl_vector_mp<uint32_t> &func_in_tet,
const stl_vector_mp<uint32_t> &start_index_of_tet,
const stl_vector_mp<uint32_t> &patch_of_face_mapping,
stl_vector_mp<half_patch_pair_t> &ordered_patch_pairs);
stl_vector_mp<small_vector_mp<uint32_t>> &half_patch_adj_list,
stl_vector_mp<dynamic_bitset_mp<>> &patch_func_signs);

11
network_process/interface/patch_connectivity.hpp

@ -1,5 +1,7 @@
#pragma once
#include <container/dynamic_bitset.hpp>
#include <utils/fwd_types.hpp>
/// Compute iso-edges and edge-face connectivity
@ -57,15 +59,14 @@ ISNP_API void compute_chains(const stl_vector_mp<iso_edge_t>& 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<stl_vector_mp<half_patch_pair_t>>& half_patch_pair_list,
ISNP_API void compute_shells_and_components(const stl_vector_mp<small_vector_mp<uint32_t>>& half_patch_adj_list,
const stl_vector_mp<dynamic_bitset_mp<>>& patch_func_signs,
stl_vector_mp<stl_vector_mp<uint32_t>>& shells,
stl_vector_mp<uint32_t>& shell_of_half_patch,
stl_vector_mp<stl_vector_mp<uint32_t>>& components,

44
network_process/src/pair_faces.cpp

@ -14,7 +14,8 @@ ISNP_API void compute_patch_order(const iso_edge_t
const stl_vector_mp<uint32_t> &start_index_of_tet,
const parallel_flat_hash_map_mp<uint32_t, stl_vector_mp<uint32_t>> &incident_tets,
const stl_vector_mp<uint32_t> &patch_of_face_mapping,
stl_vector_mp<half_patch_pair_t> &ordered_patch_pairs)
stl_vector_mp<small_vector_mp<uint32_t>> &half_patch_adj_list,
stl_vector_mp<dynamic_bitset_mp<>> &patch_func_signs)
{
using unordered_set_mp_of_index_t =
std::unordered_set<uint32_t, std::hash<uint32_t>, std::equal_to<uint32_t>, ScalableMemoryPoolAllocator<uint32_t>>;
@ -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,7 +109,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);
}
}
}
@ -113,7 +121,8 @@ ISNP_API void pair_patches_in_one_tet(const arrangement_t &tet_c
const stl_vector_mp<polygon_face_t> &iso_faces,
const iso_edge_t &iso_edge,
const stl_vector_mp<uint32_t> &patch_of_face_mapping,
stl_vector_mp<half_patch_pair_t> &ordered_patch_pairs)
stl_vector_mp<small_vector_mp<uint32_t>> &half_patch_adj_list,
stl_vector_mp<dynamic_bitset_mp<>> &patch_func_signs)
{
// find tet faces that are incident to the iso_edge
stl_vector_mp<bool> is_incident_faces(tet_cut_result.faces.size(), false);
@ -170,8 +179,14 @@ ISNP_API void pair_patches_in_one_tet(const arrangement_t &tet_c
}
// 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});
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<uint32_t> &func_in_tet,
const stl_vector_mp<uint32_t> &start_index_of_tet,
const stl_vector_mp<uint32_t> &patch_of_face_mapping,
stl_vector_mp<half_patch_pair_t> &ordered_patch_pairs)
stl_vector_mp<small_vector_mp<uint32_t>> &half_patch_adj_list,
stl_vector_mp<dynamic_bitset_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;
}

19
network_process/src/patch_connectivity.cpp

@ -126,27 +126,14 @@ ISNP_API void compute_chains(const stl_vector_mp<iso_edge_t>& patch
}
}
ISNP_API void compute_shells_and_components(uint32_t num_patch,
const stl_vector_mp<stl_vector_mp<half_patch_pair_t>>& half_patch_pair_list,
ISNP_API void compute_shells_and_components(const stl_vector_mp<small_vector_mp<uint32_t>>& half_patch_adj_list,
const stl_vector_mp<dynamic_bitset_mp<>>& patch_func_signs,
stl_vector_mp<stl_vector_mp<uint32_t>>& shells,
stl_vector_mp<uint32_t>& shell_of_half_patch,
stl_vector_mp<stl_vector_mp<uint32_t>>& components,
stl_vector_mp<uint32_t>& component_of_patch)
{
// (patch i, 1) <--> 2i, (patch i, -1) <--> 2i+1
// compute half-patch adjacency list
stl_vector_mp<small_vector_mp<uint32_t>> 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<bool> visited_flags(2 * num_patch, false);

3
shared_module/container/dynamic_bitset.hpp

@ -8,7 +8,8 @@ template <typename T = unsigned long long>
using dynamic_bitset = detail::dynamic_bitset<detail::stl_vector_bind<>::template type, T>;
template <typename T = unsigned long long>
using dynamic_bitset_mp = detail::dynamic_bitset<detail::stl_vector_bind<ScalableMemoryPoolAllocator>::template type, T>;
using dynamic_bitset_mp = detail::dynamic_bitset<detail::stl_vector_bind<tbb::tbb_allocator>::template type, T>;
// using dynamic_bitset_mp = detail::dynamic_bitset<detail::stl_vector_bind<ScalableMemoryPoolAllocator>::template type, T>;
template <typename T = unsigned long long, std::size_t N = 1>
using small_dynamic_bitset = detail::dynamic_bitset<detail::small_vector_bind<N>::template type, T>;

Loading…
Cancel
Save