diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp index eca057a5b..b323145d3 100644 --- a/src/libslic3r/Format/3mf.cpp +++ b/src/libslic3r/Format/3mf.cpp @@ -134,6 +134,13 @@ static constexpr const char* SOURCE_OFFSET_Z_KEY = "source_offset_z"; static constexpr const char* SOURCE_IN_INCHES = "source_in_inches"; static constexpr const char* SOURCE_IN_METERS = "source_in_meters"; +static constexpr const char* MESH_STAT_EDGES_FIXED = "edges_fixed"; +static constexpr const char* MESH_STAT_DEGENERATED_FACETS = "degenerate_facets"; +static constexpr const char* MESH_STAT_FACETS_REMOVED = "facets_removed"; +static constexpr const char* MESH_STAT_FACETS_RESERVED = "facets_reversed"; +static constexpr const char* MESH_STAT_BACKWARDS_EDGES = "backwards_edges"; + + const unsigned int VALID_OBJECT_TYPES_COUNT = 1; const char* VALID_OBJECT_TYPES[] = { @@ -383,6 +390,7 @@ namespace Slic3r { unsigned int first_triangle_id; unsigned int last_triangle_id; MetadataList metadata; + RepairedMeshErrors mesh_stats; VolumeMetadata(unsigned int first_triangle_id, unsigned int last_triangle_id) : first_triangle_id(first_triangle_id) @@ -531,7 +539,9 @@ namespace Slic3r { bool _handle_end_config_object(); bool _handle_start_config_volume(const char** attributes, unsigned int num_attributes); + bool _handle_start_config_volume_mesh(const char** attributes, unsigned int num_attributes); bool _handle_end_config_volume(); + bool _handle_end_config_volume_mesh(); bool _handle_start_config_metadata(const char** attributes, unsigned int num_attributes); bool _handle_end_config_metadata(); @@ -1391,6 +1401,8 @@ namespace Slic3r { res = _handle_start_config_object(attributes, num_attributes); else if (::strcmp(VOLUME_TAG, name) == 0) res = _handle_start_config_volume(attributes, num_attributes); + else if (::strcmp(MESH_TAG, name) == 0) + res = _handle_start_config_volume_mesh(attributes, num_attributes); else if (::strcmp(METADATA_TAG, name) == 0) res = _handle_start_config_metadata(attributes, num_attributes); @@ -1411,6 +1423,8 @@ namespace Slic3r { res = _handle_end_config_object(); else if (::strcmp(VOLUME_TAG, name) == 0) res = _handle_end_config_volume(); + else if (::strcmp(MESH_TAG, name) == 0) + res = _handle_end_config_volume_mesh(); else if (::strcmp(METADATA_TAG, name) == 0) res = _handle_end_config_metadata(); @@ -1845,12 +1859,43 @@ namespace Slic3r { return true; } + bool _3MF_Importer::_handle_start_config_volume_mesh(const char** attributes, unsigned int num_attributes) + { + IdToMetadataMap::iterator object = m_objects_metadata.find(m_curr_config.object_id); + if (object == m_objects_metadata.end()) { + add_error("Cannot assign volume mesh to a valid object"); + return false; + } + if (object->second.volumes.empty()) { + add_error("Cannot assign mesh to a valid olume"); + return false; + } + + ObjectMetadata::VolumeMetadata& volume = object->second.volumes.back(); + + int edges_fixed = get_attribute_value_int(attributes, num_attributes, MESH_STAT_EDGES_FIXED ); + int degenerate_facets = get_attribute_value_int(attributes, num_attributes, MESH_STAT_DEGENERATED_FACETS); + int facets_removed = get_attribute_value_int(attributes, num_attributes, MESH_STAT_FACETS_REMOVED ); + int facets_reversed = get_attribute_value_int(attributes, num_attributes, MESH_STAT_FACETS_RESERVED ); + int backwards_edges = get_attribute_value_int(attributes, num_attributes, MESH_STAT_BACKWARDS_EDGES ); + + volume.mesh_stats = { edges_fixed, degenerate_facets, facets_removed, facets_reversed, backwards_edges }; + + return true; + } + bool _3MF_Importer::_handle_end_config_volume() { // do nothing return true; } + bool _3MF_Importer::_handle_end_config_volume_mesh() + { + // do nothing + return true; + } + bool _3MF_Importer::_handle_start_config_metadata(const char** attributes, unsigned int num_attributes) { IdToMetadataMap::iterator object = m_objects_metadata.find(m_curr_config.object_id); @@ -1947,7 +1992,7 @@ namespace Slic3r { // Remove the vertices, that are not referenced by any face. its_compactify_vertices(its, true); - TriangleMesh triangle_mesh(std::move(its)); + TriangleMesh triangle_mesh(std::move(its), volume_data.mesh_stats); if (m_version == 0) { // if the 3mf was not produced by PrusaSlicer and there is only one instance, @@ -2970,6 +3015,15 @@ namespace Slic3r { for (const std::string& key : volume->config.keys()) { stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << key << "\" " << VALUE_ATTR << "=\"" << volume->config.opt_serialize(key) << "\"/>\n"; } + + // stores mesh's statistics + const RepairedMeshErrors& stats = volume->mesh().stats().repaired_errors; + stream << " <" << MESH_TAG << " "; + stream << MESH_STAT_EDGES_FIXED << "=\"" << stats.edges_fixed << "\" "; + stream << MESH_STAT_DEGENERATED_FACETS << "=\"" << stats.degenerate_facets << "\" "; + stream << MESH_STAT_FACETS_REMOVED << "=\"" << stats.facets_removed << "\" "; + stream << MESH_STAT_FACETS_RESERVED << "=\"" << stats.facets_reversed << "\" "; + stream << MESH_STAT_BACKWARDS_EDGES << "=\"" << stats.backwards_edges << "\"/>\n"; stream << " \n"; } diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index b42dfb6a4..b681cbdf4 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -1566,16 +1566,17 @@ void ModelObject::print_info() const cout << "open_edges = " << mesh.stats().open_edges << endl; if (mesh.stats().repaired()) { - 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_reversed > 0) - cout << "facets_reversed = " << mesh.stats().facets_reversed << endl; - if (mesh.stats().backwards_edges > 0) - cout << "backwards_edges = " << mesh.stats().backwards_edges << endl; + const RepairedMeshErrors& stats = mesh.stats().repaired_errors; + if (stats.degenerate_facets > 0) + cout << "degenerate_facets = " << stats.degenerate_facets << endl; + if (stats.edges_fixed > 0) + cout << "edges_fixed = " << stats.edges_fixed << endl; + if (stats.facets_removed > 0) + cout << "facets_removed = " << stats.facets_removed << endl; + if (stats.facets_reversed > 0) + cout << "facets_reversed = " << stats.facets_reversed << endl; + if (stats.backwards_edges > 0) + cout << "backwards_edges = " << stats.backwards_edges << endl; } cout << "number_of_parts = " << mesh.stats().number_of_parts << endl; cout << "volume = " << mesh.volume() << endl; @@ -1616,11 +1617,7 @@ TriangleMeshStats ModelObject::get_object_stl_stats() const // initialize full_stats (for repaired errors) full_stats.open_edges += stats.open_edges; - full_stats.degenerate_facets += stats.degenerate_facets; - full_stats.edges_fixed += stats.edges_fixed; - full_stats.facets_removed += stats.facets_removed; - full_stats.facets_reversed += stats.facets_reversed; - full_stats.backwards_edges += stats.backwards_edges; + full_stats.repaired_errors.merge(stats.repaired_errors); // another used satistics value if (volume->is_model_part()) { @@ -1637,7 +1634,7 @@ int ModelObject::get_mesh_errors_count(const int vol_idx /*= -1*/) const if (vol_idx >= 0) return this->volumes[vol_idx]->get_mesh_errors_count(); - const TriangleMeshStats& stats = get_object_stl_stats(); + const RepairedMeshErrors& stats = get_object_stl_stats().repaired_errors; return stats.degenerate_facets + stats.edges_fixed + stats.facets_removed + stats.facets_reversed + stats.backwards_edges; @@ -1709,7 +1706,7 @@ void ModelVolume::calculate_convex_hull() int ModelVolume::get_mesh_errors_count() const { - const TriangleMeshStats &stats = this->mesh().stats(); + const RepairedMeshErrors &stats = this->mesh().stats().repaired_errors; return stats.degenerate_facets + stats.edges_fixed + stats.facets_removed + stats.facets_reversed + stats.backwards_edges; diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp index 7285fc8fa..e98dcf554 100644 --- a/src/libslic3r/TriangleMesh.cpp +++ b/src/libslic3r/TriangleMesh.cpp @@ -66,8 +66,10 @@ TriangleMesh::TriangleMesh(const indexed_triangle_set &its) : its(its) fill_initial_stats(this->its, m_stats); } -TriangleMesh::TriangleMesh(indexed_triangle_set &&its) : its(std::move(its)) +TriangleMesh::TriangleMesh(indexed_triangle_set &&its, const RepairedMeshErrors& errors/* = RepairedMeshErrors()*/) : its(std::move(its)) { + if (errors.repaired()) + m_stats.repaired_errors = errors; fill_initial_stats(this->its, m_stats); } @@ -194,11 +196,12 @@ bool TriangleMesh::ReadSTLFile(const char* input_file, bool repair) auto facets_w_3_bad_edge = stl.stats.number_of_facets - stl.stats.connected_facets_1_edge; m_stats.open_edges = stl.stats.backwards_edges + facets_w_1_bad_edge + facets_w_2_bad_edge * 2 + facets_w_3_bad_edge * 3; - m_stats.edges_fixed = stl.stats.edges_fixed; - m_stats.degenerate_facets = stl.stats.degenerate_facets; - m_stats.facets_removed = stl.stats.facets_removed; - m_stats.facets_reversed = stl.stats.facets_reversed; - m_stats.backwards_edges = stl.stats.backwards_edges; + m_stats.repaired_errors = { stl.stats.edges_fixed, + stl.stats.degenerate_facets, + stl.stats.facets_removed, + stl.stats.facets_reversed, + stl.stats.backwards_edges }; + m_stats.number_of_parts = stl.stats.number_of_parts; stl_generate_shared_vertices(&stl, this->its); diff --git a/src/libslic3r/TriangleMesh.hpp b/src/libslic3r/TriangleMesh.hpp index d46fb4a8b..b223b4346 100644 --- a/src/libslic3r/TriangleMesh.hpp +++ b/src/libslic3r/TriangleMesh.hpp @@ -16,19 +16,7 @@ namespace Slic3r { class TriangleMesh; class TriangleMeshSlicer; -struct TriangleMeshStats { - // Mesh metrics. - uint32_t number_of_facets = 0; - stl_vertex max = stl_vertex::Zero(); - stl_vertex min = stl_vertex::Zero(); - stl_vertex size = stl_vertex::Zero(); - float volume = -1.f; - int number_of_parts = 0; - - // Mesh errors, remaining. - int open_edges = 0; - - // Mesh errors, fixed. +struct RepairedMeshErrors { // How many edges were united by merging their end points with some other end points in epsilon neighborhood? int edges_fixed = 0; // How many degenerate faces were removed? @@ -43,6 +31,36 @@ struct TriangleMeshStats { // Edges shared by two triangles, oriented incorrectly. int backwards_edges = 0; + void clear() { *this = RepairedMeshErrors(); } + + RepairedMeshErrors merge(const RepairedMeshErrors& rhs) const { + RepairedMeshErrors out; + out.edges_fixed = this->edges_fixed + rhs.edges_fixed; + out.degenerate_facets = this->degenerate_facets + rhs.degenerate_facets; + out.facets_removed = this->facets_removed + rhs.facets_removed; + out.facets_reversed = this->facets_reversed + rhs.facets_reversed; + out.backwards_edges = this->backwards_edges + rhs.backwards_edges; + return out; + } + + bool repaired() const { return degenerate_facets > 0 || edges_fixed > 0 || facets_removed > 0 || facets_reversed > 0 || backwards_edges > 0; } +}; + +struct TriangleMeshStats { + // Mesh metrics. + uint32_t number_of_facets = 0; + stl_vertex max = stl_vertex::Zero(); + stl_vertex min = stl_vertex::Zero(); + stl_vertex size = stl_vertex::Zero(); + float volume = -1.f; + int number_of_parts = 0; + + // Mesh errors, remaining. + int open_edges = 0; + + // Mesh errors, fixed. + RepairedMeshErrors repaired_errors; + void clear() { *this = TriangleMeshStats(); } TriangleMeshStats merge(const TriangleMeshStats &rhs) const { @@ -59,17 +77,13 @@ struct TriangleMeshStats { out.number_of_parts = this->number_of_parts + rhs.number_of_parts; out.open_edges = this->open_edges + rhs.open_edges; out.volume = this->volume + rhs.volume; - out.edges_fixed = this->edges_fixed + rhs.edges_fixed; - out.degenerate_facets = this->degenerate_facets + rhs.degenerate_facets; - out.facets_removed = this->facets_removed + rhs.facets_removed; - out.facets_reversed = this->facets_reversed + rhs.facets_reversed; - out.backwards_edges = this->backwards_edges + rhs.backwards_edges; + out.repaired_errors.merge(rhs.repaired_errors); return out; } } bool manifold() const { return open_edges == 0; } - bool repaired() const { return degenerate_facets > 0 || edges_fixed > 0 || facets_removed > 0 || facets_reversed > 0 || backwards_edges > 0; } + bool repaired() const { return repaired_errors.repaired(); } }; class TriangleMesh @@ -79,7 +93,7 @@ public: TriangleMesh(const std::vector &vertices, const std::vector &faces); TriangleMesh(std::vector &&vertices, const std::vector &&faces); explicit TriangleMesh(const indexed_triangle_set &M); - explicit TriangleMesh(indexed_triangle_set &&M); + explicit TriangleMesh(indexed_triangle_set &&M, const RepairedMeshErrors& repaired_errors = RepairedMeshErrors()); void clear() { this->its.clear(); this->m_stats.clear(); } bool ReadSTLFile(const char* input_file, bool repair = true); bool write_ascii(const char* output_file); diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 0cf57ee82..587846bf7 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -405,16 +405,18 @@ std::pair ObjectList::get_mesh_errors(const int obj_idx, auto_repaired_info = format_wxstr(_L_PLURAL("Auto-repaired %1$d error", "Auto-repaired %1$d errors", errors), errors); tooltip += auto_repaired_info +":\n"; - 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"; - if (stats.edges_fixed > 0) - tooltip += "\t" + format_wxstr(_L_PLURAL("%1$d edge fixed", "%1$d edges fixed", stats.edges_fixed), stats.edges_fixed) + "\n"; - if (stats.facets_removed > 0) - tooltip += "\t" + format_wxstr(_L_PLURAL("%1$d facet removed", "%1$d facets removed", stats.facets_removed), stats.facets_removed) + "\n"; - if (stats.facets_reversed > 0) - tooltip += "\t" + format_wxstr(_L_PLURAL("%1$d facet reversed", "%1$d facets reversed", stats.facets_reversed), stats.facets_reversed) + "\n"; - if (stats.backwards_edges > 0) - tooltip += "\t" + format_wxstr(_L_PLURAL("%1$d backwards edge", "%1$d backwards edges", stats.backwards_edges), stats.backwards_edges) + "\n"; + const RepairedMeshErrors& repaired = stats.repaired_errors; + + if (repaired.degenerate_facets > 0) + tooltip += "\t" + format_wxstr(_L_PLURAL("%1$d degenerate facet", "%1$d degenerate facets", repaired.degenerate_facets), repaired.degenerate_facets) + "\n"; + if (repaired.edges_fixed > 0) + tooltip += "\t" + format_wxstr(_L_PLURAL("%1$d edge fixed", "%1$d edges fixed", repaired.edges_fixed), repaired.edges_fixed) + "\n"; + if (repaired.facets_removed > 0) + tooltip += "\t" + format_wxstr(_L_PLURAL("%1$d facet removed", "%1$d facets removed", repaired.facets_removed), repaired.facets_removed) + "\n"; + if (repaired.facets_reversed > 0) + tooltip += "\t" + format_wxstr(_L_PLURAL("%1$d facet reversed", "%1$d facets reversed", repaired.facets_reversed), repaired.facets_reversed) + "\n"; + if (repaired.backwards_edges > 0) + tooltip += "\t" + format_wxstr(_L_PLURAL("%1$d backwards edge", "%1$d backwards edges", repaired.backwards_edges), repaired.backwards_edges) + "\n"; } if (!stats.manifold()) { remaining_info = format_wxstr(_L_PLURAL("Remaining %1$d open edge", "Remaining %1$d open edges", stats.open_edges), stats.open_edges);