Save/Load repaired errors from/to a mesh statistics to/from a 3MF

This commit is contained in:
YuSanka 2021-10-06 10:53:42 +02:00
parent 47b54d5ce0
commit 1cc7b4ba97
5 changed files with 124 additions and 54 deletions

View file

@ -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 << " </" << VOLUME_TAG << ">\n";
}

View file

@ -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;

View file

@ -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);

View file

@ -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<Vec3f> &vertices, const std::vector<Vec3i> &faces);
TriangleMesh(std::vector<Vec3f> &&vertices, const std::vector<Vec3i> &&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);

View file

@ -405,16 +405,18 @@ std::pair<wxString, std::string> 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);