123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988 |
- /* ADMesh -- process triangulated solid meshes
- * Copyright (C) 1995, 1996 Anthony D. Martin <amartin@engr.csulb.edu>
- * 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 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.
- *
- * Questions, comments, suggestions, etc to
- * https://github.com/admesh/admesh/issues
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <math.h>
- #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_nearby(stl_file *stl,
- stl_hash_edge *edge_a, stl_hash_edge *edge_b);
- static void stl_record_neighbors(stl_file *stl,
- stl_hash_edge *edge_a, stl_hash_edge *edge_b);
- static void stl_initialize_facet_check_exact(stl_file *stl);
- static void stl_initialize_facet_check_nearby(stl_file *stl);
- static void stl_load_edge_exact(stl_file *stl, stl_hash_edge *edge,
- 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);
- static void insert_hash_edge(stl_file *stl, stl_hash_edge edge,
- void (*match_neighbors)(stl_file *stl,
- stl_hash_edge *edge_a, stl_hash_edge *edge_b));
- static int stl_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);
- static void stl_which_vertices_to_change(stl_file *stl, stl_hash_edge *edge_a,
- stl_hash_edge *edge_b, int *facet1, int *vertex1,
- int *facet2, int *vertex2,
- stl_vertex *new_vertex1, stl_vertex *new_vertex2);
- static void stl_remove_degenerate(stl_file *stl, int facet);
- extern int stl_check_normal_vector(stl_file *stl,
- int facet_num, int normal_fix_flag);
- static void stl_update_connects_remove_1(stl_file *stl, int facet_num);
- 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_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;
- stl->stats.connected_facets_3_edge = 0;
- stl_initialize_facet_check_exact(stl);
- for(i = 0; i < stl->stats.number_of_facets; i++) {
- facet = stl->facet_start[i];
- // Positive and negative zeros are possible in the floats, which are considered equal by the FP unit.
- // When using a memcmp on raw floats, those numbers report to be different.
- // Unify all +0 and -0 to +0 to make the floats equal under memcmp.
- {
- uint32_t *f = (uint32_t*)&facet;
- for (int j = 0; j < 12; ++ j, ++ f) // 3x vertex + normal: 4x3 = 12 floats
- if (*f == 0x80000000)
- // Negative zero, switch to positive zero.
- *f = 0;
- }
- /* 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);
- }
- }
- stl_free_edges(stl);
- #if 0
- printf("Number of faces: %d, number of manifold edges: %d, number of connected edges: %d, number of unconnected edges: %d\r\n",
- stl->stats.number_of_facets, stl->stats.number_of_facets * 3,
- stl->stats.connected_edges, stl->stats.number_of_facets * 3 - stl->stats.connected_edges);
- #endif
- }
- static void
- stl_load_edge_exact(stl_file *stl, stl_hash_edge *edge,
- stl_vertex *a, stl_vertex *b) {
- if (stl->error) return;
- {
- float diff_x = ABS(a->x - b->x);
- float diff_y = ABS(a->y - b->y);
- float diff_z = ABS(a->z - b->z);
- float max_diff = STL_MAX(diff_x, diff_y);
- max_diff = STL_MAX(diff_z, max_diff);
- stl->stats.shortest_edge = STL_MIN(max_diff, stl->stats.shortest_edge);
- }
- // Ensure identical vertex ordering of equal edges.
- // This method is numerically robust.
- if ((a->x != b->x) ?
- (a->x < b->x) :
- ((a->y != b->y) ?
- (a->y < b->y) :
- (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) {
- int i;
- if (stl->error) return;
- stl->stats.malloced = 0;
- stl->stats.freed = 0;
- stl->stats.collisions = 0;
- 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;
- }
- stl->heads = (stl_hash_edge**)calloc(stl->M, sizeof(*stl->heads));
- if(stl->heads == NULL) perror("stl_initialize_facet_check_exact");
- stl->tail = (stl_hash_edge*)malloc(sizeof(stl_hash_edge));
- if(stl->tail == NULL) perror("stl_initialize_facet_check_exact");
- stl->tail->next = stl->tail;
- for(i = 0; i < stl->M; i++) {
- stl->heads[i] = stl->tail;
- }
- }
- static void
- insert_hash_edge(stl_file *stl, stl_hash_edge edge,
- void (*match_neighbors)(stl_file *stl,
- stl_hash_edge *edge_a, stl_hash_edge *edge_b)) {
- 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++;
- }
- }
- }
- }
- static int
- 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);
- }
- 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);
- }
- }
- void
- 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_initialize_facet_check_nearby(stl);
- for(i = 0; i < stl->stats.number_of_facets; i++) {
- facet = stl->facet_start[i];
- // Positive and negative zeros are possible in the floats, which are considered equal by the FP unit.
- // When using a memcmp on raw floats, those numbers report to be different.
- // Unify all +0 and -0 to +0 to make the floats equal under memcmp.
- {
- uint32_t *f = (uint32_t*)&facet;
- for (int j = 0; j < 12; ++ j, ++ f) // 3x vertex + normal: 4x3 = 12 floats
- if (*f == 0x80000000)
- // Negative zero, switch to positive zero.
- *f = 0;
- }
- 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) {
- // Index of a grid cell spaced by tolerance.
- uint32_t vertex1[3] = {
- (uint32_t)((a->x - stl->stats.min.x) / tolerance),
- (uint32_t)((a->y - stl->stats.min.y) / tolerance),
- (uint32_t)((a->z - stl->stats.min.z) / tolerance)
- };
- uint32_t vertex2[3] = {
- (uint32_t)((b->x - stl->stats.min.x) / tolerance),
- (uint32_t)((b->y - stl->stats.min.y) / tolerance),
- (uint32_t)((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;
- }
- // Ensure identical vertex ordering of edges, which vertices land into equal grid cells.
- // This method is numerically robust.
- if ((vertex1[0] != vertex2[0]) ?
- (vertex1[0] < vertex2[0]) :
- ((vertex1[1] != vertex2[1]) ?
- (vertex1[1] < vertex2[1]) :
- (vertex1[2] < vertex2[2]))) {
- memcpy(&edge->key[0], vertex1, 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) {
- int i;
- stl_hash_edge *temp;
- 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) {
- int i;
- if (stl->error) return;
- stl->stats.malloced = 0;
- stl->stats.freed = 0;
- stl->stats.collisions = 0;
- /* tolerance = STL_MAX(stl->stats.shortest_edge, tolerance);*/
- /* tolerance = STL_MAX((stl->stats.bounding_diameter / 500000.0), tolerance);*/
- /* tolerance *= 0.5;*/
- stl->M = 81397;
- stl->heads = (stl_hash_edge**)calloc(stl->M, sizeof(*stl->heads));
- if(stl->heads == NULL) perror("stl_initialize_facet_check_nearby");
- stl->tail = (stl_hash_edge*)malloc(sizeof(stl_hash_edge));
- if(stl->tail == NULL) perror("stl_initialize_facet_check_nearby");
- stl->tail->next = stl->tail;
- for(i = 0; i < stl->M; i++) {
- stl->heads[i] = stl->tail;
- }
- }
- static void
- stl_record_neighbors(stl_file *stl,
- stl_hash_edge *edge_a, stl_hash_edge *edge_b) {
- int i;
- int j;
- if (stl->error) return;
- /* Facet a's neighbor is facet b */
- stl->neighbors_start[edge_a->facet_number].neighbor[edge_a->which_edge % 3] =
- edge_b->facet_number; /* sets the .neighbor part */
- stl->neighbors_start[edge_a->facet_number].
- which_vertex_not[edge_a->which_edge % 3] =
- (edge_b->which_edge + 2) % 3; /* sets the .which_vertex_not part */
- /* Facet b's neighbor is facet a */
- stl->neighbors_start[edge_b->facet_number].neighbor[edge_b->which_edge % 3] =
- edge_a->facet_number; /* sets the .neighbor part */
- stl->neighbors_start[edge_b->facet_number].
- which_vertex_not[edge_b->which_edge % 3] =
- (edge_a->which_edge + 2) % 3; /* sets the .which_vertex_not part */
- if( ((edge_a->which_edge < 3) && (edge_b->which_edge < 3))
- || ((edge_a->which_edge > 2) && (edge_b->which_edge > 2))) {
- /* these facets are oriented in opposite directions. */
- /* their normals are probably messed up. */
- stl->neighbors_start[edge_a->facet_number].
- which_vertex_not[edge_a->which_edge % 3] += 3;
- stl->neighbors_start[edge_b->facet_number].
- which_vertex_not[edge_b->which_edge % 3] += 3;
- }
- /* Count successful connects */
- /* Total connects */
- stl->stats.connected_edges += 2;
- /* Count individual connects */
- i = ((stl->neighbors_start[edge_a->facet_number].neighbor[0] == -1) +
- (stl->neighbors_start[edge_a->facet_number].neighbor[1] == -1) +
- (stl->neighbors_start[edge_a->facet_number].neighbor[2] == -1));
- j = ((stl->neighbors_start[edge_b->facet_number].neighbor[0] == -1) +
- (stl->neighbors_start[edge_b->facet_number].neighbor[1] == -1) +
- (stl->neighbors_start[edge_b->facet_number].neighbor[2] == -1));
- if(i == 2) {
- stl->stats.connected_facets_1_edge +=1;
- } else if(i == 1) {
- stl->stats.connected_facets_2_edge +=1;
- } else {
- stl->stats.connected_facets_3_edge +=1;
- }
- if(j == 2) {
- stl->stats.connected_facets_1_edge +=1;
- } else if(j == 1) {
- stl->stats.connected_facets_2_edge +=1;
- } else {
- stl->stats.connected_facets_3_edge +=1;
- }
- }
- static void
- stl_match_neighbors_exact(stl_file *stl,
- 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) {
- int facet1;
- int facet2;
- int vertex1;
- int vertex2;
- int vnot1;
- int vnot2;
- stl_vertex new_vertex1;
- stl_vertex new_vertex2;
- if (stl->error) return;
- stl_record_neighbors(stl, edge_a, edge_b);
- stl_which_vertices_to_change(stl, edge_a, edge_b, &facet1, &vertex1,
- &facet2, &vertex2, &new_vertex1, &new_vertex2);
- if(facet1 != -1) {
- if(facet1 == edge_a->facet_number) {
- vnot1 = (edge_a->which_edge + 2) % 3;
- } else {
- vnot1 = (edge_b->which_edge + 2) % 3;
- }
- if(((vnot1 + 2) % 3) == vertex1) {
- vnot1 += 3;
- }
- stl_change_vertices(stl, facet1, vnot1, new_vertex1);
- }
- if(facet2 != -1) {
- if(facet2 == edge_a->facet_number) {
- vnot2 = (edge_a->which_edge + 2) % 3;
- } else {
- vnot2 = (edge_b->which_edge + 2) % 3;
- }
- if(((vnot2 + 2) % 3) == vertex2) {
- vnot2 += 3;
- }
- stl_change_vertices(stl, facet2, vnot2, new_vertex2);
- }
- stl->stats.edges_fixed += 2;
- }
- static void
- stl_change_vertices(stl_file *stl, int facet_num, int vnot,
- stl_vertex new_vertex) {
- int first_facet;
- int direction;
- int next_edge;
- int pivot_vertex;
- if (stl->error) return;
- first_facet = facet_num;
- direction = 0;
- for(;;) {
- if(vnot > 2) {
- if(direction == 0) {
- pivot_vertex = (vnot + 2) % 3;
- next_edge = pivot_vertex;
- direction = 1;
- } else {
- pivot_vertex = (vnot + 1) % 3;
- next_edge = vnot % 3;
- direction = 0;
- }
- } else {
- if(direction == 0) {
- pivot_vertex = (vnot + 1) % 3;
- next_edge = vnot;
- } else {
- pivot_vertex = (vnot + 2) % 3;
- next_edge = pivot_vertex;
- }
- }
- #if 0
- if (stl->facet_start[facet_num].vertex[pivot_vertex].x == new_vertex.x &&
- stl->facet_start[facet_num].vertex[pivot_vertex].y == new_vertex.y &&
- stl->facet_start[facet_num].vertex[pivot_vertex].z == new_vertex.z)
- printf("Changing vertex %f,%f,%f: Same !!!\r\n",
- new_vertex.x, new_vertex.y, new_vertex.z);
- else {
- if (stl->facet_start[facet_num].vertex[pivot_vertex].x != new_vertex.x)
- printf("Changing coordinate x, vertex %e (0x%08x) to %e(0x%08x)\r\n",
- stl->facet_start[facet_num].vertex[pivot_vertex].x,
- *reinterpret_cast<const int*>(&stl->facet_start[facet_num].vertex[pivot_vertex].x),
- new_vertex.x,
- *reinterpret_cast<const int*>(&new_vertex.x));
- if (stl->facet_start[facet_num].vertex[pivot_vertex].y != new_vertex.y)
- printf("Changing coordinate x, vertex %e (0x%08x) to %e(0x%08x)\r\n",
- stl->facet_start[facet_num].vertex[pivot_vertex].y,
- *reinterpret_cast<const int*>(&stl->facet_start[facet_num].vertex[pivot_vertex].y),
- new_vertex.y,
- *reinterpret_cast<const int*>(&new_vertex.y));
- if (stl->facet_start[facet_num].vertex[pivot_vertex].z != new_vertex.z)
- printf("Changing coordinate x, vertex %e (0x%08x) to %e(0x%08x)\r\n",
- stl->facet_start[facet_num].vertex[pivot_vertex].z,
- *reinterpret_cast<const int*>(&stl->facet_start[facet_num].vertex[pivot_vertex].z),
- new_vertex.z,
- *reinterpret_cast<const int*>(&new_vertex.z));
- }
- #endif
- stl->facet_start[facet_num].vertex[pivot_vertex] = new_vertex;
- vnot = stl->neighbors_start[facet_num].which_vertex_not[next_edge];
- facet_num = stl->neighbors_start[facet_num].neighbor[next_edge];
- if(facet_num == -1) {
- break;
- }
- if(facet_num == first_facet) {
- /* back to the beginning */
- printf("\
- Back to the first facet changing vertices: probably a mobius part.\n\
- Try using a smaller tolerance or don't do a nearby check\n");
- return;
- }
- }
- }
- static void
- stl_which_vertices_to_change(stl_file *stl, stl_hash_edge *edge_a,
- stl_hash_edge *edge_b, int *facet1, int *vertex1,
- int *facet2, int *vertex2,
- stl_vertex *new_vertex1, stl_vertex *new_vertex2) {
- int v1a; /* pair 1, facet a */
- int v1b; /* pair 1, facet b */
- int v2a; /* pair 2, facet a */
- int v2b; /* pair 2, facet b */
- /* Find first pair */
- if(edge_a->which_edge < 3) {
- v1a = edge_a->which_edge;
- v2a = (edge_a->which_edge + 1) % 3;
- } else {
- v2a = edge_a->which_edge % 3;
- v1a = (edge_a->which_edge + 1) % 3;
- }
- if(edge_b->which_edge < 3) {
- v1b = edge_b->which_edge;
- v2b = (edge_b->which_edge + 1) % 3;
- } else {
- v2b = edge_b->which_edge % 3;
- v1b = (edge_b->which_edge + 1) % 3;
- }
- /* Of the first pair, which vertex, if any, should be changed */
- if(!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];
- }
- }
- /* 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];
- }
- }
- }
- static void
- 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] =
- 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("\
- in stl_remove_facet: neighbor = %d numfacets = %d this is wrong\n",
- stl->neighbors_start[neighbor[i]].neighbor[(vnot[i] + 1)% 3],
- stl->stats.number_of_facets);
- return;
- }
- stl->neighbors_start[neighbor[i]].neighbor[(vnot[i] + 1)% 3]
- = facet_number;
- }
- }
- }
- void
- stl_remove_unconnected_facets(stl_file *stl) {
- /* A couple of things need to be done here. One is to remove any */
- /* completely unconnected facets (0 edges connected) since these are */
- /* useless and could be completely wrong. The second thing that needs to */
- /* be done is to remove any degenerate facets that were created during */
- /* stl_check_facets_nearby(). */
- int 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) {
- int edge1;
- int edge2;
- int edge3;
- int neighbor1;
- int neighbor2;
- int neighbor3;
- int vnot1;
- int vnot2;
- int vnot3;
- if (stl->error) 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);
- }
- neighbor3 = stl->neighbors_start[facet].neighbor[edge3];
- vnot1 = stl->neighbors_start[facet].which_vertex_not[edge1];
- vnot2 = stl->neighbors_start[facet].which_vertex_not[edge2];
- vnot3 = stl->neighbors_start[facet].which_vertex_not[edge3];
- if(neighbor1 >= 0){
- stl->neighbors_start[neighbor1].neighbor[(vnot1 + 1) % 3] = neighbor2;
- stl->neighbors_start[neighbor1].which_vertex_not[(vnot1 + 1) % 3] = vnot2;
- }
- if(neighbor2 >= 0){
- stl->neighbors_start[neighbor2].neighbor[(vnot2 + 1) % 3] = neighbor1;
- stl->neighbors_start[neighbor2].which_vertex_not[(vnot2 + 1) % 3] = vnot1;
- }
- stl_remove_facet(stl, facet);
- if(neighbor3 >= 0) {
- stl_update_connects_remove_1(stl, neighbor3);
- stl->neighbors_start[neighbor3].neighbor[(vnot3 + 1) % 3] = -1;
- }
- }
- void
- stl_update_connects_remove_1(stl_file *stl, int facet_num) {
- int j;
- if (stl->error) return;
- /* Update list of connected edges */
- j = ((stl->neighbors_start[facet_num].neighbor[0] == -1) +
- (stl->neighbors_start[facet_num].neighbor[1] == -1) +
- (stl->neighbors_start[facet_num].neighbor[2] == -1));
- if(j == 0) { /* Facet has 3 neighbors */
- stl->stats.connected_facets_3_edge -= 1;
- } else if(j == 1) { /* Facet has 2 neighbors */
- stl->stats.connected_facets_2_edge -= 1;
- } else if(j == 2) { /* Facet has 1 neighbor */
- stl->stats.connected_facets_1_edge -= 1;
- }
- }
- void
- stl_fill_holes(stl_file *stl) {
- stl_facet facet;
- stl_facet new_facet;
- int neighbors_initial[3];
- stl_hash_edge edge;
- int first_facet;
- int direction;
- int facet_num;
- int vnot;
- int next_edge;
- int pivot_vertex;
- int next_facet;
- int i;
- 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];
- 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;
- }
- 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");
- return;
- }
- }
- }
- }
- }
- void
- stl_add_facet(stl_file *stl, stl_facet *new_facet) {
- if (stl->error) return;
- stl->stats.facets_added += 1;
- if(stl->stats.facets_malloced < 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;
- stl->stats.number_of_facets += 1;
- }
|