From 3ab886b747c4742d1662a415d683857003c0388b Mon Sep 17 00:00:00 2001 From: bubnikv Date: Tue, 4 Jun 2019 18:25:53 +0200 Subject: [PATCH 01/22] Fix of mesh decimation (the admesh library). Fixes "Unable to save project (#2445)" --- src/admesh/connect.cpp | 474 ++++++++++++++++----------------- src/admesh/shared.cpp | 417 ++++++++++++++--------------- src/admesh/stl.h | 2 + src/admesh/util.cpp | 47 ++++ src/libslic3r/TriangleMesh.cpp | 36 ++- 5 files changed, 495 insertions(+), 481 deletions(-) diff --git a/src/admesh/connect.cpp b/src/admesh/connect.cpp index fb3213219..3069251d3 100644 --- a/src/admesh/connect.cpp +++ b/src/admesh/connect.cpp @@ -37,7 +37,6 @@ static void stl_match_neighbors_nearby(stl_file *stl, stl_hash_edge *edge_a, stl_hash_edge *edge_b); static void stl_record_neighbors(stl_file *stl, stl_hash_edge *edge_a, stl_hash_edge *edge_b); -static void stl_initialize_facet_check_exact(stl_file *stl); static void stl_initialize_facet_check_nearby(stl_file *stl); static void stl_load_edge_exact(stl_file *stl, stl_hash_edge *edge, const stl_vertex *a, const stl_vertex *b); static int stl_load_edge_nearby(stl_file *stl, stl_hash_edge *edge, @@ -47,63 +46,90 @@ static void insert_hash_edge(stl_file *stl, stl_hash_edge edge, stl_hash_edge *edge_a, stl_hash_edge *edge_b)); static int stl_compare_function(stl_hash_edge *edge_a, stl_hash_edge *edge_b); static void stl_free_edges(stl_file *stl); -static void stl_remove_facet(stl_file *stl, int facet_number); static void stl_change_vertices(stl_file *stl, int facet_num, int vnot, stl_vertex new_vertex); static void stl_which_vertices_to_change(stl_file *stl, stl_hash_edge *edge_a, stl_hash_edge *edge_b, int *facet1, int *vertex1, int *facet2, int *vertex2, stl_vertex *new_vertex1, stl_vertex *new_vertex2); -static void stl_remove_degenerate(stl_file *stl, int facet); extern int stl_check_normal_vector(stl_file *stl, int facet_num, int normal_fix_flag); -static void stl_update_connects_remove_1(stl_file *stl, int facet_num); + +static inline size_t hash_size_from_nr_faces(const size_t nr_faces) +{ + // Good primes for addressing a cca. 30 bit space. + // https://planetmath.org/goodhashtableprimes + static std::vector primes{ 98317, 196613, 393241, 786433, 1572869, 3145739, 6291469, 12582917, 25165843, 50331653, 100663319, 201326611, 402653189, 805306457, 1610612741 }; + // Find a prime number for 50% filling of the shared triangle edges in the mesh. + auto it = std::upper_bound(primes.begin(), primes.end(), nr_faces * 3 * 2 - 1); + return (it == primes.end()) ? primes.back() : *it; +} // This function builds the neighbors list. No modifications are made // to any of the facets. The edges are said to match only if all six // floats of the first edge matches all six floats of the second edge. void stl_check_facets_exact(stl_file *stl) { - if (stl->error) - return; + if (stl->error) + return; - stl->stats.connected_edges = 0; - stl->stats.connected_facets_1_edge = 0; - stl->stats.connected_facets_2_edge = 0; - stl->stats.connected_facets_3_edge = 0; + stl->stats.connected_edges = 0; + stl->stats.connected_facets_1_edge = 0; + stl->stats.connected_facets_2_edge = 0; + stl->stats.connected_facets_3_edge = 0; - // If any two of the three vertices are found to be exactally the same, call them degenerate and remove the facet. - // Do it before the next step, as the next step stores references to the face indices in the hash tables and removing a facet - // will break the references. - for (int i = 0; i < stl->stats.number_of_facets;) { - stl_facet &facet = stl->facet_start[i]; - if (facet.vertex[0] == facet.vertex[1] || facet.vertex[1] == facet.vertex[2] || facet.vertex[0] == facet.vertex[2]) { - // Remove the degenerate facet. - facet = stl->facet_start[--stl->stats.number_of_facets]; - stl->stats.facets_removed += 1; - stl->stats.degenerate_facets += 1; - } else - ++ i; - } + // If any two of the three vertices are found to be exactally the same, call them degenerate and remove the facet. + // Do it before the next step, as the next step stores references to the face indices in the hash tables and removing a facet + // will break the references. + for (uint32_t i = 0; i < stl->stats.number_of_facets;) { + stl_facet &facet = stl->facet_start[i]; + if (facet.vertex[0] == facet.vertex[1] || facet.vertex[1] == facet.vertex[2] || facet.vertex[0] == facet.vertex[2]) { + // Remove the degenerate facet. + facet = stl->facet_start[--stl->stats.number_of_facets]; + stl->stats.facets_removed += 1; + stl->stats.degenerate_facets += 1; + } else + ++ i; + } - // Connect neighbor edges. - stl_initialize_facet_check_exact(stl); - for (int i = 0; i < stl->stats.number_of_facets; i++) { - const stl_facet &facet = stl->facet_start[i]; - for (int j = 0; j < 3; j++) { - stl_hash_edge edge; - edge.facet_number = i; - edge.which_edge = j; - stl_load_edge_exact(stl, &edge, &facet.vertex[j], &facet.vertex[(j + 1) % 3]); - insert_hash_edge(stl, edge, stl_record_neighbors); - } - } - stl_free_edges(stl); + // Initialize hash table. + stl->stats.malloced = 0; + stl->stats.freed = 0; + stl->stats.collisions = 0; + stl->M = (int)hash_size_from_nr_faces(stl->stats.number_of_facets); + for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) { + // initialize neighbors list to -1 to mark unconnected edges + stl->neighbors_start[i].neighbor[0] = -1; + stl->neighbors_start[i].neighbor[1] = -1; + stl->neighbors_start[i].neighbor[2] = -1; + } + stl->heads = (stl_hash_edge**)calloc(stl->M, sizeof(*stl->heads)); + if (stl->heads == NULL) + perror("stl_initialize_facet_check_exact"); + stl->tail = (stl_hash_edge*)malloc(sizeof(stl_hash_edge)); + if (stl->tail == NULL) + perror("stl_initialize_facet_check_exact"); + stl->tail->next = stl->tail; + for (int i = 0; i < stl->M; ++ i) + stl->heads[i] = stl->tail; + + // Connect neighbor edges. + for (uint32_t i = 0; i < stl->stats.number_of_facets; i++) { + const stl_facet &facet = stl->facet_start[i]; + for (int j = 0; j < 3; ++ j) { + stl_hash_edge edge; + edge.facet_number = i; + edge.which_edge = j; + stl_load_edge_exact(stl, &edge, &facet.vertex[j], &facet.vertex[(j + 1) % 3]); + insert_hash_edge(stl, edge, stl_record_neighbors); + } + } + stl_free_edges(stl); #if 0 - printf("Number of faces: %d, number of manifold edges: %d, number of connected edges: %d, number of unconnected edges: %d\r\n", - stl->stats.number_of_facets, stl->stats.number_of_facets * 3, - stl->stats.connected_edges, stl->stats.number_of_facets * 3 - stl->stats.connected_edges); + printf("Number of faces: %d, number of manifold edges: %d, number of connected edges: %d, number of unconnected edges: %d\r\n", + stl->stats.number_of_facets, stl->stats.number_of_facets * 3, + stl->stats.connected_edges, stl->stats.number_of_facets * 3 - stl->stats.connected_edges); #endif } @@ -141,48 +167,6 @@ static void stl_load_edge_exact(stl_file *stl, stl_hash_edge *edge, const stl_ve } } -static inline size_t hash_size_from_nr_faces(const size_t nr_faces) -{ - // Good primes for addressing a cca. 30 bit space. - // https://planetmath.org/goodhashtableprimes - static std::vector primes{ 98317, 196613, 393241, 786433, 1572869, 3145739, 6291469, 12582917, 25165843, 50331653, 100663319, 201326611, 402653189, 805306457, 1610612741 }; - // Find a prime number for 50% filling of the shared triangle edges in the mesh. - auto it = std::upper_bound(primes.begin(), primes.end(), nr_faces * 3 * 2 - 1); - return (it == primes.end()) ? primes.back() : *it; -} - -static void -stl_initialize_facet_check_exact(stl_file *stl) { - int i; - - if (stl->error) return; - - stl->stats.malloced = 0; - stl->stats.freed = 0; - stl->stats.collisions = 0; - - stl->M = hash_size_from_nr_faces(stl->stats.number_of_facets); - - for (i = 0; i < stl->stats.number_of_facets ; i++) { - /* initialize neighbors list to -1 to mark unconnected edges */ - stl->neighbors_start[i].neighbor[0] = -1; - stl->neighbors_start[i].neighbor[1] = -1; - stl->neighbors_start[i].neighbor[2] = -1; - } - - stl->heads = (stl_hash_edge**)calloc(stl->M, sizeof(*stl->heads)); - if(stl->heads == NULL) perror("stl_initialize_facet_check_exact"); - - stl->tail = (stl_hash_edge*)malloc(sizeof(stl_hash_edge)); - if(stl->tail == NULL) perror("stl_initialize_facet_check_exact"); - - stl->tail->next = stl->tail; - - for(i = 0; i < stl->M; i++) { - stl->heads[i] = stl->tail; - } -} - static void insert_hash_edge(stl_file *stl, stl_hash_edge edge, void (*match_neighbors)(stl_file *stl, stl_hash_edge *edge_a, stl_hash_edge *edge_b)) @@ -264,7 +248,7 @@ void stl_check_facets_nearby(stl_file *stl, float tolerance) stl_initialize_facet_check_nearby(stl); - for (int i = 0; i < stl->stats.number_of_facets; ++ i) { + for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) { //FIXME is the copy necessary? stl_facet facet = stl->facet_start[i]; for (int j = 0; j < 3; j++) { @@ -348,7 +332,7 @@ static void stl_initialize_facet_check_nearby(stl_file *stl) /* tolerance = STL_MAX((stl->stats.bounding_diameter / 500000.0), tolerance);*/ /* tolerance *= 0.5;*/ - stl->M = hash_size_from_nr_faces(stl->stats.number_of_facets); + stl->M = (int)hash_size_from_nr_faces(stl->stats.number_of_facets); stl->heads = (stl_hash_edge**)calloc(stl->M, sizeof(*stl->heads)); if(stl->heads == NULL) perror("stl_initialize_facet_check_nearby"); @@ -611,181 +595,170 @@ stl_which_vertices_to_change(stl_file *stl, stl_hash_edge *edge_a, } } -static void -stl_remove_facet(stl_file *stl, int facet_number) { - int neighbor[3]; - int vnot[3]; - int i; - int j; +static void remove_facet(stl_file *stl, int facet_number) +{ + assert(! stl->error); + ++ stl->stats.facets_removed; + /* 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); + } - if (stl->error) return; + if (facet_number == -- stl->stats.number_of_facets) + // Removing the last face is easy, just forget the last face. + return; - stl->stats.facets_removed += 1; - /* Update list of connected edges */ - j = ((stl->neighbors_start[facet_number].neighbor[0] == -1) + - (stl->neighbors_start[facet_number].neighbor[1] == -1) + - (stl->neighbors_start[facet_number].neighbor[2] == -1)); - if(j == 2) { - stl->stats.connected_facets_1_edge -= 1; - } else if(j == 1) { - stl->stats.connected_facets_2_edge -= 1; - stl->stats.connected_facets_1_edge -= 1; - } else if(j == 0) { - stl->stats.connected_facets_3_edge -= 1; - stl->stats.connected_facets_2_edge -= 1; - stl->stats.connected_facets_1_edge -= 1; - } + // Copy the face and neighborship from the last face to facet_number. + stl->facet_start[facet_number] = stl->facet_start[stl->stats.number_of_facets]; + neighbors = stl->neighbors_start[stl->stats.number_of_facets]; + // Update neighborship of faces, which used to point to the last face, now moved to facet_number. + for (int i = 0; i < 3; ++ i) + if (neighbors.neighbor[i] != -1) { + int &other_face_idx = stl->neighbors_start[neighbors.neighbor[i]].neighbor[(neighbors.which_vertex_not[i] + 1) % 3]; + if (other_face_idx != stl->stats.number_of_facets) { + printf("in remove_facet: neighbor = %d numfacets = %d this is wrong\n", other_face_idx, stl->stats.number_of_facets); + return; + } + other_face_idx = facet_number; + } +} - stl->facet_start[facet_number] = - stl->facet_start[stl->stats.number_of_facets - 1]; - /* I could reallocate at this point, but it is not really necessary. */ - stl->neighbors_start[facet_number] = - stl->neighbors_start[stl->stats.number_of_facets - 1]; - stl->stats.number_of_facets -= 1; +static void remove_degenerate(stl_file *stl, int facet) +{ + assert(! stl->error); - for(i = 0; i < 3; i++) { - neighbor[i] = stl->neighbors_start[facet_number].neighbor[i]; - vnot[i] = stl->neighbors_start[facet_number].which_vertex_not[i]; - } + // Update statistics on face connectivity. + auto stl_update_connects_remove_1 = [stl](int facet_num) { + assert(! stl->error); + //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); + } + }; - for(i = 0; i < 3; i++) { - if(neighbor[i] != -1) { - if(stl->neighbors_start[neighbor[i]].neighbor[(vnot[i] + 1)% 3] != - stl->stats.number_of_facets) { - printf("\ -in stl_remove_facet: neighbor = %d numfacets = %d this is wrong\n", - stl->neighbors_start[neighbor[i]].neighbor[(vnot[i] + 1)% 3], - stl->stats.number_of_facets); - return; - } - stl->neighbors_start[neighbor[i]].neighbor[(vnot[i] + 1)% 3] - = facet_number; - } - } + int edge_to_collapse = 0; + if (stl->facet_start[facet].vertex[0] == stl->facet_start[facet].vertex[1]) { + if (stl->facet_start[facet].vertex[1] == stl->facet_start[facet].vertex[2]) { + // All 3 vertices are equal. Collapse the edge with no neighbor if it exists. + const int *nbr = stl->neighbors_start[facet].neighbor; + edge_to_collapse = (nbr[0] == -1) ? 0 : (nbr[1] == -1) ? 1 : 2; + } else { + edge_to_collapse = 0; + } + } else if (stl->facet_start[facet].vertex[1] == stl->facet_start[facet].vertex[2]) { + edge_to_collapse = 1; + } else if (stl->facet_start[facet].vertex[2] == stl->facet_start[facet].vertex[0]) { + edge_to_collapse = 2; + } else { + // No degenerate. Function shouldn't have been called. + return; + } + + int edge[3] = { (edge_to_collapse + 1) % 3, (edge_to_collapse + 2) % 3, edge_to_collapse }; + int neighbor[] = { + stl->neighbors_start[facet].neighbor[edge[0]], + stl->neighbors_start[facet].neighbor[edge[1]], + stl->neighbors_start[facet].neighbor[edge[2]] + }; + int vnot[] = { + stl->neighbors_start[facet].which_vertex_not[edge[0]], + stl->neighbors_start[facet].which_vertex_not[edge[1]], + stl->neighbors_start[facet].which_vertex_not[edge[2]] + }; + // Update statistics on edge connectivity. + if (neighbor[0] == -1) + stl_update_connects_remove_1(neighbor[1]); + if (neighbor[1] == -1) + stl_update_connects_remove_1(neighbor[0]); + + if (neighbor[0] >= 0) { + if (neighbor[1] >= 0) { + // Adjust the "flip" flag for the which_vertex_not values. + if (vnot[0] > 2) { + if (vnot[1] > 2) { + // The face to be removed has its normal flipped compared to the left & right neighbors, therefore after removing this face + // the two remaining neighbors will be oriented correctly. + vnot[0] -= 3; + vnot[1] -= 3; + } else + // One neighbor has its normal inverted compared to the face to be removed, the other is oriented equally. + // After removal, the two neighbors will have their normals flipped. + vnot[1] += 3; + } else if (vnot[1] > 2) + // One neighbor has its normal inverted compared to the face to be removed, the other is oriented equally. + // After removal, the two neighbors will have their normals flipped. + vnot[0] += 3; + } + stl->neighbors_start[neighbor[0]].neighbor[(vnot[0] + 1) % 3] = (neighbor[0] == neighbor[1]) ? -1 : neighbor[1]; + stl->neighbors_start[neighbor[0]].which_vertex_not[(vnot[0] + 1) % 3] = vnot[1]; + } + if (neighbor[1] >= 0) { + stl->neighbors_start[neighbor[1]].neighbor[(vnot[1] + 1) % 3] = (neighbor[0] == neighbor[1]) ? -1 : neighbor[0]; + 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]); + stl->neighbors_start[neighbor[2]].neighbor[(vnot[2] + 1) % 3] = -1; + } + + remove_facet(stl, facet); } void stl_remove_unconnected_facets(stl_file *stl) { - /* A couple of things need to be done here. One is to remove any */ - /* completely unconnected facets (0 edges connected) since these are */ - /* useless and could be completely wrong. The second thing that needs to */ - /* be done is to remove any degenerate facets that were created during */ - /* stl_check_facets_nearby(). */ - if (stl->error) - return; + // A couple of things need to be done here. One is to remove any completely unconnected facets (0 edges connected) since these are + // useless and could be completely wrong. The second thing that needs to be done is to remove any degenerate facets that were created during + // stl_check_facets_nearby(). + if (stl->error) + return; - // remove degenerate facets - for (int i = 0; i < stl->stats.number_of_facets; ++ i) { - if(stl->facet_start[i].vertex[0] == stl->facet_start[i].vertex[1] || - stl->facet_start[i].vertex[0] == stl->facet_start[i].vertex[2] || - stl->facet_start[i].vertex[1] == stl->facet_start[i].vertex[2]) { - stl_remove_degenerate(stl, i); - i--; - } - } + // remove degenerate facets + for (uint32_t i = 0; i < stl->stats.number_of_facets;) + if (stl->facet_start[i].vertex[0] == stl->facet_start[i].vertex[1] || + stl->facet_start[i].vertex[0] == stl->facet_start[i].vertex[2] || + stl->facet_start[i].vertex[1] == stl->facet_start[i].vertex[2]) { + remove_degenerate(stl, i); +// assert(stl_validate(stl)); + } else + ++ i; - if(stl->stats.connected_facets_1_edge < stl->stats.number_of_facets) { - // remove completely unconnected facets - for (int i = 0; i < stl->stats.number_of_facets; i++) { - if (stl->neighbors_start[i].neighbor[0] == -1 && - stl->neighbors_start[i].neighbor[1] == -1 && - stl->neighbors_start[i].neighbor[2] == -1) { - // This facet is completely unconnected. Remove it. - stl_remove_facet(stl, i); - -- i; - } - } - } -} - -static void -stl_remove_degenerate(stl_file *stl, int facet) { - int edge1; - int edge2; - int edge3; - int neighbor1; - int neighbor2; - int neighbor3; - int vnot1; - int vnot2; - int vnot3; - - if (stl->error) return; - - if (stl->facet_start[facet].vertex[0] == stl->facet_start[facet].vertex[1] && - stl->facet_start[facet].vertex[1] == stl->facet_start[facet].vertex[2]) { - /* all 3 vertices are equal. Just remove the facet. I don't think*/ - /* this is really possible, but just in case... */ - printf("removing a facet in stl_remove_degenerate\n"); - stl_remove_facet(stl, facet); - return; - } - - if (stl->facet_start[facet].vertex[0] == stl->facet_start[facet].vertex[1]) { - edge1 = 1; - edge2 = 2; - edge3 = 0; - } else if (stl->facet_start[facet].vertex[1] == stl->facet_start[facet].vertex[2]) { - edge1 = 0; - edge2 = 2; - edge3 = 1; - } else if (stl->facet_start[facet].vertex[2] == stl->facet_start[facet].vertex[0]) { - edge1 = 0; - edge2 = 1; - edge3 = 2; - } else { - /* No degenerate. Function shouldn't have been called. */ - return; - } - neighbor1 = stl->neighbors_start[facet].neighbor[edge1]; - neighbor2 = stl->neighbors_start[facet].neighbor[edge2]; - - if(neighbor1 == -1) { - stl_update_connects_remove_1(stl, neighbor2); - } - if(neighbor2 == -1) { - stl_update_connects_remove_1(stl, neighbor1); - } - - - neighbor3 = stl->neighbors_start[facet].neighbor[edge3]; - vnot1 = stl->neighbors_start[facet].which_vertex_not[edge1]; - vnot2 = stl->neighbors_start[facet].which_vertex_not[edge2]; - vnot3 = stl->neighbors_start[facet].which_vertex_not[edge3]; - - if(neighbor1 >= 0){ - stl->neighbors_start[neighbor1].neighbor[(vnot1 + 1) % 3] = neighbor2; - stl->neighbors_start[neighbor1].which_vertex_not[(vnot1 + 1) % 3] = vnot2; - } - if(neighbor2 >= 0){ - stl->neighbors_start[neighbor2].neighbor[(vnot2 + 1) % 3] = neighbor1; - stl->neighbors_start[neighbor2].which_vertex_not[(vnot2 + 1) % 3] = vnot1; - } - - stl_remove_facet(stl, facet); - - if(neighbor3 >= 0) { - stl_update_connects_remove_1(stl, neighbor3); - stl->neighbors_start[neighbor3].neighbor[(vnot3 + 1) % 3] = -1; - } -} - -void -stl_update_connects_remove_1(stl_file *stl, int facet_num) { - int j; - - if (stl->error) return; - /* Update list of connected edges */ - j = ((stl->neighbors_start[facet_num].neighbor[0] == -1) + - (stl->neighbors_start[facet_num].neighbor[1] == -1) + - (stl->neighbors_start[facet_num].neighbor[2] == -1)); - if(j == 0) { /* Facet has 3 neighbors */ - stl->stats.connected_facets_3_edge -= 1; - } else if(j == 1) { /* Facet has 2 neighbors */ - stl->stats.connected_facets_2_edge -= 1; - } else if(j == 2) { /* Facet has 1 neighbor */ - stl->stats.connected_facets_1_edge -= 1; - } + if (stl->stats.connected_facets_1_edge < (int)stl->stats.number_of_facets) { + // 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) { + // This facet is completely unconnected. Remove it. + remove_facet(stl, i); + assert(stl_validate(stl)); + } else + ++ i; + } } void @@ -801,7 +774,6 @@ stl_fill_holes(stl_file *stl) { int next_edge; int pivot_vertex; int next_facet; - int i; int j; int k; @@ -809,7 +781,7 @@ stl_fill_holes(stl_file *stl) { /* Insert all unconnected edges into hash list */ stl_initialize_facet_check_nearby(stl); - for(i = 0; i < stl->stats.number_of_facets; i++) { + for (uint32_t i = 0; i < stl->stats.number_of_facets; i++) { facet = stl->facet_start[i]; for(j = 0; j < 3; j++) { if(stl->neighbors_start[i].neighbor[j] != -1) continue; @@ -822,7 +794,7 @@ stl_fill_holes(stl_file *stl) { } } - for(i = 0; i < stl->stats.number_of_facets; i++) { + for (uint32_t i = 0; i < stl->stats.number_of_facets; i++) { facet = stl->facet_start[i]; neighbors_initial[0] = stl->neighbors_start[i].neighbor[0]; neighbors_initial[1] = stl->neighbors_start[i].neighbor[1]; @@ -900,7 +872,7 @@ stl_add_facet(stl_file *stl, stl_facet *new_facet) { if (stl->error) return; stl->stats.facets_added += 1; - if(stl->stats.facets_malloced < stl->stats.number_of_facets + 1) { + if(stl->stats.facets_malloced < (int)stl->stats.number_of_facets + 1) { stl->facet_start = (stl_facet*)realloc(stl->facet_start, (sizeof(stl_facet) * (stl->stats.facets_malloced + 256))); if(stl->facet_start == NULL) perror("stl_add_facet"); diff --git a/src/admesh/shared.cpp b/src/admesh/shared.cpp index c8c17ccd5..2ad270903 100644 --- a/src/admesh/shared.cpp +++ b/src/admesh/shared.cpp @@ -23,242 +23,239 @@ #include #include +#include + #include #include "stl.h" -void -stl_invalidate_shared_vertices(stl_file *stl) { - if (stl->error) return; +void stl_invalidate_shared_vertices(stl_file *stl) +{ + if (stl->error) + return; - if (stl->v_indices != NULL) { - free(stl->v_indices); - stl->v_indices = NULL; - } - if (stl->v_shared != NULL) { - free(stl->v_shared); - stl->v_shared = NULL; - } + if (stl->v_indices != nullptr) { + free(stl->v_indices); + stl->v_indices = nullptr; + } + if (stl->v_shared != nullptr) { + free(stl->v_shared); + stl->v_shared = nullptr; + } } -void -stl_generate_shared_vertices(stl_file *stl) { - int i; - int j; - int first_facet; - int direction; - int facet_num; - int vnot; - int next_edge; - int pivot_vertex; - int next_facet; - int reversed; +void stl_generate_shared_vertices(stl_file *stl) +{ + if (stl->error) + return; - if (stl->error) return; + /* make sure this function is idempotent and does not leak memory */ + stl_invalidate_shared_vertices(stl); - /* make sure this function is idempotent and does not leak memory */ - stl_invalidate_shared_vertices(stl); + // 3 indices to vertex per face + stl->v_indices = (v_indices_struct*)calloc(stl->stats.number_of_facets, sizeof(v_indices_struct)); + if (stl->v_indices == nullptr) + perror("stl_generate_shared_vertices"); + // Shared vertices (3D coordinates) + stl->v_shared = (stl_vertex*)calloc((stl->stats.number_of_facets / 2), sizeof(stl_vertex)); + if (stl->v_shared == nullptr) + perror("stl_generate_shared_vertices"); + stl->stats.shared_malloced = stl->stats.number_of_facets / 2; + stl->stats.shared_vertices = 0; - stl->v_indices = (v_indices_struct*) - calloc(stl->stats.number_of_facets, sizeof(v_indices_struct)); - if(stl->v_indices == NULL) perror("stl_generate_shared_vertices"); - stl->v_shared = (stl_vertex*) - calloc((stl->stats.number_of_facets / 2), sizeof(stl_vertex)); - if(stl->v_shared == NULL) perror("stl_generate_shared_vertices"); - stl->stats.shared_malloced = stl->stats.number_of_facets / 2; - stl->stats.shared_vertices = 0; + for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) { + // vertex index -1 means no shared vertex was assigned yet. + stl->v_indices[i].vertex[0] = -1; + stl->v_indices[i].vertex[1] = -1; + stl->v_indices[i].vertex[2] = -1; + } - for(i = 0; i < stl->stats.number_of_facets; i++) { - stl->v_indices[i].vertex[0] = -1; - stl->v_indices[i].vertex[1] = -1; - stl->v_indices[i].vertex[2] = -1; - } + // A degenerate mesh may contain loops: Traversing a fan will end up in an endless loop + // while never reaching the starting face. To avoid these endless loops, traversed faces at each fan traversal + // are marked with a unique fan_traversal_stamp. + unsigned int fan_traversal_stamp = 0; + std::vector fan_traversal_facet_visited(stl->stats.number_of_facets, 0); + for (uint32_t facet_idx = 0; facet_idx < stl->stats.number_of_facets; ++ facet_idx) { + for (int j = 0; j < 3; ++ j) { + if (stl->v_indices[facet_idx].vertex[j] != -1) + // Shared vertex was already assigned. + continue; + // Create a new shared vertex. + if (stl->stats.shared_vertices == stl->stats.shared_malloced) { + stl->stats.shared_malloced += 1024; + stl->v_shared = (stl_vertex*)realloc(stl->v_shared, stl->stats.shared_malloced * sizeof(stl_vertex)); + if(stl->v_shared == nullptr) + perror("stl_generate_shared_vertices"); + } + stl->v_shared[stl->stats.shared_vertices] = stl->facet_start[facet_idx].vertex[j]; + // Traverse the fan around the j-th vertex of the i-th face, assign the newly created shared vertex index to all the neighboring triangles in the triangle fan. + int facet_in_fan_idx = facet_idx; + bool edge_direction = false; + bool traversal_reversed = false; + int vnot = (j + 2) % 3; + // Increase the + ++ fan_traversal_stamp; + for (;;) { + // Next edge on facet_in_fan_idx to be traversed. The edge is indexed by its starting vertex index. + int next_edge = 0; + // Vertex index in facet_in_fan_idx, which is being pivoted around, and which is being assigned a new shared vertex. + int pivot_vertex = 0; + if (vnot > 2) { + // The edge of facet_in_fan_idx opposite to vnot is equally oriented, therefore + // the neighboring facet is flipped. + if (! edge_direction) { + pivot_vertex = (vnot + 2) % 3; + next_edge = pivot_vertex; + } else { + pivot_vertex = (vnot + 1) % 3; + next_edge = vnot % 3; + } + edge_direction = ! edge_direction; + } else { + // The neighboring facet is correctly oriented. + if (! edge_direction) { + pivot_vertex = (vnot + 1) % 3; + next_edge = vnot; + } else { + pivot_vertex = (vnot + 2) % 3; + next_edge = pivot_vertex; + } + } + stl->v_indices[facet_in_fan_idx].vertex[pivot_vertex] = stl->stats.shared_vertices; + fan_traversal_facet_visited[facet_in_fan_idx] = fan_traversal_stamp; - for(i = 0; i < stl->stats.number_of_facets; i++) { - first_facet = i; - for(j = 0; j < 3; j++) { - if(stl->v_indices[i].vertex[j] != -1) { - continue; - } - if(stl->stats.shared_vertices == stl->stats.shared_malloced) { - stl->stats.shared_malloced += 1024; - stl->v_shared = (stl_vertex*)realloc(stl->v_shared, - stl->stats.shared_malloced * sizeof(stl_vertex)); - if(stl->v_shared == NULL) perror("stl_generate_shared_vertices"); - } + // next_edge is an index of the starting vertex of the edge, not an index of the opposite vertex to the edge! + int next_facet = stl->neighbors_start[facet_in_fan_idx].neighbor[next_edge]; + if (next_facet == -1) { + // No neighbor going in the current direction. + if (traversal_reversed) { + // Went to one limit, then turned back and reached the other limit. Quit the fan traversal. + break; + } else { + // Reached the first limit. Now try to reverse and traverse up to the other limit. + edge_direction = true; + vnot = (j + 1) % 3; + traversal_reversed = true; + facet_in_fan_idx = facet_idx; + } + } else if (next_facet == facet_idx) { + // Traversed a closed fan all around. +// assert(! traversal_reversed); + break; + } else if (next_facet >= (int)stl->stats.number_of_facets) { + // The mesh is not valid! + // assert(false); + break; + } else if (fan_traversal_facet_visited[next_facet] == fan_traversal_stamp) { + // Traversed a closed fan all around, but did not reach the starting face. + // This indicates an invalid geometry (non-manifold). + //assert(false); + break; + } else { + // Continue traversal. + // next_edge is an index of the starting vertex of the edge, not an index of the opposite vertex to the edge! + vnot = stl->neighbors_start[facet_in_fan_idx].which_vertex_not[next_edge]; + facet_in_fan_idx = next_facet; + } + } - stl->v_shared[stl->stats.shared_vertices] = - stl->facet_start[i].vertex[j]; - - direction = 0; - reversed = 0; - facet_num = i; - vnot = (j + 2) % 3; - - for(;;) { - if(vnot > 2) { - if(direction == 0) { - pivot_vertex = (vnot + 2) % 3; - next_edge = pivot_vertex; - direction = 1; - } else { - pivot_vertex = (vnot + 1) % 3; - next_edge = vnot % 3; - direction = 0; - } - } else { - if(direction == 0) { - pivot_vertex = (vnot + 1) % 3; - next_edge = vnot; - } else { - pivot_vertex = (vnot + 2) % 3; - next_edge = pivot_vertex; - } - } - stl->v_indices[facet_num].vertex[pivot_vertex] = - stl->stats.shared_vertices; - - next_facet = stl->neighbors_start[facet_num].neighbor[next_edge]; - if(next_facet == -1) { - if(reversed) { - break; - } else { - direction = 1; - vnot = (j + 1) % 3; - reversed = 1; - facet_num = first_facet; - } - } else if(next_facet != first_facet) { - vnot = stl->neighbors_start[facet_num]. - which_vertex_not[next_edge]; - facet_num = next_facet; - } else { - break; - } - } - stl->stats.shared_vertices += 1; - } - } + ++ stl->stats.shared_vertices; + } + } } -void -stl_write_off(stl_file *stl, const char *file) { - int i; - FILE *fp; - char *error_msg; +void stl_write_off(stl_file *stl, const char *file) +{ + if (stl->error) + return; - if (stl->error) return; + /* Open the file */ + FILE *fp = boost::nowide::fopen(file, "w"); + if (fp == nullptr) { + char *error_msg = (char*)malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */ + sprintf(error_msg, "stl_write_ascii: Couldn't open %s for writing", file); + perror(error_msg); + free(error_msg); + stl->error = 1; + return; + } - /* Open the file */ - fp = boost::nowide::fopen(file, "w"); - if(fp == NULL) { - error_msg = (char*) - malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */ - sprintf(error_msg, "stl_write_ascii: Couldn't open %s for writing", - file); - perror(error_msg); - free(error_msg); - stl->error = 1; - return; - } - - fprintf(fp, "OFF\n"); - fprintf(fp, "%d %d 0\n", - stl->stats.shared_vertices, stl->stats.number_of_facets); - - for(i = 0; i < stl->stats.shared_vertices; i++) { - fprintf(fp, "\t%f %f %f\n", - stl->v_shared[i](0), stl->v_shared[i](1), stl->v_shared[i](2)); - } - for(i = 0; i < stl->stats.number_of_facets; i++) { - fprintf(fp, "\t3 %d %d %d\n", stl->v_indices[i].vertex[0], - stl->v_indices[i].vertex[1], stl->v_indices[i].vertex[2]); - } - fclose(fp); + fprintf(fp, "OFF\n"); + fprintf(fp, "%d %d 0\n", stl->stats.shared_vertices, stl->stats.number_of_facets); + for (int i = 0; i < stl->stats.shared_vertices; ++ i) + fprintf(fp, "\t%f %f %f\n", stl->v_shared[i](0), stl->v_shared[i](1), stl->v_shared[i](2)); + for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) + fprintf(fp, "\t3 %d %d %d\n", stl->v_indices[i].vertex[0], stl->v_indices[i].vertex[1], stl->v_indices[i].vertex[2]); + fclose(fp); } -void -stl_write_vrml(stl_file *stl, const char *file) { - int i; - FILE *fp; - char *error_msg; +void stl_write_vrml(stl_file *stl, const char *file) +{ + if (stl->error) + return; - if (stl->error) return; + /* Open the file */ + FILE *fp = boost::nowide::fopen(file, "w"); + if (fp == nullptr) { + char *error_msg = (char*)malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */ + sprintf(error_msg, "stl_write_ascii: Couldn't open %s for writing", file); + perror(error_msg); + free(error_msg); + stl->error = 1; + return; + } - /* Open the file */ - fp = boost::nowide::fopen(file, "w"); - if(fp == NULL) { - error_msg = (char*) - malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */ - sprintf(error_msg, "stl_write_ascii: Couldn't open %s for writing", - file); - perror(error_msg); - free(error_msg); - stl->error = 1; - return; - } + fprintf(fp, "#VRML V1.0 ascii\n\n"); + fprintf(fp, "Separator {\n"); + fprintf(fp, "\tDEF STLShape ShapeHints {\n"); + fprintf(fp, "\t\tvertexOrdering COUNTERCLOCKWISE\n"); + fprintf(fp, "\t\tfaceType CONVEX\n"); + fprintf(fp, "\t\tshapeType SOLID\n"); + fprintf(fp, "\t\tcreaseAngle 0.0\n"); + fprintf(fp, "\t}\n"); + fprintf(fp, "\tDEF STLModel Separator {\n"); + fprintf(fp, "\t\tDEF STLColor Material {\n"); + fprintf(fp, "\t\t\temissiveColor 0.700000 0.700000 0.000000\n"); + fprintf(fp, "\t\t}\n"); + fprintf(fp, "\t\tDEF STLVertices Coordinate3 {\n"); + fprintf(fp, "\t\t\tpoint [\n"); - fprintf(fp, "#VRML V1.0 ascii\n\n"); - fprintf(fp, "Separator {\n"); - fprintf(fp, "\tDEF STLShape ShapeHints {\n"); - fprintf(fp, "\t\tvertexOrdering COUNTERCLOCKWISE\n"); - fprintf(fp, "\t\tfaceType CONVEX\n"); - fprintf(fp, "\t\tshapeType SOLID\n"); - fprintf(fp, "\t\tcreaseAngle 0.0\n"); - fprintf(fp, "\t}\n"); - fprintf(fp, "\tDEF STLModel Separator {\n"); - fprintf(fp, "\t\tDEF STLColor Material {\n"); - fprintf(fp, "\t\t\temissiveColor 0.700000 0.700000 0.000000\n"); - fprintf(fp, "\t\t}\n"); - fprintf(fp, "\t\tDEF STLVertices Coordinate3 {\n"); - fprintf(fp, "\t\t\tpoint [\n"); + int i = 0; + for (; i < (stl->stats.shared_vertices - 1); i++) + fprintf(fp, "\t\t\t\t%f %f %f,\n", stl->v_shared[i](0), stl->v_shared[i](1), stl->v_shared[i](2)); + fprintf(fp, "\t\t\t\t%f %f %f]\n", stl->v_shared[i](0), stl->v_shared[i](1), stl->v_shared[i](2)); + fprintf(fp, "\t\t}\n"); + fprintf(fp, "\t\tDEF STLTriangles IndexedFaceSet {\n"); + fprintf(fp, "\t\t\tcoordIndex [\n"); - for(i = 0; i < (stl->stats.shared_vertices - 1); i++) { - fprintf(fp, "\t\t\t\t%f %f %f,\n", - stl->v_shared[i](0), stl->v_shared[i](1), stl->v_shared[i](2)); - } - fprintf(fp, "\t\t\t\t%f %f %f]\n", - stl->v_shared[i](0), stl->v_shared[i](1), stl->v_shared[i](2)); - fprintf(fp, "\t\t}\n"); - fprintf(fp, "\t\tDEF STLTriangles IndexedFaceSet {\n"); - fprintf(fp, "\t\t\tcoordIndex [\n"); - - for(i = 0; i < (stl->stats.number_of_facets - 1); i++) { - fprintf(fp, "\t\t\t\t%d, %d, %d, -1,\n", stl->v_indices[i].vertex[0], - stl->v_indices[i].vertex[1], stl->v_indices[i].vertex[2]); - } - fprintf(fp, "\t\t\t\t%d, %d, %d, -1]\n", stl->v_indices[i].vertex[0], - stl->v_indices[i].vertex[1], stl->v_indices[i].vertex[2]); - fprintf(fp, "\t\t}\n"); - fprintf(fp, "\t}\n"); - fprintf(fp, "}\n"); - fclose(fp); + for (int i = 0; i + 1 < (int)stl->stats.number_of_facets; ++ i) + fprintf(fp, "\t\t\t\t%d, %d, %d, -1,\n", stl->v_indices[i].vertex[0], stl->v_indices[i].vertex[1], stl->v_indices[i].vertex[2]); + fprintf(fp, "\t\t\t\t%d, %d, %d, -1]\n", stl->v_indices[i].vertex[0], stl->v_indices[i].vertex[1], stl->v_indices[i].vertex[2]); + fprintf(fp, "\t\t}\n"); + fprintf(fp, "\t}\n"); + fprintf(fp, "}\n"); + fclose(fp); } -void stl_write_obj (stl_file *stl, const char *file) { - int i; - FILE* fp; +void stl_write_obj (stl_file *stl, const char *file) +{ + if (stl->error) + return; - if (stl->error) return; + FILE *fp = boost::nowide::fopen(file, "w"); + if (fp == nullptr) { + char* error_msg = (char*)malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */ + sprintf(error_msg, "stl_write_ascii: Couldn't open %s for writing", file); + perror(error_msg); + free(error_msg); + stl->error = 1; + return; + } - /* Open the file */ - fp = boost::nowide::fopen(file, "w"); - if (fp == NULL) { - char* error_msg = (char*)malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */ - sprintf(error_msg, "stl_write_ascii: Couldn't open %s for writing", file); - perror(error_msg); - free(error_msg); - stl->error = 1; - return; - } - - for (i = 0; i < stl->stats.shared_vertices; i++) { - fprintf(fp, "v %f %f %f\n", stl->v_shared[i](0), stl->v_shared[i](1), stl->v_shared[i](2)); - } - for (i = 0; i < stl->stats.number_of_facets; i++) { - fprintf(fp, "f %d %d %d\n", stl->v_indices[i].vertex[0]+1, stl->v_indices[i].vertex[1]+1, stl->v_indices[i].vertex[2]+1); - } - - fclose(fp); + for (int i = 0; i < stl->stats.shared_vertices; ++ i) + fprintf(fp, "v %f %f %f\n", stl->v_shared[i](0), stl->v_shared[i](1), stl->v_shared[i](2)); + for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) + fprintf(fp, "f %d %d %d\n", stl->v_indices[i].vertex[0]+1, stl->v_indices[i].vertex[1]+1, stl->v_indices[i].vertex[2]+1); + fclose(fp); } diff --git a/src/admesh/stl.h b/src/admesh/stl.h index f867e197b..5ecd94bd1 100644 --- a/src/admesh/stl.h +++ b/src/admesh/stl.h @@ -277,5 +277,7 @@ extern void stl_add_facet(stl_file *stl, stl_facet *new_facet); extern void stl_clear_error(stl_file *stl); extern int stl_get_error(stl_file *stl); extern void stl_exit_on_error(stl_file *stl); +// Validate the mesh, assert on error. +extern bool stl_validate(stl_file *stl); #endif diff --git a/src/admesh/util.cpp b/src/admesh/util.cpp index 305a58e22..c2d2c2726 100644 --- a/src/admesh/util.cpp +++ b/src/admesh/util.cpp @@ -457,3 +457,50 @@ All facets connected. No further nearby check necessary.\n"); stl_verify_neighbors(stl); } } + +// Check validity of the mesh, assert on error. +bool stl_validate(stl_file *stl) +{ + assert(! stl->error); + assert(stl->fp == nullptr); + assert(stl->facet_start != nullptr); + assert(stl->heads == nullptr); + assert(stl->tail == nullptr); + assert(stl->neighbors_start != nullptr); + assert((stl->v_indices == nullptr) == (stl->v_shared == nullptr)); + assert(stl->stats.number_of_facets > 0); + +#ifdef _DEBUG + // Verify validity of neighborship data. + for (int facet_idx = 0; facet_idx < (int)stl->stats.number_of_facets; ++ facet_idx) { + const stl_neighbors &nbr = stl->neighbors_start[facet_idx]; + const int *vertices = (stl->v_indices == nullptr) ? nullptr : stl->v_indices[facet_idx].vertex; + for (int nbr_idx = 0; nbr_idx < 3; ++ nbr_idx) { + int nbr_face = stl->neighbors_start[facet_idx].neighbor[nbr_idx]; + assert(nbr_face < (int)stl->stats.number_of_facets); + if (nbr_face != -1) { + int nbr_vnot = nbr.which_vertex_not[nbr_idx]; + assert(nbr_vnot >= 0 && nbr_vnot < 6); + // Neighbor of the neighbor is the original face. + assert(stl->neighbors_start[nbr_face].neighbor[(nbr_vnot + 1) % 3] == facet_idx); + int vnot_back = stl->neighbors_start[nbr_face].which_vertex_not[(nbr_vnot + 1) % 3]; + assert(vnot_back >= 0 && vnot_back < 6); + assert((nbr_vnot < 3) == (vnot_back < 3)); + assert(vnot_back % 3 == (nbr_idx + 2) % 3); + if (vertices != nullptr) { + // Has shared vertices. + if (nbr_vnot < 3) { + // Faces facet_idx and nbr_face share two vertices accross the common edge. Faces are correctly oriented. + assert((stl->v_indices[nbr_face].vertex[(nbr_vnot + 1) % 3] == vertices[(nbr_idx + 1) % 3] && stl->v_indices[nbr_face].vertex[(nbr_vnot + 2) % 3] == vertices[nbr_idx])); + } else { + // Faces facet_idx and nbr_face share two vertices accross the common edge. Faces are incorrectly oriented, one of them is flipped. + assert((stl->v_indices[nbr_face].vertex[(nbr_vnot + 2) % 3] == vertices[(nbr_idx + 1) % 3] && stl->v_indices[nbr_face].vertex[(nbr_vnot + 1) % 3] == vertices[nbr_idx])); + } + } + } + } + } +#endif /* _DEBUG */ + + return true; +} diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp index 4d35cabca..b7c6c07a7 100644 --- a/src/libslic3r/TriangleMesh.cpp +++ b/src/libslic3r/TriangleMesh.cpp @@ -104,18 +104,21 @@ TriangleMesh& TriangleMesh::operator=(const TriangleMesh &other) void TriangleMesh::repair() { - if (this->repaired) return; + if (this->repaired) + return; // admesh fails when repairing empty meshes - if (this->stl.stats.number_of_facets == 0) return; + if (this->stl.stats.number_of_facets == 0) + return; BOOST_LOG_TRIVIAL(debug) << "TriangleMesh::repair() started"; - + // checking exact #ifdef SLIC3R_TRACE_REPAIR BOOST_LOG_TRIVIAL(trace) << "\tstl_check_faces_exact"; #endif /* SLIC3R_TRACE_REPAIR */ stl_check_facets_exact(&stl); + assert(stl_validate(&this->stl)); stl.stats.facets_w_1_bad_edge = (stl.stats.connected_facets_2_edge - stl.stats.connected_facets_3_edge); stl.stats.facets_w_2_bad_edge = (stl.stats.connected_facets_1_edge - stl.stats.connected_facets_2_edge); stl.stats.facets_w_3_bad_edge = (stl.stats.number_of_facets - stl.stats.connected_facets_1_edge); @@ -141,6 +144,7 @@ void TriangleMesh::repair() } } } + assert(stl_validate(&this->stl)); // remove_unconnected if (stl.stats.connected_facets_3_edge < (int)stl.stats.number_of_facets) { @@ -148,6 +152,7 @@ void TriangleMesh::repair() BOOST_LOG_TRIVIAL(trace) << "\tstl_remove_unconnected_facets"; #endif /* SLIC3R_TRACE_REPAIR */ stl_remove_unconnected_facets(&stl); + assert(stl_validate(&this->stl)); } // fill_holes @@ -168,24 +173,28 @@ void TriangleMesh::repair() BOOST_LOG_TRIVIAL(trace) << "\tstl_fix_normal_directions"; #endif /* SLIC3R_TRACE_REPAIR */ stl_fix_normal_directions(&stl); + assert(stl_validate(&this->stl)); // normal_values #ifdef SLIC3R_TRACE_REPAIR BOOST_LOG_TRIVIAL(trace) << "\tstl_fix_normal_values"; #endif /* SLIC3R_TRACE_REPAIR */ stl_fix_normal_values(&stl); + assert(stl_validate(&this->stl)); // always calculate the volume and reverse all normals if volume is negative #ifdef SLIC3R_TRACE_REPAIR BOOST_LOG_TRIVIAL(trace) << "\tstl_calculate_volume"; #endif /* SLIC3R_TRACE_REPAIR */ stl_calculate_volume(&stl); + assert(stl_validate(&this->stl)); // neighbors #ifdef SLIC3R_TRACE_REPAIR BOOST_LOG_TRIVIAL(trace) << "\tstl_verify_neighbors"; #endif /* SLIC3R_TRACE_REPAIR */ stl_verify_neighbors(&stl); + assert(stl_validate(&this->stl)); this->repaired = true; @@ -594,27 +603,14 @@ TriangleMesh TriangleMesh::convex_hull_3d() const void TriangleMesh::require_shared_vertices() { BOOST_LOG_TRIVIAL(trace) << "TriangleMeshSlicer::require_shared_vertices - start"; - if (!this->repaired) + assert(stl_validate(&this->stl)); + if (! this->repaired) this->repair(); - if (this->stl.v_shared == NULL) { + if (this->stl.v_shared == nullptr) { BOOST_LOG_TRIVIAL(trace) << "TriangleMeshSlicer::require_shared_vertices - stl_generate_shared_vertices"; stl_generate_shared_vertices(&(this->stl)); } -#ifdef _DEBUG - // Verify validity of neighborship data. - for (int facet_idx = 0; facet_idx < stl.stats.number_of_facets; ++facet_idx) { - const stl_neighbors &nbr = stl.neighbors_start[facet_idx]; - const int *vertices = stl.v_indices[facet_idx].vertex; - for (int nbr_idx = 0; nbr_idx < 3; ++nbr_idx) { - int nbr_face = this->stl.neighbors_start[facet_idx].neighbor[nbr_idx]; - if (nbr_face != -1) { - assert( - (stl.v_indices[nbr_face].vertex[(nbr.which_vertex_not[nbr_idx] + 1) % 3] == vertices[(nbr_idx + 1) % 3] && stl.v_indices[nbr_face].vertex[(nbr.which_vertex_not[nbr_idx] + 2) % 3] == vertices[nbr_idx]) || - (stl.v_indices[nbr_face].vertex[(nbr.which_vertex_not[nbr_idx] + 2) % 3] == vertices[(nbr_idx + 1) % 3] && stl.v_indices[nbr_face].vertex[(nbr.which_vertex_not[nbr_idx] + 1) % 3] == vertices[nbr_idx])); - } - } - } -#endif /* _DEBUG */ + assert(stl_validate(&this->stl)); BOOST_LOG_TRIVIAL(trace) << "TriangleMeshSlicer::require_shared_vertices - end"; } From 8da54139c463a09ec899a9df6bccae16802dccdf Mon Sep 17 00:00:00 2001 From: bubnikv Date: Tue, 4 Jun 2019 22:06:42 +0200 Subject: [PATCH 02/22] WIP: Admesh - replacement of C memory allocation with std vectors --- CMakeLists.txt | 2 +- src/admesh/connect.cpp | 401 ++++++++----------- src/admesh/normals.cpp | 26 +- src/admesh/shared.cpp | 37 +- src/admesh/stl.h | 187 +++++---- src/admesh/stl_io.cpp | 30 +- src/admesh/stlinit.cpp | 104 ++--- src/admesh/util.cpp | 104 +++-- src/libslic3r/Format/3mf.cpp | 2 +- src/libslic3r/Format/AMF.cpp | 2 +- src/libslic3r/Format/PRUS.cpp | 6 +- src/libslic3r/Model.cpp | 18 +- src/libslic3r/SLA/SLASupportTreeIGL.cpp | 17 +- src/libslic3r/SlicingAdaptive.cpp | 4 +- src/libslic3r/TriangleMesh.cpp | 83 ++-- src/libslic3r/TriangleMesh.hpp | 4 +- src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp | 8 +- 17 files changed, 450 insertions(+), 585 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 719bdd04e..3d7157d5e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -60,7 +60,7 @@ if (MSVC) # /bigobj (Increase Number of Sections in .Obj file) # error C3859: virtual memory range for PCH exceeded; please recompile with a command line option of '-Zm90' or greater # Generate symbols at every build target, even for the release. - add_compile_options(-bigobj -Zm316 /Zi) + add_compile_options(-bigobj -Zm520 /Zi) endif () # Display and check CMAKE_PREFIX_PATH diff --git a/src/admesh/connect.cpp b/src/admesh/connect.cpp index 3069251d3..b99f93f3d 100644 --- a/src/admesh/connect.cpp +++ b/src/admesh/connect.cpp @@ -97,18 +97,10 @@ void stl_check_facets_exact(stl_file *stl) stl->stats.freed = 0; stl->stats.collisions = 0; stl->M = (int)hash_size_from_nr_faces(stl->stats.number_of_facets); - for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) { - // initialize neighbors list to -1 to mark unconnected edges - stl->neighbors_start[i].neighbor[0] = -1; - stl->neighbors_start[i].neighbor[1] = -1; - stl->neighbors_start[i].neighbor[2] = -1; - } - stl->heads = (stl_hash_edge**)calloc(stl->M, sizeof(*stl->heads)); - if (stl->heads == NULL) - perror("stl_initialize_facet_check_exact"); - stl->tail = (stl_hash_edge*)malloc(sizeof(stl_hash_edge)); - if (stl->tail == NULL) - perror("stl_initialize_facet_check_exact"); + for (auto &neighbor : stl->neighbors_start) + neighbor.reset(); + stl->heads.assign(stl->M, nullptr); + stl->tail = new stl_hash_edge; stl->tail->next = stl->tail; for (int i = 0; i < stl->M; ++ i) stl->heads[i] = stl->tail; @@ -180,7 +172,7 @@ static void insert_hash_edge(stl_file *stl, stl_hash_edge edge, stl_hash_edge *temp; if(link == stl->tail) { /* This list doesn't have any edges currently in it. Add this one. */ - new_edge = (stl_hash_edge*)malloc(sizeof(stl_hash_edge)); + new_edge = new stl_hash_edge; if(new_edge == NULL) perror("insert_hash_edge"); stl->stats.malloced++; *new_edge = edge; @@ -192,7 +184,7 @@ static void insert_hash_edge(stl_file *stl, stl_hash_edge edge, match_neighbors(stl, &edge, link); /* Delete the matched edge from the list. */ stl->heads[chain_number] = link->next; - free(link); + delete link; stl->stats.freed++; return; } else { @@ -200,7 +192,7 @@ static void insert_hash_edge(stl_file *stl, stl_hash_edge edge, for(;;) { if(link->next == stl->tail) { /* This is the last item in the list. Insert a new edge. */ - new_edge = (stl_hash_edge*)malloc(sizeof(stl_hash_edge)); + new_edge = new stl_hash_edge; if(new_edge == NULL) perror("insert_hash_edge"); stl->stats.malloced++; *new_edge = edge; @@ -215,7 +207,7 @@ static void insert_hash_edge(stl_file *stl, stl_hash_edge edge, /* Delete the matched edge from the list. */ temp = link->next; link->next = link->next->next; - free(temp); + delete temp; stl->stats.freed++; return; } else { @@ -307,48 +299,38 @@ static void stl_free_edges(stl_file *stl) for (int i = 0; i < stl->M; i++) { for (stl_hash_edge *temp = stl->heads[i]; stl->heads[i] != stl->tail; temp = stl->heads[i]) { stl->heads[i] = stl->heads[i]->next; - free(temp); + delete temp; ++ stl->stats.freed; } } } - free(stl->heads); - stl->heads = nullptr; - free(stl->tail); + stl->heads.clear(); + delete stl->tail; stl->tail = nullptr; } static void stl_initialize_facet_check_nearby(stl_file *stl) { - int i; + if (stl->error) + return; - if (stl->error) return; + stl->stats.malloced = 0; + stl->stats.freed = 0; + stl->stats.collisions = 0; - stl->stats.malloced = 0; - stl->stats.freed = 0; - stl->stats.collisions = 0; + /* tolerance = STL_MAX(stl->stats.shortest_edge, tolerance);*/ + /* tolerance = STL_MAX((stl->stats.bounding_diameter / 500000.0), tolerance);*/ + /* tolerance *= 0.5;*/ + stl->M = (int)hash_size_from_nr_faces(stl->stats.number_of_facets); - /* tolerance = STL_MAX(stl->stats.shortest_edge, tolerance);*/ - /* tolerance = STL_MAX((stl->stats.bounding_diameter / 500000.0), tolerance);*/ - /* tolerance *= 0.5;*/ + stl->heads.assign(stl->M, nullptr); + stl->tail = new stl_hash_edge; + stl->tail->next = stl->tail; - stl->M = (int)hash_size_from_nr_faces(stl->stats.number_of_facets); - - stl->heads = (stl_hash_edge**)calloc(stl->M, sizeof(*stl->heads)); - if(stl->heads == NULL) perror("stl_initialize_facet_check_nearby"); - - stl->tail = (stl_hash_edge*)malloc(sizeof(stl_hash_edge)); - if(stl->tail == NULL) perror("stl_initialize_facet_check_nearby"); - - stl->tail->next = stl->tail; - - for(i = 0; i < stl->M; i++) { - stl->heads[i] = stl->tail; - } + for (int i = 0; i < stl->M; ++ i) + stl->heads[i] = stl->tail; } - - static void stl_record_neighbors(stl_file *stl, stl_hash_edge *edge_a, stl_hash_edge *edge_b) { @@ -358,29 +340,19 @@ stl_record_neighbors(stl_file *stl, if (stl->error) return; /* Facet a's neighbor is facet b */ - stl->neighbors_start[edge_a->facet_number].neighbor[edge_a->which_edge % 3] = - edge_b->facet_number; /* sets the .neighbor part */ - - stl->neighbors_start[edge_a->facet_number]. - which_vertex_not[edge_a->which_edge % 3] = - (edge_b->which_edge + 2) % 3; /* sets the .which_vertex_not part */ + stl->neighbors_start[edge_a->facet_number].neighbor[edge_a->which_edge % 3] = edge_b->facet_number; /* sets the .neighbor part */ + stl->neighbors_start[edge_a->facet_number].which_vertex_not[edge_a->which_edge % 3] = (edge_b->which_edge + 2) % 3; /* sets the .which_vertex_not part */ /* Facet b's neighbor is facet a */ - 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 */ + 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))) { /* 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; + 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; } @@ -561,8 +533,7 @@ stl_which_vertices_to_change(stl_file *stl, stl_hash_edge *edge_a, *facet1 = -1; } else { if( (stl->neighbors_start[edge_a->facet_number].neighbor[v1a] == -1) - && (stl->neighbors_start[edge_a->facet_number]. - neighbor[(v1a + 2) % 3] == -1)) { + && (stl->neighbors_start[edge_a->facet_number].neighbor[(v1a + 2) % 3] == -1)) { /* This vertex has no neighbors. This is a good one to change */ *facet1 = edge_a->facet_number; *vertex1 = v1a; @@ -581,8 +552,7 @@ stl_which_vertices_to_change(stl_file *stl, stl_hash_edge *edge_a, *facet2 = -1; } else { if( (stl->neighbors_start[edge_a->facet_number].neighbor[v2a] == -1) - && (stl->neighbors_start[edge_a->facet_number]. - neighbor[(v2a + 2) % 3] == -1)) { + && (stl->neighbors_start[edge_a->facet_number].neighbor[(v2a + 2) % 3] == -1)) { /* This vertex has no neighbors. This is a good one to change */ *facet2 = edge_a->facet_number; *vertex2 = v2a; @@ -595,140 +565,6 @@ stl_which_vertices_to_change(stl_file *stl, stl_hash_edge *edge_a, } } -static void remove_facet(stl_file *stl, int facet_number) -{ - assert(! stl->error); - ++ stl->stats.facets_removed; - /* 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); - } - - if (facet_number == -- stl->stats.number_of_facets) - // Removing the last face is easy, just forget the last face. - return; - - // Copy the face and neighborship from the last face to facet_number. - stl->facet_start[facet_number] = stl->facet_start[stl->stats.number_of_facets]; - neighbors = stl->neighbors_start[stl->stats.number_of_facets]; - // Update neighborship of faces, which used to point to the last face, now moved to facet_number. - for (int i = 0; i < 3; ++ i) - if (neighbors.neighbor[i] != -1) { - int &other_face_idx = stl->neighbors_start[neighbors.neighbor[i]].neighbor[(neighbors.which_vertex_not[i] + 1) % 3]; - if (other_face_idx != stl->stats.number_of_facets) { - printf("in remove_facet: neighbor = %d numfacets = %d this is wrong\n", other_face_idx, stl->stats.number_of_facets); - return; - } - other_face_idx = facet_number; - } -} - -static void remove_degenerate(stl_file *stl, int facet) -{ - assert(! stl->error); - - // Update statistics on face connectivity. - auto stl_update_connects_remove_1 = [stl](int facet_num) { - assert(! stl->error); - //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); - } - }; - - int edge_to_collapse = 0; - if (stl->facet_start[facet].vertex[0] == stl->facet_start[facet].vertex[1]) { - if (stl->facet_start[facet].vertex[1] == stl->facet_start[facet].vertex[2]) { - // All 3 vertices are equal. Collapse the edge with no neighbor if it exists. - const int *nbr = stl->neighbors_start[facet].neighbor; - edge_to_collapse = (nbr[0] == -1) ? 0 : (nbr[1] == -1) ? 1 : 2; - } else { - edge_to_collapse = 0; - } - } else if (stl->facet_start[facet].vertex[1] == stl->facet_start[facet].vertex[2]) { - edge_to_collapse = 1; - } else if (stl->facet_start[facet].vertex[2] == stl->facet_start[facet].vertex[0]) { - edge_to_collapse = 2; - } else { - // No degenerate. Function shouldn't have been called. - return; - } - - int edge[3] = { (edge_to_collapse + 1) % 3, (edge_to_collapse + 2) % 3, edge_to_collapse }; - int neighbor[] = { - stl->neighbors_start[facet].neighbor[edge[0]], - stl->neighbors_start[facet].neighbor[edge[1]], - stl->neighbors_start[facet].neighbor[edge[2]] - }; - int vnot[] = { - stl->neighbors_start[facet].which_vertex_not[edge[0]], - stl->neighbors_start[facet].which_vertex_not[edge[1]], - stl->neighbors_start[facet].which_vertex_not[edge[2]] - }; - // Update statistics on edge connectivity. - if (neighbor[0] == -1) - stl_update_connects_remove_1(neighbor[1]); - if (neighbor[1] == -1) - stl_update_connects_remove_1(neighbor[0]); - - if (neighbor[0] >= 0) { - if (neighbor[1] >= 0) { - // Adjust the "flip" flag for the which_vertex_not values. - if (vnot[0] > 2) { - if (vnot[1] > 2) { - // The face to be removed has its normal flipped compared to the left & right neighbors, therefore after removing this face - // the two remaining neighbors will be oriented correctly. - vnot[0] -= 3; - vnot[1] -= 3; - } else - // One neighbor has its normal inverted compared to the face to be removed, the other is oriented equally. - // After removal, the two neighbors will have their normals flipped. - vnot[1] += 3; - } else if (vnot[1] > 2) - // One neighbor has its normal inverted compared to the face to be removed, the other is oriented equally. - // After removal, the two neighbors will have their normals flipped. - vnot[0] += 3; - } - stl->neighbors_start[neighbor[0]].neighbor[(vnot[0] + 1) % 3] = (neighbor[0] == neighbor[1]) ? -1 : neighbor[1]; - stl->neighbors_start[neighbor[0]].which_vertex_not[(vnot[0] + 1) % 3] = vnot[1]; - } - if (neighbor[1] >= 0) { - stl->neighbors_start[neighbor[1]].neighbor[(vnot[1] + 1) % 3] = (neighbor[0] == neighbor[1]) ? -1 : neighbor[0]; - 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]); - stl->neighbors_start[neighbor[2]].neighbor[(vnot[2] + 1) % 3] = -1; - } - - remove_facet(stl, facet); -} - void stl_remove_unconnected_facets(stl_file *stl) { // A couple of things need to be done here. One is to remove any completely unconnected facets (0 edges connected) since these are @@ -737,12 +573,143 @@ void stl_remove_unconnected_facets(stl_file *stl) if (stl->error) return; + auto remove_facet = [stl](int facet_number) + { + ++ stl->stats.facets_removed; + /* 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); + } + + if (facet_number == -- stl->stats.number_of_facets) + // Removing the last face is easy, just forget the last face. + return; + + // Copy the face and neighborship from the last face to facet_number. + stl->facet_start[facet_number] = stl->facet_start[stl->stats.number_of_facets]; + neighbors = stl->neighbors_start[stl->stats.number_of_facets]; + // Update neighborship of faces, which used to point to the last face, now moved to facet_number. + for (int i = 0; i < 3; ++ i) + if (neighbors.neighbor[i] != -1) { + int &other_face_idx = stl->neighbors_start[neighbors.neighbor[i]].neighbor[(neighbors.which_vertex_not[i] + 1) % 3]; + if (other_face_idx != stl->stats.number_of_facets) { + printf("in remove_facet: neighbor = %d numfacets = %d this is wrong\n", other_face_idx, stl->stats.number_of_facets); + return; + } + other_face_idx = facet_number; + } + }; + + auto remove_degenerate = [stl, remove_facet](int facet) + { + // Update statistics on face connectivity. + auto stl_update_connects_remove_1 = [stl](int facet_num) { + assert(! stl->error); + //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); + } + }; + + int edge_to_collapse = 0; + if (stl->facet_start[facet].vertex[0] == stl->facet_start[facet].vertex[1]) { + if (stl->facet_start[facet].vertex[1] == stl->facet_start[facet].vertex[2]) { + // All 3 vertices are equal. Collapse the edge with no neighbor if it exists. + const int *nbr = stl->neighbors_start[facet].neighbor; + edge_to_collapse = (nbr[0] == -1) ? 0 : (nbr[1] == -1) ? 1 : 2; + } else { + edge_to_collapse = 0; + } + } else if (stl->facet_start[facet].vertex[1] == stl->facet_start[facet].vertex[2]) { + edge_to_collapse = 1; + } else if (stl->facet_start[facet].vertex[2] == stl->facet_start[facet].vertex[0]) { + edge_to_collapse = 2; + } else { + // No degenerate. Function shouldn't have been called. + return; + } + + int edge[3] = { (edge_to_collapse + 1) % 3, (edge_to_collapse + 2) % 3, edge_to_collapse }; + int neighbor[] = { + stl->neighbors_start[facet].neighbor[edge[0]], + stl->neighbors_start[facet].neighbor[edge[1]], + stl->neighbors_start[facet].neighbor[edge[2]] + }; + int vnot[] = { + stl->neighbors_start[facet].which_vertex_not[edge[0]], + stl->neighbors_start[facet].which_vertex_not[edge[1]], + stl->neighbors_start[facet].which_vertex_not[edge[2]] + }; + // Update statistics on edge connectivity. + if (neighbor[0] == -1) + stl_update_connects_remove_1(neighbor[1]); + if (neighbor[1] == -1) + stl_update_connects_remove_1(neighbor[0]); + + if (neighbor[0] >= 0) { + if (neighbor[1] >= 0) { + // Adjust the "flip" flag for the which_vertex_not values. + if (vnot[0] > 2) { + if (vnot[1] > 2) { + // The face to be removed has its normal flipped compared to the left & right neighbors, therefore after removing this face + // the two remaining neighbors will be oriented correctly. + vnot[0] -= 3; + vnot[1] -= 3; + } else + // One neighbor has its normal inverted compared to the face to be removed, the other is oriented equally. + // After removal, the two neighbors will have their normals flipped. + vnot[1] += 3; + } else if (vnot[1] > 2) + // One neighbor has its normal inverted compared to the face to be removed, the other is oriented equally. + // After removal, the two neighbors will have their normals flipped. + vnot[0] += 3; + } + stl->neighbors_start[neighbor[0]].neighbor[(vnot[0] + 1) % 3] = (neighbor[0] == neighbor[1]) ? -1 : neighbor[1]; + stl->neighbors_start[neighbor[0]].which_vertex_not[(vnot[0] + 1) % 3] = vnot[1]; + } + if (neighbor[1] >= 0) { + stl->neighbors_start[neighbor[1]].neighbor[(vnot[1] + 1) % 3] = (neighbor[0] == neighbor[1]) ? -1 : neighbor[0]; + 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]); + stl->neighbors_start[neighbor[2]].neighbor[(vnot[2] + 1) % 3] = -1; + } + + remove_facet(facet); + }; + // remove degenerate facets for (uint32_t i = 0; i < stl->stats.number_of_facets;) if (stl->facet_start[i].vertex[0] == stl->facet_start[i].vertex[1] || stl->facet_start[i].vertex[0] == stl->facet_start[i].vertex[2] || stl->facet_start[i].vertex[1] == stl->facet_start[i].vertex[2]) { - remove_degenerate(stl, i); + remove_degenerate(i); // assert(stl_validate(stl)); } else ++ i; @@ -754,7 +721,7 @@ void stl_remove_unconnected_facets(stl_file *stl) stl->neighbors_start[i].neighbor[1] == -1 && stl->neighbors_start[i].neighbor[2] == -1) { // This facet is completely unconnected. Remove it. - remove_facet(stl, i); + remove_facet(i); assert(stl_validate(stl)); } else ++ i; @@ -850,8 +817,7 @@ stl_fill_holes(stl_file *stl) { } break; } else { - vnot = stl->neighbors_start[facet_num]. - which_vertex_not[next_edge]; + vnot = stl->neighbors_start[facet_num].which_vertex_not[next_edge]; facet_num = next_facet; } @@ -867,27 +833,14 @@ Try using a smaller tolerance or don't do a nearby check\n"); } } -void -stl_add_facet(stl_file *stl, stl_facet *new_facet) { - if (stl->error) return; - - stl->stats.facets_added += 1; - if(stl->stats.facets_malloced < (int)stl->stats.number_of_facets + 1) { - stl->facet_start = (stl_facet*)realloc(stl->facet_start, - (sizeof(stl_facet) * (stl->stats.facets_malloced + 256))); - if(stl->facet_start == NULL) perror("stl_add_facet"); - stl->neighbors_start = (stl_neighbors*)realloc(stl->neighbors_start, - (sizeof(stl_neighbors) * (stl->stats.facets_malloced + 256))); - if(stl->neighbors_start == NULL) perror("stl_add_facet"); - stl->stats.facets_malloced += 256; - } - stl->facet_start[stl->stats.number_of_facets] = *new_facet; - - /* note that the normal vector is not set here, just initialized to 0 */ - stl->facet_start[stl->stats.number_of_facets].normal = stl_normal::Zero(); - - stl->neighbors_start[stl->stats.number_of_facets].neighbor[0] = -1; - stl->neighbors_start[stl->stats.number_of_facets].neighbor[1] = -1; - stl->neighbors_start[stl->stats.number_of_facets].neighbor[2] = -1; - stl->stats.number_of_facets += 1; +void stl_add_facet(stl_file *stl, const stl_facet *new_facet) +{ + if (stl->error) + return; + ++ stl->stats.facets_added; + ++ stl->stats.number_of_facets; + stl->facet_start.emplace_back(*new_facet); + // note that the normal vector is not set here, just initialized to 0. + stl->facet_start[stl->stats.number_of_facets].normal = stl_normal::Zero(); + stl->neighbors_start.emplace_back(); } diff --git a/src/admesh/normals.cpp b/src/admesh/normals.cpp index ecf08b59c..e11f1a3c1 100644 --- a/src/admesh/normals.cpp +++ b/src/admesh/normals.cpp @@ -84,7 +84,6 @@ stl_reverse_facet(stl_file *stl, int facet_num) { void stl_fix_normal_directions(stl_file *stl) { - char *norm_sw; /* int edge_num;*/ /* int vnot;*/ int checked = 0; @@ -101,7 +100,6 @@ stl_fix_normal_directions(stl_file *stl) { struct stl_normal *newn; struct stl_normal *temp; - int* reversed_ids; int reversed_count = 0; int id; int force_exit = 0; @@ -112,20 +110,15 @@ stl_fix_normal_directions(stl_file *stl) { if (stl->stats.number_of_facets == 0) return; /* Initialize linked list. */ - head = (struct stl_normal*)malloc(sizeof(struct stl_normal)); - if(head == NULL) perror("stl_fix_normal_directions"); - tail = (struct stl_normal*)malloc(sizeof(struct stl_normal)); - if(tail == NULL) perror("stl_fix_normal_directions"); + head = new stl_normal; + tail = new stl_normal; head->next = tail; tail->next = tail; /* Initialize list that keeps track of already fixed facets. */ - norm_sw = (char*)calloc(stl->stats.number_of_facets, sizeof(char)); - if(norm_sw == NULL) perror("stl_fix_normal_directions"); - + std::vector norm_sw(stl->stats.number_of_facets, 0); /* Initialize list that keeps track of reversed facets. */ - reversed_ids = (int*)calloc(stl->stats.number_of_facets, sizeof(int)); - if (reversed_ids == NULL) perror("stl_fix_normal_directions reversed_ids"); + std::vector reversed_ids(stl->stats.number_of_facets, 0); facet_num = 0; /* If normal vector is not within tolerance and backwards: @@ -166,8 +159,7 @@ stl_fix_normal_directions(stl_file *stl) { /* If we haven't fixed this facet yet, add it to the list: */ if(norm_sw[stl->neighbors_start[facet_num].neighbor[j]] != 1) { /* Add node to beginning of list. */ - newn = (struct stl_normal*)malloc(sizeof(struct stl_normal)); - if(newn == NULL) perror("stl_fix_normal_directions"); + newn = new stl_normal; newn->facet_num = stl->neighbors_start[facet_num].neighbor[j]; newn->next = head->next; head->next = newn; @@ -187,7 +179,7 @@ stl_fix_normal_directions(stl_file *stl) { } temp = head->next; /* Delete this facet from the list. */ head->next = head->next->next; - free(temp); + delete temp; } else { /* if we ran out of facets to fix: */ /* All of the facets in this part have been fixed. */ stl->stats.number_of_parts += 1; @@ -213,10 +205,8 @@ stl_fix_normal_directions(stl_file *stl) { } } } - free(head); - free(tail); - free(reversed_ids); - free(norm_sw); + delete head; + delete tail; } static int stl_check_normal_vector(stl_file *stl, int facet_num, int normal_fix_flag) { diff --git a/src/admesh/shared.cpp b/src/admesh/shared.cpp index 2ad270903..8162c6a8d 100644 --- a/src/admesh/shared.cpp +++ b/src/admesh/shared.cpp @@ -31,17 +31,8 @@ void stl_invalidate_shared_vertices(stl_file *stl) { - if (stl->error) - return; - - if (stl->v_indices != nullptr) { - free(stl->v_indices); - stl->v_indices = nullptr; - } - if (stl->v_shared != nullptr) { - free(stl->v_shared); - stl->v_shared = nullptr; - } + stl->v_indices.clear(); + stl->v_shared.clear(); } void stl_generate_shared_vertices(stl_file *stl) @@ -53,23 +44,11 @@ void stl_generate_shared_vertices(stl_file *stl) stl_invalidate_shared_vertices(stl); // 3 indices to vertex per face - stl->v_indices = (v_indices_struct*)calloc(stl->stats.number_of_facets, sizeof(v_indices_struct)); - if (stl->v_indices == nullptr) - perror("stl_generate_shared_vertices"); + stl->v_indices.assign(stl->stats.number_of_facets, v_indices_struct()); // Shared vertices (3D coordinates) - stl->v_shared = (stl_vertex*)calloc((stl->stats.number_of_facets / 2), sizeof(stl_vertex)); - if (stl->v_shared == nullptr) - perror("stl_generate_shared_vertices"); - stl->stats.shared_malloced = stl->stats.number_of_facets / 2; + stl->v_shared.assign(stl->stats.number_of_facets / 2, stl_vertex()); stl->stats.shared_vertices = 0; - for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) { - // vertex index -1 means no shared vertex was assigned yet. - stl->v_indices[i].vertex[0] = -1; - stl->v_indices[i].vertex[1] = -1; - stl->v_indices[i].vertex[2] = -1; - } - // A degenerate mesh may contain loops: Traversing a fan will end up in an endless loop // while never reaching the starting face. To avoid these endless loops, traversed faces at each fan traversal // are marked with a unique fan_traversal_stamp. @@ -82,13 +61,7 @@ void stl_generate_shared_vertices(stl_file *stl) // Shared vertex was already assigned. continue; // Create a new shared vertex. - if (stl->stats.shared_vertices == stl->stats.shared_malloced) { - stl->stats.shared_malloced += 1024; - stl->v_shared = (stl_vertex*)realloc(stl->v_shared, stl->stats.shared_malloced * sizeof(stl_vertex)); - if(stl->v_shared == nullptr) - perror("stl_generate_shared_vertices"); - } - stl->v_shared[stl->stats.shared_vertices] = stl->facet_start[facet_idx].vertex[j]; + stl->v_shared.emplace_back(stl->facet_start[facet_idx].vertex[j]); // Traverse the fan around the j-th vertex of the i-th face, assign the newly created shared vertex index to all the neighboring triangles in the triangle fan. int facet_in_fan_idx = facet_idx; bool edge_direction = false; diff --git a/src/admesh/stl.h b/src/admesh/stl.h index 5ecd94bd1..345951121 100644 --- a/src/admesh/stl.h +++ b/src/admesh/stl.h @@ -27,6 +27,7 @@ #include #include +#include #include // Size of the binary STL header, free form. @@ -44,18 +45,18 @@ static_assert(sizeof(stl_vertex) == 12, "size of stl_vertex incorrect"); static_assert(sizeof(stl_normal) == 12, "size of stl_normal incorrect"); struct stl_facet { - stl_normal normal; - stl_vertex vertex[3]; - char extra[2]; + stl_normal normal; + stl_vertex vertex[3]; + char extra[2]; - stl_facet rotated(const Eigen::Quaternion &rot) { - stl_facet out; - out.normal = rot * this->normal; - out.vertex[0] = rot * this->vertex[0]; - out.vertex[1] = rot * this->vertex[1]; - out.vertex[2] = rot * this->vertex[2]; - return out; - } + stl_facet rotated(const Eigen::Quaternion &rot) const { + stl_facet out; + out.normal = rot * this->normal; + out.vertex[0] = rot * this->vertex[0]; + out.vertex[1] = rot * this->vertex[1]; + out.vertex[2] = rot * this->vertex[2]; + return out; + } }; #define SIZEOF_STL_FACET 50 @@ -67,86 +68,100 @@ static_assert(sizeof(stl_facet) >= SIZEOF_STL_FACET, "size of stl_facet incorrec typedef enum {binary, ascii, inmemory} stl_type; -typedef struct { - stl_vertex p1; - stl_vertex p2; - int facet_number; -} stl_edge; +struct stl_edge { + stl_vertex p1; + stl_vertex p2; + int facet_number; +}; -typedef struct stl_hash_edge { - // Key of a hash edge: sorted vertices of the edge. - uint32_t key[6]; - // Compare two keys. - bool operator==(const stl_hash_edge &rhs) { return memcmp(key, rhs.key, sizeof(key)) == 0; } - bool operator!=(const stl_hash_edge &rhs) { return ! (*this == rhs); } - int hash(int M) const { return ((key[0] / 11 + key[1] / 7 + key[2] / 3) ^ (key[3] / 11 + key[4] / 7 + key[5] / 3)) % M; } - // Index of a facet owning this edge. - int facet_number; - // Index of this edge inside the facet with an index of facet_number. - // If this edge is stored backwards, which_edge is increased by 3. - int which_edge; - struct stl_hash_edge *next; -} stl_hash_edge; +struct stl_hash_edge { + // Key of a hash edge: sorted vertices of the edge. + uint32_t key[6]; + // Compare two keys. + bool operator==(const stl_hash_edge &rhs) { return memcmp(key, rhs.key, sizeof(key)) == 0; } + bool operator!=(const stl_hash_edge &rhs) { return ! (*this == rhs); } + int hash(int M) const { return ((key[0] / 11 + key[1] / 7 + key[2] / 3) ^ (key[3] / 11 + key[4] / 7 + key[5] / 3)) % M; } + // Index of a facet owning this edge. + int facet_number; + // Index of this edge inside the facet with an index of facet_number. + // If this edge is stored backwards, which_edge is increased by 3. + int which_edge; + struct stl_hash_edge *next; +}; -typedef struct { - // Index of a neighbor facet. - int neighbor[3]; - // Index of an opposite vertex at the neighbor face. - char which_vertex_not[3]; -} stl_neighbors; +struct stl_neighbors { + stl_neighbors() { reset(); } + void reset() { + neighbor[0] = -1; + neighbor[1] = -1; + neighbor[2] = -1; + which_vertex_not[0] = -1; + which_vertex_not[1] = -1; + which_vertex_not[2] = -1; + } -typedef struct { - int vertex[3]; -} v_indices_struct; + // Index of a neighbor facet. + int neighbor[3]; + // Index of an opposite vertex at the neighbor face. + char which_vertex_not[3]; +}; -typedef struct { - char header[81]; - stl_type type; - uint32_t number_of_facets; - stl_vertex max; - stl_vertex min; - stl_vertex size; - float bounding_diameter; - float shortest_edge; - float volume; - unsigned number_of_blocks; - int connected_edges; - int connected_facets_1_edge; - int connected_facets_2_edge; - int connected_facets_3_edge; - int facets_w_1_bad_edge; - int facets_w_2_bad_edge; - int facets_w_3_bad_edge; - int original_num_facets; - int edges_fixed; - int degenerate_facets; - int facets_removed; - int facets_added; - int facets_reversed; - int backwards_edges; - int normals_fixed; - int number_of_parts; - int malloced; - int freed; - int facets_malloced; - int collisions; - int shared_vertices; - int shared_malloced; -} stl_stats; +struct v_indices_struct { + // -1 means no vertex index has been assigned yet + v_indices_struct() { vertex[0] = -1; vertex[1] = -1; vertex[2] = -1; } + int vertex[3]; +}; -typedef struct { - FILE *fp; - stl_facet *facet_start; - stl_hash_edge **heads; - stl_hash_edge *tail; - int M; - stl_neighbors *neighbors_start; - v_indices_struct *v_indices; - stl_vertex *v_shared; - stl_stats stats; - char error; -} stl_file; +struct stl_stats { + char header[81]; + stl_type type; + uint32_t number_of_facets; + stl_vertex max; + stl_vertex min; + stl_vertex size; + float bounding_diameter; + float shortest_edge; + float volume; + unsigned number_of_blocks; + int connected_edges; + int connected_facets_1_edge; + int connected_facets_2_edge; + int connected_facets_3_edge; + int facets_w_1_bad_edge; + int facets_w_2_bad_edge; + int facets_w_3_bad_edge; + int original_num_facets; + int edges_fixed; + int degenerate_facets; + int facets_removed; + int facets_added; + int facets_reversed; + int backwards_edges; + int normals_fixed; + int number_of_parts; + int shared_vertices; + // hash table statistics + int malloced; + int freed; + int collisions; +}; + +struct stl_file { + FILE *fp; + std::vector facet_start; + std::vector neighbors_start; + // Hash table on edges + std::vector heads; + stl_hash_edge* tail; + int M; + // Indexed face set + std::vector v_indices; + std::vector v_shared; + // Statistics + stl_stats stats; + char error; +}; extern void stl_open(stl_file *stl, const char *file); extern void stl_close(stl_file *stl); @@ -272,7 +287,7 @@ extern void stl_allocate(stl_file *stl); extern void stl_read(stl_file *stl, int first_facet, bool first); extern void stl_facet_stats(stl_file *stl, stl_facet facet, bool &first); extern void stl_reallocate(stl_file *stl); -extern void stl_add_facet(stl_file *stl, stl_facet *new_facet); +extern void stl_add_facet(stl_file *stl, const stl_facet *new_facet); extern void stl_clear_error(stl_file *stl); extern int stl_get_error(stl_file *stl); diff --git a/src/admesh/stl_io.cpp b/src/admesh/stl_io.cpp index 85f66785b..81060c0a3 100644 --- a/src/admesh/stl_io.cpp +++ b/src/admesh/stl_io.cpp @@ -109,7 +109,6 @@ Normals fixed : %5d\n", stl->stats.normals_fixed); void stl_write_ascii(stl_file *stl, const char *file, const char *label) { - int i; char *error_msg; if (stl->error) return; @@ -129,7 +128,7 @@ stl_write_ascii(stl_file *stl, const char *file, const char *label) { fprintf(fp, "solid %s\n", label); - for(i = 0; i < stl->stats.number_of_facets; i++) { + for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) { fprintf(fp, " facet normal % .8E % .8E % .8E\n", stl->facet_start[i].normal(0), stl->facet_start[i].normal(1), stl->facet_start[i].normal(2)); @@ -154,7 +153,6 @@ stl_write_ascii(stl_file *stl, const char *file, const char *label) { void stl_print_neighbors(stl_file *stl, char *file) { - int i; FILE *fp; char *error_msg; @@ -173,7 +171,7 @@ stl_print_neighbors(stl_file *stl, char *file) { return; } - for(i = 0; i < stl->stats.number_of_facets; i++) { + for (uint32_t i = 0; i < stl->stats.number_of_facets; i++) { fprintf(fp, "%d, %d,%d, %d,%d, %d,%d\n", i, stl->neighbors_start[i].neighbor[0], @@ -200,7 +198,6 @@ void stl_internal_reverse_quads(char *buf, size_t cnt) void stl_write_binary(stl_file *stl, const char *file, const char *label) { FILE *fp; - int i; char *error_msg; if (stl->error) return; @@ -219,13 +216,13 @@ stl_write_binary(stl_file *stl, const char *file, const char *label) { } fprintf(fp, "%s", label); - for(i = strlen(label); i < LABEL_SIZE; i++) putc(0, fp); + for(size_t i = strlen(label); i < LABEL_SIZE; i++) putc(0, fp); fseek(fp, LABEL_SIZE, SEEK_SET); #ifdef BOOST_LITTLE_ENDIAN fwrite(&stl->stats.number_of_facets, 4, 1, fp); - for (i = 0; i < stl->stats.number_of_facets; ++ i) - fwrite(stl->facet_start + i, SIZEOF_STL_FACET, 1, fp); + for (const stl_facet &facet : stl->facet_start) + fwrite(&facet, SIZEOF_STL_FACET, 1, fp); #else /* BOOST_LITTLE_ENDIAN */ char buffer[50]; // Convert the number of facets to little endian. @@ -288,8 +285,6 @@ stl_write_neighbor(stl_file *stl, int facet) { void stl_write_quad_object(stl_file *stl, char *file) { FILE *fp; - int i; - int j; char *error_msg; stl_vertex connect_color = stl_vertex::Zero(); stl_vertex uncon_1_color = stl_vertex::Zero(); @@ -313,10 +308,10 @@ stl_write_quad_object(stl_file *stl, char *file) { } fprintf(fp, "CQUAD\n"); - for(i = 0; i < stl->stats.number_of_facets; i++) { - j = ((stl->neighbors_start[i].neighbor[0] == -1) + - (stl->neighbors_start[i].neighbor[1] == -1) + - (stl->neighbors_start[i].neighbor[2] == -1)); + for (uint32_t i = 0; i < stl->stats.number_of_facets; i++) { + int j = ((stl->neighbors_start[i].neighbor[0] == -1) + + (stl->neighbors_start[i].neighbor[1] == -1) + + (stl->neighbors_start[i].neighbor[2] == -1)); if(j == 0) { color = connect_color; } else if(j == 1) { @@ -346,9 +341,8 @@ stl_write_quad_object(stl_file *stl, char *file) { fclose(fp); } -void -stl_write_dxf(stl_file *stl, const char *file, char *label) { - int i; +void stl_write_dxf(stl_file *stl, const char *file, char *label) +{ FILE *fp; char *error_msg; @@ -375,7 +369,7 @@ stl_write_dxf(stl_file *stl, const char *file, char *label) { fprintf(fp, "0\nSECTION\n2\nENTITIES\n"); - for(i = 0; i < stl->stats.number_of_facets; i++) { + for (uint32_t i = 0; i < stl->stats.number_of_facets; i++) { fprintf(fp, "0\n3DFACE\n8\n0\n"); fprintf(fp, "10\n%f\n20\n%f\n30\n%f\n", stl->facet_start[i].vertex[0](0), stl->facet_start[i].vertex[0](1), diff --git a/src/admesh/stlinit.cpp b/src/admesh/stlinit.cpp index 911f4f5e8..81b7914c3 100644 --- a/src/admesh/stlinit.cpp +++ b/src/admesh/stlinit.cpp @@ -35,22 +35,38 @@ #error "SEEK_SET not defined" #endif -void -stl_open(stl_file *stl, const char *file) { - stl_initialize(stl); - stl_count_facets(stl, file); - stl_allocate(stl); - stl_read(stl, 0, true); - if (stl->fp != nullptr) { - fclose(stl->fp); - stl->fp = nullptr; - } +void stl_open(stl_file *stl, const char *file) +{ + stl_initialize(stl); + stl_count_facets(stl, file); + stl_allocate(stl); + stl_read(stl, 0, true); + if (stl->fp != nullptr) { + fclose(stl->fp); + stl->fp = nullptr; + } } -void -stl_initialize(stl_file *stl) { - memset(stl, 0, sizeof(stl_file)); - stl->stats.volume = -1.0; +void stl_initialize(stl_file *stl) +{ + stl->fp = nullptr; + stl->tail = nullptr; + stl->M = 0; + stl->error = 0; + stl->facet_start.clear(); + stl->neighbors_start.clear(); + stl->v_indices.clear(); + stl->v_shared.clear(); + memset(&stl->stats, 0, sizeof(stl_stats)); + stl->stats.volume = -1.0; +} + +void stl_close(stl_file *stl) +{ + assert(stl->fp == nullptr); + assert(stl->heads.empty()); + assert(stl->tail == nullptr); + stl_initialize(stl); } #ifndef BOOST_LITTLE_ENDIAN @@ -175,20 +191,14 @@ stl_count_facets(stl_file *stl, const char *file) { stl->stats.original_num_facets = stl->stats.number_of_facets; } -void -stl_allocate(stl_file *stl) { - if (stl->error) return; - - /* Allocate memory for the entire .STL file */ - stl->facet_start = (stl_facet*)calloc(stl->stats.number_of_facets, - sizeof(stl_facet)); - if(stl->facet_start == NULL) perror("stl_initialize"); - stl->stats.facets_malloced = stl->stats.number_of_facets; - - /* Allocate memory for the neighbors list */ - stl->neighbors_start = (stl_neighbors*) - calloc(stl->stats.number_of_facets, sizeof(stl_neighbors)); - if(stl->facet_start == NULL) perror("stl_initialize"); +void stl_allocate(stl_file *stl) +{ + if (stl->error) + return; + // Allocate memory for the entire .STL file. + stl->facet_start.assign(stl->stats.number_of_facets, stl_facet()); + // Allocate memory for the neighbors list. + stl->neighbors_start.assign(stl->stats.number_of_facets, stl_neighbors()); } void @@ -237,23 +247,14 @@ stl_open_merge(stl_file *stl, char *file_to_merge) { stl->fp=origFp; } -extern void -stl_reallocate(stl_file *stl) { - if (stl->error) return; - /* Reallocate more memory for the .STL file(s) */ - stl->facet_start = (stl_facet*)realloc(stl->facet_start, stl->stats.number_of_facets * - sizeof(stl_facet)); - if(stl->facet_start == NULL) perror("stl_initialize"); - stl->stats.facets_malloced = stl->stats.number_of_facets; - - /* Reallocate more memory for the neighbors list */ - stl->neighbors_start = (stl_neighbors*) - realloc(stl->neighbors_start, stl->stats.number_of_facets * - sizeof(stl_neighbors)); - if(stl->facet_start == NULL) perror("stl_initialize"); +void stl_reallocate(stl_file *stl) +{ + if (stl->error) + return; + stl->facet_start.resize(stl->stats.number_of_facets); + stl->neighbors_start.resize(stl->stats.number_of_facets); } - /* Reads the contents of the file pointed to by stl->fp into the stl structure, starting at facet first_facet. The second argument says if it's our first time running this for the stl and therefore we should reset our max and min stats. */ @@ -366,20 +367,3 @@ void stl_facet_stats(stl_file *stl, stl_facet facet, bool &first) stl->stats.max = stl->stats.max.cwiseMax(facet.vertex[i]); } } - -void stl_close(stl_file *stl) -{ - assert(stl->fp == nullptr); - assert(stl->heads == nullptr); - assert(stl->tail == nullptr); - - if (stl->facet_start != NULL) - free(stl->facet_start); - if (stl->neighbors_start != NULL) - free(stl->neighbors_start); - if (stl->v_indices != NULL) - free(stl->v_indices); - if (stl->v_shared != NULL) - free(stl->v_shared); - memset(stl, 0, sizeof(stl_file)); -} diff --git a/src/admesh/util.cpp b/src/admesh/util.cpp index c2d2c2726..61e0d11e7 100644 --- a/src/admesh/util.cpp +++ b/src/admesh/util.cpp @@ -32,45 +32,39 @@ static float get_area(stl_facet *facet); static float get_volume(stl_file *stl); -void -stl_verify_neighbors(stl_file *stl) { - int i; - int j; - stl_edge edge_a; - stl_edge edge_b; - int neighbor; - int vnot; +void stl_verify_neighbors(stl_file *stl) +{ + if (stl->error) + return; - if (stl->error) return; + stl->stats.backwards_edges = 0; - stl->stats.backwards_edges = 0; - - for(i = 0; i < stl->stats.number_of_facets; i++) { - for(j = 0; j < 3; j++) { - edge_a.p1 = stl->facet_start[i].vertex[j]; - edge_a.p2 = stl->facet_start[i].vertex[(j + 1) % 3]; - neighbor = stl->neighbors_start[i].neighbor[j]; - vnot = stl->neighbors_start[i].which_vertex_not[j]; - - if(neighbor == -1) - continue; /* this edge has no neighbor... Continue. */ - if(vnot < 3) { - edge_b.p1 = stl->facet_start[neighbor].vertex[(vnot + 2) % 3]; - edge_b.p2 = stl->facet_start[neighbor].vertex[(vnot + 1) % 3]; - } else { - stl->stats.backwards_edges += 1; - edge_b.p1 = stl->facet_start[neighbor].vertex[(vnot + 1) % 3]; - edge_b.p2 = stl->facet_start[neighbor].vertex[(vnot + 2) % 3]; - } - if (edge_a.p1 != edge_b.p1 || edge_a.p2 != edge_b.p2) { - /* These edges should match but they don't. Print results. */ - printf("edge %d of facet %d doesn't match edge %d of facet %d\n", - j, i, vnot + 1, neighbor); - stl_write_facet(stl, (char*)"first facet", i); - stl_write_facet(stl, (char*)"second facet", neighbor); - } - } - } + for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) { + for (int j = 0; j < 3; ++ j) { + stl_edge edge_a; + edge_a.p1 = stl->facet_start[i].vertex[j]; + edge_a.p2 = stl->facet_start[i].vertex[(j + 1) % 3]; + int neighbor = stl->neighbors_start[i].neighbor[j]; + if (neighbor == -1) + continue; // this edge has no neighbor... Continue. + int vnot = stl->neighbors_start[i].which_vertex_not[j]; + stl_edge edge_b; + if (vnot < 3) { + edge_b.p1 = stl->facet_start[neighbor].vertex[(vnot + 2) % 3]; + edge_b.p2 = stl->facet_start[neighbor].vertex[(vnot + 1) % 3]; + } else { + stl->stats.backwards_edges += 1; + edge_b.p1 = stl->facet_start[neighbor].vertex[(vnot + 1) % 3]; + edge_b.p2 = stl->facet_start[neighbor].vertex[(vnot + 2) % 3]; + } + if (edge_a.p1 != edge_b.p1 || edge_a.p2 != edge_b.p2) { + // These edges should match but they don't. Print results. + printf("edge %d of facet %d doesn't match edge %d of facet %d\n", j, i, vnot + 1, neighbor); + stl_write_facet(stl, (char*)"first facet", i); + stl_write_facet(stl, (char*)"second facet", neighbor); + } + } + } } void stl_translate(stl_file *stl, float x, float y, float z) @@ -263,21 +257,19 @@ void stl_mirror_yz(stl_file *stl) void stl_mirror_xz(stl_file *stl) { - if (stl->error) - return; + if (stl->error) + return; - for (int i = 0; i < stl->stats.number_of_facets; i++) { - for (int j = 0; j < 3; j++) { - stl->facet_start[i].vertex[j](1) *= -1.0; - } - } - float temp_size = stl->stats.min(1); - stl->stats.min(1) = stl->stats.max(1); - stl->stats.max(1) = temp_size; - stl->stats.min(1) *= -1.0; - stl->stats.max(1) *= -1.0; - stl_reverse_all_facets(stl); - stl->stats.facets_reversed -= stl->stats.number_of_facets; /* for not altering stats */ + for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) + for (int j = 0; j < 3; ++ j) + stl->facet_start[i].vertex[j](1) *= -1.0; + float temp_size = stl->stats.min(1); + stl->stats.min(1) = stl->stats.max(1); + stl->stats.max(1) = temp_size; + stl->stats.min(1) *= -1.0; + stl->stats.max(1) *= -1.0; + stl_reverse_all_facets(stl); + stl->stats.facets_reversed -= stl->stats.number_of_facets; // for not altering stats } static float get_volume(stl_file *stl) @@ -463,18 +455,18 @@ bool stl_validate(stl_file *stl) { assert(! stl->error); assert(stl->fp == nullptr); - assert(stl->facet_start != nullptr); - assert(stl->heads == nullptr); + assert(! stl->facet_start.empty()); + assert(stl->heads.empty()); assert(stl->tail == nullptr); - assert(stl->neighbors_start != nullptr); - assert((stl->v_indices == nullptr) == (stl->v_shared == nullptr)); + assert(! stl->neighbors_start.empty()); + assert((stl->v_indices.empty()) == (stl->v_shared.empty())); assert(stl->stats.number_of_facets > 0); #ifdef _DEBUG // Verify validity of neighborship data. for (int facet_idx = 0; facet_idx < (int)stl->stats.number_of_facets; ++ facet_idx) { const stl_neighbors &nbr = stl->neighbors_start[facet_idx]; - const int *vertices = (stl->v_indices == nullptr) ? nullptr : stl->v_indices[facet_idx].vertex; + const int *vertices = (stl->v_indices.empty()) ? nullptr : stl->v_indices[facet_idx].vertex; for (int nbr_idx = 0; nbr_idx < 3; ++ nbr_idx) { int nbr_face = stl->neighbors_start[facet_idx].neighbor[nbr_idx]; assert(nbr_face < (int)stl->stats.number_of_facets); diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp index 38b34c462..c3916a14e 100644 --- a/src/libslic3r/Format/3mf.cpp +++ b/src/libslic3r/Format/3mf.cpp @@ -1885,7 +1885,7 @@ namespace Slic3r { volume->mesh.repair(); stl_file& stl = volume->mesh.stl; - if (stl.v_shared == nullptr) + if (stl.v_shared.empty()) stl_generate_shared_vertices(&stl); if (stl.stats.shared_vertices == 0) diff --git a/src/libslic3r/Format/AMF.cpp b/src/libslic3r/Format/AMF.cpp index d26b5f3ed..f48b5b58c 100644 --- a/src/libslic3r/Format/AMF.cpp +++ b/src/libslic3r/Format/AMF.cpp @@ -926,7 +926,7 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config) if (! volume->mesh.repaired) throw std::runtime_error("store_amf() requires repair()"); auto &stl = volume->mesh.stl; - if (stl.v_shared == nullptr) + if (stl.v_shared.empty()) stl_generate_shared_vertices(&stl); const Transform3d& matrix = volume->get_matrix(); for (size_t i = 0; i < stl.stats.shared_vertices; ++i) { diff --git a/src/libslic3r/Format/PRUS.cpp b/src/libslic3r/Format/PRUS.cpp index 502cac6e9..d983b1098 100644 --- a/src/libslic3r/Format/PRUS.cpp +++ b/src/libslic3r/Format/PRUS.cpp @@ -167,10 +167,10 @@ static void extract_model_from_archive( stl.stats.original_num_facets = header.nTriangles; stl_allocate(&stl); if (header.nTriangles > 0 && data.size() == 50 * header.nTriangles + sizeof(StlHeader)) { - memcpy((char*)stl.facet_start, data.data() + sizeof(StlHeader), 50 * header.nTriangles); + memcpy((char*)stl.facet_start.data(), data.data() + sizeof(StlHeader), 50 * header.nTriangles); if (sizeof(stl_facet) > SIZEOF_STL_FACET) { // The stl.facet_start is not packed tightly. Unpack the array of stl_facets. - unsigned char *data = (unsigned char*)stl.facet_start; + unsigned char *data = (unsigned char*)stl.facet_start.data(); for (size_t i = header.nTriangles - 1; i > 0; -- i) memmove(data + i * sizeof(stl_facet), data + i * SIZEOF_STL_FACET, SIZEOF_STL_FACET); } @@ -257,7 +257,7 @@ static void extract_model_from_archive( stl.stats.number_of_facets = (uint32_t)facets.size(); stl.stats.original_num_facets = (int)facets.size(); stl_allocate(&stl); - memcpy((void*)stl.facet_start, facets.data(), facets.size() * 50); + memcpy((void*)stl.facet_start.data(), facets.data(), facets.size() * 50); stl_get_size(&stl); mesh.repair(); // Add a mesh to a model. diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 3b1bd5df2..64fbb9a2a 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -910,18 +910,16 @@ Polygon ModelObject::convex_hull_2d(const Transform3d &trafo_instance) const if (v->is_model_part()) { const stl_file &stl = v->mesh.stl; Transform3d trafo = trafo_instance * v->get_matrix(); - if (stl.v_shared == nullptr) { + if (stl.v_shared.empty()) { // Using the STL faces. - for (unsigned int i = 0; i < stl.stats.number_of_facets; ++ i) { - const stl_facet &facet = stl.facet_start[i]; + for (const stl_facet &facet : stl.facet_start) for (size_t j = 0; j < 3; ++ j) { Vec3d p = trafo * facet.vertex[j].cast(); pts.emplace_back(coord_t(scale_(p.x())), coord_t(scale_(p.y()))); } - } } else { // Using the shared vertices should be a bit quicker than using the STL faces. - for (int i = 0; i < stl.stats.shared_vertices; ++ i) { + for (int i = 0; i < stl.stats.shared_vertices; ++ i) { Vec3d p = trafo * stl.v_shared[i].cast(); pts.emplace_back(coord_t(scale_(p.x())), coord_t(scale_(p.y()))); } @@ -1347,13 +1345,9 @@ double ModelObject::get_instance_min_z(size_t instance_idx) const Transform3d mv = mi * v->get_matrix(); const TriangleMesh& hull = v->get_convex_hull(); - for (uint32_t f = 0; f < hull.stl.stats.number_of_facets; ++f) - { - const stl_facet* facet = hull.stl.facet_start + f; - min_z = std::min(min_z, Vec3d::UnitZ().dot(mv * facet->vertex[0].cast())); - min_z = std::min(min_z, Vec3d::UnitZ().dot(mv * facet->vertex[1].cast())); - min_z = std::min(min_z, Vec3d::UnitZ().dot(mv * facet->vertex[2].cast())); - } + for (const stl_facet &facet : hull.stl.facet_start) + for (int i = 0; i < 3; ++ i) + min_z = std::min(min_z, (mv * facet.vertex[i].cast()).z()); } return min_z + inst->get_offset(Z); diff --git a/src/libslic3r/SLA/SLASupportTreeIGL.cpp b/src/libslic3r/SLA/SLASupportTreeIGL.cpp index c368b8604..1609b9ac4 100644 --- a/src/libslic3r/SLA/SLASupportTreeIGL.cpp +++ b/src/libslic3r/SLA/SLASupportTreeIGL.cpp @@ -121,19 +121,10 @@ EigenMesh3D::EigenMesh3D(const TriangleMesh& tmesh): m_aabb(new AABBImpl()) { V.resize(3*stl.stats.number_of_facets, 3); F.resize(stl.stats.number_of_facets, 3); for (unsigned int i = 0; i < stl.stats.number_of_facets; ++i) { - const stl_facet* facet = stl.facet_start+i; - V(3*i+0, 0) = double(facet->vertex[0](0)); - V(3*i+0, 1) = double(facet->vertex[0](1)); - V(3*i+0, 2) = double(facet->vertex[0](2)); - - V(3*i+1, 0) = double(facet->vertex[1](0)); - V(3*i+1, 1) = double(facet->vertex[1](1)); - V(3*i+1, 2) = double(facet->vertex[1](2)); - - V(3*i+2, 0) = double(facet->vertex[2](0)); - V(3*i+2, 1) = double(facet->vertex[2](1)); - V(3*i+2, 2) = double(facet->vertex[2](2)); - + const stl_facet &facet = stl.facet_start[i]; + V.block<1, 3>(3 * i + 0, 0) = facet.vertex[0].cast(); + V.block<1, 3>(3 * i + 1, 0) = facet.vertex[1].cast(); + V.block<1, 3>(3 * i + 2, 0) = facet.vertex[2].cast(); F(i, 0) = int(3*i+0); F(i, 1) = int(3*i+1); F(i, 2) = int(3*i+2); diff --git a/src/libslic3r/SlicingAdaptive.cpp b/src/libslic3r/SlicingAdaptive.cpp index 2ef4aec8c..ad03b550b 100644 --- a/src/libslic3r/SlicingAdaptive.cpp +++ b/src/libslic3r/SlicingAdaptive.cpp @@ -27,8 +27,8 @@ void SlicingAdaptive::prepare() nfaces_total += (*it_mesh)->stl.stats.number_of_facets; m_faces.reserve(nfaces_total); for (std::vector::const_iterator it_mesh = m_meshes.begin(); it_mesh != m_meshes.end(); ++ it_mesh) - for (int i = 0; i < (*it_mesh)->stl.stats.number_of_facets; ++ i) - m_faces.push_back((*it_mesh)->stl.facet_start + i); + for (const stl_facet &face : (*it_mesh)->stl.facet_start) + m_faces.emplace_back(&face); // 2) Sort faces lexicographically by their Z span. std::sort(m_faces.begin(), m_faces.end(), [](const stl_facet *f1, const stl_facet *f2) { diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp index b7c6c07a7..ac23abd26 100644 --- a/src/libslic3r/TriangleMesh.cpp +++ b/src/libslic3r/TriangleMesh.cpp @@ -51,7 +51,7 @@ TriangleMesh::TriangleMesh(const Pointf3s &points, const std::vector& f stl.stats.type = inmemory; // count facets and allocate memory - stl.stats.number_of_facets = facets.size(); + stl.stats.number_of_facets = (uint32_t)facets.size(); stl.stats.original_num_facets = stl.stats.number_of_facets; stl_allocate(&stl); @@ -78,25 +78,14 @@ TriangleMesh& TriangleMesh::operator=(const TriangleMesh &other) stl_close(&this->stl); this->stl = other.stl; this->repaired = other.repaired; - this->stl.heads = nullptr; + this->stl.heads.clear(); this->stl.tail = nullptr; this->stl.error = other.stl.error; - if (other.stl.facet_start != nullptr) { - this->stl.facet_start = (stl_facet*)calloc(other.stl.stats.number_of_facets, sizeof(stl_facet)); - std::copy(other.stl.facet_start, other.stl.facet_start + other.stl.stats.number_of_facets, this->stl.facet_start); - } - if (other.stl.neighbors_start != nullptr) { - this->stl.neighbors_start = (stl_neighbors*)calloc(other.stl.stats.number_of_facets, sizeof(stl_neighbors)); - std::copy(other.stl.neighbors_start, other.stl.neighbors_start + other.stl.stats.number_of_facets, this->stl.neighbors_start); - } - if (other.stl.v_indices != nullptr) { - this->stl.v_indices = (v_indices_struct*)calloc(other.stl.stats.number_of_facets, sizeof(v_indices_struct)); - std::copy(other.stl.v_indices, other.stl.v_indices + other.stl.stats.number_of_facets, this->stl.v_indices); - } - if (other.stl.v_shared != nullptr) { - this->stl.v_shared = (stl_vertex*)calloc(other.stl.stats.shared_vertices, sizeof(stl_vertex)); - std::copy(other.stl.v_shared, other.stl.v_shared + other.stl.stats.shared_vertices, this->stl.v_shared); - } + this->stl.facet_start = other.stl.facet_start; + this->stl.neighbors_start = other.stl.neighbors_start; + this->stl.v_indices = other.stl.v_indices; + this->stl.v_shared = other.stl.v_shared; + this->stl.stats = other.stl.stats; return *this; } @@ -125,8 +114,8 @@ void TriangleMesh::repair() // checking nearby //int last_edges_fixed = 0; - float tolerance = stl.stats.shortest_edge; - float increment = stl.stats.bounding_diameter / 10000.0; + float tolerance = (float)stl.stats.shortest_edge; + float increment = (float)stl.stats.bounding_diameter / 10000.0f; int iterations = 2; if (stl.stats.connected_facets_3_edge < (int)stl.stats.number_of_facets) { for (int i = 0; i < iterations; i++) { @@ -444,7 +433,7 @@ TriangleMeshPtrs TriangleMesh::split() const TriangleMesh* mesh = new TriangleMesh; meshes.emplace_back(mesh); mesh->stl.stats.type = inmemory; - mesh->stl.stats.number_of_facets = facets.size(); + mesh->stl.stats.number_of_facets = (uint32_t)facets.size(); mesh->stl.stats.original_num_facets = mesh->stl.stats.number_of_facets; stl_clear_error(&mesh->stl); stl_allocate(&mesh->stl); @@ -486,13 +475,12 @@ ExPolygons TriangleMesh::horizontal_projection() const { Polygons pp; pp.reserve(this->stl.stats.number_of_facets); - for (uint32_t i = 0; i < this->stl.stats.number_of_facets; ++ i) { - stl_facet* facet = &this->stl.facet_start[i]; + for (const stl_facet &facet : this->stl.facet_start) { Polygon p; p.points.resize(3); - p.points[0] = Point::new_scale(facet->vertex[0](0), facet->vertex[0](1)); - p.points[1] = Point::new_scale(facet->vertex[1](0), facet->vertex[1](1)); - p.points[2] = Point::new_scale(facet->vertex[2](0), facet->vertex[2](1)); + p.points[0] = Point::new_scale(facet.vertex[0](0), facet.vertex[0](1)); + p.points[1] = Point::new_scale(facet.vertex[1](0), facet.vertex[1](1)); + p.points[2] = Point::new_scale(facet.vertex[2](0), facet.vertex[2](1)); p.make_counter_clockwise(); // do this after scaling, as winding order might change while doing that pp.emplace_back(p); } @@ -526,17 +514,15 @@ BoundingBoxf3 TriangleMesh::bounding_box() const BoundingBoxf3 TriangleMesh::transformed_bounding_box(const Transform3d &trafo) const { BoundingBoxf3 bbox; - if (stl.v_shared == nullptr) { + if (stl.v_shared.empty()) { // Using the STL faces. - for (size_t i = 0; i < this->facets_count(); ++ i) { - const stl_facet &facet = this->stl.facet_start[i]; + for (const stl_facet &facet : this->stl.facet_start) for (size_t j = 0; j < 3; ++ j) bbox.merge(trafo * facet.vertex[j].cast()); - } } else { // Using the shared vertices should be a bit quicker than using the STL faces. - for (int i = 0; i < stl.stats.shared_vertices; ++ i) - bbox.merge(trafo * this->stl.v_shared[i].cast()); + for (const stl_vertex &v : this->stl.v_shared) + bbox.merge(trafo * v.cast()); } return bbox; } @@ -551,18 +537,12 @@ TriangleMesh TriangleMesh::convex_hull_3d() const std::vector src_vertices; // We will now fill the vector with input points for computation: - stl_facet* facet_ptr = stl.facet_start; - while (facet_ptr < stl.facet_start + stl.stats.number_of_facets) - { - for (int i = 0; i < 3; ++i) - { - const stl_vertex& v = facet_ptr->vertex[i]; + for (const stl_facet &facet : stl.facet_start) + for (int i = 0; i < 3; ++ i) { + const stl_vertex& v = facet.vertex[i]; src_vertices.emplace_back(v(0), v(1), v(2)); } - facet_ptr += 1; - } - // The qhull call: orgQhull::Qhull qhull; qhull.disableOutputStream(); // we want qhull to be quiet @@ -606,7 +586,7 @@ void TriangleMesh::require_shared_vertices() assert(stl_validate(&this->stl)); if (! this->repaired) this->repair(); - if (this->stl.v_shared == nullptr) { + if (this->stl.v_shared.empty()) { BOOST_LOG_TRIVIAL(trace) << "TriangleMeshSlicer::require_shared_vertices - stl_generate_shared_vertices"; stl_generate_shared_vertices(&(this->stl)); } @@ -622,10 +602,9 @@ void TriangleMeshSlicer::init(const TriangleMesh *_mesh, throw_on_cancel_callbac throw_on_cancel(); facets_edges.assign(_mesh->stl.stats.number_of_facets * 3, -1); - v_scaled_shared.assign(_mesh->stl.v_shared, _mesh->stl.v_shared + _mesh->stl.stats.shared_vertices); - // Scale the copied vertices. - for (int i = 0; i < this->mesh->stl.stats.shared_vertices; ++ i) - this->v_scaled_shared[i] *= float(1. / SCALING_FACTOR); + v_scaled_shared.assign(_mesh->stl.v_shared.size(), stl_vertex()); + for (size_t i = 0; i < v_scaled_shared.size(); ++ i) + this->v_scaled_shared[i] = _mesh->stl.v_shared[i] / float(SCALING_FACTOR); // Create a mapping from triangle edge into face. struct EdgeToFace { @@ -814,7 +793,7 @@ void TriangleMeshSlicer::slice(const std::vector &z, std::vector* lines, boost::mutex* lines_mutex, const std::vector &z) const { - const stl_facet &facet = m_use_quaternion ? this->mesh->stl.facet_start[facet_idx].rotated(m_quaternion) : this->mesh->stl.facet_start[facet_idx]; + const stl_facet &facet = m_use_quaternion ? (this->mesh->stl.facet_start.data() + facet_idx)->rotated(m_quaternion) : *(this->mesh->stl.facet_start.data() + facet_idx); // find facet extents const float min_z = fminf(facet.vertex[0](2), fminf(facet.vertex[1](2), facet.vertex[2](2))); @@ -1710,7 +1689,7 @@ void TriangleMeshSlicer::cut(float z, TriangleMesh* upper, TriangleMesh* lower) BOOST_LOG_TRIVIAL(trace) << "TriangleMeshSlicer::cut - slicing object"; float scaled_z = scale_(z); for (uint32_t facet_idx = 0; facet_idx < this->mesh->stl.stats.number_of_facets; ++ facet_idx) { - stl_facet* facet = &this->mesh->stl.facet_start[facet_idx]; + const stl_facet* facet = &this->mesh->stl.facet_start[facet_idx]; // find facet extents float min_z = std::min(facet->vertex[0](2), std::min(facet->vertex[1](2), facet->vertex[2](2))); @@ -1901,10 +1880,10 @@ TriangleMesh make_cylinder(double r, double h, double fa) //FIXME better to discretize an Icosahedron recursively http://www.songho.ca/opengl/gl_sphere.html TriangleMesh make_sphere(double radius, double fa) { - int sectorCount = ceil(2. * M_PI / fa); - int stackCount = ceil(M_PI / fa); - float sectorStep = 2. * M_PI / sectorCount; - float stackStep = M_PI / stackCount; + int sectorCount = int(ceil(2. * M_PI / fa)); + int stackCount = int(ceil(M_PI / fa)); + float sectorStep = float(2. * M_PI / sectorCount); + float stackStep = float(M_PI / stackCount); Pointf3s vertices; vertices.reserve((stackCount - 1) * sectorCount + 2); diff --git a/src/libslic3r/TriangleMesh.hpp b/src/libslic3r/TriangleMesh.hpp index c284f6482..4de1f5989 100644 --- a/src/libslic3r/TriangleMesh.hpp +++ b/src/libslic3r/TriangleMesh.hpp @@ -58,7 +58,7 @@ public: TriangleMeshPtrs split() const; void merge(const TriangleMesh &mesh); ExPolygons horizontal_projection() const; - const float* first_vertex() const { return this->stl.facet_start ? &this->stl.facet_start->vertex[0](0) : nullptr; } + 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; @@ -69,7 +69,7 @@ public: void reset_repair_stats(); bool needed_repair() const; void require_shared_vertices(); - bool has_shared_vertices() const { return stl.v_shared != NULL; } + bool has_shared_vertices() const { return ! stl.v_shared.empty(); } size_t facets_count() const { return this->stl.stats.number_of_facets; } bool empty() const { return this->facets_count() == 0; } bool is_splittable() const; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index d118a6877..ae017f7d1 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -396,10 +396,10 @@ void GLGizmoSlaSupports::update_mesh() V.resize(3 * stl.stats.number_of_facets, 3); F.resize(stl.stats.number_of_facets, 3); for (unsigned int i=0; ivertex[0](0); V(3*i+0, 1) = facet->vertex[0](1); V(3*i+0, 2) = facet->vertex[0](2); - V(3*i+1, 0) = facet->vertex[1](0); V(3*i+1, 1) = facet->vertex[1](1); V(3*i+1, 2) = facet->vertex[1](2); - V(3*i+2, 0) = facet->vertex[2](0); V(3*i+2, 1) = facet->vertex[2](1); V(3*i+2, 2) = facet->vertex[2](2); + const stl_facet &facet = stl.facet_start[i]; + V.block<1, 3>(3 * i + 0, 0) = facet.vertex[0]; + V.block<1, 3>(3 * i + 1, 0) = facet.vertex[1]; + V.block<1, 3>(3 * i + 2, 0) = facet.vertex[2]; F(i, 0) = 3*i+0; F(i, 1) = 3*i+1; F(i, 2) = 3*i+2; From c7ba48a4735cb2f6e98b56999a1b5d7476bde0fb Mon Sep 17 00:00:00 2001 From: bubnikv Date: Wed, 5 Jun 2019 09:54:52 +0200 Subject: [PATCH 03/22] Fix of perl bindings --- xs/xsp/TriangleMesh.xsp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xs/xsp/TriangleMesh.xsp b/xs/xsp/TriangleMesh.xsp index e519f9210..a188e0b8d 100644 --- a/xs/xsp/TriangleMesh.xsp +++ b/xs/xsp/TriangleMesh.xsp @@ -100,7 +100,7 @@ TriangleMesh::vertices() CODE: if (!THIS->repaired) CONFESS("vertices() requires repair()"); - if (THIS->stl.v_shared == NULL) + if (THIS->stl.v_shared.empty()) stl_generate_shared_vertices(&(THIS->stl)); // vertices @@ -124,7 +124,7 @@ TriangleMesh::facets() CODE: if (!THIS->repaired) CONFESS("facets() requires repair()"); - if (THIS->stl.v_shared == NULL) + if (THIS->stl.v_shared.empty()) stl_generate_shared_vertices(&(THIS->stl)); // facets From 025f86ca3f14e35d617ddb6c76dc5d463d5bf11e Mon Sep 17 00:00:00 2001 From: bubnikv Date: Mon, 10 Jun 2019 11:04:09 +0200 Subject: [PATCH 04/22] Fix of the previous refactoring. --- src/admesh/connect.cpp | 8 +++++--- src/admesh/shared.cpp | 3 ++- src/admesh/util.cpp | 5 +++++ src/libslic3r/TriangleMesh.cpp | 35 +++++++++++++++------------------- 4 files changed, 27 insertions(+), 24 deletions(-) diff --git a/src/admesh/connect.cpp b/src/admesh/connect.cpp index b99f93f3d..d35c48aba 100644 --- a/src/admesh/connect.cpp +++ b/src/admesh/connect.cpp @@ -837,10 +837,12 @@ void stl_add_facet(stl_file *stl, const stl_facet *new_facet) { if (stl->error) return; - ++ stl->stats.facets_added; - ++ stl->stats.number_of_facets; - stl->facet_start.emplace_back(*new_facet); + assert(stl->facet_start.size() == stl->stats.number_of_facets); + assert(stl->neighbors_start.size() == stl->stats.number_of_facets); + stl->facet_start.emplace_back(*new_facet); // note that the normal vector is not set here, just initialized to 0. stl->facet_start[stl->stats.number_of_facets].normal = stl_normal::Zero(); stl->neighbors_start.emplace_back(); + ++ stl->stats.facets_added; + ++ stl->stats.number_of_facets; } diff --git a/src/admesh/shared.cpp b/src/admesh/shared.cpp index 8162c6a8d..bc264ee96 100644 --- a/src/admesh/shared.cpp +++ b/src/admesh/shared.cpp @@ -33,6 +33,7 @@ void stl_invalidate_shared_vertices(stl_file *stl) { stl->v_indices.clear(); stl->v_shared.clear(); + stl->stats.shared_vertices = 0; } void stl_generate_shared_vertices(stl_file *stl) @@ -46,7 +47,7 @@ void stl_generate_shared_vertices(stl_file *stl) // 3 indices to vertex per face stl->v_indices.assign(stl->stats.number_of_facets, v_indices_struct()); // Shared vertices (3D coordinates) - stl->v_shared.assign(stl->stats.number_of_facets / 2, stl_vertex()); + stl->v_shared.reserve(stl->stats.number_of_facets / 2); stl->stats.shared_vertices = 0; // A degenerate mesh may contain loops: Traversing a fan will end up in an endless loop diff --git a/src/admesh/util.cpp b/src/admesh/util.cpp index 61e0d11e7..d8640e575 100644 --- a/src/admesh/util.cpp +++ b/src/admesh/util.cpp @@ -456,11 +456,16 @@ bool stl_validate(stl_file *stl) assert(! stl->error); assert(stl->fp == nullptr); assert(! stl->facet_start.empty()); + assert(stl->facet_start.size() == stl->stats.number_of_facets); + assert(stl->neighbors_start.size() == stl->stats.number_of_facets); + assert(stl->facet_start.size() == stl->neighbors_start.size()); assert(stl->heads.empty()); assert(stl->tail == nullptr); assert(! stl->neighbors_start.empty()); assert((stl->v_indices.empty()) == (stl->v_shared.empty())); assert(stl->stats.number_of_facets > 0); + assert(stl->v_shared.size() == stl->stats.shared_vertices); + assert(stl->v_shared.empty() || stl->v_indices.size() == stl->stats.number_of_facets); #ifdef _DEBUG // Verify validity of neighborship data. diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp index a974f5af3..ad12047d2 100644 --- a/src/libslic3r/TriangleMesh.cpp +++ b/src/libslic3r/TriangleMesh.cpp @@ -47,7 +47,6 @@ TriangleMesh::TriangleMesh(const Pointf3s &points, const std::vector& f { stl_initialize(&this->stl); stl_file &stl = this->stl; - stl.error = 0; stl.stats.type = inmemory; // count facets and allocate memory @@ -55,7 +54,7 @@ TriangleMesh::TriangleMesh(const Pointf3s &points, const std::vector& f stl.stats.original_num_facets = stl.stats.number_of_facets; stl_allocate(&stl); - for (uint32_t i = 0; i < stl.stats.number_of_facets; i++) { + for (uint32_t i = 0; i < stl.stats.number_of_facets; ++ i) { stl_facet facet; facet.vertex[0] = points[facets[i](0)].cast(); facet.vertex[1] = points[facets[i](1)].cast(); @@ -76,16 +75,8 @@ TriangleMesh::TriangleMesh(const Pointf3s &points, const std::vector& f TriangleMesh& TriangleMesh::operator=(const TriangleMesh &other) { stl_close(&this->stl); - this->stl = other.stl; - this->repaired = other.repaired; - this->stl.heads.clear(); - this->stl.tail = nullptr; - this->stl.error = other.stl.error; - this->stl.facet_start = other.stl.facet_start; - this->stl.neighbors_start = other.stl.neighbors_start; - this->stl.v_indices = other.stl.v_indices; - this->stl.v_shared = other.stl.v_shared; - this->stl.stats = other.stl.stats; + this->stl = other.stl; + this->repaired = other.repaired; return *this; } @@ -1711,10 +1702,12 @@ void TriangleMeshSlicer::cut(float z, TriangleMesh* upper, TriangleMesh* lower) if (min_z > z || (min_z == z && max_z > z)) { // facet is above the cut plane and does not belong to it - if (upper != NULL) stl_add_facet(&upper->stl, facet); + if (upper != nullptr) + stl_add_facet(&upper->stl, facet); } else if (max_z < z || (max_z == z && min_z < z)) { // facet is below the cut plane and does not belong to it - if (lower != NULL) stl_add_facet(&lower->stl, facet); + if (lower != nullptr) + stl_add_facet(&lower->stl, facet); } else if (min_z < z && max_z > z) { // Facet is cut by the slicing plane. @@ -1761,22 +1754,24 @@ void TriangleMeshSlicer::cut(float z, TriangleMesh* upper, TriangleMesh* lower) quadrilateral[1].vertex[2] = v0v1; if (v0(2) > z) { - if (upper != NULL) stl_add_facet(&upper->stl, &triangle); - if (lower != NULL) { + if (upper != nullptr) + stl_add_facet(&upper->stl, &triangle); + if (lower != nullptr) { stl_add_facet(&lower->stl, &quadrilateral[0]); stl_add_facet(&lower->stl, &quadrilateral[1]); } } else { - if (upper != NULL) { + if (upper != nullptr) { stl_add_facet(&upper->stl, &quadrilateral[0]); stl_add_facet(&upper->stl, &quadrilateral[1]); } - if (lower != NULL) stl_add_facet(&lower->stl, &triangle); + if (lower != nullptr) + stl_add_facet(&lower->stl, &triangle); } } } - if (upper != NULL) { + if (upper != nullptr) { BOOST_LOG_TRIVIAL(trace) << "TriangleMeshSlicer::cut - triangulating upper part"; ExPolygons section; this->make_expolygons_simple(upper_lines, §ion); @@ -1790,7 +1785,7 @@ void TriangleMeshSlicer::cut(float z, TriangleMesh* upper, TriangleMesh* lower) } } - if (lower != NULL) { + if (lower != nullptr) { BOOST_LOG_TRIVIAL(trace) << "TriangleMeshSlicer::cut - triangulating lower part"; ExPolygons section; this->make_expolygons_simple(lower_lines, §ion); From 40b27e8332f5590d3998a2ef6c89bce65a48da27 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Mon, 10 Jun 2019 16:53:08 +0200 Subject: [PATCH 05/22] admesh refactoring: Move the hashing structure out of stl_file --- src/admesh/connect.cpp | 1025 ++++++++++------------- src/admesh/stl.h | 24 +- src/admesh/stl_io.cpp | 13 - src/admesh/stlinit.cpp | 4 - src/admesh/util.cpp | 2 - src/libslic3r/Fill/FillRectilinear3.cpp | 2 +- 6 files changed, 459 insertions(+), 611 deletions(-) diff --git a/src/admesh/connect.cpp b/src/admesh/connect.cpp index d35c48aba..03b13343d 100644 --- a/src/admesh/connect.cpp +++ b/src/admesh/connect.cpp @@ -32,37 +32,363 @@ #include "stl.h" +struct HashEdge { + // Key of a hash edge: sorted vertices of the edge. + uint32_t key[6]; + // Compare two keys. + bool operator==(const HashEdge &rhs) const { return memcmp(key, rhs.key, sizeof(key)) == 0; } + bool operator!=(const HashEdge &rhs) const { return ! (*this == rhs); } + int hash(int M) const { return ((key[0] / 11 + key[1] / 7 + key[2] / 3) ^ (key[3] / 11 + key[4] / 7 + key[5] / 3)) % M; } -static void stl_match_neighbors_nearby(stl_file *stl, - stl_hash_edge *edge_a, stl_hash_edge *edge_b); -static void stl_record_neighbors(stl_file *stl, - stl_hash_edge *edge_a, stl_hash_edge *edge_b); -static void stl_initialize_facet_check_nearby(stl_file *stl); -static void stl_load_edge_exact(stl_file *stl, stl_hash_edge *edge, const stl_vertex *a, const stl_vertex *b); -static int stl_load_edge_nearby(stl_file *stl, stl_hash_edge *edge, - stl_vertex *a, stl_vertex *b, float tolerance); -static void insert_hash_edge(stl_file *stl, stl_hash_edge edge, - void (*match_neighbors)(stl_file *stl, - stl_hash_edge *edge_a, stl_hash_edge *edge_b)); -static int stl_compare_function(stl_hash_edge *edge_a, stl_hash_edge *edge_b); -static void stl_free_edges(stl_file *stl); -static void stl_change_vertices(stl_file *stl, int facet_num, int vnot, - stl_vertex new_vertex); -static void stl_which_vertices_to_change(stl_file *stl, stl_hash_edge *edge_a, - stl_hash_edge *edge_b, int *facet1, int *vertex1, - int *facet2, int *vertex2, - stl_vertex *new_vertex1, stl_vertex *new_vertex2); -extern int stl_check_normal_vector(stl_file *stl, - int facet_num, int normal_fix_flag); + // Index of a facet owning this edge. + int facet_number; + // Index of this edge inside the facet with an index of facet_number. + // If this edge is stored backwards, which_edge is increased by 3. + int which_edge; + struct HashEdge *next; -static inline size_t hash_size_from_nr_faces(const size_t nr_faces) + void load_exact(stl_file *stl, const stl_vertex *a, const stl_vertex *b) + { + { + stl_vertex diff = (*a - *b).cwiseAbs(); + float max_diff = std::max(diff(0), std::max(diff(1), diff(2))); + stl->stats.shortest_edge = std::min(max_diff, stl->stats.shortest_edge); + } + + // Ensure identical vertex ordering of equal edges. + // This method is numerically robust. + if (stl_vertex_lower(*a, *b)) { + } else { + // This edge is loaded backwards. + std::swap(a, b); + this->which_edge += 3; + } + memcpy(&this->key[0], a->data(), sizeof(stl_vertex)); + memcpy(&this->key[3], b->data(), sizeof(stl_vertex)); + // Switch negative zeros to positive zeros, so memcmp will consider them to be equal. + for (size_t i = 0; i < 6; ++ i) { + unsigned char *p = (unsigned char*)(this->key + i); + #ifdef BOOST_LITTLE_ENDIAN + if (p[0] == 0 && p[1] == 0 && p[2] == 0 && p[3] == 0x80) + // Negative zero, switch to positive zero. + p[3] = 0; + #else /* BOOST_LITTLE_ENDIAN */ + if (p[0] == 0x80 && p[1] == 0 && p[2] == 0 && p[3] == 0) + // Negative zero, switch to positive zero. + p[0] = 0; + #endif /* BOOST_LITTLE_ENDIAN */ + } + } + + bool load_nearby(const stl_file *stl, const stl_vertex &a, const stl_vertex &b, float tolerance) + { + // Index of a grid cell spaced by tolerance. + typedef Eigen::Matrix Vec3i; + Vec3i vertex1 = ((a - stl->stats.min) / tolerance).cast(); + Vec3i vertex2 = ((b - stl->stats.min) / tolerance).cast(); + static_assert(sizeof(Vec3i) == 12, "size of Vec3i incorrect"); + + if (vertex1 == vertex2) + // Both vertices hash to the same value + return false; + + // Ensure identical vertex ordering of edges, which vertices land into equal grid cells. + // This method is numerically robust. + if ((vertex1[0] != vertex2[0]) ? + (vertex1[0] < vertex2[0]) : + ((vertex1[1] != vertex2[1]) ? + (vertex1[1] < vertex2[1]) : + (vertex1[2] < vertex2[2]))) { + memcpy(&this->key[0], vertex1.data(), sizeof(stl_vertex)); + memcpy(&this->key[3], vertex2.data(), sizeof(stl_vertex)); + } else { + memcpy(&this->key[0], vertex2.data(), sizeof(stl_vertex)); + memcpy(&this->key[3], vertex1.data(), sizeof(stl_vertex)); + this->which_edge += 3; /* this edge is loaded backwards */ + } + return true; + } +}; + +struct HashTableEdges { + HashTableEdges(size_t number_of_faces) { + this->M = (int)hash_size_from_nr_faces(number_of_faces); + this->heads.assign(this->M, nullptr); + this->tail = new HashEdge; + this->tail->next = this->tail; + for (int i = 0; i < this->M; ++ i) + this->heads[i] = this->tail; + } + ~HashTableEdges() { + for (int i = 0; i < this->M; ++ i) { + for (HashEdge *temp = this->heads[i]; this->heads[i] != this->tail; temp = this->heads[i]) { + this->heads[i] = this->heads[i]->next; + delete temp; + ++ this->freed; + } + } + this->heads.clear(); + delete this->tail; + this->tail = nullptr; + } + + void insert_edge(stl_file *stl, const HashEdge &edge, void (*match_neighbors)(stl_file *stl, const HashEdge &edge_a, const HashEdge &edge_b)) + { + int chain_number = edge.hash(this->M); + HashEdge *link = this->heads[chain_number]; + if (link == this->tail) { + // This list doesn't have any edges currently in it. Add this one. + HashEdge *new_edge = new HashEdge(edge); + ++ this->malloced; + new_edge->next = this->tail; + this->heads[chain_number] = new_edge; + } else if (edges_equal(edge, *link)) { + // This is a match. Record result in neighbors list. + match_neighbors(stl, edge, *link); + // Delete the matched edge from the list. + this->heads[chain_number] = link->next; + delete link; + ++ this->freed; + } else { + // Continue through the rest of the list. + for (;;) { + if (link->next == this->tail) { + // This is the last item in the list. Insert a new edge. + HashEdge *new_edge = new HashEdge; + ++ this->malloced; + *new_edge = edge; + new_edge->next = this->tail; + link->next = new_edge; + ++ this->collisions; + break; + } + if (edges_equal(edge, *link->next)) { + // This is a match. Record result in neighbors list. + match_neighbors(stl, edge, *link->next); + // Delete the matched edge from the list. + HashEdge *temp = link->next; + link->next = link->next->next; + delete temp; + ++ this->freed; + break; + } + // This is not a match. Go to the next link. + link = link->next; + ++ this->collisions; + } + } + } + + // Hash table on edges + std::vector heads; + HashEdge* tail; + int M; + + size_t malloced = 0; + size_t freed = 0; + size_t collisions = 0; + +private: + static inline size_t hash_size_from_nr_faces(const size_t nr_faces) + { + // Good primes for addressing a cca. 30 bit space. + // https://planetmath.org/goodhashtableprimes + static std::vector primes{ 98317, 196613, 393241, 786433, 1572869, 3145739, 6291469, 12582917, 25165843, 50331653, 100663319, 201326611, 402653189, 805306457, 1610612741 }; + // Find a prime number for 50% filling of the shared triangle edges in the mesh. + auto it = std::upper_bound(primes.begin(), primes.end(), nr_faces * 3 * 2 - 1); + return (it == primes.end()) ? primes.back() : *it; + } + + // Edges equal for hashing. Edgesof different facet are allowed to be matched. + static inline bool edges_equal(const HashEdge &edge_a, const HashEdge &edge_b) + { + return edge_a.facet_number != edge_b.facet_number && edge_a == edge_b; + } +}; + +static void record_neighbors(stl_file *stl, const HashEdge &edge_a, const HashEdge &edge_b) { - // Good primes for addressing a cca. 30 bit space. - // https://planetmath.org/goodhashtableprimes - static std::vector primes{ 98317, 196613, 393241, 786433, 1572869, 3145739, 6291469, 12582917, 25165843, 50331653, 100663319, 201326611, 402653189, 805306457, 1610612741 }; - // Find a prime number for 50% filling of the shared triangle edges in the mesh. - auto it = std::upper_bound(primes.begin(), primes.end(), nr_faces * 3 * 2 - 1); - return (it == primes.end()) ? primes.back() : *it; + // Facet a's neighbor is facet b + stl->neighbors_start[edge_a.facet_number].neighbor[edge_a.which_edge % 3] = edge_b.facet_number; /* sets the .neighbor part */ + stl->neighbors_start[edge_a.facet_number].which_vertex_not[edge_a.which_edge % 3] = (edge_b.which_edge + 2) % 3; /* sets the .which_vertex_not part */ + + // Facet b's neighbor is facet a + 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))) { + // 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; + } + + // Count successful connects: + // Total connects: + stl->stats.connected_edges += 2; + // Count individual connects: + switch (stl->neighbors_start[edge_a.facet_number].num_neighbors()) { + 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); + } + switch (stl->neighbors_start[edge_b.facet_number].num_neighbors()) { + 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); + } +} + +static void match_neighbors_nearby(stl_file *stl, const HashEdge &edge_a, const HashEdge &edge_b) +{ + record_neighbors(stl, edge_a, edge_b); + + // Which vertices to change + int facet1 = -1; + int facet2 = -1; + int vertex1, vertex2; + stl_vertex new_vertex1, new_vertex2; + { + int v1a; // pair 1, facet a + int v1b; // pair 1, facet b + int v2a; // pair 2, facet a + int v2b; // pair 2, facet b + // Find first pair. + if (edge_a.which_edge < 3) { + v1a = edge_a.which_edge; + v2a = (edge_a.which_edge + 1) % 3; + } else { + v2a = edge_a.which_edge % 3; + v1a = (edge_a.which_edge + 1) % 3; + } + if (edge_b.which_edge < 3) { + v1b = edge_b.which_edge; + v2b = (edge_b.which_edge + 1) % 3; + } else { + v2b = edge_b.which_edge % 3; + v1b = (edge_b.which_edge + 1) % 3; + } + + // Of the first pair, which vertex, if any, should be changed + if (stl->facet_start[edge_a.facet_number].vertex[v1a] != stl->facet_start[edge_b.facet_number].vertex[v1b]) { + // These facets are different. + if ( (stl->neighbors_start[edge_a.facet_number].neighbor[v1a] == -1) + && (stl->neighbors_start[edge_a.facet_number].neighbor[(v1a + 2) % 3] == -1)) { + // This vertex has no neighbors. This is a good one to change. + facet1 = edge_a.facet_number; + vertex1 = v1a; + new_vertex1 = stl->facet_start[edge_b.facet_number].vertex[v1b]; + } else { + facet1 = edge_b.facet_number; + vertex1 = v1b; + new_vertex1 = stl->facet_start[edge_a.facet_number].vertex[v1a]; + } + } + + // Of the second pair, which vertex, if any, should be changed. + if (stl->facet_start[edge_a.facet_number].vertex[v2a] == stl->facet_start[edge_b.facet_number].vertex[v2b]) { + // These facets are different. + if ( (stl->neighbors_start[edge_a.facet_number].neighbor[v2a] == -1) + && (stl->neighbors_start[edge_a.facet_number].neighbor[(v2a + 2) % 3] == -1)) { + // This vertex has no neighbors. This is a good one to change. + facet2 = edge_a.facet_number; + vertex2 = v2a; + new_vertex2 = stl->facet_start[edge_b.facet_number].vertex[v2b]; + } else { + facet2 = edge_b.facet_number; + vertex2 = v2b; + new_vertex2 = stl->facet_start[edge_a.facet_number].vertex[v2a]; + } + } + } + + auto change_vertices = [stl](int facet_num, int vnot, stl_vertex new_vertex) + { + int first_facet = facet_num; + bool direction = false; + + for (;;) { + int pivot_vertex; + int next_edge; + if (vnot > 2) { + if (direction) { + pivot_vertex = (vnot + 1) % 3; + next_edge = vnot % 3; + } + else { + pivot_vertex = (vnot + 2) % 3; + next_edge = pivot_vertex; + } + direction = !direction; + } + else { + if (direction) { + pivot_vertex = (vnot + 2) % 3; + next_edge = pivot_vertex; + } + else { + pivot_vertex = (vnot + 1) % 3; + next_edge = vnot; + } + } +#if 0 + if (stl->facet_start[facet_num].vertex[pivot_vertex](0) == new_vertex(0) && + stl->facet_start[facet_num].vertex[pivot_vertex](1) == new_vertex(1) && + stl->facet_start[facet_num].vertex[pivot_vertex](2) == new_vertex(2)) + printf("Changing vertex %f,%f,%f: Same !!!\r\n", new_vertex(0), new_vertex(1), new_vertex(2)); + else { + if (stl->facet_start[facet_num].vertex[pivot_vertex](0) != new_vertex(0)) + printf("Changing coordinate x, vertex %e (0x%08x) to %e(0x%08x)\r\n", + stl->facet_start[facet_num].vertex[pivot_vertex](0), + *reinterpret_cast(&stl->facet_start[facet_num].vertex[pivot_vertex](0)), + new_vertex(0), + *reinterpret_cast(&new_vertex(0))); + if (stl->facet_start[facet_num].vertex[pivot_vertex](1) != new_vertex(1)) + printf("Changing coordinate x, vertex %e (0x%08x) to %e(0x%08x)\r\n", + stl->facet_start[facet_num].vertex[pivot_vertex](1), + *reinterpret_cast(&stl->facet_start[facet_num].vertex[pivot_vertex](1)), + new_vertex(1), + *reinterpret_cast(&new_vertex(1))); + if (stl->facet_start[facet_num].vertex[pivot_vertex](2) != new_vertex(2)) + printf("Changing coordinate x, vertex %e (0x%08x) to %e(0x%08x)\r\n", + stl->facet_start[facet_num].vertex[pivot_vertex](2), + *reinterpret_cast(&stl->facet_start[facet_num].vertex[pivot_vertex](2)), + new_vertex(2), + *reinterpret_cast(&new_vertex(2))); + } +#endif + stl->facet_start[facet_num].vertex[pivot_vertex] = new_vertex; + vnot = stl->neighbors_start[facet_num].which_vertex_not[next_edge]; + facet_num = stl->neighbors_start[facet_num].neighbor[next_edge]; + if (facet_num == -1) + break; + + if (facet_num == first_facet) { + // back to the beginning + printf("Back to the first facet changing vertices: probably a mobius part.\nTry using a smaller tolerance or don't do a nearby check\n"); + return; + } + } + }; + + if (facet1 != -1) { + int vnot1 = (facet1 == edge_a.facet_number) ? + (edge_a.which_edge + 2) % 3 : + (edge_b.which_edge + 2) % 3; + if (((vnot1 + 2) % 3) == vertex1) + vnot1 += 3; + change_vertices(facet1, vnot1, new_vertex1); + } + if (facet2 != -1) { + int vnot2 = (facet2 == edge_a.facet_number) ? + (edge_a.which_edge + 2) % 3 : + (edge_b.which_edge + 2) % 3; + if (((vnot2 + 2) % 3) == vertex2) + vnot2 += 3; + change_vertices(facet2, vnot2, new_vertex2); + } + stl->stats.edges_fixed += 2; } // This function builds the neighbors list. No modifications are made @@ -93,30 +419,21 @@ void stl_check_facets_exact(stl_file *stl) } // Initialize hash table. - stl->stats.malloced = 0; - stl->stats.freed = 0; - stl->stats.collisions = 0; - stl->M = (int)hash_size_from_nr_faces(stl->stats.number_of_facets); + HashTableEdges hash_table(stl->stats.number_of_facets); for (auto &neighbor : stl->neighbors_start) neighbor.reset(); - stl->heads.assign(stl->M, nullptr); - stl->tail = new stl_hash_edge; - stl->tail->next = stl->tail; - for (int i = 0; i < stl->M; ++ i) - stl->heads[i] = stl->tail; // Connect neighbor edges. - for (uint32_t i = 0; i < stl->stats.number_of_facets; i++) { + for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) { const stl_facet &facet = stl->facet_start[i]; for (int j = 0; j < 3; ++ j) { - stl_hash_edge edge; + HashEdge edge; edge.facet_number = i; edge.which_edge = j; - stl_load_edge_exact(stl, &edge, &facet.vertex[j], &facet.vertex[(j + 1) % 3]); - insert_hash_edge(stl, edge, stl_record_neighbors); + edge.load_exact(stl, &facet.vertex[j], &facet.vertex[(j + 1) % 3]); + hash_table.insert_edge(stl, edge, record_neighbors); } } - stl_free_edges(stl); #if 0 printf("Number of faces: %d, number of manifold edges: %d, number of connected edges: %d, number of unconnected edges: %d\r\n", @@ -125,444 +442,33 @@ void stl_check_facets_exact(stl_file *stl) #endif } -static void stl_load_edge_exact(stl_file *stl, stl_hash_edge *edge, const stl_vertex *a, const stl_vertex *b) { - - if (stl->error) return; - - { - stl_vertex diff = (*a - *b).cwiseAbs(); - float max_diff = std::max(diff(0), std::max(diff(1), diff(2))); - stl->stats.shortest_edge = std::min(max_diff, stl->stats.shortest_edge); - } - - // Ensure identical vertex ordering of equal edges. - // This method is numerically robust. - if (stl_vertex_lower(*a, *b)) { - } else { - std::swap(a, b); - edge->which_edge += 3; /* this edge is loaded backwards */ - } - memcpy(&edge->key[0], a->data(), sizeof(stl_vertex)); - memcpy(&edge->key[3], b->data(), sizeof(stl_vertex)); - // Switch negative zeros to positive zeros, so memcmp will consider them to be equal. - for (size_t i = 0; i < 6; ++ i) { - unsigned char *p = (unsigned char*)(edge->key + i); -#ifdef BOOST_LITTLE_ENDIAN - if (p[0] == 0 && p[1] == 0 && p[2] == 0 && p[3] == 0x80) - // Negative zero, switch to positive zero. - p[3] = 0; -#else /* BOOST_LITTLE_ENDIAN */ - if (p[0] == 0x80 && p[1] == 0 && p[2] == 0 && p[3] == 0) - // Negative zero, switch to positive zero. - p[0] = 0; -#endif /* BOOST_LITTLE_ENDIAN */ - } -} - -static void insert_hash_edge(stl_file *stl, stl_hash_edge edge, - void (*match_neighbors)(stl_file *stl, - stl_hash_edge *edge_a, stl_hash_edge *edge_b)) -{ - if (stl->error) return; - - int chain_number = edge.hash(stl->M); - stl_hash_edge *link = stl->heads[chain_number]; - - stl_hash_edge *new_edge; - stl_hash_edge *temp; - if(link == stl->tail) { - /* This list doesn't have any edges currently in it. Add this one. */ - new_edge = new stl_hash_edge; - if(new_edge == NULL) perror("insert_hash_edge"); - stl->stats.malloced++; - *new_edge = edge; - new_edge->next = stl->tail; - stl->heads[chain_number] = new_edge; - return; - } else if(!stl_compare_function(&edge, link)) { - /* This is a match. Record result in neighbors list. */ - match_neighbors(stl, &edge, link); - /* Delete the matched edge from the list. */ - stl->heads[chain_number] = link->next; - delete link; - stl->stats.freed++; - return; - } else { - /* Continue through the rest of the list */ - for(;;) { - if(link->next == stl->tail) { - /* This is the last item in the list. Insert a new edge. */ - new_edge = new stl_hash_edge; - if(new_edge == NULL) perror("insert_hash_edge"); - stl->stats.malloced++; - *new_edge = edge; - new_edge->next = stl->tail; - link->next = new_edge; - stl->stats.collisions++; - return; - } else if(!stl_compare_function(&edge, link->next)) { - /* This is a match. Record result in neighbors list. */ - match_neighbors(stl, &edge, link->next); - - /* Delete the matched edge from the list. */ - temp = link->next; - link->next = link->next->next; - delete temp; - stl->stats.freed++; - return; - } else { - /* This is not a match. Go to the next link */ - link = link->next; - stl->stats.collisions++; - } - } - } -} - -// Return 1 if the edges are not matched. -static inline int stl_compare_function(stl_hash_edge *edge_a, stl_hash_edge *edge_b) -{ - // Don't match edges of the same facet - return (edge_a->facet_number == edge_b->facet_number) || (*edge_a != *edge_b); -} - void stl_check_facets_nearby(stl_file *stl, float tolerance) -{ - if (stl->error) - return; - - 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)) { - /* No need to check any further. All facets are connected */ - return; - } - - stl_initialize_facet_check_nearby(stl); - - for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) { - //FIXME is the copy necessary? - stl_facet facet = stl->facet_start[i]; - for (int j = 0; j < 3; j++) { - if(stl->neighbors_start[i].neighbor[j] == -1) { - stl_hash_edge edge; - edge.facet_number = i; - edge.which_edge = j; - if(stl_load_edge_nearby(stl, &edge, &facet.vertex[j], - &facet.vertex[(j + 1) % 3], - tolerance)) { - /* only insert edges that have different keys */ - insert_hash_edge(stl, edge, stl_match_neighbors_nearby); - } - } - } - } - - stl_free_edges(stl); -} - -static int stl_load_edge_nearby(stl_file *stl, stl_hash_edge *edge, stl_vertex *a, stl_vertex *b, float tolerance) -{ - // Index of a grid cell spaced by tolerance. - typedef Eigen::Matrix Vec3i; - Vec3i vertex1 = ((*a - stl->stats.min) / tolerance).cast(); - Vec3i vertex2 = ((*b - stl->stats.min) / tolerance).cast(); - static_assert(sizeof(Vec3i) == 12, "size of Vec3i incorrect"); - - if (vertex1 == vertex2) - // Both vertices hash to the same value - return 0; - - // Ensure identical vertex ordering of edges, which vertices land into equal grid cells. - // This method is numerically robust. - if ((vertex1[0] != vertex2[0]) ? - (vertex1[0] < vertex2[0]) : - ((vertex1[1] != vertex2[1]) ? - (vertex1[1] < vertex2[1]) : - (vertex1[2] < vertex2[2]))) { - memcpy(&edge->key[0], vertex1.data(), sizeof(stl_vertex)); - memcpy(&edge->key[3], vertex2.data(), sizeof(stl_vertex)); - } else { - memcpy(&edge->key[0], vertex2.data(), sizeof(stl_vertex)); - memcpy(&edge->key[3], vertex1.data(), sizeof(stl_vertex)); - edge->which_edge += 3; /* this edge is loaded backwards */ - } - return 1; -} - -static void stl_free_edges(stl_file *stl) -{ - if (stl->error) - return; - - if(stl->stats.malloced != stl->stats.freed) { - for (int i = 0; i < stl->M; i++) { - for (stl_hash_edge *temp = stl->heads[i]; stl->heads[i] != stl->tail; temp = stl->heads[i]) { - stl->heads[i] = stl->heads[i]->next; - delete temp; - ++ stl->stats.freed; - } - } - } - stl->heads.clear(); - delete stl->tail; - stl->tail = nullptr; -} - -static void stl_initialize_facet_check_nearby(stl_file *stl) { if (stl->error) return; - stl->stats.malloced = 0; - stl->stats.freed = 0; - stl->stats.collisions = 0; + 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)) { + // No need to check any further. All facets are connected. + return; + } - /* tolerance = STL_MAX(stl->stats.shortest_edge, tolerance);*/ - /* tolerance = STL_MAX((stl->stats.bounding_diameter / 500000.0), tolerance);*/ - /* tolerance *= 0.5;*/ - stl->M = (int)hash_size_from_nr_faces(stl->stats.number_of_facets); - - stl->heads.assign(stl->M, nullptr); - stl->tail = new stl_hash_edge; - stl->tail->next = stl->tail; - - for (int i = 0; i < stl->M; ++ i) - stl->heads[i] = stl->tail; -} - -static void -stl_record_neighbors(stl_file *stl, - stl_hash_edge *edge_a, stl_hash_edge *edge_b) { - int i; - int j; - - if (stl->error) return; - - /* Facet a's neighbor is facet b */ - stl->neighbors_start[edge_a->facet_number].neighbor[edge_a->which_edge % 3] = edge_b->facet_number; /* sets the .neighbor part */ - stl->neighbors_start[edge_a->facet_number].which_vertex_not[edge_a->which_edge % 3] = (edge_b->which_edge + 2) % 3; /* sets the .which_vertex_not part */ - - /* Facet b's neighbor is facet a */ - 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))) { - /* 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; - } - - - /* Count successful connects */ - /* Total connects */ - stl->stats.connected_edges += 2; - /* Count individual connects */ - i = ((stl->neighbors_start[edge_a->facet_number].neighbor[0] == -1) + - (stl->neighbors_start[edge_a->facet_number].neighbor[1] == -1) + - (stl->neighbors_start[edge_a->facet_number].neighbor[2] == -1)); - j = ((stl->neighbors_start[edge_b->facet_number].neighbor[0] == -1) + - (stl->neighbors_start[edge_b->facet_number].neighbor[1] == -1) + - (stl->neighbors_start[edge_b->facet_number].neighbor[2] == -1)); - if(i == 2) { - stl->stats.connected_facets_1_edge +=1; - } else if(i == 1) { - stl->stats.connected_facets_2_edge +=1; - } else { - stl->stats.connected_facets_3_edge +=1; - } - if(j == 2) { - stl->stats.connected_facets_1_edge +=1; - } else if(j == 1) { - stl->stats.connected_facets_2_edge +=1; - } else { - stl->stats.connected_facets_3_edge +=1; - } -} - -static void stl_match_neighbors_nearby(stl_file *stl, stl_hash_edge *edge_a, stl_hash_edge *edge_b) -{ - int facet1; - int facet2; - int vertex1; - int vertex2; - int vnot1; - int vnot2; - stl_vertex new_vertex1; - stl_vertex new_vertex2; - - if (stl->error) return; - - stl_record_neighbors(stl, edge_a, edge_b); - stl_which_vertices_to_change(stl, edge_a, edge_b, &facet1, &vertex1, - &facet2, &vertex2, &new_vertex1, &new_vertex2); - if(facet1 != -1) { - if(facet1 == edge_a->facet_number) { - vnot1 = (edge_a->which_edge + 2) % 3; - } else { - vnot1 = (edge_b->which_edge + 2) % 3; - } - if(((vnot1 + 2) % 3) == vertex1) { - vnot1 += 3; - } - stl_change_vertices(stl, facet1, vnot1, new_vertex1); - } - if(facet2 != -1) { - if(facet2 == edge_a->facet_number) { - vnot2 = (edge_a->which_edge + 2) % 3; - } else { - vnot2 = (edge_b->which_edge + 2) % 3; - } - if(((vnot2 + 2) % 3) == vertex2) { - vnot2 += 3; - } - stl_change_vertices(stl, facet2, vnot2, new_vertex2); - } - stl->stats.edges_fixed += 2; -} - - -static void stl_change_vertices(stl_file *stl, int facet_num, int vnot, stl_vertex new_vertex) { - int first_facet; - int direction; - int next_edge; - int pivot_vertex; - - if (stl->error) return; - - first_facet = facet_num; - direction = 0; - - for(;;) { - if(vnot > 2) { - if(direction == 0) { - pivot_vertex = (vnot + 2) % 3; - next_edge = pivot_vertex; - direction = 1; - } else { - pivot_vertex = (vnot + 1) % 3; - next_edge = vnot % 3; - direction = 0; - } - } else { - if(direction == 0) { - pivot_vertex = (vnot + 1) % 3; - next_edge = vnot; - } else { - pivot_vertex = (vnot + 2) % 3; - next_edge = pivot_vertex; - } - } -#if 0 - if (stl->facet_start[facet_num].vertex[pivot_vertex](0) == new_vertex(0) && - stl->facet_start[facet_num].vertex[pivot_vertex](1) == new_vertex(1) && - stl->facet_start[facet_num].vertex[pivot_vertex](2) == new_vertex(2)) - printf("Changing vertex %f,%f,%f: Same !!!\r\n", - new_vertex(0), new_vertex(1), new_vertex(2)); - else { - if (stl->facet_start[facet_num].vertex[pivot_vertex](0) != new_vertex(0)) - printf("Changing coordinate x, vertex %e (0x%08x) to %e(0x%08x)\r\n", - stl->facet_start[facet_num].vertex[pivot_vertex](0), - *reinterpret_cast(&stl->facet_start[facet_num].vertex[pivot_vertex](0)), - new_vertex(0), - *reinterpret_cast(&new_vertex(0))); - if (stl->facet_start[facet_num].vertex[pivot_vertex](1) != new_vertex(1)) - printf("Changing coordinate x, vertex %e (0x%08x) to %e(0x%08x)\r\n", - stl->facet_start[facet_num].vertex[pivot_vertex](1), - *reinterpret_cast(&stl->facet_start[facet_num].vertex[pivot_vertex](1)), - new_vertex(1), - *reinterpret_cast(&new_vertex(1))); - if (stl->facet_start[facet_num].vertex[pivot_vertex](2) != new_vertex(2)) - printf("Changing coordinate x, vertex %e (0x%08x) to %e(0x%08x)\r\n", - stl->facet_start[facet_num].vertex[pivot_vertex](2), - *reinterpret_cast(&stl->facet_start[facet_num].vertex[pivot_vertex](2)), - new_vertex(2), - *reinterpret_cast(&new_vertex(2))); - } -#endif - stl->facet_start[facet_num].vertex[pivot_vertex] = new_vertex; - vnot = stl->neighbors_start[facet_num].which_vertex_not[next_edge]; - facet_num = stl->neighbors_start[facet_num].neighbor[next_edge]; - - if(facet_num == -1) { - break; - } - - if(facet_num == first_facet) { - /* back to the beginning */ - printf("\ -Back to the first facet changing vertices: probably a mobius part.\n\ -Try using a smaller tolerance or don't do a nearby check\n"); - return; - } - } -} - -static void -stl_which_vertices_to_change(stl_file *stl, stl_hash_edge *edge_a, - stl_hash_edge *edge_b, int *facet1, int *vertex1, - int *facet2, int *vertex2, - stl_vertex *new_vertex1, stl_vertex *new_vertex2) { - int v1a; /* pair 1, facet a */ - int v1b; /* pair 1, facet b */ - int v2a; /* pair 2, facet a */ - int v2b; /* pair 2, facet b */ - - /* Find first pair */ - if(edge_a->which_edge < 3) { - v1a = edge_a->which_edge; - v2a = (edge_a->which_edge + 1) % 3; - } else { - v2a = edge_a->which_edge % 3; - v1a = (edge_a->which_edge + 1) % 3; - } - if(edge_b->which_edge < 3) { - v1b = edge_b->which_edge; - v2b = (edge_b->which_edge + 1) % 3; - } else { - v2b = edge_b->which_edge % 3; - v1b = (edge_b->which_edge + 1) % 3; - } - - // Of the first pair, which vertex, if any, should be changed - if(stl->facet_start[edge_a->facet_number].vertex[v1a] == - stl->facet_start[edge_b->facet_number].vertex[v1b]) { - // These facets are already equal. No need to change. - *facet1 = -1; - } else { - if( (stl->neighbors_start[edge_a->facet_number].neighbor[v1a] == -1) - && (stl->neighbors_start[edge_a->facet_number].neighbor[(v1a + 2) % 3] == -1)) { - /* This vertex has no neighbors. This is a good one to change */ - *facet1 = edge_a->facet_number; - *vertex1 = v1a; - *new_vertex1 = stl->facet_start[edge_b->facet_number].vertex[v1b]; - } else { - *facet1 = edge_b->facet_number; - *vertex1 = v1b; - *new_vertex1 = stl->facet_start[edge_a->facet_number].vertex[v1a]; - } - } - - /* Of the second pair, which vertex, if any, should be changed */ - if(stl->facet_start[edge_a->facet_number].vertex[v2a] == - stl->facet_start[edge_b->facet_number].vertex[v2b]) { - // These facets are already equal. No need to change. - *facet2 = -1; - } else { - if( (stl->neighbors_start[edge_a->facet_number].neighbor[v2a] == -1) - && (stl->neighbors_start[edge_a->facet_number].neighbor[(v2a + 2) % 3] == -1)) { - /* This vertex has no neighbors. This is a good one to change */ - *facet2 = edge_a->facet_number; - *vertex2 = v2a; - *new_vertex2 = stl->facet_start[edge_b->facet_number].vertex[v2b]; - } else { - *facet2 = edge_b->facet_number; - *vertex2 = v2b; - *new_vertex2 = stl->facet_start[edge_a->facet_number].vertex[v2a]; - } - } + HashTableEdges hash_table(stl->stats.number_of_facets); + for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) { + //FIXME is the copy necessary? + stl_facet facet = stl->facet_start[i]; + for (int j = 0; j < 3; j++) { + if (stl->neighbors_start[i].neighbor[j] == -1) { + HashEdge edge; + edge.facet_number = i; + edge.which_edge = j; + if (edge.load_nearby(stl, facet.vertex[j], facet.vertex[(j + 1) % 3], tolerance)) + // Only insert edges that have different keys. + hash_table.insert_edge(stl, edge, match_neighbors_nearby); + } + } + } } void stl_remove_unconnected_facets(stl_file *stl) @@ -728,109 +634,88 @@ void stl_remove_unconnected_facets(stl_file *stl) } } -void -stl_fill_holes(stl_file *stl) { - stl_facet facet; - stl_facet new_facet; - int neighbors_initial[3]; - stl_hash_edge edge; - int first_facet; - int direction; - int facet_num; - int vnot; - int next_edge; - int pivot_vertex; - int next_facet; - int j; - int k; +void stl_fill_holes(stl_file *stl) +{ + if (stl->error) + return; - if (stl->error) return; + // Insert all unconnected edges into hash list. + HashTableEdges hash_table(stl->stats.number_of_facets); + for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) { + stl_facet facet = stl->facet_start[i]; + for (int j = 0; j < 3; ++ j) { + if(stl->neighbors_start[i].neighbor[j] != -1) + continue; + HashEdge edge; + edge.facet_number = i; + edge.which_edge = j; + edge.load_exact(stl, &facet.vertex[j], &facet.vertex[(j + 1) % 3]); + hash_table.insert_edge(stl, edge, record_neighbors); + } + } - /* Insert all unconnected edges into hash list */ - stl_initialize_facet_check_nearby(stl); - for (uint32_t i = 0; i < stl->stats.number_of_facets; i++) { - facet = stl->facet_start[i]; - for(j = 0; j < 3; j++) { - if(stl->neighbors_start[i].neighbor[j] != -1) continue; - edge.facet_number = i; - edge.which_edge = j; - stl_load_edge_exact(stl, &edge, &facet.vertex[j], - &facet.vertex[(j + 1) % 3]); + for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) { + stl_facet facet = stl->facet_start[i]; + int neighbors_initial[3] = { stl->neighbors_start[i].neighbor[0], stl->neighbors_start[i].neighbor[1], stl->neighbors_start[i].neighbor[2] }; + int first_facet = i; + for (int j = 0; j < 3; ++ j) { + if (stl->neighbors_start[i].neighbor[j] != -1) + continue; - insert_hash_edge(stl, edge, stl_record_neighbors); - } - } + stl_facet new_facet; + new_facet.vertex[0] = facet.vertex[j]; + new_facet.vertex[1] = facet.vertex[(j + 1) % 3]; + bool direction = neighbors_initial[(j + 2) % 3] == -1; + int facet_num = i; + int vnot = (j + 2) % 3; - for (uint32_t i = 0; i < stl->stats.number_of_facets; i++) { - facet = stl->facet_start[i]; - neighbors_initial[0] = stl->neighbors_start[i].neighbor[0]; - neighbors_initial[1] = stl->neighbors_start[i].neighbor[1]; - neighbors_initial[2] = stl->neighbors_start[i].neighbor[2]; - first_facet = i; - for(j = 0; j < 3; j++) { - if(stl->neighbors_start[i].neighbor[j] != -1) continue; + for (;;) { + int pivot_vertex = 0; + int next_edge = 0; + if (vnot > 2) { + if (direction) { + pivot_vertex = (vnot + 1) % 3; + next_edge = vnot % 3; + } else { + pivot_vertex = (vnot + 2) % 3; + next_edge = pivot_vertex; + } + direction = ! direction; + } else { + if(direction == 0) { + pivot_vertex = (vnot + 1) % 3; + next_edge = vnot; + } else { + pivot_vertex = (vnot + 2) % 3; + next_edge = pivot_vertex; + } + } - new_facet.vertex[0] = facet.vertex[j]; - new_facet.vertex[1] = facet.vertex[(j + 1) % 3]; - if(neighbors_initial[(j + 2) % 3] == -1) { - direction = 1; - } else { - direction = 0; - } + int next_facet = stl->neighbors_start[facet_num].neighbor[next_edge]; + if (next_facet == -1) { + new_facet.vertex[2] = stl->facet_start[facet_num].vertex[vnot % 3]; + stl_add_facet(stl, &new_facet); + for (int k = 0; k < 3; ++ k) { + HashEdge edge; + edge.facet_number = stl->stats.number_of_facets - 1; + edge.which_edge = k; + edge.load_exact(stl, &new_facet.vertex[k], &new_facet.vertex[(k + 1) % 3]); + hash_table.insert_edge(stl, edge, record_neighbors); + } + break; + } - facet_num = i; - vnot = (j + 2) % 3; + vnot = stl->neighbors_start[facet_num].which_vertex_not[next_edge]; + facet_num = next_facet; - for(;;) { - if(vnot > 2) { - if(direction == 0) { - pivot_vertex = (vnot + 2) % 3; - next_edge = pivot_vertex; - direction = 1; - } else { - pivot_vertex = (vnot + 1) % 3; - next_edge = vnot % 3; - direction = 0; - } - } else { - if(direction == 0) { - pivot_vertex = (vnot + 1) % 3; - next_edge = vnot; - } else { - pivot_vertex = (vnot + 2) % 3; - next_edge = pivot_vertex; - } - } - next_facet = stl->neighbors_start[facet_num].neighbor[next_edge]; - - if(next_facet == -1) { - new_facet.vertex[2] = stl->facet_start[facet_num]. - vertex[vnot % 3]; - stl_add_facet(stl, &new_facet); - for(k = 0; k < 3; k++) { - edge.facet_number = stl->stats.number_of_facets - 1; - edge.which_edge = k; - stl_load_edge_exact(stl, &edge, &new_facet.vertex[k], - &new_facet.vertex[(k + 1) % 3]); - - insert_hash_edge(stl, edge, stl_record_neighbors); - } - break; - } else { - vnot = stl->neighbors_start[facet_num].which_vertex_not[next_edge]; - facet_num = next_facet; - } - - if(facet_num == first_facet) { - /* back to the beginning */ - printf("\ -Back to the first facet filling holes: probably a mobius part.\n\ -Try using a smaller tolerance or don't do a nearby check\n"); - return; - } - } - } - } + if (facet_num == first_facet) { + // back to the beginning + printf("Back to the first facet filling holes: probably a mobius part.\nTry using a smaller tolerance or don't do a nearby check\n"); + return; + } + } + } + } } void stl_add_facet(stl_file *stl, const stl_facet *new_facet) diff --git a/src/admesh/stl.h b/src/admesh/stl.h index 345951121..bd49ad59f 100644 --- a/src/admesh/stl.h +++ b/src/admesh/stl.h @@ -74,21 +74,6 @@ struct stl_edge { int facet_number; }; -struct stl_hash_edge { - // Key of a hash edge: sorted vertices of the edge. - uint32_t key[6]; - // Compare two keys. - bool operator==(const stl_hash_edge &rhs) { return memcmp(key, rhs.key, sizeof(key)) == 0; } - bool operator!=(const stl_hash_edge &rhs) { return ! (*this == rhs); } - int hash(int M) const { return ((key[0] / 11 + key[1] / 7 + key[2] / 3) ^ (key[3] / 11 + key[4] / 7 + key[5] / 3)) % M; } - // Index of a facet owning this edge. - int facet_number; - // Index of this edge inside the facet with an index of facet_number. - // If this edge is stored backwards, which_edge is increased by 3. - int which_edge; - struct stl_hash_edge *next; -}; - struct stl_neighbors { stl_neighbors() { reset(); } void reset() { @@ -99,8 +84,10 @@ 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(); } - // Index of a neighbor facet. + // Index of a neighbor facet. int neighbor[3]; // Index of an opposite vertex at the neighbor face. char which_vertex_not[3]; @@ -151,10 +138,6 @@ struct stl_file { FILE *fp; std::vector facet_start; std::vector neighbors_start; - // Hash table on edges - std::vector heads; - stl_hash_edge* tail; - int M; // Indexed face set std::vector v_indices; std::vector v_shared; @@ -177,7 +160,6 @@ extern void stl_check_facets_nearby(stl_file *stl, float tolerance); extern void stl_remove_unconnected_facets(stl_file *stl); extern void stl_write_vertex(stl_file *stl, int facet, int vertex); extern void stl_write_facet(stl_file *stl, char *label, int facet); -extern void stl_write_edge(stl_file *stl, char *label, stl_hash_edge edge); extern void stl_write_neighbor(stl_file *stl, int facet); extern void stl_write_quad_object(stl_file *stl, char *file); extern void stl_verify_neighbors(stl_file *stl); diff --git a/src/admesh/stl_io.cpp b/src/admesh/stl_io.cpp index 81060c0a3..1e2e1479e 100644 --- a/src/admesh/stl_io.cpp +++ b/src/admesh/stl_io.cpp @@ -257,19 +257,6 @@ stl_write_facet(stl_file *stl, char *label, int facet) { stl_write_vertex(stl, facet, 2); } -void -stl_write_edge(stl_file *stl, char *label, stl_hash_edge edge) { - if (stl->error) return; - printf("edge (%d)/(%d) %s\n", edge.facet_number, edge.which_edge, label); - if(edge.which_edge < 3) { - stl_write_vertex(stl, edge.facet_number, edge.which_edge % 3); - stl_write_vertex(stl, edge.facet_number, (edge.which_edge + 1) % 3); - } else { - stl_write_vertex(stl, edge.facet_number, (edge.which_edge + 1) % 3); - stl_write_vertex(stl, edge.facet_number, edge.which_edge % 3); - } -} - void stl_write_neighbor(stl_file *stl, int facet) { if (stl->error) return; diff --git a/src/admesh/stlinit.cpp b/src/admesh/stlinit.cpp index 81b7914c3..b7ba21b77 100644 --- a/src/admesh/stlinit.cpp +++ b/src/admesh/stlinit.cpp @@ -50,8 +50,6 @@ void stl_open(stl_file *stl, const char *file) void stl_initialize(stl_file *stl) { stl->fp = nullptr; - stl->tail = nullptr; - stl->M = 0; stl->error = 0; stl->facet_start.clear(); stl->neighbors_start.clear(); @@ -64,8 +62,6 @@ void stl_initialize(stl_file *stl) void stl_close(stl_file *stl) { assert(stl->fp == nullptr); - assert(stl->heads.empty()); - assert(stl->tail == nullptr); stl_initialize(stl); } diff --git a/src/admesh/util.cpp b/src/admesh/util.cpp index d8640e575..91293d048 100644 --- a/src/admesh/util.cpp +++ b/src/admesh/util.cpp @@ -459,8 +459,6 @@ bool stl_validate(stl_file *stl) assert(stl->facet_start.size() == stl->stats.number_of_facets); assert(stl->neighbors_start.size() == stl->stats.number_of_facets); assert(stl->facet_start.size() == stl->neighbors_start.size()); - assert(stl->heads.empty()); - assert(stl->tail == nullptr); assert(! stl->neighbors_start.empty()); assert((stl->v_indices.empty()) == (stl->v_shared.empty())); assert(stl->stats.number_of_facets > 0); diff --git a/src/libslic3r/Fill/FillRectilinear3.cpp b/src/libslic3r/Fill/FillRectilinear3.cpp index 8a0b90ead..dab584298 100644 --- a/src/libslic3r/Fill/FillRectilinear3.cpp +++ b/src/libslic3r/Fill/FillRectilinear3.cpp @@ -15,7 +15,7 @@ #include "FillRectilinear3.hpp" - #define SLIC3R_DEBUG +// #define SLIC3R_DEBUG // Make assert active if SLIC3R_DEBUG #ifdef SLIC3R_DEBUG From a1c38794fbc12c0d88c59ac85230f058d0779b64 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Mon, 10 Jun 2019 17:17:36 +0200 Subject: [PATCH 06/22] Refactored admesh to get rid of the error and fp members of stl_file. --- src/admesh/connect.cpp | 15 --- src/admesh/normals.cpp | 118 +++++++---------- src/admesh/shared.cpp | 33 ++--- src/admesh/stl.h | 74 ++++------- src/admesh/stl_io.cpp | 111 ++++++---------- src/admesh/stlinit.cpp | 228 ++++++++++++--------------------- src/admesh/util.cpp | 39 +----- src/libslic3r/Format/PRUS.cpp | 1 - src/libslic3r/Format/STL.cpp | 3 +- src/libslic3r/TriangleMesh.cpp | 5 +- src/libslic3r/TriangleMesh.hpp | 14 +- xs/xsp/TriangleMesh.xsp | 1 - 12 files changed, 213 insertions(+), 429 deletions(-) diff --git a/src/admesh/connect.cpp b/src/admesh/connect.cpp index 03b13343d..9553e7c4d 100644 --- a/src/admesh/connect.cpp +++ b/src/admesh/connect.cpp @@ -396,9 +396,6 @@ static void match_neighbors_nearby(stl_file *stl, const HashEdge &edge_a, const // floats of the first edge matches all six floats of the second edge. void stl_check_facets_exact(stl_file *stl) { - if (stl->error) - return; - stl->stats.connected_edges = 0; stl->stats.connected_facets_1_edge = 0; stl->stats.connected_facets_2_edge = 0; @@ -444,9 +441,6 @@ void stl_check_facets_exact(stl_file *stl) void stl_check_facets_nearby(stl_file *stl, float tolerance) { - if (stl->error) - return; - 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)) { @@ -476,9 +470,6 @@ void stl_remove_unconnected_facets(stl_file *stl) // A couple of things need to be done here. One is to remove any completely unconnected facets (0 edges connected) since these are // useless and could be completely wrong. The second thing that needs to be done is to remove any degenerate facets that were created during // stl_check_facets_nearby(). - if (stl->error) - return; - auto remove_facet = [stl](int facet_number) { ++ stl->stats.facets_removed; @@ -526,7 +517,6 @@ void stl_remove_unconnected_facets(stl_file *stl) { // Update statistics on face connectivity. auto stl_update_connects_remove_1 = [stl](int facet_num) { - assert(! stl->error); //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 @@ -636,9 +626,6 @@ void stl_remove_unconnected_facets(stl_file *stl) void stl_fill_holes(stl_file *stl) { - if (stl->error) - return; - // Insert all unconnected edges into hash list. HashTableEdges hash_table(stl->stats.number_of_facets); for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) { @@ -720,8 +707,6 @@ void stl_fill_holes(stl_file *stl) void stl_add_facet(stl_file *stl, const stl_facet *new_facet) { - if (stl->error) - return; assert(stl->facet_start.size() == stl->stats.number_of_facets); assert(stl->neighbors_start.size() == stl->stats.number_of_facets); stl->facet_start.emplace_back(*new_facet); diff --git a/src/admesh/normals.cpp b/src/admesh/normals.cpp index e11f1a3c1..f20d9e68e 100644 --- a/src/admesh/normals.cpp +++ b/src/admesh/normals.cpp @@ -29,61 +29,43 @@ static int stl_check_normal_vector(stl_file *stl, int facet_num, int normal_fix_flag); -static void -stl_reverse_facet(stl_file *stl, int facet_num) { - stl_vertex tmp_vertex; - /* int tmp_neighbor;*/ - int neighbor[3]; - int vnot[3]; +static void reverse_facet(stl_file *stl, int facet_num) +{ + stl->stats.facets_reversed += 1; - stl->stats.facets_reversed += 1; + int neighbor[3] = { stl->neighbors_start[facet_num].neighbor[0], stl->neighbors_start[facet_num].neighbor[1], stl->neighbors_start[facet_num].neighbor[2] }; + int vnot[3] = { stl->neighbors_start[facet_num].which_vertex_not[0], stl->neighbors_start[facet_num].which_vertex_not[1], stl->neighbors_start[facet_num].which_vertex_not[2] }; - neighbor[0] = stl->neighbors_start[facet_num].neighbor[0]; - neighbor[1] = stl->neighbors_start[facet_num].neighbor[1]; - neighbor[2] = stl->neighbors_start[facet_num].neighbor[2]; - vnot[0] = stl->neighbors_start[facet_num].which_vertex_not[0]; - vnot[1] = stl->neighbors_start[facet_num].which_vertex_not[1]; - vnot[2] = stl->neighbors_start[facet_num].which_vertex_not[2]; + // reverse the facet + stl_vertex tmp_vertex = stl->facet_start[facet_num].vertex[0]; + stl->facet_start[facet_num].vertex[0] = + stl->facet_start[facet_num].vertex[1]; + stl->facet_start[facet_num].vertex[1] = tmp_vertex; - /* reverse the facet */ - tmp_vertex = stl->facet_start[facet_num].vertex[0]; - stl->facet_start[facet_num].vertex[0] = - stl->facet_start[facet_num].vertex[1]; - stl->facet_start[facet_num].vertex[1] = tmp_vertex; + // fix the vnots of the neighboring facets + if (neighbor[0] != -1) + stl->neighbors_start[neighbor[0]].which_vertex_not[(vnot[0] + 1) % 3] = (stl->neighbors_start[neighbor[0]].which_vertex_not[(vnot[0] + 1) % 3] + 3) % 6; + if (neighbor[1] != -1) + stl->neighbors_start[neighbor[1]].which_vertex_not[(vnot[1] + 1) % 3] = (stl->neighbors_start[neighbor[1]].which_vertex_not[(vnot[1] + 1) % 3] + 4) % 6; + if (neighbor[2] != -1) + stl->neighbors_start[neighbor[2]].which_vertex_not[(vnot[2] + 1) % 3] = (stl->neighbors_start[neighbor[2]].which_vertex_not[(vnot[2] + 1) % 3] + 2) % 6; - /* fix the vnots of the neighboring facets */ - if(neighbor[0] != -1) - stl->neighbors_start[neighbor[0]].which_vertex_not[(vnot[0] + 1) % 3] = - (stl->neighbors_start[neighbor[0]]. - which_vertex_not[(vnot[0] + 1) % 3] + 3) % 6; - if(neighbor[1] != -1) - stl->neighbors_start[neighbor[1]].which_vertex_not[(vnot[1] + 1) % 3] = - (stl->neighbors_start[neighbor[1]]. - which_vertex_not[(vnot[1] + 1) % 3] + 4) % 6; - if(neighbor[2] != -1) - stl->neighbors_start[neighbor[2]].which_vertex_not[(vnot[2] + 1) % 3] = - (stl->neighbors_start[neighbor[2]]. - which_vertex_not[(vnot[2] + 1) % 3] + 2) % 6; + // swap the neighbors of the facet that is being reversed + stl->neighbors_start[facet_num].neighbor[1] = neighbor[2]; + stl->neighbors_start[facet_num].neighbor[2] = neighbor[1]; - /* swap the neighbors of the facet that is being reversed */ - stl->neighbors_start[facet_num].neighbor[1] = neighbor[2]; - stl->neighbors_start[facet_num].neighbor[2] = neighbor[1]; + // swap the vnots of the facet that is being reversed + stl->neighbors_start[facet_num].which_vertex_not[1] = vnot[2]; + stl->neighbors_start[facet_num].which_vertex_not[2] = vnot[1]; - /* swap the vnots of the facet that is being reversed */ - stl->neighbors_start[facet_num].which_vertex_not[1] = vnot[2]; - stl->neighbors_start[facet_num].which_vertex_not[2] = vnot[1]; - - /* reverse the values of the vnots of the facet that is being reversed */ - stl->neighbors_start[facet_num].which_vertex_not[0] = - (stl->neighbors_start[facet_num].which_vertex_not[0] + 3) % 6; - stl->neighbors_start[facet_num].which_vertex_not[1] = - (stl->neighbors_start[facet_num].which_vertex_not[1] + 3) % 6; - stl->neighbors_start[facet_num].which_vertex_not[2] = - (stl->neighbors_start[facet_num].which_vertex_not[2] + 3) % 6; + // reverse the values of the vnots of the facet that is being reversed + stl->neighbors_start[facet_num].which_vertex_not[0] = (stl->neighbors_start[facet_num].which_vertex_not[0] + 3) % 6; + stl->neighbors_start[facet_num].which_vertex_not[1] = (stl->neighbors_start[facet_num].which_vertex_not[1] + 3) % 6; + stl->neighbors_start[facet_num].which_vertex_not[2] = (stl->neighbors_start[facet_num].which_vertex_not[2] + 3) % 6; } -void -stl_fix_normal_directions(stl_file *stl) { +void stl_fix_normal_directions(stl_file *stl) +{ /* int edge_num;*/ /* int vnot;*/ int checked = 0; @@ -104,8 +86,6 @@ stl_fix_normal_directions(stl_file *stl) { int id; int force_exit = 0; - if (stl->error) return; - // this may happen for malformed models, see: https://github.com/prusa3d/PrusaSlicer/issues/2209 if (stl->stats.number_of_facets == 0) return; @@ -125,7 +105,7 @@ stl_fix_normal_directions(stl_file *stl) { Arbitrarily starts at face 0. If this one is wrong, we're screwed. Thankfully, the chances of it being wrong randomly are low if most of the triangles are right: */ if (stl_check_normal_vector(stl, 0, 0) == 2) { - stl_reverse_facet(stl, 0); + reverse_facet(stl, 0); reversed_ids[reversed_count++] = 0; } @@ -144,12 +124,12 @@ stl_fix_normal_directions(stl_file *stl) { if (norm_sw[stl->neighbors_start[facet_num].neighbor[j]] == 1) { /* trying to modify a facet already marked as fixed, revert all changes made until now and exit (fixes: #716, #574, #413, #269, #262, #259, #230, #228, #206) */ for (id = reversed_count - 1; id >= 0; --id) { - stl_reverse_facet(stl, reversed_ids[id]); + reverse_facet(stl, reversed_ids[id]); } force_exit = 1; break; } else { - stl_reverse_facet(stl, stl->neighbors_start[facet_num].neighbor[j]); + reverse_facet(stl, stl->neighbors_start[facet_num].neighbor[j]); reversed_ids[reversed_count++] = stl->neighbors_start[facet_num].neighbor[j]; } } @@ -193,7 +173,7 @@ stl_fix_normal_directions(stl_file *stl) { /* This is the first facet of the next part. */ facet_num = i; if(stl_check_normal_vector(stl, i, 0) == 2) { - stl_reverse_facet(stl, i); + reverse_facet(stl, i); reversed_ids[reversed_count++] = i; } @@ -209,7 +189,8 @@ stl_fix_normal_directions(stl_file *stl) { delete tail; } -static int stl_check_normal_vector(stl_file *stl, int facet_num, int normal_fix_flag) { +static int stl_check_normal_vector(stl_file *stl, int facet_num, int normal_fix_flag) +{ /* Returns 0 if the normal is within tolerance */ /* Returns 1 if the normal is not within tolerance, but direction is OK */ /* Returns 2 if the normal is not within tolerance and backwards */ @@ -260,26 +241,19 @@ static int stl_check_normal_vector(stl_file *stl, int facet_num, int normal_fix_ return 4; } -void stl_fix_normal_values(stl_file *stl) { - int i; - - if (stl->error) return; - - for(i = 0; i < stl->stats.number_of_facets; i++) { - stl_check_normal_vector(stl, i, 1); - } +void stl_fix_normal_values(stl_file *stl) +{ + for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) + stl_check_normal_vector(stl, i, 1); } void stl_reverse_all_facets(stl_file *stl) { - if (stl->error) - return; - - stl_normal normal; - for(int i = 0; i < stl->stats.number_of_facets; i++) { - stl_reverse_facet(stl, i); - stl_calculate_normal(normal, &stl->facet_start[i]); - stl_normalize_vector(normal); - stl->facet_start[i].normal = normal; - } + stl_normal normal; + for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) { + reverse_facet(stl, i); + stl_calculate_normal(normal, &stl->facet_start[i]); + stl_normalize_vector(normal); + stl->facet_start[i].normal = normal; + } } diff --git a/src/admesh/shared.cpp b/src/admesh/shared.cpp index bc264ee96..a757d8816 100644 --- a/src/admesh/shared.cpp +++ b/src/admesh/shared.cpp @@ -38,15 +38,10 @@ void stl_invalidate_shared_vertices(stl_file *stl) void stl_generate_shared_vertices(stl_file *stl) { - if (stl->error) - return; - - /* make sure this function is idempotent and does not leak memory */ - stl_invalidate_shared_vertices(stl); - // 3 indices to vertex per face stl->v_indices.assign(stl->stats.number_of_facets, v_indices_struct()); // Shared vertices (3D coordinates) + stl->v_shared.clear(); stl->v_shared.reserve(stl->stats.number_of_facets / 2); stl->stats.shared_vertices = 0; @@ -139,11 +134,8 @@ void stl_generate_shared_vertices(stl_file *stl) } } -void stl_write_off(stl_file *stl, const char *file) +bool stl_write_off(stl_file *stl, const char *file) { - if (stl->error) - return; - /* Open the file */ FILE *fp = boost::nowide::fopen(file, "w"); if (fp == nullptr) { @@ -151,8 +143,7 @@ void stl_write_off(stl_file *stl, const char *file) sprintf(error_msg, "stl_write_ascii: Couldn't open %s for writing", file); perror(error_msg); free(error_msg); - stl->error = 1; - return; + return false; } fprintf(fp, "OFF\n"); @@ -162,13 +153,11 @@ void stl_write_off(stl_file *stl, const char *file) for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) fprintf(fp, "\t3 %d %d %d\n", stl->v_indices[i].vertex[0], stl->v_indices[i].vertex[1], stl->v_indices[i].vertex[2]); fclose(fp); + return true; } -void stl_write_vrml(stl_file *stl, const char *file) +bool stl_write_vrml(stl_file *stl, const char *file) { - if (stl->error) - return; - /* Open the file */ FILE *fp = boost::nowide::fopen(file, "w"); if (fp == nullptr) { @@ -176,8 +165,7 @@ void stl_write_vrml(stl_file *stl, const char *file) sprintf(error_msg, "stl_write_ascii: Couldn't open %s for writing", file); perror(error_msg); free(error_msg); - stl->error = 1; - return; + return false; } fprintf(fp, "#VRML V1.0 ascii\n\n"); @@ -210,12 +198,11 @@ void stl_write_vrml(stl_file *stl, const char *file) fprintf(fp, "\t}\n"); fprintf(fp, "}\n"); fclose(fp); + return true; } -void stl_write_obj (stl_file *stl, const char *file) +bool stl_write_obj(stl_file *stl, const char *file) { - if (stl->error) - return; FILE *fp = boost::nowide::fopen(file, "w"); if (fp == nullptr) { @@ -223,8 +210,7 @@ void stl_write_obj (stl_file *stl, const char *file) sprintf(error_msg, "stl_write_ascii: Couldn't open %s for writing", file); perror(error_msg); free(error_msg); - stl->error = 1; - return; + return false; } for (int i = 0; i < stl->stats.shared_vertices; ++ i) @@ -232,4 +218,5 @@ void stl_write_obj (stl_file *stl, const char *file) for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) fprintf(fp, "f %d %d %d\n", stl->v_indices[i].vertex[0]+1, stl->v_indices[i].vertex[1]+1, stl->v_indices[i].vertex[2]+1); fclose(fp); + return true; } diff --git a/src/admesh/stl.h b/src/admesh/stl.h index bd49ad59f..51153ede7 100644 --- a/src/admesh/stl.h +++ b/src/admesh/stl.h @@ -127,15 +127,9 @@ struct stl_stats { int normals_fixed; int number_of_parts; int shared_vertices; - - // hash table statistics - int malloced; - int freed; - int collisions; }; struct stl_file { - FILE *fp; std::vector facet_start; std::vector neighbors_start; // Indexed face set @@ -143,17 +137,15 @@ struct stl_file { std::vector v_shared; // Statistics stl_stats stats; - char error; }; -extern void stl_open(stl_file *stl, const char *file); -extern void stl_close(stl_file *stl); +extern bool stl_open(stl_file *stl, const char *file); extern void stl_stats_out(stl_file *stl, FILE *file, char *input_file); -extern void stl_print_neighbors(stl_file *stl, char *file); +extern bool stl_print_neighbors(stl_file *stl, char *file); extern void stl_put_little_int(FILE *fp, int value_in); extern void stl_put_little_float(FILE *fp, float value_in); -extern void stl_write_ascii(stl_file *stl, const char *file, const char *label); -extern void stl_write_binary(stl_file *stl, const char *file, const char *label); +extern bool stl_write_ascii(stl_file *stl, const char *file, const char *label); +extern bool stl_write_binary(stl_file *stl, const char *file, const char *label); extern void stl_write_binary_block(stl_file *stl, FILE *fp); extern void stl_check_facets_exact(stl_file *stl); extern void stl_check_facets_nearby(stl_file *stl, float tolerance); @@ -161,7 +153,7 @@ extern void stl_remove_unconnected_facets(stl_file *stl); extern void stl_write_vertex(stl_file *stl, int facet, int vertex); extern void stl_write_facet(stl_file *stl, char *label, int facet); extern void stl_write_neighbor(stl_file *stl, int facet); -extern void stl_write_quad_object(stl_file *stl, char *file); +extern bool stl_write_quad_object(stl_file *stl, char *file); extern void stl_verify_neighbors(stl_file *stl); extern void stl_fill_holes(stl_file *stl); extern void stl_fix_normal_directions(stl_file *stl); @@ -183,34 +175,28 @@ extern void stl_get_size(stl_file *stl); template extern void stl_transform(stl_file *stl, T *trafo3x4) { - if (stl->error) - return; + for (uint32_t i_face = 0; i_face < stl->stats.number_of_facets; ++ i_face) { + stl_facet &face = stl->facet_start[i_face]; + for (int i_vertex = 0; i_vertex < 3; ++ i_vertex) { + stl_vertex &v_dst = face.vertex[i_vertex]; + stl_vertex v_src = v_dst; + v_dst(0) = T(trafo3x4[0] * v_src(0) + trafo3x4[1] * v_src(1) + trafo3x4[2] * v_src(2) + trafo3x4[3]); + v_dst(1) = T(trafo3x4[4] * v_src(0) + trafo3x4[5] * v_src(1) + trafo3x4[6] * v_src(2) + trafo3x4[7]); + v_dst(2) = T(trafo3x4[8] * v_src(0) + trafo3x4[9] * v_src(1) + trafo3x4[10] * v_src(2) + trafo3x4[11]); + } + stl_vertex &v_dst = face.normal; + stl_vertex v_src = v_dst; + v_dst(0) = T(trafo3x4[0] * v_src(0) + trafo3x4[1] * v_src(1) + trafo3x4[2] * v_src(2)); + v_dst(1) = T(trafo3x4[4] * v_src(0) + trafo3x4[5] * v_src(1) + trafo3x4[6] * v_src(2)); + v_dst(2) = T(trafo3x4[8] * v_src(0) + trafo3x4[9] * v_src(1) + trafo3x4[10] * v_src(2)); + } - for (uint32_t i_face = 0; i_face < stl->stats.number_of_facets; ++ i_face) { - stl_facet &face = stl->facet_start[i_face]; - for (int i_vertex = 0; i_vertex < 3; ++ i_vertex) { - stl_vertex &v_dst = face.vertex[i_vertex]; - stl_vertex v_src = v_dst; - v_dst(0) = T(trafo3x4[0] * v_src(0) + trafo3x4[1] * v_src(1) + trafo3x4[2] * v_src(2) + trafo3x4[3]); - v_dst(1) = T(trafo3x4[4] * v_src(0) + trafo3x4[5] * v_src(1) + trafo3x4[6] * v_src(2) + trafo3x4[7]); - v_dst(2) = T(trafo3x4[8] * v_src(0) + trafo3x4[9] * v_src(1) + trafo3x4[10] * v_src(2) + trafo3x4[11]); - } - stl_vertex &v_dst = face.normal; - stl_vertex v_src = v_dst; - v_dst(0) = T(trafo3x4[0] * v_src(0) + trafo3x4[1] * v_src(1) + trafo3x4[2] * v_src(2)); - v_dst(1) = T(trafo3x4[4] * v_src(0) + trafo3x4[5] * v_src(1) + trafo3x4[6] * v_src(2)); - v_dst(2) = T(trafo3x4[8] * v_src(0) + trafo3x4[9] * v_src(1) + trafo3x4[10] * v_src(2)); - } - - stl_get_size(stl); + stl_get_size(stl); } template inline void stl_transform(stl_file *stl, const Eigen::Transform& t) { - if (stl->error) - return; - const Eigen::Matrix r = t.matrix().template block<3, 3>(0, 0); for (size_t i = 0; i < stl->stats.number_of_facets; ++i) { stl_facet &f = stl->facet_start[i]; @@ -225,9 +211,6 @@ inline void stl_transform(stl_file *stl, const Eigen::Transform inline void stl_transform(stl_file *stl, const Eigen::Matrix& m) { - if (stl->error) - return; - for (size_t i = 0; i < stl->stats.number_of_facets; ++i) { stl_facet &f = stl->facet_start[i]; for (size_t j = 0; j < 3; ++j) @@ -238,13 +221,12 @@ inline void stl_transform(stl_file *stl, const Eigen::Matrixvertex[1] - facet->vertex[0]).cross(facet->vertex[2] - facet->vertex[0]); } @@ -263,17 +245,13 @@ extern void stl_calculate_volume(stl_file *stl); extern void stl_repair(stl_file *stl, int fixall_flag, int exact_flag, int tolerance_flag, float tolerance, int increment_flag, float increment, int nearby_flag, int iterations, int remove_unconnected_flag, int fill_holes_flag, int normal_directions_flag, int normal_values_flag, int reverse_all_flag, int verbose_flag); -extern void stl_initialize(stl_file *stl); -extern void stl_count_facets(stl_file *stl, const char *file); +extern void stl_reset(stl_file *stl); extern void stl_allocate(stl_file *stl); extern void stl_read(stl_file *stl, int first_facet, bool first); extern void stl_facet_stats(stl_file *stl, stl_facet facet, bool &first); extern void stl_reallocate(stl_file *stl); extern void stl_add_facet(stl_file *stl, const stl_facet *new_facet); -extern void stl_clear_error(stl_file *stl); -extern int stl_get_error(stl_file *stl); -extern void stl_exit_on_error(stl_file *stl); // Validate the mesh, assert on error. extern bool stl_validate(stl_file *stl); diff --git a/src/admesh/stl_io.cpp b/src/admesh/stl_io.cpp index 1e2e1479e..8f809d379 100644 --- a/src/admesh/stl_io.cpp +++ b/src/admesh/stl_io.cpp @@ -33,10 +33,8 @@ #define SEEK_END 2 #endif -void -stl_stats_out(stl_file *stl, FILE *file, char *input_file) { - if (stl->error) return; - +void stl_stats_out(stl_file *stl, FILE *file, char *input_file) +{ /* this is here for Slic3r, without our config.h it won't use this part of the code anyway */ #ifndef VERSION @@ -107,12 +105,10 @@ Backwards edges : %5d\n", stl->stats.backwards_edges); Normals fixed : %5d\n", stl->stats.normals_fixed); } -void -stl_write_ascii(stl_file *stl, const char *file, const char *label) { +bool stl_write_ascii(stl_file *stl, const char *file, const char *label) +{ char *error_msg; - if (stl->error) return; - /* Open the file */ FILE *fp = boost::nowide::fopen(file, "w"); if(fp == NULL) { @@ -122,8 +118,7 @@ stl_write_ascii(stl_file *stl, const char *file, const char *label) { file); perror(error_msg); free(error_msg); - stl->error = 1; - return; + return false; } fprintf(fp, "solid %s\n", label); @@ -149,15 +144,14 @@ stl_write_ascii(stl_file *stl, const char *file, const char *label) { fprintf(fp, "endsolid %s\n", label); fclose(fp); + return true; } -void -stl_print_neighbors(stl_file *stl, char *file) { +bool stl_print_neighbors(stl_file *stl, char *file) +{ FILE *fp; char *error_msg; - if (stl->error) return; - /* Open the file */ fp = boost::nowide::fopen(file, "w"); if(fp == NULL) { @@ -167,8 +161,7 @@ stl_print_neighbors(stl_file *stl, char *file) { file); perror(error_msg); free(error_msg); - stl->error = 1; - return; + return false; } for (uint32_t i = 0; i < stl->stats.number_of_facets; i++) { @@ -182,6 +175,7 @@ stl_print_neighbors(stl_file *stl, char *file) { (int)stl->neighbors_start[i].which_vertex_not[2]); } fclose(fp); + return true; } #ifndef BOOST_LITTLE_ENDIAN @@ -195,13 +189,11 @@ void stl_internal_reverse_quads(char *buf, size_t cnt) } #endif -void -stl_write_binary(stl_file *stl, const char *file, const char *label) { +bool stl_write_binary(stl_file *stl, const char *file, const char *label) +{ FILE *fp; char *error_msg; - if (stl->error) return; - /* Open the file */ fp = boost::nowide::fopen(file, "wb"); if(fp == NULL) { @@ -211,8 +203,7 @@ stl_write_binary(stl_file *stl, const char *file, const char *label) { file); perror(error_msg); free(error_msg); - stl->error = 1; - return; + return false; } fprintf(fp, "%s", label); @@ -237,40 +228,38 @@ stl_write_binary(stl_file *stl, const char *file, const char *label) { } #endif /* BOOST_LITTLE_ENDIAN */ fclose(fp); + return true; } -void -stl_write_vertex(stl_file *stl, int facet, int vertex) { - if (stl->error) return; - printf(" vertex %d/%d % .8E % .8E % .8E\n", vertex, facet, +void stl_write_vertex(stl_file *stl, int facet, int vertex) +{ + printf(" vertex %d/%d % .8E % .8E % .8E\n", vertex, facet, stl->facet_start[facet].vertex[vertex](0), stl->facet_start[facet].vertex[vertex](1), stl->facet_start[facet].vertex[vertex](2)); } -void -stl_write_facet(stl_file *stl, char *label, int facet) { - if (stl->error) return; - printf("facet (%d)/ %s\n", facet, label); - stl_write_vertex(stl, facet, 0); - stl_write_vertex(stl, facet, 1); - stl_write_vertex(stl, facet, 2); +void stl_write_facet(stl_file *stl, char *label, int facet) +{ + printf("facet (%d)/ %s\n", facet, label); + stl_write_vertex(stl, facet, 0); + stl_write_vertex(stl, facet, 1); + stl_write_vertex(stl, facet, 2); } -void -stl_write_neighbor(stl_file *stl, int facet) { - if (stl->error) return; - printf("Neighbors %d: %d, %d, %d ; %d, %d, %d\n", facet, - stl->neighbors_start[facet].neighbor[0], - stl->neighbors_start[facet].neighbor[1], - stl->neighbors_start[facet].neighbor[2], - stl->neighbors_start[facet].which_vertex_not[0], - stl->neighbors_start[facet].which_vertex_not[1], - stl->neighbors_start[facet].which_vertex_not[2]); +void stl_write_neighbor(stl_file *stl, int facet) +{ + printf("Neighbors %d: %d, %d, %d ; %d, %d, %d\n", facet, + stl->neighbors_start[facet].neighbor[0], + stl->neighbors_start[facet].neighbor[1], + stl->neighbors_start[facet].neighbor[2], + stl->neighbors_start[facet].which_vertex_not[0], + stl->neighbors_start[facet].which_vertex_not[1], + stl->neighbors_start[facet].which_vertex_not[2]); } -void -stl_write_quad_object(stl_file *stl, char *file) { +bool stl_write_quad_object(stl_file *stl, char *file) +{ FILE *fp; char *error_msg; stl_vertex connect_color = stl_vertex::Zero(); @@ -279,8 +268,6 @@ stl_write_quad_object(stl_file *stl, char *file) { stl_vertex uncon_3_color = stl_vertex::Zero(); stl_vertex color; - if (stl->error) return; - /* Open the file */ fp = boost::nowide::fopen(file, "w"); if(fp == NULL) { @@ -290,8 +277,7 @@ stl_write_quad_object(stl_file *stl, char *file) { file); perror(error_msg); free(error_msg); - stl->error = 1; - return; + return false; } fprintf(fp, "CQUAD\n"); @@ -326,15 +312,14 @@ stl_write_quad_object(stl_file *stl, char *file) { stl->facet_start[i].vertex[2](2), color(0), color(1), color(2)); } fclose(fp); + return true; } -void stl_write_dxf(stl_file *stl, const char *file, char *label) +bool stl_write_dxf(stl_file *stl, const char *file, char *label) { FILE *fp; char *error_msg; - if (stl->error) return; - /* Open the file */ fp = boost::nowide::fopen(file, "w"); if(fp == NULL) { @@ -344,8 +329,7 @@ void stl_write_dxf(stl_file *stl, const char *file, char *label) file); perror(error_msg); free(error_msg); - stl->error = 1; - return; + return false; } fprintf(fp, "999\n%s\n", label); @@ -375,22 +359,5 @@ void stl_write_dxf(stl_file *stl, const char *file, char *label) fprintf(fp, "0\nENDSEC\n0\nEOF\n"); fclose(fp); -} - -void -stl_clear_error(stl_file *stl) { - stl->error = 0; -} - -void -stl_exit_on_error(stl_file *stl) { - if (!stl->error) return; - stl->error = 0; - stl_close(stl); - exit(1); -} - -int -stl_get_error(stl_file *stl) { - return stl->error; + return true; } diff --git a/src/admesh/stlinit.cpp b/src/admesh/stlinit.cpp index b7ba21b77..088842d51 100644 --- a/src/admesh/stlinit.cpp +++ b/src/admesh/stlinit.cpp @@ -35,42 +35,8 @@ #error "SEEK_SET not defined" #endif -void stl_open(stl_file *stl, const char *file) +static FILE* stl_open_count_facets(stl_file *stl, const char *file) { - stl_initialize(stl); - stl_count_facets(stl, file); - stl_allocate(stl); - stl_read(stl, 0, true); - if (stl->fp != nullptr) { - fclose(stl->fp); - stl->fp = nullptr; - } -} - -void stl_initialize(stl_file *stl) -{ - stl->fp = nullptr; - stl->error = 0; - stl->facet_start.clear(); - stl->neighbors_start.clear(); - stl->v_indices.clear(); - stl->v_shared.clear(); - memset(&stl->stats, 0, sizeof(stl_stats)); - stl->stats.volume = -1.0; -} - -void stl_close(stl_file *stl) -{ - assert(stl->fp == nullptr); - stl_initialize(stl); -} - -#ifndef BOOST_LITTLE_ENDIAN -extern void stl_internal_reverse_quads(char *buf, size_t cnt); -#endif /* BOOST_LITTLE_ENDIAN */ - -void -stl_count_facets(stl_file *stl, const char *file) { long file_size; uint32_t header_num_facets; uint32_t num_facets; @@ -80,30 +46,27 @@ stl_count_facets(stl_file *stl, const char *file) { int num_lines = 1; char *error_msg; - if (stl->error) return; - /* Open the file in binary mode first */ - stl->fp = boost::nowide::fopen(file, "rb"); - if(stl->fp == NULL) { + FILE *fp = boost::nowide::fopen(file, "rb"); + if (fp == nullptr) { error_msg = (char*) malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */ sprintf(error_msg, "stl_initialize: Couldn't open %s for reading", file); perror(error_msg); free(error_msg); - stl->error = 1; - return; + return nullptr; } /* Find size of file */ - fseek(stl->fp, 0, SEEK_END); - file_size = ftell(stl->fp); + fseek(fp, 0, SEEK_END); + file_size = ftell(fp); /* Check for binary or ASCII file */ - fseek(stl->fp, HEADER_SIZE, SEEK_SET); - if (!fread(chtest, sizeof(chtest), 1, stl->fp)) { + fseek(fp, HEADER_SIZE, SEEK_SET); + if (!fread(chtest, sizeof(chtest), 1, fp)) { perror("The input is an empty file"); - stl->error = 1; - return; + fclose(fp); + return nullptr; } stl->stats.type = ascii; for(s = 0; s < sizeof(chtest); s++) { @@ -112,7 +75,7 @@ stl_count_facets(stl_file *stl, const char *file) { break; } } - rewind(stl->fp); + rewind(fp); /* Get the header and the number of facets in the .STL file */ /* If the .STL file is binary, then do the following */ @@ -121,18 +84,18 @@ stl_count_facets(stl_file *stl, const char *file) { if(((file_size - HEADER_SIZE) % SIZEOF_STL_FACET != 0) || (file_size < STL_MIN_FILE_SIZE)) { fprintf(stderr, "The file %s has the wrong size.\n", file); - stl->error = 1; - return; + fclose(fp); + return nullptr; } num_facets = (file_size - HEADER_SIZE) / SIZEOF_STL_FACET; /* Read the header */ - if (fread(stl->stats.header, LABEL_SIZE, 1, stl->fp) > 79) { + if (fread(stl->stats.header, LABEL_SIZE, 1, fp) > 79) { stl->stats.header[80] = '\0'; } /* Read the int following the header. This should contain # of facets */ - bool header_num_faces_read = fread(&header_num_facets, sizeof(uint32_t), 1, stl->fp) != 0; + bool header_num_faces_read = fread(&header_num_facets, sizeof(uint32_t), 1, fp) != 0; #ifndef BOOST_LITTLE_ENDIAN // Convert from little endian to big endian. stl_internal_reverse_quads((char*)&header_num_facets, 4); @@ -147,23 +110,23 @@ stl_count_facets(stl_file *stl, const char *file) { /* Reopen the file in text mode (for getting correct newlines on Windows) */ // fix to silence a warning about unused return value. // obviously if it fails we have problems.... - stl->fp = boost::nowide::freopen(file, "r", stl->fp); + fp = boost::nowide::freopen(file, "r", fp); // do another null check to be safe - if(stl->fp == NULL) { + if(fp == nullptr) { error_msg = (char*) malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */ sprintf(error_msg, "stl_initialize: Couldn't open %s for reading", file); perror(error_msg); free(error_msg); - stl->error = 1; - return; + fclose(fp); + return nullptr; } /* Find the number of facets */ char linebuf[100]; - while (fgets(linebuf, 100, stl->fp) != NULL) { + while (fgets(linebuf, 100, fp) != nullptr) { /* don't count short lines */ if (strlen(linebuf) <= 4) continue; @@ -173,11 +136,11 @@ stl_count_facets(stl_file *stl, const char *file) { ++num_lines; } - rewind(stl->fp); + rewind(fp); /* Get the header */ for(i = 0; - (i < 80) && (stl->stats.header[i] = getc(stl->fp)) != '\n'; i++); + (i < 80) && (stl->stats.header[i] = getc(fp)) != '\n'; i++); stl->stats.header[i] = '\0'; /* Lose the '\n' */ stl->stats.header[80] = '\0'; @@ -185,84 +148,20 @@ stl_count_facets(stl_file *stl, const char *file) { } stl->stats.number_of_facets += num_facets; stl->stats.original_num_facets = stl->stats.number_of_facets; + return fp; } -void stl_allocate(stl_file *stl) -{ - if (stl->error) - return; - // Allocate memory for the entire .STL file. - stl->facet_start.assign(stl->stats.number_of_facets, stl_facet()); - // Allocate memory for the neighbors list. - stl->neighbors_start.assign(stl->stats.number_of_facets, stl_neighbors()); -} - -void -stl_open_merge(stl_file *stl, char *file_to_merge) { - int num_facets_so_far; - stl_type origStlType; - FILE *origFp; - stl_file stl_to_merge; - - if (stl->error) return; - - /* Record how many facets we have so far from the first file. We will start putting - facets in the next position. Since we're 0-indexed, it'l be the same position. */ - num_facets_so_far = stl->stats.number_of_facets; - - /* Record the file type we started with: */ - origStlType=stl->stats.type; - /* Record the file pointer too: */ - origFp=stl->fp; - - /* Initialize the sturucture with zero stats, header info and sizes: */ - stl_initialize(&stl_to_merge); - stl_count_facets(&stl_to_merge, file_to_merge); - - /* Copy what we need to into stl so that we can read the file_to_merge directly into it - using stl_read: Save the rest of the valuable info: */ - stl->stats.type=stl_to_merge.stats.type; - stl->fp=stl_to_merge.fp; - - /* Add the number of facets we already have in stl with what we we found in stl_to_merge but - haven't read yet. */ - stl->stats.number_of_facets=num_facets_so_far+stl_to_merge.stats.number_of_facets; - - /* Allocate enough room for stl->stats.number_of_facets facets and neighbors: */ - stl_reallocate(stl); - - /* Read the file to merge directly into stl, adding it to what we have already. - Start at num_facets_so_far, the index to the first unused facet. Also say - that this isn't our first time so we should augment stats like min and max - instead of erasing them. */ - stl_read(stl, num_facets_so_far, false); - - /* Restore the stl information we overwrote (for stl_read) so that it still accurately - reflects the subject part: */ - stl->stats.type=origStlType; - stl->fp=origFp; -} - -void stl_reallocate(stl_file *stl) -{ - if (stl->error) - return; - stl->facet_start.resize(stl->stats.number_of_facets); - stl->neighbors_start.resize(stl->stats.number_of_facets); -} - -/* Reads the contents of the file pointed to by stl->fp into the stl structure, +/* Reads the contents of the file pointed to by fp into the stl structure, starting at facet first_facet. The second argument says if it's our first time running this for the stl and therefore we should reset our max and min stats. */ -void stl_read(stl_file *stl, int first_facet, bool first) { +static bool stl_read(stl_file *stl, FILE *fp, int first_facet, bool first) +{ stl_facet facet; - if (stl->error) return; - if(stl->stats.type == binary) { - fseek(stl->fp, HEADER_SIZE, SEEK_SET); + fseek(fp, HEADER_SIZE, SEEK_SET); } else { - rewind(stl->fp); + rewind(fp); } char normal_buf[3][32]; @@ -271,10 +170,8 @@ void stl_read(stl_file *stl, int first_facet, bool first) { /* Read a single facet from a binary .STL file */ { /* we assume little-endian architecture! */ - if (fread(&facet, 1, SIZEOF_STL_FACET, stl->fp) != SIZEOF_STL_FACET) { - stl->error = 1; - return; - } + if (fread(&facet, 1, SIZEOF_STL_FACET, fp) != SIZEOF_STL_FACET) + return false; #ifndef BOOST_LITTLE_ENDIAN // Convert the loaded little endian data to big endian. stl_internal_reverse_quads((char*)&facet, 48); @@ -284,27 +181,26 @@ void stl_read(stl_file *stl, int first_facet, bool first) { { // skip solid/endsolid // (in this order, otherwise it won't work when they are paired in the middle of a file) - fscanf(stl->fp, "endsolid%*[^\n]\n"); - fscanf(stl->fp, "solid%*[^\n]\n"); // name might contain spaces so %*s doesn't work and it also can be empty (just "solid") + fscanf(fp, "endsolid%*[^\n]\n"); + fscanf(fp, "solid%*[^\n]\n"); // name might contain spaces so %*s doesn't work and it also can be empty (just "solid") // Leading space in the fscanf format skips all leading white spaces including numerous new lines and tabs. - int res_normal = fscanf(stl->fp, " facet normal %31s %31s %31s", normal_buf[0], normal_buf[1], normal_buf[2]); + int res_normal = fscanf(fp, " facet normal %31s %31s %31s", normal_buf[0], normal_buf[1], normal_buf[2]); assert(res_normal == 3); - int res_outer_loop = fscanf(stl->fp, " outer loop"); + int res_outer_loop = fscanf(fp, " outer loop"); assert(res_outer_loop == 0); - int res_vertex1 = fscanf(stl->fp, " vertex %f %f %f", &facet.vertex[0](0), &facet.vertex[0](1), &facet.vertex[0](2)); + int res_vertex1 = fscanf(fp, " vertex %f %f %f", &facet.vertex[0](0), &facet.vertex[0](1), &facet.vertex[0](2)); assert(res_vertex1 == 3); - int res_vertex2 = fscanf(stl->fp, " vertex %f %f %f", &facet.vertex[1](0), &facet.vertex[1](1), &facet.vertex[1](2)); + int res_vertex2 = fscanf(fp, " vertex %f %f %f", &facet.vertex[1](0), &facet.vertex[1](1), &facet.vertex[1](2)); assert(res_vertex2 == 3); - int res_vertex3 = fscanf(stl->fp, " vertex %f %f %f", &facet.vertex[2](0), &facet.vertex[2](1), &facet.vertex[2](2)); + int res_vertex3 = fscanf(fp, " vertex %f %f %f", &facet.vertex[2](0), &facet.vertex[2](1), &facet.vertex[2](2)); assert(res_vertex3 == 3); - int res_endloop = fscanf(stl->fp, " endloop"); + int res_endloop = fscanf(fp, " endloop"); assert(res_endloop == 0); // There is a leading and trailing white space around endfacet to eat up all leading and trailing white spaces including numerous tabs and new lines. - int res_endfacet = fscanf(stl->fp, " endfacet "); + int res_endfacet = fscanf(fp, " endfacet "); if (res_normal != 3 || res_outer_loop != 0 || res_vertex1 != 3 || res_vertex2 != 3 || res_vertex3 != 3 || res_endloop != 0 || res_endfacet != 0) { perror("Something is syntactically very wrong with this ASCII STL!"); - stl->error = 1; - return; + return false; } // The facet normal has been parsed as a single string as to workaround for not a numbers in the normal definition. @@ -338,13 +234,51 @@ void stl_read(stl_file *stl, int first_facet, bool first) { } stl->stats.size = stl->stats.max - stl->stats.min; stl->stats.bounding_diameter = stl->stats.size.norm(); + return true; +} + +bool stl_open(stl_file *stl, const char *file) +{ + stl_reset(stl); + FILE *fp = stl_open_count_facets(stl, file); + if (fp == nullptr) + return false; + stl_allocate(stl); + bool result = stl_read(stl, fp, 0, true); + fclose(fp); + return result; +} + +void stl_reset(stl_file *stl) +{ + stl->facet_start.clear(); + stl->neighbors_start.clear(); + stl->v_indices.clear(); + stl->v_shared.clear(); + memset(&stl->stats, 0, sizeof(stl_stats)); + stl->stats.volume = -1.0; +} + +#ifndef BOOST_LITTLE_ENDIAN +extern void stl_internal_reverse_quads(char *buf, size_t cnt); +#endif /* BOOST_LITTLE_ENDIAN */ + +void stl_allocate(stl_file *stl) +{ + // Allocate memory for the entire .STL file. + stl->facet_start.assign(stl->stats.number_of_facets, stl_facet()); + // Allocate memory for the neighbors list. + stl->neighbors_start.assign(stl->stats.number_of_facets, stl_neighbors()); +} + +void stl_reallocate(stl_file *stl) +{ + stl->facet_start.resize(stl->stats.number_of_facets); + stl->neighbors_start.resize(stl->stats.number_of_facets); } void stl_facet_stats(stl_file *stl, stl_facet facet, bool &first) { - if (stl->error) - return; - // While we are going through all of the facets, let's find the // maximum and minimum values for x, y, and z diff --git a/src/admesh/util.cpp b/src/admesh/util.cpp index 91293d048..db05cbc09 100644 --- a/src/admesh/util.cpp +++ b/src/admesh/util.cpp @@ -34,9 +34,6 @@ static float get_volume(stl_file *stl); void stl_verify_neighbors(stl_file *stl) { - if (stl->error) - return; - stl->stats.backwards_edges = 0; for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) { @@ -69,9 +66,6 @@ void stl_verify_neighbors(stl_file *stl) void stl_translate(stl_file *stl, float x, float y, float z) { - if (stl->error) - return; - stl_vertex new_min(x, y, z); stl_vertex shift = new_min - stl->stats.min; for (int i = 0; i < stl->stats.number_of_facets; ++ i) @@ -85,9 +79,6 @@ void stl_translate(stl_file *stl, float x, float y, float z) /* Translates the stl by x,y,z, relatively from wherever it is currently */ void stl_translate_relative(stl_file *stl, float x, float y, float z) { - if (stl->error) - return; - stl_vertex shift(x, y, z); for (int i = 0; i < stl->stats.number_of_facets; ++ i) for (int j = 0; j < 3; ++ j) @@ -99,9 +90,6 @@ void stl_translate_relative(stl_file *stl, float x, float y, float z) void stl_scale_versor(stl_file *stl, const stl_vertex &versor) { - if (stl->error) - return; - // Scale extents. auto s = versor.array(); stl->stats.min.array() *= s; @@ -120,9 +108,6 @@ void stl_scale_versor(stl_file *stl, const stl_vertex &versor) static void calculate_normals(stl_file *stl) { - if (stl->error) - return; - stl_normal normal; for(uint32_t i = 0; i < stl->stats.number_of_facets; i++) { stl_calculate_normal(normal, &stl->facet_start[i]); @@ -139,8 +124,6 @@ stl_rotate_x(stl_file *stl, float angle) { double c = cos(radian_angle); double s = sin(radian_angle); - if (stl->error) return; - for(i = 0; i < stl->stats.number_of_facets; i++) { for(j = 0; j < 3; j++) { stl_rotate(&stl->facet_start[i].vertex[j](1), @@ -159,8 +142,6 @@ stl_rotate_y(stl_file *stl, float angle) { double c = cos(radian_angle); double s = sin(radian_angle); - if (stl->error) return; - for(i = 0; i < stl->stats.number_of_facets; i++) { for(j = 0; j < 3; j++) { stl_rotate(&stl->facet_start[i].vertex[j](2), @@ -179,8 +160,6 @@ stl_rotate_z(stl_file *stl, float angle) { double c = cos(radian_angle); double s = sin(radian_angle); - if (stl->error) return; - for(i = 0; i < stl->stats.number_of_facets; i++) { for(j = 0; j < 3; j++) { stl_rotate(&stl->facet_start[i].vertex[j](0), @@ -203,7 +182,7 @@ stl_rotate(float *x, float *y, const double c, const double s) { void stl_get_size(stl_file *stl) { - if (stl->error || stl->stats.number_of_facets == 0) + if (stl->stats.number_of_facets == 0) return; stl->stats.min = stl->facet_start[0].vertex[0]; stl->stats.max = stl->stats.min; @@ -220,9 +199,6 @@ void stl_get_size(stl_file *stl) void stl_mirror_xy(stl_file *stl) { - if (stl->error) - return; - for(int i = 0; i < stl->stats.number_of_facets; i++) { for(int j = 0; j < 3; j++) { stl->facet_start[i].vertex[j](2) *= -1.0; @@ -239,8 +215,6 @@ void stl_mirror_xy(stl_file *stl) void stl_mirror_yz(stl_file *stl) { - if (stl->error) return; - for (int i = 0; i < stl->stats.number_of_facets; i++) { for (int j = 0; j < 3; j++) { stl->facet_start[i].vertex[j](0) *= -1.0; @@ -257,9 +231,6 @@ void stl_mirror_yz(stl_file *stl) void stl_mirror_xz(stl_file *stl) { - if (stl->error) - return; - for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) for (int j = 0; j < 3; ++ j) stl->facet_start[i].vertex[j](1) *= -1.0; @@ -274,9 +245,6 @@ void stl_mirror_xz(stl_file *stl) static float get_volume(stl_file *stl) { - if (stl->error) - return 0; - // Choose a point, any point as the reference. stl_vertex p0 = stl->facet_start[0].vertex[0]; float volume = 0.f; @@ -291,7 +259,6 @@ static float get_volume(stl_file *stl) void stl_calculate_volume(stl_file *stl) { - if (stl->error) return; stl->stats.volume = get_volume(stl); if(stl->stats.volume < 0.0) { stl_reverse_all_facets(stl); @@ -346,8 +313,6 @@ void stl_repair(stl_file *stl, int i; int last_edges_fixed = 0; - if (stl->error) return; - if(exact_flag || fixall_flag || nearby_flag || remove_unconnected_flag || fill_holes_flag || normal_directions_flag) { if (verbose_flag) @@ -453,8 +418,6 @@ All facets connected. No further nearby check necessary.\n"); // Check validity of the mesh, assert on error. bool stl_validate(stl_file *stl) { - assert(! stl->error); - assert(stl->fp == nullptr); assert(! stl->facet_start.empty()); assert(stl->facet_start.size() == stl->stats.number_of_facets); assert(stl->neighbors_start.size() == stl->stats.number_of_facets); diff --git a/src/libslic3r/Format/PRUS.cpp b/src/libslic3r/Format/PRUS.cpp index d983b1098..03ea71a83 100644 --- a/src/libslic3r/Format/PRUS.cpp +++ b/src/libslic3r/Format/PRUS.cpp @@ -161,7 +161,6 @@ static void extract_model_from_archive( else { // Header has been extracted. Now read the faces. stl_file &stl = mesh.stl; - stl.error = 0; stl.stats.type = inmemory; stl.stats.number_of_facets = header.nTriangles; stl.stats.original_num_facets = header.nTriangles; diff --git a/src/libslic3r/Format/STL.cpp b/src/libslic3r/Format/STL.cpp index b00623d1d..932906fe0 100644 --- a/src/libslic3r/Format/STL.cpp +++ b/src/libslic3r/Format/STL.cpp @@ -17,8 +17,7 @@ namespace Slic3r { bool load_stl(const char *path, Model *model, const char *object_name_in) { TriangleMesh mesh; - mesh.ReadSTLFile(path); - if (mesh.stl.error) { + if (! mesh.ReadSTLFile(path)) { // die "Failed to open $file\n" if !-e $path; return false; } diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp index ad12047d2..27163eb57 100644 --- a/src/libslic3r/TriangleMesh.cpp +++ b/src/libslic3r/TriangleMesh.cpp @@ -45,7 +45,7 @@ namespace Slic3r { TriangleMesh::TriangleMesh(const Pointf3s &points, const std::vector& facets) : repaired(false) { - stl_initialize(&this->stl); + stl_reset(&this->stl); stl_file &stl = this->stl; stl.stats.type = inmemory; @@ -74,7 +74,7 @@ TriangleMesh::TriangleMesh(const Pointf3s &points, const std::vector& f TriangleMesh& TriangleMesh::operator=(const TriangleMesh &other) { - stl_close(&this->stl); + stl_reset(&this->stl); this->stl = other.stl; this->repaired = other.repaired; return *this; @@ -426,7 +426,6 @@ TriangleMeshPtrs TriangleMesh::split() const mesh->stl.stats.type = inmemory; mesh->stl.stats.number_of_facets = (uint32_t)facets.size(); mesh->stl.stats.original_num_facets = mesh->stl.stats.number_of_facets; - stl_clear_error(&mesh->stl); stl_allocate(&mesh->stl); // Assign the facets to the new mesh. diff --git a/src/libslic3r/TriangleMesh.hpp b/src/libslic3r/TriangleMesh.hpp index 4de1f5989..c16f4a664 100644 --- a/src/libslic3r/TriangleMesh.hpp +++ b/src/libslic3r/TriangleMesh.hpp @@ -21,18 +21,18 @@ typedef std::vector TriangleMeshPtrs; class TriangleMesh { public: - TriangleMesh() : repaired(false) { stl_initialize(&this->stl); } + TriangleMesh() : repaired(false) { stl_reset(&this->stl); } TriangleMesh(const Pointf3s &points, const std::vector &facets); - TriangleMesh(const TriangleMesh &other) : repaired(false) { stl_initialize(&this->stl); *this = other; } - TriangleMesh(TriangleMesh &&other) : repaired(false) { stl_initialize(&this->stl); this->swap(other); } + TriangleMesh(const TriangleMesh &other) : repaired(false) { stl_reset(&this->stl); *this = other; } + TriangleMesh(TriangleMesh &&other) : repaired(false) { stl_reset(&this->stl); this->swap(other); } ~TriangleMesh() { clear(); } TriangleMesh& operator=(const TriangleMesh &other); TriangleMesh& operator=(TriangleMesh &&other) { this->swap(other); return *this; } - void clear() { stl_close(&this->stl); this->repaired = false; } + void clear() { stl_reset(&this->stl); this->repaired = false; } void swap(TriangleMesh &other) { std::swap(this->stl, other.stl); std::swap(this->repaired, other.repaired); } - void ReadSTLFile(const char* input_file) { stl_open(&stl, input_file); } - void write_ascii(const char* output_file) { stl_write_ascii(&this->stl, output_file, ""); } - void write_binary(const char* output_file) { stl_write_binary(&this->stl, output_file, ""); } + bool ReadSTLFile(const char* input_file) { return stl_open(&stl, input_file); } + bool write_ascii(const char* output_file) { return stl_write_ascii(&this->stl, output_file, ""); } + bool write_binary(const char* output_file) { return stl_write_binary(&this->stl, output_file, ""); } void repair(); float volume(); void check_topology(); diff --git a/xs/xsp/TriangleMesh.xsp b/xs/xsp/TriangleMesh.xsp index a188e0b8d..3cfbaa54d 100644 --- a/xs/xsp/TriangleMesh.xsp +++ b/xs/xsp/TriangleMesh.xsp @@ -46,7 +46,6 @@ TriangleMesh::ReadFromPerl(vertices, facets) SV* facets CODE: stl_file &stl = THIS->stl; - stl.error = 0; stl.stats.type = inmemory; // count facets and allocate memory From 65238a89b10fb18e7f9b647f5026da9276d32d58 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Mon, 10 Jun 2019 17:36:15 +0200 Subject: [PATCH 07/22] admesh refactoring: Removed the shared_vertices counter as it is now contained inside v_shared std::vector --- src/admesh/shared.cpp | 14 +++++--------- src/admesh/stl.h | 2 -- src/admesh/util.cpp | 1 - src/libslic3r/Format/3mf.cpp | 6 +++--- src/libslic3r/Format/AMF.cpp | 4 ++-- src/libslic3r/Model.cpp | 2 +- src/libslic3r/TriangleMesh.cpp | 4 ++-- xs/xsp/TriangleMesh.xsp | 4 ++-- 8 files changed, 15 insertions(+), 22 deletions(-) diff --git a/src/admesh/shared.cpp b/src/admesh/shared.cpp index a757d8816..e9f075498 100644 --- a/src/admesh/shared.cpp +++ b/src/admesh/shared.cpp @@ -33,7 +33,6 @@ void stl_invalidate_shared_vertices(stl_file *stl) { stl->v_indices.clear(); stl->v_shared.clear(); - stl->stats.shared_vertices = 0; } void stl_generate_shared_vertices(stl_file *stl) @@ -43,7 +42,6 @@ void stl_generate_shared_vertices(stl_file *stl) // Shared vertices (3D coordinates) stl->v_shared.clear(); stl->v_shared.reserve(stl->stats.number_of_facets / 2); - stl->stats.shared_vertices = 0; // A degenerate mesh may contain loops: Traversing a fan will end up in an endless loop // while never reaching the starting face. To avoid these endless loops, traversed faces at each fan traversal @@ -91,7 +89,7 @@ void stl_generate_shared_vertices(stl_file *stl) next_edge = pivot_vertex; } } - stl->v_indices[facet_in_fan_idx].vertex[pivot_vertex] = stl->stats.shared_vertices; + stl->v_indices[facet_in_fan_idx].vertex[pivot_vertex] = stl->v_shared.size() - 1; fan_traversal_facet_visited[facet_in_fan_idx] = fan_traversal_stamp; // next_edge is an index of the starting vertex of the edge, not an index of the opposite vertex to the edge! @@ -128,8 +126,6 @@ void stl_generate_shared_vertices(stl_file *stl) facet_in_fan_idx = next_facet; } } - - ++ stl->stats.shared_vertices; } } } @@ -147,8 +143,8 @@ bool stl_write_off(stl_file *stl, const char *file) } fprintf(fp, "OFF\n"); - fprintf(fp, "%d %d 0\n", stl->stats.shared_vertices, stl->stats.number_of_facets); - for (int i = 0; i < stl->stats.shared_vertices; ++ i) + fprintf(fp, "%d %d 0\n", stl->v_shared.size(), stl->stats.number_of_facets); + for (int i = 0; i < stl->v_shared.size(); ++ i) fprintf(fp, "\t%f %f %f\n", stl->v_shared[i](0), stl->v_shared[i](1), stl->v_shared[i](2)); for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) fprintf(fp, "\t3 %d %d %d\n", stl->v_indices[i].vertex[0], stl->v_indices[i].vertex[1], stl->v_indices[i].vertex[2]); @@ -184,7 +180,7 @@ bool stl_write_vrml(stl_file *stl, const char *file) fprintf(fp, "\t\t\tpoint [\n"); int i = 0; - for (; i < (stl->stats.shared_vertices - 1); i++) + for (; i + 1 < stl->v_shared.size(); ++ i) fprintf(fp, "\t\t\t\t%f %f %f,\n", stl->v_shared[i](0), stl->v_shared[i](1), stl->v_shared[i](2)); fprintf(fp, "\t\t\t\t%f %f %f]\n", stl->v_shared[i](0), stl->v_shared[i](1), stl->v_shared[i](2)); fprintf(fp, "\t\t}\n"); @@ -213,7 +209,7 @@ bool stl_write_obj(stl_file *stl, const char *file) return false; } - for (int i = 0; i < stl->stats.shared_vertices; ++ i) + for (size_t i = 0; i < stl->v_shared.size(); ++ i) fprintf(fp, "v %f %f %f\n", stl->v_shared[i](0), stl->v_shared[i](1), stl->v_shared[i](2)); for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) fprintf(fp, "f %d %d %d\n", stl->v_indices[i].vertex[0]+1, stl->v_indices[i].vertex[1]+1, stl->v_indices[i].vertex[2]+1); diff --git a/src/admesh/stl.h b/src/admesh/stl.h index 51153ede7..4aee6048f 100644 --- a/src/admesh/stl.h +++ b/src/admesh/stl.h @@ -109,7 +109,6 @@ struct stl_stats { float bounding_diameter; float shortest_edge; float volume; - unsigned number_of_blocks; int connected_edges; int connected_facets_1_edge; int connected_facets_2_edge; @@ -126,7 +125,6 @@ struct stl_stats { int backwards_edges; int normals_fixed; int number_of_parts; - int shared_vertices; }; struct stl_file { diff --git a/src/admesh/util.cpp b/src/admesh/util.cpp index db05cbc09..685b641b4 100644 --- a/src/admesh/util.cpp +++ b/src/admesh/util.cpp @@ -425,7 +425,6 @@ bool stl_validate(stl_file *stl) assert(! stl->neighbors_start.empty()); assert((stl->v_indices.empty()) == (stl->v_shared.empty())); assert(stl->stats.number_of_facets > 0); - assert(stl->v_shared.size() == stl->stats.shared_vertices); assert(stl->v_shared.empty() || stl->v_indices.size() == stl->stats.number_of_facets); #ifdef _DEBUG diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp index c3916a14e..d67106656 100644 --- a/src/libslic3r/Format/3mf.cpp +++ b/src/libslic3r/Format/3mf.cpp @@ -1888,17 +1888,17 @@ namespace Slic3r { if (stl.v_shared.empty()) stl_generate_shared_vertices(&stl); - if (stl.stats.shared_vertices == 0) + if (stl.v_shared.empty()) { add_error("Found invalid mesh"); return false; } - vertices_count += stl.stats.shared_vertices; + vertices_count += stl.v_shared.size(); const Transform3d& matrix = volume->get_matrix(); - for (int i = 0; i < stl.stats.shared_vertices; ++i) + for (size_t i = 0; i < stl.v_shared.size(); ++i) { stream << " <" << VERTEX_TAG << " "; Vec3f v = (matrix * stl.v_shared[i].cast()).cast(); diff --git a/src/libslic3r/Format/AMF.cpp b/src/libslic3r/Format/AMF.cpp index f48b5b58c..e81ced3ad 100644 --- a/src/libslic3r/Format/AMF.cpp +++ b/src/libslic3r/Format/AMF.cpp @@ -929,7 +929,7 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config) if (stl.v_shared.empty()) stl_generate_shared_vertices(&stl); const Transform3d& matrix = volume->get_matrix(); - for (size_t i = 0; i < stl.stats.shared_vertices; ++i) { + for (size_t i = 0; i < stl.v_shared.size(); ++i) { stream << " \n"; stream << " \n"; Vec3f v = (matrix * stl.v_shared[i].cast()).cast(); @@ -939,7 +939,7 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config) stream << " \n"; stream << " \n"; } - num_vertices += stl.stats.shared_vertices; + num_vertices += stl.v_shared.size(); } stream << " \n"; for (size_t i_volume = 0; i_volume < object->volumes.size(); ++i_volume) { diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 64fbb9a2a..6da7fc0c3 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -919,7 +919,7 @@ Polygon ModelObject::convex_hull_2d(const Transform3d &trafo_instance) const } } else { // Using the shared vertices should be a bit quicker than using the STL faces. - for (int i = 0; i < stl.stats.shared_vertices; ++ i) { + for (size_t i = 0; i < stl.v_shared.size(); ++ i) { Vec3d p = trafo * stl.v_shared[i].cast(); pts.emplace_back(coord_t(scale_(p.x())), coord_t(scale_(p.y()))); } diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp index 27163eb57..003affc27 100644 --- a/src/libslic3r/TriangleMesh.cpp +++ b/src/libslic3r/TriangleMesh.cpp @@ -484,8 +484,8 @@ Polygon TriangleMesh::convex_hull() { this->require_shared_vertices(); Points pp; - pp.reserve(this->stl.stats.shared_vertices); - for (int i = 0; i < this->stl.stats.shared_vertices; ++ i) { + pp.reserve(this->stl.v_shared.size()); + for (size_t i = 0; i < this->stl.v_shared.size(); ++ i) { const stl_vertex &v = this->stl.v_shared[i]; pp.emplace_back(Point::new_scale(v(0), v(1))); } diff --git a/xs/xsp/TriangleMesh.xsp b/xs/xsp/TriangleMesh.xsp index 3cfbaa54d..53b052027 100644 --- a/xs/xsp/TriangleMesh.xsp +++ b/xs/xsp/TriangleMesh.xsp @@ -104,8 +104,8 @@ TriangleMesh::vertices() // vertices AV* vertices = newAV(); - av_extend(vertices, THIS->stl.stats.shared_vertices); - for (int i = 0; i < THIS->stl.stats.shared_vertices; i++) { + av_extend(vertices, THIS->stl.v_shared.size()); + for (size_t i = 0; i < THIS->stl.v_shared.size(); i++) { AV* vertex = newAV(); av_store(vertices, i, newRV_noinc((SV*)vertex)); av_extend(vertex, 2); From 6defabea537ba871070fc405a14c2173cb92fc89 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Mon, 10 Jun 2019 18:30:54 +0200 Subject: [PATCH 08/22] admesh refactoring: separation of the shared vertices / indices into an indexed_triangle_set structure --- src/admesh/shared.cpp | 111 +++++++++++++++++++++++--------- src/admesh/stl.h | 26 ++++---- src/admesh/stlinit.cpp | 2 - src/admesh/util.cpp | 50 -------------- src/libslic3r/Format/3mf.cpp | 24 +++---- src/libslic3r/Format/AMF.cpp | 17 +++-- src/libslic3r/Model.cpp | 9 +-- src/libslic3r/TriangleMesh.cpp | 46 ++++++------- src/libslic3r/TriangleMesh.hpp | 3 +- src/slic3r/GUI/PresetBundle.cpp | 4 +- xs/xsp/TriangleMesh.xsp | 24 +++---- 11 files changed, 154 insertions(+), 162 deletions(-) diff --git a/src/admesh/shared.cpp b/src/admesh/shared.cpp index e9f075498..7da2841b0 100644 --- a/src/admesh/shared.cpp +++ b/src/admesh/shared.cpp @@ -29,19 +29,13 @@ #include "stl.h" -void stl_invalidate_shared_vertices(stl_file *stl) -{ - stl->v_indices.clear(); - stl->v_shared.clear(); -} - -void stl_generate_shared_vertices(stl_file *stl) +void stl_generate_shared_vertices(stl_file *stl, indexed_triangle_set &its) { // 3 indices to vertex per face - stl->v_indices.assign(stl->stats.number_of_facets, v_indices_struct()); + its.indices.assign(stl->stats.number_of_facets, v_indices_struct()); // Shared vertices (3D coordinates) - stl->v_shared.clear(); - stl->v_shared.reserve(stl->stats.number_of_facets / 2); + its.vertices.clear(); + its.vertices.reserve(stl->stats.number_of_facets / 2); // A degenerate mesh may contain loops: Traversing a fan will end up in an endless loop // while never reaching the starting face. To avoid these endless loops, traversed faces at each fan traversal @@ -51,11 +45,11 @@ void stl_generate_shared_vertices(stl_file *stl) for (uint32_t facet_idx = 0; facet_idx < stl->stats.number_of_facets; ++ facet_idx) { for (int j = 0; j < 3; ++ j) { - if (stl->v_indices[facet_idx].vertex[j] != -1) + if (its.indices[facet_idx].vertex[j] != -1) // Shared vertex was already assigned. continue; // Create a new shared vertex. - stl->v_shared.emplace_back(stl->facet_start[facet_idx].vertex[j]); + its.vertices.emplace_back(stl->facet_start[facet_idx].vertex[j]); // Traverse the fan around the j-th vertex of the i-th face, assign the newly created shared vertex index to all the neighboring triangles in the triangle fan. int facet_in_fan_idx = facet_idx; bool edge_direction = false; @@ -89,7 +83,7 @@ void stl_generate_shared_vertices(stl_file *stl) next_edge = pivot_vertex; } } - stl->v_indices[facet_in_fan_idx].vertex[pivot_vertex] = stl->v_shared.size() - 1; + its.indices[facet_in_fan_idx].vertex[pivot_vertex] = its.vertices.size() - 1; fan_traversal_facet_visited[facet_in_fan_idx] = fan_traversal_stamp; // next_edge is an index of the starting vertex of the edge, not an index of the opposite vertex to the edge! @@ -130,7 +124,7 @@ void stl_generate_shared_vertices(stl_file *stl) } } -bool stl_write_off(stl_file *stl, const char *file) +bool its_write_off(const indexed_triangle_set &its, const char *file) { /* Open the file */ FILE *fp = boost::nowide::fopen(file, "w"); @@ -143,16 +137,16 @@ bool stl_write_off(stl_file *stl, const char *file) } fprintf(fp, "OFF\n"); - fprintf(fp, "%d %d 0\n", stl->v_shared.size(), stl->stats.number_of_facets); - for (int i = 0; i < stl->v_shared.size(); ++ i) - fprintf(fp, "\t%f %f %f\n", stl->v_shared[i](0), stl->v_shared[i](1), stl->v_shared[i](2)); - for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) - fprintf(fp, "\t3 %d %d %d\n", stl->v_indices[i].vertex[0], stl->v_indices[i].vertex[1], stl->v_indices[i].vertex[2]); + fprintf(fp, "%d %d 0\n", (int)its.vertices.size(), (int)its.indices.size()); + for (int i = 0; i < its.vertices.size(); ++ i) + fprintf(fp, "\t%f %f %f\n", its.vertices[i](0), its.vertices[i](1), its.vertices[i](2)); + for (uint32_t i = 0; i < its.indices.size(); ++ i) + fprintf(fp, "\t3 %d %d %d\n", its.indices[i].vertex[0], its.indices[i].vertex[1], its.indices[i].vertex[2]); fclose(fp); return true; } -bool stl_write_vrml(stl_file *stl, const char *file) +bool its_write_vrml(const indexed_triangle_set &its, const char *file) { /* Open the file */ FILE *fp = boost::nowide::fopen(file, "w"); @@ -180,16 +174,16 @@ bool stl_write_vrml(stl_file *stl, const char *file) fprintf(fp, "\t\t\tpoint [\n"); int i = 0; - for (; i + 1 < stl->v_shared.size(); ++ i) - fprintf(fp, "\t\t\t\t%f %f %f,\n", stl->v_shared[i](0), stl->v_shared[i](1), stl->v_shared[i](2)); - fprintf(fp, "\t\t\t\t%f %f %f]\n", stl->v_shared[i](0), stl->v_shared[i](1), stl->v_shared[i](2)); + for (; i + 1 < its.vertices.size(); ++ i) + fprintf(fp, "\t\t\t\t%f %f %f,\n", its.vertices[i](0), its.vertices[i](1), its.vertices[i](2)); + fprintf(fp, "\t\t\t\t%f %f %f]\n", its.vertices[i](0), its.vertices[i](1), its.vertices[i](2)); fprintf(fp, "\t\t}\n"); fprintf(fp, "\t\tDEF STLTriangles IndexedFaceSet {\n"); fprintf(fp, "\t\t\tcoordIndex [\n"); - for (int i = 0; i + 1 < (int)stl->stats.number_of_facets; ++ i) - fprintf(fp, "\t\t\t\t%d, %d, %d, -1,\n", stl->v_indices[i].vertex[0], stl->v_indices[i].vertex[1], stl->v_indices[i].vertex[2]); - fprintf(fp, "\t\t\t\t%d, %d, %d, -1]\n", stl->v_indices[i].vertex[0], stl->v_indices[i].vertex[1], stl->v_indices[i].vertex[2]); + for (size_t i = 0; i + 1 < its.indices.size(); ++ i) + fprintf(fp, "\t\t\t\t%d, %d, %d, -1,\n", its.indices[i].vertex[0], its.indices[i].vertex[1], its.indices[i].vertex[2]); + fprintf(fp, "\t\t\t\t%d, %d, %d, -1]\n", its.indices[i].vertex[0], its.indices[i].vertex[1], its.indices[i].vertex[2]); fprintf(fp, "\t\t}\n"); fprintf(fp, "\t}\n"); fprintf(fp, "}\n"); @@ -197,7 +191,7 @@ bool stl_write_vrml(stl_file *stl, const char *file) return true; } -bool stl_write_obj(stl_file *stl, const char *file) +bool its_write_obj(const indexed_triangle_set &its, const char *file) { FILE *fp = boost::nowide::fopen(file, "w"); @@ -209,10 +203,65 @@ bool stl_write_obj(stl_file *stl, const char *file) return false; } - for (size_t i = 0; i < stl->v_shared.size(); ++ i) - fprintf(fp, "v %f %f %f\n", stl->v_shared[i](0), stl->v_shared[i](1), stl->v_shared[i](2)); - for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) - fprintf(fp, "f %d %d %d\n", stl->v_indices[i].vertex[0]+1, stl->v_indices[i].vertex[1]+1, stl->v_indices[i].vertex[2]+1); + for (size_t i = 0; i < its.vertices.size(); ++ i) + fprintf(fp, "v %f %f %f\n", its.vertices[i](0), its.vertices[i](1), its.vertices[i](2)); + for (size_t i = 0; i < its.indices.size(); ++ i) + fprintf(fp, "f %d %d %d\n", its.indices[i].vertex[0]+1, its.indices[i].vertex[1]+1, its.indices[i].vertex[2]+1); fclose(fp); return true; } + + +// Check validity of the mesh, assert on error. +bool stl_validate(const stl_file *stl, const indexed_triangle_set &its) +{ + assert(! stl->facet_start.empty()); + assert(stl->facet_start.size() == stl->stats.number_of_facets); + assert(stl->neighbors_start.size() == stl->stats.number_of_facets); + assert(stl->facet_start.size() == stl->neighbors_start.size()); + assert(! stl->neighbors_start.empty()); + assert((its.indices.empty()) == (its.vertices.empty())); + assert(stl->stats.number_of_facets > 0); + assert(its.vertices.empty() || its.indices.size() == stl->stats.number_of_facets); + +#ifdef _DEBUG + // Verify validity of neighborship data. + for (int facet_idx = 0; facet_idx < (int)stl->stats.number_of_facets; ++ facet_idx) { + const stl_neighbors &nbr = stl->neighbors_start[facet_idx]; + const int *vertices = (its.indices.empty()) ? nullptr : its.indices[facet_idx].vertex; + for (int nbr_idx = 0; nbr_idx < 3; ++ nbr_idx) { + int nbr_face = stl->neighbors_start[facet_idx].neighbor[nbr_idx]; + assert(nbr_face < (int)stl->stats.number_of_facets); + if (nbr_face != -1) { + int nbr_vnot = nbr.which_vertex_not[nbr_idx]; + assert(nbr_vnot >= 0 && nbr_vnot < 6); + // Neighbor of the neighbor is the original face. + assert(stl->neighbors_start[nbr_face].neighbor[(nbr_vnot + 1) % 3] == facet_idx); + int vnot_back = stl->neighbors_start[nbr_face].which_vertex_not[(nbr_vnot + 1) % 3]; + assert(vnot_back >= 0 && vnot_back < 6); + assert((nbr_vnot < 3) == (vnot_back < 3)); + assert(vnot_back % 3 == (nbr_idx + 2) % 3); + if (vertices != nullptr) { + // Has shared vertices. + if (nbr_vnot < 3) { + // Faces facet_idx and nbr_face share two vertices accross the common edge. Faces are correctly oriented. + assert((its.indices[nbr_face].vertex[(nbr_vnot + 1) % 3] == vertices[(nbr_idx + 1) % 3] && its.indices[nbr_face].vertex[(nbr_vnot + 2) % 3] == vertices[nbr_idx])); + } else { + // Faces facet_idx and nbr_face share two vertices accross the common edge. Faces are incorrectly oriented, one of them is flipped. + assert((its.indices[nbr_face].vertex[(nbr_vnot + 2) % 3] == vertices[(nbr_idx + 1) % 3] && its.indices[nbr_face].vertex[(nbr_vnot + 1) % 3] == vertices[nbr_idx])); + } + } + } + } + } +#endif /* _DEBUG */ + + return true; +} + +// Check validity of the mesh, assert on error. +bool stl_validate(const stl_file *stl) +{ + indexed_triangle_set its; + return stl_validate(stl, its); +} diff --git a/src/admesh/stl.h b/src/admesh/stl.h index 4aee6048f..bb5d25296 100644 --- a/src/admesh/stl.h +++ b/src/admesh/stl.h @@ -130,21 +130,22 @@ struct stl_stats { struct stl_file { std::vector facet_start; std::vector neighbors_start; - // Indexed face set - std::vector v_indices; - std::vector v_shared; // Statistics stl_stats stats; }; +struct indexed_triangle_set +{ + void clear() { indices.clear(); vertices.clear(); } + std::vector indices; + std::vector vertices; +}; + extern bool stl_open(stl_file *stl, const char *file); extern void stl_stats_out(stl_file *stl, FILE *file, char *input_file); extern bool stl_print_neighbors(stl_file *stl, char *file); -extern void stl_put_little_int(FILE *fp, int value_in); -extern void stl_put_little_float(FILE *fp, float value_in); extern bool stl_write_ascii(stl_file *stl, const char *file, const char *label); extern bool stl_write_binary(stl_file *stl, const char *file, const char *label); -extern void stl_write_binary_block(stl_file *stl, FILE *fp); extern void stl_check_facets_exact(stl_file *stl); extern void stl_check_facets_nearby(stl_file *stl, float tolerance); extern void stl_remove_unconnected_facets(stl_file *stl); @@ -219,12 +220,12 @@ inline void stl_transform(stl_file *stl, const Eigen::Matrixvertex[1] - facet->vertex[0]).cross(facet->vertex[2] - facet->vertex[0]); } @@ -251,6 +252,7 @@ extern void stl_reallocate(stl_file *stl); extern void stl_add_facet(stl_file *stl, const stl_facet *new_facet); // Validate the mesh, assert on error. -extern bool stl_validate(stl_file *stl); +extern bool stl_validate(const stl_file *stl); +extern bool stl_validate(const stl_file *stl, const indexed_triangle_set &its); #endif diff --git a/src/admesh/stlinit.cpp b/src/admesh/stlinit.cpp index 088842d51..44477511f 100644 --- a/src/admesh/stlinit.cpp +++ b/src/admesh/stlinit.cpp @@ -253,8 +253,6 @@ void stl_reset(stl_file *stl) { stl->facet_start.clear(); stl->neighbors_start.clear(); - stl->v_indices.clear(); - stl->v_shared.clear(); memset(&stl->stats, 0, sizeof(stl_stats)); stl->stats.volume = -1.0; } diff --git a/src/admesh/util.cpp b/src/admesh/util.cpp index 685b641b4..f4e4dbf0a 100644 --- a/src/admesh/util.cpp +++ b/src/admesh/util.cpp @@ -73,7 +73,6 @@ void stl_translate(stl_file *stl, float x, float y, float z) stl->facet_start[i].vertex[j] += shift; stl->stats.min = new_min; stl->stats.max += shift; - stl_invalidate_shared_vertices(stl); } /* Translates the stl by x,y,z, relatively from wherever it is currently */ @@ -85,7 +84,6 @@ void stl_translate_relative(stl_file *stl, float x, float y, float z) stl->facet_start[i].vertex[j] += shift; stl->stats.min += shift; stl->stats.max += shift; - stl_invalidate_shared_vertices(stl); } void stl_scale_versor(stl_file *stl, const stl_vertex &versor) @@ -103,7 +101,6 @@ void stl_scale_versor(stl_file *stl, const stl_vertex &versor) for (int i = 0; i < stl->stats.number_of_facets; ++ i) for (int j = 0; j < 3; ++ j) stl->facet_start[i].vertex[j].array() *= s; - stl_invalidate_shared_vertices(stl); } static void calculate_normals(stl_file *stl) @@ -414,50 +411,3 @@ All facets connected. No further nearby check necessary.\n"); stl_verify_neighbors(stl); } } - -// Check validity of the mesh, assert on error. -bool stl_validate(stl_file *stl) -{ - assert(! stl->facet_start.empty()); - assert(stl->facet_start.size() == stl->stats.number_of_facets); - assert(stl->neighbors_start.size() == stl->stats.number_of_facets); - assert(stl->facet_start.size() == stl->neighbors_start.size()); - assert(! stl->neighbors_start.empty()); - assert((stl->v_indices.empty()) == (stl->v_shared.empty())); - assert(stl->stats.number_of_facets > 0); - assert(stl->v_shared.empty() || stl->v_indices.size() == stl->stats.number_of_facets); - -#ifdef _DEBUG - // Verify validity of neighborship data. - for (int facet_idx = 0; facet_idx < (int)stl->stats.number_of_facets; ++ facet_idx) { - const stl_neighbors &nbr = stl->neighbors_start[facet_idx]; - const int *vertices = (stl->v_indices.empty()) ? nullptr : stl->v_indices[facet_idx].vertex; - for (int nbr_idx = 0; nbr_idx < 3; ++ nbr_idx) { - int nbr_face = stl->neighbors_start[facet_idx].neighbor[nbr_idx]; - assert(nbr_face < (int)stl->stats.number_of_facets); - if (nbr_face != -1) { - int nbr_vnot = nbr.which_vertex_not[nbr_idx]; - assert(nbr_vnot >= 0 && nbr_vnot < 6); - // Neighbor of the neighbor is the original face. - assert(stl->neighbors_start[nbr_face].neighbor[(nbr_vnot + 1) % 3] == facet_idx); - int vnot_back = stl->neighbors_start[nbr_face].which_vertex_not[(nbr_vnot + 1) % 3]; - assert(vnot_back >= 0 && vnot_back < 6); - assert((nbr_vnot < 3) == (vnot_back < 3)); - assert(vnot_back % 3 == (nbr_idx + 2) % 3); - if (vertices != nullptr) { - // Has shared vertices. - if (nbr_vnot < 3) { - // Faces facet_idx and nbr_face share two vertices accross the common edge. Faces are correctly oriented. - assert((stl->v_indices[nbr_face].vertex[(nbr_vnot + 1) % 3] == vertices[(nbr_idx + 1) % 3] && stl->v_indices[nbr_face].vertex[(nbr_vnot + 2) % 3] == vertices[nbr_idx])); - } else { - // Faces facet_idx and nbr_face share two vertices accross the common edge. Faces are incorrectly oriented, one of them is flipped. - assert((stl->v_indices[nbr_face].vertex[(nbr_vnot + 2) % 3] == vertices[(nbr_idx + 1) % 3] && stl->v_indices[nbr_face].vertex[(nbr_vnot + 1) % 3] == vertices[nbr_idx])); - } - } - } - } - } -#endif /* _DEBUG */ - - return true; -} diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp index d67106656..8298fe222 100644 --- a/src/libslic3r/Format/3mf.cpp +++ b/src/libslic3r/Format/3mf.cpp @@ -1881,27 +1881,23 @@ namespace Slic3r { volumes_offsets.insert(VolumeToOffsetsMap::value_type(volume, Offsets(vertices_count))).first; - if (!volume->mesh.repaired) - volume->mesh.repair(); + volume->mesh.require_shared_vertices(); - stl_file& stl = volume->mesh.stl; - if (stl.v_shared.empty()) - stl_generate_shared_vertices(&stl); - - if (stl.v_shared.empty()) + const indexed_triangle_set &its = volume->mesh.its; + if (its.vertices.empty()) { add_error("Found invalid mesh"); return false; } - vertices_count += stl.v_shared.size(); + vertices_count += its.vertices.size(); const Transform3d& matrix = volume->get_matrix(); - for (size_t i = 0; i < stl.v_shared.size(); ++i) + for (size_t i = 0; i < its.vertices.size(); ++i) { stream << " <" << VERTEX_TAG << " "; - Vec3f v = (matrix * stl.v_shared[i].cast()).cast(); + Vec3f v = (matrix * its.vertices[i].cast()).cast(); stream << "x=\"" << v(0) << "\" "; stream << "y=\"" << v(1) << "\" "; stream << "z=\"" << v(2) << "\" />\n"; @@ -1920,19 +1916,19 @@ namespace Slic3r { VolumeToOffsetsMap::iterator volume_it = volumes_offsets.find(volume); assert(volume_it != volumes_offsets.end()); - stl_file& stl = volume->mesh.stl; + const indexed_triangle_set &its = volume->mesh.its; // updates triangle offsets volume_it->second.first_triangle_id = triangles_count; - triangles_count += stl.stats.number_of_facets; + triangles_count += its.indices.size(); volume_it->second.last_triangle_id = triangles_count - 1; - for (uint32_t i = 0; i < stl.stats.number_of_facets; ++i) + for (size_t i = 0; i < its.indices.size(); ++ i) { stream << " <" << TRIANGLE_TAG << " "; for (int j = 0; j < 3; ++j) { - stream << "v" << j + 1 << "=\"" << stl.v_indices[i].vertex[j] + volume_it->second.first_vertex_id << "\" "; + stream << "v" << j + 1 << "=\"" << its.indices[i].vertex[j] + volume_it->second.first_vertex_id << "\" "; } stream << "/>\n"; } diff --git a/src/libslic3r/Format/AMF.cpp b/src/libslic3r/Format/AMF.cpp index e81ced3ad..dcd913864 100644 --- a/src/libslic3r/Format/AMF.cpp +++ b/src/libslic3r/Format/AMF.cpp @@ -923,23 +923,22 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config) int num_vertices = 0; for (ModelVolume *volume : object->volumes) { vertices_offsets.push_back(num_vertices); - if (! volume->mesh.repaired) + if (! volume->mesh.repaired) throw std::runtime_error("store_amf() requires repair()"); - auto &stl = volume->mesh.stl; - if (stl.v_shared.empty()) - stl_generate_shared_vertices(&stl); + volume->mesh.require_shared_vertices(); + const indexed_triangle_set &its = volume->mesh.its; const Transform3d& matrix = volume->get_matrix(); - for (size_t i = 0; i < stl.v_shared.size(); ++i) { + for (size_t i = 0; i < its.vertices.size(); ++i) { stream << " \n"; stream << " \n"; - Vec3f v = (matrix * stl.v_shared[i].cast()).cast(); + Vec3f v = (matrix * its.vertices[i].cast()).cast(); stream << " " << v(0) << "\n"; stream << " " << v(1) << "\n"; stream << " " << v(2) << "\n"; stream << " \n"; stream << " \n"; } - num_vertices += stl.v_shared.size(); + num_vertices += its.vertices.size(); } stream << " \n"; for (size_t i_volume = 0; i_volume < object->volumes.size(); ++i_volume) { @@ -956,10 +955,10 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config) if (volume->is_modifier()) stream << " 1\n"; stream << " " << ModelVolume::type_to_string(volume->type()) << "\n"; - for (int i = 0; i < (int)volume->mesh.stl.stats.number_of_facets; ++i) { + for (size_t i = 0; i < (int)volume->mesh.its.indices.size(); ++i) { stream << " \n"; for (int j = 0; j < 3; ++j) - stream << " " << volume->mesh.stl.v_indices[i].vertex[j] + vertices_offset << "\n"; + stream << " " << volume->mesh.its.indices[i].vertex[j] + vertices_offset << "\n"; stream << " \n"; } stream << " \n"; diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 6da7fc0c3..770581c03 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -908,10 +908,11 @@ Polygon ModelObject::convex_hull_2d(const Transform3d &trafo_instance) const Points pts; for (const ModelVolume *v : this->volumes) if (v->is_model_part()) { - const stl_file &stl = v->mesh.stl; Transform3d trafo = trafo_instance * v->get_matrix(); - if (stl.v_shared.empty()) { + const indexed_triangle_set &its = v->mesh.its; + if (its.vertices.empty()) { // Using the STL faces. + const stl_file& stl = v->mesh.stl; for (const stl_facet &facet : stl.facet_start) for (size_t j = 0; j < 3; ++ j) { Vec3d p = trafo * facet.vertex[j].cast(); @@ -919,8 +920,8 @@ Polygon ModelObject::convex_hull_2d(const Transform3d &trafo_instance) const } } else { // Using the shared vertices should be a bit quicker than using the STL faces. - for (size_t i = 0; i < stl.v_shared.size(); ++ i) { - Vec3d p = trafo * stl.v_shared[i].cast(); + for (size_t i = 0; i < its.vertices.size(); ++ i) { + Vec3d p = trafo * its.vertices[i].cast(); pts.emplace_back(coord_t(scale_(p.x())), coord_t(scale_(p.y()))); } } diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp index 003affc27..ae35c8a5b 100644 --- a/src/libslic3r/TriangleMesh.cpp +++ b/src/libslic3r/TriangleMesh.cpp @@ -238,20 +238,20 @@ bool TriangleMesh::needed_repair() const void TriangleMesh::WriteOBJFile(const char* output_file) { - stl_generate_shared_vertices(&stl); - stl_write_obj(&stl, output_file); + stl_generate_shared_vertices(&stl, its); + its_write_obj(its, output_file); } void TriangleMesh::scale(float factor) { stl_scale(&(this->stl), factor); - stl_invalidate_shared_vertices(&this->stl); + this->its.clear(); } void TriangleMesh::scale(const Vec3d &versor) { stl_scale_versor(&this->stl, versor.cast()); - stl_invalidate_shared_vertices(&this->stl); + this->its.clear(); } void TriangleMesh::translate(float x, float y, float z) @@ -259,7 +259,7 @@ void TriangleMesh::translate(float x, float y, float z) if (x == 0.f && y == 0.f && z == 0.f) return; stl_translate_relative(&(this->stl), x, y, z); - stl_invalidate_shared_vertices(&this->stl); + this->its.clear(); } void TriangleMesh::translate(const Vec3f &displacement) @@ -282,7 +282,7 @@ void TriangleMesh::rotate(float angle, const Axis &axis) } else if (axis == Z) { stl_rotate_z(&(this->stl), angle); } - stl_invalidate_shared_vertices(&this->stl); + this->its.clear(); } void TriangleMesh::rotate(float angle, const Vec3d& axis) @@ -305,13 +305,13 @@ void TriangleMesh::mirror(const Axis &axis) } else if (axis == Z) { stl_mirror_xy(&this->stl); } - stl_invalidate_shared_vertices(&this->stl); + this->its.clear(); } void TriangleMesh::transform(const Transform3d& t, bool fix_left_handed) { stl_transform(&stl, t); - stl_invalidate_shared_vertices(&stl); + this->its.clear(); if (fix_left_handed && t.matrix().block(0, 0, 3, 3).determinant() < 0.) { // Left handed transformation is being applied. It is a good idea to flip the faces and their normals. this->repair(); @@ -322,7 +322,7 @@ void TriangleMesh::transform(const Transform3d& t, bool fix_left_handed) void TriangleMesh::transform(const Matrix3d& m, bool fix_left_handed) { stl_transform(&stl, m); - stl_invalidate_shared_vertices(&stl); + this->its.clear(); if (fix_left_handed && m.determinant() < 0.) { // Left handed transformation is being applied. It is a good idea to flip the faces and their normals. this->repair(); @@ -443,7 +443,7 @@ void TriangleMesh::merge(const TriangleMesh &mesh) { // reset stats and metadata int number_of_facets = this->stl.stats.number_of_facets; - stl_invalidate_shared_vertices(&this->stl); + this->its.clear(); this->repaired = false; // update facet count and allocate more memory @@ -484,9 +484,9 @@ Polygon TriangleMesh::convex_hull() { this->require_shared_vertices(); Points pp; - pp.reserve(this->stl.v_shared.size()); - for (size_t i = 0; i < this->stl.v_shared.size(); ++ i) { - const stl_vertex &v = this->stl.v_shared[i]; + pp.reserve(this->its.vertices.size()); + for (size_t i = 0; i < this->its.vertices.size(); ++ i) { + const stl_vertex &v = this->its.vertices[i]; pp.emplace_back(Point::new_scale(v(0), v(1))); } return Slic3r::Geometry::convex_hull(pp); @@ -504,14 +504,14 @@ BoundingBoxf3 TriangleMesh::bounding_box() const BoundingBoxf3 TriangleMesh::transformed_bounding_box(const Transform3d &trafo) const { BoundingBoxf3 bbox; - if (stl.v_shared.empty()) { + if (this->its.vertices.empty()) { // Using the STL faces. for (const stl_facet &facet : this->stl.facet_start) for (size_t j = 0; j < 3; ++ j) bbox.merge(trafo * facet.vertex[j].cast()); } else { // Using the shared vertices should be a bit quicker than using the STL faces. - for (const stl_vertex &v : this->stl.v_shared) + for (const stl_vertex &v : this->its.vertices) bbox.merge(trafo * v.cast()); } return bbox; @@ -576,11 +576,11 @@ void TriangleMesh::require_shared_vertices() assert(stl_validate(&this->stl)); if (! this->repaired) this->repair(); - if (this->stl.v_shared.empty()) { + if (this->its.vertices.empty()) { BOOST_LOG_TRIVIAL(trace) << "TriangleMeshSlicer::require_shared_vertices - stl_generate_shared_vertices"; - stl_generate_shared_vertices(&(this->stl)); + stl_generate_shared_vertices(&this->stl, this->its); } - assert(stl_validate(&this->stl)); + assert(stl_validate(&this->stl, this->its)); BOOST_LOG_TRIVIAL(trace) << "TriangleMeshSlicer::require_shared_vertices - end"; } @@ -592,9 +592,9 @@ void TriangleMeshSlicer::init(const TriangleMesh *_mesh, throw_on_cancel_callbac throw_on_cancel(); facets_edges.assign(_mesh->stl.stats.number_of_facets * 3, -1); - v_scaled_shared.assign(_mesh->stl.v_shared.size(), stl_vertex()); + v_scaled_shared.assign(_mesh->its.vertices.size(), stl_vertex()); for (size_t i = 0; i < v_scaled_shared.size(); ++ i) - this->v_scaled_shared[i] = _mesh->stl.v_shared[i] / float(SCALING_FACTOR); + this->v_scaled_shared[i] = _mesh->its.vertices[i] / float(SCALING_FACTOR); // Create a mapping from triangle edge into face. struct EdgeToFace { @@ -614,8 +614,8 @@ void TriangleMeshSlicer::init(const TriangleMesh *_mesh, throw_on_cancel_callbac for (uint32_t facet_idx = 0; facet_idx < this->mesh->stl.stats.number_of_facets; ++ facet_idx) for (int i = 0; i < 3; ++ i) { EdgeToFace &e2f = edges_map[facet_idx*3+i]; - e2f.vertex_low = this->mesh->stl.v_indices[facet_idx].vertex[i]; - e2f.vertex_high = this->mesh->stl.v_indices[facet_idx].vertex[(i + 1) % 3]; + e2f.vertex_low = this->mesh->its.indices[facet_idx].vertex[i]; + e2f.vertex_high = this->mesh->its.indices[facet_idx].vertex[(i + 1) % 3]; e2f.face = facet_idx; // 1 based indexing, to be always strictly positive. e2f.face_edge = i + 1; @@ -852,7 +852,7 @@ TriangleMeshSlicer::FacetSliceType TriangleMeshSlicer::slice_facet( // Reorder vertices so that the first one is the one with lowest Z. // This is needed to get all intersection lines in a consistent order // (external on the right of the line) - const int *vertices = this->mesh->stl.v_indices[facet_idx].vertex; + const int *vertices = this->mesh->its.indices[facet_idx].vertex; int i = (facet.vertex[1].z() == min_z) ? 1 : ((facet.vertex[2].z() == min_z) ? 2 : 0); // These are used only if the cut plane is tilted: diff --git a/src/libslic3r/TriangleMesh.hpp b/src/libslic3r/TriangleMesh.hpp index c16f4a664..75082cfdb 100644 --- a/src/libslic3r/TriangleMesh.hpp +++ b/src/libslic3r/TriangleMesh.hpp @@ -69,12 +69,13 @@ public: void reset_repair_stats(); bool needed_repair() const; void require_shared_vertices(); - bool has_shared_vertices() const { return ! stl.v_shared.empty(); } + bool has_shared_vertices() const { return ! this->its.vertices.empty(); } size_t facets_count() const { return this->stl.stats.number_of_facets; } bool empty() const { return this->facets_count() == 0; } bool is_splittable() const; stl_file stl; + indexed_triangle_set its; bool repaired; private: diff --git a/src/slic3r/GUI/PresetBundle.cpp b/src/slic3r/GUI/PresetBundle.cpp index fb3b6f7a4..45092f257 100644 --- a/src/slic3r/GUI/PresetBundle.cpp +++ b/src/slic3r/GUI/PresetBundle.cpp @@ -781,7 +781,7 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool if (i == 0) suffix[0] = 0; else - sprintf(suffix, "%d", i); + sprintf(suffix, "%d", (int)i); std::string new_name = name + suffix; loaded = &this->filaments.load_preset(this->filaments.path_from_name(new_name), new_name, std::move(cfg), i == 0); @@ -1379,7 +1379,7 @@ void PresetBundle::export_configbundle(const std::string &path, bool export_syst for (size_t i = 0; i < this->filament_presets.size(); ++ i) { char suffix[64]; if (i > 0) - sprintf(suffix, "_%d", i); + sprintf(suffix, "_%d", (int)i); else suffix[0] = 0; c << "filament" << suffix << " = " << this->filament_presets[i] << std::endl; diff --git a/xs/xsp/TriangleMesh.xsp b/xs/xsp/TriangleMesh.xsp index 53b052027..3e90bfefd 100644 --- a/xs/xsp/TriangleMesh.xsp +++ b/xs/xsp/TriangleMesh.xsp @@ -98,20 +98,18 @@ SV* TriangleMesh::vertices() CODE: if (!THIS->repaired) CONFESS("vertices() requires repair()"); - - if (THIS->stl.v_shared.empty()) - stl_generate_shared_vertices(&(THIS->stl)); + THIS->require_shared_vertices(); // vertices AV* vertices = newAV(); - av_extend(vertices, THIS->stl.v_shared.size()); - for (size_t i = 0; i < THIS->stl.v_shared.size(); i++) { + av_extend(vertices, THIS->its.vertices.size()); + for (size_t i = 0; i < THIS->its.vertices.size(); i++) { AV* vertex = newAV(); av_store(vertices, i, newRV_noinc((SV*)vertex)); av_extend(vertex, 2); - av_store(vertex, 0, newSVnv(THIS->stl.v_shared[i](0))); - av_store(vertex, 1, newSVnv(THIS->stl.v_shared[i](1))); - av_store(vertex, 2, newSVnv(THIS->stl.v_shared[i](2))); + av_store(vertex, 0, newSVnv(THIS->its.vertices[i](0))); + av_store(vertex, 1, newSVnv(THIS->its.vertices[i](1))); + av_store(vertex, 2, newSVnv(THIS->its.vertices[i](2))); } RETVAL = newRV_noinc((SV*)vertices); @@ -122,9 +120,7 @@ SV* TriangleMesh::facets() CODE: if (!THIS->repaired) CONFESS("facets() requires repair()"); - - if (THIS->stl.v_shared.empty()) - stl_generate_shared_vertices(&(THIS->stl)); + THIS->require_shared_vertices(); // facets AV* facets = newAV(); @@ -133,9 +129,9 @@ TriangleMesh::facets() AV* facet = newAV(); av_store(facets, i, newRV_noinc((SV*)facet)); av_extend(facet, 2); - av_store(facet, 0, newSVnv(THIS->stl.v_indices[i].vertex[0])); - av_store(facet, 1, newSVnv(THIS->stl.v_indices[i].vertex[1])); - av_store(facet, 2, newSVnv(THIS->stl.v_indices[i].vertex[2])); + av_store(facet, 0, newSVnv(THIS->its.indices[i].vertex[0])); + av_store(facet, 1, newSVnv(THIS->its.indices[i].vertex[1])); + av_store(facet, 2, newSVnv(THIS->its.indices[i].vertex[2])); } RETVAL = newRV_noinc((SV*)facets); From 313ec7424a9714ba6de64a94b7d4b89ebae05f91 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Mon, 10 Jun 2019 19:45:38 +0200 Subject: [PATCH 09/22] admesh refactoring: replaced various diagnostics outputs with boost::log --- src/admesh/connect.cpp | 23 ++- src/admesh/shared.cpp | 16 +- src/admesh/stl.h | 2 +- src/admesh/stl_io.cpp | 283 +++++++++++-------------- src/admesh/stlinit.cpp | 356 +++++++++++++++----------------- src/admesh/util.cpp | 204 +++++++++--------- src/slic3r/GUI/PresetBundle.cpp | 2 +- 7 files changed, 405 insertions(+), 481 deletions(-) diff --git a/src/admesh/connect.cpp b/src/admesh/connect.cpp index 9553e7c4d..5ae03597e 100644 --- a/src/admesh/connect.cpp +++ b/src/admesh/connect.cpp @@ -28,6 +28,7 @@ #include #include +#include #include #include "stl.h" @@ -124,7 +125,9 @@ struct HashTableEdges { for (HashEdge *temp = this->heads[i]; this->heads[i] != this->tail; temp = this->heads[i]) { this->heads[i] = this->heads[i]->next; delete temp; +#ifndef NDEBUG ++ this->freed; +#endif /* NDEBUG */ } } this->heads.clear(); @@ -139,7 +142,9 @@ struct HashTableEdges { if (link == this->tail) { // This list doesn't have any edges currently in it. Add this one. HashEdge *new_edge = new HashEdge(edge); +#ifndef NDEBUG ++ this->malloced; +#endif /* NDEBUG */ new_edge->next = this->tail; this->heads[chain_number] = new_edge; } else if (edges_equal(edge, *link)) { @@ -148,18 +153,24 @@ struct HashTableEdges { // Delete the matched edge from the list. this->heads[chain_number] = link->next; delete link; +#ifndef NDEBUG ++ this->freed; +#endif /* NDEBUG */ } else { // Continue through the rest of the list. for (;;) { if (link->next == this->tail) { // This is the last item in the list. Insert a new edge. HashEdge *new_edge = new HashEdge; +#ifndef NDEBUG ++ this->malloced; +#endif /* NDEBUG */ *new_edge = edge; new_edge->next = this->tail; link->next = new_edge; +#ifndef NDEBUG ++ this->collisions; +#endif /* NDEBUG */ break; } if (edges_equal(edge, *link->next)) { @@ -169,12 +180,16 @@ struct HashTableEdges { HashEdge *temp = link->next; link->next = link->next->next; delete temp; +#ifndef NDEBUG ++ this->freed; +#endif /* NDEBUG */ break; } // This is not a match. Go to the next link. link = link->next; +#ifndef NDEBUG ++ this->collisions; +#endif /* NDEBUG */ } } } @@ -184,9 +199,11 @@ struct HashTableEdges { HashEdge* tail; int M; +#ifndef NDEBUG size_t malloced = 0; size_t freed = 0; size_t collisions = 0; +#endif /* NDEBUG */ private: static inline size_t hash_size_from_nr_faces(const size_t nr_faces) @@ -366,7 +383,7 @@ static void match_neighbors_nearby(stl_file *stl, const HashEdge &edge_a, const if (facet_num == first_facet) { // back to the beginning - printf("Back to the first facet changing vertices: probably a mobius part.\nTry using a smaller tolerance or don't do a nearby check\n"); + BOOST_LOG_TRIVIAL(info) << "Back to the first facet changing vertices: probably a mobius part. Try using a smaller tolerance or don't do a nearby check."; return; } } @@ -506,7 +523,7 @@ void stl_remove_unconnected_facets(stl_file *stl) if (neighbors.neighbor[i] != -1) { int &other_face_idx = stl->neighbors_start[neighbors.neighbor[i]].neighbor[(neighbors.which_vertex_not[i] + 1) % 3]; if (other_face_idx != stl->stats.number_of_facets) { - printf("in remove_facet: neighbor = %d numfacets = %d this is wrong\n", other_face_idx, stl->stats.number_of_facets); + BOOST_LOG_TRIVIAL(info) << "in remove_facet: neighbor = " << other_face_idx << " numfacets = " << stl->stats.number_of_facets << " this is wrong"; return; } other_face_idx = facet_number; @@ -697,7 +714,7 @@ void stl_fill_holes(stl_file *stl) if (facet_num == first_facet) { // back to the beginning - printf("Back to the first facet filling holes: probably a mobius part.\nTry using a smaller tolerance or don't do a nearby check\n"); + BOOST_LOG_TRIVIAL(info) << "Back to the first facet filling holes: probably a mobius part. Try using a smaller tolerance or don't do a nearby check."; return; } } diff --git a/src/admesh/shared.cpp b/src/admesh/shared.cpp index 7da2841b0..fe6d5e656 100644 --- a/src/admesh/shared.cpp +++ b/src/admesh/shared.cpp @@ -25,6 +25,7 @@ #include +#include #include #include "stl.h" @@ -129,10 +130,7 @@ bool its_write_off(const indexed_triangle_set &its, const char *file) /* Open the file */ FILE *fp = boost::nowide::fopen(file, "w"); if (fp == nullptr) { - char *error_msg = (char*)malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */ - sprintf(error_msg, "stl_write_ascii: Couldn't open %s for writing", file); - perror(error_msg); - free(error_msg); + BOOST_LOG_TRIVIAL(error) << "stl_write_ascii: Couldn't open " << file << " for writing"; return false; } @@ -151,10 +149,7 @@ bool its_write_vrml(const indexed_triangle_set &its, const char *file) /* Open the file */ FILE *fp = boost::nowide::fopen(file, "w"); if (fp == nullptr) { - char *error_msg = (char*)malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */ - sprintf(error_msg, "stl_write_ascii: Couldn't open %s for writing", file); - perror(error_msg); - free(error_msg); + BOOST_LOG_TRIVIAL(error) << "stl_write_vrml: Couldn't open " << file << " for writing"; return false; } @@ -196,10 +191,7 @@ bool its_write_obj(const indexed_triangle_set &its, const char *file) FILE *fp = boost::nowide::fopen(file, "w"); if (fp == nullptr) { - char* error_msg = (char*)malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */ - sprintf(error_msg, "stl_write_ascii: Couldn't open %s for writing", file); - perror(error_msg); - free(error_msg); + BOOST_LOG_TRIVIAL(error) << "stl_write_obj: Couldn't open " << file << " for writing"; return false; } diff --git a/src/admesh/stl.h b/src/admesh/stl.h index bb5d25296..500d6bfdb 100644 --- a/src/admesh/stl.h +++ b/src/admesh/stl.h @@ -242,7 +242,7 @@ inline bool stl_vertex_lower(const stl_vertex &a, const stl_vertex &b) { } extern void stl_calculate_volume(stl_file *stl); -extern void stl_repair(stl_file *stl, int fixall_flag, int exact_flag, int tolerance_flag, float tolerance, int increment_flag, float increment, int nearby_flag, int iterations, int remove_unconnected_flag, int fill_holes_flag, int normal_directions_flag, int normal_values_flag, int reverse_all_flag, int verbose_flag); +extern void stl_repair(stl_file *stl, bool fixall_flag, bool exact_flag, bool tolerance_flag, float tolerance, bool increment_flag, float increment, bool nearby_flag, int iterations, bool remove_unconnected_flag, bool fill_holes_flag, bool normal_directions_flag, bool normal_values_flag, bool reverse_all_flag, bool verbose_flag); extern void stl_reset(stl_file *stl); extern void stl_allocate(stl_file *stl); diff --git a/src/admesh/stl_io.cpp b/src/admesh/stl_io.cpp index 8f809d379..dc4e4a7db 100644 --- a/src/admesh/stl_io.cpp +++ b/src/admesh/stl_io.cpp @@ -24,6 +24,7 @@ #include #include "stl.h" +#include #include #include @@ -107,65 +108,47 @@ Normals fixed : %5d\n", stl->stats.normals_fixed); bool stl_write_ascii(stl_file *stl, const char *file, const char *label) { - char *error_msg; + FILE *fp = boost::nowide::fopen(file, "w"); + if (fp == NULL) { + BOOST_LOG_TRIVIAL(error) << "stl_write_ascii: Couldn't open " << file << " for writing"; + return false; + } - /* Open the file */ - FILE *fp = boost::nowide::fopen(file, "w"); - if(fp == NULL) { - error_msg = (char*) - malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */ - sprintf(error_msg, "stl_write_ascii: Couldn't open %s for writing", - file); - perror(error_msg); - free(error_msg); - return false; - } + fprintf(fp, "solid %s\n", label); - fprintf(fp, "solid %s\n", label); + for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) { + fprintf(fp, " facet normal % .8E % .8E % .8E\n", + stl->facet_start[i].normal(0), stl->facet_start[i].normal(1), + stl->facet_start[i].normal(2)); + fprintf(fp, " outer loop\n"); + fprintf(fp, " vertex % .8E % .8E % .8E\n", + stl->facet_start[i].vertex[0](0), stl->facet_start[i].vertex[0](1), + stl->facet_start[i].vertex[0](2)); + fprintf(fp, " vertex % .8E % .8E % .8E\n", + stl->facet_start[i].vertex[1](0), stl->facet_start[i].vertex[1](1), + stl->facet_start[i].vertex[1](2)); + fprintf(fp, " vertex % .8E % .8E % .8E\n", + stl->facet_start[i].vertex[2](0), stl->facet_start[i].vertex[2](1), + stl->facet_start[i].vertex[2](2)); + fprintf(fp, " endloop\n"); + fprintf(fp, " endfacet\n"); + } - for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) { - fprintf(fp, " facet normal % .8E % .8E % .8E\n", - stl->facet_start[i].normal(0), stl->facet_start[i].normal(1), - stl->facet_start[i].normal(2)); - fprintf(fp, " outer loop\n"); - fprintf(fp, " vertex % .8E % .8E % .8E\n", - stl->facet_start[i].vertex[0](0), stl->facet_start[i].vertex[0](1), - stl->facet_start[i].vertex[0](2)); - fprintf(fp, " vertex % .8E % .8E % .8E\n", - stl->facet_start[i].vertex[1](0), stl->facet_start[i].vertex[1](1), - stl->facet_start[i].vertex[1](2)); - fprintf(fp, " vertex % .8E % .8E % .8E\n", - stl->facet_start[i].vertex[2](0), stl->facet_start[i].vertex[2](1), - stl->facet_start[i].vertex[2](2)); - fprintf(fp, " endloop\n"); - fprintf(fp, " endfacet\n"); - } - - fprintf(fp, "endsolid %s\n", label); - - fclose(fp); - return true; + fprintf(fp, "endsolid %s\n", label); + fclose(fp); + return true; } bool stl_print_neighbors(stl_file *stl, char *file) { - FILE *fp; - char *error_msg; + FILE *fp = boost::nowide::fopen(file, "w"); + if (fp == NULL) { + BOOST_LOG_TRIVIAL(error) << "stl_print_neighbors: Couldn't open " << file << " for writing"; + return false; + } - /* Open the file */ - fp = boost::nowide::fopen(file, "w"); - if(fp == NULL) { - error_msg = (char*) - malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */ - sprintf(error_msg, "stl_print_neighbors: Couldn't open %s for writing", - file); - perror(error_msg); - free(error_msg); - return false; - } - - for (uint32_t i = 0; i < stl->stats.number_of_facets; i++) { - fprintf(fp, "%d, %d,%d, %d,%d, %d,%d\n", + for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) { + fprintf(fp, "%d, %d,%d, %d,%d, %d,%d\n", i, stl->neighbors_start[i].neighbor[0], (int)stl->neighbors_start[i].which_vertex_not[0], @@ -173,62 +156,54 @@ bool stl_print_neighbors(stl_file *stl, char *file) (int)stl->neighbors_start[i].which_vertex_not[1], stl->neighbors_start[i].neighbor[2], (int)stl->neighbors_start[i].which_vertex_not[2]); - } - fclose(fp); - return true; + } + fclose(fp); + return true; } #ifndef BOOST_LITTLE_ENDIAN // Swap a buffer of 32bit data from little endian to big endian and vice versa. void stl_internal_reverse_quads(char *buf, size_t cnt) { - for (size_t i = 0; i < cnt; i += 4) { - std::swap(buf[i], buf[i+3]); - std::swap(buf[i+1], buf[i+2]); - } + for (size_t i = 0; i < cnt; i += 4) { + std::swap(buf[i], buf[i+3]); + std::swap(buf[i+1], buf[i+2]); + } } #endif bool stl_write_binary(stl_file *stl, const char *file, const char *label) { - FILE *fp; - char *error_msg; + FILE *fp = boost::nowide::fopen(file, "wb"); + if (fp == NULL) { + BOOST_LOG_TRIVIAL(error) << "stl_write_binary: Couldn't open " << file << " for writing"; + return false; + } - /* Open the file */ - fp = boost::nowide::fopen(file, "wb"); - if(fp == NULL) { - error_msg = (char*) - malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */ - sprintf(error_msg, "stl_write_binary: Couldn't open %s for writing", - file); - perror(error_msg); - free(error_msg); - return false; - } + fprintf(fp, "%s", label); + for (size_t i = strlen(label); i < LABEL_SIZE; ++ i) + putc(0, fp); - fprintf(fp, "%s", label); - for(size_t i = strlen(label); i < LABEL_SIZE; i++) putc(0, fp); - - fseek(fp, LABEL_SIZE, SEEK_SET); + fseek(fp, LABEL_SIZE, SEEK_SET); #ifdef BOOST_LITTLE_ENDIAN - fwrite(&stl->stats.number_of_facets, 4, 1, fp); - for (const stl_facet &facet : stl->facet_start) - fwrite(&facet, SIZEOF_STL_FACET, 1, fp); + fwrite(&stl->stats.number_of_facets, 4, 1, fp); + for (const stl_facet &facet : stl->facet_start) + fwrite(&facet, SIZEOF_STL_FACET, 1, fp); #else /* BOOST_LITTLE_ENDIAN */ - char buffer[50]; - // Convert the number of facets to little endian. - memcpy(buffer, &stl->stats.number_of_facets, 4); - stl_internal_reverse_quads(buffer, 4); - fwrite(buffer, 4, 1, fp); - for (i = 0; i < stl->stats.number_of_facets; ++ i) { - memcpy(buffer, stl->facet_start + i, 50); - // Convert to little endian. - stl_internal_reverse_quads(buffer, 48); - fwrite(buffer, SIZEOF_STL_FACET, 1, fp); - } + char buffer[50]; + // Convert the number of facets to little endian. + memcpy(buffer, &stl->stats.number_of_facets, 4); + stl_internal_reverse_quads(buffer, 4); + fwrite(buffer, 4, 1, fp); + for (i = 0; i < stl->stats.number_of_facets; ++ i) { + memcpy(buffer, stl->facet_start + i, 50); + // Convert to little endian. + stl_internal_reverse_quads(buffer, 48); + fwrite(buffer, SIZEOF_STL_FACET, 1, fp); + } #endif /* BOOST_LITTLE_ENDIAN */ - fclose(fp); - return true; + fclose(fp); + return true; } void stl_write_vertex(stl_file *stl, int facet, int vertex) @@ -260,53 +235,39 @@ void stl_write_neighbor(stl_file *stl, int facet) bool stl_write_quad_object(stl_file *stl, char *file) { - FILE *fp; - char *error_msg; - stl_vertex connect_color = stl_vertex::Zero(); - stl_vertex uncon_1_color = stl_vertex::Zero(); - stl_vertex uncon_2_color = stl_vertex::Zero(); - stl_vertex uncon_3_color = stl_vertex::Zero(); - stl_vertex color; + stl_vertex connect_color = stl_vertex::Zero(); + stl_vertex uncon_1_color = stl_vertex::Zero(); + stl_vertex uncon_2_color = stl_vertex::Zero(); + stl_vertex uncon_3_color = stl_vertex::Zero(); + stl_vertex color; - /* Open the file */ - fp = boost::nowide::fopen(file, "w"); - if(fp == NULL) { - error_msg = (char*) - malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */ - sprintf(error_msg, "stl_write_quad_object: Couldn't open %s for writing", - file); - perror(error_msg); - free(error_msg); - return false; - } + FILE *fp = boost::nowide::fopen(file, "w"); + if (fp == NULL) { + BOOST_LOG_TRIVIAL(error) << "stl_write_quad_object: Couldn't open " << file << " for writing"; + return false; + } - fprintf(fp, "CQUAD\n"); - for (uint32_t i = 0; i < stl->stats.number_of_facets; i++) { - int j = ((stl->neighbors_start[i].neighbor[0] == -1) + - (stl->neighbors_start[i].neighbor[1] == -1) + - (stl->neighbors_start[i].neighbor[2] == -1)); - if(j == 0) { - color = connect_color; - } else if(j == 1) { - color = uncon_1_color; - } else if(j == 2) { - color = uncon_2_color; - } else { - color = uncon_3_color; - } - fprintf(fp, "%f %f %f %1.1f %1.1f %1.1f 1\n", + 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; + } + 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", + 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)); - fprintf(fp, "%f %f %f %1.1f %1.1f %1.1f 1\n", + fprintf(fp, "%f %f %f %1.1f %1.1f %1.1f 1\n", stl->facet_start[i].vertex[2](0), stl->facet_start[i].vertex[2](1), stl->facet_start[i].vertex[2](2), color(0), color(1), color(2)); - fprintf(fp, "%f %f %f %1.1f %1.1f %1.1f 1\n", + fprintf(fp, "%f %f %f %1.1f %1.1f %1.1f 1\n", stl->facet_start[i].vertex[2](0), stl->facet_start[i].vertex[2](1), stl->facet_start[i].vertex[2](2), color(0), color(1), color(2)); @@ -317,47 +278,37 @@ bool stl_write_quad_object(stl_file *stl, char *file) bool stl_write_dxf(stl_file *stl, const char *file, char *label) { - FILE *fp; - char *error_msg; + FILE *fp = boost::nowide::fopen(file, "w"); + if (fp == NULL) { + BOOST_LOG_TRIVIAL(error) << "stl_write_quad_object: Couldn't open " << file << " for writing"; + return false; + } - /* Open the file */ - fp = boost::nowide::fopen(file, "w"); - if(fp == NULL) { - error_msg = (char*) - malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */ - sprintf(error_msg, "stl_write_ascii: Couldn't open %s for writing", - file); - perror(error_msg); - free(error_msg); - return false; - } + fprintf(fp, "999\n%s\n", label); + fprintf(fp, "0\nSECTION\n2\nHEADER\n0\nENDSEC\n"); + fprintf(fp, "0\nSECTION\n2\nTABLES\n0\nTABLE\n2\nLAYER\n70\n1\n\ + 0\nLAYER\n2\n0\n70\n0\n62\n7\n6\nCONTINUOUS\n0\nENDTAB\n0\nENDSEC\n"); + fprintf(fp, "0\nSECTION\n2\nBLOCKS\n0\nENDSEC\n"); - fprintf(fp, "999\n%s\n", label); - fprintf(fp, "0\nSECTION\n2\nHEADER\n0\nENDSEC\n"); - fprintf(fp, "0\nSECTION\n2\nTABLES\n0\nTABLE\n2\nLAYER\n70\n1\n\ -0\nLAYER\n2\n0\n70\n0\n62\n7\n6\nCONTINUOUS\n0\nENDTAB\n0\nENDSEC\n"); - fprintf(fp, "0\nSECTION\n2\nBLOCKS\n0\nENDSEC\n"); + fprintf(fp, "0\nSECTION\n2\nENTITIES\n"); - fprintf(fp, "0\nSECTION\n2\nENTITIES\n"); + for (uint32_t i = 0; i < stl->stats.number_of_facets; i++) { + fprintf(fp, "0\n3DFACE\n8\n0\n"); + fprintf(fp, "10\n%f\n20\n%f\n30\n%f\n", + stl->facet_start[i].vertex[0](0), stl->facet_start[i].vertex[0](1), + stl->facet_start[i].vertex[0](2)); + fprintf(fp, "11\n%f\n21\n%f\n31\n%f\n", + stl->facet_start[i].vertex[1](0), stl->facet_start[i].vertex[1](1), + stl->facet_start[i].vertex[1](2)); + fprintf(fp, "12\n%f\n22\n%f\n32\n%f\n", + stl->facet_start[i].vertex[2](0), stl->facet_start[i].vertex[2](1), + stl->facet_start[i].vertex[2](2)); + fprintf(fp, "13\n%f\n23\n%f\n33\n%f\n", + stl->facet_start[i].vertex[2](0), stl->facet_start[i].vertex[2](1), + stl->facet_start[i].vertex[2](2)); + } - for (uint32_t i = 0; i < stl->stats.number_of_facets; i++) { - fprintf(fp, "0\n3DFACE\n8\n0\n"); - fprintf(fp, "10\n%f\n20\n%f\n30\n%f\n", - stl->facet_start[i].vertex[0](0), stl->facet_start[i].vertex[0](1), - stl->facet_start[i].vertex[0](2)); - fprintf(fp, "11\n%f\n21\n%f\n31\n%f\n", - stl->facet_start[i].vertex[1](0), stl->facet_start[i].vertex[1](1), - stl->facet_start[i].vertex[1](2)); - fprintf(fp, "12\n%f\n22\n%f\n32\n%f\n", - stl->facet_start[i].vertex[2](0), stl->facet_start[i].vertex[2](1), - stl->facet_start[i].vertex[2](2)); - fprintf(fp, "13\n%f\n23\n%f\n33\n%f\n", - stl->facet_start[i].vertex[2](0), stl->facet_start[i].vertex[2](1), - stl->facet_start[i].vertex[2](2)); - } - - fprintf(fp, "0\nENDSEC\n0\nEOF\n"); - - fclose(fp); - return true; + fprintf(fp, "0\nENDSEC\n0\nEOF\n"); + fclose(fp); + return true; } diff --git a/src/admesh/stlinit.cpp b/src/admesh/stlinit.cpp index 44477511f..24fbe9edc 100644 --- a/src/admesh/stlinit.cpp +++ b/src/admesh/stlinit.cpp @@ -26,6 +26,7 @@ #include #include +#include #include #include @@ -37,118 +38,102 @@ static FILE* stl_open_count_facets(stl_file *stl, const char *file) { - long file_size; - uint32_t header_num_facets; - uint32_t num_facets; - int i; - size_t s; - unsigned char chtest[128]; - int num_lines = 1; - char *error_msg; + // Open the file in binary mode first. + FILE *fp = boost::nowide::fopen(file, "rb"); + if (fp == nullptr) { + BOOST_LOG_TRIVIAL(error) << "stl_open_count_facets: Couldn't open " << file << " for reading"; + return nullptr; + } + // Find size of file. + fseek(fp, 0, SEEK_END); + long file_size = ftell(fp); - /* Open the file in binary mode first */ - FILE *fp = boost::nowide::fopen(file, "rb"); - if (fp == nullptr) { - error_msg = (char*) - malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */ - sprintf(error_msg, "stl_initialize: Couldn't open %s for reading", - file); - perror(error_msg); - free(error_msg); - return nullptr; - } - /* Find size of file */ - fseek(fp, 0, SEEK_END); - file_size = ftell(fp); + // Check for binary or ASCII file. + fseek(fp, HEADER_SIZE, SEEK_SET); + unsigned char chtest[128]; + if (! fread(chtest, sizeof(chtest), 1, fp)) { + BOOST_LOG_TRIVIAL(error) << "stl_open_count_facets: The input is an empty file: " << file; + fclose(fp); + return nullptr; + } + stl->stats.type = ascii; + for (size_t s = 0; s < sizeof(chtest); s++) { + if (chtest[s] > 127) { + stl->stats.type = binary; + break; + } + } + rewind(fp); - /* Check for binary or ASCII file */ - fseek(fp, HEADER_SIZE, SEEK_SET); - if (!fread(chtest, sizeof(chtest), 1, fp)) { - perror("The input is an empty file"); - fclose(fp); - return nullptr; - } - stl->stats.type = ascii; - for(s = 0; s < sizeof(chtest); s++) { - if(chtest[s] > 127) { - stl->stats.type = binary; - break; - } - } - rewind(fp); + uint32_t num_facets = 0; - /* Get the header and the number of facets in the .STL file */ - /* If the .STL file is binary, then do the following */ - if(stl->stats.type == binary) { - /* Test if the STL file has the right size */ - if(((file_size - HEADER_SIZE) % SIZEOF_STL_FACET != 0) - || (file_size < STL_MIN_FILE_SIZE)) { - fprintf(stderr, "The file %s has the wrong size.\n", file); - fclose(fp); - return nullptr; - } - num_facets = (file_size - HEADER_SIZE) / SIZEOF_STL_FACET; + // Get the header and the number of facets in the .STL file. + // If the .STL file is binary, then do the following: + if (stl->stats.type == binary) { + // Test if the STL file has the right size. + if (((file_size - HEADER_SIZE) % SIZEOF_STL_FACET != 0) || (file_size < STL_MIN_FILE_SIZE)) { + BOOST_LOG_TRIVIAL(error) << "stl_open_count_facets: The file " << file << " has the wrong size."; + fclose(fp); + return nullptr; + } + num_facets = (file_size - HEADER_SIZE) / SIZEOF_STL_FACET; - /* Read the header */ - if (fread(stl->stats.header, LABEL_SIZE, 1, fp) > 79) { - stl->stats.header[80] = '\0'; - } + // Read the header. + if (fread(stl->stats.header, LABEL_SIZE, 1, fp) > 79) + stl->stats.header[80] = '\0'; - /* Read the int following the header. This should contain # of facets */ - bool header_num_faces_read = fread(&header_num_facets, sizeof(uint32_t), 1, fp) != 0; + // Read the int following the header. This should contain # of facets. + uint32_t header_num_facets; + bool header_num_faces_read = fread(&header_num_facets, sizeof(uint32_t), 1, fp) != 0; #ifndef BOOST_LITTLE_ENDIAN - // Convert from little endian to big endian. - stl_internal_reverse_quads((char*)&header_num_facets, 4); + // Convert from little endian to big endian. + stl_internal_reverse_quads((char*)&header_num_facets, 4); #endif /* BOOST_LITTLE_ENDIAN */ - if (! header_num_faces_read || num_facets != header_num_facets) { - fprintf(stderr, - "Warning: File size doesn't match number of facets in the header\n"); - } - } - /* Otherwise, if the .STL file is ASCII, then do the following */ - else { - /* Reopen the file in text mode (for getting correct newlines on Windows) */ - // fix to silence a warning about unused return value. - // obviously if it fails we have problems.... - fp = boost::nowide::freopen(file, "r", fp); + if (! header_num_faces_read || num_facets != header_num_facets) + BOOST_LOG_TRIVIAL(info) << "stl_open_count_facets: Warning: File size doesn't match number of facets in the header: " << file; + } + // Otherwise, if the .STL file is ASCII, then do the following: + else + { + // Reopen the file in text mode (for getting correct newlines on Windows) + // fix to silence a warning about unused return value. + // obviously if it fails we have problems.... + fp = boost::nowide::freopen(file, "r", fp); - // do another null check to be safe - if(fp == nullptr) { - error_msg = (char*) - malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */ - sprintf(error_msg, "stl_initialize: Couldn't open %s for reading", - file); - perror(error_msg); - free(error_msg); - fclose(fp); - return nullptr; - } + // do another null check to be safe + if (fp == nullptr) { + BOOST_LOG_TRIVIAL(error) << "stl_open_count_facets: Couldn't open " << file << " for reading"; + fclose(fp); + return nullptr; + } - /* Find the number of facets */ - char linebuf[100]; - while (fgets(linebuf, 100, fp) != nullptr) { - /* don't count short lines */ - if (strlen(linebuf) <= 4) continue; - - /* skip solid/endsolid lines as broken STL file generators may put several of them */ - if (strncmp(linebuf, "solid", 5) == 0 || strncmp(linebuf, "endsolid", 8) == 0) continue; - - ++num_lines; - } - - rewind(fp); - - /* Get the header */ - for(i = 0; - (i < 80) && (stl->stats.header[i] = getc(fp)) != '\n'; i++); - stl->stats.header[i] = '\0'; /* Lose the '\n' */ - stl->stats.header[80] = '\0'; + // Find the number of facets. + char linebuf[100]; + int num_lines = 1; + while (fgets(linebuf, 100, fp) != nullptr) { + // Don't count short lines. + if (strlen(linebuf) <= 4) + continue; + // Skip solid/endsolid lines as broken STL file generators may put several of them. + if (strncmp(linebuf, "solid", 5) == 0 || strncmp(linebuf, "endsolid", 8) == 0) + continue; + ++ num_lines; + } - num_facets = num_lines / ASCII_LINES_PER_FACET; - } - stl->stats.number_of_facets += num_facets; - stl->stats.original_num_facets = stl->stats.number_of_facets; - return fp; + rewind(fp); + + // Get the header. + int i = 0; + for (; i < 80 && (stl->stats.header[i] = getc(fp)) != '\n'; ++ i) ; + stl->stats.header[i] = '\0'; // Lose the '\n' + stl->stats.header[80] = '\0'; + + num_facets = num_lines / ASCII_LINES_PER_FACET; + } + + stl->stats.number_of_facets += num_facets; + stl->stats.original_num_facets = stl->stats.number_of_facets; + return fp; } /* Reads the contents of the file pointed to by fp into the stl structure, @@ -156,85 +141,82 @@ static FILE* stl_open_count_facets(stl_file *stl, const char *file) time running this for the stl and therefore we should reset our max and min stats. */ static bool stl_read(stl_file *stl, FILE *fp, int first_facet, bool first) { - stl_facet facet; + if (stl->stats.type == binary) + fseek(fp, HEADER_SIZE, SEEK_SET); + else + rewind(fp); - if(stl->stats.type == binary) { - fseek(fp, HEADER_SIZE, SEEK_SET); - } else { - rewind(fp); - } + char normal_buf[3][32]; + for (uint32_t i = first_facet; i < stl->stats.number_of_facets; ++i) { + stl_facet facet; - char normal_buf[3][32]; - for(uint32_t i = first_facet; i < stl->stats.number_of_facets; i++) { - if(stl->stats.type == binary) - /* Read a single facet from a binary .STL file */ - { - /* we assume little-endian architecture! */ - if (fread(&facet, 1, SIZEOF_STL_FACET, fp) != SIZEOF_STL_FACET) - return false; + if (stl->stats.type == binary) { + // Read a single facet from a binary .STL file. We assume little-endian architecture! + if (fread(&facet, 1, SIZEOF_STL_FACET, fp) != SIZEOF_STL_FACET) + return false; #ifndef BOOST_LITTLE_ENDIAN - // Convert the loaded little endian data to big endian. - stl_internal_reverse_quads((char*)&facet, 48); + // Convert the loaded little endian data to big endian. + stl_internal_reverse_quads((char*)&facet, 48); #endif /* BOOST_LITTLE_ENDIAN */ - } else - /* Read a single facet from an ASCII .STL file */ - { - // skip solid/endsolid - // (in this order, otherwise it won't work when they are paired in the middle of a file) - fscanf(fp, "endsolid%*[^\n]\n"); - fscanf(fp, "solid%*[^\n]\n"); // name might contain spaces so %*s doesn't work and it also can be empty (just "solid") - // Leading space in the fscanf format skips all leading white spaces including numerous new lines and tabs. - int res_normal = fscanf(fp, " facet normal %31s %31s %31s", normal_buf[0], normal_buf[1], normal_buf[2]); - assert(res_normal == 3); - int res_outer_loop = fscanf(fp, " outer loop"); - assert(res_outer_loop == 0); - int res_vertex1 = fscanf(fp, " vertex %f %f %f", &facet.vertex[0](0), &facet.vertex[0](1), &facet.vertex[0](2)); - assert(res_vertex1 == 3); - int res_vertex2 = fscanf(fp, " vertex %f %f %f", &facet.vertex[1](0), &facet.vertex[1](1), &facet.vertex[1](2)); - assert(res_vertex2 == 3); - int res_vertex3 = fscanf(fp, " vertex %f %f %f", &facet.vertex[2](0), &facet.vertex[2](1), &facet.vertex[2](2)); - assert(res_vertex3 == 3); - int res_endloop = fscanf(fp, " endloop"); - assert(res_endloop == 0); - // There is a leading and trailing white space around endfacet to eat up all leading and trailing white spaces including numerous tabs and new lines. - int res_endfacet = fscanf(fp, " endfacet "); - if (res_normal != 3 || res_outer_loop != 0 || res_vertex1 != 3 || res_vertex2 != 3 || res_vertex3 != 3 || res_endloop != 0 || res_endfacet != 0) { - perror("Something is syntactically very wrong with this ASCII STL!"); - return false; - } + } else { + // Read a single facet from an ASCII .STL file + // skip solid/endsolid + // (in this order, otherwise it won't work when they are paired in the middle of a file) + fscanf(fp, "endsolid%*[^\n]\n"); + fscanf(fp, "solid%*[^\n]\n"); // name might contain spaces so %*s doesn't work and it also can be empty (just "solid") + // Leading space in the fscanf format skips all leading white spaces including numerous new lines and tabs. + int res_normal = fscanf(fp, " facet normal %31s %31s %31s", normal_buf[0], normal_buf[1], normal_buf[2]); + assert(res_normal == 3); + int res_outer_loop = fscanf(fp, " outer loop"); + assert(res_outer_loop == 0); + int res_vertex1 = fscanf(fp, " vertex %f %f %f", &facet.vertex[0](0), &facet.vertex[0](1), &facet.vertex[0](2)); + assert(res_vertex1 == 3); + int res_vertex2 = fscanf(fp, " vertex %f %f %f", &facet.vertex[1](0), &facet.vertex[1](1), &facet.vertex[1](2)); + assert(res_vertex2 == 3); + int res_vertex3 = fscanf(fp, " vertex %f %f %f", &facet.vertex[2](0), &facet.vertex[2](1), &facet.vertex[2](2)); + assert(res_vertex3 == 3); + int res_endloop = fscanf(fp, " endloop"); + assert(res_endloop == 0); + // There is a leading and trailing white space around endfacet to eat up all leading and trailing white spaces including numerous tabs and new lines. + int res_endfacet = fscanf(fp, " endfacet "); + if (res_normal != 3 || res_outer_loop != 0 || res_vertex1 != 3 || res_vertex2 != 3 || res_vertex3 != 3 || res_endloop != 0 || res_endfacet != 0) { + BOOST_LOG_TRIVIAL(error) << "Something is syntactically very wrong with this ASCII STL! "; + return false; + } - // The facet normal has been parsed as a single string as to workaround for not a numbers in the normal definition. - if (sscanf(normal_buf[0], "%f", &facet.normal(0)) != 1 || - sscanf(normal_buf[1], "%f", &facet.normal(1)) != 1 || - sscanf(normal_buf[2], "%f", &facet.normal(2)) != 1) { - // Normal was mangled. Maybe denormals or "not a number" were stored? - // Just reset the normal and silently ignore it. - memset(&facet.normal, 0, sizeof(facet.normal)); - } - } + // The facet normal has been parsed as a single string as to workaround for not a numbers in the normal definition. + if (sscanf(normal_buf[0], "%f", &facet.normal(0)) != 1 || + sscanf(normal_buf[1], "%f", &facet.normal(1)) != 1 || + sscanf(normal_buf[2], "%f", &facet.normal(2)) != 1) { + // Normal was mangled. Maybe denormals or "not a number" were stored? + // Just reset the normal and silently ignore it. + memset(&facet.normal, 0, sizeof(facet.normal)); + } + } #if 0 - // Report close to zero vertex coordinates. Due to the nature of the floating point numbers, - // close to zero values may be represented with singificantly higher precision than the rest of the vertices. - // It may be worth to round these numbers to zero during loading to reduce the number of errors reported - // during the STL import. - for (size_t j = 0; j < 3; ++ j) { - if (facet.vertex[j](0) > -1e-12f && facet.vertex[j](0) < 1e-12f) - printf("stl_read: facet %d(0) = %e\r\n", j, facet.vertex[j](0)); - if (facet.vertex[j](1) > -1e-12f && facet.vertex[j](1) < 1e-12f) - printf("stl_read: facet %d(1) = %e\r\n", j, facet.vertex[j](1)); - if (facet.vertex[j](2) > -1e-12f && facet.vertex[j](2) < 1e-12f) - printf("stl_read: facet %d(2) = %e\r\n", j, facet.vertex[j](2)); - } + // Report close to zero vertex coordinates. Due to the nature of the floating point numbers, + // close to zero values may be represented with singificantly higher precision than the rest of the vertices. + // It may be worth to round these numbers to zero during loading to reduce the number of errors reported + // during the STL import. + for (size_t j = 0; j < 3; ++ j) { + if (facet.vertex[j](0) > -1e-12f && facet.vertex[j](0) < 1e-12f) + printf("stl_read: facet %d(0) = %e\r\n", j, facet.vertex[j](0)); + if (facet.vertex[j](1) > -1e-12f && facet.vertex[j](1) < 1e-12f) + printf("stl_read: facet %d(1) = %e\r\n", j, facet.vertex[j](1)); + if (facet.vertex[j](2) > -1e-12f && facet.vertex[j](2) < 1e-12f) + printf("stl_read: facet %d(2) = %e\r\n", j, facet.vertex[j](2)); + } #endif - /* Write the facet into memory. */ - stl->facet_start[i] = facet; - stl_facet_stats(stl, facet, first); - } - stl->stats.size = stl->stats.max - stl->stats.min; - stl->stats.bounding_diameter = stl->stats.size.norm(); - return true; + // Write the facet into memory. + stl->facet_start[i] = facet; + stl_facet_stats(stl, facet, first); + } + + stl->stats.size = stl->stats.max - stl->stats.min; + stl->stats.bounding_diameter = stl->stats.size.norm(); + return true; } bool stl_open(stl_file *stl, const char *file) @@ -277,21 +259,21 @@ void stl_reallocate(stl_file *stl) void stl_facet_stats(stl_file *stl, stl_facet facet, bool &first) { - // While we are going through all of the facets, let's find the - // maximum and minimum values for x, y, and z + // While we are going through all of the facets, let's find the + // maximum and minimum values for x, y, and z - if (first) { - // Initialize the max and min values the first time through - stl->stats.min = facet.vertex[0]; - stl->stats.max = facet.vertex[0]; - stl_vertex diff = (facet.vertex[1] - facet.vertex[0]).cwiseAbs(); - stl->stats.shortest_edge = std::max(diff(0), std::max(diff(1), diff(2))); - first = false; - } + if (first) { + // Initialize the max and min values the first time through + stl->stats.min = facet.vertex[0]; + stl->stats.max = facet.vertex[0]; + stl_vertex diff = (facet.vertex[1] - facet.vertex[0]).cwiseAbs(); + stl->stats.shortest_edge = std::max(diff(0), std::max(diff(1), diff(2))); + first = false; + } - // Now find the max and min values. - for (size_t i = 0; i < 3; ++ i) { - stl->stats.min = stl->stats.min.cwiseMin(facet.vertex[i]); - stl->stats.max = stl->stats.max.cwiseMax(facet.vertex[i]); - } + // Now find the max and min values. + for (size_t i = 0; i < 3; ++ i) { + stl->stats.min = stl->stats.min.cwiseMin(facet.vertex[i]); + stl->stats.max = stl->stats.max.cwiseMax(facet.vertex[i]); + } } diff --git a/src/admesh/util.cpp b/src/admesh/util.cpp index f4e4dbf0a..bb135db95 100644 --- a/src/admesh/util.cpp +++ b/src/admesh/util.cpp @@ -25,13 +25,14 @@ #include #include +#include + #include "stl.h" static void stl_rotate(float *x, float *y, const double c, const double s); static float get_area(stl_facet *facet); static float get_volume(stl_file *stl); - void stl_verify_neighbors(stl_file *stl) { stl->stats.backwards_edges = 0; @@ -56,7 +57,7 @@ void stl_verify_neighbors(stl_file *stl) } if (edge_a.p1 != edge_b.p1 || edge_a.p2 != edge_b.p2) { // These edges should match but they don't. Print results. - printf("edge %d of facet %d doesn't match edge %d of facet %d\n", j, i, vnot + 1, neighbor); + BOOST_LOG_TRIVIAL(info) << "edge " << j << " of facet " << i << " doesn't match edge " << (vnot + 1) << " of facet " << neighbor; stl_write_facet(stl, (char*)"first facet", i); stl_write_facet(stl, (char*)"second facet", neighbor); } @@ -291,123 +292,104 @@ static float get_area(stl_facet *facet) return 0.5f * n.dot(sum); } -void stl_repair(stl_file *stl, - int fixall_flag, - int exact_flag, - int tolerance_flag, - float tolerance, - int increment_flag, - float increment, - int nearby_flag, - int iterations, - int remove_unconnected_flag, - int fill_holes_flag, - int normal_directions_flag, - int normal_values_flag, - int reverse_all_flag, - int verbose_flag) { - - int i; - int last_edges_fixed = 0; +void stl_repair( + stl_file *stl, + bool fixall_flag, + bool exact_flag, + bool tolerance_flag, + float tolerance, + bool increment_flag, + float increment, + bool nearby_flag, + int iterations, + bool remove_unconnected_flag, + bool fill_holes_flag, + bool normal_directions_flag, + bool normal_values_flag, + bool reverse_all_flag, + bool verbose_flag) +{ + if (exact_flag || fixall_flag || nearby_flag || remove_unconnected_flag || fill_holes_flag || normal_directions_flag) { + if (verbose_flag) + printf("Checking exact...\n"); + exact_flag = true; + stl_check_facets_exact(stl); + stl->stats.facets_w_1_bad_edge = (stl->stats.connected_facets_2_edge - stl->stats.connected_facets_3_edge); + stl->stats.facets_w_2_bad_edge = (stl->stats.connected_facets_1_edge - stl->stats.connected_facets_2_edge); + stl->stats.facets_w_3_bad_edge = (stl->stats.number_of_facets - stl->stats.connected_facets_1_edge); + } - if(exact_flag || fixall_flag || nearby_flag || remove_unconnected_flag - || fill_holes_flag || normal_directions_flag) { - if (verbose_flag) - printf("Checking exact...\n"); - exact_flag = 1; - stl_check_facets_exact(stl); - stl->stats.facets_w_1_bad_edge = - (stl->stats.connected_facets_2_edge - - stl->stats.connected_facets_3_edge); - stl->stats.facets_w_2_bad_edge = - (stl->stats.connected_facets_1_edge - - stl->stats.connected_facets_2_edge); - stl->stats.facets_w_3_bad_edge = - (stl->stats.number_of_facets - - stl->stats.connected_facets_1_edge); - } - - if(nearby_flag || fixall_flag) { - if(!tolerance_flag) { - tolerance = stl->stats.shortest_edge; - } - if(!increment_flag) { - increment = stl->stats.bounding_diameter / 10000.0; + if (nearby_flag || fixall_flag) { + if (! tolerance_flag) + tolerance = stl->stats.shortest_edge; + if (! increment_flag) + increment = stl->stats.bounding_diameter / 10000.0; } - if(stl->stats.connected_facets_3_edge < stl->stats.number_of_facets) { - for(i = 0; i < iterations; i++) { - if(stl->stats.connected_facets_3_edge < - stl->stats.number_of_facets) { - if (verbose_flag) - printf("\ -Checking nearby. Tolerance= %f Iteration=%d of %d...", - tolerance, i + 1, iterations); - stl_check_facets_nearby(stl, tolerance); - if (verbose_flag) - printf(" Fixed %d edges.\n", - stl->stats.edges_fixed - last_edges_fixed); - last_edges_fixed = stl->stats.edges_fixed; - tolerance += increment; - } else { - if (verbose_flag) - printf("\ -All facets connected. No further nearby check necessary.\n"); - break; - } - } - } else { - if (verbose_flag) - printf("All facets connected. No nearby check necessary.\n"); - } - } + if (stl->stats.connected_facets_3_edge < stl->stats.number_of_facets) { + int last_edges_fixed = 0; + for (int i = 0; i < iterations; ++ i) { + if (stl->stats.connected_facets_3_edge < stl->stats.number_of_facets) { + if (verbose_flag) + printf("Checking nearby. Tolerance= %f Iteration=%d of %d...", tolerance, i + 1, iterations); + stl_check_facets_nearby(stl, tolerance); + if (verbose_flag) + printf(" Fixed %d edges.\n", stl->stats.edges_fixed - last_edges_fixed); + last_edges_fixed = stl->stats.edges_fixed; + tolerance += increment; + } else { + if (verbose_flag) + printf("All facets connected. No further nearby check necessary.\n"); + break; + } + } + } else if (verbose_flag) + printf("All facets connected. No nearby check necessary.\n"); - if(remove_unconnected_flag || fixall_flag || fill_holes_flag) { - if(stl->stats.connected_facets_3_edge < stl->stats.number_of_facets) { - if (verbose_flag) - printf("Removing unconnected facets...\n"); - stl_remove_unconnected_facets(stl); - } else - if (verbose_flag) - printf("No unconnected need to be removed.\n"); - } + if (remove_unconnected_flag || fixall_flag || fill_holes_flag) { + if (stl->stats.connected_facets_3_edge < stl->stats.number_of_facets) { + if (verbose_flag) + printf("Removing unconnected facets...\n"); + stl_remove_unconnected_facets(stl); + } else if (verbose_flag) + printf("No unconnected need to be removed.\n"); + } - if(fill_holes_flag || fixall_flag) { - if(stl->stats.connected_facets_3_edge < stl->stats.number_of_facets) { - if (verbose_flag) - printf("Filling holes...\n"); - stl_fill_holes(stl); - } else - if (verbose_flag) - printf("No holes need to be filled.\n"); - } + if (fill_holes_flag || fixall_flag) { + if (stl->stats.connected_facets_3_edge < stl->stats.number_of_facets) { + if (verbose_flag) + printf("Filling holes...\n"); + stl_fill_holes(stl); + } else if (verbose_flag) + printf("No holes need to be filled.\n"); + } - if(reverse_all_flag) { - if (verbose_flag) - printf("Reversing all facets...\n"); - stl_reverse_all_facets(stl); - } + if (reverse_all_flag) { + if (verbose_flag) + printf("Reversing all facets...\n"); + stl_reverse_all_facets(stl); + } - if(normal_directions_flag || fixall_flag) { - if (verbose_flag) - printf("Checking normal directions...\n"); - stl_fix_normal_directions(stl); - } + if (normal_directions_flag || fixall_flag) { + if (verbose_flag) + printf("Checking normal directions...\n"); + stl_fix_normal_directions(stl); + } - if(normal_values_flag || fixall_flag) { - if (verbose_flag) - printf("Checking normal values...\n"); - stl_fix_normal_values(stl); - } + if (normal_values_flag || fixall_flag) { + if (verbose_flag) + printf("Checking normal values...\n"); + stl_fix_normal_values(stl); + } - /* Always calculate the volume. It shouldn't take too long */ - if (verbose_flag) - printf("Calculating volume...\n"); - stl_calculate_volume(stl); + // Always calculate the volume. It shouldn't take too long. + if (verbose_flag) + printf("Calculating volume...\n"); + stl_calculate_volume(stl); - if(exact_flag) { - if (verbose_flag) - printf("Verifying neighbors...\n"); - stl_verify_neighbors(stl); - } + if (exact_flag) { + if (verbose_flag) + printf("Verifying neighbors...\n"); + stl_verify_neighbors(stl); + } } diff --git a/src/slic3r/GUI/PresetBundle.cpp b/src/slic3r/GUI/PresetBundle.cpp index 45092f257..b28cb2eda 100644 --- a/src/slic3r/GUI/PresetBundle.cpp +++ b/src/slic3r/GUI/PresetBundle.cpp @@ -837,7 +837,7 @@ void PresetBundle::load_config_file_config_bundle(const std::string &path, const return preset_name_dst; // Try to generate another name. char buf[64]; - sprintf(buf, " (%d)", i); + sprintf(buf, " (%d)", (int)i); preset_name_dst = preset_name_src + buf + bundle_name; } } From af5017c46c42305553e42f95c4f62c2cbe27d607 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Mon, 10 Jun 2019 21:14:58 +0200 Subject: [PATCH 10/22] admesh refactoring: Use Eigen vec3i for indexed triangles. --- src/admesh/connect.cpp | 10 +- src/admesh/normals.cpp | 308 +++++++++++++++---------------- src/admesh/shared.cpp | 20 +- src/admesh/stl.h | 17 +- src/admesh/stl_io.cpp | 170 ++++++----------- src/admesh/util.cpp | 321 +++++++++++++++------------------ src/libslic3r/Format/3mf.cpp | 2 +- src/libslic3r/Format/AMF.cpp | 2 +- src/libslic3r/TriangleMesh.cpp | 6 +- xs/xsp/TriangleMesh.xsp | 6 +- 10 files changed, 369 insertions(+), 493 deletions(-) diff --git a/src/admesh/connect.cpp b/src/admesh/connect.cpp index 5ae03597e..cbd4f1d33 100644 --- a/src/admesh/connect.cpp +++ b/src/admesh/connect.cpp @@ -196,13 +196,13 @@ struct HashTableEdges { // Hash table on edges std::vector heads; - HashEdge* tail; - int M; + HashEdge* tail; + int M; #ifndef NDEBUG - size_t malloced = 0; - size_t freed = 0; - size_t collisions = 0; + size_t malloced = 0; + size_t freed = 0; + size_t collisions = 0; #endif /* NDEBUG */ private: diff --git a/src/admesh/normals.cpp b/src/admesh/normals.cpp index f20d9e68e..464f9e6d8 100644 --- a/src/admesh/normals.cpp +++ b/src/admesh/normals.cpp @@ -27,19 +27,16 @@ #include "stl.h" -static int stl_check_normal_vector(stl_file *stl, int facet_num, int normal_fix_flag); - static void reverse_facet(stl_file *stl, int facet_num) { - stl->stats.facets_reversed += 1; + ++ stl->stats.facets_reversed; int neighbor[3] = { stl->neighbors_start[facet_num].neighbor[0], stl->neighbors_start[facet_num].neighbor[1], stl->neighbors_start[facet_num].neighbor[2] }; int vnot[3] = { stl->neighbors_start[facet_num].which_vertex_not[0], stl->neighbors_start[facet_num].which_vertex_not[1], stl->neighbors_start[facet_num].which_vertex_not[2] }; // reverse the facet stl_vertex tmp_vertex = stl->facet_start[facet_num].vertex[0]; - stl->facet_start[facet_num].vertex[0] = - stl->facet_start[facet_num].vertex[1]; + stl->facet_start[facet_num].vertex[0] = stl->facet_start[facet_num].vertex[1]; stl->facet_start[facet_num].vertex[1] = tmp_vertex; // fix the vnots of the neighboring facets @@ -64,187 +61,164 @@ static void reverse_facet(stl_file *stl, int facet_num) stl->neighbors_start[facet_num].which_vertex_not[2] = (stl->neighbors_start[facet_num].which_vertex_not[2] + 3) % 6; } -void stl_fix_normal_directions(stl_file *stl) +// Returns true if the normal was flipped. +static bool check_normal_vector(stl_file *stl, int facet_num, int normal_fix_flag) { - /* int edge_num;*/ - /* int vnot;*/ - int checked = 0; - int facet_num; - /* int next_facet;*/ - int i; - int j; - struct stl_normal { - int facet_num; - struct stl_normal *next; - }; - struct stl_normal *head; - struct stl_normal *tail; - struct stl_normal *newn; - struct stl_normal *temp; + stl_facet *facet = &stl->facet_start[facet_num]; - int reversed_count = 0; - int id; - int force_exit = 0; + stl_normal normal; + stl_calculate_normal(normal, facet); + stl_normalize_vector(normal); + stl_normal normal_dif = (normal - facet->normal).cwiseAbs(); - // this may happen for malformed models, see: https://github.com/prusa3d/PrusaSlicer/issues/2209 - if (stl->stats.number_of_facets == 0) return; + const float eps = 0.001f; + if (normal_dif(0) < eps && normal_dif(1) < eps && normal_dif(2) < eps) { + // Normal is within tolerance. It is not really necessary to change the values here, but just for consistency, I will. + facet->normal = normal; + return false; + } - /* Initialize linked list. */ - head = new stl_normal; - tail = new stl_normal; - head->next = tail; - tail->next = tail; + stl_normal test_norm = facet->normal; + stl_normalize_vector(test_norm); + normal_dif = (normal - test_norm).cwiseAbs(); + if (normal_dif(0) < eps && normal_dif(1) < eps && normal_dif(2) < eps) { + // The normal is not within tolerance, but direction is OK. + if (normal_fix_flag) { + facet->normal = normal; + ++ stl->stats.normals_fixed; + } + return false; + } - /* Initialize list that keeps track of already fixed facets. */ - std::vector norm_sw(stl->stats.number_of_facets, 0); - /* Initialize list that keeps track of reversed facets. */ - std::vector reversed_ids(stl->stats.number_of_facets, 0); - - facet_num = 0; - /* If normal vector is not within tolerance and backwards: - Arbitrarily starts at face 0. If this one is wrong, we're screwed. Thankfully, the chances - of it being wrong randomly are low if most of the triangles are right: */ - if (stl_check_normal_vector(stl, 0, 0) == 2) { - reverse_facet(stl, 0); - reversed_ids[reversed_count++] = 0; - } - - /* Say that we've fixed this facet: */ - norm_sw[facet_num] = 1; - checked++; - - for(;;) { - /* Add neighbors_to_list. - Add unconnected neighbors to the list:a */ - for(j = 0; j < 3; j++) { - /* Reverse the neighboring facets if necessary. */ - if(stl->neighbors_start[facet_num].which_vertex_not[j] > 2) { - /* If the facet has a neighbor that is -1, it means that edge isn't shared by another facet */ - if(stl->neighbors_start[facet_num].neighbor[j] != -1) { - if (norm_sw[stl->neighbors_start[facet_num].neighbor[j]] == 1) { - /* trying to modify a facet already marked as fixed, revert all changes made until now and exit (fixes: #716, #574, #413, #269, #262, #259, #230, #228, #206) */ - for (id = reversed_count - 1; id >= 0; --id) { - reverse_facet(stl, reversed_ids[id]); - } - force_exit = 1; - break; - } else { - reverse_facet(stl, stl->neighbors_start[facet_num].neighbor[j]); - reversed_ids[reversed_count++] = stl->neighbors_start[facet_num].neighbor[j]; - } - } - } - /* If this edge of the facet is connected: */ - if(stl->neighbors_start[facet_num].neighbor[j] != -1) { - /* If we haven't fixed this facet yet, add it to the list: */ - if(norm_sw[stl->neighbors_start[facet_num].neighbor[j]] != 1) { - /* Add node to beginning of list. */ - newn = new stl_normal; - newn->facet_num = stl->neighbors_start[facet_num].neighbor[j]; - newn->next = head->next; - head->next = newn; - } - } - } - - /* an error occourred, quit the for loop and exit */ - if (force_exit) break; - - /* Get next facet to fix from top of list. */ - if(head->next != tail) { - facet_num = head->next->facet_num; - if(norm_sw[facet_num] != 1) { /* If facet is in list mutiple times */ - norm_sw[facet_num] = 1; /* Record this one as being fixed. */ - checked++; - } - temp = head->next; /* Delete this facet from the list. */ - head->next = head->next->next; - delete temp; - } else { /* if we ran out of facets to fix: */ - /* All of the facets in this part have been fixed. */ - stl->stats.number_of_parts += 1; - if(checked >= stl->stats.number_of_facets) { - /* All of the facets have been checked. Bail out. */ - break; - } else { - /* There is another part here. Find it and continue. */ - for(i = 0; i < stl->stats.number_of_facets; i++) { - if(norm_sw[i] == 0) { - /* This is the first facet of the next part. */ - facet_num = i; - if(stl_check_normal_vector(stl, i, 0) == 2) { - reverse_facet(stl, i); - reversed_ids[reversed_count++] = i; - } - - norm_sw[facet_num] = 1; - checked++; - break; - } - } - } - } - } - delete head; - delete tail; + test_norm *= -1.f; + normal_dif = (normal - test_norm).cwiseAbs(); + if (normal_dif(0) < eps && normal_dif(1) < eps && normal_dif(2) < eps) { + // The normal is not within tolerance and backwards. + if (normal_fix_flag) { + facet->normal = normal; + ++ stl->stats.normals_fixed; + } + return true; + } + if (normal_fix_flag) { + facet->normal = normal; + ++ stl->stats.normals_fixed; + } + // Status is unknown. + return false; } -static int stl_check_normal_vector(stl_file *stl, int facet_num, int normal_fix_flag) +void stl_fix_normal_directions(stl_file *stl) { - /* Returns 0 if the normal is within tolerance */ - /* Returns 1 if the normal is not within tolerance, but direction is OK */ - /* Returns 2 if the normal is not within tolerance and backwards */ - /* Returns 4 if the status is unknown. */ + // This may happen for malformed models, see: https://github.com/prusa3d/PrusaSlicer/issues/2209 + if (stl->stats.number_of_facets == 0) + return; - stl_facet *facet; + struct stl_normal { + int facet_num; + stl_normal *next; + }; - facet = &stl->facet_start[facet_num]; + // Initialize linked list. + stl_normal *head = new stl_normal; + stl_normal *tail = new stl_normal; + head->next = tail; + tail->next = tail; - stl_normal normal; - stl_calculate_normal(normal, facet); - stl_normalize_vector(normal); - stl_normal normal_dif = (normal - facet->normal).cwiseAbs(); + // Initialize list that keeps track of already fixed facets. + std::vector norm_sw(stl->stats.number_of_facets, 0); + // Initialize list that keeps track of reversed facets. + std::vector reversed_ids(stl->stats.number_of_facets, 0); - const float eps = 0.001f; - if (normal_dif(0) < eps && normal_dif(1) < eps && normal_dif(2) < eps) { - /* It is not really necessary to change the values here */ - /* but just for consistency, I will. */ - facet->normal = normal; - return 0; - } + int facet_num = 0; + int reversed_count = 0; + // If normal vector is not within tolerance and backwards: + // Arbitrarily starts at face 0. If this one is wrong, we're screwed. Thankfully, the chances + // of it being wrong randomly are low if most of the triangles are right: + if (check_normal_vector(stl, 0, 0)) { + reverse_facet(stl, 0); + reversed_ids[reversed_count ++] = 0; + } - stl_normal test_norm = facet->normal; - stl_normalize_vector(test_norm); - normal_dif = (normal - test_norm).cwiseAbs(); - if (normal_dif(0) < eps && normal_dif(1) < eps && normal_dif(2) < eps) { - if(normal_fix_flag) { - facet->normal = normal; - stl->stats.normals_fixed += 1; - } - return 1; - } + // Say that we've fixed this facet: + norm_sw[facet_num] = 1; + int checked = 1; - test_norm *= -1.f; - normal_dif = (normal - test_norm).cwiseAbs(); - if (normal_dif(0) < eps && normal_dif(1) < eps && normal_dif(2) < eps) { - // Facet is backwards. - if(normal_fix_flag) { - facet->normal = normal; - stl->stats.normals_fixed += 1; - } - return 2; - } - if(normal_fix_flag) { - facet->normal = normal; - stl->stats.normals_fixed += 1; - } - return 4; + for (;;) { + // Add neighbors_to_list. Add unconnected neighbors to the list. + bool force_exit = false; + for (int j = 0; j < 3; ++ j) { + // Reverse the neighboring facets if necessary. + if (stl->neighbors_start[facet_num].which_vertex_not[j] > 2) { + // If the facet has a neighbor that is -1, it means that edge isn't shared by another facet + if (stl->neighbors_start[facet_num].neighbor[j] != -1) { + if (norm_sw[stl->neighbors_start[facet_num].neighbor[j]] == 1) { + // trying to modify a facet already marked as fixed, revert all changes made until now and exit (fixes: #716, #574, #413, #269, #262, #259, #230, #228, #206) + for (int id = reversed_count - 1; id >= 0; -- id) + reverse_facet(stl, reversed_ids[id]); + force_exit = true; + break; + } + reverse_facet(stl, stl->neighbors_start[facet_num].neighbor[j]); + reversed_ids[reversed_count ++] = stl->neighbors_start[facet_num].neighbor[j]; + } + } + // If this edge of the facet is connected: + if (stl->neighbors_start[facet_num].neighbor[j] != -1) { + // If we haven't fixed this facet yet, add it to the list: + if (norm_sw[stl->neighbors_start[facet_num].neighbor[j]] != 1) { + // Add node to beginning of list. + stl_normal *newn = new stl_normal; + newn->facet_num = stl->neighbors_start[facet_num].neighbor[j]; + newn->next = head->next; + head->next = newn; + } + } + } + + // an error occourred, quit the for loop and exit + if (force_exit) + break; + + // Get next facet to fix from top of list. + if (head->next != tail) { + facet_num = head->next->facet_num; + if (norm_sw[facet_num] != 1) { // If facet is in list mutiple times + norm_sw[facet_num] = 1; // Record this one as being fixed. + ++ checked; + } + stl_normal *temp = head->next; // Delete this facet from the list. + head->next = head->next->next; + delete temp; + } else { // If we ran out of facets to fix: All of the facets in this part have been fixed. + ++ stl->stats.number_of_parts; + if (checked >= stl->stats.number_of_facets) + // All of the facets have been checked. Bail out. + break; + // There is another part here. Find it and continue. + for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) + if (norm_sw[i] == 0) { + // This is the first facet of the next part. + facet_num = i; + if (check_normal_vector(stl, i, 0)) { + reverse_facet(stl, i); + reversed_ids[reversed_count++] = i; + } + norm_sw[facet_num] = 1; + ++ checked; + break; + } + } + } + + delete head; + delete tail; } void stl_fix_normal_values(stl_file *stl) { for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) - stl_check_normal_vector(stl, i, 1); + check_normal_vector(stl, i, 1); } void stl_reverse_all_facets(stl_file *stl) diff --git a/src/admesh/shared.cpp b/src/admesh/shared.cpp index fe6d5e656..78179e863 100644 --- a/src/admesh/shared.cpp +++ b/src/admesh/shared.cpp @@ -33,7 +33,7 @@ void stl_generate_shared_vertices(stl_file *stl, indexed_triangle_set &its) { // 3 indices to vertex per face - its.indices.assign(stl->stats.number_of_facets, v_indices_struct()); + its.indices.assign(stl->stats.number_of_facets, stl_triangle_vertex_indices(-1, -1, -1)); // Shared vertices (3D coordinates) its.vertices.clear(); its.vertices.reserve(stl->stats.number_of_facets / 2); @@ -46,7 +46,7 @@ void stl_generate_shared_vertices(stl_file *stl, indexed_triangle_set &its) for (uint32_t facet_idx = 0; facet_idx < stl->stats.number_of_facets; ++ facet_idx) { for (int j = 0; j < 3; ++ j) { - if (its.indices[facet_idx].vertex[j] != -1) + if (its.indices[facet_idx][j] != -1) // Shared vertex was already assigned. continue; // Create a new shared vertex. @@ -84,7 +84,7 @@ void stl_generate_shared_vertices(stl_file *stl, indexed_triangle_set &its) next_edge = pivot_vertex; } } - its.indices[facet_in_fan_idx].vertex[pivot_vertex] = its.vertices.size() - 1; + its.indices[facet_in_fan_idx][pivot_vertex] = its.vertices.size() - 1; fan_traversal_facet_visited[facet_in_fan_idx] = fan_traversal_stamp; // next_edge is an index of the starting vertex of the edge, not an index of the opposite vertex to the edge! @@ -139,7 +139,7 @@ bool its_write_off(const indexed_triangle_set &its, const char *file) for (int i = 0; i < its.vertices.size(); ++ i) fprintf(fp, "\t%f %f %f\n", its.vertices[i](0), its.vertices[i](1), its.vertices[i](2)); for (uint32_t i = 0; i < its.indices.size(); ++ i) - fprintf(fp, "\t3 %d %d %d\n", its.indices[i].vertex[0], its.indices[i].vertex[1], its.indices[i].vertex[2]); + fprintf(fp, "\t3 %d %d %d\n", its.indices[i][0], its.indices[i][1], its.indices[i][2]); fclose(fp); return true; } @@ -177,8 +177,8 @@ bool its_write_vrml(const indexed_triangle_set &its, const char *file) fprintf(fp, "\t\t\tcoordIndex [\n"); for (size_t i = 0; i + 1 < its.indices.size(); ++ i) - fprintf(fp, "\t\t\t\t%d, %d, %d, -1,\n", its.indices[i].vertex[0], its.indices[i].vertex[1], its.indices[i].vertex[2]); - fprintf(fp, "\t\t\t\t%d, %d, %d, -1]\n", its.indices[i].vertex[0], its.indices[i].vertex[1], its.indices[i].vertex[2]); + fprintf(fp, "\t\t\t\t%d, %d, %d, -1,\n", its.indices[i][0], its.indices[i][1], its.indices[i][2]); + fprintf(fp, "\t\t\t\t%d, %d, %d, -1]\n", its.indices[i][0], its.indices[i][1], its.indices[i][2]); fprintf(fp, "\t\t}\n"); fprintf(fp, "\t}\n"); fprintf(fp, "}\n"); @@ -198,7 +198,7 @@ bool its_write_obj(const indexed_triangle_set &its, const char *file) for (size_t i = 0; i < its.vertices.size(); ++ i) fprintf(fp, "v %f %f %f\n", its.vertices[i](0), its.vertices[i](1), its.vertices[i](2)); for (size_t i = 0; i < its.indices.size(); ++ i) - fprintf(fp, "f %d %d %d\n", its.indices[i].vertex[0]+1, its.indices[i].vertex[1]+1, its.indices[i].vertex[2]+1); + fprintf(fp, "f %d %d %d\n", its.indices[i][0]+1, its.indices[i][1]+1, its.indices[i][2]+1); fclose(fp); return true; } @@ -220,7 +220,7 @@ bool stl_validate(const stl_file *stl, const indexed_triangle_set &its) // Verify validity of neighborship data. for (int facet_idx = 0; facet_idx < (int)stl->stats.number_of_facets; ++ facet_idx) { const stl_neighbors &nbr = stl->neighbors_start[facet_idx]; - const int *vertices = (its.indices.empty()) ? nullptr : its.indices[facet_idx].vertex; + const int *vertices = (its.indices.empty()) ? nullptr : its.indices[facet_idx]; for (int nbr_idx = 0; nbr_idx < 3; ++ nbr_idx) { int nbr_face = stl->neighbors_start[facet_idx].neighbor[nbr_idx]; assert(nbr_face < (int)stl->stats.number_of_facets); @@ -237,10 +237,10 @@ bool stl_validate(const stl_file *stl, const indexed_triangle_set &its) // Has shared vertices. if (nbr_vnot < 3) { // Faces facet_idx and nbr_face share two vertices accross the common edge. Faces are correctly oriented. - assert((its.indices[nbr_face].vertex[(nbr_vnot + 1) % 3] == vertices[(nbr_idx + 1) % 3] && its.indices[nbr_face].vertex[(nbr_vnot + 2) % 3] == vertices[nbr_idx])); + assert((its.indices[nbr_face][(nbr_vnot + 1) % 3] == vertices[(nbr_idx + 1) % 3] && its.indices[nbr_face][(nbr_vnot + 2) % 3] == vertices[nbr_idx])); } else { // Faces facet_idx and nbr_face share two vertices accross the common edge. Faces are incorrectly oriented, one of them is flipped. - assert((its.indices[nbr_face].vertex[(nbr_vnot + 2) % 3] == vertices[(nbr_idx + 1) % 3] && its.indices[nbr_face].vertex[(nbr_vnot + 1) % 3] == vertices[nbr_idx])); + assert((its.indices[nbr_face][(nbr_vnot + 2) % 3] == vertices[(nbr_idx + 1) % 3] && its.indices[nbr_face][(nbr_vnot + 1) % 3] == vertices[nbr_idx])); } } } diff --git a/src/admesh/stl.h b/src/admesh/stl.h index 500d6bfdb..fce23eb3f 100644 --- a/src/admesh/stl.h +++ b/src/admesh/stl.h @@ -41,6 +41,7 @@ typedef Eigen::Matrix stl_vertex; typedef Eigen::Matrix stl_normal; +typedef Eigen::Matrix stl_triangle_vertex_indices; static_assert(sizeof(stl_vertex) == 12, "size of stl_vertex incorrect"); static_assert(sizeof(stl_normal) == 12, "size of stl_normal incorrect"); @@ -68,12 +69,6 @@ static_assert(sizeof(stl_facet) >= SIZEOF_STL_FACET, "size of stl_facet incorrec typedef enum {binary, ascii, inmemory} stl_type; -struct stl_edge { - stl_vertex p1; - stl_vertex p2; - int facet_number; -}; - struct stl_neighbors { stl_neighbors() { reset(); } void reset() { @@ -93,12 +88,6 @@ struct stl_neighbors { char which_vertex_not[3]; }; -struct v_indices_struct { - // -1 means no vertex index has been assigned yet - v_indices_struct() { vertex[0] = -1; vertex[1] = -1; vertex[2] = -1; } - int vertex[3]; -}; - struct stl_stats { char header[81]; stl_type type; @@ -137,8 +126,8 @@ struct stl_file { struct indexed_triangle_set { void clear() { indices.clear(); vertices.clear(); } - std::vector indices; - std::vector vertices; + std::vector indices; + std::vector vertices; }; extern bool stl_open(stl_file *stl, const char *file); diff --git a/src/admesh/stl_io.cpp b/src/admesh/stl_io.cpp index dc4e4a7db..7e181716c 100644 --- a/src/admesh/stl_io.cpp +++ b/src/admesh/stl_io.cpp @@ -22,94 +22,55 @@ #include #include -#include "stl.h" #include #include #include -#if !defined(SEEK_SET) -#define SEEK_SET 0 -#define SEEK_CUR 1 -#define SEEK_END 2 -#endif +#include "stl.h" void stl_stats_out(stl_file *stl, FILE *file, char *input_file) { - /* this is here for Slic3r, without our config.h - it won't use this part of the code anyway */ + // This is here for Slic3r, without our config.h it won't use this part of the code anyway. #ifndef VERSION #define VERSION "unknown" #endif - fprintf(file, "\n\ -================= Results produced by ADMesh version " VERSION " ================\n"); - fprintf(file, "\ -Input file : %s\n", input_file); - if(stl->stats.type == binary) { - fprintf(file, "\ -File type : Binary STL file\n"); - } else { - fprintf(file, "\ -File type : ASCII STL file\n"); - } - fprintf(file, "\ -Header : %s\n", stl->stats.header); - fprintf(file, "============== Size ==============\n"); - fprintf(file, "Min X = % f, Max X = % f\n", - stl->stats.min(0), stl->stats.max(0)); - fprintf(file, "Min Y = % f, Max Y = % f\n", - stl->stats.min(1), stl->stats.max(1)); - fprintf(file, "Min Z = % f, Max Z = % f\n", - stl->stats.min(2), stl->stats.max(2)); - - fprintf(file, "\ -========= Facet Status ========== Original ============ Final ====\n"); - fprintf(file, "\ -Number of facets : %5d %5d\n", - stl->stats.original_num_facets, stl->stats.number_of_facets); - fprintf(file, "\ -Facets with 1 disconnected edge : %5d %5d\n", - stl->stats.facets_w_1_bad_edge, stl->stats.connected_facets_2_edge - - stl->stats.connected_facets_3_edge); - fprintf(file, "\ -Facets with 2 disconnected edges : %5d %5d\n", - stl->stats.facets_w_2_bad_edge, stl->stats.connected_facets_1_edge - - stl->stats.connected_facets_2_edge); - fprintf(file, "\ -Facets with 3 disconnected edges : %5d %5d\n", - stl->stats.facets_w_3_bad_edge, stl->stats.number_of_facets - - stl->stats.connected_facets_1_edge); - fprintf(file, "\ -Total disconnected facets : %5d %5d\n", - stl->stats.facets_w_1_bad_edge + stl->stats.facets_w_2_bad_edge + - stl->stats.facets_w_3_bad_edge, stl->stats.number_of_facets - - stl->stats.connected_facets_3_edge); - - fprintf(file, - "=== Processing Statistics === ===== Other Statistics =====\n"); - fprintf(file, "\ -Number of parts : %5d Volume : % f\n", - stl->stats.number_of_parts, stl->stats.volume); - fprintf(file, "\ -Degenerate facets : %5d\n", stl->stats.degenerate_facets); - fprintf(file, "\ -Edges fixed : %5d\n", stl->stats.edges_fixed); - fprintf(file, "\ -Facets removed : %5d\n", stl->stats.facets_removed); - fprintf(file, "\ -Facets added : %5d\n", stl->stats.facets_added); - fprintf(file, "\ -Facets reversed : %5d\n", stl->stats.facets_reversed); - fprintf(file, "\ -Backwards edges : %5d\n", stl->stats.backwards_edges); - fprintf(file, "\ -Normals fixed : %5d\n", stl->stats.normals_fixed); + fprintf(file, "\n================= Results produced by ADMesh version " VERSION " ================\n"); + fprintf(file, "Input file : %s\n", input_file); + if (stl->stats.type == binary) + fprintf(file, "File type : Binary STL file\n"); + else + fprintf(file, "File type : ASCII STL file\n"); + fprintf(file, "Header : %s\n", stl->stats.header); + fprintf(file, "============== Size ==============\n"); + fprintf(file, "Min X = % f, Max X = % f\n", stl->stats.min(0), stl->stats.max(0)); + fprintf(file, "Min Y = % f, Max Y = % f\n", stl->stats.min(1), stl->stats.max(1)); + fprintf(file, "Min Z = % f, Max Z = % f\n", stl->stats.min(2), stl->stats.max(2)); + fprintf(file, "========= Facet Status ========== Original ============ Final ====\n"); + fprintf(file, "Number of facets : %5d %5d\n", stl->stats.original_num_facets, stl->stats.number_of_facets); + fprintf(file, "Facets with 1 disconnected edge : %5d %5d\n", + stl->stats.facets_w_1_bad_edge, stl->stats.connected_facets_2_edge - stl->stats.connected_facets_3_edge); + fprintf(file, "Facets with 2 disconnected edges : %5d %5d\n", + stl->stats.facets_w_2_bad_edge, stl->stats.connected_facets_1_edge - stl->stats.connected_facets_2_edge); + fprintf(file, "Facets with 3 disconnected edges : %5d %5d\n", + stl->stats.facets_w_3_bad_edge, stl->stats.number_of_facets - stl->stats.connected_facets_1_edge); + fprintf(file, "Total disconnected facets : %5d %5d\n", + stl->stats.facets_w_1_bad_edge + stl->stats.facets_w_2_bad_edge + stl->stats.facets_w_3_bad_edge, stl->stats.number_of_facets - stl->stats.connected_facets_3_edge); + fprintf(file, "=== Processing Statistics === ===== Other Statistics =====\n"); + fprintf(file, "Number of parts : %5d Volume : %f\n", stl->stats.number_of_parts, stl->stats.volume); + fprintf(file, "Degenerate facets : %5d\n", stl->stats.degenerate_facets); + fprintf(file, "Edges fixed : %5d\n", stl->stats.edges_fixed); + fprintf(file, "Facets removed : %5d\n", stl->stats.facets_removed); + fprintf(file, "Facets added : %5d\n", stl->stats.facets_added); + fprintf(file, "Facets reversed : %5d\n", stl->stats.facets_reversed); + fprintf(file, "Backwards edges : %5d\n", stl->stats.backwards_edges); + fprintf(file, "Normals fixed : %5d\n", stl->stats.normals_fixed); } bool stl_write_ascii(stl_file *stl, const char *file, const char *label) { FILE *fp = boost::nowide::fopen(file, "w"); - if (fp == NULL) { + if (fp == nullptr) { BOOST_LOG_TRIVIAL(error) << "stl_write_ascii: Couldn't open " << file << " for writing"; return false; } @@ -117,19 +78,11 @@ bool stl_write_ascii(stl_file *stl, const char *file, const char *label) fprintf(fp, "solid %s\n", label); for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) { - fprintf(fp, " facet normal % .8E % .8E % .8E\n", - stl->facet_start[i].normal(0), stl->facet_start[i].normal(1), - stl->facet_start[i].normal(2)); + fprintf(fp, " facet normal % .8E % .8E % .8E\n", stl->facet_start[i].normal(0), stl->facet_start[i].normal(1), stl->facet_start[i].normal(2)); fprintf(fp, " outer loop\n"); - fprintf(fp, " vertex % .8E % .8E % .8E\n", - stl->facet_start[i].vertex[0](0), stl->facet_start[i].vertex[0](1), - stl->facet_start[i].vertex[0](2)); - fprintf(fp, " vertex % .8E % .8E % .8E\n", - stl->facet_start[i].vertex[1](0), stl->facet_start[i].vertex[1](1), - stl->facet_start[i].vertex[1](2)); - fprintf(fp, " vertex % .8E % .8E % .8E\n", - stl->facet_start[i].vertex[2](0), stl->facet_start[i].vertex[2](1), - stl->facet_start[i].vertex[2](2)); + fprintf(fp, " vertex % .8E % .8E % .8E\n", stl->facet_start[i].vertex[0](0), stl->facet_start[i].vertex[0](1), stl->facet_start[i].vertex[0](2)); + fprintf(fp, " vertex % .8E % .8E % .8E\n", stl->facet_start[i].vertex[1](0), stl->facet_start[i].vertex[1](1), stl->facet_start[i].vertex[1](2)); + fprintf(fp, " vertex % .8E % .8E % .8E\n", stl->facet_start[i].vertex[2](0), stl->facet_start[i].vertex[2](1), stl->facet_start[i].vertex[2](2)); fprintf(fp, " endloop\n"); fprintf(fp, " endfacet\n"); } @@ -142,7 +95,7 @@ bool stl_write_ascii(stl_file *stl, const char *file, const char *label) bool stl_print_neighbors(stl_file *stl, char *file) { FILE *fp = boost::nowide::fopen(file, "w"); - if (fp == NULL) { + if (fp == nullptr) { BOOST_LOG_TRIVIAL(error) << "stl_print_neighbors: Couldn't open " << file << " for writing"; return false; } @@ -175,7 +128,7 @@ void stl_internal_reverse_quads(char *buf, size_t cnt) bool stl_write_binary(stl_file *stl, const char *file, const char *label) { FILE *fp = boost::nowide::fopen(file, "wb"); - if (fp == NULL) { + if (fp == nullptr) { BOOST_LOG_TRIVIAL(error) << "stl_write_binary: Couldn't open " << file << " for writing"; return false; } @@ -184,6 +137,9 @@ bool stl_write_binary(stl_file *stl, const char *file, const char *label) for (size_t i = strlen(label); i < LABEL_SIZE; ++ i) putc(0, fp); +#if !defined(SEEK_SET) + #define SEEK_SET 0 +#endif fseek(fp, LABEL_SIZE, SEEK_SET); #ifdef BOOST_LITTLE_ENDIAN fwrite(&stl->stats.number_of_facets, 4, 1, fp); @@ -242,7 +198,7 @@ bool stl_write_quad_object(stl_file *stl, char *file) stl_vertex color; FILE *fp = boost::nowide::fopen(file, "w"); - if (fp == NULL) { + if (fp == nullptr) { BOOST_LOG_TRIVIAL(error) << "stl_write_quad_object: Couldn't open " << file << " for writing"; return false; } @@ -255,22 +211,10 @@ bool stl_write_quad_object(stl_file *stl, char *file) case 2: color = uncon_2_color; break; default: color = uncon_3_color; } - 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)); - fprintf(fp, "%f %f %f %1.1f %1.1f %1.1f 1\n", - stl->facet_start[i].vertex[2](0), - stl->facet_start[i].vertex[2](1), - stl->facet_start[i].vertex[2](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[2](0), - stl->facet_start[i].vertex[2](1), - stl->facet_start[i].vertex[2](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[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)); + fprintf(fp, "%f %f %f %1.1f %1.1f %1.1f 1\n", stl->facet_start[i].vertex[2](0), stl->facet_start[i].vertex[2](1), stl->facet_start[i].vertex[2](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[2](0), stl->facet_start[i].vertex[2](1), stl->facet_start[i].vertex[2](2), color(0), color(1), color(2)); } fclose(fp); return true; @@ -279,7 +223,7 @@ bool stl_write_quad_object(stl_file *stl, char *file) bool stl_write_dxf(stl_file *stl, const char *file, char *label) { FILE *fp = boost::nowide::fopen(file, "w"); - if (fp == NULL) { + if (fp == nullptr) { BOOST_LOG_TRIVIAL(error) << "stl_write_quad_object: Couldn't open " << file << " for writing"; return false; } @@ -292,20 +236,12 @@ bool stl_write_dxf(stl_file *stl, const char *file, char *label) fprintf(fp, "0\nSECTION\n2\nENTITIES\n"); - for (uint32_t i = 0; i < stl->stats.number_of_facets; i++) { + for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) { fprintf(fp, "0\n3DFACE\n8\n0\n"); - fprintf(fp, "10\n%f\n20\n%f\n30\n%f\n", - stl->facet_start[i].vertex[0](0), stl->facet_start[i].vertex[0](1), - stl->facet_start[i].vertex[0](2)); - fprintf(fp, "11\n%f\n21\n%f\n31\n%f\n", - stl->facet_start[i].vertex[1](0), stl->facet_start[i].vertex[1](1), - stl->facet_start[i].vertex[1](2)); - fprintf(fp, "12\n%f\n22\n%f\n32\n%f\n", - stl->facet_start[i].vertex[2](0), stl->facet_start[i].vertex[2](1), - stl->facet_start[i].vertex[2](2)); - fprintf(fp, "13\n%f\n23\n%f\n33\n%f\n", - stl->facet_start[i].vertex[2](0), stl->facet_start[i].vertex[2](1), - stl->facet_start[i].vertex[2](2)); + fprintf(fp, "10\n%f\n20\n%f\n30\n%f\n", stl->facet_start[i].vertex[0](0), stl->facet_start[i].vertex[0](1), stl->facet_start[i].vertex[0](2)); + fprintf(fp, "11\n%f\n21\n%f\n31\n%f\n", stl->facet_start[i].vertex[1](0), stl->facet_start[i].vertex[1](1), stl->facet_start[i].vertex[1](2)); + fprintf(fp, "12\n%f\n22\n%f\n32\n%f\n", stl->facet_start[i].vertex[2](0), stl->facet_start[i].vertex[2](1), stl->facet_start[i].vertex[2](2)); + fprintf(fp, "13\n%f\n23\n%f\n33\n%f\n", stl->facet_start[i].vertex[2](0), stl->facet_start[i].vertex[2](1), stl->facet_start[i].vertex[2](2)); } fprintf(fp, "0\nENDSEC\n0\nEOF\n"); diff --git a/src/admesh/util.cpp b/src/admesh/util.cpp index bb135db95..6fff8a8ed 100644 --- a/src/admesh/util.cpp +++ b/src/admesh/util.cpp @@ -29,16 +29,17 @@ #include "stl.h" -static void stl_rotate(float *x, float *y, const double c, const double s); -static float get_area(stl_facet *facet); -static float get_volume(stl_file *stl); - void stl_verify_neighbors(stl_file *stl) { stl->stats.backwards_edges = 0; for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) { for (int j = 0; j < 3; ++ j) { + struct stl_edge { + stl_vertex p1; + stl_vertex p2; + int facet_number; + }; stl_edge edge_a; edge_a.p1 = stl->facet_start[i].vertex[j]; edge_a.p2 = stl->facet_start[i].vertex[(j + 1) % 3]; @@ -67,164 +68,140 @@ void stl_verify_neighbors(stl_file *stl) void stl_translate(stl_file *stl, float x, float y, float z) { - stl_vertex new_min(x, y, z); - stl_vertex shift = new_min - stl->stats.min; - for (int i = 0; i < stl->stats.number_of_facets; ++ i) - for (int j = 0; j < 3; ++ j) - stl->facet_start[i].vertex[j] += shift; - stl->stats.min = new_min; - stl->stats.max += shift; + stl_vertex new_min(x, y, z); + stl_vertex shift = new_min - stl->stats.min; + for (int i = 0; i < stl->stats.number_of_facets; ++ i) + for (int j = 0; j < 3; ++ j) + stl->facet_start[i].vertex[j] += shift; + stl->stats.min = new_min; + stl->stats.max += shift; } /* Translates the stl by x,y,z, relatively from wherever it is currently */ void stl_translate_relative(stl_file *stl, float x, float y, float z) { - stl_vertex shift(x, y, z); - for (int i = 0; i < stl->stats.number_of_facets; ++ i) - for (int j = 0; j < 3; ++ j) - stl->facet_start[i].vertex[j] += shift; - stl->stats.min += shift; - stl->stats.max += shift; + stl_vertex shift(x, y, z); + for (int i = 0; i < stl->stats.number_of_facets; ++ i) + for (int j = 0; j < 3; ++ j) + stl->facet_start[i].vertex[j] += shift; + stl->stats.min += shift; + stl->stats.max += shift; } void stl_scale_versor(stl_file *stl, const stl_vertex &versor) { - // Scale extents. - auto s = versor.array(); - stl->stats.min.array() *= s; - stl->stats.max.array() *= s; - // Scale size. - stl->stats.size.array() *= s; - // Scale volume. - if (stl->stats.volume > 0.0) - stl->stats.volume *= versor(0) * versor(1) * versor(2); - // Scale the mesh. - for (int i = 0; i < stl->stats.number_of_facets; ++ i) - for (int j = 0; j < 3; ++ j) - stl->facet_start[i].vertex[j].array() *= s; + // Scale extents. + auto s = versor.array(); + stl->stats.min.array() *= s; + stl->stats.max.array() *= s; + // Scale size. + stl->stats.size.array() *= s; + // Scale volume. + if (stl->stats.volume > 0.0) + stl->stats.volume *= versor(0) * versor(1) * versor(2); + // Scale the mesh. + for (int i = 0; i < stl->stats.number_of_facets; ++ i) + for (int j = 0; j < 3; ++ j) + stl->facet_start[i].vertex[j].array() *= s; } static void calculate_normals(stl_file *stl) { - stl_normal normal; - for(uint32_t i = 0; i < stl->stats.number_of_facets; i++) { - stl_calculate_normal(normal, &stl->facet_start[i]); - stl_normalize_vector(normal); - stl->facet_start[i].normal = normal; - } + stl_normal normal; + for (uint32_t i = 0; i < stl->stats.number_of_facets; i++) { + stl_calculate_normal(normal, &stl->facet_start[i]); + stl_normalize_vector(normal); + stl->facet_start[i].normal = normal; + } } -void -stl_rotate_x(stl_file *stl, float angle) { - int i; - int j; - double radian_angle = (angle / 180.0) * M_PI; - double c = cos(radian_angle); - double s = sin(radian_angle); - - for(i = 0; i < stl->stats.number_of_facets; i++) { - for(j = 0; j < 3; j++) { - stl_rotate(&stl->facet_start[i].vertex[j](1), - &stl->facet_start[i].vertex[j](2), c, s); - } - } - stl_get_size(stl); - calculate_normals(stl); +static void rotate_point_2d(float *x, float *y, const double c, const double s) +{ + double xold = *x; + double yold = *y; + *x = float(c * xold - s * yold); + *y = float(s * xold + c * yold); } -void -stl_rotate_y(stl_file *stl, float angle) { - int i; - int j; - double radian_angle = (angle / 180.0) * M_PI; - double c = cos(radian_angle); - double s = sin(radian_angle); - - for(i = 0; i < stl->stats.number_of_facets; i++) { - for(j = 0; j < 3; j++) { - stl_rotate(&stl->facet_start[i].vertex[j](2), - &stl->facet_start[i].vertex[j](0), c, s); - } - } - stl_get_size(stl); - calculate_normals(stl); +void stl_rotate_x(stl_file *stl, float angle) +{ + double radian_angle = (angle / 180.0) * M_PI; + double c = cos(radian_angle); + double s = sin(radian_angle); + for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) + for (int j = 0; j < 3; ++ j) + rotate_point_2d(&stl->facet_start[i].vertex[j](1), &stl->facet_start[i].vertex[j](2), c, s); + stl_get_size(stl); + calculate_normals(stl); } -void -stl_rotate_z(stl_file *stl, float angle) { - int i; - int j; - double radian_angle = (angle / 180.0) * M_PI; - double c = cos(radian_angle); - double s = sin(radian_angle); - - for(i = 0; i < stl->stats.number_of_facets; i++) { - for(j = 0; j < 3; j++) { - stl_rotate(&stl->facet_start[i].vertex[j](0), - &stl->facet_start[i].vertex[j](1), c, s); - } - } - stl_get_size(stl); - calculate_normals(stl); +void stl_rotate_y(stl_file *stl, float angle) +{ + double radian_angle = (angle / 180.0) * M_PI; + double c = cos(radian_angle); + double s = sin(radian_angle); + for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) + for (int j = 0; j < 3; ++ j) + rotate_point_2d(&stl->facet_start[i].vertex[j](2), &stl->facet_start[i].vertex[j](0), c, s); + stl_get_size(stl); + calculate_normals(stl); } - - -static void -stl_rotate(float *x, float *y, const double c, const double s) { - double xold = *x; - double yold = *y; - *x = float(c * xold - s * yold); - *y = float(s * xold + c * yold); +void stl_rotate_z(stl_file *stl, float angle) +{ + double radian_angle = (angle / 180.0) * M_PI; + double c = cos(radian_angle); + double s = sin(radian_angle); + for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) + for (int j = 0; j < 3; ++ j) + rotate_point_2d(&stl->facet_start[i].vertex[j](0), &stl->facet_start[i].vertex[j](1), c, s); + stl_get_size(stl); + calculate_normals(stl); } void stl_get_size(stl_file *stl) { - if (stl->stats.number_of_facets == 0) - return; - stl->stats.min = stl->facet_start[0].vertex[0]; - stl->stats.max = stl->stats.min; - for (int i = 0; i < stl->stats.number_of_facets; ++ i) { - const stl_facet &face = stl->facet_start[i]; - for (int j = 0; j < 3; ++ j) { - stl->stats.min = stl->stats.min.cwiseMin(face.vertex[j]); - stl->stats.max = stl->stats.max.cwiseMax(face.vertex[j]); - } - } - stl->stats.size = stl->stats.max - stl->stats.min; - stl->stats.bounding_diameter = stl->stats.size.norm(); + if (stl->stats.number_of_facets == 0) + return; + stl->stats.min = stl->facet_start[0].vertex[0]; + stl->stats.max = stl->stats.min; + for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) { + const stl_facet &face = stl->facet_start[i]; + for (int j = 0; j < 3; ++ j) { + stl->stats.min = stl->stats.min.cwiseMin(face.vertex[j]); + stl->stats.max = stl->stats.max.cwiseMax(face.vertex[j]); + } + } + stl->stats.size = stl->stats.max - stl->stats.min; + stl->stats.bounding_diameter = stl->stats.size.norm(); } void stl_mirror_xy(stl_file *stl) { - for(int i = 0; i < stl->stats.number_of_facets; i++) { - for(int j = 0; j < 3; j++) { - stl->facet_start[i].vertex[j](2) *= -1.0; - } - } - float temp_size = stl->stats.min(2); - stl->stats.min(2) = stl->stats.max(2); - stl->stats.max(2) = temp_size; - stl->stats.min(2) *= -1.0; - stl->stats.max(2) *= -1.0; - stl_reverse_all_facets(stl); - stl->stats.facets_reversed -= stl->stats.number_of_facets; /* for not altering stats */ + for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) + for (int j = 0; j < 3; ++ j) + stl->facet_start[i].vertex[j](2) *= -1.0; + float temp_size = stl->stats.min(2); + stl->stats.min(2) = stl->stats.max(2); + stl->stats.max(2) = temp_size; + stl->stats.min(2) *= -1.0; + stl->stats.max(2) *= -1.0; + stl_reverse_all_facets(stl); + stl->stats.facets_reversed -= stl->stats.number_of_facets; /* for not altering stats */ } void stl_mirror_yz(stl_file *stl) { - for (int i = 0; i < stl->stats.number_of_facets; i++) { - for (int j = 0; j < 3; j++) { - stl->facet_start[i].vertex[j](0) *= -1.0; - } - } - float temp_size = stl->stats.min(0); - stl->stats.min(0) = stl->stats.max(0); - stl->stats.max(0) = temp_size; - stl->stats.min(0) *= -1.0; - stl->stats.max(0) *= -1.0; - stl_reverse_all_facets(stl); - stl->stats.facets_reversed -= stl->stats.number_of_facets; /* for not altering stats */ + for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) + for (int j = 0; j < 3; j++) + stl->facet_start[i].vertex[j](0) *= -1.0; + float temp_size = stl->stats.min(0); + stl->stats.min(0) = stl->stats.max(0); + stl->stats.max(0) = temp_size; + stl->stats.min(0) *= -1.0; + stl->stats.max(0) *= -1.0; + stl_reverse_all_facets(stl); + stl->stats.facets_reversed -= stl->stats.number_of_facets; /* for not altering stats */ } void stl_mirror_xz(stl_file *stl) @@ -241,55 +218,55 @@ void stl_mirror_xz(stl_file *stl) stl->stats.facets_reversed -= stl->stats.number_of_facets; // for not altering stats } +static float get_area(stl_facet *facet) +{ + /* cast to double before calculating cross product because large coordinates + can result in overflowing product + (bad area is responsible for bad volume and bad facets reversal) */ + double cross[3][3]; + for (int i = 0; i < 3; i++) { + cross[i][0]=(((double)facet->vertex[i](1) * (double)facet->vertex[(i + 1) % 3](2)) - + ((double)facet->vertex[i](2) * (double)facet->vertex[(i + 1) % 3](1))); + cross[i][1]=(((double)facet->vertex[i](2) * (double)facet->vertex[(i + 1) % 3](0)) - + ((double)facet->vertex[i](0) * (double)facet->vertex[(i + 1) % 3](2))); + cross[i][2]=(((double)facet->vertex[i](0) * (double)facet->vertex[(i + 1) % 3](1)) - + ((double)facet->vertex[i](1) * (double)facet->vertex[(i + 1) % 3](0))); + } + + stl_normal sum; + sum(0) = cross[0][0] + cross[1][0] + cross[2][0]; + sum(1) = cross[0][1] + cross[1][1] + cross[2][1]; + sum(2) = cross[0][2] + cross[1][2] + cross[2][2]; + + // This should already be done. But just in case, let's do it again. + //FIXME this is questionable. the "sum" normal should be accurate, while the normal "n" may be calculated with a low accuracy. + stl_normal n; + stl_calculate_normal(n, facet); + stl_normalize_vector(n); + return 0.5f * n.dot(sum); +} + static float get_volume(stl_file *stl) { - // Choose a point, any point as the reference. - stl_vertex p0 = stl->facet_start[0].vertex[0]; - float volume = 0.f; - for(uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) { - // Do dot product to get distance from point to plane. - float height = stl->facet_start[i].normal.dot(stl->facet_start[i].vertex[0] - p0); - float area = get_area(&stl->facet_start[i]); - volume += (area * height) / 3.0f; - } - return volume; + // Choose a point, any point as the reference. + stl_vertex p0 = stl->facet_start[0].vertex[0]; + float volume = 0.f; + for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) { + // Do dot product to get distance from point to plane. + float height = stl->facet_start[i].normal.dot(stl->facet_start[i].vertex[0] - p0); + float area = get_area(&stl->facet_start[i]); + volume += (area * height) / 3.0f; + } + return volume; } void stl_calculate_volume(stl_file *stl) { - stl->stats.volume = get_volume(stl); - if(stl->stats.volume < 0.0) { - stl_reverse_all_facets(stl); - stl->stats.volume = -stl->stats.volume; - } -} - -static float get_area(stl_facet *facet) -{ - /* cast to double before calculating cross product because large coordinates - can result in overflowing product - (bad area is responsible for bad volume and bad facets reversal) */ - double cross[3][3]; - for (int i = 0; i < 3; i++) { - cross[i][0]=(((double)facet->vertex[i](1) * (double)facet->vertex[(i + 1) % 3](2)) - - ((double)facet->vertex[i](2) * (double)facet->vertex[(i + 1) % 3](1))); - cross[i][1]=(((double)facet->vertex[i](2) * (double)facet->vertex[(i + 1) % 3](0)) - - ((double)facet->vertex[i](0) * (double)facet->vertex[(i + 1) % 3](2))); - cross[i][2]=(((double)facet->vertex[i](0) * (double)facet->vertex[(i + 1) % 3](1)) - - ((double)facet->vertex[i](1) * (double)facet->vertex[(i + 1) % 3](0))); - } - - stl_normal sum; - sum(0) = cross[0][0] + cross[1][0] + cross[2][0]; - sum(1) = cross[0][1] + cross[1][1] + cross[2][1]; - sum(2) = cross[0][2] + cross[1][2] + cross[2][2]; - - // This should already be done. But just in case, let's do it again. - //FIXME this is questionable. the "sum" normal should be accurate, while the normal "n" may be calculated with a low accuracy. - stl_normal n; - stl_calculate_normal(n, facet); - stl_normalize_vector(n); - return 0.5f * n.dot(sum); + stl->stats.volume = get_volume(stl); + if (stl->stats.volume < 0.0) { + stl_reverse_all_facets(stl); + stl->stats.volume = -stl->stats.volume; + } } void stl_repair( diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp index 8298fe222..654426528 100644 --- a/src/libslic3r/Format/3mf.cpp +++ b/src/libslic3r/Format/3mf.cpp @@ -1928,7 +1928,7 @@ namespace Slic3r { stream << " <" << TRIANGLE_TAG << " "; for (int j = 0; j < 3; ++j) { - stream << "v" << j + 1 << "=\"" << its.indices[i].vertex[j] + volume_it->second.first_vertex_id << "\" "; + stream << "v" << j + 1 << "=\"" << its.indices[i][j] + volume_it->second.first_vertex_id << "\" "; } stream << "/>\n"; } diff --git a/src/libslic3r/Format/AMF.cpp b/src/libslic3r/Format/AMF.cpp index dcd913864..48887bc78 100644 --- a/src/libslic3r/Format/AMF.cpp +++ b/src/libslic3r/Format/AMF.cpp @@ -958,7 +958,7 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config) for (size_t i = 0; i < (int)volume->mesh.its.indices.size(); ++i) { stream << " \n"; for (int j = 0; j < 3; ++j) - stream << " " << volume->mesh.its.indices[i].vertex[j] + vertices_offset << "\n"; + stream << " " << volume->mesh.its.indices[i][j] + vertices_offset << "\n"; stream << " \n"; } stream << " \n"; diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp index ae35c8a5b..5b0ecbd00 100644 --- a/src/libslic3r/TriangleMesh.cpp +++ b/src/libslic3r/TriangleMesh.cpp @@ -614,8 +614,8 @@ void TriangleMeshSlicer::init(const TriangleMesh *_mesh, throw_on_cancel_callbac for (uint32_t facet_idx = 0; facet_idx < this->mesh->stl.stats.number_of_facets; ++ facet_idx) for (int i = 0; i < 3; ++ i) { EdgeToFace &e2f = edges_map[facet_idx*3+i]; - e2f.vertex_low = this->mesh->its.indices[facet_idx].vertex[i]; - e2f.vertex_high = this->mesh->its.indices[facet_idx].vertex[(i + 1) % 3]; + e2f.vertex_low = this->mesh->its.indices[facet_idx][i]; + e2f.vertex_high = this->mesh->its.indices[facet_idx][(i + 1) % 3]; e2f.face = facet_idx; // 1 based indexing, to be always strictly positive. e2f.face_edge = i + 1; @@ -852,7 +852,7 @@ TriangleMeshSlicer::FacetSliceType TriangleMeshSlicer::slice_facet( // Reorder vertices so that the first one is the one with lowest Z. // This is needed to get all intersection lines in a consistent order // (external on the right of the line) - const int *vertices = this->mesh->its.indices[facet_idx].vertex; + const stl_triangle_vertex_indices &vertices = this->mesh->its.indices[facet_idx]; int i = (facet.vertex[1].z() == min_z) ? 1 : ((facet.vertex[2].z() == min_z) ? 2 : 0); // These are used only if the cut plane is tilted: diff --git a/xs/xsp/TriangleMesh.xsp b/xs/xsp/TriangleMesh.xsp index 3e90bfefd..f3153665c 100644 --- a/xs/xsp/TriangleMesh.xsp +++ b/xs/xsp/TriangleMesh.xsp @@ -129,9 +129,9 @@ TriangleMesh::facets() AV* facet = newAV(); av_store(facets, i, newRV_noinc((SV*)facet)); av_extend(facet, 2); - av_store(facet, 0, newSVnv(THIS->its.indices[i].vertex[0])); - av_store(facet, 1, newSVnv(THIS->its.indices[i].vertex[1])); - av_store(facet, 2, newSVnv(THIS->its.indices[i].vertex[2])); + av_store(facet, 0, newSVnv(THIS->its.indices[i][0])); + av_store(facet, 1, newSVnv(THIS->its.indices[i][1])); + av_store(facet, 2, newSVnv(THIS->its.indices[i][2])); } RETVAL = newRV_noinc((SV*)facets); From 0cb5b57c5cf6661f20ab0b3fca3a85ce3b9c790d Mon Sep 17 00:00:00 2001 From: bubnikv Date: Mon, 10 Jun 2019 22:43:21 +0200 Subject: [PATCH 11/22] SLA gimzmo: Sharing the Mesh's indexed triangle set with IGL AABB structure directly, without having to make a copy. --- src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp | 61 ++++++++++---------- src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp | 7 ++- 2 files changed, 33 insertions(+), 35 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index ae017f7d1..89475a058 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -27,6 +27,7 @@ GLGizmoSlaSupports::GLGizmoSlaSupports(GLCanvas3D& parent, unsigned int sprite_i : GLGizmoBase(parent, sprite_id) #endif // ENABLE_SVG_ICONS , m_quadric(nullptr) + , m_its(nullptr) { m_quadric = ::gluNewQuadric(); if (m_quadric != nullptr) @@ -379,36 +380,24 @@ bool GLGizmoSlaSupports::is_point_clipped(const Vec3d& point) const bool GLGizmoSlaSupports::is_mesh_update_necessary() const { return ((m_state == On) && (m_model_object != nullptr) && !m_model_object->instances.empty()) - && ((m_model_object->id() != m_current_mesh_model_id) || m_V.size()==0); + && ((m_model_object->id() != m_current_mesh_model_id) || m_its == nullptr); } void GLGizmoSlaSupports::update_mesh() { wxBusyCursor wait; - Eigen::MatrixXf& V = m_V; - Eigen::MatrixXi& F = m_F; - // We rely on SLA model object having a single volume, // this way we can use that mesh directly. // This mesh does not account for the possible Z up SLA offset. m_mesh = &m_model_object->volumes.front()->mesh; const_cast(m_mesh)->require_shared_vertices(); // TriangleMeshSlicer needs this - const stl_file& stl = m_mesh->stl; - V.resize(3 * stl.stats.number_of_facets, 3); - F.resize(stl.stats.number_of_facets, 3); - for (unsigned int i=0; i(3 * i + 0, 0) = facet.vertex[0]; - V.block<1, 3>(3 * i + 1, 0) = facet.vertex[1]; - V.block<1, 3>(3 * i + 2, 0) = facet.vertex[2]; - F(i, 0) = 3*i+0; - F(i, 1) = 3*i+1; - F(i, 2) = 3*i+2; - } + m_its = &m_mesh->its; m_current_mesh_model_id = m_model_object->id(); m_editing_mode = false; - m_AABB = igl::AABB(); - m_AABB.init(m_V, m_F); + m_AABB.deinit(); + m_AABB.init( + MapMatrixXfUnaligned(m_its->vertices.front().data(), m_its->vertices.size(), 3), + MapMatrixXiUnaligned(m_its->indices.front().data(), m_its->indices.size(), 3)); } // Unprojects the mouse position on the mesh and return the hit point and normal of the facet. @@ -416,7 +405,7 @@ void GLGizmoSlaSupports::update_mesh() std::pair GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse_pos) { // if the gizmo doesn't have the V, F structures for igl, calculate them first: - if (m_V.size() == 0) + if (m_its == nullptr) update_mesh(); const Camera& camera = m_parent.get_camera(); @@ -442,7 +431,10 @@ std::pair GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse point1 = inv * point1; point2 = inv * point2; - if (!m_AABB.intersect_ray(m_V, m_F, point1.cast(), (point2-point1).cast(), hits)) + if (!m_AABB.intersect_ray( + MapMatrixXfUnaligned(m_its->vertices.front().data(), m_its->vertices.size(), 3), + MapMatrixXiUnaligned(m_its->indices.front().data(), m_its->indices.size(), 3), + point1.cast(), (point2-point1).cast(), hits)) throw std::invalid_argument("unproject_on_mesh(): No intersection found."); std::sort(hits.begin(), hits.end(), [](const igl::Hit& a, const igl::Hit& b) { return a.t < b.t; }); @@ -457,9 +449,9 @@ std::pair GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse igl::Hit& hit = hits[i]; int fid = hit.id; // facet id bc = Vec3f(1-hit.u-hit.v, hit.u, hit.v); // barycentric coordinates of the hit - a = (m_V.row(m_F(fid, 1)) - m_V.row(m_F(fid, 0))); - b = (m_V.row(m_F(fid, 2)) - m_V.row(m_F(fid, 0))); - result = bc(0) * m_V.row(m_F(fid, 0)) + bc(1) * m_V.row(m_F(fid, 1)) + bc(2)*m_V.row(m_F(fid, 2)); + a = (m_its->vertices[m_its->indices[fid](1)] - m_its->vertices[m_its->indices[fid](0)]); + b = (m_its->vertices[m_its->indices[fid](2)] - m_its->vertices[m_its->indices[fid](0)]); + result = bc(0) * m_its->vertices[m_its->indices[fid](0)] + bc(1) * m_its->vertices[m_its->indices[fid](1)] + bc(2)*m_its->vertices[m_its->indices[fid](2)]; if (m_clipping_plane_distance == 0.f || !is_point_clipped(result.cast())) break; } @@ -564,15 +556,18 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous // Cast a ray in the direction of the camera and look for intersection with the mesh: std::vector hits; // Offset the start of the ray to the front of the ball + EPSILON to account for numerical inaccuracies. - if (m_AABB.intersect_ray(m_V, m_F, support_point.pos + direction_to_camera_mesh * (support_point.head_front_radius + EPSILON), direction_to_camera_mesh, hits)) { + if (m_AABB.intersect_ray( + MapMatrixXfUnaligned(m_its->vertices.front().data(), m_its->vertices.size(), 3), + MapMatrixXiUnaligned(m_its->indices.front().data(), m_its->indices.size(), 3), + support_point.pos + direction_to_camera_mesh * (support_point.head_front_radius + EPSILON), direction_to_camera_mesh, hits)) { std::sort(hits.begin(), hits.end(), [](const igl::Hit& h1, const igl::Hit& h2) { return h1.t < h2.t; }); if (m_clipping_plane_distance != 0.f) { // If the closest hit facet normal points in the same direction as the ray, // we are looking through the mesh and should therefore discard the point: int fid = hits.front().id; // facet id - Vec3f a = (m_V.row(m_F(fid, 1)) - m_V.row(m_F(fid, 0))); - Vec3f b = (m_V.row(m_F(fid, 2)) - m_V.row(m_F(fid, 0))); + Vec3f a = (m_its->vertices[m_its->indices[fid](1)] - m_its->vertices[m_its->indices[fid](0)]); + Vec3f b = (m_its->vertices[m_its->indices[fid](2)] - m_its->vertices[m_its->indices[fid](0)]); if ((a.cross(b)).dot(direction_to_camera_mesh) > 0.f) is_obscured = true; @@ -582,7 +577,7 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous int fid = hit.id; // facet id Vec3f bc = Vec3f(1-hit.u-hit.v, hit.u, hit.v); // barycentric coordinates of the hit - Vec3f hit_pos = bc(0) * m_V.row(m_F(fid, 0)) + bc(1) * m_V.row(m_F(fid, 1)) + bc(2)*m_V.row(m_F(fid, 2)); + Vec3f hit_pos = bc(0) * m_its->vertices[m_its->indices[fid](0)] + bc(1) * m_its->vertices[m_its->indices[fid](1)] + bc(2)*m_its->vertices[m_its->indices[fid](2)]; if (is_point_clipped(hit_pos.cast())) { hits.erase(hits.begin()+j); --j; @@ -759,9 +754,12 @@ void GLGizmoSlaSupports::update_cache_entry_normal(unsigned int i) const int idx = 0; Eigen::Matrix pp = m_editing_mode_cache[i].support_point.pos; Eigen::Matrix cc; - m_AABB.squared_distance(m_V, m_F, pp, idx, cc); - Vec3f a = (m_V.row(m_F(idx, 1)) - m_V.row(m_F(idx, 0))); - Vec3f b = (m_V.row(m_F(idx, 2)) - m_V.row(m_F(idx, 0))); + m_AABB.squared_distance( + MapMatrixXfUnaligned(m_its->vertices.front().data(), m_its->vertices.size(), 3), + MapMatrixXiUnaligned(m_its->indices.front().data(), m_its->indices.size(), 3), + pp, idx, cc); + Vec3f a = (m_its->vertices[m_its->indices[idx](1)] - m_its->vertices[m_its->indices[idx](0)]); + Vec3f b = (m_its->vertices[m_its->indices[idx](2)] - m_its->vertices[m_its->indices[idx](0)]); m_editing_mode_cache[i].normal = a.cross(b); } @@ -1067,8 +1065,7 @@ void GLGizmoSlaSupports::on_set_state() m_clipping_plane_distance = 0.f; // Release triangle mesh slicer and the AABB spatial search structure. m_AABB.deinit(); - m_V = Eigen::MatrixXf(); - m_F = Eigen::MatrixXi(); + m_its = nullptr; m_tms.reset(); m_supports_tms.reset(); }); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp index fb758d240..4946db12d 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp @@ -35,10 +35,11 @@ private: const float RenderPointScale = 1.f; GLUquadricObj* m_quadric; - Eigen::MatrixXf m_V; // vertices - Eigen::MatrixXi m_F; // facets indices - igl::AABB m_AABB; + typedef Eigen::Map> MapMatrixXfUnaligned; + typedef Eigen::Map> MapMatrixXiUnaligned; + igl::AABB m_AABB; const TriangleMesh* m_mesh; + const indexed_triangle_set* m_its; mutable const TriangleMesh* m_supports_mesh; mutable std::vector m_triangles; mutable std::vector m_supports_triangles; From 590c290ede9ed9da7e608614fbe170d489d1aa06 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Mon, 10 Jun 2019 22:43:42 +0200 Subject: [PATCH 12/22] Fix of a typo. --- src/admesh/shared.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/admesh/shared.cpp b/src/admesh/shared.cpp index 78179e863..902bbfc9b 100644 --- a/src/admesh/shared.cpp +++ b/src/admesh/shared.cpp @@ -220,7 +220,7 @@ bool stl_validate(const stl_file *stl, const indexed_triangle_set &its) // Verify validity of neighborship data. for (int facet_idx = 0; facet_idx < (int)stl->stats.number_of_facets; ++ facet_idx) { const stl_neighbors &nbr = stl->neighbors_start[facet_idx]; - const int *vertices = (its.indices.empty()) ? nullptr : its.indices[facet_idx]; + const int *vertices = its.indices.empty() ? nullptr : its.indices[facet_idx].data(); for (int nbr_idx = 0; nbr_idx < 3; ++ nbr_idx) { int nbr_face = stl->neighbors_start[facet_idx].neighbor[nbr_idx]; assert(nbr_face < (int)stl->stats.number_of_facets); From 5fc465b7e8e5398771e4b6db6043bc84770e5923 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Tue, 11 Jun 2019 09:29:32 +0200 Subject: [PATCH 13/22] admesh refactoring: Using boost::object_pool for linked list memory allocation. --- src/admesh/connect.cpp | 525 +++++++++++++++++++++-------------------- src/admesh/normals.cpp | 15 +- src/admesh/stl_io.cpp | 10 +- 3 files changed, 284 insertions(+), 266 deletions(-) diff --git a/src/admesh/connect.cpp b/src/admesh/connect.cpp index cbd4f1d33..be782b1b7 100644 --- a/src/admesh/connect.cpp +++ b/src/admesh/connect.cpp @@ -28,8 +28,9 @@ #include #include +#include #include -#include +#include #include "stl.h" @@ -42,11 +43,11 @@ struct HashEdge { int hash(int M) const { return ((key[0] / 11 + key[1] / 7 + key[2] / 3) ^ (key[3] / 11 + key[4] / 7 + key[5] / 3)) % M; } // Index of a facet owning this edge. - int facet_number; + int facet_number; // Index of this edge inside the facet with an index of facet_number. // If this edge is stored backwards, which_edge is increased by 3. - int which_edge; - struct HashEdge *next; + int which_edge; + HashEdge *next; void load_exact(stl_file *stl, const stl_vertex *a, const stl_vertex *b) { @@ -69,15 +70,15 @@ struct HashEdge { // Switch negative zeros to positive zeros, so memcmp will consider them to be equal. for (size_t i = 0; i < 6; ++ i) { unsigned char *p = (unsigned char*)(this->key + i); - #ifdef BOOST_LITTLE_ENDIAN + #if BOOST_ENDIAN_LITTLE_BYTE if (p[0] == 0 && p[1] == 0 && p[2] == 0 && p[3] == 0x80) // Negative zero, switch to positive zero. p[3] = 0; - #else /* BOOST_LITTLE_ENDIAN */ + #else /* BOOST_ENDIAN_LITTLE_BYTE */ if (p[0] == 0x80 && p[1] == 0 && p[2] == 0 && p[3] == 0) // Negative zero, switch to positive zero. p[0] = 0; - #endif /* BOOST_LITTLE_ENDIAN */ + #endif /* BOOST_ENDIAN_LITTLE_BYTE */ } } @@ -115,7 +116,7 @@ struct HashTableEdges { HashTableEdges(size_t number_of_faces) { this->M = (int)hash_size_from_nr_faces(number_of_faces); this->heads.assign(this->M, nullptr); - this->tail = new HashEdge; + this->tail = pool.construct(); this->tail->next = this->tail; for (int i = 0; i < this->M; ++ i) this->heads[i] = this->tail; @@ -124,80 +125,32 @@ struct HashTableEdges { for (int i = 0; i < this->M; ++ i) { for (HashEdge *temp = this->heads[i]; this->heads[i] != this->tail; temp = this->heads[i]) { this->heads[i] = this->heads[i]->next; - delete temp; + pool.destroy(temp); #ifndef NDEBUG ++ this->freed; #endif /* NDEBUG */ } } this->heads.clear(); - delete this->tail; + pool.destroy(this->tail); this->tail = nullptr; } - void insert_edge(stl_file *stl, const HashEdge &edge, void (*match_neighbors)(stl_file *stl, const HashEdge &edge_a, const HashEdge &edge_b)) + void insert_edge_exact(stl_file *stl, const HashEdge &edge) { - int chain_number = edge.hash(this->M); - HashEdge *link = this->heads[chain_number]; - if (link == this->tail) { - // This list doesn't have any edges currently in it. Add this one. - HashEdge *new_edge = new HashEdge(edge); -#ifndef NDEBUG - ++ this->malloced; -#endif /* NDEBUG */ - new_edge->next = this->tail; - this->heads[chain_number] = new_edge; - } else if (edges_equal(edge, *link)) { - // This is a match. Record result in neighbors list. - match_neighbors(stl, edge, *link); - // Delete the matched edge from the list. - this->heads[chain_number] = link->next; - delete link; -#ifndef NDEBUG - ++ this->freed; -#endif /* NDEBUG */ - } else { - // Continue through the rest of the list. - for (;;) { - if (link->next == this->tail) { - // This is the last item in the list. Insert a new edge. - HashEdge *new_edge = new HashEdge; -#ifndef NDEBUG - ++ this->malloced; -#endif /* NDEBUG */ - *new_edge = edge; - new_edge->next = this->tail; - link->next = new_edge; -#ifndef NDEBUG - ++ this->collisions; -#endif /* NDEBUG */ - break; - } - if (edges_equal(edge, *link->next)) { - // This is a match. Record result in neighbors list. - match_neighbors(stl, edge, *link->next); - // Delete the matched edge from the list. - HashEdge *temp = link->next; - link->next = link->next->next; - delete temp; -#ifndef NDEBUG - ++ this->freed; -#endif /* NDEBUG */ - break; - } - // This is not a match. Go to the next link. - link = link->next; -#ifndef NDEBUG - ++ this->collisions; -#endif /* NDEBUG */ - } - } + this->insert_edge(stl, edge, [stl](const HashEdge& edge1, const HashEdge& edge2) { record_neighbors(stl, edge1, edge2); }); + } + + void insert_edge_nearby(stl_file *stl, const HashEdge &edge) + { + this->insert_edge(stl, edge, [stl](const HashEdge& edge1, const HashEdge& edge2) { match_neighbors_nearby(stl, edge1, edge2); }); } // Hash table on edges std::vector heads; HashEdge* tail; int M; + boost::object_pool pool; #ifndef NDEBUG size_t malloced = 0; @@ -216,198 +169,260 @@ private: return (it == primes.end()) ? primes.back() : *it; } + + // MatchNeighbors(stl_file *stl, const HashEdge &edge_a, const HashEdge &edge_b) + template + void insert_edge(stl_file *stl, const HashEdge &edge, MatchNeighbors match_neighbors) + { + int chain_number = edge.hash(this->M); + HashEdge *link = this->heads[chain_number]; + if (link == this->tail) { + // This list doesn't have any edges currently in it. Add this one. + HashEdge *new_edge = pool.construct(edge); +#ifndef NDEBUG + ++ this->malloced; +#endif /* NDEBUG */ + new_edge->next = this->tail; + this->heads[chain_number] = new_edge; + } else if (edges_equal(edge, *link)) { + // This is a match. Record result in neighbors list. + match_neighbors(edge, *link); + // Delete the matched edge from the list. + this->heads[chain_number] = link->next; + pool.destroy(link); +#ifndef NDEBUG + ++ this->freed; +#endif /* NDEBUG */ + } else { + // Continue through the rest of the list. + for (;;) { + if (link->next == this->tail) { + // This is the last item in the list. Insert a new edge. + HashEdge *new_edge = pool.construct(); +#ifndef NDEBUG + ++ this->malloced; +#endif /* NDEBUG */ + *new_edge = edge; + new_edge->next = this->tail; + link->next = new_edge; +#ifndef NDEBUG + ++ this->collisions; +#endif /* NDEBUG */ + break; + } + if (edges_equal(edge, *link->next)) { + // This is a match. Record result in neighbors list. + match_neighbors(edge, *link->next); + // Delete the matched edge from the list. + HashEdge *temp = link->next; + link->next = link->next->next; + pool.destroy(temp); +#ifndef NDEBUG + ++ this->freed; +#endif /* NDEBUG */ + break; + } + // This is not a match. Go to the next link. + link = link->next; +#ifndef NDEBUG + ++ this->collisions; +#endif /* NDEBUG */ + } + } + } + // Edges equal for hashing. Edgesof different facet are allowed to be matched. static inline bool edges_equal(const HashEdge &edge_a, const HashEdge &edge_b) { return edge_a.facet_number != edge_b.facet_number && edge_a == edge_b; } + + static void record_neighbors(stl_file *stl, const HashEdge &edge_a, const HashEdge &edge_b) + { + // Facet a's neighbor is facet b + stl->neighbors_start[edge_a.facet_number].neighbor[edge_a.which_edge % 3] = edge_b.facet_number; /* sets the .neighbor part */ + stl->neighbors_start[edge_a.facet_number].which_vertex_not[edge_a.which_edge % 3] = (edge_b.which_edge + 2) % 3; /* sets the .which_vertex_not part */ + + // Facet b's neighbor is facet a + 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))) { + // 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; + } + + // Count successful connects: + // Total connects: + stl->stats.connected_edges += 2; + // Count individual connects: + switch (stl->neighbors_start[edge_a.facet_number].num_neighbors()) { + 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); + } + switch (stl->neighbors_start[edge_b.facet_number].num_neighbors()) { + 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); + } + } + + static void match_neighbors_nearby(stl_file *stl, const HashEdge &edge_a, const HashEdge &edge_b) + { + record_neighbors(stl, edge_a, edge_b); + + // Which vertices to change + int facet1 = -1; + int facet2 = -1; + int vertex1, vertex2; + stl_vertex new_vertex1, new_vertex2; + { + int v1a; // pair 1, facet a + int v1b; // pair 1, facet b + int v2a; // pair 2, facet a + int v2b; // pair 2, facet b + // Find first pair. + if (edge_a.which_edge < 3) { + v1a = edge_a.which_edge; + v2a = (edge_a.which_edge + 1) % 3; + } else { + v2a = edge_a.which_edge % 3; + v1a = (edge_a.which_edge + 1) % 3; + } + if (edge_b.which_edge < 3) { + v1b = edge_b.which_edge; + v2b = (edge_b.which_edge + 1) % 3; + } else { + v2b = edge_b.which_edge % 3; + v1b = (edge_b.which_edge + 1) % 3; + } + + // Of the first pair, which vertex, if any, should be changed + if (stl->facet_start[edge_a.facet_number].vertex[v1a] != stl->facet_start[edge_b.facet_number].vertex[v1b]) { + // These facets are different. + if ( (stl->neighbors_start[edge_a.facet_number].neighbor[v1a] == -1) + && (stl->neighbors_start[edge_a.facet_number].neighbor[(v1a + 2) % 3] == -1)) { + // This vertex has no neighbors. This is a good one to change. + facet1 = edge_a.facet_number; + vertex1 = v1a; + new_vertex1 = stl->facet_start[edge_b.facet_number].vertex[v1b]; + } else { + facet1 = edge_b.facet_number; + vertex1 = v1b; + new_vertex1 = stl->facet_start[edge_a.facet_number].vertex[v1a]; + } + } + + // Of the second pair, which vertex, if any, should be changed. + if (stl->facet_start[edge_a.facet_number].vertex[v2a] == stl->facet_start[edge_b.facet_number].vertex[v2b]) { + // These facets are different. + if ( (stl->neighbors_start[edge_a.facet_number].neighbor[v2a] == -1) + && (stl->neighbors_start[edge_a.facet_number].neighbor[(v2a + 2) % 3] == -1)) { + // This vertex has no neighbors. This is a good one to change. + facet2 = edge_a.facet_number; + vertex2 = v2a; + new_vertex2 = stl->facet_start[edge_b.facet_number].vertex[v2b]; + } else { + facet2 = edge_b.facet_number; + vertex2 = v2b; + new_vertex2 = stl->facet_start[edge_a.facet_number].vertex[v2a]; + } + } + } + + auto change_vertices = [stl](int facet_num, int vnot, stl_vertex new_vertex) + { + int first_facet = facet_num; + bool direction = false; + + for (;;) { + int pivot_vertex; + int next_edge; + if (vnot > 2) { + if (direction) { + pivot_vertex = (vnot + 1) % 3; + next_edge = vnot % 3; + } + else { + pivot_vertex = (vnot + 2) % 3; + next_edge = pivot_vertex; + } + direction = !direction; + } + else { + if (direction) { + pivot_vertex = (vnot + 2) % 3; + next_edge = pivot_vertex; + } + else { + pivot_vertex = (vnot + 1) % 3; + next_edge = vnot; + } + } + #if 0 + if (stl->facet_start[facet_num].vertex[pivot_vertex](0) == new_vertex(0) && + stl->facet_start[facet_num].vertex[pivot_vertex](1) == new_vertex(1) && + stl->facet_start[facet_num].vertex[pivot_vertex](2) == new_vertex(2)) + printf("Changing vertex %f,%f,%f: Same !!!\r\n", new_vertex(0), new_vertex(1), new_vertex(2)); + else { + if (stl->facet_start[facet_num].vertex[pivot_vertex](0) != new_vertex(0)) + printf("Changing coordinate x, vertex %e (0x%08x) to %e(0x%08x)\r\n", + stl->facet_start[facet_num].vertex[pivot_vertex](0), + *reinterpret_cast(&stl->facet_start[facet_num].vertex[pivot_vertex](0)), + new_vertex(0), + *reinterpret_cast(&new_vertex(0))); + if (stl->facet_start[facet_num].vertex[pivot_vertex](1) != new_vertex(1)) + printf("Changing coordinate x, vertex %e (0x%08x) to %e(0x%08x)\r\n", + stl->facet_start[facet_num].vertex[pivot_vertex](1), + *reinterpret_cast(&stl->facet_start[facet_num].vertex[pivot_vertex](1)), + new_vertex(1), + *reinterpret_cast(&new_vertex(1))); + if (stl->facet_start[facet_num].vertex[pivot_vertex](2) != new_vertex(2)) + printf("Changing coordinate x, vertex %e (0x%08x) to %e(0x%08x)\r\n", + stl->facet_start[facet_num].vertex[pivot_vertex](2), + *reinterpret_cast(&stl->facet_start[facet_num].vertex[pivot_vertex](2)), + new_vertex(2), + *reinterpret_cast(&new_vertex(2))); + } + #endif + stl->facet_start[facet_num].vertex[pivot_vertex] = new_vertex; + vnot = stl->neighbors_start[facet_num].which_vertex_not[next_edge]; + facet_num = stl->neighbors_start[facet_num].neighbor[next_edge]; + if (facet_num == -1) + break; + + if (facet_num == first_facet) { + // back to the beginning + BOOST_LOG_TRIVIAL(info) << "Back to the first facet changing vertices: probably a mobius part. Try using a smaller tolerance or don't do a nearby check."; + return; + } + } + }; + + if (facet1 != -1) { + int vnot1 = (facet1 == edge_a.facet_number) ? + (edge_a.which_edge + 2) % 3 : + (edge_b.which_edge + 2) % 3; + if (((vnot1 + 2) % 3) == vertex1) + vnot1 += 3; + change_vertices(facet1, vnot1, new_vertex1); + } + if (facet2 != -1) { + int vnot2 = (facet2 == edge_a.facet_number) ? + (edge_a.which_edge + 2) % 3 : + (edge_b.which_edge + 2) % 3; + if (((vnot2 + 2) % 3) == vertex2) + vnot2 += 3; + change_vertices(facet2, vnot2, new_vertex2); + } + stl->stats.edges_fixed += 2; + } }; -static void record_neighbors(stl_file *stl, const HashEdge &edge_a, const HashEdge &edge_b) -{ - // Facet a's neighbor is facet b - stl->neighbors_start[edge_a.facet_number].neighbor[edge_a.which_edge % 3] = edge_b.facet_number; /* sets the .neighbor part */ - stl->neighbors_start[edge_a.facet_number].which_vertex_not[edge_a.which_edge % 3] = (edge_b.which_edge + 2) % 3; /* sets the .which_vertex_not part */ - - // Facet b's neighbor is facet a - 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))) { - // 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; - } - - // Count successful connects: - // Total connects: - stl->stats.connected_edges += 2; - // Count individual connects: - switch (stl->neighbors_start[edge_a.facet_number].num_neighbors()) { - 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); - } - switch (stl->neighbors_start[edge_b.facet_number].num_neighbors()) { - 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); - } -} - -static void match_neighbors_nearby(stl_file *stl, const HashEdge &edge_a, const HashEdge &edge_b) -{ - record_neighbors(stl, edge_a, edge_b); - - // Which vertices to change - int facet1 = -1; - int facet2 = -1; - int vertex1, vertex2; - stl_vertex new_vertex1, new_vertex2; - { - int v1a; // pair 1, facet a - int v1b; // pair 1, facet b - int v2a; // pair 2, facet a - int v2b; // pair 2, facet b - // Find first pair. - if (edge_a.which_edge < 3) { - v1a = edge_a.which_edge; - v2a = (edge_a.which_edge + 1) % 3; - } else { - v2a = edge_a.which_edge % 3; - v1a = (edge_a.which_edge + 1) % 3; - } - if (edge_b.which_edge < 3) { - v1b = edge_b.which_edge; - v2b = (edge_b.which_edge + 1) % 3; - } else { - v2b = edge_b.which_edge % 3; - v1b = (edge_b.which_edge + 1) % 3; - } - - // Of the first pair, which vertex, if any, should be changed - if (stl->facet_start[edge_a.facet_number].vertex[v1a] != stl->facet_start[edge_b.facet_number].vertex[v1b]) { - // These facets are different. - if ( (stl->neighbors_start[edge_a.facet_number].neighbor[v1a] == -1) - && (stl->neighbors_start[edge_a.facet_number].neighbor[(v1a + 2) % 3] == -1)) { - // This vertex has no neighbors. This is a good one to change. - facet1 = edge_a.facet_number; - vertex1 = v1a; - new_vertex1 = stl->facet_start[edge_b.facet_number].vertex[v1b]; - } else { - facet1 = edge_b.facet_number; - vertex1 = v1b; - new_vertex1 = stl->facet_start[edge_a.facet_number].vertex[v1a]; - } - } - - // Of the second pair, which vertex, if any, should be changed. - if (stl->facet_start[edge_a.facet_number].vertex[v2a] == stl->facet_start[edge_b.facet_number].vertex[v2b]) { - // These facets are different. - if ( (stl->neighbors_start[edge_a.facet_number].neighbor[v2a] == -1) - && (stl->neighbors_start[edge_a.facet_number].neighbor[(v2a + 2) % 3] == -1)) { - // This vertex has no neighbors. This is a good one to change. - facet2 = edge_a.facet_number; - vertex2 = v2a; - new_vertex2 = stl->facet_start[edge_b.facet_number].vertex[v2b]; - } else { - facet2 = edge_b.facet_number; - vertex2 = v2b; - new_vertex2 = stl->facet_start[edge_a.facet_number].vertex[v2a]; - } - } - } - - auto change_vertices = [stl](int facet_num, int vnot, stl_vertex new_vertex) - { - int first_facet = facet_num; - bool direction = false; - - for (;;) { - int pivot_vertex; - int next_edge; - if (vnot > 2) { - if (direction) { - pivot_vertex = (vnot + 1) % 3; - next_edge = vnot % 3; - } - else { - pivot_vertex = (vnot + 2) % 3; - next_edge = pivot_vertex; - } - direction = !direction; - } - else { - if (direction) { - pivot_vertex = (vnot + 2) % 3; - next_edge = pivot_vertex; - } - else { - pivot_vertex = (vnot + 1) % 3; - next_edge = vnot; - } - } -#if 0 - if (stl->facet_start[facet_num].vertex[pivot_vertex](0) == new_vertex(0) && - stl->facet_start[facet_num].vertex[pivot_vertex](1) == new_vertex(1) && - stl->facet_start[facet_num].vertex[pivot_vertex](2) == new_vertex(2)) - printf("Changing vertex %f,%f,%f: Same !!!\r\n", new_vertex(0), new_vertex(1), new_vertex(2)); - else { - if (stl->facet_start[facet_num].vertex[pivot_vertex](0) != new_vertex(0)) - printf("Changing coordinate x, vertex %e (0x%08x) to %e(0x%08x)\r\n", - stl->facet_start[facet_num].vertex[pivot_vertex](0), - *reinterpret_cast(&stl->facet_start[facet_num].vertex[pivot_vertex](0)), - new_vertex(0), - *reinterpret_cast(&new_vertex(0))); - if (stl->facet_start[facet_num].vertex[pivot_vertex](1) != new_vertex(1)) - printf("Changing coordinate x, vertex %e (0x%08x) to %e(0x%08x)\r\n", - stl->facet_start[facet_num].vertex[pivot_vertex](1), - *reinterpret_cast(&stl->facet_start[facet_num].vertex[pivot_vertex](1)), - new_vertex(1), - *reinterpret_cast(&new_vertex(1))); - if (stl->facet_start[facet_num].vertex[pivot_vertex](2) != new_vertex(2)) - printf("Changing coordinate x, vertex %e (0x%08x) to %e(0x%08x)\r\n", - stl->facet_start[facet_num].vertex[pivot_vertex](2), - *reinterpret_cast(&stl->facet_start[facet_num].vertex[pivot_vertex](2)), - new_vertex(2), - *reinterpret_cast(&new_vertex(2))); - } -#endif - stl->facet_start[facet_num].vertex[pivot_vertex] = new_vertex; - vnot = stl->neighbors_start[facet_num].which_vertex_not[next_edge]; - facet_num = stl->neighbors_start[facet_num].neighbor[next_edge]; - if (facet_num == -1) - break; - - if (facet_num == first_facet) { - // back to the beginning - BOOST_LOG_TRIVIAL(info) << "Back to the first facet changing vertices: probably a mobius part. Try using a smaller tolerance or don't do a nearby check."; - return; - } - } - }; - - if (facet1 != -1) { - int vnot1 = (facet1 == edge_a.facet_number) ? - (edge_a.which_edge + 2) % 3 : - (edge_b.which_edge + 2) % 3; - if (((vnot1 + 2) % 3) == vertex1) - vnot1 += 3; - change_vertices(facet1, vnot1, new_vertex1); - } - if (facet2 != -1) { - int vnot2 = (facet2 == edge_a.facet_number) ? - (edge_a.which_edge + 2) % 3 : - (edge_b.which_edge + 2) % 3; - if (((vnot2 + 2) % 3) == vertex2) - vnot2 += 3; - change_vertices(facet2, vnot2, new_vertex2); - } - stl->stats.edges_fixed += 2; -} - // This function builds the neighbors list. No modifications are made // to any of the facets. The edges are said to match only if all six // floats of the first edge matches all six floats of the second edge. @@ -445,7 +460,7 @@ void stl_check_facets_exact(stl_file *stl) edge.facet_number = i; edge.which_edge = j; edge.load_exact(stl, &facet.vertex[j], &facet.vertex[(j + 1) % 3]); - hash_table.insert_edge(stl, edge, record_neighbors); + hash_table.insert_edge_exact(stl, edge); } } @@ -476,7 +491,7 @@ void stl_check_facets_nearby(stl_file *stl, float tolerance) edge.which_edge = j; if (edge.load_nearby(stl, facet.vertex[j], facet.vertex[(j + 1) % 3], tolerance)) // Only insert edges that have different keys. - hash_table.insert_edge(stl, edge, match_neighbors_nearby); + hash_table.insert_edge_nearby(stl, edge); } } } @@ -654,7 +669,7 @@ void stl_fill_holes(stl_file *stl) edge.facet_number = i; edge.which_edge = j; edge.load_exact(stl, &facet.vertex[j], &facet.vertex[(j + 1) % 3]); - hash_table.insert_edge(stl, edge, record_neighbors); + hash_table.insert_edge_exact(stl, edge); } } @@ -704,7 +719,7 @@ void stl_fill_holes(stl_file *stl) edge.facet_number = stl->stats.number_of_facets - 1; edge.which_edge = k; edge.load_exact(stl, &new_facet.vertex[k], &new_facet.vertex[(k + 1) % 3]); - hash_table.insert_edge(stl, edge, record_neighbors); + hash_table.insert_edge_exact(stl, edge); } break; } diff --git a/src/admesh/normals.cpp b/src/admesh/normals.cpp index 464f9e6d8..4d47573f6 100644 --- a/src/admesh/normals.cpp +++ b/src/admesh/normals.cpp @@ -25,6 +25,8 @@ #include #include +#include + #include "stl.h" static void reverse_facet(stl_file *stl, int facet_num) @@ -120,8 +122,9 @@ void stl_fix_normal_directions(stl_file *stl) }; // Initialize linked list. - stl_normal *head = new stl_normal; - stl_normal *tail = new stl_normal; + boost::object_pool pool; + stl_normal *head = pool.construct(); + stl_normal *tail = pool.construct(); head->next = tail; tail->next = tail; @@ -168,7 +171,7 @@ void stl_fix_normal_directions(stl_file *stl) // If we haven't fixed this facet yet, add it to the list: if (norm_sw[stl->neighbors_start[facet_num].neighbor[j]] != 1) { // Add node to beginning of list. - stl_normal *newn = new stl_normal; + stl_normal *newn = pool.construct(); newn->facet_num = stl->neighbors_start[facet_num].neighbor[j]; newn->next = head->next; head->next = newn; @@ -189,7 +192,7 @@ void stl_fix_normal_directions(stl_file *stl) } stl_normal *temp = head->next; // Delete this facet from the list. head->next = head->next->next; - delete temp; + pool.destroy(temp); } else { // If we ran out of facets to fix: All of the facets in this part have been fixed. ++ stl->stats.number_of_parts; if (checked >= stl->stats.number_of_facets) @@ -211,8 +214,8 @@ void stl_fix_normal_directions(stl_file *stl) } } - delete head; - delete tail; + pool.destroy(head); + pool.destroy(tail); } void stl_fix_normal_values(stl_file *stl) diff --git a/src/admesh/stl_io.cpp b/src/admesh/stl_io.cpp index 7e181716c..464c98907 100644 --- a/src/admesh/stl_io.cpp +++ b/src/admesh/stl_io.cpp @@ -25,7 +25,7 @@ #include #include -#include +#include #include "stl.h" @@ -114,7 +114,7 @@ bool stl_print_neighbors(stl_file *stl, char *file) return true; } -#ifndef BOOST_LITTLE_ENDIAN +#if BOOST_ENDIAN_BIG_BYTE // Swap a buffer of 32bit data from little endian to big endian and vice versa. void stl_internal_reverse_quads(char *buf, size_t cnt) { @@ -141,11 +141,11 @@ bool stl_write_binary(stl_file *stl, const char *file, const char *label) #define SEEK_SET 0 #endif fseek(fp, LABEL_SIZE, SEEK_SET); -#ifdef BOOST_LITTLE_ENDIAN +#if BOOST_ENDIAN_LITTLE_BYTE fwrite(&stl->stats.number_of_facets, 4, 1, fp); for (const stl_facet &facet : stl->facet_start) fwrite(&facet, SIZEOF_STL_FACET, 1, fp); -#else /* BOOST_LITTLE_ENDIAN */ +#else /* BOOST_ENDIAN_LITTLE_BYTE */ char buffer[50]; // Convert the number of facets to little endian. memcpy(buffer, &stl->stats.number_of_facets, 4); @@ -157,7 +157,7 @@ bool stl_write_binary(stl_file *stl, const char *file, const char *label) stl_internal_reverse_quads(buffer, 48); fwrite(buffer, SIZEOF_STL_FACET, 1, fp); } -#endif /* BOOST_LITTLE_ENDIAN */ +#endif /* BOOST_ENDIAN_LITTLE_BYTE */ fclose(fp); return true; } From 0bb8ee149e8702fb644a70ab1f3924ff8e6f3d71 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Tue, 11 Jun 2019 17:08:47 +0200 Subject: [PATCH 14/22] Sharing TriangleMesh objects between the front end (UI) and back end (background processing) --- src/PrusaSlicer.cpp | 8 +- src/admesh/connect.cpp | 46 +++++--- src/admesh/stl.h | 38 +++++- src/admesh/stlinit.cpp | 2 +- src/admesh/util.cpp | 2 +- src/libslic3r/Format/3mf.cpp | 27 +++-- src/libslic3r/Format/AMF.cpp | 20 ++-- src/libslic3r/Model.cpp | 118 +++++++++---------- src/libslic3r/Model.hpp | 46 +++++--- src/libslic3r/PrintObject.cpp | 14 ++- src/libslic3r/Slicing.cpp | 2 +- src/libslic3r/TriangleMesh.cpp | 72 ++++++----- src/libslic3r/TriangleMesh.hpp | 2 +- src/slic3r/GUI/3DScene.cpp | 25 ++-- src/slic3r/GUI/3DScene.hpp | 12 +- src/slic3r/GUI/GLCanvas3D.cpp | 2 +- src/slic3r/GUI/GUI_ObjectList.cpp | 4 +- src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp | 3 +- src/slic3r/GUI/Plater.cpp | 2 +- xs/xsp/Model.xsp | 2 +- 20 files changed, 254 insertions(+), 193 deletions(-) diff --git a/src/PrusaSlicer.cpp b/src/PrusaSlicer.cpp index fef1f6e7f..a3247b929 100644 --- a/src/PrusaSlicer.cpp +++ b/src/PrusaSlicer.cpp @@ -241,8 +241,7 @@ int CLI::run(int argc, char **argv) } else if (opt_key == "cut" || opt_key == "cut_x" || opt_key == "cut_y") { std::vector new_models; for (auto &model : m_models) { - model.repair(); - model.translate(0, 0, -model.bounding_box().min.z()); // align to z = 0 + model.translate(0, 0, -model.bounding_box().min.z()); // align to z = 0 size_t num_objects = model.objects.size(); for (size_t i = 0; i < num_objects; ++ i) { @@ -301,8 +300,9 @@ int CLI::run(int argc, char **argv) } } } else if (opt_key == "repair") { - for (auto &model : m_models) - model.repair(); + // Models are repaired by default. + //for (auto &model : m_models) + // model.repair(); } else { boost::nowide::cerr << "error: option not implemented yet: " << opt_key << std::endl; return 1; diff --git a/src/admesh/connect.cpp b/src/admesh/connect.cpp index be782b1b7..1a7b7965d 100644 --- a/src/admesh/connect.cpp +++ b/src/admesh/connect.cpp @@ -59,7 +59,7 @@ struct HashEdge { // Ensure identical vertex ordering of equal edges. // This method is numerically robust. - if (stl_vertex_lower(*a, *b)) { + if (vertex_lower(*a, *b)) { } else { // This edge is loaded backwards. std::swap(a, b); @@ -110,6 +110,12 @@ struct HashEdge { } return true; } + +private: + inline bool vertex_lower(const stl_vertex &a, const stl_vertex &b) { + return (a(0) != b(0)) ? (a(0) < b(0)) : + ((a(1) != b(1)) ? (a(1) < b(1)) : (a(2) < b(2))); + } }; struct HashTableEdges { @@ -440,7 +446,9 @@ void stl_check_facets_exact(stl_file *stl) stl_facet &facet = stl->facet_start[i]; if (facet.vertex[0] == facet.vertex[1] || facet.vertex[1] == facet.vertex[2] || facet.vertex[0] == facet.vertex[2]) { // Remove the degenerate facet. - facet = stl->facet_start[--stl->stats.number_of_facets]; + facet = stl->facet_start[-- stl->stats.number_of_facets]; + stl->facet_start.pop_back(); + stl->neighbors_start.pop_back(); stl->stats.facets_removed += 1; stl->stats.degenerate_facets += 1; } else @@ -526,23 +534,25 @@ void stl_remove_unconnected_facets(stl_file *stl) assert(false); } - if (facet_number == -- stl->stats.number_of_facets) - // Removing the last face is easy, just forget the last face. - return; - - // Copy the face and neighborship from the last face to facet_number. - stl->facet_start[facet_number] = stl->facet_start[stl->stats.number_of_facets]; - neighbors = stl->neighbors_start[stl->stats.number_of_facets]; - // Update neighborship of faces, which used to point to the last face, now moved to facet_number. - for (int i = 0; i < 3; ++ i) - if (neighbors.neighbor[i] != -1) { - int &other_face_idx = stl->neighbors_start[neighbors.neighbor[i]].neighbor[(neighbors.which_vertex_not[i] + 1) % 3]; - if (other_face_idx != stl->stats.number_of_facets) { - BOOST_LOG_TRIVIAL(info) << "in remove_facet: neighbor = " << other_face_idx << " numfacets = " << stl->stats.number_of_facets << " this is wrong"; - return; + if (facet_number < -- stl->stats.number_of_facets) { + // Removing a face, which was not the last one. + // Copy the face and neighborship from the last face to facet_number. + stl->facet_start[facet_number] = stl->facet_start[stl->stats.number_of_facets]; + neighbors = stl->neighbors_start[stl->stats.number_of_facets]; + // Update neighborship of faces, which used to point to the last face, now moved to facet_number. + for (int i = 0; i < 3; ++ i) + if (neighbors.neighbor[i] != -1) { + int &other_face_idx = stl->neighbors_start[neighbors.neighbor[i]].neighbor[(neighbors.which_vertex_not[i] + 1) % 3]; + if (other_face_idx != stl->stats.number_of_facets) { + BOOST_LOG_TRIVIAL(info) << "in remove_facet: neighbor = " << other_face_idx << " numfacets = " << stl->stats.number_of_facets << " this is wrong"; + return; + } + other_face_idx = facet_number; } - other_face_idx = facet_number; - } + } + + stl->facet_start.pop_back(); + stl->neighbors_start.pop_back(); }; auto remove_degenerate = [stl, remove_facet](int facet) diff --git a/src/admesh/stl.h b/src/admesh/stl.h index fce23eb3f..c419c567b 100644 --- a/src/admesh/stl.h +++ b/src/admesh/stl.h @@ -128,6 +128,8 @@ struct indexed_triangle_set void clear() { indices.clear(); vertices.clear(); } std::vector indices; std::vector vertices; + //FIXME add normals once we get rid of the stl_file from TriangleMesh completely. + //std::vector normals }; extern bool stl_open(stl_file *stl, const char *file); @@ -186,7 +188,7 @@ template inline void stl_transform(stl_file *stl, const Eigen::Transform& t) { const Eigen::Matrix r = t.matrix().template block<3, 3>(0, 0); - for (size_t i = 0; i < stl->stats.number_of_facets; ++i) { + for (size_t i = 0; i < stl->stats.number_of_facets; ++ i) { stl_facet &f = stl->facet_start[i]; for (size_t j = 0; j < 3; ++j) f.vertex[j] = (t * f.vertex[j].template cast()).template cast().eval(); @@ -199,7 +201,7 @@ inline void stl_transform(stl_file *stl, const Eigen::Transform inline void stl_transform(stl_file *stl, const Eigen::Matrix& m) { - for (size_t i = 0; i < stl->stats.number_of_facets; ++i) { + for (size_t i = 0; i < stl->stats.number_of_facets; ++ i) { stl_facet &f = stl->facet_start[i]; for (size_t j = 0; j < 3; ++j) f.vertex[j] = (m * f.vertex[j].template cast()).template cast().eval(); @@ -209,6 +211,34 @@ inline void stl_transform(stl_file *stl, const Eigen::Matrix +extern void its_transform(indexed_triangle_set &its, T *trafo3x4) +{ + for (stl_vertex &v_dst : its.vertices) { + stl_vertex &v_dst = face.vertex[i_vertex]; + stl_vertex v_src = v_dst; + v_dst(0) = T(trafo3x4[0] * v_src(0) + trafo3x4[1] * v_src(1) + trafo3x4[2] * v_src(2) + trafo3x4[3]); + v_dst(1) = T(trafo3x4[4] * v_src(0) + trafo3x4[5] * v_src(1) + trafo3x4[6] * v_src(2) + trafo3x4[7]); + v_dst(2) = T(trafo3x4[8] * v_src(0) + trafo3x4[9] * v_src(1) + trafo3x4[10] * v_src(2) + trafo3x4[11]); + } +} + +template +inline void its_transform(indexed_triangle_set &its, const Eigen::Transform& t) +{ + const Eigen::Matrix r = t.matrix().template block<3, 3>(0, 0); + for (stl_vertex &v : its.vertices) + v = (t * v.template cast()).template cast().eval(); +} + +template +inline void its_transform(indexed_triangle_set &its, const Eigen::Matrix& m) +{ + for (stl_vertex &v : its.vertices) + v = (m * v.template cast()).template cast().eval(); +} + extern void stl_generate_shared_vertices(stl_file *stl, indexed_triangle_set &its); extern bool its_write_obj(const indexed_triangle_set &its, const char *file); extern bool its_write_off(const indexed_triangle_set &its, const char *file); @@ -225,10 +255,6 @@ inline void stl_normalize_vector(stl_normal &normal) { else normal *= float(1.0 / length); } -inline bool stl_vertex_lower(const stl_vertex &a, const stl_vertex &b) { - return (a(0) != b(0)) ? (a(0) < b(0)) : - ((a(1) != b(1)) ? (a(1) < b(1)) : (a(2) < b(2))); -} extern void stl_calculate_volume(stl_file *stl); extern void stl_repair(stl_file *stl, bool fixall_flag, bool exact_flag, bool tolerance_flag, float tolerance, bool increment_flag, float increment, bool nearby_flag, int iterations, bool remove_unconnected_flag, bool fill_holes_flag, bool normal_directions_flag, bool normal_values_flag, bool reverse_all_flag, bool verbose_flag); diff --git a/src/admesh/stlinit.cpp b/src/admesh/stlinit.cpp index 24fbe9edc..0cc6e50c7 100644 --- a/src/admesh/stlinit.cpp +++ b/src/admesh/stlinit.cpp @@ -147,7 +147,7 @@ static bool stl_read(stl_file *stl, FILE *fp, int first_facet, bool first) rewind(fp); char normal_buf[3][32]; - for (uint32_t i = first_facet; i < stl->stats.number_of_facets; ++i) { + for (uint32_t i = first_facet; i < stl->stats.number_of_facets; ++ i) { stl_facet facet; if (stl->stats.type == binary) { diff --git a/src/admesh/util.cpp b/src/admesh/util.cpp index 6fff8a8ed..70f4ffc27 100644 --- a/src/admesh/util.cpp +++ b/src/admesh/util.cpp @@ -108,7 +108,7 @@ void stl_scale_versor(stl_file *stl, const stl_vertex &versor) static void calculate_normals(stl_file *stl) { stl_normal normal; - for (uint32_t i = 0; i < stl->stats.number_of_facets; i++) { + for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) { stl_calculate_normal(normal, &stl->facet_start[i]); stl_normalize_vector(normal); stl->facet_start[i].normal = normal; diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp index 654426528..4793586e3 100644 --- a/src/libslic3r/Format/3mf.cpp +++ b/src/libslic3r/Format/3mf.cpp @@ -1489,10 +1489,10 @@ namespace Slic3r { } // splits volume out of imported geometry - unsigned int triangles_count = volume_data.last_triangle_id - volume_data.first_triangle_id + 1; - ModelVolume* volume = object.add_volume(TriangleMesh()); - stl_file& stl = volume->mesh.stl; - stl.stats.type = inmemory; + TriangleMesh triangle_mesh; + stl_file &stl = triangle_mesh.stl; + unsigned int triangles_count = volume_data.last_triangle_id - volume_data.first_triangle_id + 1; + stl.stats.type = inmemory; stl.stats.number_of_facets = (uint32_t)triangles_count; stl.stats.original_num_facets = (int)stl.stats.number_of_facets; stl_allocate(&stl); @@ -1509,9 +1509,11 @@ namespace Slic3r { } } - stl_get_size(&stl); - volume->mesh.repair(); - volume->center_geometry(); + stl_get_size(&stl); + triangle_mesh.repair(); + + ModelVolume* volume = object.add_volume(std::move(triangle_mesh)); + volume->center_geometry_after_creation(); volume->calculate_convex_hull(); // apply volume's name and config data @@ -1879,11 +1881,14 @@ namespace Slic3r { if (volume == nullptr) continue; + if (!volume->mesh().repaired) + throw std::runtime_error("store_3mf() requires repair()"); + if (!volume->mesh().has_shared_vertices()) + throw std::runtime_error("store_3mf() requires shared vertices"); + volumes_offsets.insert(VolumeToOffsetsMap::value_type(volume, Offsets(vertices_count))).first; - volume->mesh.require_shared_vertices(); - - const indexed_triangle_set &its = volume->mesh.its; + const indexed_triangle_set &its = volume->mesh().its; if (its.vertices.empty()) { add_error("Found invalid mesh"); @@ -1916,7 +1921,7 @@ namespace Slic3r { VolumeToOffsetsMap::iterator volume_it = volumes_offsets.find(volume); assert(volume_it != volumes_offsets.end()); - const indexed_triangle_set &its = volume->mesh.its; + const indexed_triangle_set &its = volume->mesh().its; // updates triangle offsets volume_it->second.first_triangle_id = triangles_count; diff --git a/src/libslic3r/Format/AMF.cpp b/src/libslic3r/Format/AMF.cpp index 48887bc78..a33d21c9f 100644 --- a/src/libslic3r/Format/AMF.cpp +++ b/src/libslic3r/Format/AMF.cpp @@ -522,7 +522,8 @@ void AMFParserContext::endElement(const char * /* name */) case NODE_TYPE_VOLUME: { assert(m_object && m_volume); - stl_file &stl = m_volume->mesh.stl; + TriangleMesh mesh; + stl_file &stl = mesh.stl; stl.stats.type = inmemory; stl.stats.number_of_facets = int(m_volume_facets.size() / 3); stl.stats.original_num_facets = stl.stats.number_of_facets; @@ -533,8 +534,9 @@ void AMFParserContext::endElement(const char * /* name */) memcpy(facet.vertex[v].data(), &m_object_vertices[m_volume_facets[i ++] * 3], 3 * sizeof(float)); } stl_get_size(&stl); - m_volume->mesh.repair(); - m_volume->center_geometry(); + mesh.repair(); + m_volume->set_mesh(std::move(mesh)); + m_volume->center_geometry_after_creation(); m_volume->calculate_convex_hull(); m_volume_facets.clear(); m_volume = nullptr; @@ -923,10 +925,11 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config) int num_vertices = 0; for (ModelVolume *volume : object->volumes) { vertices_offsets.push_back(num_vertices); - if (! volume->mesh.repaired) + if (! volume->mesh().repaired) throw std::runtime_error("store_amf() requires repair()"); - volume->mesh.require_shared_vertices(); - const indexed_triangle_set &its = volume->mesh.its; + if (! volume->mesh().has_shared_vertices()) + throw std::runtime_error("store_amf() requires shared vertices"); + const indexed_triangle_set &its = volume->mesh().its; const Transform3d& matrix = volume->get_matrix(); for (size_t i = 0; i < its.vertices.size(); ++i) { stream << " \n"; @@ -955,10 +958,11 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config) if (volume->is_modifier()) stream << " 1\n"; stream << " " << ModelVolume::type_to_string(volume->type()) << "\n"; - for (size_t i = 0; i < (int)volume->mesh.its.indices.size(); ++i) { + const indexed_triangle_set &its = volume->mesh().its; + for (size_t i = 0; i < (int)its.indices.size(); ++i) { stream << " \n"; for (int j = 0; j < 3; ++j) - stream << " " << volume->mesh.its.indices[i][j] + vertices_offset << "\n"; + stream << " " << its.indices[i][j] + vertices_offset << "\n"; stream << " \n"; } stream << " \n"; diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 770581c03..113b21503 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -160,12 +160,6 @@ Model Model::read_from_archive(const std::string &input_file, DynamicPrintConfig return model; } -void Model::repair() -{ - for (ModelObject *o : this->objects) - o->repair(); -} - ModelObject* Model::add_object() { this->objects.emplace_back(new ModelObject(this)); @@ -472,7 +466,7 @@ bool Model::looks_like_multipart_object() const if (obj->volumes.size() > 1 || obj->config.keys().size() > 1) return false; for (const ModelVolume *vol : obj->volumes) { - double zmin_this = vol->mesh.bounding_box().min(2); + double zmin_this = vol->mesh().bounding_box().min(2); if (zmin == std::numeric_limits::max()) zmin = zmin_this; else if (std::abs(zmin - zmin_this) > EPSILON) @@ -679,7 +673,7 @@ ModelVolume* ModelObject::add_volume(const TriangleMesh &mesh) { ModelVolume* v = new ModelVolume(this, mesh); this->volumes.push_back(v); - v->center_geometry(); + v->center_geometry_after_creation(); this->invalidate_bounding_box(); return v; } @@ -688,7 +682,7 @@ ModelVolume* ModelObject::add_volume(TriangleMesh &&mesh) { ModelVolume* v = new ModelVolume(this, std::move(mesh)); this->volumes.push_back(v); - v->center_geometry(); + v->center_geometry_after_creation(); this->invalidate_bounding_box(); return v; } @@ -697,7 +691,7 @@ ModelVolume* ModelObject::add_volume(const ModelVolume &other) { ModelVolume* v = new ModelVolume(this, other); this->volumes.push_back(v); - v->center_geometry(); + v->center_geometry_after_creation(); this->invalidate_bounding_box(); return v; } @@ -706,7 +700,7 @@ ModelVolume* ModelObject::add_volume(const ModelVolume &other, TriangleMesh &&me { ModelVolume* v = new ModelVolume(this, other, std::move(mesh)); this->volumes.push_back(v); - v->center_geometry(); + v->center_geometry_after_creation(); this->invalidate_bounding_box(); return v; } @@ -827,7 +821,7 @@ TriangleMesh ModelObject::raw_mesh() const for (const ModelVolume *v : this->volumes) if (v->is_model_part()) { - TriangleMesh vol_mesh(v->mesh); + TriangleMesh vol_mesh(v->mesh()); vol_mesh.transform(v->get_matrix()); mesh.merge(vol_mesh); } @@ -840,7 +834,7 @@ TriangleMesh ModelObject::full_raw_mesh() const TriangleMesh mesh; for (const ModelVolume *v : this->volumes) { - TriangleMesh vol_mesh(v->mesh); + TriangleMesh vol_mesh(v->mesh()); vol_mesh.transform(v->get_matrix()); mesh.merge(vol_mesh); } @@ -854,7 +848,7 @@ const BoundingBoxf3& ModelObject::raw_mesh_bounding_box() const m_raw_mesh_bounding_box.reset(); for (const ModelVolume *v : this->volumes) if (v->is_model_part()) - m_raw_mesh_bounding_box.merge(v->mesh.transformed_bounding_box(v->get_matrix())); + m_raw_mesh_bounding_box.merge(v->mesh().transformed_bounding_box(v->get_matrix())); } return m_raw_mesh_bounding_box; } @@ -863,7 +857,7 @@ BoundingBoxf3 ModelObject::full_raw_mesh_bounding_box() const { BoundingBoxf3 bb; for (const ModelVolume *v : this->volumes) - bb.merge(v->mesh.transformed_bounding_box(v->get_matrix())); + bb.merge(v->mesh().transformed_bounding_box(v->get_matrix())); return bb; } @@ -881,7 +875,7 @@ const BoundingBoxf3& ModelObject::raw_bounding_box() const for (const ModelVolume *v : this->volumes) { if (v->is_model_part()) - m_raw_bounding_box.merge(v->mesh.transformed_bounding_box(inst_matrix * v->get_matrix())); + m_raw_bounding_box.merge(v->mesh().transformed_bounding_box(inst_matrix * v->get_matrix())); } } return m_raw_bounding_box; @@ -895,7 +889,7 @@ BoundingBoxf3 ModelObject::instance_bounding_box(size_t instance_idx, bool dont_ for (ModelVolume *v : this->volumes) { if (v->is_model_part()) - bb.merge(v->mesh.transformed_bounding_box(inst_matrix * v->get_matrix())); + bb.merge(v->mesh().transformed_bounding_box(inst_matrix * v->get_matrix())); } return bb; } @@ -909,10 +903,10 @@ Polygon ModelObject::convex_hull_2d(const Transform3d &trafo_instance) const for (const ModelVolume *v : this->volumes) if (v->is_model_part()) { Transform3d trafo = trafo_instance * v->get_matrix(); - const indexed_triangle_set &its = v->mesh.its; + const indexed_triangle_set &its = v->mesh().its; if (its.vertices.empty()) { // Using the STL faces. - const stl_file& stl = v->mesh.stl; + const stl_file& stl = v->mesh().stl; for (const stl_facet &facet : stl.facet_start) for (size_t j = 0; j < 3; ++ j) { Vec3d p = trafo * facet.vertex[j].cast(); @@ -1038,6 +1032,7 @@ void ModelObject::mirror(Axis axis) this->invalidate_bounding_box(); } +// This method could only be called before the meshes of this ModelVolumes are not shared! void ModelObject::scale_mesh(const Vec3d &versor) { for (ModelVolume *v : this->volumes) @@ -1061,14 +1056,14 @@ 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().stl.stats.number_of_facets; return num; } bool ModelObject::needed_repair() const { for (const ModelVolume *v : this->volumes) - if (v->is_model_part() && v->mesh.needed_repair()) + if (v->is_model_part() && v->mesh().needed_repair()) return true; return false; } @@ -1134,11 +1129,12 @@ ModelObjectPtrs ModelObject::cut(size_t instance, coordf_t z, bool keep_upper, b // Transform the mesh by the combined transformation matrix. // Flip the triangles in case the composite transformation is left handed. - volume->mesh.transform(instance_matrix * volume_matrix, true); + TriangleMesh mesh(volume->mesh()); + mesh.transform(instance_matrix * volume_matrix, true); + volume->reset_mesh(); // Perform cut - volume->mesh.require_shared_vertices(); // TriangleMeshSlicer needs this - TriangleMeshSlicer tms(&volume->mesh); + TriangleMeshSlicer tms(&mesh); tms.cut(float(z), &upper_mesh, &lower_mesh); // Reset volume transformation except for offset @@ -1157,14 +1153,14 @@ ModelObjectPtrs ModelObject::cut(size_t instance, coordf_t z, bool keep_upper, b if (keep_upper && upper_mesh.facets_count() > 0) { ModelVolume* vol = upper->add_volume(upper_mesh); - vol->name = volume->name; - vol->config = volume->config; + vol->name = volume->name; + vol->config = volume->config; vol->set_material(volume->material_id(), *volume->material()); } if (keep_lower && lower_mesh.facets_count() > 0) { ModelVolume* vol = lower->add_volume(lower_mesh); - vol->name = volume->name; - vol->config = volume->config; + vol->name = volume->name; + vol->config = volume->config; vol->set_material(volume->material_id(), *volume->material()); // Compute the lower part instances' bounding boxes to figure out where to place @@ -1232,7 +1228,7 @@ void ModelObject::split(ModelObjectPtrs* new_objects) } ModelVolume* volume = this->volumes.front(); - TriangleMeshPtrs meshptrs = volume->mesh.split(); + TriangleMeshPtrs meshptrs = volume->mesh().split(); for (TriangleMesh *mesh : meshptrs) { mesh->repair(); @@ -1259,12 +1255,6 @@ void ModelObject::split(ModelObjectPtrs* new_objects) return; } -void ModelObject::repair() -{ - for (ModelVolume *v : this->volumes) - v->mesh.repair(); -} - // Support for non-uniform scaling of instances. If an instance is rotated by angles, which are not multiples of ninety degrees, // then the scaling in world coordinate system is not representable by the Geometry::Transformation structure. // This situation is solved by baking in the instance transformation into the mesh vertices. @@ -1294,8 +1284,8 @@ void ModelObject::bake_xy_rotation_into_meshes(size_t instance_idx) // Adjust the meshes. // Transformation to be applied to the meshes. - Eigen::Matrix3d mesh_trafo_3x3 = reference_trafo.get_matrix(true, false, uniform_scaling, ! has_mirrorring).matrix().block<3, 3>(0, 0); - Transform3d volume_offset_correction = this->instances[instance_idx]->get_transformation().get_matrix().inverse() * reference_trafo.get_matrix(); + Eigen::Matrix3d mesh_trafo_3x3 = reference_trafo.get_matrix(true, false, uniform_scaling, ! has_mirrorring).matrix().block<3, 3>(0, 0); + Transform3d volume_offset_correction = this->instances[instance_idx]->get_transformation().get_matrix().inverse() * reference_trafo.get_matrix(); for (ModelVolume *model_volume : this->volumes) { const Geometry::Transformation volume_trafo = model_volume->get_transformation(); bool volume_left_handed = volume_trafo.is_left_handed(); @@ -1305,7 +1295,8 @@ void ModelObject::bake_xy_rotation_into_meshes(size_t instance_idx) double volume_new_scaling_factor = volume_uniform_scaling ? volume_trafo.get_scaling_factor().x() : 1.; // Transform the mesh. Matrix3d volume_trafo_3x3 = volume_trafo.get_matrix(true, false, volume_uniform_scaling, !volume_has_mirrorring).matrix().block<3, 3>(0, 0); - model_volume->transform_mesh(mesh_trafo_3x3 * volume_trafo_3x3, left_handed != volume_left_handed); + // Following method creates a new shared_ptr + model_volume->transform_this_mesh(mesh_trafo_3x3 * volume_trafo_3x3, left_handed != volume_left_handed); // Reset the rotation, scaling and mirroring. model_volume->set_rotation(Vec3d(0., 0., 0.)); model_volume->set_scaling_factor(Vec3d(volume_new_scaling_factor, volume_new_scaling_factor, volume_new_scaling_factor)); @@ -1447,7 +1438,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().stl.stats; stl_stats full_stats; memset(&full_stats, 0, sizeof(stl_stats)); @@ -1458,7 +1449,7 @@ stl_stats ModelObject::get_object_stl_stats() const if (volume->id() == this->volumes[0]->id()) continue; - const stl_stats& stats = volume->mesh.stl.stats; + const stl_stats& stats = volume->mesh().stl.stats; // initialize full_stats (for repaired errors) full_stats.degenerate_facets += stats.degenerate_facets; @@ -1526,30 +1517,30 @@ bool ModelVolume::is_splittable() const { // the call mesh.is_splittable() is expensive, so cache the value to calculate it only once if (m_is_splittable == -1) - m_is_splittable = (int)mesh.is_splittable(); + m_is_splittable = (int)this->mesh().is_splittable(); return m_is_splittable == 1; } -void ModelVolume::center_geometry() +void ModelVolume::center_geometry_after_creation() { - Vec3d shift = mesh.bounding_box().center(); + Vec3d shift = this->mesh().bounding_box().center(); if (!shift.isApprox(Vec3d::Zero())) { - mesh.translate(-(float)shift(0), -(float)shift(1), -(float)shift(2)); - m_convex_hull.translate(-(float)shift(0), -(float)shift(1), -(float)shift(2)); + m_mesh->translate(-(float)shift(0), -(float)shift(1), -(float)shift(2)); + m_convex_hull->translate(-(float)shift(0), -(float)shift(1), -(float)shift(2)); translate(shift); } } void ModelVolume::calculate_convex_hull() { - m_convex_hull = mesh.convex_hull_3d(); + m_convex_hull = std::make_shared(this->mesh().convex_hull_3d()); } int ModelVolume::get_mesh_errors_count() const { - const stl_stats& stats = this->mesh.stl.stats; + const stl_stats& stats = this->mesh().stl.stats; return stats.degenerate_facets + stats.edges_fixed + stats.facets_removed + stats.facets_added + stats.facets_reversed + stats.backwards_edges; @@ -1557,7 +1548,7 @@ int ModelVolume::get_mesh_errors_count() const const TriangleMesh& ModelVolume::get_convex_hull() const { - return m_convex_hull; + return *m_convex_hull.get(); } ModelVolumeType ModelVolume::type_from_string(const std::string &s) @@ -1597,7 +1588,7 @@ std::string ModelVolume::type_to_string(const ModelVolumeType t) // This is useful to assign different materials to different volumes of an object. size_t ModelVolume::split(unsigned int max_extruders) { - TriangleMeshPtrs meshptrs = this->mesh.split(); + TriangleMeshPtrs meshptrs = this->mesh().split(); if (meshptrs.size() <= 1) { delete meshptrs.front(); return 1; @@ -1614,7 +1605,7 @@ size_t ModelVolume::split(unsigned int max_extruders) mesh->repair(); if (idx == 0) { - this->mesh = std::move(*mesh); + this->set_mesh(std::move(*mesh)); this->calculate_convex_hull(); // Assign a new unique ID, so that a new GLVolume will be generated. this->set_new_unique_id(); @@ -1623,7 +1614,7 @@ size_t ModelVolume::split(unsigned int max_extruders) this->object->volumes.insert(this->object->volumes.begin() + (++ivolume), new ModelVolume(object, *this, std::move(*mesh))); this->object->volumes[ivolume]->set_offset(Vec3d::Zero()); - this->object->volumes[ivolume]->center_geometry(); + this->object->volumes[ivolume]->center_geometry_after_creation(); this->object->volumes[ivolume]->translate(offset); this->object->volumes[ivolume]->name = name + "_" + std::to_string(idx + 1); this->object->volumes[ivolume]->config.set_deserialize("extruder", Model::get_auto_extruder_id_as_string(max_extruders)); @@ -1689,24 +1680,33 @@ void ModelVolume::mirror(Axis axis) set_mirror(mirror); } +// This method could only be called before the meshes of this ModelVolumes are not shared! void ModelVolume::scale_geometry(const Vec3d& versor) { - mesh.scale(versor); - m_convex_hull.scale(versor); + m_mesh->scale(versor); + m_convex_hull->scale(versor); } -void ModelVolume::transform_mesh(const Transform3d &mesh_trafo, bool fix_left_handed) +void ModelVolume::transform_this_mesh(const Transform3d &mesh_trafo, bool fix_left_handed) { - this->mesh.transform(mesh_trafo, fix_left_handed); - this->m_convex_hull.transform(mesh_trafo, fix_left_handed); + TriangleMesh mesh = this->mesh(); + mesh.transform(mesh_trafo, fix_left_handed); + this->set_mesh(std::move(mesh)); + TriangleMesh convex_hull = this->get_convex_hull(); + convex_hull.transform(mesh_trafo, fix_left_handed); + this->m_convex_hull = std::make_shared(std::move(convex_hull)); // Let the rest of the application know that the geometry changed, so the meshes have to be reloaded. this->set_new_unique_id(); } -void ModelVolume::transform_mesh(const Matrix3d &matrix, bool fix_left_handed) +void ModelVolume::transform_this_mesh(const Matrix3d &matrix, bool fix_left_handed) { - this->mesh.transform(matrix, fix_left_handed); - this->m_convex_hull.transform(matrix, fix_left_handed); + TriangleMesh mesh = this->mesh(); + mesh.transform(matrix, fix_left_handed); + this->set_mesh(std::move(mesh)); + TriangleMesh convex_hull = this->get_convex_hull(); + convex_hull.transform(matrix, fix_left_handed); + this->m_convex_hull = std::make_shared(std::move(convex_hull)); // Let the rest of the application know that the geometry changed, so the meshes have to be reloaded. this->set_new_unique_id(); } diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 41bf5bd4b..0fd1140f0 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -7,7 +7,9 @@ #include "Point.hpp" #include "TriangleMesh.hpp" #include "Slicing.hpp" + #include +#include #include #include #include @@ -261,6 +263,7 @@ public: void rotate(double angle, const Vec3d& axis); void mirror(Axis axis); + // This method could only be called before the meshes of this ModelVolumes are not shared! void scale_mesh(const Vec3d& versor); size_t materials_count() const; @@ -268,7 +271,6 @@ public: bool needed_repair() const; ModelObjectPtrs cut(size_t instance, coordf_t z, bool keep_upper = true, bool keep_lower = true, bool rotate_lower = false); // Note: z is in world coordinates void split(ModelObjectPtrs* new_objects); - void repair(); // Support for non-uniform scaling of instances. If an instance is rotated by angles, which are not multiples of ninety degrees, // then the scaling in world coordinate system is not representable by the Geometry::Transformation structure. // This situation is solved by baking in the instance transformation into the mesh vertices. @@ -340,7 +342,12 @@ class ModelVolume : public ModelBase public: std::string name; // The triangular model. - TriangleMesh mesh; + const TriangleMesh& mesh() const { return *m_mesh.get(); } + void set_mesh(const TriangleMesh &mesh) { m_mesh = std::make_shared(mesh); } + void set_mesh(TriangleMesh &&mesh) { m_mesh = std::make_shared(std::move(mesh)); } + void set_mesh(std::shared_ptr &mesh) { m_mesh = mesh; } + void set_mesh(std::unique_ptr &&mesh) { m_mesh = std::move(mesh); } + void reset_mesh() { m_mesh = std::make_shared(); } // Configuration parameters specific to an object model geometry or a modifier volume, // overriding the global Slic3r settings and the ModelObject settings. DynamicPrintConfig config; @@ -377,13 +384,16 @@ public: void rotate(double angle, const Vec3d& axis); void mirror(Axis axis); + // This method could only be called before the meshes of this ModelVolumes are not shared! void scale_geometry(const Vec3d& versor); - // translates the mesh and the convex hull so that the origin of their vertices is in the center of this volume's bounding box - void center_geometry(); + // Translates the mesh and the convex hull so that the origin of their vertices is in the center of this volume's bounding box. + // Attention! This method may only be called just after ModelVolume creation! It must not be called once the TriangleMesh of this ModelVolume is shared! + void center_geometry_after_creation(); void calculate_convex_hull(); const TriangleMesh& get_convex_hull() const; + std::shared_ptr get_convex_hull_shared_ptr() const { return m_convex_hull; } // Get count of errors in the mesh int get_mesh_errors_count() const; @@ -430,18 +440,20 @@ protected: explicit ModelVolume(const ModelVolume &rhs) = default; void set_model_object(ModelObject *model_object) { object = model_object; } - void transform_mesh(const Transform3d& t, bool fix_left_handed); - void transform_mesh(const Matrix3d& m, bool fix_left_handed); + void transform_this_mesh(const Transform3d& t, bool fix_left_handed); + void transform_this_mesh(const Matrix3d& m, bool fix_left_handed); private: // Parent object owning this ModelVolume. - ModelObject* object; + ModelObject* object; + // The triangular model. + std::shared_ptr m_mesh; // Is it an object to be printed, or a modifier volume? - ModelVolumeType m_type; - t_model_material_id m_material_id; + ModelVolumeType m_type; + t_model_material_id m_material_id; // The convex hull of this model's mesh. - TriangleMesh m_convex_hull; - Geometry::Transformation m_transformation; + std::shared_ptr m_convex_hull; + Geometry::Transformation m_transformation; // flag to optimize the checking if the volume is splittable // -1 -> is unknown value (before first cheking) @@ -449,24 +461,24 @@ private: // 1 -> is splittable mutable int m_is_splittable{ -1 }; - ModelVolume(ModelObject *object, const TriangleMesh &mesh) : mesh(mesh), m_type(ModelVolumeType::MODEL_PART), object(object) + ModelVolume(ModelObject *object, const TriangleMesh &mesh) : m_mesh(new TriangleMesh(mesh)), m_type(ModelVolumeType::MODEL_PART), object(object) { if (mesh.stl.stats.number_of_facets > 1) calculate_convex_hull(); } ModelVolume(ModelObject *object, TriangleMesh &&mesh, TriangleMesh &&convex_hull) : - mesh(std::move(mesh)), m_convex_hull(std::move(convex_hull)), m_type(ModelVolumeType::MODEL_PART), object(object) {} + m_mesh(new TriangleMesh(std::move(mesh))), m_convex_hull(new TriangleMesh(std::move(convex_hull))), m_type(ModelVolumeType::MODEL_PART), object(object) {} // Copying an existing volume, therefore this volume will get a copy of the ID assigned. ModelVolume(ModelObject *object, const ModelVolume &other) : ModelBase(other), // copy the ID - name(other.name), mesh(other.mesh), m_convex_hull(other.m_convex_hull), config(other.config), m_type(other.m_type), object(object), m_transformation(other.m_transformation) + name(other.name), m_mesh(other.m_mesh), m_convex_hull(other.m_convex_hull), config(other.config), m_type(other.m_type), object(object), m_transformation(other.m_transformation) { this->set_material_id(other.material_id()); } // Providing a new mesh, therefore this volume will get a new unique ID assigned. ModelVolume(ModelObject *object, const ModelVolume &other, const TriangleMesh &&mesh) : - name(other.name), mesh(std::move(mesh)), config(other.config), m_type(other.m_type), object(object), m_transformation(other.m_transformation) + name(other.name), m_mesh(new TriangleMesh(std::move(mesh))), config(other.config), m_type(other.m_type), object(object), m_transformation(other.m_transformation) { this->set_material_id(other.material_id()); if (mesh.stl.stats.number_of_facets > 1) @@ -597,10 +609,6 @@ public: static Model read_from_file(const std::string &input_file, DynamicPrintConfig *config = nullptr, bool add_default_instances = true); static Model read_from_archive(const std::string &input_file, DynamicPrintConfig *config, bool add_default_instances = true); - /// Repair the ModelObjects of the current Model. - /// This function calls repair function on each TriangleMesh of each model object volume - void repair(); - // Add a new ModelObject to this Model, generate a new ID for this ModelObject. ModelObject* add_object(); ModelObject* add_object(const char *name, const char *path, const TriangleMesh &mesh); diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 660a2d939..d99aceabf 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -1797,7 +1797,7 @@ std::vector PrintObject::_slice_volumes(const std::vector &z, if (! volumes.empty()) { // Compose mesh. //FIXME better to perform slicing over each volume separately and then to use a Boolean operation to merge them. - TriangleMesh mesh(volumes.front()->mesh); + TriangleMesh mesh(volumes.front()->mesh()); mesh.transform(volumes.front()->get_matrix(), true); assert(mesh.repaired); if (volumes.size() == 1 && mesh.repaired) { @@ -1806,7 +1806,7 @@ std::vector PrintObject::_slice_volumes(const std::vector &z, } for (size_t idx_volume = 1; idx_volume < volumes.size(); ++ idx_volume) { const ModelVolume &model_volume = *volumes[idx_volume]; - TriangleMesh vol_mesh(model_volume.mesh); + TriangleMesh vol_mesh(model_volume.mesh()); vol_mesh.transform(model_volume.get_matrix(), true); mesh.merge(vol_mesh); } @@ -1815,10 +1815,11 @@ std::vector PrintObject::_slice_volumes(const std::vector &z, // apply XY shift mesh.translate(- unscale(m_copies_shift(0)), - unscale(m_copies_shift(1)), 0); // perform actual slicing - TriangleMeshSlicer mslicer; const Print *print = this->print(); auto callback = TriangleMeshSlicer::throw_on_cancel_callback_type([print](){print->throw_if_canceled();}); - mesh.require_shared_vertices(); // TriangleMeshSlicer needs this + // TriangleMeshSlicer needs shared vertices, also this calls the repair() function. + mesh.require_shared_vertices(); + TriangleMeshSlicer mslicer; mslicer.init(&mesh, callback); mslicer.slice(z, float(m_config.slice_closing_radius.value), &layers, callback); m_print->throw_if_canceled(); @@ -1832,7 +1833,7 @@ std::vector PrintObject::_slice_volume(const std::vector &z, std::vector layers; // Compose mesh. //FIXME better to perform slicing over each volume separately and then to use a Boolean operation to merge them. - TriangleMesh mesh(volume.mesh); + TriangleMesh mesh(volume.mesh()); mesh.transform(volume.get_matrix(), true); if (mesh.repaired) { //FIXME The admesh repair function may break the face connectivity, rather refresh it here as the slicing code relies on it. @@ -1846,7 +1847,8 @@ std::vector PrintObject::_slice_volume(const std::vector &z, TriangleMeshSlicer mslicer; const Print *print = this->print(); auto callback = TriangleMeshSlicer::throw_on_cancel_callback_type([print](){print->throw_if_canceled();}); - mesh.require_shared_vertices(); // TriangleMeshSlicer needs this + // TriangleMeshSlicer needs the shared vertices. + mesh.require_shared_vertices(); mslicer.init(&mesh, callback); mslicer.slice(z, float(m_config.slice_closing_radius.value), &layers, callback); m_print->throw_if_canceled(); diff --git a/src/libslic3r/Slicing.cpp b/src/libslic3r/Slicing.cpp index 3a05e9d8a..e1bb4b313 100644 --- a/src/libslic3r/Slicing.cpp +++ b/src/libslic3r/Slicing.cpp @@ -227,7 +227,7 @@ std::vector layer_height_profile_adaptive( as.set_slicing_parameters(slicing_params); for (const ModelVolume *volume : volumes) if (volume->is_model_part()) - as.add_mesh(&volume->mesh); + as.add_mesh(&volume->mesh()); as.prepare(); // 2) Generate layers using the algorithm of @platsch diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp index 5b0ecbd00..11f45147c 100644 --- a/src/libslic3r/TriangleMesh.cpp +++ b/src/libslic3r/TriangleMesh.cpp @@ -82,11 +82,14 @@ TriangleMesh& TriangleMesh::operator=(const TriangleMesh &other) // #define SLIC3R_TRACE_REPAIR -void TriangleMesh::repair() +void TriangleMesh::repair(bool update_shared_vertices) { - if (this->repaired) + if (this->repaired) { + if (update_shared_vertices) + this->require_shared_vertices(); return; - + } + // admesh fails when repairing empty meshes if (this->stl.stats.number_of_facets == 0) return; @@ -97,6 +100,7 @@ void TriangleMesh::repair() #ifdef SLIC3R_TRACE_REPAIR BOOST_LOG_TRIVIAL(trace) << "\tstl_check_faces_exact"; #endif /* SLIC3R_TRACE_REPAIR */ + assert(stl_validate(&this->stl)); stl_check_facets_exact(&stl); assert(stl_validate(&this->stl)); stl.stats.facets_w_1_bad_edge = (stl.stats.connected_facets_2_edge - stl.stats.connected_facets_3_edge); @@ -179,6 +183,12 @@ void TriangleMesh::repair() this->repaired = true; BOOST_LOG_TRIVIAL(debug) << "TriangleMesh::repair() finished"; + + // This call should be quite cheap, a lot of code requires the indexed_triangle_set data structure, + // and it is risky to generate such a structure once the meshes are shared. Do it now. + this->its.clear(); + if (update_shared_vertices) + this->require_shared_vertices(); } float TriangleMesh::volume() @@ -238,8 +248,7 @@ bool TriangleMesh::needed_repair() const void TriangleMesh::WriteOBJFile(const char* output_file) { - stl_generate_shared_vertices(&stl, its); - its_write_obj(its, output_file); + its_write_obj(this->its, output_file); } void TriangleMesh::scale(float factor) @@ -294,6 +303,7 @@ void TriangleMesh::rotate(float angle, const Vec3d& axis) Transform3d m = Transform3d::Identity(); m.rotate(Eigen::AngleAxisd(angle, axis_norm)); stl_transform(&stl, m); + its_transform(its, m); } void TriangleMesh::mirror(const Axis &axis) @@ -311,22 +321,26 @@ void TriangleMesh::mirror(const Axis &axis) void TriangleMesh::transform(const Transform3d& t, bool fix_left_handed) { stl_transform(&stl, t); - this->its.clear(); + its_transform(its, t); if (fix_left_handed && t.matrix().block(0, 0, 3, 3).determinant() < 0.) { // Left handed transformation is being applied. It is a good idea to flip the faces and their normals. - this->repair(); + this->repair(false); stl_reverse_all_facets(&stl); + this->its.clear(); + this->require_shared_vertices(); } } void TriangleMesh::transform(const Matrix3d& m, bool fix_left_handed) { stl_transform(&stl, m); - this->its.clear(); + its_transform(its, m); if (fix_left_handed && m.determinant() < 0.) { // Left handed transformation is being applied. It is a good idea to flip the faces and their normals. - this->repair(); + this->repair(false); stl_reverse_all_facets(&stl); + this->its.clear(); + this->require_shared_vertices(); } } @@ -482,7 +496,6 @@ ExPolygons TriangleMesh::horizontal_projection() const // 2D convex hull of a 3D mesh projected into the Z=0 plane. Polygon TriangleMesh::convex_hull() { - this->require_shared_vertices(); Points pp; pp.reserve(this->its.vertices.size()); for (size_t i = 0; i < this->its.vertices.size(); ++ i) { @@ -519,26 +532,32 @@ BoundingBoxf3 TriangleMesh::transformed_bounding_box(const Transform3d &trafo) c TriangleMesh TriangleMesh::convex_hull_3d() const { - // Helper struct for qhull: - struct PointForQHull{ - PointForQHull(float x_p, float y_p, float z_p) : x((realT)x_p), y((realT)y_p), z((realT)z_p) {} - realT x, y, z; - }; - std::vector src_vertices; - - // We will now fill the vector with input points for computation: - for (const stl_facet &facet : stl.facet_start) - for (int i = 0; i < 3; ++ i) { - const stl_vertex& v = facet.vertex[i]; - src_vertices.emplace_back(v(0), v(1), v(2)); - } - // The qhull call: orgQhull::Qhull qhull; qhull.disableOutputStream(); // we want qhull to be quiet - try + std::vector src_vertices; + try { - qhull.runQhull("", 3, (int)src_vertices.size(), (const realT*)(src_vertices.data()), "Qt"); + if (this->has_shared_vertices()) { +#if REALfloat + qhull.runQhull("", 3, (int)this->its.vertices.size() / 3, (const realT*)(this->its.vertices.front().data()), "Qt"); +#else + src_vertices.reserve(this->its.vertices() * 3); + // We will now fill the vector with input points for computation: + for (const stl_vertex &v : ths->its.vertices.size()) + for (int i = 0; i < 3; ++ i) + src_vertices.emplace_back(v(i)); + qhull.runQhull("", 3, (int)src_vertices.size() / 3, src_vertices.data(), "Qt"); +#endif + } else { + src_vertices.reserve(this->stl.facet_start.size() * 9); + // We will now fill the vector with input points for computation: + for (const stl_facet &f : this->stl.facet_start) + for (int i = 0; i < 3; ++ i) + for (int j = 0; j < 3; ++ j) + src_vertices.emplace_back(f.vertex[i](j)); + qhull.runQhull("", 3, (int)src_vertices.size() / 3, src_vertices.data(), "Qt"); + } } catch (...) { @@ -566,7 +585,6 @@ TriangleMesh TriangleMesh::convex_hull_3d() const TriangleMesh output_mesh(dst_vertices, facets); output_mesh.repair(); - output_mesh.require_shared_vertices(); return output_mesh; } diff --git a/src/libslic3r/TriangleMesh.hpp b/src/libslic3r/TriangleMesh.hpp index 75082cfdb..ffd9b7e62 100644 --- a/src/libslic3r/TriangleMesh.hpp +++ b/src/libslic3r/TriangleMesh.hpp @@ -33,7 +33,7 @@ public: bool ReadSTLFile(const char* input_file) { return stl_open(&stl, input_file); } bool write_ascii(const char* output_file) { return stl_write_ascii(&this->stl, output_file, ""); } bool write_binary(const char* output_file) { return stl_write_binary(&this->stl, output_file, ""); } - void repair(); + void repair(bool update_shared_vertices = true); float volume(); void check_topology(); bool is_manifold() const { return this->stl.stats.connected_facets_3_edge == (int)this->stl.stats.number_of_facets; } diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 59480de1c..33ab1f5d1 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -241,8 +241,6 @@ GLVolume::GLVolume(float r, float g, float b, float a) : m_transformed_bounding_box_dirty(true) , m_sla_shift_z(0.0) , m_transformed_convex_hull_bounding_box_dirty(true) - , m_convex_hull(nullptr) - , m_convex_hull_owned(false) // geometry_id == 0 -> invalid , geometry_id(std::pair(0, 0)) , extruder_id(0) @@ -268,12 +266,6 @@ GLVolume::GLVolume(float r, float g, float b, float a) set_render_color(r, g, b, a); } -GLVolume::~GLVolume() -{ - if (m_convex_hull_owned) - delete m_convex_hull; -} - void GLVolume::set_render_color(float r, float g, float b, float a) { render_color[0] = r; @@ -335,12 +327,6 @@ void GLVolume::set_color_from_model_volume(const ModelVolume *model_volume) color[3] = model_volume->is_model_part() ? 1.f : 0.5f; } -void GLVolume::set_convex_hull(const TriangleMesh *convex_hull, bool owned) -{ - m_convex_hull = convex_hull; - m_convex_hull_owned = owned; -} - Transform3d GLVolume::world_matrix() const { Transform3d m = m_instance_transformation.get_matrix() * m_volume_transformation.get_matrix(); @@ -377,7 +363,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 != nullptr && m_convex_hull->stl.stats.number_of_facets > 0) ? + return (m_convex_hull && m_convex_hull->stl.stats.number_of_facets > 0) ? m_convex_hull->transformed_bounding_box(trafo) : bounding_box.transformed(trafo); } @@ -587,7 +573,7 @@ int GLVolumeCollection::load_object_volume( const ModelVolume *model_volume = model_object->volumes[volume_idx]; const int extruder_id = model_volume->extruder_id(); const ModelInstance *instance = model_object->instances[instance_idx]; - const TriangleMesh& mesh = model_volume->mesh; + const TriangleMesh& mesh = model_volume->mesh(); float color[4]; memcpy(color, GLVolume::MODEL_COLOR[((color_by == "volume") ? volume_idx : obj_idx) % 4], sizeof(float) * 3); /* if (model_volume->is_support_blocker()) { @@ -613,7 +599,7 @@ int GLVolumeCollection::load_object_volume( if (model_volume->is_model_part()) { // GLVolume will reference a convex hull from model_volume! - v.set_convex_hull(&model_volume->get_convex_hull(), false); + v.set_convex_hull(model_volume->get_convex_hull_shared_ptr()); if (extruder_id != -1) v.extruder_id = extruder_id; } @@ -656,7 +642,10 @@ void GLVolumeCollection::load_object_auxiliary( v.composite_id = GLVolume::CompositeID(obj_idx, - int(milestone), (int)instance_idx.first); v.geometry_id = std::pair(timestamp, model_instance.id().id); // Create a copy of the convex hull mesh for each instance. Use a move operator on the last instance. - v.set_convex_hull((&instance_idx == &instances.back()) ? new TriangleMesh(std::move(convex_hull)) : new TriangleMesh(convex_hull), true); + if (&instance_idx == &instances.back()) + v.set_convex_hull(std::move(convex_hull)); + else + v.set_convex_hull(convex_hull); v.is_modifier = false; v.shader_outside_printer_detection_enabled = (milestone == slaposSupportTree); v.set_instance_transformation(model_instance.get_transformation()); diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index 2ca11073b..b9ac668e0 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -10,6 +10,7 @@ #include "slic3r/GUI/GLCanvas3DManager.hpp" #include +#include #ifndef NDEBUG #define HAS_GLSAFE @@ -243,7 +244,6 @@ public: GLVolume(float r = 1.f, float g = 1.f, float b = 1.f, float a = 1.f); GLVolume(const float *rgba) : GLVolume(rgba[0], rgba[1], rgba[2], rgba[3]) {} - ~GLVolume(); private: Geometry::Transformation m_instance_transformation; @@ -255,10 +255,8 @@ private: mutable BoundingBoxf3 m_transformed_bounding_box; // Whether or not is needed to recalculate the transformed bounding box. mutable bool m_transformed_bounding_box_dirty; - // Pointer to convex hull of the original mesh, if any. - // This object may or may not own the convex hull instance based on m_convex_hull_owned - const TriangleMesh* m_convex_hull; - bool m_convex_hull_owned; + // Convex hull of the volume, if any. + std::shared_ptr m_convex_hull; // Bounding box of this volume, in unscaled coordinates. mutable BoundingBoxf3 m_transformed_convex_hull_bounding_box; // Whether or not is needed to recalculate the transformed convex hull bounding box. @@ -395,7 +393,9 @@ public: double get_sla_shift_z() const { return m_sla_shift_z; } void set_sla_shift_z(double z) { m_sla_shift_z = z; } - void set_convex_hull(const TriangleMesh *convex_hull, bool owned); + void set_convex_hull(std::shared_ptr &convex_hull) { m_convex_hull = convex_hull; } + void set_convex_hull(const TriangleMesh &convex_hull) { m_convex_hull = std::make_shared(convex_hull); } + void set_convex_hull(TriangleMesh &&convex_hull) { m_convex_hull = std::make_shared(std::move(convex_hull)); } int object_idx() const { return this->composite_id.object_id; } int volume_idx() const { return this->composite_id.volume_id; } diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index b8ca905d2..f0a40950d 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -5498,7 +5498,7 @@ void GLCanvas3D::_load_sla_shells() v.set_instance_offset(unscale(instance.shift(0), instance.shift(1), 0)); v.set_instance_rotation(Vec3d(0.0, 0.0, (double)instance.rotation)); v.set_instance_mirror(X, object.is_left_handed() ? -1. : 1.); - v.set_convex_hull(new TriangleMesh(std::move(mesh.convex_hull_3d())), true); + v.set_convex_hull(mesh.convex_hull_3d()); }; // adds objects' volumes diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index dffa02e95..cbf7a5ef5 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -261,7 +261,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().stl.stats; std::map error_msg = { { L("degenerate facets"), stats.degenerate_facets }, @@ -1592,7 +1592,7 @@ void ObjectList::load_generic_subobject(const std::string& type_name, const Mode // First (any) GLVolume of the selected instance. They all share the same instance matrix. const GLVolume* v = selection.get_volume(*selection.get_volume_idxs().begin()); // Transform the new modifier to be aligned with the print bed. - const BoundingBoxf3 mesh_bb = new_volume->mesh.bounding_box(); + const BoundingBoxf3 mesh_bb = new_volume->mesh().bounding_box(); new_volume->set_transformation(volume_to_bed_transformation(v->get_instance_transformation(), mesh_bb)); // Set the modifier position. auto offset = (type_name == "Slab") ? diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index 89475a058..2a2adcae9 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -388,8 +388,7 @@ void GLGizmoSlaSupports::update_mesh() wxBusyCursor wait; // this way we can use that mesh directly. // This mesh does not account for the possible Z up SLA offset. - m_mesh = &m_model_object->volumes.front()->mesh; - const_cast(m_mesh)->require_shared_vertices(); // TriangleMeshSlicer needs this + m_mesh = &m_model_object->volumes.front()->mesh(); m_its = &m_mesh->its; m_current_mesh_model_id = m_model_object->id(); m_editing_mode = false; diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 44f77b3f7..18b3078bb 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -3565,7 +3565,7 @@ void Plater::export_stl(bool extended, bool selection_only) else { const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); - mesh = model_object->volumes[volume->volume_idx()]->mesh; + mesh = model_object->volumes[volume->volume_idx()]->mesh(); mesh.transform(volume->get_volume_transformation().get_matrix()); mesh.translate(-model_object->origin_translation.cast()); } diff --git a/xs/xsp/Model.xsp b/xs/xsp/Model.xsp index a1c8890ef..6a2cc6080 100644 --- a/xs/xsp/Model.xsp +++ b/xs/xsp/Model.xsp @@ -253,7 +253,7 @@ ModelMaterial::attributes() Ref config() %code%{ RETVAL = &THIS->config; %}; Ref mesh() - %code%{ RETVAL = &THIS->mesh; %}; + %code%{ RETVAL = &THIS->mesh(); %}; bool modifier() %code%{ RETVAL = THIS->is_modifier(); %}; From 3872b939e440421dec0fc2cee8fad40fba6f1c0c Mon Sep 17 00:00:00 2001 From: bubnikv Date: Tue, 11 Jun 2019 17:15:07 +0200 Subject: [PATCH 15/22] Fix of previous commit --- src/admesh/stl.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/admesh/stl.h b/src/admesh/stl.h index c419c567b..40bced2f4 100644 --- a/src/admesh/stl.h +++ b/src/admesh/stl.h @@ -216,7 +216,6 @@ template extern void its_transform(indexed_triangle_set &its, T *trafo3x4) { for (stl_vertex &v_dst : its.vertices) { - stl_vertex &v_dst = face.vertex[i_vertex]; stl_vertex v_src = v_dst; v_dst(0) = T(trafo3x4[0] * v_src(0) + trafo3x4[1] * v_src(1) + trafo3x4[2] * v_src(2) + trafo3x4[3]); v_dst(1) = T(trafo3x4[4] * v_src(0) + trafo3x4[5] * v_src(1) + trafo3x4[6] * v_src(2) + trafo3x4[7]); From 9379fedd439826846d97eb02c7d88455aa50c47e Mon Sep 17 00:00:00 2001 From: bubnikv Date: Thu, 13 Jun 2019 16:33:50 +0200 Subject: [PATCH 16/22] Further C++isation of the admesh library & TriangleMesh (copy & move constructors / operators) --- src/admesh/connect.cpp | 2 ++ src/admesh/stl.h | 26 ++++++++++++++- src/admesh/stlinit.cpp | 10 +----- src/admesh/util.cpp | 43 ++++++++++++++++++++----- src/libslic3r/TriangleMesh.cpp | 47 +++++++++++++++------------- src/libslic3r/TriangleMesh.hpp | 14 ++++----- src/slic3r/Config/Version.cpp | 5 +++ src/slic3r/Utils/FixModelByWin10.cpp | 4 +-- 8 files changed, 102 insertions(+), 49 deletions(-) diff --git a/src/admesh/connect.cpp b/src/admesh/connect.cpp index 1a7b7965d..5afb85d2c 100644 --- a/src/admesh/connect.cpp +++ b/src/admesh/connect.cpp @@ -30,6 +30,8 @@ #include #include +// Boost pool: Don't use mutexes to synchronize memory allocation. +#define BOOST_POOL_NO_MT #include #include "stl.h" diff --git a/src/admesh/stl.h b/src/admesh/stl.h index 40bced2f4..87210b3c9 100644 --- a/src/admesh/stl.h +++ b/src/admesh/stl.h @@ -89,6 +89,8 @@ struct stl_neighbors { }; struct stl_stats { + stl_stats() { this->reset(); } + void reset() { memset(this, 0, sizeof(stl_stats)); this->volume = -1.0; } char header[81]; stl_type type; uint32_t number_of_facets; @@ -117,6 +119,18 @@ struct stl_stats { }; struct stl_file { + stl_file() {} + stl_file(const stl_file &rhs) : facet_start(rhs.facet_start), neighbors_start(rhs.neighbors_start), stats(rhs.stats) {} + stl_file(stl_file &&rhs) : facet_start(std::move(rhs.facet_start)), neighbors_start(std::move(rhs.neighbors_start)), stats(rhs.stats) {} + stl_file& operator=(const stl_file &rhs) { this->facet_start = rhs.facet_start; this->neighbors_start = rhs.neighbors_start; this->stats = rhs.stats; return *this; } + stl_file& operator=(stl_file &&rhs) { this->facet_start = std::move(rhs.facet_start); this->neighbors_start = std::move(rhs.neighbors_start); this->stats = rhs.stats; return *this; } + + void clear() { + this->facet_start.clear(); + this->neighbors_start.clear(); + this->stats.reset(); + } + std::vector facet_start; std::vector neighbors_start; // Statistics @@ -125,7 +139,14 @@ struct stl_file { struct indexed_triangle_set { + indexed_triangle_set() {} + indexed_triangle_set(const indexed_triangle_set &rhs) : indices(rhs.indices), vertices(rhs.vertices) {} + indexed_triangle_set(indexed_triangle_set &&rhs) : indices(std::move(rhs.indices)), vertices(std::move(rhs.vertices)) {} + indexed_triangle_set& operator=(const indexed_triangle_set &rhs) { this->indices = rhs.indices; this->vertices = rhs.vertices; return *this; } + indexed_triangle_set& operator=(indexed_triangle_set &&rhs) { this->indices = std::move(rhs.indices); this->vertices = std::move(rhs.vertices); return *this; } + void clear() { indices.clear(); vertices.clear(); } + std::vector indices; std::vector vertices; //FIXME add normals once we get rid of the stl_file from TriangleMesh completely. @@ -238,6 +259,10 @@ inline void its_transform(indexed_triangle_set &its, const Eigen::Matrix()).template cast().eval(); } +extern void its_rotate_x(indexed_triangle_set &its, float angle); +extern void its_rotate_y(indexed_triangle_set &its, float angle); +extern void its_rotate_z(indexed_triangle_set &its, float angle); + extern void stl_generate_shared_vertices(stl_file *stl, indexed_triangle_set &its); extern bool its_write_obj(const indexed_triangle_set &its, const char *file); extern bool its_write_off(const indexed_triangle_set &its, const char *file); @@ -258,7 +283,6 @@ extern void stl_calculate_volume(stl_file *stl); extern void stl_repair(stl_file *stl, bool fixall_flag, bool exact_flag, bool tolerance_flag, float tolerance, bool increment_flag, float increment, bool nearby_flag, int iterations, bool remove_unconnected_flag, bool fill_holes_flag, bool normal_directions_flag, bool normal_values_flag, bool reverse_all_flag, bool verbose_flag); -extern void stl_reset(stl_file *stl); extern void stl_allocate(stl_file *stl); extern void stl_read(stl_file *stl, int first_facet, bool first); extern void stl_facet_stats(stl_file *stl, stl_facet facet, bool &first); diff --git a/src/admesh/stlinit.cpp b/src/admesh/stlinit.cpp index 0cc6e50c7..a328baa75 100644 --- a/src/admesh/stlinit.cpp +++ b/src/admesh/stlinit.cpp @@ -221,7 +221,7 @@ static bool stl_read(stl_file *stl, FILE *fp, int first_facet, bool first) bool stl_open(stl_file *stl, const char *file) { - stl_reset(stl); + stl->clear(); FILE *fp = stl_open_count_facets(stl, file); if (fp == nullptr) return false; @@ -231,14 +231,6 @@ bool stl_open(stl_file *stl, const char *file) return result; } -void stl_reset(stl_file *stl) -{ - stl->facet_start.clear(); - stl->neighbors_start.clear(); - memset(&stl->stats, 0, sizeof(stl_stats)); - stl->stats.volume = -1.0; -} - #ifndef BOOST_LITTLE_ENDIAN extern void stl_internal_reverse_quads(char *buf, size_t cnt); #endif /* BOOST_LITTLE_ENDIAN */ diff --git a/src/admesh/util.cpp b/src/admesh/util.cpp index 70f4ffc27..029e44a28 100644 --- a/src/admesh/util.cpp +++ b/src/admesh/util.cpp @@ -115,12 +115,12 @@ static void calculate_normals(stl_file *stl) } } -static void rotate_point_2d(float *x, float *y, const double c, const double s) +static inline void rotate_point_2d(float &x, float &y, const double c, const double s) { - double xold = *x; - double yold = *y; - *x = float(c * xold - s * yold); - *y = float(s * xold + c * yold); + double xold = x; + double yold = y; + x = float(c * xold - s * yold); + y = float(s * xold + c * yold); } void stl_rotate_x(stl_file *stl, float angle) @@ -130,7 +130,7 @@ void stl_rotate_x(stl_file *stl, float angle) double s = sin(radian_angle); for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) for (int j = 0; j < 3; ++ j) - rotate_point_2d(&stl->facet_start[i].vertex[j](1), &stl->facet_start[i].vertex[j](2), c, s); + rotate_point_2d(stl->facet_start[i].vertex[j](1), stl->facet_start[i].vertex[j](2), c, s); stl_get_size(stl); calculate_normals(stl); } @@ -142,7 +142,7 @@ void stl_rotate_y(stl_file *stl, float angle) double s = sin(radian_angle); for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) for (int j = 0; j < 3; ++ j) - rotate_point_2d(&stl->facet_start[i].vertex[j](2), &stl->facet_start[i].vertex[j](0), c, s); + rotate_point_2d(stl->facet_start[i].vertex[j](2), stl->facet_start[i].vertex[j](0), c, s); stl_get_size(stl); calculate_normals(stl); } @@ -154,11 +154,38 @@ void stl_rotate_z(stl_file *stl, float angle) double s = sin(radian_angle); for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) for (int j = 0; j < 3; ++ j) - rotate_point_2d(&stl->facet_start[i].vertex[j](0), &stl->facet_start[i].vertex[j](1), c, s); + rotate_point_2d(stl->facet_start[i].vertex[j](0), stl->facet_start[i].vertex[j](1), c, s); stl_get_size(stl); calculate_normals(stl); } +void its_rotate_x(indexed_triangle_set &its, float angle) +{ + double radian_angle = (angle / 180.0) * M_PI; + double c = cos(radian_angle); + double s = sin(radian_angle); + for (stl_vertex &v : its.vertices) + rotate_point_2d(v(1), v(2), c, s); +} + +void its_rotate_y(indexed_triangle_set& its, float angle) +{ + double radian_angle = (angle / 180.0) * M_PI; + double c = cos(radian_angle); + double s = sin(radian_angle); + for (stl_vertex& v : its.vertices) + rotate_point_2d(v(2), v(0), c, s); +} + +void its_rotate_z(indexed_triangle_set& its, float angle) +{ + double radian_angle = (angle / 180.0) * M_PI; + double c = cos(radian_angle); + double s = sin(radian_angle); + for (stl_vertex& v : its.vertices) + rotate_point_2d(v(0), v(1), c, s); +} + void stl_get_size(stl_file *stl) { if (stl->stats.number_of_facets == 0) diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp index 11f45147c..56accfefa 100644 --- a/src/libslic3r/TriangleMesh.cpp +++ b/src/libslic3r/TriangleMesh.cpp @@ -42,10 +42,8 @@ namespace Slic3r { -TriangleMesh::TriangleMesh(const Pointf3s &points, const std::vector& facets) - : repaired(false) +TriangleMesh::TriangleMesh(const Pointf3s &points, const std::vector& facets) : repaired(false) { - stl_reset(&this->stl); stl_file &stl = this->stl; stl.stats.type = inmemory; @@ -72,14 +70,6 @@ TriangleMesh::TriangleMesh(const Pointf3s &points, const std::vector& f stl_get_size(&stl); } -TriangleMesh& TriangleMesh::operator=(const TriangleMesh &other) -{ - stl_reset(&this->stl); - this->stl = other.stl; - this->repaired = other.repaired; - return *this; -} - // #define SLIC3R_TRACE_REPAIR void TriangleMesh::repair(bool update_shared_vertices) @@ -254,13 +244,18 @@ void TriangleMesh::WriteOBJFile(const char* output_file) void TriangleMesh::scale(float factor) { stl_scale(&(this->stl), factor); - this->its.clear(); + for (stl_vertex& v : this->its.vertices) + v *= factor; } void TriangleMesh::scale(const Vec3d &versor) { stl_scale_versor(&this->stl, versor.cast()); - this->its.clear(); + for (stl_vertex& v : this->its.vertices) { + v.x() *= versor.x(); + v.y() *= versor.y(); + v.z() *= versor.z(); + } } void TriangleMesh::translate(float x, float y, float z) @@ -268,7 +263,9 @@ void TriangleMesh::translate(float x, float y, float z) if (x == 0.f && y == 0.f && z == 0.f) return; stl_translate_relative(&(this->stl), x, y, z); - this->its.clear(); + stl_vertex shift(x, y, z); + for (stl_vertex& v : this->its.vertices) + v += shift; } void TriangleMesh::translate(const Vec3f &displacement) @@ -285,13 +282,15 @@ void TriangleMesh::rotate(float angle, const Axis &axis) angle = Slic3r::Geometry::rad2deg(angle); if (axis == X) { - stl_rotate_x(&(this->stl), angle); + stl_rotate_x(&this->stl, angle); + its_rotate_x(this->its, angle); } else if (axis == Y) { - stl_rotate_y(&(this->stl), angle); + stl_rotate_y(&this->stl, angle); + its_rotate_y(this->its, angle); } else if (axis == Z) { - stl_rotate_z(&(this->stl), angle); + stl_rotate_z(&this->stl, angle); + its_rotate_z(this->its, angle); } - this->its.clear(); } void TriangleMesh::rotate(float angle, const Vec3d& axis) @@ -310,12 +309,17 @@ void TriangleMesh::mirror(const Axis &axis) { if (axis == X) { stl_mirror_yz(&this->stl); + for (stl_vertex &v : this->its.vertices) + v(0) *= -1.0; } else if (axis == Y) { stl_mirror_xz(&this->stl); + for (stl_vertex &v : this->its.vertices) + v(1) *= -1.0; } else if (axis == Z) { stl_mirror_xy(&this->stl); + for (stl_vertex &v : this->its.vertices) + v(2) *= -1.0; } - this->its.clear(); } void TriangleMesh::transform(const Transform3d& t, bool fix_left_handed) @@ -358,7 +362,8 @@ void TriangleMesh::rotate(double angle, Point* center) return; Vec2f c = center->cast(); this->translate(-c(0), -c(1), 0); - stl_rotate_z(&(this->stl), (float)angle); + stl_rotate_z(&this->stl, (float)angle); + its_rotate_z(this->its, (float)angle); this->translate(c(0), c(1), 0); } @@ -540,7 +545,7 @@ TriangleMesh TriangleMesh::convex_hull_3d() const { if (this->has_shared_vertices()) { #if REALfloat - qhull.runQhull("", 3, (int)this->its.vertices.size() / 3, (const realT*)(this->its.vertices.front().data()), "Qt"); + qhull.runQhull("", 3, (int)this->its.vertices.size(), (const realT*)(this->its.vertices.front().data()), "Qt"); #else src_vertices.reserve(this->its.vertices() * 3); // We will now fill the vector with input points for computation: diff --git a/src/libslic3r/TriangleMesh.hpp b/src/libslic3r/TriangleMesh.hpp index ffd9b7e62..54c6dc5d0 100644 --- a/src/libslic3r/TriangleMesh.hpp +++ b/src/libslic3r/TriangleMesh.hpp @@ -21,15 +21,13 @@ typedef std::vector TriangleMeshPtrs; class TriangleMesh { public: - TriangleMesh() : repaired(false) { stl_reset(&this->stl); } + TriangleMesh() : repaired(false) {} TriangleMesh(const Pointf3s &points, const std::vector &facets); - TriangleMesh(const TriangleMesh &other) : repaired(false) { stl_reset(&this->stl); *this = other; } - TriangleMesh(TriangleMesh &&other) : repaired(false) { stl_reset(&this->stl); this->swap(other); } - ~TriangleMesh() { clear(); } - TriangleMesh& operator=(const TriangleMesh &other); - TriangleMesh& operator=(TriangleMesh &&other) { this->swap(other); return *this; } - void clear() { stl_reset(&this->stl); this->repaired = false; } - void swap(TriangleMesh &other) { std::swap(this->stl, other.stl); std::swap(this->repaired, other.repaired); } + TriangleMesh(const TriangleMesh& rhs) : stl(rhs.stl), its(rhs.its), repaired(rhs.repaired) {} + TriangleMesh(TriangleMesh&& rhs) : stl(std::move(rhs.stl)), its(std::move(rhs.its)), repaired(rhs.repaired) {} + TriangleMesh& operator=(const TriangleMesh& rhs) { this->stl = rhs.stl; this->its = rhs.its; this->repaired = rhs.repaired; return *this; } + TriangleMesh& operator=(TriangleMesh &&rhs) { this->stl = std::move(rhs.stl); this->its = std::move(rhs.its); this->repaired = rhs.repaired; return *this; } + void clear() { this->stl.clear(); this->its.clear(); this->repaired = false; } bool ReadSTLFile(const char* input_file) { return stl_open(&stl, input_file); } bool write_ascii(const char* output_file) { return stl_write_ascii(&this->stl, output_file, ""); } bool write_binary(const char* output_file) { return stl_write_binary(&this->stl, output_file, ""); } diff --git a/src/slic3r/Config/Version.cpp b/src/slic3r/Config/Version.cpp index 2eda135d6..fe3adfd7f 100644 --- a/src/slic3r/Config/Version.cpp +++ b/src/slic3r/Config/Version.cpp @@ -198,6 +198,11 @@ size_t Index::load(const boost::filesystem::path &path) size_t idx_line = 0; Version ver; while (std::getline(ifs, line)) { +#ifndef _MSVCVER + // On a Unix system, getline does not remove the trailing carriage returns, if the index is shared over a Windows filesystem. Remove them manually. + while (! line.empty() && line.back() == '\r') + line.pop_back(); +#endif ++ idx_line; // Skip the initial white spaces. char *key = left_trim(const_cast(line.data())); diff --git a/src/slic3r/Utils/FixModelByWin10.cpp b/src/slic3r/Utils/FixModelByWin10.cpp index 1daeaff26..710f19090 100644 --- a/src/slic3r/Utils/FixModelByWin10.cpp +++ b/src/slic3r/Utils/FixModelByWin10.cpp @@ -389,10 +389,10 @@ void fix_model_by_win10_sdk_gui(ModelObject &model_object, int volume_idx) throw std::runtime_error(L("Repaired 3MF file does not contain any volume")); if (model.objects.front()->volumes.size() > 1) throw std::runtime_error(L("Repaired 3MF file contains more than one volume")); - meshes_repaired.emplace_back(std::move(model.objects.front()->volumes.front()->mesh)); + meshes_repaired.emplace_back(std::move(model.objects.front()->volumes.front()->mesh())); } for (size_t i = 0; i < volumes.size(); ++ i) { - volumes[i]->mesh = std::move(meshes_repaired[i]); + volumes[i]->set_mesh(std::move(meshes_repaired[i])); volumes[i]->set_new_unique_id(); } model_object.invalidate_bounding_box(); From dbfa4e6c838eda34fd059ca2f6ce71f2130c5180 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Thu, 13 Jun 2019 16:55:12 +0200 Subject: [PATCH 17/22] Fix of a smart pointer gymnastics from previous commit --- src/slic3r/GUI/3DScene.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index b9ac668e0..0414a1ed3 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -393,7 +393,7 @@ public: double get_sla_shift_z() const { return m_sla_shift_z; } void set_sla_shift_z(double z) { m_sla_shift_z = z; } - void set_convex_hull(std::shared_ptr &convex_hull) { m_convex_hull = convex_hull; } + void set_convex_hull(std::shared_ptr convex_hull) { m_convex_hull = std::move(convex_hull); } void set_convex_hull(const TriangleMesh &convex_hull) { m_convex_hull = std::make_shared(convex_hull); } void set_convex_hull(TriangleMesh &&convex_hull) { m_convex_hull = std::make_shared(std::move(convex_hull)); } From 9b7bb41db5b949285d28206a4ff44078bce37ecf Mon Sep 17 00:00:00 2001 From: bubnikv Date: Thu, 13 Jun 2019 17:24:37 +0200 Subject: [PATCH 18/22] ModelObject::add_volume(const ModelVolume &other) shall not re-center the volume as it will share meshes (object mesh, convex hull mesh) of the source, which may be in use by the background processing. --- src/libslic3r/Model.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 113b21503..8e879a3e6 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -691,8 +691,9 @@ ModelVolume* ModelObject::add_volume(const ModelVolume &other) { ModelVolume* v = new ModelVolume(this, other); this->volumes.push_back(v); - v->center_geometry_after_creation(); - this->invalidate_bounding_box(); + // The volume should already be centered at this point of time when copying shared pointers of the triangle mesh and convex hull. +// v->center_geometry_after_creation(); +// this->invalidate_bounding_box(); return v; } From d750d4f9255bfb388ba7b53d3a366ac16d84a7d0 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Thu, 13 Jun 2019 17:42:55 +0200 Subject: [PATCH 19/22] Re-enable high power graphics card on Windows. This is a regression issue against 1.41.3 --- src/PrusaSlicer.cpp | 3 +++ src/PrusaSlicer_app_msvc.cpp | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/src/PrusaSlicer.cpp b/src/PrusaSlicer.cpp index a3247b929..2becb8071 100644 --- a/src/PrusaSlicer.cpp +++ b/src/PrusaSlicer.cpp @@ -7,10 +7,13 @@ #include #include #ifdef SLIC3R_GUI + extern "C" + { // Let the NVIDIA and AMD know we want to use their graphics card // on a dual graphics card system. __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001; __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1; + } #endif /* SLIC3R_GUI */ #endif /* WIN32 */ diff --git a/src/PrusaSlicer_app_msvc.cpp b/src/PrusaSlicer_app_msvc.cpp index 5b01751b9..ee8cdf696 100644 --- a/src/PrusaSlicer_app_msvc.cpp +++ b/src/PrusaSlicer_app_msvc.cpp @@ -8,10 +8,14 @@ #include #ifdef SLIC3R_GUI +//Turn on high power graphics for NVidia cards on laptops (with built in graphics cards + Nvidia cards) +extern "C" +{ // Let the NVIDIA and AMD know we want to use their graphics card // on a dual graphics card system. __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001; __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1; +} #endif /* SLIC3R_GUI */ #include From 77954a13b9c34c74a46ac652ef58118b3b9c6977 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Fri, 14 Jun 2019 11:07:07 +0200 Subject: [PATCH 20/22] Fix of admesh import due to boost::pool::destroy taking O(n). Why on earth?! --- src/admesh/connect.cpp | 16 +++++----------- src/admesh/normals.cpp | 8 +++++--- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/src/admesh/connect.cpp b/src/admesh/connect.cpp index 5afb85d2c..e729c8922 100644 --- a/src/admesh/connect.cpp +++ b/src/admesh/connect.cpp @@ -130,18 +130,12 @@ struct HashTableEdges { this->heads[i] = this->tail; } ~HashTableEdges() { - for (int i = 0; i < this->M; ++ i) { - for (HashEdge *temp = this->heads[i]; this->heads[i] != this->tail; temp = this->heads[i]) { - this->heads[i] = this->heads[i]->next; - pool.destroy(temp); #ifndef NDEBUG + for (int i = 0; i < this->M; ++ i) + for (HashEdge *temp = this->heads[i]; this->heads[i] != this->tail; temp = this->heads[i]) ++ this->freed; -#endif /* NDEBUG */ - } - } - this->heads.clear(); - pool.destroy(this->tail); this->tail = nullptr; +#endif /* NDEBUG */ } void insert_edge_exact(stl_file *stl, const HashEdge &edge) @@ -197,7 +191,7 @@ private: match_neighbors(edge, *link); // Delete the matched edge from the list. this->heads[chain_number] = link->next; - pool.destroy(link); + // pool.destroy(link); #ifndef NDEBUG ++ this->freed; #endif /* NDEBUG */ @@ -224,7 +218,7 @@ private: // Delete the matched edge from the list. HashEdge *temp = link->next; link->next = link->next->next; - pool.destroy(temp); + // pool.destroy(temp); #ifndef NDEBUG ++ this->freed; #endif /* NDEBUG */ diff --git a/src/admesh/normals.cpp b/src/admesh/normals.cpp index 4d47573f6..16bb3daab 100644 --- a/src/admesh/normals.cpp +++ b/src/admesh/normals.cpp @@ -25,6 +25,8 @@ #include #include +// Boost pool: Don't use mutexes to synchronize memory allocation. +#define BOOST_POOL_NO_MT #include #include "stl.h" @@ -192,7 +194,7 @@ void stl_fix_normal_directions(stl_file *stl) } stl_normal *temp = head->next; // Delete this facet from the list. head->next = head->next->next; - pool.destroy(temp); + // pool.destroy(temp); } else { // If we ran out of facets to fix: All of the facets in this part have been fixed. ++ stl->stats.number_of_parts; if (checked >= stl->stats.number_of_facets) @@ -214,8 +216,8 @@ void stl_fix_normal_directions(stl_file *stl) } } - pool.destroy(head); - pool.destroy(tail); + // pool.destroy(head); + // pool.destroy(tail); } void stl_fix_normal_values(stl_file *stl) From f8c5570155e9a36a28c2147a95c1404d1c7a9f75 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Fri, 14 Jun 2019 15:47:40 +0200 Subject: [PATCH 21/22] Removed unnecessary copy / move constructors / assignment operators. --- src/PrusaSlicer_app_msvc.cpp | 1 - src/admesh/stl.h | 8 -------- src/libslic3r/TriangleMesh.hpp | 4 ---- 3 files changed, 13 deletions(-) diff --git a/src/PrusaSlicer_app_msvc.cpp b/src/PrusaSlicer_app_msvc.cpp index ee8cdf696..95dd4fb07 100644 --- a/src/PrusaSlicer_app_msvc.cpp +++ b/src/PrusaSlicer_app_msvc.cpp @@ -8,7 +8,6 @@ #include #ifdef SLIC3R_GUI -//Turn on high power graphics for NVidia cards on laptops (with built in graphics cards + Nvidia cards) extern "C" { // Let the NVIDIA and AMD know we want to use their graphics card diff --git a/src/admesh/stl.h b/src/admesh/stl.h index 87210b3c9..2ac6c7fd2 100644 --- a/src/admesh/stl.h +++ b/src/admesh/stl.h @@ -120,10 +120,6 @@ struct stl_stats { struct stl_file { stl_file() {} - stl_file(const stl_file &rhs) : facet_start(rhs.facet_start), neighbors_start(rhs.neighbors_start), stats(rhs.stats) {} - stl_file(stl_file &&rhs) : facet_start(std::move(rhs.facet_start)), neighbors_start(std::move(rhs.neighbors_start)), stats(rhs.stats) {} - stl_file& operator=(const stl_file &rhs) { this->facet_start = rhs.facet_start; this->neighbors_start = rhs.neighbors_start; this->stats = rhs.stats; return *this; } - stl_file& operator=(stl_file &&rhs) { this->facet_start = std::move(rhs.facet_start); this->neighbors_start = std::move(rhs.neighbors_start); this->stats = rhs.stats; return *this; } void clear() { this->facet_start.clear(); @@ -140,10 +136,6 @@ struct stl_file { struct indexed_triangle_set { indexed_triangle_set() {} - indexed_triangle_set(const indexed_triangle_set &rhs) : indices(rhs.indices), vertices(rhs.vertices) {} - indexed_triangle_set(indexed_triangle_set &&rhs) : indices(std::move(rhs.indices)), vertices(std::move(rhs.vertices)) {} - indexed_triangle_set& operator=(const indexed_triangle_set &rhs) { this->indices = rhs.indices; this->vertices = rhs.vertices; return *this; } - indexed_triangle_set& operator=(indexed_triangle_set &&rhs) { this->indices = std::move(rhs.indices); this->vertices = std::move(rhs.vertices); return *this; } void clear() { indices.clear(); vertices.clear(); } diff --git a/src/libslic3r/TriangleMesh.hpp b/src/libslic3r/TriangleMesh.hpp index 54c6dc5d0..054a98935 100644 --- a/src/libslic3r/TriangleMesh.hpp +++ b/src/libslic3r/TriangleMesh.hpp @@ -23,10 +23,6 @@ class TriangleMesh public: TriangleMesh() : repaired(false) {} TriangleMesh(const Pointf3s &points, const std::vector &facets); - TriangleMesh(const TriangleMesh& rhs) : stl(rhs.stl), its(rhs.its), repaired(rhs.repaired) {} - TriangleMesh(TriangleMesh&& rhs) : stl(std::move(rhs.stl)), its(std::move(rhs.its)), repaired(rhs.repaired) {} - TriangleMesh& operator=(const TriangleMesh& rhs) { this->stl = rhs.stl; this->its = rhs.its; this->repaired = rhs.repaired; return *this; } - TriangleMesh& operator=(TriangleMesh &&rhs) { this->stl = std::move(rhs.stl); this->its = std::move(rhs.its); this->repaired = rhs.repaired; return *this; } void clear() { this->stl.clear(); this->its.clear(); this->repaired = false; } bool ReadSTLFile(const char* input_file) { return stl_open(&stl, input_file); } bool write_ascii(const char* output_file) { return stl_write_ascii(&this->stl, output_file, ""); } From 630883ad0f4d7f602e06773a8f333e65c1385e77 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Tue, 18 Jun 2019 08:54:28 +0200 Subject: [PATCH 22/22] Extended the error message when the G-code cannot be copied to the SD card --- src/slic3r/GUI/BackgroundSlicingProcess.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.cpp b/src/slic3r/GUI/BackgroundSlicingProcess.cpp index 94fb6481b..b77a272e2 100644 --- a/src/slic3r/GUI/BackgroundSlicingProcess.cpp +++ b/src/slic3r/GUI/BackgroundSlicingProcess.cpp @@ -89,7 +89,7 @@ void BackgroundSlicingProcess::process_fff() // Perform the final post-processing of the export path by applying the print statistics over the file name. std::string export_path = m_fff_print->print_statistics().finalize_output_path(m_export_path); if (copy_file(m_temp_output_path, export_path) != 0) - throw std::runtime_error(_utf8(L("Copying of the temporary G-code to the output G-code failed"))); + throw std::runtime_error(_utf8(L("Copying of the temporary G-code to the output G-code failed. Maybe the SD card is write locked?"))); m_print->set_status(95, _utf8(L("Running post-processing scripts"))); run_post_process_scripts(export_path, m_fff_print->config()); m_print->set_status(100, (boost::format(_utf8(L("G-code file exported to %1%"))) % export_path).str());