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,13 +28,11 @@
#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];
@ -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;
}; };
@ -106,11 +103,12 @@ stl_fix_normal_directions(stl_file *stl)
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;
@ -121,44 +119,34 @@ stl_fix_normal_directions(stl_file *stl)
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. */ /* Reverse the neighboring facets if necessary. */
if(stl->neighbors_start[facet_num].which_vertex_not[j] > 2) if(stl->neighbors_start[facet_num].which_vertex_not[j] > 2) {
{ /* If the facet has a neighbor that is -1, it means that edge isn't shared by another facet */
// If the facet has a neighbor that is -1, it means that edge isn't shared by another if(stl->neighbors_start[facet_num].neighbor[j] != -1) {
// facet.
if(stl->neighbors_start[facet_num].neighbor[j] != -1)
{
stl_reverse_facet stl_reverse_facet
(stl, stl->neighbors_start[facet_num].neighbor[j]); (stl, stl->neighbors_start[facet_num].neighbor[j]);
} }
} }
//If this edge of the facet is connected: /* If this edge of the facet is connected: */
if(stl->neighbors_start[facet_num].neighbor[j] != -1) if(stl->neighbors_start[facet_num].neighbor[j] != -1) {
{ /* If we haven't fixed this facet yet, add it to the list: */
//If we haven't fixed this facet yet, add it to the list: if(norm_sw[stl->neighbors_start[facet_num].neighbor[j]] != 1) {
if(norm_sw[stl->neighbors_start[facet_num].neighbor[j]] != 1)
{
/* Add node to beginning of list. */ /* Add node to beginning of list. */
newn = (stl_normal*)malloc(sizeof(struct stl_normal)); newn = (struct stl_normal*)malloc(sizeof(struct stl_normal));
if(newn == NULL) perror("stl_fix_normal_directions"); if(newn == NULL) perror("stl_fix_normal_directions");
newn->facet_num = stl->neighbors_start[facet_num].neighbor[j]; newn->facet_num = stl->neighbors_start[facet_num].neighbor[j];
newn->next = head->next; newn->next = head->next;
@ -167,40 +155,28 @@ stl_fix_normal_directions(stl_file *stl)
} }
} }
/* Get next facet to fix from top of list. */ /* Get next facet to fix from top of list. */
if(head->next != tail) if(head->next != tail) {
{
facet_num = head->next->facet_num; facet_num = head->next->facet_num;
if(norm_sw[facet_num] != 1) /* If facet is in list mutiple times */ if(norm_sw[facet_num] != 1) { /* If facet is in list mutiple times */
{
norm_sw[facet_num] = 1; /* Record this one as being fixed. */ norm_sw[facet_num] = 1; /* Record this one as being fixed. */
checked++; checked++;
} }
temp = head->next; /* Delete this facet from the list. */ temp = head->next; /* Delete this facet from the list. */
head->next = head->next->next; head->next = head->next->next;
free(temp); free(temp);
} } else { /* if we ran out of facets to fix: */
else //if we ran out of facets to fix:
{
/* All of the facets in this part have been fixed. */ /* All of the facets in this part have been fixed. */
stl->stats.number_of_parts += 1; stl->stats.number_of_parts += 1;
/* There are (checked-checked_before) facets */ if(checked >= stl->stats.number_of_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. */ /* All of the facets have been checked. Bail out. */
break; break;
} } else {
else
{
/* There is another part here. Find it and continue. */ /* There is another part here. Find it and continue. */
for(i = 0; i < stl->stats.number_of_facets; i++) for(i = 0; i < stl->stats.number_of_facets; i++) {
{ if(norm_sw[i] == 0) {
if(norm_sw[i] == 0) /* This is the first facet of the next part. */
{ /* This is the first facet of the next part. */
facet_num = i; facet_num = i;
if(stl_check_normal_vector(stl, i, 0) == 2) if(stl_check_normal_vector(stl, i, 0) == 2) {
{
stl_reverse_facet(stl, i); stl_reverse_facet(stl, i);
} }
@ -218,8 +194,7 @@ stl_fix_normal_directions(stl_file *stl)
} }
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 */
@ -236,8 +211,7 @@ stl_check_normal_vector(stl_file *stl, int facet_num, int normal_fix_flag)
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];
@ -253,10 +227,8 @@ stl_check_normal_vector(stl_file *stl, int facet_num, int normal_fix_flag)
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.x = normal[0];
facet->normal.y = normal[1]; facet->normal.y = normal[1];
facet->normal.z = normal[2]; facet->normal.z = normal[2];
@ -268,11 +240,9 @@ stl_check_normal_vector(stl_file *stl, int facet_num, int normal_fix_flag)
stl_reverse_vector(test_norm); stl_reverse_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)) {
{
/* Facet is backwards. */ /* Facet is backwards. */
if(normal_fix_flag) 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];
@ -280,8 +250,7 @@ stl_check_normal_vector(stl_file *stl, int facet_num, int normal_fix_flag)
} }
return 2; return 2;
} }
if(normal_fix_flag) 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];
@ -291,8 +260,7 @@ stl_check_normal_vector(stl_file *stl, int facet_num, int normal_fix_flag)
} }
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,48 +284,14 @@ 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;
@ -371,24 +304,24 @@ 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;
{
for(i = 0; i < stl->stats.number_of_facets; i++) {
stl_check_normal_vector(stl, i, 1); 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;
{
for(i = 0; i < stl->stats.number_of_facets; i++) {
stl_reverse_facet(stl, i); stl_reverse_facet(stl, i);
stl_calculate_normal(normal, &stl->facet_start[i]); stl_calculate_normal(normal, &stl->facet_start[i]);
stl_normalize_vector(normal); stl_normalize_vector(normal);

View File

@ -1,31 +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>
*/ */
#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) { if (stl->v_indices != NULL) {
free(stl->v_indices); free(stl->v_indices);
stl->v_indices = NULL; stl->v_indices = NULL;
@ -37,8 +40,7 @@ stl_invalidate_shared_vertices(stl_file *stl)
} }
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;
@ -50,7 +52,9 @@ stl_generate_shared_vertices(stl_file *stl)
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*)
@ -62,25 +66,20 @@ stl_generate_shared_vertices(stl_file *stl)
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; first_facet = i;
for(j = 0; j < 3; j++) for(j = 0; j < 3; j++) {
{ if(stl->v_indices[i].vertex[j] != -1) {
if(stl->v_indices[i].vertex[j] != -1)
{
continue; continue;
} }
if(stl->stats.shared_vertices == stl->stats.shared_malloced) if(stl->stats.shared_vertices == stl->stats.shared_malloced) {
{
stl->stats.shared_malloced += 1024; stl->stats.shared_malloced += 1024;
stl->v_shared = (stl_vertex*)realloc(stl->v_shared, stl->v_shared = (stl_vertex*)realloc(stl->v_shared,
stl->stats.shared_malloced * sizeof(stl_vertex)); stl->stats.shared_malloced * sizeof(stl_vertex));
@ -95,32 +94,22 @@ stl_generate_shared_vertices(stl_file *stl)
facet_num = i; facet_num = i;
vnot = (j + 2) % 3; vnot = (j + 2) % 3;
for(;;) for(;;) {
{ if(vnot > 2) {
if(vnot > 2) if(direction == 0) {
{
if(direction == 0)
{
pivot_vertex = (vnot + 2) % 3; pivot_vertex = (vnot + 2) % 3;
next_edge = pivot_vertex; next_edge = pivot_vertex;
direction = 1; direction = 1;
} } else {
else
{
pivot_vertex = (vnot + 1) % 3; pivot_vertex = (vnot + 1) % 3;
next_edge = vnot % 3; next_edge = vnot % 3;
direction = 0; direction = 0;
} }
} } else {
else if(direction == 0) {
{
if(direction == 0)
{
pivot_vertex = (vnot + 1) % 3; pivot_vertex = (vnot + 1) % 3;
next_edge = vnot; next_edge = vnot;
} } else {
else
{
pivot_vertex = (vnot + 2) % 3; pivot_vertex = (vnot + 2) % 3;
next_edge = pivot_vertex; next_edge = pivot_vertex;
} }
@ -129,28 +118,20 @@ stl_generate_shared_vertices(stl_file *stl)
stl->stats.shared_vertices; stl->stats.shared_vertices;
next_facet = stl->neighbors_start[facet_num].neighbor[next_edge]; next_facet = stl->neighbors_start[facet_num].neighbor[next_edge];
if(next_facet == -1) if(next_facet == -1) {
{ if(reversed) {
if(reversed)
{
break; break;
} } else {
else
{
direction = 1; direction = 1;
vnot = (j + 1) % 3; vnot = (j + 1) % 3;
reversed = 1; reversed = 1;
facet_num = first_facet; facet_num = first_facet;
} }
} } else if(next_facet != first_facet) {
else if(next_facet != first_facet)
{
vnot = stl->neighbors_start[facet_num]. vnot = stl->neighbors_start[facet_num].
which_vertex_not[next_edge]; which_vertex_not[next_edge];
facet_num = next_facet; facet_num = next_facet;
} } else {
else
{
break; break;
} }
} }
@ -160,37 +141,35 @@ stl_generate_shared_vertices(stl_file *stl)
} }
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);
exit(1); stl->error = 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], 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]); stl->v_indices[i].vertex[1], stl->v_indices[i].vertex[2]);
} }
@ -198,24 +177,24 @@ stl_write_off(stl_file *stl, char *file)
} }
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);
exit(1); stl->error = 1;
return;
} }
fprintf(fp, "#VRML V1.0 ascii\n\n"); fprintf(fp, "#VRML V1.0 ascii\n\n");
@ -233,8 +212,7 @@ 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);
} }
@ -244,8 +222,7 @@ stl_write_vrml(stl_file *stl, char *file)
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]);
} }
@ -259,15 +236,19 @@ 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;
if (stl->error) return;
/* Open the file */ /* Open the file */
FILE* fp = fopen(file, "w"); fp = fopen(file, "w");
if (fp == NULL) { if (fp == NULL) {
char* error_msg = (char*)malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */ char* error_msg = (char*)malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */
sprintf(error_msg, "stl_write_ascii: Couldn't open %s for writing", file); sprintf(error_msg, "stl_write_ascii: Couldn't open %s for writing", file);
perror(error_msg); perror(error_msg);
free(error_msg); free(error_msg);
exit(1); stl->error = 1;
return;
} }
for (i = 0; i < stl->stats.shared_vertices; i++) { for (i = 0; i < stl->stats.shared_vertices; i++) {

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,18 +31,15 @@
#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,
@ -50,19 +50,22 @@ stl_print_edges(stl_file *stl, FILE *file)
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");
} }
@ -100,7 +103,7 @@ Total disconnected facets : %5d %5d\n",
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);
@ -121,30 +124,29 @@ 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);
exit(1); stl->error = 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);
@ -168,27 +170,27 @@ stl_write_ascii(stl_file *stl, const char *file, const char *label)
} }
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);
exit(1); stl->error = 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],
@ -201,12 +203,10 @@ stl_print_neighbors(stl_file *stl, char *file)
fclose(fp); fclose(fp);
} }
static void void
stl_put_little_int(FILE *fp, int value_in) stl_put_little_int(FILE *fp, int value_in) {
{
int new_value; int new_value;
union union {
{
int int_value; int int_value;
char char_value[4]; char char_value[4];
} value; } value;
@ -220,12 +220,10 @@ stl_put_little_int(FILE *fp, int value_in)
fwrite(&new_value, sizeof(int), 1, fp); fwrite(&new_value, sizeof(int), 1, fp);
} }
static void void
stl_put_little_float(FILE *fp, float value_in) stl_put_little_float(FILE *fp, float value_in) {
{
int new_value; int new_value;
union union {
{
float float_value; float float_value;
char char_value[4]; char char_value[4];
} value; } value;
@ -239,35 +237,10 @@ stl_put_little_float(FILE *fp, float value_in)
fwrite(&new_value, sizeof(int), 1, fp); fwrite(&new_value, sizeof(int), 1, fp);
} }
void void
stl_write_binary(stl_file *stl, const char *file, const char *label) 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,13 +258,44 @@ 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,
@ -299,8 +303,8 @@ stl_write_vertex(stl_file *stl, int facet, int vertex)
} }
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,24 +312,21 @@ 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 {
else
{
stl_write_vertex(stl, edge.facet_number, (edge.which_edge + 1) % 3); stl_write_vertex(stl, edge.facet_number, (edge.which_edge + 1) % 3);
stl_write_vertex(stl, edge.facet_number, edge.which_edge % 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],
@ -336,8 +337,7 @@ stl_write_neighbor(stl_file *stl, int facet)
} }
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;
@ -348,17 +348,19 @@ stl_write_quad_object(stl_file *stl, char *file)
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);
exit(1); stl->error = 1;
return;
} }
connect_color.x = 0.0; connect_color.x = 0.0;
@ -375,25 +377,17 @@ 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; color = connect_color;
} } else if(j == 1) {
else if(j == 1)
{
color = uncon_1_color; color = uncon_1_color;
} } else if(j == 2) {
else if(j == 2)
{
color = uncon_2_color; color = uncon_2_color;
} } else {
else
{
color = uncon_3_color; color = uncon_3_color;
} }
fprintf(fp, "%f %f %f %1.1f %1.1f %1.1f 1\n", fprintf(fp, "%f %f %f %1.1f %1.1f %1.1f 1\n",
@ -417,24 +411,24 @@ stl_write_quad_object(stl_file *stl, char *file)
} }
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);
exit(1); stl->error = 1;
return;
} }
fprintf(fp, "999\n%s\n", label); fprintf(fp, "999\n%s\n", label);
@ -445,8 +439,7 @@ stl_write_dxf(stl_file *stl, char *file, char *label)
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,
@ -466,3 +459,21 @@ stl_write_dxf(stl_file *stl, char *file, char *label)
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;
@ -63,28 +64,30 @@ stl_initialize(stl_file *stl)
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);
exit(1); stl->error = 1;
return;
} }
/* Find size of file */ /* Find size of file */
fseek(stl->fp, 0, SEEK_END); fseek(stl->fp, 0, SEEK_END);
@ -92,14 +95,16 @@ stl_count_facets(stl_file *stl, char *file)
/* 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; stl->stats.type = binary;
// close and reopen with binary flag (needed on Windows) /* close and reopen with binary flag (needed on Windows) */
fclose(stl->fp); fclose(stl->fp);
stl->fp = fopen(file, "rb"); stl->fp = fopen(file, "rb");
break; break;
@ -109,41 +114,35 @@ stl_count_facets(stl_file *stl, char *file)
/* 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); fprintf(stderr, "The file %s has the wrong size.\n", file);
exit(1); stl->error = 1;
return;
} }
num_facets = (file_size - HEADER_SIZE) / SIZEOF_STL_FACET; num_facets = (file_size - HEADER_SIZE) / SIZEOF_STL_FACET;
/* Read the header */ /* Read the header */
fread(stl->stats.header, LABEL_SIZE, 1, stl->fp); if (fread(stl->stats.header, LABEL_SIZE, 1, stl->fp) > 79) {
stl->stats.header[80] = '\0'; stl->stats.header[80] = '\0';
}
/* Read the int following the header. This should contain # of facets */ /* Read the int following the header. This should contain # of facets */
fread(&header_num_facets, sizeof(int), 1, stl->fp); if((!fread(&header_num_facets, sizeof(int), 1, stl->fp)) || (num_facets != header_num_facets)) {
if(num_facets != header_num_facets)
{
fprintf(stderr, fprintf(stderr,
"Warning: File size doesn't match number of facets in the header\n"); "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++; j++;
if(getc(stl->fp) == '\n') if(getc(stl->fp) == '\n') {
{ if(j > 4) { /* don't count short lines */
if(j > 4) /* don't count short lines */
{
num_lines++; num_lines++;
} }
j = 0; j = 0;
@ -164,8 +163,9 @@ stl_count_facets(stl_file *stl, char *file)
} }
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));
@ -179,20 +179,54 @@ stl_allocate(stl_file *stl)
} }
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;
stl_file stl_to_merge;
first_facet = stl->stats.number_of_facets; if (stl->error) return;
stl_initialize(stl);
stl_count_facets(stl, file); /* 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));
@ -206,47 +240,51 @@ stl_reallocate(stl_file *stl)
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;
{
if(stl->stats.type == binary) {
fseek(stl->fp, HEADER_SIZE, SEEK_SET); fseek(stl->fp, HEADER_SIZE, SEEK_SET);
} } else {
else
{
rewind(stl->fp); rewind(stl->fp);
/* Skip the first line of the file */ /* Skip the first line of the file */
while(getc(stl->fp) != '\n'); while(getc(stl->fp) != '\n');
} }
for(i = first_facet; i < stl->stats.number_of_facets; i++) for(i = first_facet; i < stl->stats.number_of_facets; i++) {
{
if(stl->stats.type == binary) if(stl->stats.type == binary)
/* Read a single facet from a binary .STL file */ /* Read a single facet from a binary .STL file */
{ {
// we assume little-endian architecture! /* we assume little-endian architecture! */
fread(&facet.normal, sizeof(stl_normal), 1, stl->fp); if (fread(&facet.normal, sizeof(stl_normal), 1, stl->fp) \
fread(&facet.vertex, sizeof(stl_vertex), 3, stl->fp); + fread(&facet.vertex, sizeof(stl_vertex), 3, stl->fp) \
fread(&facet.extra, sizeof(char), 2, stl->fp); + fread(&facet.extra, sizeof(char), 2, stl->fp) != 6) {
perror("Cannot read facet");
stl->error = 1;
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. */ /* Write the facet into memory. */
stl->facet_start[i] = facet; stl->facet_start[i] = facet;
@ -265,12 +303,14 @@ stl_read(stl_file *stl, int first_facet, int first)
} }
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;
if (stl->error) return;
/* while we are going through all of the facets, let's find the */ /* while we are going through all of the facets, let's find the */
/* maximum and minimum values for x, y, and z */ /* maximum and minimum values for x, y, and z */
@ -317,8 +357,9 @@ stl_facet_stats(stl_file *stl, stl_facet facet, int first)
} }
void void
stl_close(stl_file *stl) stl_close(stl_file *stl) {
{ if (stl->error) return;
if(stl->neighbors_start != NULL) if(stl->neighbors_start != NULL)
free(stl->neighbors_start); free(stl->neighbors_start);
if(stl->facet_start != NULL) if(stl->facet_start != NULL)

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,12 +41,12 @@ 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.p1 = stl->facet_start[i].vertex[j];
edge_a.p2 = stl->facet_start[i].vertex[(j + 1) % 3]; edge_a.p2 = stl->facet_start[i].vertex[(j + 1) % 3];
neighbor = stl->neighbors_start[i].neighbor[j]; neighbor = stl->neighbors_start[i].neighbor[j];
@ -53,19 +54,15 @@ stl_verify_neighbors(stl_file *stl)
if(neighbor == -1) if(neighbor == -1)
continue; /* this edge has no neighbor... Continue. */ continue; /* this edge has no neighbor... Continue. */
if(vnot < 3) if(vnot < 3) {
{
edge_b.p1 = stl->facet_start[neighbor].vertex[(vnot + 2) % 3]; edge_b.p1 = stl->facet_start[neighbor].vertex[(vnot + 2) % 3];
edge_b.p2 = stl->facet_start[neighbor].vertex[(vnot + 1) % 3]; edge_b.p2 = stl->facet_start[neighbor].vertex[(vnot + 1) % 3];
} } else {
else
{
stl->stats.backwards_edges += 1; stl->stats.backwards_edges += 1;
edge_b.p1 = 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]; edge_b.p2 = stl->facet_start[neighbor].vertex[(vnot + 2) % 3];
} }
if(memcmp(&edge_a, &edge_b, SIZEOF_EDGE_SORT) != 0) if(memcmp(&edge_a, &edge_b, SIZEOF_EDGE_SORT) != 0) {
{
/* These edges should match but they don't. Print results. */ /* 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", printf("edge %d of facet %d doesn't match edge %d of facet %d\n",
j, i, vnot + 1, neighbor); j, i, vnot + 1, neighbor);
@ -77,15 +74,39 @@ stl_verify_neighbors(stl_file *stl)
} }
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 -= (stl->stats.min.x - x);
stl->facet_start[i].vertex[j].y -= (stl->stats.min.y - y);
stl->facet_start[i].vertex[j].z -= (stl->stats.min.z - z);
}
}
stl->stats.max.x -= (stl->stats.min.x - x);
stl->stats.max.y -= (stl->stats.min.y - y);
stl->stats.max.z -= (stl->stats.min.z - z);
stl->stats.min.x = x;
stl->stats.min.y = y;
stl->stats.min.z = z;
stl_invalidate_shared_vertices(stl);
}
/* Translates the stl by x,y,z, relatively from wherever it is currently */
void
stl_translate_relative(stl_file *stl, float x, float y, float z) {
int i;
int j;
if (stl->error) return;
for(i = 0; i < stl->stats.number_of_facets; i++) {
for(j = 0; j < 3; j++) {
stl->facet_start[i].vertex[j].x += x; stl->facet_start[i].vertex[j].x += x;
stl->facet_start[i].vertex[j].y += y; stl->facet_start[i].vertex[j].y += y;
stl->facet_start[i].vertex[j].z += z; stl->facet_start[i].vertex[j].z += z;
@ -102,12 +123,13 @@ stl_translate_relative(stl_file *stl, float x, float y, float z)
} }
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];
@ -115,20 +137,18 @@ stl_scale_versor(stl_file *stl, float versor[3])
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].x *= versor[0];
stl->facet_start[i].vertex[j].y *= versor[1]; stl->facet_start[i].vertex[j].y *= versor[1];
stl->facet_start[i].vertex[j].z *= versor[2]; stl->facet_start[i].vertex[j].z *= versor[2];
@ -139,21 +159,24 @@ stl_scale_versor(stl_file *stl, float versor[3])
} }
void void
stl_scale(stl_file *stl, float factor) stl_scale(stl_file *stl, float factor) {
{
float versor[3]; float versor[3];
if (stl->error) return;
versor[0] = factor; versor[0] = factor;
versor[1] = factor; versor[1] = factor;
versor[2] = factor; versor[2] = factor;
stl_scale_versor(stl, versor); 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];
for(i = 0; i < stl->stats.number_of_facets; i++){ if (stl->error) return;
for(i = 0; i < stl->stats.number_of_facets; i++) {
stl_calculate_normal(normal, &stl->facet_start[i]); stl_calculate_normal(normal, &stl->facet_start[i]);
stl_normalize_vector(normal); stl_normalize_vector(normal);
stl->facet_start[i].normal.x = normal[0]; stl->facet_start[i].normal.x = normal[0];
@ -163,15 +186,14 @@ static void calculate_normals(stl_file *stl)
} }
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);
} }
@ -181,15 +203,14 @@ stl_rotate_x(stl_file *stl, float angle)
} }
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);
} }
@ -199,15 +220,14 @@ stl_rotate_y(stl_file *stl, float angle)
} }
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);
} }
@ -219,28 +239,27 @@ stl_rotate_z(stl_file *stl, float angle)
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;
@ -248,10 +267,8 @@ stl_get_size(stl_file *stl)
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->stats.min.x = STL_MIN(stl->stats.min.x,
stl->facet_start[i].vertex[j].x); stl->facet_start[i].vertex[j].x);
stl->stats.min.y = STL_MIN(stl->stats.min.y, stl->stats.min.y = STL_MIN(stl->stats.min.y,
@ -277,16 +294,15 @@ stl_get_size(stl_file *stl)
} }
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;
} }
} }
@ -296,21 +312,19 @@ stl_mirror_xy(stl_file *stl)
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;
} }
} }
@ -320,20 +334,19 @@ stl_mirror_yz(stl_file *stl)
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;
} }
} }
@ -343,11 +356,10 @@ stl_mirror_xz(stl_file *stl)
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;
@ -356,12 +368,14 @@ static float get_volume(stl_file *stl)
float area; float area;
float volume = 0.0; float volume = 0.0;
if (stl->error) return 0;
/* Choose a point, any point as the reference */ /* Choose a point, any point as the reference */
p0.x = stl->facet_start[0].vertex[0].x; p0.x = stl->facet_start[0].vertex[0].x;
p0.y = stl->facet_start[0].vertex[0].y; p0.y = stl->facet_start[0].vertex[0].y;
p0.z = stl->facet_start[0].vertex[0].z; p0.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++) {
p.x = stl->facet_start[i].vertex[0].x - p0.x; p.x = stl->facet_start[i].vertex[0].x - p0.x;
p.y = stl->facet_start[i].vertex[0].y - p0.y; p.y = stl->facet_start[i].vertex[0].y - p0.y;
p.z = stl->facet_start[i].vertex[0].z - p0.z; p.z = stl->facet_start[i].vertex[0].z - p0.z;
@ -374,27 +388,26 @@ static float get_volume(stl_file *stl)
return volume; 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 /* cast to double before calculating cross product because large coordinates
// can result in overflowing product can result in overflowing product
// (bad area is responsible for bad volume and bad facets reversal) (bad area is responsible for bad volume and bad facets reversal) */
for(i = 0; i < 3; i++){ for(i = 0; i < 3; i++) {
cross[i][0]=(((double)facet->vertex[i].y * (double)facet->vertex[(i + 1) % 3].z) - 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)); ((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) - cross[i][1]=(((double)facet->vertex[i].z * (double)facet->vertex[(i + 1) % 3].x) -
@ -414,3 +427,126 @@ static float get_area(stl_facet *facet)
area = 0.5 * (n[0] * sum[0] + n[1] * sum[1] + n[2] * sum[2]); area = 0.5 * (n[0] * sum[0] + n[1] * sum[1] + n[2] * sum[2]);
return area; 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