mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-07-25 15:44:12 -06:00
Eradicated admesh from TriangleMesh:
TriangleMesh newly only holds indexed_triangle_set and TriangleMeshStats. TriangleMeshStats contains an excerpt of stl_stats. TriangleMeshStats are updated when initializing with indexed_triangle_set. Admesh triangle mesh fixing is newly only used when loading an STL. AMF / 3MF / OBJ file formats are already indexed triangle sets, thus they are no more converted to admesh stl_file format, nor fixed through admesh repair machinery. When importing AMF / 3MF / OBJ files, volume is calculated and if negative, all faces are flipped. Also a bounding box and number of open edges is calculated. Implemented its_number_of_patches(), its_num_open_edges() Optimized its_split(), its_is_splittable() using a visitor pattern. Reworked QHull integration into TriangleMesh: 1) Face normals were not right. 2) Indexed triangle set is newly emitted instead of duplicating vertices for each face. Fixed cut_mesh(): Orient the triangulated faces correctly.
This commit is contained in:
parent
f484953a5a
commit
8a2a9dba2f
59 changed files with 1056 additions and 1758 deletions
|
@ -239,6 +239,7 @@ private:
|
|||
return edge_a.facet_number != edge_b.facet_number && edge_a == edge_b;
|
||||
}
|
||||
|
||||
// Connect edge_a with edge_b, update edge connection statistics.
|
||||
static void record_neighbors(stl_file *stl, const HashEdge &edge_a, const HashEdge &edge_b)
|
||||
{
|
||||
// Facet a's neighbor is facet b
|
||||
|
@ -249,7 +250,7 @@ private:
|
|||
stl->neighbors_start[edge_b.facet_number].neighbor[edge_b.which_edge % 3] = edge_a.facet_number; /* sets the .neighbor part */
|
||||
stl->neighbors_start[edge_b.facet_number].which_vertex_not[edge_b.which_edge % 3] = (edge_a.which_edge + 2) % 3; /* sets the .which_vertex_not part */
|
||||
|
||||
if (((edge_a.which_edge < 3) && (edge_b.which_edge < 3)) || ((edge_a.which_edge > 2) && (edge_b.which_edge > 2))) {
|
||||
if ((edge_a.which_edge < 3 && edge_b.which_edge < 3) || (edge_a.which_edge > 2 && edge_b.which_edge > 2)) {
|
||||
// These facets are oriented in opposite directions, their normals are probably messed up.
|
||||
stl->neighbors_start[edge_a.facet_number].which_vertex_not[edge_a.which_edge % 3] += 3;
|
||||
stl->neighbors_start[edge_b.facet_number].which_vertex_not[edge_b.which_edge % 3] += 3;
|
||||
|
@ -479,12 +480,13 @@ void stl_check_facets_exact(stl_file *stl)
|
|||
|
||||
void stl_check_facets_nearby(stl_file *stl, float tolerance)
|
||||
{
|
||||
if ( (stl->stats.connected_facets_1_edge == stl->stats.number_of_facets)
|
||||
&& (stl->stats.connected_facets_2_edge == stl->stats.number_of_facets)
|
||||
&& (stl->stats.connected_facets_3_edge == stl->stats.number_of_facets)) {
|
||||
assert(stl->stats.connected_facets_3_edge <= stl->stats.connected_facets_2_edge);
|
||||
assert(stl->stats.connected_facets_2_edge <= stl->stats.connected_facets_1_edge);
|
||||
assert(stl->stats.connected_facets_1_edge <= stl->stats.number_of_facets);
|
||||
|
||||
if (stl->stats.connected_facets_3_edge == stl->stats.number_of_facets)
|
||||
// No need to check any further. All facets are connected.
|
||||
return;
|
||||
}
|
||||
|
||||
HashTableEdges hash_table(stl->stats.number_of_facets);
|
||||
for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) {
|
||||
|
@ -514,22 +516,12 @@ void stl_remove_unconnected_facets(stl_file *stl)
|
|||
/* Update list of connected edges */
|
||||
stl_neighbors &neighbors = stl->neighbors_start[facet_number];
|
||||
// Update statistics on unconnected triangle edges.
|
||||
switch ((neighbors.neighbor[0] == -1) + (neighbors.neighbor[1] == -1) + (neighbors.neighbor[2] == -1)) {
|
||||
case 0: // Facet has 3 neighbors
|
||||
-- stl->stats.connected_facets_3_edge;
|
||||
-- stl->stats.connected_facets_2_edge;
|
||||
-- stl->stats.connected_facets_1_edge;
|
||||
break;
|
||||
case 1: // Facet has 2 neighbors
|
||||
-- stl->stats.connected_facets_2_edge;
|
||||
-- stl->stats.connected_facets_1_edge;
|
||||
break;
|
||||
case 2: // Facet has 1 neighbor
|
||||
-- stl->stats.connected_facets_1_edge;
|
||||
case 3: // Facet has 0 neighbors
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
switch (neighbors.num_neighbors()) {
|
||||
case 3: -- stl->stats.connected_facets_3_edge; // fall through
|
||||
case 2: -- stl->stats.connected_facets_2_edge; // fall through
|
||||
case 1: -- stl->stats.connected_facets_1_edge; // fall through
|
||||
case 0: break;
|
||||
default: assert(false);
|
||||
}
|
||||
|
||||
if (facet_number < int(-- stl->stats.number_of_facets)) {
|
||||
|
@ -555,20 +547,14 @@ void stl_remove_unconnected_facets(stl_file *stl)
|
|||
|
||||
auto remove_degenerate = [stl, remove_facet](int facet)
|
||||
{
|
||||
// Update statistics on face connectivity.
|
||||
auto stl_update_connects_remove_1 = [stl](int facet_num) {
|
||||
//FIXME when decreasing 3_edge, should I increase 2_edge etc?
|
||||
switch ((stl->neighbors_start[facet_num].neighbor[0] == -1) + (stl->neighbors_start[facet_num].neighbor[1] == -1) + (stl->neighbors_start[facet_num].neighbor[2] == -1)) {
|
||||
case 0: // Facet has 3 neighbors
|
||||
-- stl->stats.connected_facets_3_edge; break;
|
||||
case 1: // Facet has 2 neighbors
|
||||
-- stl->stats.connected_facets_2_edge; break;
|
||||
case 2: // Facet has 1 neighbor
|
||||
-- stl->stats.connected_facets_1_edge; break;
|
||||
case 3: // Facet has 0 neighbors
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
// Update statistics on face connectivity after one edge was disconnected on the facet "facet_num".
|
||||
auto update_connects_remove_1 = [stl](int facet_num) {
|
||||
switch (stl->neighbors_start[facet_num].num_neighbors()) {
|
||||
case 0: assert(false); break;
|
||||
case 1: -- stl->stats.connected_facets_1_edge; break;
|
||||
case 2: -- stl->stats.connected_facets_2_edge; break;
|
||||
case 3: -- stl->stats.connected_facets_3_edge; break;
|
||||
default: assert(false);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -604,9 +590,9 @@ void stl_remove_unconnected_facets(stl_file *stl)
|
|||
|
||||
// Update statistics on edge connectivity.
|
||||
if ((neighbor[0] == -1) && (neighbor[1] != -1))
|
||||
stl_update_connects_remove_1(neighbor[1]);
|
||||
update_connects_remove_1(neighbor[1]);
|
||||
if ((neighbor[1] == -1) && (neighbor[0] != -1))
|
||||
stl_update_connects_remove_1(neighbor[0]);
|
||||
update_connects_remove_1(neighbor[0]);
|
||||
|
||||
if (neighbor[0] >= 0) {
|
||||
if (neighbor[1] >= 0) {
|
||||
|
@ -634,7 +620,7 @@ void stl_remove_unconnected_facets(stl_file *stl)
|
|||
stl->neighbors_start[neighbor[1]].which_vertex_not[(vnot[1] + 1) % 3] = vnot[0];
|
||||
}
|
||||
if (neighbor[2] >= 0) {
|
||||
stl_update_connects_remove_1(neighbor[2]);
|
||||
update_connects_remove_1(neighbor[2]);
|
||||
stl->neighbors_start[neighbor[2]].neighbor[(vnot[2] + 1) % 3] = -1;
|
||||
}
|
||||
|
||||
|
@ -652,11 +638,9 @@ void stl_remove_unconnected_facets(stl_file *stl)
|
|||
++ i;
|
||||
|
||||
if (stl->stats.connected_facets_1_edge < (int)stl->stats.number_of_facets) {
|
||||
// remove completely unconnected facets
|
||||
// There are some faces with no connected edge at all. Remove completely unconnected facets.
|
||||
for (uint32_t i = 0; i < stl->stats.number_of_facets;)
|
||||
if (stl->neighbors_start[i].neighbor[0] == -1 &&
|
||||
stl->neighbors_start[i].neighbor[1] == -1 &&
|
||||
stl->neighbors_start[i].neighbor[2] == -1) {
|
||||
if (stl->neighbors_start[i].num_neighbors() == 0) {
|
||||
// This facet is completely unconnected. Remove it.
|
||||
remove_facet(i);
|
||||
assert(stl_validate(stl));
|
||||
|
|
|
@ -79,8 +79,7 @@ struct stl_neighbors {
|
|||
which_vertex_not[1] = -1;
|
||||
which_vertex_not[2] = -1;
|
||||
}
|
||||
int num_neighbors_missing() const { return (this->neighbor[0] == -1) + (this->neighbor[1] == -1) + (this->neighbor[2] == -1); }
|
||||
int num_neighbors() const { return 3 - this->num_neighbors_missing(); }
|
||||
int num_neighbors() const { return 3 - ((this->neighbor[0] == -1) + (this->neighbor[1] == -1) + (this->neighbor[2] == -1)); }
|
||||
|
||||
// Index of a neighbor facet.
|
||||
int neighbor[3];
|
||||
|
@ -92,28 +91,44 @@ struct stl_stats {
|
|||
stl_stats() { memset(&header, 0, 81); }
|
||||
char header[81];
|
||||
stl_type type = (stl_type)0;
|
||||
// Should always match the number of facets stored inside stl_file::facet_start.
|
||||
uint32_t number_of_facets = 0;
|
||||
// Bounding box.
|
||||
stl_vertex max = stl_vertex::Zero();
|
||||
stl_vertex min = stl_vertex::Zero();
|
||||
stl_vertex size = stl_vertex::Zero();
|
||||
float bounding_diameter = 0.f;
|
||||
float shortest_edge = 0.f;
|
||||
// After repair, the volume shall always be positive.
|
||||
float volume = -1.f;
|
||||
// Number of face edges connected to another face.
|
||||
// Don't use this statistics after repair, use the connected_facets_1/2/3_edge instead!
|
||||
int connected_edges = 0;
|
||||
// Faces with >=1, >=2 and 3 edges connected to another face.
|
||||
int connected_facets_1_edge = 0;
|
||||
int connected_facets_2_edge = 0;
|
||||
int connected_facets_3_edge = 0;
|
||||
// Faces with 1, 2 and 3 open edges after exact chaining, but before repair.
|
||||
int facets_w_1_bad_edge = 0;
|
||||
int facets_w_2_bad_edge = 0;
|
||||
int facets_w_3_bad_edge = 0;
|
||||
// Number of faces read form an STL file.
|
||||
int original_num_facets = 0;
|
||||
// Number of edges connected one to another by snapping their end vertices.
|
||||
int edges_fixed = 0;
|
||||
// Number of faces removed because they were degenerated.
|
||||
int degenerate_facets = 0;
|
||||
// Total number of facets removed: Degenerate faces and unconnected faces.
|
||||
int facets_removed = 0;
|
||||
// Number of faces added by hole filling.
|
||||
int facets_added = 0;
|
||||
// Number of faces reversed because of negative volume or because one patch was connected to another patch with incompatible normals.
|
||||
int facets_reversed = 0;
|
||||
// Number of incompatible edges remaining after the patches were connected together and possibly their normals flipped.
|
||||
int backwards_edges = 0;
|
||||
// Number of triangles, which were flipped during the fixing process.
|
||||
int normals_fixed = 0;
|
||||
// Number of connected triangle patches.
|
||||
int number_of_parts = 0;
|
||||
|
||||
void clear() { *this = stl_stats(); }
|
||||
|
@ -135,13 +150,11 @@ struct stl_file {
|
|||
std::vector<stl_facet> facet_start;
|
||||
std::vector<stl_neighbors> neighbors_start;
|
||||
// Statistics
|
||||
stl_stats stats;
|
||||
stl_stats stats;
|
||||
};
|
||||
|
||||
struct indexed_triangle_set
|
||||
{
|
||||
indexed_triangle_set() {}
|
||||
|
||||
void clear() { indices.clear(); vertices.clear(); }
|
||||
|
||||
size_t memsize() const {
|
||||
|
@ -149,9 +162,7 @@ struct indexed_triangle_set
|
|||
}
|
||||
|
||||
std::vector<stl_triangle_vertex_indices> indices;
|
||||
std::vector<stl_vertex> vertices;
|
||||
//FIXME add normals once we get rid of the stl_file from TriangleMesh completely.
|
||||
//std::vector<stl_normal> normals
|
||||
std::vector<stl_vertex> vertices;
|
||||
|
||||
bool empty() const { return indices.empty() || vertices.empty(); }
|
||||
};
|
||||
|
|
|
@ -205,11 +205,12 @@ bool stl_write_quad_object(stl_file *stl, char *file)
|
|||
|
||||
fprintf(fp, "CQUAD\n");
|
||||
for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) {
|
||||
switch (stl->neighbors_start[i].num_neighbors_missing()) {
|
||||
case 0: color = connect_color; break;
|
||||
case 1: color = uncon_1_color; break;
|
||||
case 2: color = uncon_2_color; break;
|
||||
default: color = uncon_3_color;
|
||||
switch (stl->neighbors_start[i].num_neighbors()) {
|
||||
case 0:
|
||||
default: color = uncon_3_color; break;
|
||||
case 1: color = uncon_2_color; break;
|
||||
case 2: color = uncon_1_color; break;
|
||||
case 3: color = connect_color; break;
|
||||
}
|
||||
fprintf(fp, "%f %f %f %1.1f %1.1f %1.1f 1\n", stl->facet_start[i].vertex[0](0), stl->facet_start[i].vertex[0](1), stl->facet_start[i].vertex[0](2), color(0), color(1), color(2));
|
||||
fprintf(fp, "%f %f %f %1.1f %1.1f %1.1f 1\n", stl->facet_start[i].vertex[1](0), stl->facet_start[i].vertex[1](1), stl->facet_start[i].vertex[1](2), color(0), color(1), color(2));
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue