diff --git a/application/basic_test.cpp b/application/basic_test.cpp new file mode 100644 index 0000000..cee94e5 --- /dev/null +++ b/application/basic_test.cpp @@ -0,0 +1,43 @@ +#include +#include + +#include + +#include +#include +#include + +#include +#include "internal_api.hpp" +#include "primitive_descriptor.h" + +int main() +{ + std::cout << "Setting scene..." << std::endl; + box_descriptor_t box_large{ + {500, 50, 50}, + {500, 50, 50} + }; + box_descriptor_t box_small{ + {45, 50, 50}, + {5, 50, 50} + }; + auto tree_root = make_primitive_node_by_move(box_large); + auto tree_small = make_primitive_node_by_move(box_small); + virtual_node_boolean_difference(&tree_root, &tree_small); + + std::cout << "Setting environments..." << std::endl; + setting_descriptor setting_desc{21, 1e-5}; + update_setting(setting_desc); + update_environment(&tree_root); + + std::cout << "Executing solver..." << std::endl; + auto result = execute_solver(&tree_root); + std::cout << "Surface integral result: " << result.surf_int_result << std::endl; + std::cout << "Volume integral result: " << result.vol_int_result << std::endl; + + std::cout << "Time statistics: " << std::endl; + print_statistics(); + + return 0; +} \ No newline at end of file diff --git a/application/xmake.lua b/application/xmake.lua index d35d93e..ff1215a 100644 --- a/application/xmake.lua +++ b/application/xmake.lua @@ -9,9 +9,6 @@ target("test_frontend") set_kind("binary") add_deps("frontend") - add_files("main.cpp") - add_linkdirs("E:\\CProj\\ImplicitSurfaceNetwork\\build\\windows\\x64\\debug") - after_build(function(target) - print("Hello, xmake!") - end) + add_files("basic_test.cpp") + -- add_files("main.cpp") target_end() \ No newline at end of file diff --git a/blobtree_structure/src/blobtree.cpp b/blobtree_structure/src/blobtree.cpp index a5cd138..ede0fa8 100644 --- a/blobtree_structure/src/blobtree.cpp +++ b/blobtree_structure/src/blobtree.cpp @@ -83,11 +83,7 @@ BS_API void clear_blobtree() noexcept virtual_node_t push_primitive_node(primitive_node_t&& primitive_node) { - primitives.emplace_back(primitive_node); - primitive_node.desc = - nullptr; // NOTE: primitives.back().desc and primitive_node.desc share same memory, so when this - // function returns, primitive_node.desc will be invalidated, so as primitives.back().desc, which outputs - // errors. Thus, we manually set primitive_node.desc to nullptr to avoid this problem. + primitives.emplace_back(std::move(primitive_node)); node_t node{standard_new_node}; node_fetch_primitive_index(node) = static_cast(primitives.size() - 1); @@ -286,45 +282,45 @@ void offset_primitive(primitive_node_t& node, const Eigen::Vector3d& offset) break; } case PRIMITIVE_TYPE_PLANE: { - auto desc = static_cast(node.desc); + auto desc = static_cast(node.data); offset_point(desc->point, offset); break; } case PRIMITIVE_TYPE_SPHERE: { - auto desc = static_cast(node.desc); + auto desc = static_cast(node.data); offset_point(desc->center, offset); break; } case PRIMITIVE_TYPE_CYLINDER: { - auto desc = static_cast(node.desc); + auto desc = static_cast(node.data); offset_point(desc->bottom_center, offset); break; } case PRIMITIVE_TYPE_CONE: { - auto desc = static_cast(node.desc); + auto desc = static_cast(node.data); offset_point(desc->top_center, offset); offset_point(desc->bottom_center, offset); break; } case PRIMITIVE_TYPE_BOX: { - auto desc = static_cast(node.desc); + auto desc = static_cast(node.data); offset_point(desc->center, offset); break; } case PRIMITIVE_TYPE_MESH: { - auto desc = static_cast(node.desc); + auto desc = static_cast(node.data); for (auto& v : desc->vertices) v += offset; break; } case PRIMITIVE_TYPE_EXTRUDE_POLYLINE: { - auto desc = static_cast(node.desc); + auto desc = static_cast(node.data); auto& matrix_handle = desc->axis_to_world.matrix(); matrix_handle.col(3) += offset; break; } case PRIMITIVE_TYPE_EXTRUDE_HELIXLINE: { - auto desc = static_cast(node.desc); + auto desc = static_cast(node.data); auto& matrix_handle = desc->axis_to_world.matrix(); matrix_handle.col(3) += offset; break; diff --git a/frontend/src/implicit_surface_network_processor.cpp b/frontend/src/implicit_surface_network_processor.cpp index d0f5a07..8b2a81c 100644 --- a/frontend/src/implicit_surface_network_processor.cpp +++ b/frontend/src/implicit_surface_network_processor.cpp @@ -74,8 +74,8 @@ solve_result_t ImplicitSurfaceNetworkProcessor::run(const virtual_node_t& tree_n // Eigen::Matrix scalar_field_signs(num_funcs, num_vert); auto scalar_field_sign = [](double x) -> int8_t { return (x < 0) ? 1 : ((x > 0) ? -1 : 0); }; stl_vector_mp> vertex_scalar_values(num_vert, stl_vector_mp(num_funcs)); - stl_vector_mp is_positive_scalar_field_sign(num_funcs * num_vert, false); - stl_vector_mp is_negative_scalar_field_sign(num_funcs * num_vert, false); + stl_vector_mp> is_positive_scalar_field_sign(num_vert, stl_vector_mp(num_funcs)); + stl_vector_mp> is_negative_scalar_field_sign(num_vert, stl_vector_mp(num_funcs)); stl_vector_mp is_degenerate_vertex(num_vert, false); bool has_degenerate_vertex{}; { @@ -84,14 +84,14 @@ solve_result_t ImplicitSurfaceNetworkProcessor::run(const virtual_node_t& tree_n const auto& point = background_vertices[i]; for (uint32_t j = 0; j < num_funcs; ++j) { vertex_scalar_values[i][j] = evaluate_sdf(j, point); - const auto sign = scalar_field_sign(vertex_scalar_values[i][j]); + const auto sign = scalar_field_sign(vertex_scalar_values[i][j]); switch (sign) { - case -1: is_negative_scalar_field_sign[i * num_funcs + j] = true; break; + case -1: is_negative_scalar_field_sign[i][j] = true; break; case 0: is_degenerate_vertex[i] = true; has_degenerate_vertex = true; break; - case 1: is_positive_scalar_field_sign[i * num_funcs + j] = true; break; + case 1: is_positive_scalar_field_sign[i][j] = true; break; default: break; } } @@ -113,8 +113,9 @@ solve_result_t ImplicitSurfaceNetworkProcessor::run(const virtual_node_t& tree_n for (Eigen::Index j = 0; j < num_funcs; ++j) { uint32_t pos_count{}, neg_count{}; for (uint32_t k = 0; k < 4; ++k) { - if (is_positive_scalar_field_sign[background_indices[i][k] * num_funcs + j]) pos_count++; - if (is_negative_scalar_field_sign[background_indices[i][k] * num_funcs + j]) neg_count++; + const auto& vertex_index = background_indices[i][k]; + if (is_positive_scalar_field_sign[vertex_index][j]) pos_count++; + if (is_negative_scalar_field_sign[vertex_index][j]) neg_count++; } // if (scalar_field_signs(j, tet_ptr[k]) == 1) pos_count++; // tets[i].size() == 4, this means that the function is active in this tet diff --git a/primitive_process/interface/internal_primitive_desc.hpp b/primitive_process/interface/internal_primitive_desc.hpp index ab75cea..68c7959 100644 --- a/primitive_process/interface/internal_primitive_desc.hpp +++ b/primitive_process/interface/internal_primitive_desc.hpp @@ -51,15 +51,24 @@ using legal_primitive_descriptor_t = std::variant; +// EDIT: safe memory block with basic RTTI support, behave like std::unique_ptr struct PE_API primitive_node_t { aabb_t<> aabb{}; - void* desc{nullptr}; // Type conversion when using + void* data{nullptr}; primitive_type type{}; primitive_node_t(const legal_primitive_descriptor_t&) noexcept; primitive_node_t(legal_primitive_descriptor_t&&) noexcept; + primitive_node_t(primitive_node_t&&) noexcept; ~primitive_node_t() noexcept; + primitive_node_t(const primitive_node_t&) = delete; + primitive_node_t& operator=(const primitive_node_t&) = delete; + + primitive_node_t& operator=(primitive_node_t&& other) noexcept; + + void swap(primitive_node_t& other) noexcept; + double evaluate_sdf([[maybe_unused]] const Eigen::Ref&) const; Eigen::Vector3d evaluate_cpm([[maybe_unused]] const Eigen::Ref&) const; }; diff --git a/primitive_process/src/primitive_node.cpp b/primitive_process/src/primitive_node.cpp index 0bd3ff9..4418bd9 100644 --- a/primitive_process/src/primitive_node.cpp +++ b/primitive_process/src/primitive_node.cpp @@ -61,14 +61,38 @@ struct primitive_descriptor_meta { // =========================================================================== +static inline void free_data_block(void *ptr, primitive_type type) noexcept +{ + if (ptr == nullptr) return; + +#define PRIM_DTOR(prim_type, internal_prim_type) \ + case prim_type: static_cast(ptr)->~internal_prim_type(); break + + switch (type) { + PRIM_DTOR(PRIMITIVE_TYPE_CONSTANT, constant); + PRIM_DTOR(PRIMITIVE_TYPE_PLANE, plane); + PRIM_DTOR(PRIMITIVE_TYPE_SPHERE, sphere); + PRIM_DTOR(PRIMITIVE_TYPE_CYLINDER, cylinder); + PRIM_DTOR(PRIMITIVE_TYPE_CONE, cone); + PRIM_DTOR(PRIMITIVE_TYPE_BOX, box); + PRIM_DTOR(PRIMITIVE_TYPE_MESH, mesh); + PRIM_DTOR(PRIMITIVE_TYPE_EXTRUDE_POLYLINE, extrude_polyline); + PRIM_DTOR(PRIMITIVE_TYPE_EXTRUDE_HELIXLINE, extrude_helixline); + } + +#undef PRIM_DTOR + + ::free(ptr); +} + primitive_node_t::primitive_node_t(const legal_primitive_descriptor_t &descriptor) noexcept { std::visit( [this](auto &&desc) -> void { using T = std::decay_t; using internal_type = typename primitive_descriptor_meta::internal_type; - this->desc = ::malloc(sizeof(internal_type)); - auto handle = new (this->desc) internal_type(desc, this->aabb); + this->data = ::malloc(sizeof(internal_type)); + auto handle = new (this->data) internal_type(desc, this->aabb); this->type = primitive_descriptor_meta::type; }, descriptor); @@ -80,59 +104,82 @@ primitive_node_t::primitive_node_t(legal_primitive_descriptor_t &&descriptor) no [this](auto &&desc) { using T = std::decay_t; using internal_type = typename primitive_descriptor_meta::internal_type; - this->desc = ::malloc(sizeof(internal_type)); - auto handle = new (this->desc) internal_type(std::move(desc), this->aabb); + this->data = ::malloc(sizeof(internal_type)); + auto handle = new (this->data) internal_type(std::move(desc), this->aabb); this->type = primitive_descriptor_meta::type; }, std::move(descriptor)); } -primitive_node_t::~primitive_node_t() noexcept +primitive_node_t::primitive_node_t(primitive_node_t &&other) noexcept + : aabb(std::move(other.aabb)), data(other.data), type(other.type) { - if (this->desc == nullptr) return; - - if (this->type == PRIMITIVE_TYPE_MESH) - static_cast(this->desc)->~mesh(); - else if (this->type == PRIMITIVE_TYPE_EXTRUDE_POLYLINE) - static_cast(this->desc)->~extrude_polyline(); - else if (this->type == PRIMITIVE_TYPE_EXTRUDE_HELIXLINE) - static_cast(this->desc)->~extrude_helixline(); - ::free(this->desc); - this->desc = nullptr; + other.data = nullptr; +} + +primitive_node_t::~primitive_node_t() noexcept { free_data_block(this->data, this->type); } + +primitive_node_t &primitive_node_t::operator=(primitive_node_t &&other) noexcept +{ + auto old_ptr = std::exchange(this->data, other.data); + free_data_block(old_ptr, type); + this->type = other.type; + + other.data = nullptr; + + return *this; +} + +void primitive_node_t::swap(primitive_node_t &other) noexcept +{ + using std::swap; + swap(this->aabb, other.aabb); + swap(this->data, other.data); + swap(this->type, other.type); } double primitive_node_t::evaluate_sdf([[maybe_unused]] const Eigen::Ref &point) const { + assert(this->data); + +#define PRIM_EVAL_SDF(prim_type, internal_prim_type) \ + case prim_type: return static_cast(this->data)->evaluate_sdf(point) + switch (this->type) { - case PRIMITIVE_TYPE_CONSTANT: return static_cast(this->desc)->evaluate_sdf(point); - case PRIMITIVE_TYPE_PLANE: return static_cast(this->desc)->evaluate_sdf(point); - case PRIMITIVE_TYPE_SPHERE: return static_cast(this->desc)->evaluate_sdf(point); - case PRIMITIVE_TYPE_CYLINDER: return static_cast(this->desc)->evaluate_sdf(point); - case PRIMITIVE_TYPE_CONE: return static_cast(this->desc)->evaluate_sdf(point); - case PRIMITIVE_TYPE_BOX: return static_cast(this->desc)->evaluate_sdf(point); - case PRIMITIVE_TYPE_MESH: return static_cast(this->desc)->evaluate_sdf(point); - case PRIMITIVE_TYPE_EXTRUDE_POLYLINE: - return static_cast(this->desc)->evaluate_sdf(point); - case PRIMITIVE_TYPE_EXTRUDE_HELIXLINE: - return static_cast(this->desc)->evaluate_sdf(point); + PRIM_EVAL_SDF(PRIMITIVE_TYPE_CONSTANT, constant); + PRIM_EVAL_SDF(PRIMITIVE_TYPE_PLANE, plane); + PRIM_EVAL_SDF(PRIMITIVE_TYPE_SPHERE, sphere); + PRIM_EVAL_SDF(PRIMITIVE_TYPE_CYLINDER, cylinder); + PRIM_EVAL_SDF(PRIMITIVE_TYPE_CONE, cone); + PRIM_EVAL_SDF(PRIMITIVE_TYPE_BOX, box); + PRIM_EVAL_SDF(PRIMITIVE_TYPE_MESH, mesh); + PRIM_EVAL_SDF(PRIMITIVE_TYPE_EXTRUDE_POLYLINE, extrude_polyline); + PRIM_EVAL_SDF(PRIMITIVE_TYPE_EXTRUDE_HELIXLINE, extrude_helixline); default: throw std::runtime_error("Invalid primitive type"); } + +#undef PRIM_EVAL_SDF } Eigen::Vector3d primitive_node_t::evaluate_cpm([[maybe_unused]] const Eigen::Ref &point) const { + assert(this->data); + +#define PRIM_EVAL_CPM(prim_type, internal_prim_type) \ + case prim_type: return static_cast(this->data)->evaluate_cpm(point) + switch (this->type) { - case PRIMITIVE_TYPE_CONSTANT: return static_cast(this->desc)->evaluate_cpm(point); - case PRIMITIVE_TYPE_PLANE: return static_cast(this->desc)->evaluate_cpm(point); - case PRIMITIVE_TYPE_SPHERE: return static_cast(this->desc)->evaluate_cpm(point); - case PRIMITIVE_TYPE_CYLINDER: return static_cast(this->desc)->evaluate_cpm(point); - case PRIMITIVE_TYPE_CONE: return static_cast(this->desc)->evaluate_cpm(point); - case PRIMITIVE_TYPE_BOX: return static_cast(this->desc)->evaluate_cpm(point); - case PRIMITIVE_TYPE_MESH: return static_cast(this->desc)->evaluate_cpm(point); - case PRIMITIVE_TYPE_EXTRUDE_POLYLINE: - return static_cast(this->desc)->evaluate_cpm(point); - case PRIMITIVE_TYPE_EXTRUDE_HELIXLINE: - return static_cast(this->desc)->evaluate_cpm(point); + PRIM_EVAL_CPM(PRIMITIVE_TYPE_CONSTANT, constant); + PRIM_EVAL_CPM(PRIMITIVE_TYPE_PLANE, plane); + PRIM_EVAL_CPM(PRIMITIVE_TYPE_SPHERE, sphere); + PRIM_EVAL_CPM(PRIMITIVE_TYPE_CYLINDER, cylinder); + PRIM_EVAL_CPM(PRIMITIVE_TYPE_CONE, cone); + PRIM_EVAL_CPM(PRIMITIVE_TYPE_BOX, box); + PRIM_EVAL_CPM(PRIMITIVE_TYPE_MESH, mesh); + PRIM_EVAL_CPM(PRIMITIVE_TYPE_EXTRUDE_POLYLINE, extrude_polyline); + PRIM_EVAL_CPM(PRIMITIVE_TYPE_EXTRUDE_HELIXLINE, extrude_helixline); default: throw std::runtime_error("Invalid primitive type"); } + +#undef PRIM_EVAL_CPM } \ No newline at end of file