From b9f4880b23ab4e6f5d577db1ee643ca3e218f17d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Tue, 23 Sep 2014 14:34:37 +0200 Subject: [PATCH] Updated to admesh 0.98.1 --- xs/src/admesh/connect.c | 1330 +++++++++++++---------------- xs/src/admesh/normals.c | 391 ++++----- xs/src/admesh/shared.c | 371 ++++---- xs/src/admesh/stl.h | 93 +- xs/src/admesh/stl_io.c | 607 ++++++------- xs/src/admesh/stlinit.c | 471 +++++----- xs/src/admesh/util.c | 646 ++++++++------ xs/src/libslic3r/TriangleMesh.cpp | 4 + 8 files changed, 1940 insertions(+), 1973 deletions(-) diff --git a/xs/src/admesh/connect.c b/xs/src/admesh/connect.c index d38a44a2b..dbd889689 100644 --- a/xs/src/admesh/connect.c +++ b/xs/src/admesh/connect.c @@ -1,21 +1,23 @@ /* ADMesh -- process triangulated solid meshes - * Copyright (C) 1995 Anthony D. Martin + * Copyright (C) 1995, 1996 Anthony D. Martin + * Copyright (C) 2013, 2014 several contributors, see AUTHORS * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * Questions, comments, suggestions, etc to + * Questions, comments, suggestions, etc to + * https://github.com/admesh/admesh/issues */ #include @@ -26,50 +28,51 @@ #include "stl.h" -static void stl_match_neighbors_exact(stl_file *stl, - stl_hash_edge *edge_a, stl_hash_edge *edge_b); +static void stl_match_neighbors_exact(stl_file *stl, + stl_hash_edge *edge_a, stl_hash_edge *edge_b); static void stl_match_neighbors_nearby(stl_file *stl, - stl_hash_edge *edge_a, stl_hash_edge *edge_b); + 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); + 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, - stl_vertex *a, stl_vertex *b); + stl_vertex *a, stl_vertex *b); static int stl_load_edge_nearby(stl_file *stl, stl_hash_edge *edge, - stl_vertex *a, stl_vertex *b, float tolerance); + 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)); + void (*match_neighbors)(stl_file *stl, + stl_hash_edge *edge_a, stl_hash_edge *edge_b)); static int stl_get_hash_for_edge(int M, stl_hash_edge *edge); 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); + 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); + 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); + int facet_num, int normal_fix_flag); static void stl_update_connects_remove_1(stl_file *stl, int facet_num); void -stl_check_facets_exact(stl_file *stl) -{ -/* 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. - */ +stl_check_facets_exact(stl_file *stl) { + /* 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. + */ stl_hash_edge edge; stl_facet facet; int i; int j; + if (stl->error) return; + stl->stats.connected_edges = 0; stl->stats.connected_facets_1_edge = 0; stl->stats.connected_facets_2_edge = 0; @@ -77,48 +80,45 @@ stl_check_facets_exact(stl_file *stl) stl_initialize_facet_check_exact(stl); - for(i = 0; i < stl->stats.number_of_facets; i++) - { - facet = stl->facet_start[i]; + for(i = 0; i < stl->stats.number_of_facets; i++) { + facet = stl->facet_start[i]; - //If any two of the three vertices are found to be exactally the same, call them degenerate and remove the facet. - if( !memcmp(&facet.vertex[0], &facet.vertex[1], - sizeof(stl_vertex)) - || !memcmp(&facet.vertex[1], &facet.vertex[2], - sizeof(stl_vertex)) - || !memcmp(&facet.vertex[0], &facet.vertex[2], - sizeof(stl_vertex))) - { - stl->stats.degenerate_facets += 1; - stl_remove_facet(stl, i); - i--; - continue; + /* If any two of the three vertices are found to be exactally the same, call them degenerate and remove the facet. */ + if( !memcmp(&facet.vertex[0], &facet.vertex[1], + sizeof(stl_vertex)) + || !memcmp(&facet.vertex[1], &facet.vertex[2], + sizeof(stl_vertex)) + || !memcmp(&facet.vertex[0], &facet.vertex[2], + sizeof(stl_vertex))) { + stl->stats.degenerate_facets += 1; + stl_remove_facet(stl, i); + i--; + continue; - } - for(j = 0; j < 3; j++) - { - 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_match_neighbors_exact); - } } + for(j = 0; j < 3; j++) { + 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_match_neighbors_exact); + } + } stl_free_edges(stl); } static void stl_load_edge_exact(stl_file *stl, stl_hash_edge *edge, - stl_vertex *a, stl_vertex *b) -{ + stl_vertex *a, stl_vertex *b) { float diff_x; float diff_y; float diff_z; float max_diff; - - + + if (stl->error) return; + diff_x = ABS(a->x - b->x); diff_y = ABS(a->y - b->y); diff_z = ABS(a->z - b->z); @@ -126,55 +126,42 @@ stl_load_edge_exact(stl_file *stl, stl_hash_edge *edge, max_diff = STL_MAX(diff_z, max_diff); stl->stats.shortest_edge = STL_MIN(max_diff, stl->stats.shortest_edge); - if(diff_x == max_diff) - { - if(a->x > b->x) - { - memcpy(&edge->key[0], a, sizeof(stl_vertex)); - memcpy(&edge->key[3], b, sizeof(stl_vertex)); - } - else - { - memcpy(&edge->key[0], b, sizeof(stl_vertex)); - memcpy(&edge->key[3], a, sizeof(stl_vertex)); - edge->which_edge += 3; /* this edge is loaded backwards */ - } + if(diff_x == max_diff) { + if(a->x > b->x) { + memcpy(&edge->key[0], a, sizeof(stl_vertex)); + memcpy(&edge->key[3], b, sizeof(stl_vertex)); + } else { + memcpy(&edge->key[0], b, sizeof(stl_vertex)); + memcpy(&edge->key[3], a, sizeof(stl_vertex)); + edge->which_edge += 3; /* this edge is loaded backwards */ } - else if(diff_y == max_diff) - { - if(a->y > b->y) - { - memcpy(&edge->key[0], a, sizeof(stl_vertex)); - memcpy(&edge->key[3], b, sizeof(stl_vertex)); - } - else - { - memcpy(&edge->key[0], b, sizeof(stl_vertex)); - memcpy(&edge->key[3], a, sizeof(stl_vertex)); - edge->which_edge += 3; /* this edge is loaded backwards */ - } + } else if(diff_y == max_diff) { + if(a->y > b->y) { + memcpy(&edge->key[0], a, sizeof(stl_vertex)); + memcpy(&edge->key[3], b, sizeof(stl_vertex)); + } else { + memcpy(&edge->key[0], b, sizeof(stl_vertex)); + memcpy(&edge->key[3], a, sizeof(stl_vertex)); + edge->which_edge += 3; /* this edge is loaded backwards */ } - else - { - if(a->z > b->z) - { - memcpy(&edge->key[0], a, sizeof(stl_vertex)); - memcpy(&edge->key[3], b, sizeof(stl_vertex)); - } - else - { - memcpy(&edge->key[0], b, sizeof(stl_vertex)); - memcpy(&edge->key[3], a, sizeof(stl_vertex)); - edge->which_edge += 3; /* this edge is loaded backwards */ - } + } else { + if(a->z > b->z) { + memcpy(&edge->key[0], a, sizeof(stl_vertex)); + memcpy(&edge->key[3], b, sizeof(stl_vertex)); + } else { + memcpy(&edge->key[0], b, sizeof(stl_vertex)); + memcpy(&edge->key[3], a, sizeof(stl_vertex)); + edge->which_edge += 3; /* this edge is loaded backwards */ } + } } static void -stl_initialize_facet_check_exact(stl_file *stl) -{ +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; @@ -182,13 +169,12 @@ stl_initialize_facet_check_exact(stl_file *stl) stl->M = 81397; - 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; - } + 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"); @@ -198,152 +184,131 @@ stl_initialize_facet_check_exact(stl_file *stl) stl->tail->next = stl->tail; - for(i = 0; i < stl->M; i++) - { - stl->heads[i] = 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)) -{ + void (*match_neighbors)(stl_file *stl, + stl_hash_edge *edge_a, stl_hash_edge *edge_b)) { stl_hash_edge *link; stl_hash_edge *new_edge; stl_hash_edge *temp; int chain_number; + if (stl->error) return; + chain_number = stl_get_hash_for_edge(stl->M, &edge); link = stl->heads[chain_number]; - 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)); - 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; - free(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 = (stl_hash_edge*)malloc(sizeof(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; - free(temp); - stl->stats.freed++; - return; - } - else - { - /* This is not a match. Go to the next link */ - link = link->next; - stl->stats.collisions++; - } - } + 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)); + 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; + free(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 = (stl_hash_edge*)malloc(sizeof(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; + free(temp); + stl->stats.freed++; + return; + } else { + /* This is not a match. Go to the next link */ + link = link->next; + stl->stats.collisions++; + } } + } } static int -stl_get_hash_for_edge(int M, stl_hash_edge *edge) -{ +stl_get_hash_for_edge(int M, stl_hash_edge *edge) { return ((edge->key[0] / 23 + edge->key[1] / 19 + edge->key[2] / 17 - + edge->key[3] /13 + edge->key[4] / 11 + edge->key[5] / 7 ) % M); + + edge->key[3] /13 + edge->key[4] / 11 + edge->key[5] / 7 ) % M); } static int -stl_compare_function(stl_hash_edge *edge_a, stl_hash_edge *edge_b) -{ - if(edge_a->facet_number == edge_b->facet_number) - { - return 1; /* Don't match edges of the same facet */ - } - else - { - return memcmp(edge_a, edge_b, SIZEOF_EDGE_SORT); - } +stl_compare_function(stl_hash_edge *edge_a, stl_hash_edge *edge_b) { + if(edge_a->facet_number == edge_b->facet_number) { + return 1; /* Don't match edges of the same facet */ + } else { + return memcmp(edge_a, edge_b, SIZEOF_EDGE_SORT); + } } void -stl_check_facets_nearby(stl_file *stl, float tolerance) -{ +stl_check_facets_nearby(stl_file *stl, float tolerance) { stl_hash_edge edge[3]; stl_facet facet; int i; int j; + 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->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(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) - { - edge[j].facet_number = i; - edge[j].which_edge = j; - if(stl_load_edge_nearby(stl, &edge[j], &facet.vertex[j], - &facet.vertex[(j + 1) % 3], - tolerance)) - { - /* only insert edges that have different keys */ - insert_hash_edge(stl, edge[j], stl_match_neighbors_nearby); - } - } - } + for(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) { + edge[j].facet_number = i; + edge[j].which_edge = j; + if(stl_load_edge_nearby(stl, &edge[j], &facet.vertex[j], + &facet.vertex[(j + 1) % 3], + tolerance)) { + /* only insert edges that have different keys */ + insert_hash_edge(stl, edge[j], 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) -{ + stl_vertex *a, stl_vertex *b, float tolerance) { float diff_x; float diff_y; float diff_z; @@ -364,88 +329,72 @@ stl_load_edge_nearby(stl_file *stl, stl_hash_edge *edge, vertex2[0] = (unsigned)((b->x - stl->stats.min.x) / tolerance); vertex2[1] = (unsigned)((b->y - stl->stats.min.y) / tolerance); vertex2[2] = (unsigned)((b->z - stl->stats.min.z) / tolerance); - - if( (vertex1[0] == vertex2[0]) - && (vertex1[1] == vertex2[1]) - && (vertex1[2] == vertex2[2])) - { - /* Both vertices hash to the same value */ - return 0; - } - if(diff_x == max_diff) - { - if(a->x > b->x) - { - memcpy(&edge->key[0], vertex1, sizeof(stl_vertex)); - memcpy(&edge->key[3], vertex2, sizeof(stl_vertex)); - } - else - { - memcpy(&edge->key[0], vertex2, sizeof(stl_vertex)); - memcpy(&edge->key[3], vertex1, sizeof(stl_vertex)); - edge->which_edge += 3; /* this edge is loaded backwards */ - } + if( (vertex1[0] == vertex2[0]) + && (vertex1[1] == vertex2[1]) + && (vertex1[2] == vertex2[2])) { + /* Both vertices hash to the same value */ + return 0; + } + + if(diff_x == max_diff) { + if(a->x > b->x) { + memcpy(&edge->key[0], vertex1, sizeof(stl_vertex)); + memcpy(&edge->key[3], vertex2, sizeof(stl_vertex)); + } else { + memcpy(&edge->key[0], vertex2, sizeof(stl_vertex)); + memcpy(&edge->key[3], vertex1, sizeof(stl_vertex)); + edge->which_edge += 3; /* this edge is loaded backwards */ } - else if(diff_y == max_diff) - { - if(a->y > b->y) - { - memcpy(&edge->key[0], vertex1, sizeof(stl_vertex)); - memcpy(&edge->key[3], vertex2, sizeof(stl_vertex)); - } - else - { - memcpy(&edge->key[0], vertex2, sizeof(stl_vertex)); - memcpy(&edge->key[3], vertex1, sizeof(stl_vertex)); - edge->which_edge += 3; /* this edge is loaded backwards */ - } + } else if(diff_y == max_diff) { + if(a->y > b->y) { + memcpy(&edge->key[0], vertex1, sizeof(stl_vertex)); + memcpy(&edge->key[3], vertex2, sizeof(stl_vertex)); + } else { + memcpy(&edge->key[0], vertex2, sizeof(stl_vertex)); + memcpy(&edge->key[3], vertex1, sizeof(stl_vertex)); + edge->which_edge += 3; /* this edge is loaded backwards */ } - else - { - if(a->z > b->z) - { - memcpy(&edge->key[0], vertex1, sizeof(stl_vertex)); - memcpy(&edge->key[3], vertex2, sizeof(stl_vertex)); - } - else - { - memcpy(&edge->key[0], vertex2, sizeof(stl_vertex)); - memcpy(&edge->key[3], vertex1, sizeof(stl_vertex)); - edge->which_edge += 3; /* this edge is loaded backwards */ - } + } else { + if(a->z > b->z) { + memcpy(&edge->key[0], vertex1, sizeof(stl_vertex)); + memcpy(&edge->key[3], vertex2, sizeof(stl_vertex)); + } else { + memcpy(&edge->key[0], vertex2, sizeof(stl_vertex)); + memcpy(&edge->key[3], vertex1, sizeof(stl_vertex)); + edge->which_edge += 3; /* this edge is loaded backwards */ } + } return 1; } static void -stl_free_edges(stl_file *stl) -{ +stl_free_edges(stl_file *stl) { int i; stl_hash_edge *temp; - - if(stl->stats.malloced != stl->stats.freed) - { - for(i = 0; i < stl->M; i++) - { - for(temp = stl->heads[i]; stl->heads[i] != stl->tail; - temp = stl->heads[i]) - { - stl->heads[i] = stl->heads[i]->next; - free(temp); - stl->stats.freed++; - } - } + + if (stl->error) return; + + if(stl->stats.malloced != stl->stats.freed) { + for(i = 0; i < stl->M; i++) { + for(temp = stl->heads[i]; stl->heads[i] != stl->tail; + temp = stl->heads[i]) { + stl->heads[i] = stl->heads[i]->next; + free(temp); + stl->stats.freed++; + } } + } free(stl->heads); free(stl->tail); } - + static void -stl_initialize_facet_check_nearby(stl_file *stl) -{ +stl_initialize_facet_check_nearby(stl_file *stl) { int i; + if (stl->error) return; + stl->stats.malloced = 0; stl->stats.freed = 0; stl->stats.collisions = 0; @@ -464,48 +413,47 @@ stl_initialize_facet_check_nearby(stl_file *stl) stl->tail->next = stl->tail; - for(i = 0; i < stl->M; i++) - { - stl->heads[i] = stl->tail; - } + for(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) -{ + 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 */ - + 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 */ - + 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; - } - + || ((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 */ @@ -517,43 +465,32 @@ stl_record_neighbors(stl_file *stl, 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; - } + 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_exact(stl_file *stl, - stl_hash_edge *edge_a, stl_hash_edge *edge_b) -{ + stl_hash_edge *edge_a, stl_hash_edge *edge_b) { + if (stl->error) return; stl_record_neighbors(stl, edge_a, edge_b); } static void stl_match_neighbors_nearby(stl_file *stl, - stl_hash_edge *edge_a, stl_hash_edge *edge_b) -{ + stl_hash_edge *edge_a, stl_hash_edge *edge_b) { int facet1; int facet2; int vertex1; @@ -563,264 +500,213 @@ stl_match_neighbors_nearby(stl_file *stl, 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); + &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(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); + 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) -{ + 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; - } - } - 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");*/ - printf("Failed to repair mesh (back to the first facet changing vertices: probably a mobius part)\n"); - return; - exit(1); - break; - } + 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->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) -{ + 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; - } + 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(!memcmp(&stl->facet_start[edge_a->facet_number].vertex[v1a], - &stl->facet_start[edge_b->facet_number].vertex[v1b], - sizeof(stl_vertex))) - { - /* 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]; - } + &stl->facet_start[edge_b->facet_number].vertex[v1b], + sizeof(stl_vertex))) { + /* 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(!memcmp(&stl->facet_start[edge_a->facet_number].vertex[v2a], - &stl->facet_start[edge_b->facet_number].vertex[v2b], - sizeof(stl_vertex))) - { - /* 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]; - } + &stl->facet_start[edge_b->facet_number].vertex[v2b], + sizeof(stl_vertex))) { + /* 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]; } + } } static void -stl_remove_facet(stl_file *stl, int facet_number) -{ +stl_remove_facet(stl_file *stl, int facet_number) { int neighbor[3]; int vnot[3]; int i; int j; + if (stl->error) 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; - } - - stl->facet_start[facet_number] = + 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; + } + + 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; - - 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]; - } - - 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("\ + + 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]; + } + + 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); - exit(1); - } - stl->neighbors_start[neighbor[i]].neighbor[(vnot[i] + 1)% 3] - = facet_number; - } + 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; } + } } void -stl_remove_unconnected_facets(stl_file *stl) -{ +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 */ @@ -828,42 +714,38 @@ stl_remove_unconnected_facets(stl_file *stl) /* stl_check_facets_nearby(). */ int i; - - /* remove degenerate facets */ - for(i = 0; i < stl->stats.number_of_facets; i++) - { - if( !memcmp(&stl->facet_start[i].vertex[0], - &stl->facet_start[i].vertex[1], sizeof(stl_vertex)) - || !memcmp(&stl->facet_start[i].vertex[1], - &stl->facet_start[i].vertex[2], sizeof(stl_vertex)) - || !memcmp(&stl->facet_start[i].vertex[0], - &stl->facet_start[i].vertex[2], sizeof(stl_vertex))) - { - stl_remove_degenerate(stl, i); - i--; - } - } - if(stl->stats.connected_facets_1_edge < stl->stats.number_of_facets) - { - /* remove completely unconnected facets */ - for(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--; - } - } + if (stl->error) return; + + /* remove degenerate facets */ + for(i = 0; i < stl->stats.number_of_facets; i++) { + if( !memcmp(&stl->facet_start[i].vertex[0], + &stl->facet_start[i].vertex[1], sizeof(stl_vertex)) + || !memcmp(&stl->facet_start[i].vertex[1], + &stl->facet_start[i].vertex[2], sizeof(stl_vertex)) + || !memcmp(&stl->facet_start[i].vertex[0], + &stl->facet_start[i].vertex[2], sizeof(stl_vertex))) { + stl_remove_degenerate(stl, i); + i--; } + } + + if(stl->stats.connected_facets_1_edge < stl->stats.number_of_facets) { + /* remove completely unconnected facets */ + for(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) -{ +stl_remove_degenerate(stl_file *stl, int facet) { int edge1; int edge2; int edge3; @@ -874,58 +756,50 @@ stl_remove_degenerate(stl_file *stl, int facet) int vnot2; int vnot3; - if( !memcmp(&stl->facet_start[facet].vertex[0], - &stl->facet_start[facet].vertex[1], sizeof(stl_vertex)) - && !memcmp(&stl->facet_start[facet].vertex[1], - &stl->facet_start[facet].vertex[2], sizeof(stl_vertex))) - { - /* 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"); + if (stl->error) return; - stl_remove_facet(stl, facet); - return; - } - - if(!memcmp(&stl->facet_start[facet].vertex[0], - &stl->facet_start[facet].vertex[1], sizeof(stl_vertex))) - { - edge1 = 1; - edge2 = 2; - edge3 = 0; - } - else if(!memcmp(&stl->facet_start[facet].vertex[1], - &stl->facet_start[facet].vertex[2], sizeof(stl_vertex))) - { - edge1 = 0; - edge2 = 2; - edge3 = 1; - } - else if(!memcmp(&stl->facet_start[facet].vertex[2], - &stl->facet_start[facet].vertex[0], sizeof(stl_vertex))) - { - edge1 = 0; - edge2 = 1; - edge3 = 2; - } - else - { - /* No degenerate. Function shouldn't have been called. */ - return; - } + if( !memcmp(&stl->facet_start[facet].vertex[0], + &stl->facet_start[facet].vertex[1], sizeof(stl_vertex)) + && !memcmp(&stl->facet_start[facet].vertex[1], + &stl->facet_start[facet].vertex[2], sizeof(stl_vertex))) { + /* 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(!memcmp(&stl->facet_start[facet].vertex[0], + &stl->facet_start[facet].vertex[1], sizeof(stl_vertex))) { + edge1 = 1; + edge2 = 2; + edge3 = 0; + } else if(!memcmp(&stl->facet_start[facet].vertex[1], + &stl->facet_start[facet].vertex[2], sizeof(stl_vertex))) { + edge1 = 0; + edge2 = 2; + edge3 = 1; + } else if(!memcmp(&stl->facet_start[facet].vertex[2], + &stl->facet_start[facet].vertex[0], sizeof(stl_vertex))) { + 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); - } - - + 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]; @@ -935,42 +809,35 @@ stl_remove_degenerate(stl_file *stl, int facet) stl->neighbors_start[neighbor2].neighbor[(vnot2 + 1) % 3] = neighbor1; stl->neighbors_start[neighbor1].which_vertex_not[(vnot1 + 1) % 3] = vnot2; stl->neighbors_start[neighbor2].which_vertex_not[(vnot2 + 1) % 3] = vnot1; - + stl_remove_facet(stl, facet); - - if(neighbor3 != -1) - { - stl_update_connects_remove_1(stl, neighbor3); - stl->neighbors_start[neighbor3].neighbor[(vnot3 + 1) % 3] = -1; - } + + if(neighbor3 != -1) { + 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) -{ +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(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; + } } void -stl_fill_holes(stl_file *stl) -{ +stl_fill_holes(stl_file *stl) { stl_facet facet; stl_facet new_facet; int neighbors_initial[3]; @@ -986,140 +853,117 @@ stl_fill_holes(stl_file *stl) int j; int k; + if (stl->error) return; + /* Insert all unconnected edges into hash list */ stl_initialize_facet_check_nearby(stl); - for(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]); - - insert_hash_edge(stl, edge, stl_match_neighbors_exact); - } + for(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]); + + insert_hash_edge(stl, edge, stl_match_neighbors_exact); } + } - for(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; - - 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; - } + for(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; - 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; - } - } - 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_match_neighbors_exact); - } - 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("\ + 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; + } + + 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; + } + } + 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_match_neighbors_exact); + } + 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"); */ - printf("Failed to repair mesh (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; - exit(1); - break; - } - } - } + } + } } + } } void -stl_add_facet(stl_file *stl, stl_facet *new_facet) -{ +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) - { - 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; - } + if(stl->stats.facets_malloced < 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.x = 0.0; stl->facet_start[stl->stats.number_of_facets].normal.y = 0.0; stl->facet_start[stl->stats.number_of_facets].normal.z = 0.0; - + 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; diff --git a/xs/src/admesh/normals.c b/xs/src/admesh/normals.c index f827a712c..2832899fa 100644 --- a/xs/src/admesh/normals.c +++ b/xs/src/admesh/normals.c @@ -1,21 +1,23 @@ /* ADMesh -- process triangulated solid meshes - * Copyright (C) 1995 Anthony D. Martin + * Copyright (C) 1995, 1996 Anthony D. Martin + * Copyright (C) 2013, 2014 several contributors, see AUTHORS * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * Questions, comments, suggestions, etc to + * Questions, comments, suggestions, etc to + * https://github.com/admesh/admesh/issues */ #include @@ -26,20 +28,18 @@ #include "stl.h" static void stl_reverse_facet(stl_file *stl, int facet_num); -/* static float stl_calculate_area(stl_facet *facet); */ static void stl_reverse_vector(float v[]); 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_reverse_facet(stl_file *stl, int facet_num) { stl_vertex tmp_vertex; /* int tmp_neighbor;*/ int neighbor[3]; int vnot[3]; stl->stats.facets_reversed += 1; - + 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]; @@ -49,23 +49,23 @@ stl_reverse_facet(stl_file *stl, int facet_num) /* 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[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; + 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; + 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; + 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]; @@ -85,8 +85,7 @@ stl_reverse_facet(stl_file *stl, int facet_num) } void -stl_fix_normal_directions(stl_file *stl) -{ +stl_fix_normal_directions(stl_file *stl) { char *norm_sw; /* int edge_num;*/ /* int vnot;*/ @@ -95,9 +94,7 @@ stl_fix_normal_directions(stl_file *stl) /* int next_facet;*/ int i; int j; - int checked_before = 0; - struct stl_normal - { + struct stl_normal { int facet_num; struct stl_normal *next; }; @@ -105,12 +102,13 @@ stl_fix_normal_directions(stl_file *stl) struct stl_normal *tail; struct stl_normal *newn; struct stl_normal *temp; - - + + if (stl->error) return; + /* Initialize linked list. */ - head = (stl_normal*)malloc(sizeof(struct stl_normal)); + head = (struct stl_normal*)malloc(sizeof(struct stl_normal)); if(head == NULL) perror("stl_fix_normal_directions"); - tail = (stl_normal*)malloc(sizeof(struct stl_normal)); + tail = (struct stl_normal*)malloc(sizeof(struct stl_normal)); if(tail == NULL) perror("stl_fix_normal_directions"); head->next = tail; tail->next = tail; @@ -118,113 +116,90 @@ stl_fix_normal_directions(stl_file *stl) /* 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"); - + 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 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) stl_reverse_facet(stl, 0); - //Say that we've fixed this facet: + /* Say that we've fixed this facet: */ norm_sw[facet_num] = 1; - /* edge_num = 0; - vnot = stl->neighbors_start[0].which_vertex_not[0]; - */ 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) - { - stl_reverse_facet - (stl, 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 = (stl_normal*)malloc(sizeof(struct stl_normal)); - if(newn == NULL) perror("stl_fix_normal_directions"); - newn->facet_num = stl->neighbors_start[facet_num].neighbor[j]; - newn->next = head->next; - head->next = newn; - } - } - } - /* 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; - free(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; - /* There are (checked-checked_before) facets */ - /* in part stl->stats.number_of_parts */ - checked_before = checked; - 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) - { - stl_reverse_facet(stl, i); - } - - norm_sw[facet_num] = 1; - checked++; - break; - } - } - } - } + 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) { + stl_reverse_facet + (stl, 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 = (struct stl_normal*)malloc(sizeof(struct stl_normal)); + if(newn == NULL) perror("stl_fix_normal_directions"); + newn->facet_num = stl->neighbors_start[facet_num].neighbor[j]; + newn->next = head->next; + head->next = newn; + } + } } + /* 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; + free(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) { + stl_reverse_facet(stl, i); + } + + norm_sw[facet_num] = 1; + checked++; + break; + } + } + } + } + } free(head); free(tail); free(norm_sw); } int -stl_check_normal_vector(stl_file *stl, int facet_num, int normal_fix_flag) -{ +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 */ /* Returns 4 if the status is unknown. */ - + float normal[3]; float test_norm[3]; stl_facet *facet; @@ -233,66 +208,59 @@ stl_check_normal_vector(stl_file *stl, int facet_num, int normal_fix_flag) stl_calculate_normal(normal, facet); stl_normalize_vector(normal); - + if( (ABS(normal[0] - facet->normal.x) < 0.001) - && (ABS(normal[1] - facet->normal.y) < 0.001) - && (ABS(normal[2] - facet->normal.z) < 0.001)) - { - /* It is not really necessary to change the values here */ - /* but just for consistency, I will. */ - facet->normal.x = normal[0]; - facet->normal.y = normal[1]; - facet->normal.z = normal[2]; - return 0; - } - + && (ABS(normal[1] - facet->normal.y) < 0.001) + && (ABS(normal[2] - facet->normal.z) < 0.001)) { + /* It is not really necessary to change the values here */ + /* but just for consistency, I will. */ + facet->normal.x = normal[0]; + facet->normal.y = normal[1]; + facet->normal.z = normal[2]; + return 0; + } + test_norm[0] = facet->normal.x; test_norm[1] = facet->normal.y; test_norm[2] = facet->normal.z; - + stl_normalize_vector(test_norm); if( (ABS(normal[0] - test_norm[0]) < 0.001) - && (ABS(normal[1] - test_norm[1]) < 0.001) - && (ABS(normal[2] - test_norm[2]) < 0.001)) - { - if(normal_fix_flag) - { - facet->normal.x = normal[0]; - facet->normal.y = normal[1]; - facet->normal.z = normal[2]; - stl->stats.normals_fixed += 1; - } - return 1; - } - - stl_reverse_vector(test_norm); - if( (ABS(normal[0] - test_norm[0]) < 0.001) - && (ABS(normal[1] - test_norm[1]) < 0.001) - && (ABS(normal[2] - test_norm[2]) < 0.001)) - { - /* Facet is backwards. */ - if(normal_fix_flag) - { - facet->normal.x = normal[0]; - facet->normal.y = normal[1]; - facet->normal.z = normal[2]; - stl->stats.normals_fixed += 1; - } - return 2; - } - if(normal_fix_flag) - { + && (ABS(normal[1] - test_norm[1]) < 0.001) + && (ABS(normal[2] - test_norm[2]) < 0.001)) { + if(normal_fix_flag) { facet->normal.x = normal[0]; facet->normal.y = normal[1]; facet->normal.z = normal[2]; stl->stats.normals_fixed += 1; - } + } + return 1; + } + + stl_reverse_vector(test_norm); + if( (ABS(normal[0] - test_norm[0]) < 0.001) + && (ABS(normal[1] - test_norm[1]) < 0.001) + && (ABS(normal[2] - test_norm[2]) < 0.001)) { + /* Facet is backwards. */ + if(normal_fix_flag) { + facet->normal.x = normal[0]; + facet->normal.y = normal[1]; + facet->normal.z = normal[2]; + stl->stats.normals_fixed += 1; + } + return 2; + } + if(normal_fix_flag) { + facet->normal.x = normal[0]; + facet->normal.y = normal[1]; + facet->normal.z = normal[2]; + stl->stats.normals_fixed += 1; + } return 4; } static void -stl_reverse_vector(float v[]) -{ +stl_reverse_vector(float v[]) { v[0] *= -1; v[1] *= -1; v[2] *= -1; @@ -300,8 +268,7 @@ stl_reverse_vector(float v[]) void -stl_calculate_normal(float normal[], stl_facet *facet) -{ +stl_calculate_normal(float normal[], stl_facet *facet) { float v1[3]; float v2[3]; @@ -317,53 +284,19 @@ stl_calculate_normal(float normal[], stl_facet *facet) normal[2] = (float)((double)v1[0] * (double)v2[1]) - ((double)v1[1] * (double)v2[0]); } -/* -static float -stl_calculate_area(stl_facet *facet) -{ - float cross[3][3]; - float sum[3]; - float normal[3]; - float area; - int i; - - for(i = 0; i < 3; i++) - { - cross[i][0] = ((facet->vertex[i].y * facet->vertex[(i + 1) % 3].z) - - (facet->vertex[i].z * facet->vertex[(i + 1) % 3].y)); - cross[i][1] = ((facet->vertex[i].z * facet->vertex[(i + 1) % 3].x) - - (facet->vertex[i].x * facet->vertex[(i + 1) % 3].z)); - cross[i][2] = ((facet->vertex[i].x * facet->vertex[(i + 1) % 3].y) - - (facet->vertex[i].y * facet->vertex[(i + 1) % 3].x)); - } - - 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]; - - stl_calculate_normal(normal, facet); - stl_normalize_vector(normal); - area = 0.5 * (normal[0] * sum[0] + normal[1] * sum[1] + - normal[2] * sum[2]); - return ABS(area); -} -*/ - -void stl_normalize_vector(float v[]) -{ +void stl_normalize_vector(float v[]) { double length; double factor; float min_normal_length; - + length = sqrt((double)v[0] * (double)v[0] + (double)v[1] * (double)v[1] + (double)v[2] * (double)v[2]); min_normal_length = 0.000000000001; - if(length < min_normal_length) - { - v[0] = 0.0; - v[1] = 0.0; - v[2] = 0.0; - return; - } + if(length < min_normal_length) { + v[0] = 0.0; + v[1] = 0.0; + v[2] = 0.0; + return; + } factor = 1.0 / length; v[0] *= factor; v[1] *= factor; @@ -371,30 +304,30 @@ void stl_normalize_vector(float v[]) } void -stl_fix_normal_values(stl_file *stl) -{ +stl_fix_normal_values(stl_file *stl) { int i; - - for(i = 0; i < stl->stats.number_of_facets; i++) - { - stl_check_normal_vector(stl, i, 1); - } + + if (stl->error) return; + + for(i = 0; i < stl->stats.number_of_facets; i++) { + stl_check_normal_vector(stl, i, 1); + } } void -stl_reverse_all_facets(stl_file *stl) -{ +stl_reverse_all_facets(stl_file *stl) { int i; float normal[3]; - - for(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.x = normal[0]; - stl->facet_start[i].normal.y = normal[1]; - stl->facet_start[i].normal.z = normal[2]; - } + + if (stl->error) return; + + for(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.x = normal[0]; + stl->facet_start[i].normal.y = normal[1]; + stl->facet_start[i].normal.z = normal[2]; + } } diff --git a/xs/src/admesh/shared.c b/xs/src/admesh/shared.c index 59fbbb219..56164e25f 100644 --- a/xs/src/admesh/shared.c +++ b/xs/src/admesh/shared.c @@ -1,44 +1,46 @@ /* ADMesh -- process triangulated solid meshes - * Copyright (C) 1995, 1996 Anthony D. Martin + * Copyright (C) 1995, 1996 Anthony D. Martin + * Copyright (C) 2013, 2014 several contributors, see AUTHORS * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * Questions, comments, suggestions, etc to + * Questions, comments, suggestions, etc to + * https://github.com/admesh/admesh/issues */ -#include #include +#include #include "stl.h" void -stl_invalidate_shared_vertices(stl_file *stl) -{ - 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; - } +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; + } } void -stl_generate_shared_vertices(stl_file *stl) -{ +stl_generate_shared_vertices(stl_file *stl) { int i; int j; int first_facet; @@ -49,175 +51,152 @@ stl_generate_shared_vertices(stl_file *stl) int pivot_vertex; int next_facet; int reversed; - - // make sure this function is idempotent and does not leak memory + + if (stl->error) return; + + /* make sure this function is idempotent and does not leak memory */ stl_invalidate_shared_vertices(stl); - + stl->v_indices = (v_indices_struct*) - calloc(stl->stats.number_of_facets, sizeof(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)); + 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(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; - } - - - 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"); - } - - 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; - } + + 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; + } + + + 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"); + } + + 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; } + } } void -stl_write_off(stl_file *stl, char *file) -{ +stl_write_off(stl_file *stl, char *file) { int i; FILE *fp; char *error_msg; - - + + if (stl->error) return; + /* Open the file */ fp = 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); - exit(1); - } - + 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); + 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].x, stl->v_shared[i].y, stl->v_shared[i].z); - } - 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]); - } + for(i = 0; i < stl->stats.shared_vertices; i++) { + fprintf(fp, "\t%f %f %f\n", + stl->v_shared[i].x, stl->v_shared[i].y, stl->v_shared[i].z); + } + 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); } void -stl_write_vrml(stl_file *stl, char *file) -{ +stl_write_vrml(stl_file *stl, char *file) { int i; FILE *fp; char *error_msg; - - + + if (stl->error) return; + /* Open the file */ fp = 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); - exit(1); - } - + 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"); @@ -233,24 +212,22 @@ stl_write_vrml(stl_file *stl, char *file) fprintf(fp, "\t\tDEF STLVertices Coordinate3 {\n"); fprintf(fp, "\t\t\tpoint [\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].x, stl->v_shared[i].y, stl->v_shared[i].z); - } + for(i = 0; i < (stl->stats.shared_vertices - 1); i++) { + fprintf(fp, "\t\t\t\t%f %f %f,\n", + stl->v_shared[i].x, stl->v_shared[i].y, stl->v_shared[i].z); + } fprintf(fp, "\t\t\t\t%f %f %f]\n", - stl->v_shared[i].x, stl->v_shared[i].y, stl->v_shared[i].z); + stl->v_shared[i].x, stl->v_shared[i].y, stl->v_shared[i].z); 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]); - } + 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]); + stl->v_indices[i].vertex[1], stl->v_indices[i].vertex[2]); fprintf(fp, "\t\t}\n"); fprintf(fp, "\t}\n"); fprintf(fp, "}\n"); @@ -258,24 +235,28 @@ stl_write_vrml(stl_file *stl, char *file) } void stl_write_obj (stl_file *stl, char *file) { - int i; - - /* Open the file */ - FILE* fp = 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); - exit(1); - } - - for (i = 0; i < stl->stats.shared_vertices; i++) { - fprintf(fp, "v %f %f %f\n", stl->v_shared[i].x, stl->v_shared[i].y, stl->v_shared[i].z); - } - 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); + int i; + FILE* fp; + + if (stl->error) return; + + /* Open the file */ + fp = 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].x, stl->v_shared[i].y, stl->v_shared[i].z); + } + 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); } diff --git a/xs/src/admesh/stl.h b/xs/src/admesh/stl.h index aa6340436..25fe770aa 100644 --- a/xs/src/admesh/stl.h +++ b/xs/src/admesh/stl.h @@ -1,25 +1,34 @@ /* ADMesh -- process triangulated solid meshes - * Copyright (C) 1995, 1996 Anthony D. Martin + * Copyright (C) 1995, 1996 Anthony D. Martin + * Copyright (C) 2013, 2014 several contributors, see AUTHORS * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * Questions, comments, suggestions, etc to + * Questions, comments, suggestions, etc to + * https://github.com/admesh/admesh/issues */ +#ifndef __admesh_stl__ +#define __admesh_stl__ + #include +#ifdef __cplusplus +extern "C" { +#endif + #define STL_MAX(A,B) ((A)>(B)? (A):(B)) #define STL_MIN(A,B) ((A)<(B)? (A):(B)) #define ABS(X) ((X) < 0 ? -(X) : (X)) @@ -31,60 +40,52 @@ #define ASCII_LINES_PER_FACET 7 #define SIZEOF_EDGE_SORT 24 -typedef struct -{ +typedef struct { float x; float y; float z; -}stl_vertex; +} stl_vertex; -typedef struct -{ +typedef struct { float x; float y; float z; -}stl_normal; +} stl_normal; typedef char stl_extra[2]; -typedef struct -{ +typedef struct { stl_normal normal; stl_vertex vertex[3]; stl_extra extra; -}stl_facet; +} stl_facet; #define SIZEOF_STL_FACET 50 typedef enum {binary, ascii, inmemory} stl_type; -typedef struct -{ +typedef struct { stl_vertex p1; stl_vertex p2; int facet_number; -}stl_edge; +} stl_edge; -typedef struct stl_hash_edge -{ +typedef struct stl_hash_edge { unsigned key[6]; int facet_number; int which_edge; struct stl_hash_edge *next; -}stl_hash_edge; +} stl_hash_edge; -typedef struct -{ +typedef struct { int neighbor[3]; char which_vertex_not[3]; -}stl_neighbors; +} stl_neighbors; -typedef struct -{ +typedef struct { int vertex[3]; -}v_indices_struct; +} v_indices_struct; -typedef struct -{ +typedef struct { char header[81]; stl_type type; int number_of_facets; @@ -117,10 +118,9 @@ typedef struct int collisions; int shared_vertices; int shared_malloced; -}stl_stats; +} stl_stats; -typedef struct -{ +typedef struct { FILE *fp; stl_facet *facet_start; stl_edge *edge_start; @@ -131,7 +131,8 @@ typedef struct v_indices_struct *v_indices; stl_vertex *v_shared; stl_stats stats; -}stl_file; + char error; +} stl_file; extern void stl_open(stl_file *stl, char *file); @@ -139,8 +140,11 @@ extern void stl_close(stl_file *stl); extern void stl_stats_out(stl_file *stl, FILE *file, char *input_file); extern void stl_print_edges(stl_file *stl, FILE *file); extern void 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 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); @@ -154,6 +158,7 @@ extern void stl_fill_holes(stl_file *stl); extern void stl_fix_normal_directions(stl_file *stl); extern void stl_fix_normal_values(stl_file *stl); extern void stl_reverse_all_facets(stl_file *stl); +extern void stl_translate(stl_file *stl, float x, float y, float z); extern void stl_translate_relative(stl_file *stl, float x, float y, float z); extern void stl_scale_versor(stl_file *stl, float versor[3]); extern void stl_scale(stl_file *stl, float factor); @@ -174,11 +179,23 @@ extern void stl_calculate_normal(float normal[], stl_facet *facet); extern void stl_normalize_vector(float v[]); 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); -static void stl_count_facets(stl_file *stl, char *file); +extern void stl_count_facets(stl_file *stl, char *file); extern void stl_allocate(stl_file *stl); -static void stl_read(stl_file *stl, int first_facet, int first); +extern void stl_read(stl_file *stl, int first_facet, int first); extern void stl_facet_stats(stl_file *stl, stl_facet facet, int first); extern void stl_reallocate(stl_file *stl); extern void stl_add_facet(stl_file *stl, stl_facet *new_facet); extern void stl_get_size(stl_file *stl); + +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); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/xs/src/admesh/stl_io.c b/xs/src/admesh/stl_io.c index 95dff856e..2a530997b 100644 --- a/xs/src/admesh/stl_io.c +++ b/xs/src/admesh/stl_io.c @@ -1,26 +1,29 @@ /* ADMesh -- process triangulated solid meshes - * Copyright (C) 1995, 1996 Anthony D. Martin + * Copyright (C) 1995, 1996 Anthony D. Martin + * Copyright (C) 2013, 2014 several contributors, see AUTHORS * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * Questions, comments, suggestions, etc to + * Questions, comments, suggestions, etc to + * https://github.com/admesh/admesh/issues */ -#include #include +#include #include "stl.h" +#include "config.h" #if !defined(SEEK_SET) #define SEEK_SET 0 @@ -28,82 +31,82 @@ #define SEEK_END 2 #endif -static void stl_put_little_int(FILE *fp, int value); -static void stl_put_little_float(FILE *fp, float value_in); - void -stl_print_edges(stl_file *stl, FILE *file) -{ +stl_print_edges(stl_file *stl, FILE *file) { int i; int edges_allocated; + if (stl->error) return; + edges_allocated = stl->stats.number_of_facets * 3; - for(i = 0; i < edges_allocated; i++) - { - fprintf(file, "%d, %f, %f, %f, %f, %f, %f\n", - stl->edge_start[i].facet_number, - stl->edge_start[i].p1.x, stl->edge_start[i].p1.y, - stl->edge_start[i].p1.z, stl->edge_start[i].p2.x, - stl->edge_start[i].p2.y, stl->edge_start[i].p2.z); - } + for(i = 0; i < edges_allocated; i++) { + fprintf(file, "%d, %f, %f, %f, %f, %f, %f\n", + stl->edge_start[i].facet_number, + stl->edge_start[i].p1.x, stl->edge_start[i].p1.y, + stl->edge_start[i].p1.z, stl->edge_start[i].p2.x, + stl->edge_start[i].p2.y, stl->edge_start[i].p2.z); + } } void -stl_stats_out(stl_file *stl, FILE *file, char *input_file) -{ +stl_stats_out(stl_file *stl, FILE *file, char *input_file) { + if (stl->error) return; + + /* 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 0.95 ================\n"); +================= Results produced by ADMesh version " VERSION " ================\n"); fprintf(file, "\ Input file : %s\n", input_file); - if(stl->stats.type == binary) - { - fprintf(file, "\ + if(stl->stats.type == binary) { + fprintf(file, "\ File type : Binary STL file\n"); - } - else - { - fprintf(file, "\ + } 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.x, stl->stats.max.x); - fprintf(file, "Min Y = % f, Max Y = % f\n", - stl->stats.min.y, stl->stats.max.y); - fprintf(file, "Min Z = % f, Max Z = % f\n", - stl->stats.min.z, stl->stats.max.z); - + fprintf(file, "Min X = % f, Max X = % f\n", + stl->stats.min.x, stl->stats.max.x); + fprintf(file, "Min Y = % f, Max Y = % f\n", + stl->stats.min.y, stl->stats.max.y); + fprintf(file, "Min Z = % f, Max Z = % f\n", + stl->stats.min.z, stl->stats.max.z); + 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); +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); +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); +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); +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"); +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); + stl->stats.number_of_parts, stl->stats.volume); fprintf(file, "\ Degenerate facets : %5d\n", stl->stats.degenerate_facets); fprintf(file, "\ @@ -121,153 +124,123 @@ Normals fixed : %5d\n", stl->stats.normals_fixed); } void -stl_write_ascii(stl_file *stl, const char *file, const char *label) -{ +stl_write_ascii(stl_file *stl, const char *file, const char *label) { int i; FILE *fp; char *error_msg; - - + + if (stl->error) return; + /* Open the file */ fp = 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); - exit(1); - } - + 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, "solid %s\n", label); - - for(i = 0; i < stl->stats.number_of_facets; i++) - { - fprintf(fp, " facet normal % .8E % .8E % .8E\n", - stl->facet_start[i].normal.x, stl->facet_start[i].normal.y, - stl->facet_start[i].normal.z); - fprintf(fp, " outer loop\n"); - fprintf(fp, " vertex % .8E % .8E % .8E\n", - stl->facet_start[i].vertex[0].x, stl->facet_start[i].vertex[0].y, - stl->facet_start[i].vertex[0].z); - fprintf(fp, " vertex % .8E % .8E % .8E\n", - stl->facet_start[i].vertex[1].x, stl->facet_start[i].vertex[1].y, - stl->facet_start[i].vertex[1].z); - fprintf(fp, " vertex % .8E % .8E % .8E\n", - stl->facet_start[i].vertex[2].x, stl->facet_start[i].vertex[2].y, - stl->facet_start[i].vertex[2].z); - fprintf(fp, " endloop\n"); - fprintf(fp, " endfacet\n"); - } - + + for(i = 0; i < stl->stats.number_of_facets; i++) { + fprintf(fp, " facet normal % .8E % .8E % .8E\n", + stl->facet_start[i].normal.x, stl->facet_start[i].normal.y, + stl->facet_start[i].normal.z); + fprintf(fp, " outer loop\n"); + fprintf(fp, " vertex % .8E % .8E % .8E\n", + stl->facet_start[i].vertex[0].x, stl->facet_start[i].vertex[0].y, + stl->facet_start[i].vertex[0].z); + fprintf(fp, " vertex % .8E % .8E % .8E\n", + stl->facet_start[i].vertex[1].x, stl->facet_start[i].vertex[1].y, + stl->facet_start[i].vertex[1].z); + fprintf(fp, " vertex % .8E % .8E % .8E\n", + stl->facet_start[i].vertex[2].x, stl->facet_start[i].vertex[2].y, + stl->facet_start[i].vertex[2].z); + fprintf(fp, " endloop\n"); + fprintf(fp, " endfacet\n"); + } + fprintf(fp, "endsolid %s\n", label); - + fclose(fp); } void -stl_print_neighbors(stl_file *stl, char *file) -{ +stl_print_neighbors(stl_file *stl, char *file) { int i; FILE *fp; char *error_msg; + if (stl->error) return; + /* Open the file */ fp = 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); - exit(1); - } + 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); + stl->error = 1; + return; + } - for(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], - stl->neighbors_start[i].neighbor[1], - (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); + for(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], + stl->neighbors_start[i].neighbor[1], + (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); } -static void -stl_put_little_int(FILE *fp, int value_in) -{ - int new_value; - union - { - int int_value; - char char_value[4]; - } value; - - value.int_value = value_in; - - new_value = value.char_value[0] & 0xFF; - new_value |= (value.char_value[1] & 0xFF) << 0x08; - new_value |= (value.char_value[2] & 0xFF) << 0x10; - new_value |= (value.char_value[3] & 0xFF) << 0x18; - fwrite(&new_value, sizeof(int), 1, fp); -} - -static void -stl_put_little_float(FILE *fp, float value_in) -{ - int new_value; - union - { - float float_value; - char char_value[4]; - } value; - - value.float_value = value_in; - - new_value = value.char_value[0] & 0xFF; - new_value |= (value.char_value[1] & 0xFF) << 0x08; - new_value |= (value.char_value[2] & 0xFF) << 0x10; - new_value |= (value.char_value[3] & 0xFF) << 0x18; - fwrite(&new_value, sizeof(int), 1, fp); -} - - void -stl_write_binary(stl_file *stl, const char *file, const char *label) +stl_put_little_int(FILE *fp, int value_in) { + int new_value; + union { + int int_value; + char char_value[4]; + } value; + + value.int_value = value_in; + + new_value = value.char_value[0] & 0xFF; + new_value |= (value.char_value[1] & 0xFF) << 0x08; + new_value |= (value.char_value[2] & 0xFF) << 0x10; + new_value |= (value.char_value[3] & 0xFF) << 0x18; + fwrite(&new_value, sizeof(int), 1, fp); +} + +void +stl_put_little_float(FILE *fp, float value_in) { + int new_value; + union { + float float_value; + char char_value[4]; + } value; + + value.float_value = value_in; + + new_value = value.char_value[0] & 0xFF; + new_value |= (value.char_value[1] & 0xFF) << 0x08; + new_value |= (value.char_value[2] & 0xFF) << 0x10; + new_value |= (value.char_value[3] & 0xFF) << 0x18; + fwrite(&new_value, sizeof(int), 1, fp); +} + +void +stl_write_binary_block(stl_file *stl, FILE *fp) { - FILE *fp; - int i; - char *error_msg; - - - /* Open the file */ - fp = 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); - exit(1); - } - - fprintf(fp, "%s", label); - for(i = strlen(label); i < LABEL_SIZE; i++) putc(0, fp); - - fseek(fp, LABEL_SIZE, SEEK_SET); - - stl_put_little_int(fp, stl->stats.number_of_facets); - + int i; for(i = 0; i < stl->stats.number_of_facets; i++) { stl_put_little_float(fp, stl->facet_start[i].normal.x); @@ -285,22 +258,53 @@ stl_write_binary(stl_file *stl, const char *file, const char *label) fputc(stl->facet_start[i].extra[0], fp); fputc(stl->facet_start[i].extra[1], fp); } - +} + +void +stl_write_binary(stl_file *stl, const char *file, const char *label) { + FILE *fp; + int i; + char *error_msg; + + if (stl->error) return; + + /* Open the file */ + fp = 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_binary: Couldn't open %s for writing", + file); + perror(error_msg); + free(error_msg); + stl->error = 1; + return; + } + + fprintf(fp, "%s", label); + for(i = strlen(label); i < LABEL_SIZE; i++) putc(0, fp); + + fseek(fp, LABEL_SIZE, SEEK_SET); + + stl_put_little_int(fp, stl->stats.number_of_facets); + + stl_write_binary_block(stl, fp); + fclose(fp); } void -stl_write_vertex(stl_file *stl, int facet, int vertex) -{ +stl_write_vertex(stl_file *stl, int facet, int vertex) { + if (stl->error) return; printf(" vertex %d/%d % .8E % .8E % .8E\n", vertex, facet, - stl->facet_start[facet].vertex[vertex].x, - stl->facet_start[facet].vertex[vertex].y, - stl->facet_start[facet].vertex[vertex].z); + stl->facet_start[facet].vertex[vertex].x, + stl->facet_start[facet].vertex[vertex].y, + stl->facet_start[facet].vertex[vertex].z); } void -stl_write_facet(stl_file *stl, char *label, int facet) -{ +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); @@ -308,36 +312,32 @@ stl_write_facet(stl_file *stl, char *label, int facet) } void -stl_write_edge(stl_file *stl, char *label, stl_hash_edge edge) -{ +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); - } + 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) -{ +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]); + 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) -{ +stl_write_quad_object(stl_file *stl, char *file) { FILE *fp; int i; int j; @@ -347,19 +347,21 @@ stl_write_quad_object(stl_file *stl, char *file) stl_vertex uncon_2_color; stl_vertex uncon_3_color; stl_vertex color; - + + if (stl->error) return; + /* Open the file */ fp = 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); - exit(1); - } + 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); + stl->error = 1; + return; + } connect_color.x = 0.0; connect_color.y = 0.0; @@ -375,94 +377,103 @@ stl_write_quad_object(stl_file *stl, char *file) uncon_3_color.z = 0.0; 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)); - 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", - stl->facet_start[i].vertex[0].x, - stl->facet_start[i].vertex[0].y, - stl->facet_start[i].vertex[0].z, color.x, color.y, color.z); - fprintf(fp, "%f %f %f %1.1f %1.1f %1.1f 1\n", - stl->facet_start[i].vertex[1].x, - stl->facet_start[i].vertex[1].y, - stl->facet_start[i].vertex[1].z, color.x, color.y, color.z); - fprintf(fp, "%f %f %f %1.1f %1.1f %1.1f 1\n", - stl->facet_start[i].vertex[2].x, - stl->facet_start[i].vertex[2].y, - stl->facet_start[i].vertex[2].z, color.x, color.y, color.z); - fprintf(fp, "%f %f %f %1.1f %1.1f %1.1f 1\n", - stl->facet_start[i].vertex[2].x, - stl->facet_start[i].vertex[2].y, - stl->facet_start[i].vertex[2].z, color.x, color.y, color.z); + 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)); + 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", + stl->facet_start[i].vertex[0].x, + stl->facet_start[i].vertex[0].y, + stl->facet_start[i].vertex[0].z, color.x, color.y, color.z); + fprintf(fp, "%f %f %f %1.1f %1.1f %1.1f 1\n", + stl->facet_start[i].vertex[1].x, + stl->facet_start[i].vertex[1].y, + stl->facet_start[i].vertex[1].z, color.x, color.y, color.z); + fprintf(fp, "%f %f %f %1.1f %1.1f %1.1f 1\n", + stl->facet_start[i].vertex[2].x, + stl->facet_start[i].vertex[2].y, + stl->facet_start[i].vertex[2].z, color.x, color.y, color.z); + fprintf(fp, "%f %f %f %1.1f %1.1f %1.1f 1\n", + stl->facet_start[i].vertex[2].x, + stl->facet_start[i].vertex[2].y, + stl->facet_start[i].vertex[2].z, color.x, color.y, color.z); + } fclose(fp); } - + void -stl_write_dxf(stl_file *stl, char *file, char *label) -{ +stl_write_dxf(stl_file *stl, char *file, char *label) { int i; FILE *fp; char *error_msg; - - + + if (stl->error) return; + /* Open the file */ fp = 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); - exit(1); - } - + 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, "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"); - for(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].x, stl->facet_start[i].vertex[0].y, - stl->facet_start[i].vertex[0].z); - fprintf(fp, "11\n%f\n21\n%f\n31\n%f\n", - stl->facet_start[i].vertex[1].x, stl->facet_start[i].vertex[1].y, - stl->facet_start[i].vertex[1].z); - fprintf(fp, "12\n%f\n22\n%f\n32\n%f\n", - stl->facet_start[i].vertex[2].x, stl->facet_start[i].vertex[2].y, - stl->facet_start[i].vertex[2].z); - fprintf(fp, "13\n%f\n23\n%f\n33\n%f\n", - stl->facet_start[i].vertex[2].x, stl->facet_start[i].vertex[2].y, - stl->facet_start[i].vertex[2].z); - } - + for(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].x, stl->facet_start[i].vertex[0].y, + stl->facet_start[i].vertex[0].z); + fprintf(fp, "11\n%f\n21\n%f\n31\n%f\n", + stl->facet_start[i].vertex[1].x, stl->facet_start[i].vertex[1].y, + stl->facet_start[i].vertex[1].z); + fprintf(fp, "12\n%f\n22\n%f\n32\n%f\n", + stl->facet_start[i].vertex[2].x, stl->facet_start[i].vertex[2].y, + stl->facet_start[i].vertex[2].z); + fprintf(fp, "13\n%f\n23\n%f\n33\n%f\n", + stl->facet_start[i].vertex[2].x, stl->facet_start[i].vertex[2].y, + stl->facet_start[i].vertex[2].z); + } + 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; +} diff --git a/xs/src/admesh/stlinit.c b/xs/src/admesh/stlinit.c index 138163ec8..67c43e86f 100644 --- a/xs/src/admesh/stlinit.c +++ b/xs/src/admesh/stlinit.c @@ -1,21 +1,23 @@ /* ADMesh -- process triangulated solid meshes - * Copyright (C) 1995, 1996 Anthony D. Martin + * Copyright (C) 1995, 1996 Anthony D. Martin + * Copyright (C) 2013, 2014 several contributors, see AUTHORS * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * Questions, comments, suggestions, etc to + * Questions, comments, suggestions, etc to + * https://github.com/admesh/admesh/issues */ #include @@ -32,19 +34,18 @@ #endif void -stl_open(stl_file *stl, char *file) -{ +stl_open(stl_file *stl, char *file) { stl_initialize(stl); stl_count_facets(stl, file); stl_allocate(stl); stl_read(stl, 0, 1); - fclose(stl->fp); + if (!stl->error) fclose(stl->fp); } void -stl_initialize(stl_file *stl) -{ +stl_initialize(stl_file *stl) { + stl->error = 0; stl->stats.degenerate_facets = 0; stl->stats.edges_fixed = 0; stl->stats.facets_added = 0; @@ -56,276 +57,316 @@ stl_initialize(stl_file *stl) stl->stats.number_of_facets = 0; stl->stats.facets_malloced = 0; stl->stats.volume = -1.0; - + stl->neighbors_start = NULL; stl->facet_start = NULL; stl->v_indices = NULL; stl->v_shared = NULL; } -static void -stl_count_facets(stl_file *stl, char *file) -{ +void +stl_count_facets(stl_file *stl, char *file) { long file_size; int header_num_facets; int num_facets; int i, j; + size_t s; unsigned char chtest[128]; int num_lines = 1; char *error_msg; - + + if (stl->error) return; + /* Open the file */ stl->fp = fopen(file, "r"); - if(stl->fp == NULL) - { - 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); - exit(1); - } + if(stl->fp == NULL) { + 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; + } /* Find size of file */ fseek(stl->fp, 0, SEEK_END); file_size = ftell(stl->fp); - + /* Check for binary or ASCII file */ fseek(stl->fp, HEADER_SIZE, SEEK_SET); - fread(chtest, sizeof(chtest), 1, stl->fp); + if (!fread(chtest, sizeof(chtest), 1, stl->fp)) { + perror("The input is an empty file"); + stl->error = 1; + return; + } stl->stats.type = ascii; - for(i = 0; i < sizeof(chtest); i++) - { - if(chtest[i] > 127) - { - stl->stats.type = binary; - // close and reopen with binary flag (needed on Windows) - fclose(stl->fp); - stl->fp = fopen(file, "rb"); - break; - } + for(s = 0; s < sizeof(chtest); s++) { + if(chtest[s] > 127) { + stl->stats.type = binary; + /* close and reopen with binary flag (needed on Windows) */ + fclose(stl->fp); + stl->fp = fopen(file, "rb"); + break; } + } rewind(stl->fp); /* 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); - exit(1); - } - num_facets = (file_size - HEADER_SIZE) / SIZEOF_STL_FACET; - - /* Read the header */ - fread(stl->stats.header, LABEL_SIZE, 1, stl->fp); - stl->stats.header[80] = '\0'; - - /* Read the int following the header. This should contain # of facets */ - fread(&header_num_facets, sizeof(int), 1, stl->fp); - if(num_facets != header_num_facets) - { - fprintf(stderr, - "Warning: File size doesn't match number of facets in the header\n"); - } + 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); + stl->error = 1; + return; } + num_facets = (file_size - HEADER_SIZE) / SIZEOF_STL_FACET; + + /* Read the header */ + if (fread(stl->stats.header, LABEL_SIZE, 1, stl->fp) > 79) { + stl->stats.header[80] = '\0'; + } + + /* Read the int following the header. This should contain # of facets */ + if((!fread(&header_num_facets, sizeof(int), 1, stl->fp)) || (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 - { - /* Find the number of facets */ - j = 0; - for(i = 0; i < file_size ; i++) - { - j++; - if(getc(stl->fp) == '\n') - { - if(j > 4) /* don't count short lines */ - { - num_lines++; - } - j = 0; - } - } - rewind(stl->fp); - - /* Get the header */ - for(i = 0; - (i < 80) && (stl->stats.header[i] = getc(stl->fp)) != '\n'; i++); - stl->stats.header[i] = '\0'; /* Lose the '\n' */ - stl->stats.header[80] = '\0'; - - num_facets = num_lines / ASCII_LINES_PER_FACET; + else { + /* Find the number of facets */ + j = 0; + for(i = 0; i < file_size ; i++) { + j++; + if(getc(stl->fp) == '\n') { + if(j > 4) { /* don't count short lines */ + num_lines++; + } + j = 0; + } } + rewind(stl->fp); + + /* Get the header */ + for(i = 0; + (i < 80) && (stl->stats.header[i] = getc(stl->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; } void -stl_allocate(stl_file *stl) -{ +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)); + 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)); + calloc(stl->stats.number_of_facets, sizeof(stl_neighbors)); if(stl->facet_start == NULL) perror("stl_initialize"); } void -stl_open_merge(stl_file *stl, char *file) -{ - int first_facet; - - first_facet = stl->stats.number_of_facets; - stl_initialize(stl); - stl_count_facets(stl, file); +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); - stl_read(stl, first_facet, 0); + + /* 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, 0); + + /* 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; } extern void -stl_reallocate(stl_file *stl) -{ +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)); + 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)); + realloc(stl->neighbors_start, stl->stats.number_of_facets * + sizeof(stl_neighbors)); if(stl->facet_start == NULL) perror("stl_initialize"); } -static void -stl_read(stl_file *stl, int first_facet, int first) -{ + +/* 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. */ +void +stl_read(stl_file *stl, int first_facet, int first) { stl_facet facet; int i; - if(stl->stats.type == binary) - { - fseek(stl->fp, HEADER_SIZE, SEEK_SET); - } - else - { - rewind(stl->fp); - /* Skip the first line of the file */ - while(getc(stl->fp) != '\n'); - } + if (stl->error) return; - for(i = first_facet; i < stl->stats.number_of_facets; i++) + if(stl->stats.type == binary) { + fseek(stl->fp, HEADER_SIZE, SEEK_SET); + } else { + rewind(stl->fp); + /* Skip the first line of the file */ + while(getc(stl->fp) != '\n'); + } + + for(i = first_facet; i < stl->stats.number_of_facets; i++) { + if(stl->stats.type == binary) + /* Read a single facet from a binary .STL file */ { - if(stl->stats.type == binary) - /* Read a single facet from a binary .STL file */ - { - // we assume little-endian architecture! - fread(&facet.normal, sizeof(stl_normal), 1, stl->fp); - fread(&facet.vertex, sizeof(stl_vertex), 3, stl->fp); - fread(&facet.extra, sizeof(char), 2, stl->fp); - } - else - /* Read a single facet from an ASCII .STL file */ - { - fscanf(stl->fp, "%*s %*s %f %f %f\n", &facet.normal.x, - &facet.normal.y, &facet.normal.z); - fscanf(stl->fp, "%*s %*s"); - fscanf(stl->fp, "%*s %f %f %f\n", &facet.vertex[0].x, - &facet.vertex[0].y, &facet.vertex[0].z); - fscanf(stl->fp, "%*s %f %f %f\n", &facet.vertex[1].x, - &facet.vertex[1].y, &facet.vertex[1].z); - fscanf(stl->fp, "%*s %f %f %f\n", &facet.vertex[2].x, - &facet.vertex[2].y, &facet.vertex[2].z); - fscanf(stl->fp, "%*s"); - fscanf(stl->fp, "%*s"); - } - /* Write the facet into memory. */ - stl->facet_start[i] = facet; - - stl_facet_stats(stl, facet, first); - first = 0; + /* we assume little-endian architecture! */ + if (fread(&facet.normal, sizeof(stl_normal), 1, stl->fp) \ + + fread(&facet.vertex, sizeof(stl_vertex), 3, stl->fp) \ + + fread(&facet.extra, sizeof(char), 2, stl->fp) != 6) { + perror("Cannot read facet"); + stl->error = 1; + return; + } + } else + /* Read a single facet from an ASCII .STL file */ + { + if((fscanf(stl->fp, "%*s %*s %f %f %f\n", &facet.normal.x, &facet.normal.y, &facet.normal.z) + \ + fscanf(stl->fp, "%*s %*s") + \ + fscanf(stl->fp, "%*s %f %f %f\n", &facet.vertex[0].x, &facet.vertex[0].y, &facet.vertex[0].z) + \ + fscanf(stl->fp, "%*s %f %f %f\n", &facet.vertex[1].x, &facet.vertex[1].y, &facet.vertex[1].z) + \ + fscanf(stl->fp, "%*s %f %f %f\n", &facet.vertex[2].x, &facet.vertex[2].y, &facet.vertex[2].z) + \ + fscanf(stl->fp, "%*s") + \ + fscanf(stl->fp, "%*s")) != 12) { + perror("Something is syntactically very wrong with this ASCII STL!"); + stl->error = 1; + return; + } } - stl->stats.size.x = stl->stats.max.x - stl->stats.min.x; - stl->stats.size.y = stl->stats.max.y - stl->stats.min.y; - stl->stats.size.z = stl->stats.max.z - stl->stats.min.z; - stl->stats.bounding_diameter = sqrt( - stl->stats.size.x * stl->stats.size.x + - stl->stats.size.y * stl->stats.size.y + - stl->stats.size.z * stl->stats.size.z - ); + /* Write the facet into memory. */ + stl->facet_start[i] = facet; + + stl_facet_stats(stl, facet, first); + first = 0; + } + stl->stats.size.x = stl->stats.max.x - stl->stats.min.x; + stl->stats.size.y = stl->stats.max.y - stl->stats.min.y; + stl->stats.size.z = stl->stats.max.z - stl->stats.min.z; + stl->stats.bounding_diameter = sqrt( + stl->stats.size.x * stl->stats.size.x + + stl->stats.size.y * stl->stats.size.y + + stl->stats.size.z * stl->stats.size.z + ); } void -stl_facet_stats(stl_file *stl, stl_facet facet, int first) -{ - float diff_x; - float diff_y; - float diff_z; - float max_diff; - /* while we are going through all of the facets, let's find the */ - /* maximum and minimum values for x, y, and z */ - - /* Initialize the max and min values the first time through*/ - if (first) { - stl->stats.max.x = facet.vertex[0].x; - stl->stats.min.x = facet.vertex[0].x; - stl->stats.max.y = facet.vertex[0].y; - stl->stats.min.y = facet.vertex[0].y; - stl->stats.max.z = facet.vertex[0].z; - stl->stats.min.z = facet.vertex[0].z; - - diff_x = ABS(facet.vertex[0].x - facet.vertex[1].x); - diff_y = ABS(facet.vertex[0].y - facet.vertex[1].y); - diff_z = ABS(facet.vertex[0].z - facet.vertex[1].z); - max_diff = STL_MAX(diff_x, diff_y); - max_diff = STL_MAX(diff_z, max_diff); - stl->stats.shortest_edge = max_diff; - - first = 0; - } - - /* now find the max and min values */ - stl->stats.max.x = STL_MAX(stl->stats.max.x, facet.vertex[0].x); - stl->stats.min.x = STL_MIN(stl->stats.min.x, facet.vertex[0].x); - stl->stats.max.y = STL_MAX(stl->stats.max.y, facet.vertex[0].y); - stl->stats.min.y = STL_MIN(stl->stats.min.y, facet.vertex[0].y); - stl->stats.max.z = STL_MAX(stl->stats.max.z, facet.vertex[0].z); - stl->stats.min.z = STL_MIN(stl->stats.min.z, facet.vertex[0].z); - - stl->stats.max.x = STL_MAX(stl->stats.max.x, facet.vertex[1].x); - stl->stats.min.x = STL_MIN(stl->stats.min.x, facet.vertex[1].x); - stl->stats.max.y = STL_MAX(stl->stats.max.y, facet.vertex[1].y); - stl->stats.min.y = STL_MIN(stl->stats.min.y, facet.vertex[1].y); - stl->stats.max.z = STL_MAX(stl->stats.max.z, facet.vertex[1].z); - stl->stats.min.z = STL_MIN(stl->stats.min.z, facet.vertex[1].z); - - stl->stats.max.x = STL_MAX(stl->stats.max.x, facet.vertex[2].x); - stl->stats.min.x = STL_MIN(stl->stats.min.x, facet.vertex[2].x); - stl->stats.max.y = STL_MAX(stl->stats.max.y, facet.vertex[2].y); - stl->stats.min.y = STL_MIN(stl->stats.min.y, facet.vertex[2].y); - stl->stats.max.z = STL_MAX(stl->stats.max.z, facet.vertex[2].z); - stl->stats.min.z = STL_MIN(stl->stats.min.z, facet.vertex[2].z); +stl_facet_stats(stl_file *stl, stl_facet facet, int first) { + float diff_x; + float diff_y; + float diff_z; + float max_diff; + + 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 */ + + /* Initialize the max and min values the first time through*/ + if (first) { + stl->stats.max.x = facet.vertex[0].x; + stl->stats.min.x = facet.vertex[0].x; + stl->stats.max.y = facet.vertex[0].y; + stl->stats.min.y = facet.vertex[0].y; + stl->stats.max.z = facet.vertex[0].z; + stl->stats.min.z = facet.vertex[0].z; + + diff_x = ABS(facet.vertex[0].x - facet.vertex[1].x); + diff_y = ABS(facet.vertex[0].y - facet.vertex[1].y); + diff_z = ABS(facet.vertex[0].z - facet.vertex[1].z); + max_diff = STL_MAX(diff_x, diff_y); + max_diff = STL_MAX(diff_z, max_diff); + stl->stats.shortest_edge = max_diff; + + first = 0; + } + + /* now find the max and min values */ + stl->stats.max.x = STL_MAX(stl->stats.max.x, facet.vertex[0].x); + stl->stats.min.x = STL_MIN(stl->stats.min.x, facet.vertex[0].x); + stl->stats.max.y = STL_MAX(stl->stats.max.y, facet.vertex[0].y); + stl->stats.min.y = STL_MIN(stl->stats.min.y, facet.vertex[0].y); + stl->stats.max.z = STL_MAX(stl->stats.max.z, facet.vertex[0].z); + stl->stats.min.z = STL_MIN(stl->stats.min.z, facet.vertex[0].z); + + stl->stats.max.x = STL_MAX(stl->stats.max.x, facet.vertex[1].x); + stl->stats.min.x = STL_MIN(stl->stats.min.x, facet.vertex[1].x); + stl->stats.max.y = STL_MAX(stl->stats.max.y, facet.vertex[1].y); + stl->stats.min.y = STL_MIN(stl->stats.min.y, facet.vertex[1].y); + stl->stats.max.z = STL_MAX(stl->stats.max.z, facet.vertex[1].z); + stl->stats.min.z = STL_MIN(stl->stats.min.z, facet.vertex[1].z); + + stl->stats.max.x = STL_MAX(stl->stats.max.x, facet.vertex[2].x); + stl->stats.min.x = STL_MIN(stl->stats.min.x, facet.vertex[2].x); + stl->stats.max.y = STL_MAX(stl->stats.max.y, facet.vertex[2].y); + stl->stats.min.y = STL_MIN(stl->stats.min.y, facet.vertex[2].y); + stl->stats.max.z = STL_MAX(stl->stats.max.z, facet.vertex[2].z); + stl->stats.min.z = STL_MIN(stl->stats.min.z, facet.vertex[2].z); } void -stl_close(stl_file *stl) -{ - if(stl->neighbors_start != NULL) - free(stl->neighbors_start); - if(stl->facet_start != NULL) - free(stl->facet_start); - if(stl->v_indices != NULL) - free(stl->v_indices); - if(stl->v_shared != NULL) - free(stl->v_shared); +stl_close(stl_file *stl) { + if (stl->error) return; + + if(stl->neighbors_start != NULL) + free(stl->neighbors_start); + if(stl->facet_start != NULL) + free(stl->facet_start); + if(stl->v_indices != NULL) + free(stl->v_indices); + if(stl->v_shared != NULL) + free(stl->v_shared); } diff --git a/xs/src/admesh/util.c b/xs/src/admesh/util.c index eec705b9a..f29ba1614 100644 --- a/xs/src/admesh/util.c +++ b/xs/src/admesh/util.c @@ -1,21 +1,23 @@ /* ADMesh -- process triangulated solid meshes - * Copyright (C) 1995, 1996 Anthony D. Martin + * Copyright (C) 1995, 1996 Anthony D. Martin + * Copyright (C) 2013, 2014 several contributors, see AUTHORS * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * Questions, comments, suggestions, etc to + * Questions, comments, suggestions, etc to + * https://github.com/admesh/admesh/issues */ #include @@ -31,8 +33,7 @@ static float get_volume(stl_file *stl); void -stl_verify_neighbors(stl_file *stl) -{ +stl_verify_neighbors(stl_file *stl) { int i; int j; stl_edge edge_a; @@ -40,377 +41,512 @@ stl_verify_neighbors(stl_file *stl) int neighbor; int vnot; + if (stl->error) return; + 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(memcmp(&edge_a, &edge_b, SIZEOF_EDGE_SORT) != 0) - { - /* 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(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(memcmp(&edge_a, &edge_b, SIZEOF_EDGE_SORT) != 0) { + /* 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_relative(stl_file *stl, float x, float y, float z) -{ +stl_translate(stl_file *stl, float x, float y, float z) { int i; int j; - - for(i = 0; i < stl->stats.number_of_facets; i++) - { - for(j = 0; j < 3; j++) - { - stl->facet_start[i].vertex[j].x += x; - stl->facet_start[i].vertex[j].y += y; - stl->facet_start[i].vertex[j].z += z; - } + + if (stl->error) return; + + for(i = 0; i < stl->stats.number_of_facets; i++) { + for(j = 0; j < 3; j++) { + stl->facet_start[i].vertex[j].x -= (stl->stats.min.x - x); + stl->facet_start[i].vertex[j].y -= (stl->stats.min.y - y); + stl->facet_start[i].vertex[j].z -= (stl->stats.min.z - z); } + } + stl->stats.max.x -= (stl->stats.min.x - x); + stl->stats.max.y -= (stl->stats.min.y - y); + stl->stats.max.z -= (stl->stats.min.z - z); + stl->stats.min.x = x; + stl->stats.min.y = y; + stl->stats.min.z = z; + + stl_invalidate_shared_vertices(stl); +} + +/* 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) { + int i; + int j; + + if (stl->error) return; + + for(i = 0; i < stl->stats.number_of_facets; i++) { + for(j = 0; j < 3; j++) { + stl->facet_start[i].vertex[j].x += x; + stl->facet_start[i].vertex[j].y += y; + stl->facet_start[i].vertex[j].z += z; + } + } stl->stats.min.x += x; stl->stats.min.y += y; stl->stats.min.z += z; stl->stats.max.x += x; stl->stats.max.y += y; stl->stats.max.z += z; - + stl_invalidate_shared_vertices(stl); } void -stl_scale_versor(stl_file *stl, float versor[3]) -{ +stl_scale_versor(stl_file *stl, float versor[3]) { int i; int j; - - // scale extents + + if (stl->error) return; + + /* scale extents */ stl->stats.min.x *= versor[0]; stl->stats.min.y *= versor[1]; stl->stats.min.z *= versor[2]; stl->stats.max.x *= versor[0]; stl->stats.max.y *= versor[1]; stl->stats.max.z *= versor[2]; - - // scale size + + /* scale size */ stl->stats.size.x *= versor[0]; stl->stats.size.y *= versor[1]; stl->stats.size.z *= versor[2]; - - // scale volume + + /* scale volume */ if (stl->stats.volume > 0.0) { stl->stats.volume *= (versor[0] * versor[1] * versor[2]); } - - for(i = 0; i < stl->stats.number_of_facets; i++) - { - for(j = 0; j < 3; j++) - { - stl->facet_start[i].vertex[j].x *= versor[0]; - stl->facet_start[i].vertex[j].y *= versor[1]; - stl->facet_start[i].vertex[j].z *= versor[2]; - } + + for(i = 0; i < stl->stats.number_of_facets; i++) { + for(j = 0; j < 3; j++) { + stl->facet_start[i].vertex[j].x *= versor[0]; + stl->facet_start[i].vertex[j].y *= versor[1]; + stl->facet_start[i].vertex[j].z *= versor[2]; } - - stl_invalidate_shared_vertices(stl); + } + + stl_invalidate_shared_vertices(stl); } void -stl_scale(stl_file *stl, float factor) -{ - float versor[3]; - versor[0] = factor; - versor[1] = factor; - versor[2] = factor; - stl_scale_versor(stl, versor); +stl_scale(stl_file *stl, float factor) { + float versor[3]; + + if (stl->error) return; + + versor[0] = factor; + versor[1] = factor; + versor[2] = factor; + stl_scale_versor(stl, versor); } -static void calculate_normals(stl_file *stl) -{ - long i; - float normal[3]; - - for(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.x = normal[0]; - stl->facet_start[i].normal.y = normal[1]; - stl->facet_start[i].normal.z = normal[2]; - } +static void calculate_normals(stl_file *stl) { + long i; + float normal[3]; + + if (stl->error) return; + + for(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.x = normal[0]; + stl->facet_start[i].normal.y = normal[1]; + stl->facet_start[i].normal.z = normal[2]; + } } void -stl_rotate_x(stl_file *stl, float angle) -{ +stl_rotate_x(stl_file *stl, float angle) { int i; int j; - - for(i = 0; i < stl->stats.number_of_facets; i++) - { - for(j = 0; j < 3; j++) - { - stl_rotate(&stl->facet_start[i].vertex[j].y, - &stl->facet_start[i].vertex[j].z, 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].y, + &stl->facet_start[i].vertex[j].z, angle); } + } stl_get_size(stl); - calculate_normals(stl); + calculate_normals(stl); } void -stl_rotate_y(stl_file *stl, float angle) -{ +stl_rotate_y(stl_file *stl, float angle) { int i; int j; - - for(i = 0; i < stl->stats.number_of_facets; i++) - { - for(j = 0; j < 3; j++) - { - stl_rotate(&stl->facet_start[i].vertex[j].z, - &stl->facet_start[i].vertex[j].x, 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].z, + &stl->facet_start[i].vertex[j].x, angle); } + } stl_get_size(stl); - calculate_normals(stl); + calculate_normals(stl); } void -stl_rotate_z(stl_file *stl, float angle) -{ +stl_rotate_z(stl_file *stl, float angle) { int i; int j; - - for(i = 0; i < stl->stats.number_of_facets; i++) - { - for(j = 0; j < 3; j++) - { - stl_rotate(&stl->facet_start[i].vertex[j].x, - &stl->facet_start[i].vertex[j].y, 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].x, + &stl->facet_start[i].vertex[j].y, angle); } + } stl_get_size(stl); - calculate_normals(stl); + calculate_normals(stl); } - + static void -stl_rotate(float *x, float *y, float angle) -{ +stl_rotate(float *x, float *y, float angle) { double r; double theta; double radian_angle; - + radian_angle = (angle / 180.0) * M_PI; - - r = sqrt((*x * *x) + (*y * *y)); + + r = sqrt((*x **x) + (*y **y)); theta = atan2(*y, *x); *x = r * cos(theta + radian_angle); *y = r * sin(theta + radian_angle); } extern void -stl_get_size(stl_file *stl) -{ - if (stl->stats.number_of_facets == 0) return; - +stl_get_size(stl_file *stl) { int i; int j; + if (stl->error) return; + if (stl->stats.number_of_facets == 0) return; + stl->stats.min.x = stl->facet_start[0].vertex[0].x; stl->stats.min.y = stl->facet_start[0].vertex[0].y; stl->stats.min.z = stl->facet_start[0].vertex[0].z; stl->stats.max.x = stl->facet_start[0].vertex[0].x; stl->stats.max.y = stl->facet_start[0].vertex[0].y; stl->stats.max.z = stl->facet_start[0].vertex[0].z; - - for(i = 0; i < stl->stats.number_of_facets; i++) - { - for(j = 0; j < 3; j++) - { - stl->stats.min.x = STL_MIN(stl->stats.min.x, - stl->facet_start[i].vertex[j].x); - stl->stats.min.y = STL_MIN(stl->stats.min.y, - stl->facet_start[i].vertex[j].y); - stl->stats.min.z = STL_MIN(stl->stats.min.z, - stl->facet_start[i].vertex[j].z); - stl->stats.max.x = STL_MAX(stl->stats.max.x, - stl->facet_start[i].vertex[j].x); - stl->stats.max.y = STL_MAX(stl->stats.max.y, - stl->facet_start[i].vertex[j].y); - stl->stats.max.z = STL_MAX(stl->stats.max.z, - stl->facet_start[i].vertex[j].z); - } + + for(i = 0; i < stl->stats.number_of_facets; i++) { + for(j = 0; j < 3; j++) { + stl->stats.min.x = STL_MIN(stl->stats.min.x, + stl->facet_start[i].vertex[j].x); + stl->stats.min.y = STL_MIN(stl->stats.min.y, + stl->facet_start[i].vertex[j].y); + stl->stats.min.z = STL_MIN(stl->stats.min.z, + stl->facet_start[i].vertex[j].z); + stl->stats.max.x = STL_MAX(stl->stats.max.x, + stl->facet_start[i].vertex[j].x); + stl->stats.max.y = STL_MAX(stl->stats.max.y, + stl->facet_start[i].vertex[j].y); + stl->stats.max.z = STL_MAX(stl->stats.max.z, + stl->facet_start[i].vertex[j].z); } - stl->stats.size.x = stl->stats.max.x - stl->stats.min.x; - stl->stats.size.y = stl->stats.max.y - stl->stats.min.y; - stl->stats.size.z = stl->stats.max.z - stl->stats.min.z; - stl->stats.bounding_diameter = sqrt( - stl->stats.size.x * stl->stats.size.x + - stl->stats.size.y * stl->stats.size.y + - stl->stats.size.z * stl->stats.size.z - ); + } + stl->stats.size.x = stl->stats.max.x - stl->stats.min.x; + stl->stats.size.y = stl->stats.max.y - stl->stats.min.y; + stl->stats.size.z = stl->stats.max.z - stl->stats.min.z; + stl->stats.bounding_diameter = sqrt( + stl->stats.size.x * stl->stats.size.x + + stl->stats.size.y * stl->stats.size.y + + stl->stats.size.z * stl->stats.size.z + ); } void -stl_mirror_xy(stl_file *stl) -{ +stl_mirror_xy(stl_file *stl) { int i; int j; float temp_size; - - for(i = 0; i < stl->stats.number_of_facets; i++) - { - for(j = 0; j < 3; j++) - { - stl->facet_start[i].vertex[j].z *= -1.0; - } + + if (stl->error) return; + + for(i = 0; i < stl->stats.number_of_facets; i++) { + for(j = 0; j < 3; j++) { + stl->facet_start[i].vertex[j].z *= -1.0; } + } temp_size = stl->stats.min.z; stl->stats.min.z = stl->stats.max.z; stl->stats.max.z = temp_size; stl->stats.min.z *= -1.0; stl->stats.max.z *= -1.0; - stl_reverse_all_facets(stl); - stl->stats.facets_reversed -= stl->stats.number_of_facets; // for not altering stats - + 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) -{ +stl_mirror_yz(stl_file *stl) { int i; int j; float temp_size; - - for(i = 0; i < stl->stats.number_of_facets; i++) - { - for(j = 0; j < 3; j++) - { - stl->facet_start[i].vertex[j].x *= -1.0; - } + + if (stl->error) return; + + for(i = 0; i < stl->stats.number_of_facets; i++) { + for(j = 0; j < 3; j++) { + stl->facet_start[i].vertex[j].x *= -1.0; } + } temp_size = stl->stats.min.x; stl->stats.min.x = stl->stats.max.x; stl->stats.max.x = temp_size; stl->stats.min.x *= -1.0; stl->stats.max.x *= -1.0; - stl_reverse_all_facets(stl); - stl->stats.facets_reversed -= stl->stats.number_of_facets; // for not altering stats + 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) -{ +stl_mirror_xz(stl_file *stl) { int i; int j; float temp_size; - - for(i = 0; i < stl->stats.number_of_facets; i++) - { - for(j = 0; j < 3; j++) - { - stl->facet_start[i].vertex[j].y *= -1.0; - } + + if (stl->error) return; + + for(i = 0; i < stl->stats.number_of_facets; i++) { + for(j = 0; j < 3; j++) { + stl->facet_start[i].vertex[j].y *= -1.0; } + } temp_size = stl->stats.min.y; stl->stats.min.y = stl->stats.max.y; stl->stats.max.y = temp_size; stl->stats.min.y *= -1.0; stl->stats.max.y *= -1.0; - stl_reverse_all_facets(stl); - stl->stats.facets_reversed -= stl->stats.number_of_facets; // for not altering stats + 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) -{ - long i; - stl_vertex p0; - stl_vertex p; - stl_normal n; - float height; - float area; - float volume = 0.0; - - /* Choose a point, any point as the reference */ - p0.x = stl->facet_start[0].vertex[0].x; - p0.y = stl->facet_start[0].vertex[0].y; - p0.z = stl->facet_start[0].vertex[0].z; +static float get_volume(stl_file *stl) { + long i; + stl_vertex p0; + stl_vertex p; + stl_normal n; + float height; + float area; + float volume = 0.0; - for(i = 0; i < stl->stats.number_of_facets; i++){ - p.x = stl->facet_start[i].vertex[0].x - p0.x; - p.y = stl->facet_start[i].vertex[0].y - p0.y; - p.z = stl->facet_start[i].vertex[0].z - p0.z; - /* Do dot product to get distance from point to plane */ - n = stl->facet_start[i].normal; - height = (n.x * p.x) + (n.y * p.y) + (n.z * p.z); - area = get_area(&stl->facet_start[i]); - volume += (area * height) / 3.0; - } - return volume; + if (stl->error) return 0; + + /* Choose a point, any point as the reference */ + p0.x = stl->facet_start[0].vertex[0].x; + p0.y = stl->facet_start[0].vertex[0].y; + p0.z = stl->facet_start[0].vertex[0].z; + + for(i = 0; i < stl->stats.number_of_facets; i++) { + p.x = stl->facet_start[i].vertex[0].x - p0.x; + p.y = stl->facet_start[i].vertex[0].y - p0.y; + p.z = stl->facet_start[i].vertex[0].z - p0.z; + /* Do dot product to get distance from point to plane */ + n = stl->facet_start[i].normal; + height = (n.x * p.x) + (n.y * p.y) + (n.z * p.z); + area = get_area(&stl->facet_start[i]); + volume += (area * height) / 3.0; + } + 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; - } +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); + stl->stats.volume = -stl->stats.volume; + } } -static float get_area(stl_facet *facet) -{ - double cross[3][3]; - float sum[3]; - float n[3]; - float area; - int i; - - // 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) - for(i = 0; i < 3; i++){ - cross[i][0]=(((double)facet->vertex[i].y * (double)facet->vertex[(i + 1) % 3].z) - - ((double)facet->vertex[i].z * (double)facet->vertex[(i + 1) % 3].y)); - cross[i][1]=(((double)facet->vertex[i].z * (double)facet->vertex[(i + 1) % 3].x) - - ((double)facet->vertex[i].x * (double)facet->vertex[(i + 1) % 3].z)); - cross[i][2]=(((double)facet->vertex[i].x * (double)facet->vertex[(i + 1) % 3].y) - - ((double)facet->vertex[i].y * (double)facet->vertex[(i + 1) % 3].x)); - } - - 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]; +static float get_area(stl_facet *facet) { + double cross[3][3]; + float sum[3]; + float n[3]; + float area; + int i; - /* This should already be done. But just in case, let's do it again */ - stl_calculate_normal(n, facet); - stl_normalize_vector(n); + /* 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) */ + for(i = 0; i < 3; i++) { + cross[i][0]=(((double)facet->vertex[i].y * (double)facet->vertex[(i + 1) % 3].z) - + ((double)facet->vertex[i].z * (double)facet->vertex[(i + 1) % 3].y)); + cross[i][1]=(((double)facet->vertex[i].z * (double)facet->vertex[(i + 1) % 3].x) - + ((double)facet->vertex[i].x * (double)facet->vertex[(i + 1) % 3].z)); + cross[i][2]=(((double)facet->vertex[i].x * (double)facet->vertex[(i + 1) % 3].y) - + ((double)facet->vertex[i].y * (double)facet->vertex[(i + 1) % 3].x)); + } - area = 0.5 * (n[0] * sum[0] + n[1] * sum[1] + n[2] * sum[2]); - return area; + 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 */ + stl_calculate_normal(n, facet); + stl_normalize_vector(n); + + area = 0.5 * (n[0] * sum[0] + n[1] * sum[1] + n[2] * sum[2]); + return area; +} + +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; + + if (stl->error) return; + + 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(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(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(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_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); + + if(exact_flag) { + if (verbose_flag) + printf("Verifying neighbors...\n"); + stl_verify_neighbors(stl); + } } diff --git a/xs/src/libslic3r/TriangleMesh.cpp b/xs/src/libslic3r/TriangleMesh.cpp index db9b516d8..551eafe41 100644 --- a/xs/src/libslic3r/TriangleMesh.cpp +++ b/xs/src/libslic3r/TriangleMesh.cpp @@ -29,6 +29,7 @@ TriangleMesh::TriangleMesh(const TriangleMesh &other) { this->stl.heads = NULL; this->stl.tail = NULL; + this->stl.error = other.stl.error; if (other.stl.facet_start != NULL) { 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); @@ -125,6 +126,7 @@ TriangleMesh::repair() { // fill_holes if (stl.stats.connected_facets_3_edge < stl.stats.number_of_facets) { stl_fill_holes(&stl); + stl_clear_error(&stl); } // normal_directions @@ -280,6 +282,7 @@ TriangleMesh::split() const mesh->stl.stats.type = inmemory; mesh->stl.stats.number_of_facets = facets.size(); mesh->stl.stats.original_num_facets = mesh->stl.stats.number_of_facets; + stl_clear_error(&mesh->stl); stl_allocate(&mesh->stl); int first = 1; @@ -389,6 +392,7 @@ TriangleMesh::to_SV() { void TriangleMesh::ReadFromPerl(SV* vertices, SV* facets) { + stl.error = 0; stl.stats.type = inmemory; // count facets and allocate memory