OcctNoCleanTriangulation CacheShapes PermissiveShapeReuse setting; Cgal conditional copy during triangulation; occt cheaper check for triangulation existance #6712

This commit is contained in:
Thomas Krijnen
2025-05-18 22:14:22 +02:00
parent 404bf13a18
commit 439f9c14ce
8 changed files with 161 additions and 32 deletions
@@ -47,8 +47,6 @@ namespace {
};
bool are_facets_coplanar(const Facet_const_handle& f1, const Facet_const_handle& f2) {
// Function to determine if two facets are coplanar
// You can use the normal vectors and the equation of the planes to determine coplanarity
auto normal_1 = CGAL::normal(f1->halfedge()->vertex()->point(),
f1->halfedge()->next()->vertex()->point(),
f1->halfedge()->next()->next()->vertex()->point());
@@ -69,8 +67,8 @@ namespace {
continue;
}
// Create a new component for coplanar facets
std::set<Facet_const_handle> component;
components.emplace_back();
auto& component = components.back();
std::queue<Facet_const_handle> queue;
queue.push(face);
@@ -82,18 +80,15 @@ namespace {
component.insert(current);
// Iterate over neighboring facets
Halfedge_around_facet_circulator he = current->facet_begin();
do {
Facet_const_handle neighbour = he->opposite()->face();
if (neighbour != nullptr && visited.find(neighbour) == visited.end() && are_facets_coplanar(current, neighbour)) {
if (visited.find(neighbour) == visited.end() && neighbour != nullptr && visited.find(neighbour) == visited.end() && are_facets_coplanar(current, neighbour)) {
queue.push(neighbour);
visited.insert(neighbour);
}
} while (++he != current->facet_begin());
}
components.push_back(component);
}
}
}
@@ -184,20 +179,30 @@ void ifcopenshell::geometry::CgalShape::to_nef() const {
#endif
void ifcopenshell::geometry::CgalShape::Triangulate(ifcopenshell::geometry::Settings settings, const ifcopenshell::geometry::taxonomy::matrix4& place, IfcGeom::Representation::Triangulation* t, int item_id, int surface_style_id) const {
// Copy is made because triangulate_faces() obviously does not accept a const argument
// ... also becuase of transforming the vertex positions, right?
cgal_shape_t s = *this;
const bool all_triangles = std::all_of(shape_->facets_begin(), shape_->facets_end(), [](auto f) { return f.is_triangle(); });
const bool has_iden_transform = place.is_identity();
std::unique_ptr<cgal_shape_t> shape_copy_holder;
cgal_shape_t* shape_to_use;
if (!all_triangles || !has_iden_transform) {
// A copy is made when triangulate_faces() is required or when vertex positions need be transformed
shape_copy_holder.reset(new cgal_shape_t(*this));
shape_to_use = shape_copy_holder.get();
} else {
shape_to_use = &*shape_;
}
const bool setting_use_original_edges = settings.get<ifcopenshell::geometry::settings::CgalEmitOriginalEdges>().get();
std::set<std::set<Kernel_::Point_3>> original_edges;
if (setting_use_original_edges) {
for (auto it = s.edges_begin(); it != s.edges_end(); ++it) {
for (auto it = shape_to_use->edges_begin(); it != shape_to_use->edges_end(); ++it) {
original_edges.insert({ it->vertex()->point(), it->prev()->vertex()->point() });
}
}
if (!place.is_identity()) {
if (!has_iden_transform) {
const auto& m = place.ccomponents();
// @todo check
@@ -207,33 +212,33 @@ void ifcopenshell::geometry::CgalShape::Triangulate(ifcopenshell::geometry::Sett
m(2, 0), m(2, 1), m(2, 2), m(2, 3));
// Apply transformation
for (auto &vertex : s.vertex_handles()) {
for (auto &vertex : shape_to_use->vertex_handles()) {
vertex->point() = vertex->point().transform(trsf);
}
}
if (!std::all_of(s.facets_begin(), s.facets_end(), [](auto f) { return f.is_triangle(); })) {
if (!s.is_valid()) {
if (!all_triangles) {
if (!shape_to_use->is_valid()) {
Logger::Message(Logger::LOG_ERROR, "Invalid Polyhedron_3 in object (before triangulation)");
return;
}
bool success = false;
try {
success = CGAL::Polygon_mesh_processing::triangulate_faces(s);
success = CGAL::Polygon_mesh_processing::triangulate_faces(*shape_to_use);
} catch (...) {
Logger::Message(Logger::LOG_ERROR, "Triangulation crashed");
return;
}
CGAL::Polygon_mesh_processing::remove_degenerate_faces(s);
CGAL::Polygon_mesh_processing::remove_degenerate_faces(*shape_to_use);
if (!success) {
Logger::Message(Logger::LOG_ERROR, "Triangulation failed");
return;
}
if (!s.is_valid()) {
if (!shape_to_use->is_valid()) {
Logger::Message(Logger::LOG_ERROR, "Invalid Polyhedron_3 in object (after triangulation)");
// return;
}
@@ -244,7 +249,7 @@ void ifcopenshell::geometry::CgalShape::Triangulate(ifcopenshell::geometry::Sett
std::vector<std::set<Facet_const_handle>> components;
std::map<Facet_const_handle, typename decltype(components)::const_iterator> facet_to_component;
if (!setting_use_original_edges) {
partition_coplanar_components(s, components);
partition_coplanar_components(*shape_to_use, components);
for (auto it = components.begin(); it != components.end(); ++it) {
for (auto& f : *it) {
facet_to_component[f] = it;
@@ -261,7 +266,7 @@ void ifcopenshell::geometry::CgalShape::Triangulate(ifcopenshell::geometry::Sett
// CGAL::Polygon_mesh_processing::compute_normals(s, vertex_normals_map, face_normals_map);
try {
CGAL::Polygon_mesh_processing::compute_face_normals(s, face_normals_map);
CGAL::Polygon_mesh_processing::compute_face_normals(*shape_to_use, face_normals_map);
} catch (...) {
Logger::Message(Logger::LOG_ERROR, "Face normal calculation failed");
return;
@@ -275,7 +280,7 @@ void ifcopenshell::geometry::CgalShape::Triangulate(ifcopenshell::geometry::Sett
std::set<std::pair<int, int>> registered_edges;
int num_faces = 0, num_vertices = 0;
for (auto &face : faces(s)) {
for (auto &face : faces(*shape_to_use)) {
if (!face->is_triangle()) {
std::cout << "Warning: non-triangular face!" << std::endl;
continue;