diff --git a/sandboxes/opencsg/Engine.cpp b/sandboxes/opencsg/Engine.cpp index f110b23c5..53e340294 100644 --- a/sandboxes/opencsg/Engine.cpp +++ b/sandboxes/opencsg/Engine.cpp @@ -145,7 +145,7 @@ void IndexedVertexArray::load_mesh(const TriangleMesh &mesh) this->vertices_and_normals_interleaved.reserve(this->vertices_and_normals_interleaved.size() + 3 * 3 * 2 * mesh.facets_count()); int vertices_count = 0; - for (size_t i = 0; i < mesh.stl.stats.number_of_facets; ++i) { + for (size_t i = 0; i < mesh.facets_count(); ++i) { const stl_facet &facet = mesh.stl.facet_start[i]; for (int j = 0; j < 3; ++j) this->push_geometry(facet.vertex[j](0), facet.vertex[j](1), facet.vertex[j](2), facet.normal(0), facet.normal(1), facet.normal(2)); diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index f9bef903b..d42077b9c 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -78,8 +78,6 @@ add_library(libslic3r STATIC Format/OBJ.hpp Format/objparser.cpp Format/objparser.hpp - Format/PRUS.cpp - Format/PRUS.hpp Format/STL.cpp Format/STL.hpp Format/SL1.hpp diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index fb6ab5635..8d7b9ccad 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -9,7 +9,6 @@ #include "Format/AMF.hpp" #include "Format/OBJ.hpp" -#include "Format/PRUS.hpp" #include "Format/STL.hpp" #include "Format/3mf.hpp" @@ -118,8 +117,6 @@ Model Model::read_from_file(const std::string& input_file, DynamicPrintConfig* c else if (boost::algorithm::iends_with(input_file, ".3mf")) //FIXME options & LoadAttribute::CheckVersion ? result = load_3mf(input_file.c_str(), *config, *config_substitutions, &model, false); - else if (boost::algorithm::iends_with(input_file, ".prusa")) - result = load_prus(input_file.c_str(), &model); else throw Slic3r::RuntimeError("Unknown file format. Input file must have .stl, .obj, .amf(.xml) or .prusa extension."); @@ -1154,7 +1151,7 @@ size_t ModelObject::facets_count() const size_t num = 0; for (const ModelVolume *v : this->volumes) if (v->is_model_part()) - num += v->mesh().stl.stats.number_of_facets; + num += v->mesh().facets_count(); return num; } @@ -1508,9 +1505,9 @@ double ModelObject::get_instance_min_z(size_t instance_idx) const const Transform3d mv = mi * v->get_matrix(); const TriangleMesh& hull = v->get_convex_hull(); - for (const stl_facet &facet : hull.stl.facet_start) + for (const stl_triangle_vertex_indices facet : hull.its.indices) for (int i = 0; i < 3; ++ i) - min_z = std::min(min_z, (mv * facet.vertex[i].cast()).z()); + min_z = std::min(min_z, (mv * hull.its.vertices[facet[i]].cast()).z()); } return min_z + inst->get_offset(Z); @@ -1529,9 +1526,9 @@ double ModelObject::get_instance_max_z(size_t instance_idx) const const Transform3d mv = mi * v->get_matrix(); const TriangleMesh& hull = v->get_convex_hull(); - for (const stl_facet& facet : hull.stl.facet_start) + for (const stl_triangle_vertex_indices facet : hull.its.indices) for (int i = 0; i < 3; ++i) - max_z = std::max(max_z, (mv * facet.vertex[i].cast()).z()); + max_z = std::max(max_z, (mv * hull.its.vertices[facet[i]].cast()).z()); } return max_z + inst->get_offset(Z); @@ -1584,27 +1581,27 @@ void ModelObject::print_info() const cout << "max_x = " << bb.max(0) << endl; cout << "max_y = " << bb.max(1) << endl; cout << "max_z = " << bb.max(2) << endl; - cout << "number_of_facets = " << mesh.stl.stats.number_of_facets << endl; + cout << "number_of_facets = " << mesh.facets_count() << endl; cout << "manifold = " << (mesh.is_manifold() ? "yes" : "no") << endl; mesh.repair(); // this calculates number_of_parts if (mesh.needed_repair()) { mesh.repair(); - if (mesh.stl.stats.degenerate_facets > 0) - cout << "degenerate_facets = " << mesh.stl.stats.degenerate_facets << endl; - if (mesh.stl.stats.edges_fixed > 0) - cout << "edges_fixed = " << mesh.stl.stats.edges_fixed << endl; - if (mesh.stl.stats.facets_removed > 0) - cout << "facets_removed = " << mesh.stl.stats.facets_removed << endl; - if (mesh.stl.stats.facets_added > 0) - cout << "facets_added = " << mesh.stl.stats.facets_added << endl; - if (mesh.stl.stats.facets_reversed > 0) - cout << "facets_reversed = " << mesh.stl.stats.facets_reversed << endl; - if (mesh.stl.stats.backwards_edges > 0) - cout << "backwards_edges = " << mesh.stl.stats.backwards_edges << endl; + if (mesh.stats().degenerate_facets > 0) + cout << "degenerate_facets = " << mesh.stats().degenerate_facets << endl; + if (mesh.stats().edges_fixed > 0) + cout << "edges_fixed = " << mesh.stats().edges_fixed << endl; + if (mesh.stats().facets_removed > 0) + cout << "facets_removed = " << mesh.stats().facets_removed << endl; + if (mesh.stats().facets_added > 0) + cout << "facets_added = " << mesh.stats().facets_added << endl; + if (mesh.stats().facets_reversed > 0) + cout << "facets_reversed = " << mesh.stats().facets_reversed << endl; + if (mesh.stats().backwards_edges > 0) + cout << "backwards_edges = " << mesh.stats().backwards_edges << endl; } - cout << "number_of_parts = " << mesh.stl.stats.number_of_parts << endl; - cout << "volume = " << mesh.volume() << endl; + cout << "number_of_parts = " << mesh.stats().number_of_parts << endl; + cout << "volume = " << mesh.volume() << endl; } std::string ModelObject::get_export_filename() const @@ -1630,7 +1627,7 @@ std::string ModelObject::get_export_filename() const stl_stats ModelObject::get_object_stl_stats() const { if (this->volumes.size() == 1) - return this->volumes[0]->mesh().stl.stats; + return this->volumes[0]->mesh().stats(); stl_stats full_stats; full_stats.volume = 0.f; @@ -1638,7 +1635,7 @@ stl_stats ModelObject::get_object_stl_stats() const // fill full_stats from all objet's meshes for (ModelVolume* volume : this->volumes) { - const stl_stats& stats = volume->mesh().stl.stats; + const stl_stats& stats = volume->mesh().stats(); // initialize full_stats (for repaired errors) full_stats.degenerate_facets += stats.degenerate_facets; @@ -1734,7 +1731,7 @@ void ModelVolume::calculate_convex_hull() int ModelVolume::get_mesh_errors_count() const { - const stl_stats& stats = this->mesh().stl.stats; + const stl_stats &stats = this->mesh().stats(); return stats.degenerate_facets + stats.edges_fixed + stats.facets_removed + stats.facets_added + stats.facets_reversed + stats.backwards_edges; diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index ba3156139..07274d352 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -774,7 +774,7 @@ private: assert(this->id() != this->supported_facets.id()); assert(this->id() != this->seam_facets.id()); assert(this->id() != this->mmu_segmentation_facets.id()); - if (mesh.stl.stats.number_of_facets > 1) + if (mesh.facets_count() > 1) calculate_convex_hull(); } ModelVolume(ModelObject *object, TriangleMesh &&mesh, TriangleMesh &&convex_hull, ModelVolumeType type = ModelVolumeType::MODEL_PART) : @@ -830,7 +830,7 @@ private: assert(this->config.id() == other.config.id()); this->set_material_id(other.material_id()); this->config.set_new_unique_id(); - if (mesh.stl.stats.number_of_facets > 1) + if (mesh.facets_count() > 1) calculate_convex_hull(); assert(this->config.id().valid()); assert(this->config.id() != other.config.id()); diff --git a/src/libslic3r/PrintObjectSlice.cpp b/src/libslic3r/PrintObjectSlice.cpp index 1d61be85b..7db0de626 100644 --- a/src/libslic3r/PrintObjectSlice.cpp +++ b/src/libslic3r/PrintObjectSlice.cpp @@ -39,23 +39,6 @@ LayerPtrs new_layers( return out; } -//FIXME The admesh repair function may break the face connectivity, rather refresh it here as the slicing code relies on it. -// This function will go away once we get rid of admesh from ModelVolume. -static indexed_triangle_set get_mesh_its_fix_mesh_connectivity(TriangleMesh mesh) -{ - assert(mesh.repaired && mesh.has_shared_vertices()); - if (mesh.stl.stats.number_of_facets > 0) { - assert(mesh.repaired && mesh.has_shared_vertices()); - auto nr_degenerated = mesh.stl.stats.degenerate_facets; - stl_check_facets_exact(&mesh.stl); - if (nr_degenerated != mesh.stl.stats.degenerate_facets) - // stl_check_facets_exact() removed some newly degenerated faces. Some faces could become degenerate after some mesh transformation. - stl_generate_shared_vertices(&mesh.stl, mesh.its); - } else - mesh.its.clear(); - return std::move(mesh.its); -} - // Slice single triangle mesh. static std::vector slice_volume( const ModelVolume &volume, @@ -65,7 +48,7 @@ static std::vector slice_volume( { std::vector layers; if (! zs.empty()) { - indexed_triangle_set its = get_mesh_its_fix_mesh_connectivity(volume.mesh()); + indexed_triangle_set its = volume.mesh().its; if (its.indices.size() > 0) { MeshSlicingParamsEx params2 { params }; params2.trafo = params2.trafo * volume.get_matrix(); diff --git a/src/libslic3r/SlicingAdaptive.cpp b/src/libslic3r/SlicingAdaptive.cpp index 9b9b48f88..77f41d7bf 100644 --- a/src/libslic3r/SlicingAdaptive.cpp +++ b/src/libslic3r/SlicingAdaptive.cpp @@ -35,13 +35,6 @@ legend("tan(a) as cura - topographic lines distance limit", "sqrt(tan(a)) as Pru namespace Slic3r { -static inline std::pair face_z_span(const stl_facet &f) -{ - return std::pair( - std::min(std::min(f.vertex[0](2), f.vertex[1](2)), f.vertex[2](2)), - std::max(std::max(f.vertex[0](2), f.vertex[1](2)), f.vertex[2](2))); -} - // By Florens Waserfall aka @platch: // This constant essentially describes the volumetric error at the surface which is induced // by stacking "elliptic" extrusion threads. It is empirically determined by @@ -88,10 +81,15 @@ void SlicingAdaptive::prepare(const ModelObject &object) mesh.transform(first_instance.get_matrix(), first_instance.is_left_handed()); // 1) Collect faces from mesh. - m_faces.reserve(mesh.stl.stats.number_of_facets); - for (const stl_facet &face : mesh.stl.facet_start) { - Vec3f n = face.normal.normalized(); - m_faces.emplace_back(FaceZ({ face_z_span(face), std::abs(n.z()), std::sqrt(n.x() * n.x() + n.y() * n.y()) })); + m_faces.reserve(mesh.facets_count()); + for (stl_triangle_vertex_indices face : mesh.its.indices) { + stl_vertex vertex[3] = { mesh.its.vertices[face[0]], mesh.its.vertices[face[1]], mesh.its.vertices[face[2]] }; + stl_vertex n = (vertex[2] - vertex[1]).cross(vertex[3] - vertex[2]).normalized(); + std::pair face_z_span { + std::min(std::min(vertex[0].z(), vertex[1].z()), vertex[2].z()), + std::max(std::max(vertex[0].z(), vertex[1].z()), vertex[2].z()) + }; + m_faces.emplace_back(FaceZ({ face_z_span, std::abs(n.z()), std::sqrt(n.x() * n.x() + n.y() * n.y()) })); } // 2) Sort faces lexicographically by their Z span. diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp index fa8f8bce6..ff8511090 100644 --- a/src/libslic3r/TriangleMesh.cpp +++ b/src/libslic3r/TriangleMesh.cpp @@ -187,6 +187,10 @@ void TriangleMesh::repair(bool update_shared_vertices) this->repaired = true; + //FIXME The admesh repair function may break the face connectivity, rather refresh it here as the slicing code relies on it. + if (auto nr_degenerated = this->stl.stats.degenerate_facets; this->facets_count() > 0 && nr_degenerated > 0) + stl_check_facets_exact(&this->stl); + BOOST_LOG_TRIVIAL(debug) << "TriangleMesh::repair() finished"; // This call should be quite cheap, a lot of code requires the indexed_triangle_set data structure, @@ -1335,4 +1339,15 @@ std::vector its_face_neighbors_par(const indexed_triangle_set &its) return create_face_neighbors_index(ex_tbb, its); } +std::vector its_face_normals(const indexed_triangle_set &its) +{ + std::vector normals; + normals.reserve(its.indices.size()); + for (stl_triangle_vertex_indices face : its.indices) { + stl_vertex vertex[3] = { its.vertices[face[0]], its.vertices[face[1]], its.vertices[face[2]] }; + normals.push_back((vertex[2] - vertex[1]).cross(vertex[3] - vertex[2]).normalized()); + } + return normals; +} + } // namespace Slic3r diff --git a/src/libslic3r/TriangleMesh.hpp b/src/libslic3r/TriangleMesh.hpp index c463af5a2..1a3d1fae0 100644 --- a/src/libslic3r/TriangleMesh.hpp +++ b/src/libslic3r/TriangleMesh.hpp @@ -52,7 +52,6 @@ public: TriangleMeshPtrs split() const; void merge(const TriangleMesh &mesh); ExPolygons horizontal_projection() const; - const float* first_vertex() const { return this->stl.facet_start.empty() ? nullptr : &this->stl.facet_start.front().vertex[0](0); } // 2D convex hull of a 3D mesh projected into the Z=0 plane. Polygon convex_hull(); BoundingBoxf3 bounding_box() const; @@ -80,10 +79,14 @@ public: // Restore optional data possibly released by release_optional(). void restore_optional(); - stl_file stl; + const stl_stats& stats() const { return this->stl.stats; } + indexed_triangle_set its; bool repaired; +//private: + stl_file stl; + private: std::deque find_unvisited_neighbors(std::vector &facet_visited) const; }; @@ -205,6 +208,8 @@ void its_merge(indexed_triangle_set &A, const indexed_triangle_set &B); void its_merge(indexed_triangle_set &A, const std::vector &triangles); void its_merge(indexed_triangle_set &A, const Pointf3s &triangles); +std::vector its_face_normals(const indexed_triangle_set &its); + indexed_triangle_set its_make_cube(double x, double y, double z); TriangleMesh make_cube(double x, double y, double z); diff --git a/src/libslic3r/TriangleSelector.cpp b/src/libslic3r/TriangleSelector.cpp index 6178bcec8..7dfe6a8f8 100644 --- a/src/libslic3r/TriangleSelector.cpp +++ b/src/libslic3r/TriangleSelector.cpp @@ -9,16 +9,6 @@ namespace Slic3r { -static inline Vec3i root_neighbors(const TriangleMesh &mesh, int triangle_id) -{ - Vec3i neighbors; - const stl_neighbors& neighbors_src = mesh.stl.neighbors_start[triangle_id]; - for (int i = 0; i < 3; ++i) - // Refuse a neighbor with a flipped normal. - neighbors(i) = neighbors_src.neighbor[i]; - return neighbors; -} - #ifndef NDEBUG bool TriangleSelector::verify_triangle_midpoints(const Triangle &tr) const { @@ -129,7 +119,7 @@ int TriangleSelector::select_unsplit_triangle(const Vec3f &hit, int facet_idx) c if (!m_triangles[facet_idx].valid()) return -1; - Vec3i neighbors = root_neighbors(*m_mesh, facet_idx); + Vec3i neighbors = m_neighbors[facet_idx]; assert(this->verify_triangle_neighbors(m_triangles[facet_idx], neighbors)); return this->select_unsplit_triangle(hit, facet_idx, neighbors); } @@ -167,7 +157,7 @@ void TriangleSelector::select_patch(const Vec3f& hit, int facet_start, if (! visited[facet]) { if (select_triangle(facet, new_state, triangle_splitting)) { // add neighboring facets to list to be proccessed later - for (int neighbor_idx : m_mesh->stl.neighbors_start[facet].neighbor) { + for (int neighbor_idx : m_neighbors[facet]) { if (neighbor_idx >=0 && (m_cursor.type == SPHERE || faces_camera(neighbor_idx))) facets_to_check.push_back(neighbor_idx); } @@ -213,12 +203,12 @@ void TriangleSelector::seed_fill_select_triangles(const Vec3f &hit, int facet_st if (current_facet < m_orig_size_indices) // Propagate over the original triangles. - for (int neighbor_idx : m_mesh->stl.neighbors_start[current_facet].neighbor) { + for (int neighbor_idx : m_neighbors[current_facet]) { assert(neighbor_idx >= -1); if (neighbor_idx >= 0 && !visited[neighbor_idx]) { // Check if neighbour_facet_idx is satisfies angle in seed_fill_angle and append it to facet_queue if it do. - const Vec3f &n1 = m_mesh->stl.facet_start[m_triangles[neighbor_idx].source_triangle].normal; - const Vec3f &n2 = m_mesh->stl.facet_start[m_triangles[current_facet].source_triangle].normal; + const Vec3f &n1 = m_face_normals[m_triangles[neighbor_idx].source_triangle]; + const Vec3f &n2 = m_face_normals[m_triangles[current_facet].source_triangle]; if (std::clamp(n1.dot(n2), 0.f, 1.f) >= facet_angle_limit) facet_queue.push(neighbor_idx); } @@ -261,7 +251,7 @@ std::pair, std::vector> TriangleSelector::precompute_a std::vector neighbors(m_triangles.size(), Vec3i(-1, -1, -1)); std::vector neighbors_propagated(m_triangles.size(), Vec3i(-1, -1, -1)); for (int facet_idx = 0; facet_idx < this->m_orig_size_indices; ++facet_idx) { - neighbors[facet_idx] = root_neighbors(*m_mesh, facet_idx); + neighbors[facet_idx] = m_neighbors[facet_idx]; neighbors_propagated[facet_idx] = neighbors[facet_idx]; assert(this->verify_triangle_neighbors(m_triangles[facet_idx], neighbors[facet_idx])); if (m_triangles[facet_idx].is_split()) @@ -403,7 +393,7 @@ bool TriangleSelector::select_triangle(int facet_idx, EnforcerBlockerType type, if (! m_triangles[facet_idx].valid()) return false; - Vec3i neighbors = root_neighbors(*m_mesh, facet_idx); + Vec3i neighbors = m_neighbors[facet_idx]; assert(this->verify_triangle_neighbors(m_triangles[facet_idx], neighbors)); if (! select_triangle_recursive(facet_idx, neighbors, type, triangle_splitting)) @@ -906,14 +896,7 @@ bool TriangleSelector::is_pointer_in_triangle(int facet_idx) const bool TriangleSelector::faces_camera(int facet) const { assert(facet < m_orig_size_indices); - // The normal is cached in mesh->stl, use it. - Vec3f normal = m_mesh->stl.facet_start[facet].normal; - - if (! m_cursor.uniform_scaling) { - // Transform the normal into world coords. - normal = m_cursor.trafo_normal * normal; - } - return (normal.dot(m_cursor.dir) < 0.); + return (m_cursor.uniform_scaling ? m_face_normals[facet] : m_cursor.trafo_normal * m_face_normals[facet]).dot(m_cursor.dir) < 0.; } @@ -1094,7 +1077,7 @@ void TriangleSelector::garbage_collect() } TriangleSelector::TriangleSelector(const TriangleMesh& mesh) - : m_mesh{&mesh} + : m_mesh{mesh}, m_neighbors(its_face_neighbors(mesh.its)), m_face_normals(its_face_normals(mesh.its)) { reset(); } @@ -1107,16 +1090,17 @@ void TriangleSelector::reset() m_invalid_triangles = 0; m_free_triangles_head = -1; m_free_vertices_head = -1; - m_vertices.reserve(m_mesh->its.vertices.size()); - for (const stl_vertex& vert : m_mesh->its.vertices) + m_vertices.reserve(m_mesh.its.vertices.size()); + for (const stl_vertex& vert : m_mesh.its.vertices) m_vertices.emplace_back(vert); - m_triangles.reserve(m_mesh->its.indices.size()); - for (size_t i = 0; i < m_mesh->its.indices.size(); ++i) { - const stl_triangle_vertex_indices &ind = m_mesh->its.indices[i]; + m_triangles.reserve(m_mesh.its.indices.size()); + for (size_t i = 0; i < m_mesh.its.indices.size(); ++i) { + const stl_triangle_vertex_indices &ind = m_mesh.its.indices[i]; push_triangle(ind[0], ind[1], ind[2], int(i)); } m_orig_size_vertices = int(m_vertices.size()); m_orig_size_indices = int(m_triangles.size()); + } @@ -1286,7 +1270,7 @@ indexed_triangle_set TriangleSelector::get_facets_strict(EnforcerBlockerType sta } for (int itriangle = 0; itriangle < m_orig_size_indices; ++ itriangle) - this->get_facets_strict_recursive(m_triangles[itriangle], root_neighbors(*m_mesh, itriangle), state, out.indices); + this->get_facets_strict_recursive(m_triangles[itriangle], m_neighbors[itriangle], state, out.indices); for (auto &triangle : out.indices) for (int i = 0; i < 3; ++ i) @@ -1398,7 +1382,7 @@ void TriangleSelector::get_facets_split_by_tjoints(const Vec3i &vertices, const std::vector TriangleSelector::get_seed_fill_contour() const { std::vector edges_out; for (int facet_idx = 0; facet_idx < this->m_orig_size_indices; ++facet_idx) { - const Vec3i neighbors = root_neighbors(*m_mesh, facet_idx); + const Vec3i neighbors = m_neighbors[facet_idx]; assert(this->verify_triangle_neighbors(m_triangles[facet_idx], neighbors)); this->get_seed_fill_contour_recursive(facet_idx, neighbors, neighbors, edges_out); } @@ -1522,10 +1506,10 @@ void TriangleSelector::deserialize(const std::pairits.indices.size(), data.second.size() / 4)); + m_triangles.reserve(std::max(m_mesh.its.indices.size(), data.second.size() / 4)); // Number of triangles is twice the number of vertices on a large manifold mesh of genus zero. // Here the triangles count account for both the nodes and leaves, thus the following line may overestimate. - m_vertices.reserve(std::max(m_mesh->its.vertices.size(), m_triangles.size() / 2)); + m_vertices.reserve(std::max(m_mesh.its.vertices.size(), m_triangles.size() / 2)); // Vector to store all parents that have offsprings. struct ProcessingInfo { @@ -1565,7 +1549,7 @@ void TriangleSelector::deserialize(const std::pair m_vertices; std::vector m_triangles; - const TriangleMesh* m_mesh; + const TriangleMesh &m_mesh; + const std::vector m_neighbors; + const std::vector m_face_normals; // Number of invalid triangles (to trigger garbage collection). int m_invalid_triangles; diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index ba72c432d..b4258e781 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -158,22 +158,27 @@ void GLIndexedVertexArray::load_mesh_full_shading(const TriangleMesh& mesh) } else { #endif // ENABLE_SMOOTH_NORMALS - this->vertices_and_normals_interleaved.reserve(this->vertices_and_normals_interleaved.size() + 3 * 3 * 2 * mesh.facets_count()); - - unsigned int vertices_count = 0; - for (int i = 0; i < (int)mesh.stl.stats.number_of_facets; ++i) { - const stl_facet& facet = mesh.stl.facet_start[i]; - for (int j = 0; j < 3; ++j) - this->push_geometry(facet.vertex[j](0), facet.vertex[j](1), facet.vertex[j](2), facet.normal(0), facet.normal(1), facet.normal(2)); - - this->push_triangle(vertices_count, vertices_count + 1, vertices_count + 2); - vertices_count += 3; - } + this->load_its_flat_shading(mesh.its); #if ENABLE_SMOOTH_NORMALS } #endif // ENABLE_SMOOTH_NORMALS } +void GLIndexedVertexArray::load_its_flat_shading(const indexed_triangle_set &its) +{ + this->vertices_and_normals_interleaved.reserve(this->vertices_and_normals_interleaved.size() + 3 * 3 * 2 * its.indices.size()); + unsigned int vertices_count = 0; + for (int i = 0; i < int(its.indices.size()); ++ i) { + stl_triangle_vertex_indices face = its.indices[i]; + stl_vertex vertex[3] = { its.vertices[face[0]], its.vertices[face[1]], its.vertices[face[2]] }; + stl_vertex n = (vertex[2] - vertex[1]).cross(vertex[3] - vertex[2]).normalized(); + for (int j = 0; j < 3; ++j) + this->push_geometry(vertex[j](0), vertex[j](1), vertex[j](2), n(0), n(1), n(2)); + this->push_triangle(vertices_count, vertices_count + 1, vertices_count + 2); + vertices_count += 3; + } +} + void GLIndexedVertexArray::finalize_geometry(bool opengl_initialized) { assert(this->vertices_and_normals_interleaved_VBO_id == 0); @@ -531,7 +536,7 @@ const BoundingBoxf3& GLVolume::transformed_convex_hull_bounding_box() const BoundingBoxf3 GLVolume::transformed_convex_hull_bounding_box(const Transform3d &trafo) const { - return (m_convex_hull && m_convex_hull->stl.stats.number_of_facets > 0) ? + return (m_convex_hull && m_convex_hull->facets_count() > 0) ? m_convex_hull->transformed_bounding_box(trafo) : bounding_box().transformed(trafo); } diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index 1a85cc41e..c90af7d4b 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -128,6 +128,8 @@ public: void load_mesh(const TriangleMesh& mesh) { this->load_mesh_full_shading(mesh); } #endif // ENABLE_SMOOTH_NORMALS + void load_its_flat_shading(const indexed_triangle_set &its); + inline bool has_VBOs() const { return vertices_and_normals_interleaved_VBO_id != 0; } inline void reserve(size_t sz) { diff --git a/src/slic3r/GUI/GLModel.cpp b/src/slic3r/GUI/GLModel.cpp index d22925673..6e58a3231 100644 --- a/src/slic3r/GUI/GLModel.cpp +++ b/src/slic3r/GUI/GLModel.cpp @@ -78,7 +78,7 @@ void GLModel::init_from(const InitializationData& data) } } -void GLModel::init_from(const TriangleMesh& mesh) +void GLModel::init_from(const indexed_triangle_set& its, const BoundingBoxf3 &bbox) { if (!m_render_data.empty()) // call reset() if you want to reuse this model return; @@ -86,25 +86,26 @@ void GLModel::init_from(const TriangleMesh& mesh) RenderData data; data.type = PrimitiveType::Triangles; - std::vector vertices = std::vector(18 * mesh.stl.stats.number_of_facets); - std::vector indices = std::vector(3 * mesh.stl.stats.number_of_facets); + std::vector vertices = std::vector(18 * its.indices.size()); + std::vector indices = std::vector(3 * its.indices.size()); unsigned int vertices_count = 0; - for (uint32_t i = 0; i < mesh.stl.stats.number_of_facets; ++i) { - const stl_facet& facet = mesh.stl.facet_start[i]; - for (size_t j = 0; j < 3; ++j) { + for (uint32_t i = 0; i < its.indices.size(); ++i) { + stl_triangle_vertex_indices face = its.indices[i]; + stl_vertex vertex[3] = { its.vertices[face[0]], its.vertices[face[1]], its.vertices[face[2]] }; + stl_vertex n = (vertex[2] - vertex[1]).cross(vertex[3] - vertex[2]).normalized(); + for (size_t j = 0; j < 3; ++ j) { size_t offset = i * 18 + j * 6; - ::memcpy(static_cast(&vertices[offset]), static_cast(facet.vertex[j].data()), 3 * sizeof(float)); - ::memcpy(static_cast(&vertices[3 + offset]), static_cast(facet.normal.data()), 3 * sizeof(float)); + ::memcpy(static_cast(&vertices[offset]), static_cast(vertex[j].data()), 3 * sizeof(float)); + ::memcpy(static_cast(&vertices[3 + offset]), static_cast(n.data()), 3 * sizeof(float)); } - for (size_t j = 0; j < 3; ++j) { + for (size_t j = 0; j < 3; ++j) indices[i * 3 + j] = vertices_count + j; - } vertices_count += 3; } data.indices_count = static_cast(indices.size()); - m_bounding_box = mesh.bounding_box(); + m_bounding_box = bbox; send_to_gpu(data, vertices, indices); m_render_data.emplace_back(data); diff --git a/src/slic3r/GUI/GLModel.hpp b/src/slic3r/GUI/GLModel.hpp index 7422466f0..c57faa9e8 100644 --- a/src/slic3r/GUI/GLModel.hpp +++ b/src/slic3r/GUI/GLModel.hpp @@ -70,7 +70,8 @@ namespace GUI { virtual ~GLModel() { reset(); } void init_from(const InitializationData& data); - void init_from(const TriangleMesh& mesh); + void init_from(const TriangleMesh& mesh) { this->init_from(mesh.its, mesh.bounding_box()); } + void init_from(const indexed_triangle_set& its, const BoundingBoxf3& bbox); #if ENABLE_SINKING_CONTOURS void init_from(const Polygons& polygons, float z); #endif // ENABLE_SINKING_CONTOURS diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 79186a8ea..2c9aabc38 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -429,9 +429,8 @@ wxString file_wildcards(FileType file_type, const std::string &custom_extension) /* FT_OBJ */ "OBJ files (*.obj)|*.obj;*.OBJ", /* FT_AMF */ "AMF files (*.amf)|*.zip.amf;*.amf;*.AMF;*.xml;*.XML", /* FT_3MF */ "3MF files (*.3mf)|*.3mf;*.3MF;", - /* FT_PRUSA */ "Prusa Control files (*.prusa)|*.prusa;*.PRUSA", /* FT_GCODE */ "G-code files (*.gcode, *.gco, *.g, *.ngc)|*.gcode;*.GCODE;*.gco;*.GCO;*.g;*.G;*.ngc;*.NGC", - /* FT_MODEL */ "Known files (*.stl, *.obj, *.amf, *.xml, *.3mf, *.prusa)|*.stl;*.STL;*.obj;*.OBJ;*.amf;*.AMF;*.xml;*.XML;*.3mf;*.3MF;*.prusa;*.PRUSA", + /* FT_MODEL */ "Known files (*.stl, *.obj, *.amf, *.xml, *.3mf, *.prusa)|*.stl;*.STL;*.obj;*.OBJ;*.amf;*.AMF;*.xml;*.XML;*.3mf;*.3MF", /* FT_PROJECT */ "Project files (*.3mf, *.amf)|*.3mf;*.3MF;*.amf;*.AMF", /* FT_GALLERY */ "Known files (*.stl, *.obj)|*.stl;*.STL;*.obj;*.OBJ", diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 378f91cbc..6eadb9681 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -393,7 +393,7 @@ wxString ObjectList::get_mesh_errors_list(const int obj_idx, const int vol_idx / const stl_stats& stats = vol_idx == -1 ? (*m_objects)[obj_idx]->get_object_stl_stats() : - (*m_objects)[obj_idx]->volumes[vol_idx]->mesh().stl.stats; + (*m_objects)[obj_idx]->volumes[vol_idx]->mesh().stats(); if (stats.degenerate_facets > 0) tooltip += "\t" + format_wxstr(_L_PLURAL("%1$d degenerate facet", "%1$d degenerate facets", stats.degenerate_facets), stats.degenerate_facets) + "\n"; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp index 1ebba4d11..5270087be 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp @@ -288,9 +288,12 @@ void GLGizmoFdmSupports::select_facets_by_angle(float threshold_deg, bool block) // Now calculate dot product of vert_direction and facets' normals. int idx = -1; - for (const stl_facet &facet : mv->mesh().stl.facet_start) { - ++idx; - if (facet.normal.dot(down) > dot_limit) { + const indexed_triangle_set &its = mv->mesh().its; + for (stl_triangle_vertex_indices face : its.indices) { + stl_vertex vertex[3] = { its.vertices[face[0]], its.vertices[face[1]], its.vertices[face[2]] }; + stl_vertex n = (vertex[2] - vertex[1]).cross(vertex[3] - vertex[2]).normalized(); + ++ idx; + if (n.dot(down) > dot_limit) { m_triangle_selectors[mesh_id]->set_facet(idx, block ? EnforcerBlockerType::BLOCKER : EnforcerBlockerType::ENFORCER); m_triangle_selectors.back()->request_update_render_data(); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp index b8c7d9f92..9e30202bd 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp @@ -142,11 +142,13 @@ void GLGizmoFlatten::update_planes() // Now we'll go through all the facets and append Points of facets sharing the same normal. // This part is still performed in mesh coordinate system. - const int num_of_facets = ch.stl.stats.number_of_facets; - std::vector facet_queue(num_of_facets, 0); - std::vector facet_visited(num_of_facets, false); - int facet_queue_cnt = 0; - const stl_normal* normal_ptr = nullptr; + const int num_of_facets = ch.facets_count(); + const std::vector face_normals = its_face_normals(ch.its); + const std::vector face_neighbors = its_face_neighbors(ch.its); + std::vector facet_queue(num_of_facets, 0); + std::vector facet_visited(num_of_facets, false); + int facet_queue_cnt = 0; + const stl_normal* normal_ptr = nullptr; while (1) { // Find next unvisited triangle: int facet_idx = 0; @@ -154,7 +156,7 @@ void GLGizmoFlatten::update_planes() if (!facet_visited[facet_idx]) { facet_queue[facet_queue_cnt ++] = facet_idx; facet_visited[facet_idx] = true; - normal_ptr = &ch.stl.facet_start[facet_idx].normal; + normal_ptr = &face_normals[facet_idx]; m_planes.emplace_back(); break; } @@ -163,18 +165,16 @@ void GLGizmoFlatten::update_planes() while (facet_queue_cnt > 0) { int facet_idx = facet_queue[-- facet_queue_cnt]; - const stl_normal& this_normal = ch.stl.facet_start[facet_idx].normal; + const stl_normal& this_normal = face_normals[facet_idx]; if (std::abs(this_normal(0) - (*normal_ptr)(0)) < 0.001 && std::abs(this_normal(1) - (*normal_ptr)(1)) < 0.001 && std::abs(this_normal(2) - (*normal_ptr)(2)) < 0.001) { - stl_vertex* first_vertex = ch.stl.facet_start[facet_idx].vertex; + const Vec3i face = ch.its.indices[facet_idx]; for (int j=0; j<3; ++j) - m_planes.back().vertices.emplace_back(first_vertex[j].cast()); + m_planes.back().vertices.emplace_back(ch.its.vertices[face[j]].cast()); facet_visited[facet_idx] = true; - for (int j = 0; j < 3; ++ j) { - int neighbor_idx = ch.stl.neighbors_start[facet_idx].neighbor[j]; - if (! facet_visited[neighbor_idx]) + for (int j = 0; j < 3; ++ j) + if (int neighbor_idx = face_neighbors[facet_idx][j]; neighbor_idx >= 0 && ! facet_visited[neighbor_idx]) facet_queue[facet_queue_cnt ++] = neighbor_idx; - } } } m_planes.back().normal = normal_ptr->cast(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp index 155738b32..aac4d6ff7 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp @@ -8,8 +8,9 @@ #include "slic3r/GUI/GUI_App.hpp" #include "slic3r/GUI/Camera.hpp" #include "slic3r/GUI/Plater.hpp" -#include "libslic3r/PresetBundle.hpp" #include "libslic3r/Model.hpp" +#include "libslic3r/PresetBundle.hpp" +#include "libslic3r/TriangleMesh.hpp" @@ -20,17 +21,10 @@ GLGizmoPainterBase::GLGizmoPainterBase(GLCanvas3D& parent, const std::string& ic : GLGizmoBase(parent, icon_filename, sprite_id) { // Make sphere and save it into a vertex buffer. - const TriangleMesh sphere_mesh = make_sphere(1., (2*M_PI)/24.); - for (size_t i=0; i(), - sphere_mesh.stl.facet_start[i].normal.cast()); - for (const stl_triangle_vertex_indices& indices : sphere_mesh.its.indices) - m_vbo_sphere.push_triangle(indices(0), indices(1), indices(2)); + m_vbo_sphere.load_its_flat_shading(its_make_sphere(1., (2*M_PI)/24.)); m_vbo_sphere.finalize_geometry(true); } - - // port of 948bc382655993721d93d3b9fce9b0186fcfb211 void GLGizmoPainterBase::activate_internal_undo_redo_stack(bool activate) { @@ -632,9 +626,15 @@ void TriangleSelectorGUI::update_render_data() GLIndexedVertexArray &iva = tr.get_state() == EnforcerBlockerType::ENFORCER ? m_iva_enforcers : m_iva_blockers; int & cnt = tr.get_state() == EnforcerBlockerType::ENFORCER ? enf_cnt : blc_cnt; - - for (int i = 0; i < 3; ++i) - iva.push_geometry(m_vertices[tr.verts_idxs[i]].v, m_mesh->stl.facet_start[tr.source_triangle].normal); + const Vec3f &v0 = m_vertices[tr.verts_idxs[0]].v; + const Vec3f &v1 = m_vertices[tr.verts_idxs[1]].v; + const Vec3f &v2 = m_vertices[tr.verts_idxs[2]].v; + //FIXME the normal may likely be pulled from m_triangle_selectors, but it may not be worth the effort + // or the current implementation may be more cache friendly. + const Vec3f n = (v1 - v0).cross(v2 - v1).normalized(); + iva.push_geometry(v0, n); + iva.push_geometry(v1, n); + iva.push_geometry(v2, n); iva.push_triangle(cnt, cnt + 1, cnt + 2); cnt += 3; } diff --git a/src/slic3r/GUI/MeshUtils.hpp b/src/slic3r/GUI/MeshUtils.hpp index 65c326116..6d767df03 100644 --- a/src/slic3r/GUI/MeshUtils.hpp +++ b/src/slic3r/GUI/MeshUtils.hpp @@ -113,10 +113,8 @@ public: // during MeshRaycaster existence. MeshRaycaster(const TriangleMesh& mesh) : m_emesh(mesh, true) // calculate epsilon for triangle-ray intersection from an average edge length + , m_normals(its_face_normals(mesh.its)) { - m_normals.reserve(mesh.stl.facet_start.size()); - for (const stl_facet& facet : mesh.stl.facet_start) - m_normals.push_back(facet.normal); } void line_from_mouse_pos(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera, diff --git a/tests/fff_print/test_trianglemesh.cpp b/tests/fff_print/test_trianglemesh.cpp index fa6237c8b..df237db96 100644 --- a/tests/fff_print/test_trianglemesh.cpp +++ b/tests/fff_print/test_trianglemesh.cpp @@ -342,7 +342,7 @@ SCENARIO( "TriangleMesh: Mesh merge functions") { cube.merge(cube2); cube.repair(); THEN( "There are twice as many facets in the merged mesh as the original.") { - REQUIRE(cube.stl.stats.number_of_facets == 2 * cube2.stl.stats.number_of_facets); + REQUIRE(cube.facets_count() == 2 * cube2.facets_count()); } } } diff --git a/xs/xsp/Model.xsp b/xs/xsp/Model.xsp index e7a171efd..35fbb48ee 100644 --- a/xs/xsp/Model.xsp +++ b/xs/xsp/Model.xsp @@ -10,7 +10,6 @@ #include "libslic3r/Format/AMF.hpp" #include "libslic3r/Format/3mf.hpp" #include "libslic3r/Format/OBJ.hpp" -#include "libslic3r/Format/PRUS.hpp" #include "libslic3r/Format/STL.hpp" #include "libslic3r/PresetBundle.hpp" %}