Save/Load repaired errors from/to a mesh statistics to/from a 3MF
This commit is contained in:
parent
47b54d5ce0
commit
1cc7b4ba97
5 changed files with 124 additions and 54 deletions
|
@ -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";
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue