feat(v3.9): parallel OpenMP boolean + assembly instancing + update notifier
This commit is contained in:
@@ -158,6 +158,7 @@ add_library(vde_brep STATIC
|
||||
brep/assembly_constraints.cpp
|
||||
brep/measure.cpp
|
||||
brep/trimmed_surface.cpp
|
||||
brep/assembly_instance.cpp
|
||||
)
|
||||
target_include_directories(vde_brep
|
||||
PUBLIC ${CMAKE_SOURCE_DIR}/include
|
||||
@@ -219,3 +220,15 @@ if(VDE_USE_GMP)
|
||||
else()
|
||||
message(STATUS "GMP disabled (-DVDE_USE_GMP=ON to enable)")
|
||||
endif()
|
||||
|
||||
# ── OpenMP parallelization ──
|
||||
if(VDE_USE_OPENMP)
|
||||
find_package(OpenMP)
|
||||
if(OpenMP_CXX_FOUND)
|
||||
target_link_libraries(vde_brep PUBLIC OpenMP::OpenMP_CXX)
|
||||
target_compile_definitions(vde_brep PUBLIC VDE_USE_OPENMP)
|
||||
message(STATUS "OpenMP enabled")
|
||||
else()
|
||||
message(STATUS "OpenMP not found (parallelism disabled)")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
#include "vde/brep/assembly_instance.h"
|
||||
|
||||
namespace vde::brep {
|
||||
|
||||
int AssemblyInstancer::register_instance(const std::string& name, const BrepModel& geom) {
|
||||
// Check for existing match: same name + similar bounding box
|
||||
for (size_t i = 0; i < instances_.size(); ++i) {
|
||||
if (instances_[i].part_name == name) {
|
||||
auto bb1 = instances_[i].geometry.bounds();
|
||||
auto bb2 = geom.bounds();
|
||||
if ((bb1.min() - bb2.min()).norm() < 1e-3) {
|
||||
instances_[i].use_count++;
|
||||
return static_cast<int>(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
instances_.push_back({name, geom, 1});
|
||||
return static_cast<int>(instances_.size() - 1);
|
||||
}
|
||||
|
||||
void AssemblyInstancer::place_instance(Assembly& assy, AssemblyNode* parent,
|
||||
int instance_id, const Transform3D& transform) {
|
||||
if (instance_id < 0 || instance_id >= static_cast<int>(instances_.size())) return;
|
||||
auto& inst = instances_[instance_id];
|
||||
if (parent) {
|
||||
parent->add_part(inst.part_name, inst.geometry, transform);
|
||||
} else {
|
||||
assy.root.add_part(inst.part_name, inst.geometry, transform);
|
||||
}
|
||||
total_placed_++;
|
||||
}
|
||||
|
||||
} // namespace vde::brep
|
||||
@@ -11,6 +11,11 @@
|
||||
#include <unordered_map>
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
#include <mutex>
|
||||
|
||||
#ifdef VDE_USE_OPENMP
|
||||
#include <omp.h>
|
||||
#endif
|
||||
|
||||
namespace vde::brep {
|
||||
|
||||
@@ -562,8 +567,12 @@ BrepModel brep_union(const BrepModel& a, const BrepModel& b) {
|
||||
// then classify fragments. Keep OUT and ON (from A).
|
||||
// For each face of B: same against A, keep only OUT.
|
||||
std::vector<BrepModel> keep;
|
||||
std::mutex keep_mutex;
|
||||
|
||||
// A faces: SSI-split against B, classify, keep OUT/ON
|
||||
#ifdef VDE_USE_OPENMP
|
||||
#pragma omp parallel for schedule(dynamic)
|
||||
#endif
|
||||
for (size_t fia = 0; fia < a.num_faces(); ++fia) {
|
||||
std::vector<BrepModel> fragments;
|
||||
fragments.push_back(extract_face_fragment(a, static_cast<int>(fia)));
|
||||
@@ -589,11 +598,17 @@ BrepModel brep_union(const BrepModel& a, const BrepModel& b) {
|
||||
// Classify each fragment against B
|
||||
for (auto& frag : fragments) {
|
||||
auto cls = classify_face_fragment(frag, b);
|
||||
if (cls == OUT || cls == ON) keep.push_back(std::move(frag));
|
||||
if (cls == OUT || cls == ON) {
|
||||
std::lock_guard<std::mutex> lock(keep_mutex);
|
||||
keep.push_back(std::move(frag));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// B faces: SSI-split against A, classify, keep OUT only (ON from A already)
|
||||
#ifdef VDE_USE_OPENMP
|
||||
#pragma omp parallel for schedule(dynamic)
|
||||
#endif
|
||||
for (size_t fib = 0; fib < b.num_faces(); ++fib) {
|
||||
std::vector<BrepModel> fragments;
|
||||
fragments.push_back(extract_face_fragment(b, static_cast<int>(fib)));
|
||||
@@ -615,7 +630,10 @@ BrepModel brep_union(const BrepModel& a, const BrepModel& b) {
|
||||
|
||||
for (auto& frag : fragments) {
|
||||
auto cls = classify_face_fragment(frag, a);
|
||||
if (cls == OUT) keep.push_back(std::move(frag));
|
||||
if (cls == OUT) {
|
||||
std::lock_guard<std::mutex> lock(keep_mutex);
|
||||
keep.push_back(std::move(frag));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -634,8 +652,12 @@ BrepModel brep_intersection(const BrepModel& a, const BrepModel& b) {
|
||||
// For intersection: keep fragments IN the other body,
|
||||
// and fragments ON the boundary (only from A to avoid duplicates).
|
||||
std::vector<BrepModel> keep;
|
||||
std::mutex keep_mutex;
|
||||
|
||||
// A faces: SSI-split against B, classify, keep IN/ON
|
||||
#ifdef VDE_USE_OPENMP
|
||||
#pragma omp parallel for schedule(dynamic)
|
||||
#endif
|
||||
for (size_t fia = 0; fia < a.num_faces(); ++fia) {
|
||||
std::vector<BrepModel> fragments;
|
||||
fragments.push_back(extract_face_fragment(a, static_cast<int>(fia)));
|
||||
@@ -657,11 +679,17 @@ BrepModel brep_intersection(const BrepModel& a, const BrepModel& b) {
|
||||
|
||||
for (auto& frag : fragments) {
|
||||
auto cls = classify_face_fragment(frag, b);
|
||||
if (cls == IN || cls == ON) keep.push_back(std::move(frag));
|
||||
if (cls == IN || cls == ON) {
|
||||
std::lock_guard<std::mutex> lock(keep_mutex);
|
||||
keep.push_back(std::move(frag));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// B faces: SSI-split against A, classify, keep IN only
|
||||
#ifdef VDE_USE_OPENMP
|
||||
#pragma omp parallel for schedule(dynamic)
|
||||
#endif
|
||||
for (size_t fib = 0; fib < b.num_faces(); ++fib) {
|
||||
std::vector<BrepModel> fragments;
|
||||
fragments.push_back(extract_face_fragment(b, static_cast<int>(fib)));
|
||||
@@ -683,7 +711,10 @@ BrepModel brep_intersection(const BrepModel& a, const BrepModel& b) {
|
||||
|
||||
for (auto& frag : fragments) {
|
||||
auto cls = classify_face_fragment(frag, a);
|
||||
if (cls == IN) keep.push_back(std::move(frag));
|
||||
if (cls == IN) {
|
||||
std::lock_guard<std::mutex> lock(keep_mutex);
|
||||
keep.push_back(std::move(frag));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -704,8 +735,12 @@ BrepModel brep_difference(const BrepModel& a, const BrepModel& b) {
|
||||
// - Keep A fragments that are OUT of B (discard IN and ON)
|
||||
// - Keep B fragments that are IN A (forms the inner cut surface)
|
||||
std::vector<BrepModel> keep;
|
||||
std::mutex keep_mutex;
|
||||
|
||||
// A faces: SSI-split against B, classify, keep OUT
|
||||
#ifdef VDE_USE_OPENMP
|
||||
#pragma omp parallel for schedule(dynamic)
|
||||
#endif
|
||||
for (size_t fia = 0; fia < a.num_faces(); ++fia) {
|
||||
std::vector<BrepModel> fragments;
|
||||
fragments.push_back(extract_face_fragment(a, static_cast<int>(fia)));
|
||||
@@ -727,11 +762,17 @@ BrepModel brep_difference(const BrepModel& a, const BrepModel& b) {
|
||||
|
||||
for (auto& frag : fragments) {
|
||||
auto cls = classify_face_fragment(frag, b);
|
||||
if (cls == OUT) keep.push_back(std::move(frag));
|
||||
if (cls == OUT) {
|
||||
std::lock_guard<std::mutex> lock(keep_mutex);
|
||||
keep.push_back(std::move(frag));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// B faces: SSI-split against A, classify, keep IN (forms inner cut surface)
|
||||
#ifdef VDE_USE_OPENMP
|
||||
#pragma omp parallel for schedule(dynamic)
|
||||
#endif
|
||||
for (size_t fib = 0; fib < b.num_faces(); ++fib) {
|
||||
std::vector<BrepModel> fragments;
|
||||
fragments.push_back(extract_face_fragment(b, static_cast<int>(fib)));
|
||||
@@ -753,7 +794,10 @@ BrepModel brep_difference(const BrepModel& a, const BrepModel& b) {
|
||||
|
||||
for (auto& frag : fragments) {
|
||||
auto cls = classify_face_fragment(frag, a);
|
||||
if (cls == IN) keep.push_back(std::move(frag));
|
||||
if (cls == IN) {
|
||||
std::lock_guard<std::mutex> lock(keep_mutex);
|
||||
keep.push_back(std::move(frag));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user