Merge pull request #2278 from hroncok/admesh98

Updated to admesh 0.98.1
This commit is contained in:
Alessandro Ranellucci 2014-11-24 15:36:26 +01:00
commit 945567d1f3
8 changed files with 1940 additions and 1973 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,21 +1,23 @@
/* ADMesh -- process triangulated solid meshes /* ADMesh -- process triangulated solid meshes
* Copyright (C) 1995 Anthony D. Martin * 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 * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option) * the Free Software Foundation; either version 2 of the License, or
* any later version. * (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * 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 * Questions, comments, suggestions, etc to
* along with this program; if not, write to the Free Software * https://github.com/admesh/admesh/issues
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Questions, comments, suggestions, etc to <amartin@engr.csulb.edu>
*/ */
#include <stdio.h> #include <stdio.h>
@ -26,20 +28,18 @@
#include "stl.h" #include "stl.h"
static void stl_reverse_facet(stl_file *stl, int facet_num); 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[]); static void stl_reverse_vector(float v[]);
int stl_check_normal_vector(stl_file *stl, int facet_num, int normal_fix_flag); int stl_check_normal_vector(stl_file *stl, int facet_num, int normal_fix_flag);
static void static void
stl_reverse_facet(stl_file *stl, int facet_num) stl_reverse_facet(stl_file *stl, int facet_num) {
{
stl_vertex tmp_vertex; stl_vertex tmp_vertex;
/* int tmp_neighbor;*/ /* int tmp_neighbor;*/
int neighbor[3]; int neighbor[3];
int vnot[3]; int vnot[3];
stl->stats.facets_reversed += 1; stl->stats.facets_reversed += 1;
neighbor[0] = stl->neighbors_start[facet_num].neighbor[0]; neighbor[0] = stl->neighbors_start[facet_num].neighbor[0];
neighbor[1] = stl->neighbors_start[facet_num].neighbor[1]; neighbor[1] = stl->neighbors_start[facet_num].neighbor[1];
neighbor[2] = stl->neighbors_start[facet_num].neighbor[2]; 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 */ /* reverse the facet */
tmp_vertex = stl->facet_start[facet_num].vertex[0]; 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];
stl->facet_start[facet_num].vertex[1] = tmp_vertex; stl->facet_start[facet_num].vertex[1] = tmp_vertex;
/* fix the vnots of the neighboring facets */ /* fix the vnots of the neighboring facets */
if(neighbor[0] != -1) 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] =
(stl->neighbors_start[neighbor[0]]. (stl->neighbors_start[neighbor[0]].
which_vertex_not[(vnot[0] + 1) % 3] + 3) % 6; which_vertex_not[(vnot[0] + 1) % 3] + 3) % 6;
if(neighbor[1] != -1) 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] =
(stl->neighbors_start[neighbor[1]]. (stl->neighbors_start[neighbor[1]].
which_vertex_not[(vnot[1] + 1) % 3] + 4) % 6; which_vertex_not[(vnot[1] + 1) % 3] + 4) % 6;
if(neighbor[2] != -1) 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] =
(stl->neighbors_start[neighbor[2]]. (stl->neighbors_start[neighbor[2]].
which_vertex_not[(vnot[2] + 1) % 3] + 2) % 6; which_vertex_not[(vnot[2] + 1) % 3] + 2) % 6;
/* swap the neighbors of the facet that is being reversed */ /* swap the neighbors of the facet that is being reversed */
stl->neighbors_start[facet_num].neighbor[1] = neighbor[2]; stl->neighbors_start[facet_num].neighbor[1] = neighbor[2];
@ -85,8 +85,7 @@ stl_reverse_facet(stl_file *stl, int facet_num)
} }
void void
stl_fix_normal_directions(stl_file *stl) stl_fix_normal_directions(stl_file *stl) {
{
char *norm_sw; char *norm_sw;
/* int edge_num;*/ /* int edge_num;*/
/* int vnot;*/ /* int vnot;*/
@ -95,9 +94,7 @@ stl_fix_normal_directions(stl_file *stl)
/* int next_facet;*/ /* int next_facet;*/
int i; int i;
int j; int j;
int checked_before = 0; struct stl_normal {
struct stl_normal
{
int facet_num; int facet_num;
struct stl_normal *next; struct stl_normal *next;
}; };
@ -105,12 +102,13 @@ stl_fix_normal_directions(stl_file *stl)
struct stl_normal *tail; struct stl_normal *tail;
struct stl_normal *newn; struct stl_normal *newn;
struct stl_normal *temp; struct stl_normal *temp;
if (stl->error) return;
/* Initialize linked list. */ /* 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"); 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"); if(tail == NULL) perror("stl_fix_normal_directions");
head->next = tail; head->next = tail;
tail->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. */ /* Initialize list that keeps track of already fixed facets. */
norm_sw = (char*)calloc(stl->stats.number_of_facets, sizeof(char)); norm_sw = (char*)calloc(stl->stats.number_of_facets, sizeof(char));
if(norm_sw == NULL) perror("stl_fix_normal_directions"); if(norm_sw == NULL) perror("stl_fix_normal_directions");
facet_num = 0; facet_num = 0;
//If normal vector is not within tolerance and backwards: /* 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 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: of it being wrong randomly are low if most of the triangles are right: */
if(stl_check_normal_vector(stl, 0, 0) == 2) if(stl_check_normal_vector(stl, 0, 0) == 2)
stl_reverse_facet(stl, 0); stl_reverse_facet(stl, 0);
//Say that we've fixed this facet: /* Say that we've fixed this facet: */
norm_sw[facet_num] = 1; norm_sw[facet_num] = 1;
/* edge_num = 0;
vnot = stl->neighbors_start[0].which_vertex_not[0];
*/
checked++; checked++;
for(;;) for(;;) {
{ /* Add neighbors_to_list.
/* Add neighbors_to_list. */ Add unconnected neighbors to the list:a */
//Add unconnected neighbors to the list:a for(j = 0; j < 3; j++) {
for(j = 0; j < 3; j++) /* Reverse the neighboring facets if necessary. */
{ if(stl->neighbors_start[facet_num].which_vertex_not[j] > 2) {
/* Reverse the neighboring facets if necessary. */ /* 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].which_vertex_not[j] > 2) if(stl->neighbors_start[facet_num].neighbor[j] != -1) {
{ stl_reverse_facet
// If the facet has a neighbor that is -1, it means that edge isn't shared by another (stl, stl->neighbors_start[facet_num].neighbor[j]);
// facet. }
if(stl->neighbors_start[facet_num].neighbor[j] != -1) }
{ /* If this edge of the facet is connected: */
stl_reverse_facet if(stl->neighbors_start[facet_num].neighbor[j] != -1) {
(stl, stl->neighbors_start[facet_num].neighbor[j]); /* 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. */
//If this edge of the facet is connected: newn = (struct stl_normal*)malloc(sizeof(struct stl_normal));
if(stl->neighbors_start[facet_num].neighbor[j] != -1) if(newn == NULL) perror("stl_fix_normal_directions");
{ newn->facet_num = stl->neighbors_start[facet_num].neighbor[j];
//If we haven't fixed this facet yet, add it to the list: newn->next = head->next;
if(norm_sw[stl->neighbors_start[facet_num].neighbor[j]] != 1) head->next = newn;
{ }
/* 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;
}
}
}
}
} }
/* 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(head);
free(tail); free(tail);
free(norm_sw); free(norm_sw);
} }
int 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 0 if the normal is within tolerance */
/* Returns 1 if the normal is not within tolerance, but direction is OK */ /* 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 2 if the normal is not within tolerance and backwards */
/* Returns 4 if the status is unknown. */ /* Returns 4 if the status is unknown. */
float normal[3]; float normal[3];
float test_norm[3]; float test_norm[3];
stl_facet *facet; 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_calculate_normal(normal, facet);
stl_normalize_vector(normal); stl_normalize_vector(normal);
if( (ABS(normal[0] - facet->normal.x) < 0.001) if( (ABS(normal[0] - facet->normal.x) < 0.001)
&& (ABS(normal[1] - facet->normal.y) < 0.001) && (ABS(normal[1] - facet->normal.y) < 0.001)
&& (ABS(normal[2] - facet->normal.z) < 0.001)) && (ABS(normal[2] - facet->normal.z) < 0.001)) {
{ /* It is not really necessary to change the values here */
/* It is not really necessary to change the values here */ /* but just for consistency, I will. */
/* but just for consistency, I will. */ facet->normal.x = normal[0];
facet->normal.x = normal[0]; facet->normal.y = normal[1];
facet->normal.y = normal[1]; facet->normal.z = normal[2];
facet->normal.z = normal[2]; return 0;
return 0; }
}
test_norm[0] = facet->normal.x; test_norm[0] = facet->normal.x;
test_norm[1] = facet->normal.y; test_norm[1] = facet->normal.y;
test_norm[2] = facet->normal.z; test_norm[2] = facet->normal.z;
stl_normalize_vector(test_norm); stl_normalize_vector(test_norm);
if( (ABS(normal[0] - test_norm[0]) < 0.001) if( (ABS(normal[0] - test_norm[0]) < 0.001)
&& (ABS(normal[1] - test_norm[1]) < 0.001) && (ABS(normal[1] - test_norm[1]) < 0.001)
&& (ABS(normal[2] - test_norm[2]) < 0.001)) && (ABS(normal[2] - test_norm[2]) < 0.001)) {
{ if(normal_fix_flag) {
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.x = normal[0];
facet->normal.y = normal[1]; facet->normal.y = normal[1];
facet->normal.z = normal[2]; facet->normal.z = normal[2];
stl->stats.normals_fixed += 1; 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; return 4;
} }
static void static void
stl_reverse_vector(float v[]) stl_reverse_vector(float v[]) {
{
v[0] *= -1; v[0] *= -1;
v[1] *= -1; v[1] *= -1;
v[2] *= -1; v[2] *= -1;
@ -300,8 +268,7 @@ stl_reverse_vector(float v[])
void void
stl_calculate_normal(float normal[], stl_facet *facet) stl_calculate_normal(float normal[], stl_facet *facet) {
{
float v1[3]; float v1[3];
float v2[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]); normal[2] = (float)((double)v1[0] * (double)v2[1]) - ((double)v1[1] * (double)v2[0]);
} }
/* void stl_normalize_vector(float v[]) {
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[])
{
double length; double length;
double factor; double factor;
float min_normal_length; float min_normal_length;
length = sqrt((double)v[0] * (double)v[0] + (double)v[1] * (double)v[1] + (double)v[2] * (double)v[2]); 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; min_normal_length = 0.000000000001;
if(length < min_normal_length) if(length < min_normal_length) {
{ v[0] = 0.0;
v[0] = 0.0; v[1] = 0.0;
v[1] = 0.0; v[2] = 0.0;
v[2] = 0.0; return;
return; }
}
factor = 1.0 / length; factor = 1.0 / length;
v[0] *= factor; v[0] *= factor;
v[1] *= factor; v[1] *= factor;
@ -371,30 +304,30 @@ void stl_normalize_vector(float v[])
} }
void void
stl_fix_normal_values(stl_file *stl) stl_fix_normal_values(stl_file *stl) {
{
int i; int i;
for(i = 0; i < stl->stats.number_of_facets; i++) if (stl->error) return;
{
stl_check_normal_vector(stl, i, 1); for(i = 0; i < stl->stats.number_of_facets; i++) {
} stl_check_normal_vector(stl, i, 1);
}
} }
void void
stl_reverse_all_facets(stl_file *stl) stl_reverse_all_facets(stl_file *stl) {
{
int i; int i;
float normal[3]; float normal[3];
for(i = 0; i < stl->stats.number_of_facets; i++) if (stl->error) return;
{
stl_reverse_facet(stl, i); for(i = 0; i < stl->stats.number_of_facets; i++) {
stl_calculate_normal(normal, &stl->facet_start[i]); stl_reverse_facet(stl, i);
stl_normalize_vector(normal); stl_calculate_normal(normal, &stl->facet_start[i]);
stl->facet_start[i].normal.x = normal[0]; stl_normalize_vector(normal);
stl->facet_start[i].normal.y = normal[1]; stl->facet_start[i].normal.x = normal[0];
stl->facet_start[i].normal.z = normal[2]; stl->facet_start[i].normal.y = normal[1];
} stl->facet_start[i].normal.z = normal[2];
}
} }

View File

@ -1,44 +1,46 @@
/* ADMesh -- process triangulated solid meshes /* ADMesh -- process triangulated solid meshes
* Copyright (C) 1995, 1996 Anthony D. Martin * 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 * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option) * the Free Software Foundation; either version 2 of the License, or
* any later version. * (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * 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 * Questions, comments, suggestions, etc to
* along with this program; if not, write to the Free Software * https://github.com/admesh/admesh/issues
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Questions, comments, suggestions, etc to <amartin@engr.csulb.edu>
*/ */
#include <cstring>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include "stl.h" #include "stl.h"
void void
stl_invalidate_shared_vertices(stl_file *stl) stl_invalidate_shared_vertices(stl_file *stl) {
{ if (stl->error) return;
if (stl->v_indices != NULL) {
free(stl->v_indices); if (stl->v_indices != NULL) {
stl->v_indices = NULL; free(stl->v_indices);
} stl->v_indices = NULL;
if (stl->v_shared != NULL) { }
free(stl->v_shared); if (stl->v_shared != NULL) {
stl->v_shared = NULL; free(stl->v_shared);
} stl->v_shared = NULL;
}
} }
void void
stl_generate_shared_vertices(stl_file *stl) stl_generate_shared_vertices(stl_file *stl) {
{
int i; int i;
int j; int j;
int first_facet; int first_facet;
@ -49,175 +51,152 @@ stl_generate_shared_vertices(stl_file *stl)
int pivot_vertex; int pivot_vertex;
int next_facet; int next_facet;
int reversed; 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_invalidate_shared_vertices(stl);
stl->v_indices = (v_indices_struct*) 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"); if(stl->v_indices == NULL) perror("stl_generate_shared_vertices");
stl->v_shared = (stl_vertex*) 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"); if(stl->v_shared == NULL) perror("stl_generate_shared_vertices");
stl->stats.shared_malloced = stl->stats.number_of_facets / 2; stl->stats.shared_malloced = stl->stats.number_of_facets / 2;
stl->stats.shared_vertices = 0; stl->stats.shared_vertices = 0;
for(i = 0; i < stl->stats.number_of_facets; i++) for(i = 0; i < stl->stats.number_of_facets; i++) {
{ stl->v_indices[i].vertex[0] = -1;
stl->v_indices[i].vertex[0] = -1; stl->v_indices[i].vertex[1] = -1;
stl->v_indices[i].vertex[1] = -1; stl->v_indices[i].vertex[2] = -1;
stl->v_indices[i].vertex[2] = -1; }
}
for(i = 0; i < stl->stats.number_of_facets; i++) {
for(i = 0; i < stl->stats.number_of_facets; i++) first_facet = i;
{ for(j = 0; j < 3; j++) {
first_facet = i; if(stl->v_indices[i].vertex[j] != -1) {
for(j = 0; j < 3; j++) continue;
{ }
if(stl->v_indices[i].vertex[j] != -1) if(stl->stats.shared_vertices == stl->stats.shared_malloced) {
{ stl->stats.shared_malloced += 1024;
continue; stl->v_shared = (stl_vertex*)realloc(stl->v_shared,
} stl->stats.shared_malloced * sizeof(stl_vertex));
if(stl->stats.shared_vertices == stl->stats.shared_malloced) if(stl->v_shared == NULL) perror("stl_generate_shared_vertices");
{ }
stl->stats.shared_malloced += 1024;
stl->v_shared = (stl_vertex*)realloc(stl->v_shared, stl->v_shared[stl->stats.shared_vertices] =
stl->stats.shared_malloced * sizeof(stl_vertex)); stl->facet_start[i].vertex[j];
if(stl->v_shared == NULL) perror("stl_generate_shared_vertices");
} direction = 0;
reversed = 0;
stl->v_shared[stl->stats.shared_vertices] = facet_num = i;
stl->facet_start[i].vertex[j]; vnot = (j + 2) % 3;
direction = 0; for(;;) {
reversed = 0; if(vnot > 2) {
facet_num = i; if(direction == 0) {
vnot = (j + 2) % 3; pivot_vertex = (vnot + 2) % 3;
next_edge = pivot_vertex;
for(;;) direction = 1;
{ } else {
if(vnot > 2) pivot_vertex = (vnot + 1) % 3;
{ next_edge = vnot % 3;
if(direction == 0) direction = 0;
{ }
pivot_vertex = (vnot + 2) % 3; } else {
next_edge = pivot_vertex; if(direction == 0) {
direction = 1; pivot_vertex = (vnot + 1) % 3;
} next_edge = vnot;
else } else {
{ pivot_vertex = (vnot + 2) % 3;
pivot_vertex = (vnot + 1) % 3; next_edge = pivot_vertex;
next_edge = vnot % 3; }
direction = 0; }
} stl->v_indices[facet_num].vertex[pivot_vertex] =
} stl->stats.shared_vertices;
else
{ next_facet = stl->neighbors_start[facet_num].neighbor[next_edge];
if(direction == 0) if(next_facet == -1) {
{ if(reversed) {
pivot_vertex = (vnot + 1) % 3; break;
next_edge = vnot; } else {
} direction = 1;
else vnot = (j + 1) % 3;
{ reversed = 1;
pivot_vertex = (vnot + 2) % 3; facet_num = first_facet;
next_edge = pivot_vertex; }
} } else if(next_facet != first_facet) {
} vnot = stl->neighbors_start[facet_num].
stl->v_indices[facet_num].vertex[pivot_vertex] = which_vertex_not[next_edge];
stl->stats.shared_vertices; facet_num = next_facet;
} else {
next_facet = stl->neighbors_start[facet_num].neighbor[next_edge]; break;
if(next_facet == -1) }
{ }
if(reversed) stl->stats.shared_vertices += 1;
{
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 void
stl_write_off(stl_file *stl, char *file) stl_write_off(stl_file *stl, char *file) {
{
int i; int i;
FILE *fp; FILE *fp;
char *error_msg; char *error_msg;
if (stl->error) return;
/* Open the file */ /* Open the file */
fp = fopen(file, "w"); fp = fopen(file, "w");
if(fp == NULL) if(fp == NULL) {
{ error_msg = (char*)
error_msg = (char*) malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */
malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */ sprintf(error_msg, "stl_write_ascii: Couldn't open %s for writing",
sprintf(error_msg, "stl_write_ascii: Couldn't open %s for writing", file);
file); perror(error_msg);
perror(error_msg); free(error_msg);
free(error_msg); stl->error = 1;
exit(1); return;
} }
fprintf(fp, "OFF\n"); fprintf(fp, "OFF\n");
fprintf(fp, "%d %d 0\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++) for(i = 0; i < stl->stats.shared_vertices; i++) {
{ fprintf(fp, "\t%f %f %f\n",
fprintf(fp, "\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); }
} for(i = 0; i < stl->stats.number_of_facets; i++) {
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]);
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); fclose(fp);
} }
void void
stl_write_vrml(stl_file *stl, char *file) stl_write_vrml(stl_file *stl, char *file) {
{
int i; int i;
FILE *fp; FILE *fp;
char *error_msg; char *error_msg;
if (stl->error) return;
/* Open the file */ /* Open the file */
fp = fopen(file, "w"); fp = fopen(file, "w");
if(fp == NULL) if(fp == NULL) {
{ error_msg = (char*)
error_msg = (char*) malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */
malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */ sprintf(error_msg, "stl_write_ascii: Couldn't open %s for writing",
sprintf(error_msg, "stl_write_ascii: Couldn't open %s for writing", file);
file); perror(error_msg);
perror(error_msg); free(error_msg);
free(error_msg); stl->error = 1;
exit(1); return;
} }
fprintf(fp, "#VRML V1.0 ascii\n\n"); fprintf(fp, "#VRML V1.0 ascii\n\n");
fprintf(fp, "Separator {\n"); fprintf(fp, "Separator {\n");
fprintf(fp, "\tDEF STLShape ShapeHints {\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\tDEF STLVertices Coordinate3 {\n");
fprintf(fp, "\t\t\tpoint [\n"); fprintf(fp, "\t\t\tpoint [\n");
for(i = 0; i < (stl->stats.shared_vertices - 1); i++) for(i = 0; i < (stl->stats.shared_vertices - 1); i++) {
{ fprintf(fp, "\t\t\t\t%f %f %f,\n",
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\t\t%f %f %f]\n", 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\t}\n");
fprintf(fp, "\t\tDEF STLTriangles IndexedFaceSet {\n"); fprintf(fp, "\t\tDEF STLTriangles IndexedFaceSet {\n");
fprintf(fp, "\t\t\tcoordIndex [\n"); fprintf(fp, "\t\t\tcoordIndex [\n");
for(i = 0; i < (stl->stats.number_of_facets - 1); i++) 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],
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\t\t%d, %d, %d, -1]\n", stl->v_indices[i].vertex[0], 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\t}\n");
fprintf(fp, "\t}\n"); fprintf(fp, "\t}\n");
fprintf(fp, "}\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) { void stl_write_obj (stl_file *stl, char *file) {
int i; int i;
FILE* fp;
/* Open the file */
FILE* fp = fopen(file, "w"); if (stl->error) return;
if (fp == NULL) {
char* error_msg = (char*)malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */ /* Open the file */
sprintf(error_msg, "stl_write_ascii: Couldn't open %s for writing", file); fp = fopen(file, "w");
perror(error_msg); if (fp == NULL) {
free(error_msg); char* error_msg = (char*)malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */
exit(1); sprintf(error_msg, "stl_write_ascii: Couldn't open %s for writing", file);
} perror(error_msg);
free(error_msg);
for (i = 0; i < stl->stats.shared_vertices; i++) { stl->error = 1;
fprintf(fp, "v %f %f %f\n", stl->v_shared[i].x, stl->v_shared[i].y, stl->v_shared[i].z); return;
} }
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); 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);
}
fclose(fp); 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);
} }

View File

@ -1,25 +1,34 @@
/* ADMesh -- process triangulated solid meshes /* ADMesh -- process triangulated solid meshes
* Copyright (C) 1995, 1996 Anthony D. Martin * 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 * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option) * the Free Software Foundation; either version 2 of the License, or
* any later version. * (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * 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 * Questions, comments, suggestions, etc to
* along with this program; if not, write to the Free Software * https://github.com/admesh/admesh/issues
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Questions, comments, suggestions, etc to <amartin@engr.csulb.edu>
*/ */
#ifndef __admesh_stl__
#define __admesh_stl__
#include <stdio.h> #include <stdio.h>
#ifdef __cplusplus
extern "C" {
#endif
#define STL_MAX(A,B) ((A)>(B)? (A):(B)) #define STL_MAX(A,B) ((A)>(B)? (A):(B))
#define STL_MIN(A,B) ((A)<(B)? (A):(B)) #define STL_MIN(A,B) ((A)<(B)? (A):(B))
#define ABS(X) ((X) < 0 ? -(X) : (X)) #define ABS(X) ((X) < 0 ? -(X) : (X))
@ -31,60 +40,52 @@
#define ASCII_LINES_PER_FACET 7 #define ASCII_LINES_PER_FACET 7
#define SIZEOF_EDGE_SORT 24 #define SIZEOF_EDGE_SORT 24
typedef struct typedef struct {
{
float x; float x;
float y; float y;
float z; float z;
}stl_vertex; } stl_vertex;
typedef struct typedef struct {
{
float x; float x;
float y; float y;
float z; float z;
}stl_normal; } stl_normal;
typedef char stl_extra[2]; typedef char stl_extra[2];
typedef struct typedef struct {
{
stl_normal normal; stl_normal normal;
stl_vertex vertex[3]; stl_vertex vertex[3];
stl_extra extra; stl_extra extra;
}stl_facet; } stl_facet;
#define SIZEOF_STL_FACET 50 #define SIZEOF_STL_FACET 50
typedef enum {binary, ascii, inmemory} stl_type; typedef enum {binary, ascii, inmemory} stl_type;
typedef struct typedef struct {
{
stl_vertex p1; stl_vertex p1;
stl_vertex p2; stl_vertex p2;
int facet_number; int facet_number;
}stl_edge; } stl_edge;
typedef struct stl_hash_edge typedef struct stl_hash_edge {
{
unsigned key[6]; unsigned key[6];
int facet_number; int facet_number;
int which_edge; int which_edge;
struct stl_hash_edge *next; struct stl_hash_edge *next;
}stl_hash_edge; } stl_hash_edge;
typedef struct typedef struct {
{
int neighbor[3]; int neighbor[3];
char which_vertex_not[3]; char which_vertex_not[3];
}stl_neighbors; } stl_neighbors;
typedef struct typedef struct {
{
int vertex[3]; int vertex[3];
}v_indices_struct; } v_indices_struct;
typedef struct typedef struct {
{
char header[81]; char header[81];
stl_type type; stl_type type;
int number_of_facets; int number_of_facets;
@ -117,10 +118,9 @@ typedef struct
int collisions; int collisions;
int shared_vertices; int shared_vertices;
int shared_malloced; int shared_malloced;
}stl_stats; } stl_stats;
typedef struct typedef struct {
{
FILE *fp; FILE *fp;
stl_facet *facet_start; stl_facet *facet_start;
stl_edge *edge_start; stl_edge *edge_start;
@ -131,7 +131,8 @@ typedef struct
v_indices_struct *v_indices; v_indices_struct *v_indices;
stl_vertex *v_shared; stl_vertex *v_shared;
stl_stats stats; stl_stats stats;
}stl_file; char error;
} stl_file;
extern void stl_open(stl_file *stl, char *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_stats_out(stl_file *stl, FILE *file, char *input_file);
extern void stl_print_edges(stl_file *stl, FILE *file); extern void stl_print_edges(stl_file *stl, FILE *file);
extern void stl_print_neighbors(stl_file *stl, char *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_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(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_exact(stl_file *stl);
extern void stl_check_facets_nearby(stl_file *stl, float tolerance); extern void stl_check_facets_nearby(stl_file *stl, float tolerance);
extern void stl_remove_unconnected_facets(stl_file *stl); 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_directions(stl_file *stl);
extern void stl_fix_normal_values(stl_file *stl); extern void stl_fix_normal_values(stl_file *stl);
extern void stl_reverse_all_facets(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_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_versor(stl_file *stl, float versor[3]);
extern void stl_scale(stl_file *stl, float factor); 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_normalize_vector(float v[]);
extern void stl_calculate_volume(stl_file *stl); extern void stl_calculate_volume(stl_file *stl);
extern void stl_repair(stl_file *stl, int fixall_flag, int exact_flag, int tolerance_flag, float tolerance, int increment_flag, float increment, int nearby_flag, int iterations, int remove_unconnected_flag, int fill_holes_flag, int normal_directions_flag, int normal_values_flag, int reverse_all_flag, int verbose_flag);
extern void stl_initialize(stl_file *stl); extern void stl_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); 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_facet_stats(stl_file *stl, stl_facet facet, int first);
extern void stl_reallocate(stl_file *stl); extern void stl_reallocate(stl_file *stl);
extern void stl_add_facet(stl_file *stl, stl_facet *new_facet); extern void stl_add_facet(stl_file *stl, stl_facet *new_facet);
extern void stl_get_size(stl_file *stl); 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

View File

@ -1,26 +1,29 @@
/* ADMesh -- process triangulated solid meshes /* ADMesh -- process triangulated solid meshes
* Copyright (C) 1995, 1996 Anthony D. Martin * 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 * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option) * the Free Software Foundation; either version 2 of the License, or
* any later version. * (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * 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 * Questions, comments, suggestions, etc to
* along with this program; if not, write to the Free Software * https://github.com/admesh/admesh/issues
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Questions, comments, suggestions, etc to <amartin@engr.csulb.edu>
*/ */
#include <cstring>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include "stl.h" #include "stl.h"
#include "config.h"
#if !defined(SEEK_SET) #if !defined(SEEK_SET)
#define SEEK_SET 0 #define SEEK_SET 0
@ -28,82 +31,82 @@
#define SEEK_END 2 #define SEEK_END 2
#endif #endif
static void stl_put_little_int(FILE *fp, int value);
static void stl_put_little_float(FILE *fp, float value_in);
void void
stl_print_edges(stl_file *stl, FILE *file) stl_print_edges(stl_file *stl, FILE *file) {
{
int i; int i;
int edges_allocated; int edges_allocated;
if (stl->error) return;
edges_allocated = stl->stats.number_of_facets * 3; edges_allocated = stl->stats.number_of_facets * 3;
for(i = 0; i < edges_allocated; i++) for(i = 0; i < edges_allocated; i++) {
{ fprintf(file, "%d, %f, %f, %f, %f, %f, %f\n",
fprintf(file, "%d, %f, %f, %f, %f, %f, %f\n", stl->edge_start[i].facet_number,
stl->edge_start[i].facet_number, stl->edge_start[i].p1.x, stl->edge_start[i].p1.y,
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].p1.z, stl->edge_start[i].p2.x, stl->edge_start[i].p2.y, stl->edge_start[i].p2.z);
stl->edge_start[i].p2.y, stl->edge_start[i].p2.z); }
}
} }
void 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\ fprintf(file, "\n\
================= Results produced by ADMesh version 0.95 ================\n"); ================= Results produced by ADMesh version " VERSION " ================\n");
fprintf(file, "\ fprintf(file, "\
Input file : %s\n", input_file); Input file : %s\n", input_file);
if(stl->stats.type == binary) if(stl->stats.type == binary) {
{ fprintf(file, "\
fprintf(file, "\
File type : Binary STL file\n"); File type : Binary STL file\n");
} } else {
else fprintf(file, "\
{
fprintf(file, "\
File type : ASCII STL file\n"); File type : ASCII STL file\n");
} }
fprintf(file, "\ fprintf(file, "\
Header : %s\n", stl->stats.header); Header : %s\n", stl->stats.header);
fprintf(file, "============== Size ==============\n"); fprintf(file, "============== Size ==============\n");
fprintf(file, "Min X = % f, Max X = % f\n", fprintf(file, "Min X = % f, Max X = % f\n",
stl->stats.min.x, stl->stats.max.x); stl->stats.min.x, stl->stats.max.x);
fprintf(file, "Min Y = % f, Max Y = % f\n", fprintf(file, "Min Y = % f, Max Y = % f\n",
stl->stats.min.y, stl->stats.max.y); stl->stats.min.y, stl->stats.max.y);
fprintf(file, "Min Z = % f, Max Z = % f\n", fprintf(file, "Min Z = % f, Max Z = % f\n",
stl->stats.min.z, stl->stats.max.z); stl->stats.min.z, stl->stats.max.z);
fprintf(file, "\ fprintf(file, "\
========= Facet Status ========== Original ============ Final ====\n"); ========= Facet Status ========== Original ============ Final ====\n");
fprintf(file, "\ fprintf(file, "\
Number of facets : %5d %5d\n", Number of facets : %5d %5d\n",
stl->stats.original_num_facets, stl->stats.number_of_facets); stl->stats.original_num_facets, stl->stats.number_of_facets);
fprintf(file, "\ fprintf(file, "\
Facets with 1 disconnected edge : %5d %5d\n", Facets with 1 disconnected edge : %5d %5d\n",
stl->stats.facets_w_1_bad_edge, stl->stats.connected_facets_2_edge - stl->stats.facets_w_1_bad_edge, stl->stats.connected_facets_2_edge -
stl->stats.connected_facets_3_edge); stl->stats.connected_facets_3_edge);
fprintf(file, "\ fprintf(file, "\
Facets with 2 disconnected edges : %5d %5d\n", Facets with 2 disconnected edges : %5d %5d\n",
stl->stats.facets_w_2_bad_edge, stl->stats.connected_facets_1_edge - stl->stats.facets_w_2_bad_edge, stl->stats.connected_facets_1_edge -
stl->stats.connected_facets_2_edge); stl->stats.connected_facets_2_edge);
fprintf(file, "\ fprintf(file, "\
Facets with 3 disconnected edges : %5d %5d\n", Facets with 3 disconnected edges : %5d %5d\n",
stl->stats.facets_w_3_bad_edge, stl->stats.number_of_facets - stl->stats.facets_w_3_bad_edge, stl->stats.number_of_facets -
stl->stats.connected_facets_1_edge); stl->stats.connected_facets_1_edge);
fprintf(file, "\ fprintf(file, "\
Total disconnected facets : %5d %5d\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_1_bad_edge + stl->stats.facets_w_2_bad_edge +
stl->stats.facets_w_3_bad_edge, stl->stats.number_of_facets - stl->stats.facets_w_3_bad_edge, stl->stats.number_of_facets -
stl->stats.connected_facets_3_edge); stl->stats.connected_facets_3_edge);
fprintf(file, fprintf(file,
"=== Processing Statistics === ===== Other Statistics =====\n"); "=== Processing Statistics === ===== Other Statistics =====\n");
fprintf(file, "\ fprintf(file, "\
Number of parts : %5d Volume : % f\n", 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, "\ fprintf(file, "\
Degenerate facets : %5d\n", stl->stats.degenerate_facets); Degenerate facets : %5d\n", stl->stats.degenerate_facets);
fprintf(file, "\ fprintf(file, "\
@ -121,153 +124,123 @@ Normals fixed : %5d\n", stl->stats.normals_fixed);
} }
void 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; int i;
FILE *fp; FILE *fp;
char *error_msg; char *error_msg;
if (stl->error) return;
/* Open the file */ /* Open the file */
fp = fopen(file, "w"); fp = fopen(file, "w");
if(fp == NULL) if(fp == NULL) {
{ error_msg = (char*)
error_msg = (char*) malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */
malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */ sprintf(error_msg, "stl_write_ascii: Couldn't open %s for writing",
sprintf(error_msg, "stl_write_ascii: Couldn't open %s for writing", file);
file); perror(error_msg);
perror(error_msg); free(error_msg);
free(error_msg); stl->error = 1;
exit(1); return;
} }
fprintf(fp, "solid %s\n", label); fprintf(fp, "solid %s\n", label);
for(i = 0; i < stl->stats.number_of_facets; i++) for(i = 0; i < stl->stats.number_of_facets; i++) {
{ fprintf(fp, " facet normal % .8E % .8E % .8E\n",
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.x, stl->facet_start[i].normal.y, stl->facet_start[i].normal.z);
stl->facet_start[i].normal.z); fprintf(fp, " outer loop\n");
fprintf(fp, " outer loop\n"); fprintf(fp, " vertex % .8E % .8E % .8E\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].x, stl->facet_start[i].vertex[0].y, stl->facet_start[i].vertex[0].z);
stl->facet_start[i].vertex[0].z); fprintf(fp, " vertex % .8E % .8E % .8E\n",
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].x, stl->facet_start[i].vertex[1].y, stl->facet_start[i].vertex[1].z);
stl->facet_start[i].vertex[1].z); fprintf(fp, " vertex % .8E % .8E % .8E\n",
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].x, stl->facet_start[i].vertex[2].y, stl->facet_start[i].vertex[2].z);
stl->facet_start[i].vertex[2].z); fprintf(fp, " endloop\n");
fprintf(fp, " endloop\n"); fprintf(fp, " endfacet\n");
fprintf(fp, " endfacet\n"); }
}
fprintf(fp, "endsolid %s\n", label); fprintf(fp, "endsolid %s\n", label);
fclose(fp); fclose(fp);
} }
void void
stl_print_neighbors(stl_file *stl, char *file) stl_print_neighbors(stl_file *stl, char *file) {
{
int i; int i;
FILE *fp; FILE *fp;
char *error_msg; char *error_msg;
if (stl->error) return;
/* Open the file */ /* Open the file */
fp = fopen(file, "w"); fp = fopen(file, "w");
if(fp == NULL) if(fp == NULL) {
{ error_msg = (char*)
error_msg = (char*) malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */
malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */ sprintf(error_msg, "stl_print_neighbors: Couldn't open %s for writing",
sprintf(error_msg, "stl_print_neighbors: Couldn't open %s for writing", file);
file); perror(error_msg);
perror(error_msg); free(error_msg);
free(error_msg); stl->error = 1;
exit(1); return;
} }
for(i = 0; i < stl->stats.number_of_facets; i++) for(i = 0; i < stl->stats.number_of_facets; i++) {
{ fprintf(fp, "%d, %d,%d, %d,%d, %d,%d\n",
fprintf(fp, "%d, %d,%d, %d,%d, %d,%d\n", i,
i, stl->neighbors_start[i].neighbor[0],
stl->neighbors_start[i].neighbor[0], (int)stl->neighbors_start[i].which_vertex_not[0],
(int)stl->neighbors_start[i].which_vertex_not[0], stl->neighbors_start[i].neighbor[1],
stl->neighbors_start[i].neighbor[1], (int)stl->neighbors_start[i].which_vertex_not[1],
(int)stl->neighbors_start[i].which_vertex_not[1], stl->neighbors_start[i].neighbor[2],
stl->neighbors_start[i].neighbor[2], (int)stl->neighbors_start[i].which_vertex_not[2]);
(int)stl->neighbors_start[i].which_vertex_not[2]); }
} fclose(fp);
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 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;
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);
for(i = 0; i < stl->stats.number_of_facets; i++) for(i = 0; i < stl->stats.number_of_facets; i++)
{ {
stl_put_little_float(fp, stl->facet_start[i].normal.x); 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[0], fp);
fputc(stl->facet_start[i].extra[1], 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); fclose(fp);
} }
void 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, printf(" vertex %d/%d % .8E % .8E % .8E\n", vertex, facet,
stl->facet_start[facet].vertex[vertex].x, stl->facet_start[facet].vertex[vertex].x,
stl->facet_start[facet].vertex[vertex].y, stl->facet_start[facet].vertex[vertex].y,
stl->facet_start[facet].vertex[vertex].z); stl->facet_start[facet].vertex[vertex].z);
} }
void 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); printf("facet (%d)/ %s\n", facet, label);
stl_write_vertex(stl, facet, 0); stl_write_vertex(stl, facet, 0);
stl_write_vertex(stl, facet, 1); stl_write_vertex(stl, facet, 1);
@ -308,36 +312,32 @@ stl_write_facet(stl_file *stl, char *label, int facet)
} }
void 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); printf("edge (%d)/(%d) %s\n", edge.facet_number, edge.which_edge, label);
if(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 % 3); stl_write_vertex(stl, edge.facet_number, (edge.which_edge + 1) % 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);
else stl_write_vertex(stl, edge.facet_number, edge.which_edge % 3);
{ }
stl_write_vertex(stl, edge.facet_number, (edge.which_edge + 1) % 3);
stl_write_vertex(stl, edge.facet_number, edge.which_edge % 3);
}
} }
void 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, printf("Neighbors %d: %d, %d, %d ; %d, %d, %d\n", facet,
stl->neighbors_start[facet].neighbor[0], stl->neighbors_start[facet].neighbor[0],
stl->neighbors_start[facet].neighbor[1], stl->neighbors_start[facet].neighbor[1],
stl->neighbors_start[facet].neighbor[2], stl->neighbors_start[facet].neighbor[2],
stl->neighbors_start[facet].which_vertex_not[0], stl->neighbors_start[facet].which_vertex_not[0],
stl->neighbors_start[facet].which_vertex_not[1], stl->neighbors_start[facet].which_vertex_not[1],
stl->neighbors_start[facet].which_vertex_not[2]); stl->neighbors_start[facet].which_vertex_not[2]);
} }
void void
stl_write_quad_object(stl_file *stl, char *file) stl_write_quad_object(stl_file *stl, char *file) {
{
FILE *fp; FILE *fp;
int i; int i;
int j; int j;
@ -347,19 +347,21 @@ stl_write_quad_object(stl_file *stl, char *file)
stl_vertex uncon_2_color; stl_vertex uncon_2_color;
stl_vertex uncon_3_color; stl_vertex uncon_3_color;
stl_vertex color; stl_vertex color;
if (stl->error) return;
/* Open the file */ /* Open the file */
fp = fopen(file, "w"); fp = fopen(file, "w");
if(fp == NULL) if(fp == NULL) {
{ error_msg = (char*)
error_msg = (char*) malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */
malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */ sprintf(error_msg, "stl_write_quad_object: Couldn't open %s for writing",
sprintf(error_msg, "stl_write_quad_object: Couldn't open %s for writing", file);
file); perror(error_msg);
perror(error_msg); free(error_msg);
free(error_msg); stl->error = 1;
exit(1); return;
} }
connect_color.x = 0.0; connect_color.x = 0.0;
connect_color.y = 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; uncon_3_color.z = 0.0;
fprintf(fp, "CQUAD\n"); fprintf(fp, "CQUAD\n");
for(i = 0; i < stl->stats.number_of_facets; i++) for(i = 0; i < stl->stats.number_of_facets; i++) {
{ j = ((stl->neighbors_start[i].neighbor[0] == -1) +
j = ((stl->neighbors_start[i].neighbor[0] == -1) + (stl->neighbors_start[i].neighbor[1] == -1) +
(stl->neighbors_start[i].neighbor[1] == -1) + (stl->neighbors_start[i].neighbor[2] == -1));
(stl->neighbors_start[i].neighbor[2] == -1)); if(j == 0) {
if(j == 0) color = connect_color;
{ } else if(j == 1) {
color = connect_color; color = uncon_1_color;
} } else if(j == 2) {
else if(j == 1) color = uncon_2_color;
{ } else {
color = uncon_1_color; color = uncon_3_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);
} }
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); fclose(fp);
} }
void void
stl_write_dxf(stl_file *stl, char *file, char *label) stl_write_dxf(stl_file *stl, char *file, char *label) {
{
int i; int i;
FILE *fp; FILE *fp;
char *error_msg; char *error_msg;
if (stl->error) return;
/* Open the file */ /* Open the file */
fp = fopen(file, "w"); fp = fopen(file, "w");
if(fp == NULL) if(fp == NULL) {
{ error_msg = (char*)
error_msg = (char*) malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */
malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */ sprintf(error_msg, "stl_write_ascii: Couldn't open %s for writing",
sprintf(error_msg, "stl_write_ascii: Couldn't open %s for writing", file);
file); perror(error_msg);
perror(error_msg); free(error_msg);
free(error_msg); stl->error = 1;
exit(1); return;
} }
fprintf(fp, "999\n%s\n", label); fprintf(fp, "999\n%s\n", label);
fprintf(fp, "0\nSECTION\n2\nHEADER\n0\nENDSEC\n"); fprintf(fp, "0\nSECTION\n2\nHEADER\n0\nENDSEC\n");
fprintf(fp, "0\nSECTION\n2\nTABLES\n0\nTABLE\n2\nLAYER\n70\n1\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"); 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\nBLOCKS\n0\nENDSEC\n");
fprintf(fp, "0\nSECTION\n2\nENTITIES\n"); fprintf(fp, "0\nSECTION\n2\nENTITIES\n");
for(i = 0; i < stl->stats.number_of_facets; i++) for(i = 0; i < stl->stats.number_of_facets; i++) {
{ fprintf(fp, "0\n3DFACE\n8\n0\n");
fprintf(fp, "0\n3DFACE\n8\n0\n"); fprintf(fp, "10\n%f\n20\n%f\n30\n%f\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].x, stl->facet_start[i].vertex[0].y, stl->facet_start[i].vertex[0].z);
stl->facet_start[i].vertex[0].z); fprintf(fp, "11\n%f\n21\n%f\n31\n%f\n",
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].x, stl->facet_start[i].vertex[1].y, stl->facet_start[i].vertex[1].z);
stl->facet_start[i].vertex[1].z); fprintf(fp, "12\n%f\n22\n%f\n32\n%f\n",
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].x, stl->facet_start[i].vertex[2].y, stl->facet_start[i].vertex[2].z);
stl->facet_start[i].vertex[2].z); fprintf(fp, "13\n%f\n23\n%f\n33\n%f\n",
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].x, stl->facet_start[i].vertex[2].y, stl->facet_start[i].vertex[2].z);
stl->facet_start[i].vertex[2].z); }
}
fprintf(fp, "0\nENDSEC\n0\nEOF\n"); fprintf(fp, "0\nENDSEC\n0\nEOF\n");
fclose(fp); 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;
}

View File

@ -1,21 +1,23 @@
/* ADMesh -- process triangulated solid meshes /* ADMesh -- process triangulated solid meshes
* Copyright (C) 1995, 1996 Anthony D. Martin * 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 * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option) * the Free Software Foundation; either version 2 of the License, or
* any later version. * (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * 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 * Questions, comments, suggestions, etc to
* along with this program; if not, write to the Free Software * https://github.com/admesh/admesh/issues
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Questions, comments, suggestions, etc to <amartin@engr.csulb.edu>
*/ */
#include <stdio.h> #include <stdio.h>
@ -32,19 +34,18 @@
#endif #endif
void void
stl_open(stl_file *stl, char *file) stl_open(stl_file *stl, char *file) {
{
stl_initialize(stl); stl_initialize(stl);
stl_count_facets(stl, file); stl_count_facets(stl, file);
stl_allocate(stl); stl_allocate(stl);
stl_read(stl, 0, 1); stl_read(stl, 0, 1);
fclose(stl->fp); if (!stl->error) fclose(stl->fp);
} }
void void
stl_initialize(stl_file *stl) stl_initialize(stl_file *stl) {
{ stl->error = 0;
stl->stats.degenerate_facets = 0; stl->stats.degenerate_facets = 0;
stl->stats.edges_fixed = 0; stl->stats.edges_fixed = 0;
stl->stats.facets_added = 0; stl->stats.facets_added = 0;
@ -56,276 +57,316 @@ stl_initialize(stl_file *stl)
stl->stats.number_of_facets = 0; stl->stats.number_of_facets = 0;
stl->stats.facets_malloced = 0; stl->stats.facets_malloced = 0;
stl->stats.volume = -1.0; stl->stats.volume = -1.0;
stl->neighbors_start = NULL; stl->neighbors_start = NULL;
stl->facet_start = NULL; stl->facet_start = NULL;
stl->v_indices = NULL; stl->v_indices = NULL;
stl->v_shared = NULL; stl->v_shared = NULL;
} }
static void void
stl_count_facets(stl_file *stl, char *file) stl_count_facets(stl_file *stl, char *file) {
{
long file_size; long file_size;
int header_num_facets; int header_num_facets;
int num_facets; int num_facets;
int i, j; int i, j;
size_t s;
unsigned char chtest[128]; unsigned char chtest[128];
int num_lines = 1; int num_lines = 1;
char *error_msg; char *error_msg;
if (stl->error) return;
/* Open the file */ /* Open the file */
stl->fp = fopen(file, "r"); stl->fp = fopen(file, "r");
if(stl->fp == NULL) if(stl->fp == NULL) {
{ error_msg = (char*)
error_msg = (char*) malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */
malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */ sprintf(error_msg, "stl_initialize: Couldn't open %s for reading",
sprintf(error_msg, "stl_initialize: Couldn't open %s for reading", file);
file); perror(error_msg);
perror(error_msg); free(error_msg);
free(error_msg); stl->error = 1;
exit(1); return;
} }
/* Find size of file */ /* Find size of file */
fseek(stl->fp, 0, SEEK_END); fseek(stl->fp, 0, SEEK_END);
file_size = ftell(stl->fp); file_size = ftell(stl->fp);
/* Check for binary or ASCII file */ /* Check for binary or ASCII file */
fseek(stl->fp, HEADER_SIZE, SEEK_SET); 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; stl->stats.type = ascii;
for(i = 0; i < sizeof(chtest); i++) for(s = 0; s < sizeof(chtest); s++) {
{ if(chtest[s] > 127) {
if(chtest[i] > 127) stl->stats.type = binary;
{ /* close and reopen with binary flag (needed on Windows) */
stl->stats.type = binary; fclose(stl->fp);
// close and reopen with binary flag (needed on Windows) stl->fp = fopen(file, "rb");
fclose(stl->fp); break;
stl->fp = fopen(file, "rb");
break;
}
} }
}
rewind(stl->fp); rewind(stl->fp);
/* Get the header and the number of facets in the .STL file */ /* Get the header and the number of facets in the .STL file */
/* If the .STL file is binary, then do the following */ /* If the .STL file is binary, then do the following */
if(stl->stats.type == binary) if(stl->stats.type == binary) {
{ /* Test if the STL file has the right size */
/* Test if the STL file has the right size */ if(((file_size - HEADER_SIZE) % SIZEOF_STL_FACET != 0)
if(((file_size - HEADER_SIZE) % SIZEOF_STL_FACET != 0) || (file_size < STL_MIN_FILE_SIZE)) {
|| (file_size < STL_MIN_FILE_SIZE)) fprintf(stderr, "The file %s has the wrong size.\n", file);
{ stl->error = 1;
fprintf(stderr, "The file %s has the wrong size.\n", file); return;
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");
}
} }
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 */ /* Otherwise, if the .STL file is ASCII, then do the following */
else else {
{ /* Find the number of facets */
/* Find the number of facets */ j = 0;
j = 0; for(i = 0; i < file_size ; i++) {
for(i = 0; i < file_size ; i++) j++;
{ if(getc(stl->fp) == '\n') {
j++; if(j > 4) { /* don't count short lines */
if(getc(stl->fp) == '\n') num_lines++;
{ }
if(j > 4) /* don't count short lines */ j = 0;
{ }
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;
} }
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.number_of_facets += num_facets;
stl->stats.original_num_facets = stl->stats.number_of_facets; stl->stats.original_num_facets = stl->stats.number_of_facets;
} }
void void
stl_allocate(stl_file *stl) stl_allocate(stl_file *stl) {
{ if (stl->error) return;
/* Allocate memory for the entire .STL file */ /* Allocate memory for the entire .STL file */
stl->facet_start = (stl_facet*)calloc(stl->stats.number_of_facets, stl->facet_start = (stl_facet*)calloc(stl->stats.number_of_facets,
sizeof(stl_facet)); sizeof(stl_facet));
if(stl->facet_start == NULL) perror("stl_initialize"); if(stl->facet_start == NULL) perror("stl_initialize");
stl->stats.facets_malloced = stl->stats.number_of_facets; stl->stats.facets_malloced = stl->stats.number_of_facets;
/* Allocate memory for the neighbors list */ /* Allocate memory for the neighbors list */
stl->neighbors_start = (stl_neighbors*) 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"); if(stl->facet_start == NULL) perror("stl_initialize");
} }
void void
stl_open_merge(stl_file *stl, char *file) stl_open_merge(stl_file *stl, char *file_to_merge) {
{ int num_facets_so_far;
int first_facet; stl_type origStlType;
FILE *origFp;
first_facet = stl->stats.number_of_facets; stl_file stl_to_merge;
stl_initialize(stl);
stl_count_facets(stl, file); 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_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 extern void
stl_reallocate(stl_file *stl) stl_reallocate(stl_file *stl) {
{ if (stl->error) return;
/* Reallocate more memory for the .STL file(s) */ /* Reallocate more memory for the .STL file(s) */
stl->facet_start = (stl_facet*)realloc(stl->facet_start, stl->stats.number_of_facets * 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"); if(stl->facet_start == NULL) perror("stl_initialize");
stl->stats.facets_malloced = stl->stats.number_of_facets; stl->stats.facets_malloced = stl->stats.number_of_facets;
/* Reallocate more memory for the neighbors list */ /* Reallocate more memory for the neighbors list */
stl->neighbors_start = (stl_neighbors*) stl->neighbors_start = (stl_neighbors*)
realloc(stl->neighbors_start, stl->stats.number_of_facets * realloc(stl->neighbors_start, stl->stats.number_of_facets *
sizeof(stl_neighbors)); sizeof(stl_neighbors));
if(stl->facet_start == NULL) perror("stl_initialize"); 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; stl_facet facet;
int i; int i;
if(stl->stats.type == binary) if (stl->error) return;
{
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) {
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) /* we assume little-endian architecture! */
/* Read a single facet from a binary .STL file */ if (fread(&facet.normal, sizeof(stl_normal), 1, stl->fp) \
{ + fread(&facet.vertex, sizeof(stl_vertex), 3, stl->fp) \
// we assume little-endian architecture! + fread(&facet.extra, sizeof(char), 2, stl->fp) != 6) {
fread(&facet.normal, sizeof(stl_normal), 1, stl->fp); perror("Cannot read facet");
fread(&facet.vertex, sizeof(stl_vertex), 3, stl->fp); stl->error = 1;
fread(&facet.extra, sizeof(char), 2, stl->fp); return;
} }
else } else
/* Read a single facet from an ASCII .STL file */ /* Read a single facet from an ASCII .STL file */
{ {
fscanf(stl->fp, "%*s %*s %f %f %f\n", &facet.normal.x, if((fscanf(stl->fp, "%*s %*s %f %f %f\n", &facet.normal.x, &facet.normal.y, &facet.normal.z) + \
&facet.normal.y, &facet.normal.z); fscanf(stl->fp, "%*s %*s") + \
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[0].x, fscanf(stl->fp, "%*s %f %f %f\n", &facet.vertex[1].x, &facet.vertex[1].y, &facet.vertex[1].z) + \
&facet.vertex[0].y, &facet.vertex[0].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 %f %f %f\n", &facet.vertex[1].x, fscanf(stl->fp, "%*s") + \
&facet.vertex[1].y, &facet.vertex[1].z); fscanf(stl->fp, "%*s")) != 12) {
fscanf(stl->fp, "%*s %f %f %f\n", &facet.vertex[2].x, perror("Something is syntactically very wrong with this ASCII STL!");
&facet.vertex[2].y, &facet.vertex[2].z); stl->error = 1;
fscanf(stl->fp, "%*s"); return;
fscanf(stl->fp, "%*s"); }
}
/* 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; /* Write the facet into memory. */
stl->stats.size.y = stl->stats.max.y - stl->stats.min.y; stl->facet_start[i] = facet;
stl->stats.size.z = stl->stats.max.z - stl->stats.min.z;
stl->stats.bounding_diameter = sqrt( stl_facet_stats(stl, facet, first);
stl->stats.size.x * stl->stats.size.x + first = 0;
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 void
stl_facet_stats(stl_file *stl, stl_facet facet, int first) stl_facet_stats(stl_file *stl, stl_facet facet, int first) {
{ float diff_x;
float diff_x; float diff_y;
float diff_y; float diff_z;
float diff_z; float max_diff;
float max_diff;
/* while we are going through all of the facets, let's find the */ if (stl->error) return;
/* maximum and minimum values for x, y, and z */
/* while we are going through all of the facets, let's find the */
/* Initialize the max and min values the first time through*/ /* maximum and minimum values for x, y, and z */
if (first) {
stl->stats.max.x = facet.vertex[0].x; /* Initialize the max and min values the first time through*/
stl->stats.min.x = facet.vertex[0].x; if (first) {
stl->stats.max.y = facet.vertex[0].y; stl->stats.max.x = facet.vertex[0].x;
stl->stats.min.y = facet.vertex[0].y; stl->stats.min.x = facet.vertex[0].x;
stl->stats.max.z = facet.vertex[0].z; stl->stats.max.y = facet.vertex[0].y;
stl->stats.min.z = facet.vertex[0].z; stl->stats.min.y = facet.vertex[0].y;
stl->stats.max.z = facet.vertex[0].z;
diff_x = ABS(facet.vertex[0].x - facet.vertex[1].x); stl->stats.min.z = facet.vertex[0].z;
diff_y = ABS(facet.vertex[0].y - facet.vertex[1].y);
diff_z = ABS(facet.vertex[0].z - facet.vertex[1].z); diff_x = ABS(facet.vertex[0].x - facet.vertex[1].x);
max_diff = STL_MAX(diff_x, diff_y); diff_y = ABS(facet.vertex[0].y - facet.vertex[1].y);
max_diff = STL_MAX(diff_z, max_diff); diff_z = ABS(facet.vertex[0].z - facet.vertex[1].z);
stl->stats.shortest_edge = max_diff; max_diff = STL_MAX(diff_x, diff_y);
max_diff = STL_MAX(diff_z, max_diff);
first = 0; 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); /* now find the max and min values */
stl->stats.max.y = STL_MAX(stl->stats.max.y, facet.vertex[0].y); stl->stats.max.x = STL_MAX(stl->stats.max.x, facet.vertex[0].x);
stl->stats.min.y = STL_MIN(stl->stats.min.y, facet.vertex[0].y); stl->stats.min.x = STL_MIN(stl->stats.min.x, facet.vertex[0].x);
stl->stats.max.z = STL_MAX(stl->stats.max.z, facet.vertex[0].z); stl->stats.max.y = STL_MAX(stl->stats.max.y, facet.vertex[0].y);
stl->stats.min.z = STL_MIN(stl->stats.min.z, facet.vertex[0].z); 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.max.x = STL_MAX(stl->stats.max.x, facet.vertex[1].x); stl->stats.min.z = STL_MIN(stl->stats.min.z, facet.vertex[0].z);
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.max.x = STL_MAX(stl->stats.max.x, facet.vertex[1].x);
stl->stats.min.y = STL_MIN(stl->stats.min.y, facet.vertex[1].y); stl->stats.min.x = STL_MIN(stl->stats.min.x, facet.vertex[1].x);
stl->stats.max.z = STL_MAX(stl->stats.max.z, facet.vertex[1].z); stl->stats.max.y = STL_MAX(stl->stats.max.y, facet.vertex[1].y);
stl->stats.min.z = STL_MIN(stl->stats.min.z, facet.vertex[1].z); 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.max.x = STL_MAX(stl->stats.max.x, facet.vertex[2].x); stl->stats.min.z = STL_MIN(stl->stats.min.z, facet.vertex[1].z);
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.max.x = STL_MAX(stl->stats.max.x, facet.vertex[2].x);
stl->stats.min.y = STL_MIN(stl->stats.min.y, facet.vertex[2].y); stl->stats.min.x = STL_MIN(stl->stats.min.x, facet.vertex[2].x);
stl->stats.max.z = STL_MAX(stl->stats.max.z, facet.vertex[2].z); stl->stats.max.y = STL_MAX(stl->stats.max.y, facet.vertex[2].y);
stl->stats.min.z = STL_MIN(stl->stats.min.z, facet.vertex[2].z); 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 void
stl_close(stl_file *stl) stl_close(stl_file *stl) {
{ if (stl->error) return;
if(stl->neighbors_start != NULL)
free(stl->neighbors_start); if(stl->neighbors_start != NULL)
if(stl->facet_start != NULL) free(stl->neighbors_start);
free(stl->facet_start); if(stl->facet_start != NULL)
if(stl->v_indices != NULL) free(stl->facet_start);
free(stl->v_indices); if(stl->v_indices != NULL)
if(stl->v_shared != NULL) free(stl->v_indices);
free(stl->v_shared); if(stl->v_shared != NULL)
free(stl->v_shared);
} }

View File

@ -1,21 +1,23 @@
/* ADMesh -- process triangulated solid meshes /* ADMesh -- process triangulated solid meshes
* Copyright (C) 1995, 1996 Anthony D. Martin * 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 * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option) * the Free Software Foundation; either version 2 of the License, or
* any later version. * (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * 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 * Questions, comments, suggestions, etc to
* along with this program; if not, write to the Free Software * https://github.com/admesh/admesh/issues
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Questions, comments, suggestions, etc to <amartin@engr.csulb.edu>
*/ */
#include <stdio.h> #include <stdio.h>
@ -31,8 +33,7 @@ static float get_volume(stl_file *stl);
void void
stl_verify_neighbors(stl_file *stl) stl_verify_neighbors(stl_file *stl) {
{
int i; int i;
int j; int j;
stl_edge edge_a; stl_edge edge_a;
@ -40,377 +41,512 @@ stl_verify_neighbors(stl_file *stl)
int neighbor; int neighbor;
int vnot; int vnot;
if (stl->error) return;
stl->stats.backwards_edges = 0; stl->stats.backwards_edges = 0;
for(i = 0; i < stl->stats.number_of_facets; i++) for(i = 0; i < stl->stats.number_of_facets; i++) {
{ for(j = 0; j < 3; j++) {
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];
edge_a.p1 = stl->facet_start[i].vertex[j]; neighbor = stl->neighbors_start[i].neighbor[j];
edge_a.p2 = stl->facet_start[i].vertex[(j + 1) % 3]; vnot = stl->neighbors_start[i].which_vertex_not[j];
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(neighbor == -1) if(vnot < 3) {
continue; /* this edge has no neighbor... Continue. */ edge_b.p1 = stl->facet_start[neighbor].vertex[(vnot + 2) % 3];
if(vnot < 3) edge_b.p2 = stl->facet_start[neighbor].vertex[(vnot + 1) % 3];
{ } else {
edge_b.p1 = stl->facet_start[neighbor].vertex[(vnot + 2) % 3]; stl->stats.backwards_edges += 1;
edge_b.p2 = stl->facet_start[neighbor].vertex[(vnot + 1) % 3]; edge_b.p1 = stl->facet_start[neighbor].vertex[(vnot + 1) % 3];
} edge_b.p2 = stl->facet_start[neighbor].vertex[(vnot + 2) % 3];
else }
{ if(memcmp(&edge_a, &edge_b, SIZEOF_EDGE_SORT) != 0) {
stl->stats.backwards_edges += 1; /* These edges should match but they don't. Print results. */
edge_b.p1 = stl->facet_start[neighbor].vertex[(vnot + 1) % 3]; printf("edge %d of facet %d doesn't match edge %d of facet %d\n",
edge_b.p2 = stl->facet_start[neighbor].vertex[(vnot + 2) % 3]; j, i, vnot + 1, neighbor);
} stl_write_facet(stl, (char*)"first facet", i);
if(memcmp(&edge_a, &edge_b, SIZEOF_EDGE_SORT) != 0) stl_write_facet(stl, (char*)"second facet", neighbor);
{ }
/* 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 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 i;
int j; int j;
for(i = 0; i < stl->stats.number_of_facets; i++) if (stl->error) return;
{
for(j = 0; j < 3; 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].x -= (stl->stats.min.x - x);
stl->facet_start[i].vertex[j].y += y; stl->facet_start[i].vertex[j].y -= (stl->stats.min.y - y);
stl->facet_start[i].vertex[j].z += z; 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.x += x;
stl->stats.min.y += y; stl->stats.min.y += y;
stl->stats.min.z += z; stl->stats.min.z += z;
stl->stats.max.x += x; stl->stats.max.x += x;
stl->stats.max.y += y; stl->stats.max.y += y;
stl->stats.max.z += z; stl->stats.max.z += z;
stl_invalidate_shared_vertices(stl); stl_invalidate_shared_vertices(stl);
} }
void void
stl_scale_versor(stl_file *stl, float versor[3]) stl_scale_versor(stl_file *stl, float versor[3]) {
{
int i; int i;
int j; int j;
// scale extents if (stl->error) return;
/* scale extents */
stl->stats.min.x *= versor[0]; stl->stats.min.x *= versor[0];
stl->stats.min.y *= versor[1]; stl->stats.min.y *= versor[1];
stl->stats.min.z *= versor[2]; stl->stats.min.z *= versor[2];
stl->stats.max.x *= versor[0]; stl->stats.max.x *= versor[0];
stl->stats.max.y *= versor[1]; stl->stats.max.y *= versor[1];
stl->stats.max.z *= versor[2]; stl->stats.max.z *= versor[2];
// scale size /* scale size */
stl->stats.size.x *= versor[0]; stl->stats.size.x *= versor[0];
stl->stats.size.y *= versor[1]; stl->stats.size.y *= versor[1];
stl->stats.size.z *= versor[2]; stl->stats.size.z *= versor[2];
// scale volume /* scale volume */
if (stl->stats.volume > 0.0) { if (stl->stats.volume > 0.0) {
stl->stats.volume *= (versor[0] * versor[1] * versor[2]); stl->stats.volume *= (versor[0] * versor[1] * versor[2]);
} }
for(i = 0; i < stl->stats.number_of_facets; i++) for(i = 0; i < stl->stats.number_of_facets; i++) {
{ for(j = 0; j < 3; j++) {
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].x *= versor[0]; stl->facet_start[i].vertex[j].z *= versor[2];
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 void
stl_scale(stl_file *stl, float factor) stl_scale(stl_file *stl, float factor) {
{ float versor[3];
float versor[3];
versor[0] = factor; if (stl->error) return;
versor[1] = factor;
versor[2] = factor; versor[0] = factor;
stl_scale_versor(stl, versor); versor[1] = factor;
versor[2] = factor;
stl_scale_versor(stl, versor);
} }
static void calculate_normals(stl_file *stl) static void calculate_normals(stl_file *stl) {
{ long i;
long i; float normal[3];
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]); for(i = 0; i < stl->stats.number_of_facets; i++) {
stl_normalize_vector(normal); stl_calculate_normal(normal, &stl->facet_start[i]);
stl->facet_start[i].normal.x = normal[0]; stl_normalize_vector(normal);
stl->facet_start[i].normal.y = normal[1]; stl->facet_start[i].normal.x = normal[0];
stl->facet_start[i].normal.z = normal[2]; stl->facet_start[i].normal.y = normal[1];
} stl->facet_start[i].normal.z = normal[2];
}
} }
void void
stl_rotate_x(stl_file *stl, float angle) stl_rotate_x(stl_file *stl, float angle) {
{
int i; int i;
int j; int j;
for(i = 0; i < stl->stats.number_of_facets; i++) if (stl->error) return;
{
for(j = 0; j < 3; 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_rotate(&stl->facet_start[i].vertex[j].y,
&stl->facet_start[i].vertex[j].z, angle); &stl->facet_start[i].vertex[j].z, angle);
}
} }
}
stl_get_size(stl); stl_get_size(stl);
calculate_normals(stl); calculate_normals(stl);
} }
void void
stl_rotate_y(stl_file *stl, float angle) stl_rotate_y(stl_file *stl, float angle) {
{
int i; int i;
int j; int j;
for(i = 0; i < stl->stats.number_of_facets; i++) if (stl->error) return;
{
for(j = 0; j < 3; 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_rotate(&stl->facet_start[i].vertex[j].z,
&stl->facet_start[i].vertex[j].x, angle); &stl->facet_start[i].vertex[j].x, angle);
}
} }
}
stl_get_size(stl); stl_get_size(stl);
calculate_normals(stl); calculate_normals(stl);
} }
void void
stl_rotate_z(stl_file *stl, float angle) stl_rotate_z(stl_file *stl, float angle) {
{
int i; int i;
int j; int j;
for(i = 0; i < stl->stats.number_of_facets; i++) if (stl->error) return;
{
for(j = 0; j < 3; 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_rotate(&stl->facet_start[i].vertex[j].x,
&stl->facet_start[i].vertex[j].y, angle); &stl->facet_start[i].vertex[j].y, angle);
}
} }
}
stl_get_size(stl); stl_get_size(stl);
calculate_normals(stl); calculate_normals(stl);
} }
static void static void
stl_rotate(float *x, float *y, float angle) stl_rotate(float *x, float *y, float angle) {
{
double r; double r;
double theta; double theta;
double radian_angle; double radian_angle;
radian_angle = (angle / 180.0) * M_PI; radian_angle = (angle / 180.0) * M_PI;
r = sqrt((*x * *x) + (*y * *y)); r = sqrt((*x **x) + (*y **y));
theta = atan2(*y, *x); theta = atan2(*y, *x);
*x = r * cos(theta + radian_angle); *x = r * cos(theta + radian_angle);
*y = r * sin(theta + radian_angle); *y = r * sin(theta + radian_angle);
} }
extern void extern void
stl_get_size(stl_file *stl) stl_get_size(stl_file *stl) {
{
if (stl->stats.number_of_facets == 0) return;
int i; int i;
int j; 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.x = stl->facet_start[0].vertex[0].x;
stl->stats.min.y = stl->facet_start[0].vertex[0].y; stl->stats.min.y = stl->facet_start[0].vertex[0].y;
stl->stats.min.z = stl->facet_start[0].vertex[0].z; 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.x = stl->facet_start[0].vertex[0].x;
stl->stats.max.y = stl->facet_start[0].vertex[0].y; stl->stats.max.y = stl->facet_start[0].vertex[0].y;
stl->stats.max.z = stl->facet_start[0].vertex[0].z; stl->stats.max.z = stl->facet_start[0].vertex[0].z;
for(i = 0; i < stl->stats.number_of_facets; i++) for(i = 0; i < stl->stats.number_of_facets; i++) {
{ for(j = 0; j < 3; j++) {
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.x = STL_MIN(stl->stats.min.x, stl->stats.min.y = STL_MIN(stl->stats.min.y,
stl->facet_start[i].vertex[j].x); stl->facet_start[i].vertex[j].y);
stl->stats.min.y = STL_MIN(stl->stats.min.y, stl->stats.min.z = STL_MIN(stl->stats.min.z,
stl->facet_start[i].vertex[j].y); stl->facet_start[i].vertex[j].z);
stl->stats.min.z = STL_MIN(stl->stats.min.z, stl->stats.max.x = STL_MAX(stl->stats.max.x,
stl->facet_start[i].vertex[j].z); stl->facet_start[i].vertex[j].x);
stl->stats.max.x = STL_MAX(stl->stats.max.x, stl->stats.max.y = STL_MAX(stl->stats.max.y,
stl->facet_start[i].vertex[j].x); stl->facet_start[i].vertex[j].y);
stl->stats.max.y = STL_MAX(stl->stats.max.y, stl->stats.max.z = STL_MAX(stl->stats.max.z,
stl->facet_start[i].vertex[j].y); stl->facet_start[i].vertex[j].z);
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.x = stl->stats.max.x - stl->stats.min.x;
stl->stats.size.z = stl->stats.max.z - stl->stats.min.z; stl->stats.size.y = stl->stats.max.y - stl->stats.min.y;
stl->stats.bounding_diameter = sqrt( stl->stats.size.z = stl->stats.max.z - stl->stats.min.z;
stl->stats.size.x * stl->stats.size.x + stl->stats.bounding_diameter = sqrt(
stl->stats.size.y * stl->stats.size.y + stl->stats.size.x * stl->stats.size.x +
stl->stats.size.z * stl->stats.size.z stl->stats.size.y * stl->stats.size.y +
); stl->stats.size.z * stl->stats.size.z
);
} }
void void
stl_mirror_xy(stl_file *stl) stl_mirror_xy(stl_file *stl) {
{
int i; int i;
int j; int j;
float temp_size; float temp_size;
for(i = 0; i < stl->stats.number_of_facets; i++) if (stl->error) return;
{
for(j = 0; j < 3; j++) 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; stl->facet_start[i].vertex[j].z *= -1.0;
}
} }
}
temp_size = stl->stats.min.z; temp_size = stl->stats.min.z;
stl->stats.min.z = stl->stats.max.z; stl->stats.min.z = stl->stats.max.z;
stl->stats.max.z = temp_size; stl->stats.max.z = temp_size;
stl->stats.min.z *= -1.0; stl->stats.min.z *= -1.0;
stl->stats.max.z *= -1.0; stl->stats.max.z *= -1.0;
stl_reverse_all_facets(stl); stl_reverse_all_facets(stl);
stl->stats.facets_reversed -= stl->stats.number_of_facets; // for not altering stats stl->stats.facets_reversed -= stl->stats.number_of_facets; /* for not altering stats */
} }
void void
stl_mirror_yz(stl_file *stl) stl_mirror_yz(stl_file *stl) {
{
int i; int i;
int j; int j;
float temp_size; float temp_size;
for(i = 0; i < stl->stats.number_of_facets; i++) if (stl->error) return;
{
for(j = 0; j < 3; j++) 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; stl->facet_start[i].vertex[j].x *= -1.0;
}
} }
}
temp_size = stl->stats.min.x; temp_size = stl->stats.min.x;
stl->stats.min.x = stl->stats.max.x; stl->stats.min.x = stl->stats.max.x;
stl->stats.max.x = temp_size; stl->stats.max.x = temp_size;
stl->stats.min.x *= -1.0; stl->stats.min.x *= -1.0;
stl->stats.max.x *= -1.0; stl->stats.max.x *= -1.0;
stl_reverse_all_facets(stl); stl_reverse_all_facets(stl);
stl->stats.facets_reversed -= stl->stats.number_of_facets; // for not altering stats stl->stats.facets_reversed -= stl->stats.number_of_facets; /* for not altering stats */
} }
void void
stl_mirror_xz(stl_file *stl) stl_mirror_xz(stl_file *stl) {
{
int i; int i;
int j; int j;
float temp_size; float temp_size;
for(i = 0; i < stl->stats.number_of_facets; i++) if (stl->error) return;
{
for(j = 0; j < 3; j++) 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; stl->facet_start[i].vertex[j].y *= -1.0;
}
} }
}
temp_size = stl->stats.min.y; temp_size = stl->stats.min.y;
stl->stats.min.y = stl->stats.max.y; stl->stats.min.y = stl->stats.max.y;
stl->stats.max.y = temp_size; stl->stats.max.y = temp_size;
stl->stats.min.y *= -1.0; stl->stats.min.y *= -1.0;
stl->stats.max.y *= -1.0; stl->stats.max.y *= -1.0;
stl_reverse_all_facets(stl); stl_reverse_all_facets(stl);
stl->stats.facets_reversed -= stl->stats.number_of_facets; // for not altering stats stl->stats.facets_reversed -= stl->stats.number_of_facets; /* for not altering stats */
} }
static float get_volume(stl_file *stl) static float get_volume(stl_file *stl) {
{ long i;
long i; stl_vertex p0;
stl_vertex p0; stl_vertex p;
stl_vertex p; stl_normal n;
stl_normal n; float height;
float height; float area;
float area; float volume = 0.0;
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;
for(i = 0; i < stl->stats.number_of_facets; i++){ if (stl->error) return 0;
p.x = stl->facet_start[i].vertex[0].x - p0.x;
p.y = stl->facet_start[i].vertex[0].y - p0.y; /* Choose a point, any point as the reference */
p.z = stl->facet_start[i].vertex[0].z - p0.z; p0.x = stl->facet_start[0].vertex[0].x;
/* Do dot product to get distance from point to plane */ p0.y = stl->facet_start[0].vertex[0].y;
n = stl->facet_start[i].normal; p0.z = stl->facet_start[0].vertex[0].z;
height = (n.x * p.x) + (n.y * p.y) + (n.z * p.z);
area = get_area(&stl->facet_start[i]); for(i = 0; i < stl->stats.number_of_facets; i++) {
volume += (area * height) / 3.0; p.x = stl->facet_start[i].vertex[0].x - p0.x;
} p.y = stl->facet_start[i].vertex[0].y - p0.y;
return volume; 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) void stl_calculate_volume(stl_file *stl) {
{ if (stl->error) return;
stl->stats.volume = get_volume(stl); stl->stats.volume = get_volume(stl);
if(stl->stats.volume < 0.0){ if(stl->stats.volume < 0.0) {
stl_reverse_all_facets(stl); stl_reverse_all_facets(stl);
stl->stats.volume = -stl->stats.volume; stl->stats.volume = -stl->stats.volume;
} }
} }
static float get_area(stl_facet *facet) static float get_area(stl_facet *facet) {
{ double cross[3][3];
double cross[3][3]; float sum[3];
float sum[3]; float n[3];
float n[3]; float area;
float area; int i;
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];
/* This should already be done. But just in case, let's do it again */ /* cast to double before calculating cross product because large coordinates
stl_calculate_normal(n, facet); can result in overflowing product
stl_normalize_vector(n); (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]); sum[0] = cross[0][0] + cross[1][0] + cross[2][0];
return area; 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);
}
} }

View File

@ -29,6 +29,7 @@ TriangleMesh::TriangleMesh(const TriangleMesh &other)
{ {
this->stl.heads = NULL; this->stl.heads = NULL;
this->stl.tail = NULL; this->stl.tail = NULL;
this->stl.error = other.stl.error;
if (other.stl.facet_start != NULL) { if (other.stl.facet_start != NULL) {
this->stl.facet_start = (stl_facet*)calloc(other.stl.stats.number_of_facets, sizeof(stl_facet)); 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); 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 // fill_holes
if (stl.stats.connected_facets_3_edge < stl.stats.number_of_facets) { if (stl.stats.connected_facets_3_edge < stl.stats.number_of_facets) {
stl_fill_holes(&stl); stl_fill_holes(&stl);
stl_clear_error(&stl);
} }
// normal_directions // normal_directions
@ -280,6 +282,7 @@ TriangleMesh::split() const
mesh->stl.stats.type = inmemory; mesh->stl.stats.type = inmemory;
mesh->stl.stats.number_of_facets = facets.size(); mesh->stl.stats.number_of_facets = facets.size();
mesh->stl.stats.original_num_facets = mesh->stl.stats.number_of_facets; mesh->stl.stats.original_num_facets = mesh->stl.stats.number_of_facets;
stl_clear_error(&mesh->stl);
stl_allocate(&mesh->stl); stl_allocate(&mesh->stl);
int first = 1; int first = 1;
@ -389,6 +392,7 @@ TriangleMesh::to_SV() {
void TriangleMesh::ReadFromPerl(SV* vertices, SV* facets) void TriangleMesh::ReadFromPerl(SV* vertices, SV* facets)
{ {
stl.error = 0;
stl.stats.type = inmemory; stl.stats.type = inmemory;
// count facets and allocate memory // count facets and allocate memory