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
* 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
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Questions, comments, suggestions, etc to <amartin@engr.csulb.edu>
* Questions, comments, suggestions, etc to
* https://github.com/admesh/admesh/issues
*/
#include <stdio.h>
@ -26,13 +28,11 @@
#include "stl.h"
static void stl_reverse_facet(stl_file *stl, int facet_num);
/* static float stl_calculate_area(stl_facet *facet); */
static void stl_reverse_vector(float v[]);
int stl_check_normal_vector(stl_file *stl, int facet_num, int normal_fix_flag);
static void
stl_reverse_facet(stl_file *stl, int facet_num)
{
stl_reverse_facet(stl_file *stl, int facet_num) {
stl_vertex tmp_vertex;
/* int tmp_neighbor;*/
int neighbor[3];
@ -85,8 +85,7 @@ stl_reverse_facet(stl_file *stl, int facet_num)
}
void
stl_fix_normal_directions(stl_file *stl)
{
stl_fix_normal_directions(stl_file *stl) {
char *norm_sw;
/* int edge_num;*/
/* int vnot;*/
@ -95,9 +94,7 @@ stl_fix_normal_directions(stl_file *stl)
/* int next_facet;*/
int i;
int j;
int checked_before = 0;
struct stl_normal
{
struct stl_normal {
int facet_num;
struct stl_normal *next;
};
@ -106,11 +103,12 @@ stl_fix_normal_directions(stl_file *stl)
struct stl_normal *newn;
struct stl_normal *temp;
if (stl->error) return;
/* Initialize linked list. */
head = (stl_normal*)malloc(sizeof(struct stl_normal));
head = (struct stl_normal*)malloc(sizeof(struct stl_normal));
if(head == NULL) perror("stl_fix_normal_directions");
tail = (stl_normal*)malloc(sizeof(struct stl_normal));
tail = (struct stl_normal*)malloc(sizeof(struct stl_normal));
if(tail == NULL) perror("stl_fix_normal_directions");
head->next = tail;
tail->next = tail;
@ -121,44 +119,34 @@ stl_fix_normal_directions(stl_file *stl)
facet_num = 0;
//If normal vector is not within tolerance and backwards:
//Arbitrarily starts at face 0. If this one is wrong, we're screwed. Thankfully, the chances
// of it being wrong randomly are low if most of the triangles are right:
/* If normal vector is not within tolerance and backwards:
Arbitrarily starts at face 0. If this one is wrong, we're screwed. Thankfully, the chances
of it being wrong randomly are low if most of the triangles are right: */
if(stl_check_normal_vector(stl, 0, 0) == 2)
stl_reverse_facet(stl, 0);
//Say that we've fixed this facet:
/* Say that we've fixed this facet: */
norm_sw[facet_num] = 1;
/* edge_num = 0;
vnot = stl->neighbors_start[0].which_vertex_not[0];
*/
checked++;
for(;;)
{
/* Add neighbors_to_list. */
//Add unconnected neighbors to the list:a
for(j = 0; j < 3; j++)
{
for(;;) {
/* Add neighbors_to_list.
Add unconnected neighbors to the list:a */
for(j = 0; j < 3; j++) {
/* Reverse the neighboring facets if necessary. */
if(stl->neighbors_start[facet_num].which_vertex_not[j] > 2)
{
// If the facet has a neighbor that is -1, it means that edge isn't shared by another
// facet.
if(stl->neighbors_start[facet_num].neighbor[j] != -1)
{
if(stl->neighbors_start[facet_num].which_vertex_not[j] > 2) {
/* If the facet has a neighbor that is -1, it means that edge isn't shared by another facet */
if(stl->neighbors_start[facet_num].neighbor[j] != -1) {
stl_reverse_facet
(stl, stl->neighbors_start[facet_num].neighbor[j]);
}
}
//If this edge of the facet is connected:
if(stl->neighbors_start[facet_num].neighbor[j] != -1)
{
//If we haven't fixed this facet yet, add it to the list:
if(norm_sw[stl->neighbors_start[facet_num].neighbor[j]] != 1)
{
/* If this edge of the facet is connected: */
if(stl->neighbors_start[facet_num].neighbor[j] != -1) {
/* If we haven't fixed this facet yet, add it to the list: */
if(norm_sw[stl->neighbors_start[facet_num].neighbor[j]] != 1) {
/* Add node to beginning of list. */
newn = (stl_normal*)malloc(sizeof(struct stl_normal));
newn = (struct stl_normal*)malloc(sizeof(struct stl_normal));
if(newn == NULL) perror("stl_fix_normal_directions");
newn->facet_num = stl->neighbors_start[facet_num].neighbor[j];
newn->next = head->next;
@ -167,40 +155,28 @@ stl_fix_normal_directions(stl_file *stl)
}
}
/* Get next facet to fix from top of list. */
if(head->next != tail)
{
if(head->next != tail) {
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. */
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:
{
} 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)
{
if(checked >= stl->stats.number_of_facets) {
/* All of the facets have been checked. Bail out. */
break;
}
else
{
} 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. */
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)
{
if(stl_check_normal_vector(stl, i, 0) == 2) {
stl_reverse_facet(stl, i);
}
@ -218,8 +194,7 @@ stl_fix_normal_directions(stl_file *stl)
}
int
stl_check_normal_vector(stl_file *stl, int facet_num, int normal_fix_flag)
{
stl_check_normal_vector(stl_file *stl, int facet_num, int normal_fix_flag) {
/* Returns 0 if the normal is within tolerance */
/* Returns 1 if the normal is not within tolerance, but direction is OK */
/* Returns 2 if the normal is not within tolerance and backwards */
@ -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)
&& (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 */
/* but just for consistency, I will. */
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);
if( (ABS(normal[0] - test_norm[0]) < 0.001)
&& (ABS(normal[1] - test_norm[1]) < 0.001)
&& (ABS(normal[2] - test_norm[2]) < 0.001))
{
if(normal_fix_flag)
{
&& (ABS(normal[2] - test_norm[2]) < 0.001)) {
if(normal_fix_flag) {
facet->normal.x = normal[0];
facet->normal.y = normal[1];
facet->normal.z = normal[2];
@ -268,11 +240,9 @@ stl_check_normal_vector(stl_file *stl, int facet_num, int normal_fix_flag)
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))
{
&& (ABS(normal[2] - test_norm[2]) < 0.001)) {
/* Facet is backwards. */
if(normal_fix_flag)
{
if(normal_fix_flag) {
facet->normal.x = normal[0];
facet->normal.y = normal[1];
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;
}
if(normal_fix_flag)
{
if(normal_fix_flag) {
facet->normal.x = normal[0];
facet->normal.y = normal[1];
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
stl_reverse_vector(float v[])
{
stl_reverse_vector(float v[]) {
v[0] *= -1;
v[1] *= -1;
v[2] *= -1;
@ -300,8 +268,7 @@ stl_reverse_vector(float v[])
void
stl_calculate_normal(float normal[], stl_facet *facet)
{
stl_calculate_normal(float normal[], stl_facet *facet) {
float v1[3];
float v2[3];
@ -317,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]);
}
/*
static float
stl_calculate_area(stl_facet *facet)
{
float cross[3][3];
float sum[3];
float normal[3];
float area;
int i;
for(i = 0; i < 3; i++)
{
cross[i][0] = ((facet->vertex[i].y * facet->vertex[(i + 1) % 3].z) -
(facet->vertex[i].z * facet->vertex[(i + 1) % 3].y));
cross[i][1] = ((facet->vertex[i].z * facet->vertex[(i + 1) % 3].x) -
(facet->vertex[i].x * facet->vertex[(i + 1) % 3].z));
cross[i][2] = ((facet->vertex[i].x * facet->vertex[(i + 1) % 3].y) -
(facet->vertex[i].y * facet->vertex[(i + 1) % 3].x));
}
sum[0] = cross[0][0] + cross[1][0] + cross[2][0];
sum[1] = cross[0][1] + cross[1][1] + cross[2][1];
sum[2] = cross[0][2] + cross[1][2] + cross[2][2];
stl_calculate_normal(normal, facet);
stl_normalize_vector(normal);
area = 0.5 * (normal[0] * sum[0] + normal[1] * sum[1] +
normal[2] * sum[2]);
return ABS(area);
}
*/
void stl_normalize_vector(float v[])
{
void stl_normalize_vector(float v[]) {
double length;
double factor;
float min_normal_length;
length = sqrt((double)v[0] * (double)v[0] + (double)v[1] * (double)v[1] + (double)v[2] * (double)v[2]);
min_normal_length = 0.000000000001;
if(length < min_normal_length)
{
if(length < min_normal_length) {
v[0] = 0.0;
v[1] = 0.0;
v[2] = 0.0;
@ -371,24 +304,24 @@ void stl_normalize_vector(float v[])
}
void
stl_fix_normal_values(stl_file *stl)
{
stl_fix_normal_values(stl_file *stl) {
int i;
for(i = 0; i < stl->stats.number_of_facets; i++)
{
if (stl->error) return;
for(i = 0; i < stl->stats.number_of_facets; i++) {
stl_check_normal_vector(stl, i, 1);
}
}
void
stl_reverse_all_facets(stl_file *stl)
{
stl_reverse_all_facets(stl_file *stl) {
int i;
float normal[3];
for(i = 0; i < stl->stats.number_of_facets; i++)
{
if (stl->error) return;
for(i = 0; i < stl->stats.number_of_facets; i++) {
stl_reverse_facet(stl, i);
stl_calculate_normal(normal, &stl->facet_start[i]);
stl_normalize_vector(normal);

View file

@ -1,31 +1,34 @@
/* 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
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Questions, comments, suggestions, etc to <amartin@engr.csulb.edu>
* Questions, comments, suggestions, etc to
* https://github.com/admesh/admesh/issues
*/
#include <cstring>
#include <stdlib.h>
#include <string.h>
#include "stl.h"
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);
stl->v_indices = NULL;
@ -37,8 +40,7 @@ stl_invalidate_shared_vertices(stl_file *stl)
}
void
stl_generate_shared_vertices(stl_file *stl)
{
stl_generate_shared_vertices(stl_file *stl) {
int i;
int j;
int first_facet;
@ -50,7 +52,9 @@ stl_generate_shared_vertices(stl_file *stl)
int next_facet;
int reversed;
// make sure this function is idempotent and does not leak memory
if (stl->error) return;
/* make sure this function is idempotent and does not leak memory */
stl_invalidate_shared_vertices(stl);
stl->v_indices = (v_indices_struct*)
@ -62,25 +66,20 @@ stl_generate_shared_vertices(stl_file *stl)
stl->stats.shared_malloced = stl->stats.number_of_facets / 2;
stl->stats.shared_vertices = 0;
for(i = 0; i < stl->stats.number_of_facets; i++)
{
for(i = 0; i < stl->stats.number_of_facets; i++) {
stl->v_indices[i].vertex[0] = -1;
stl->v_indices[i].vertex[1] = -1;
stl->v_indices[i].vertex[2] = -1;
}
for(i = 0; i < stl->stats.number_of_facets; i++)
{
for(i = 0; i < stl->stats.number_of_facets; i++) {
first_facet = i;
for(j = 0; j < 3; j++)
{
if(stl->v_indices[i].vertex[j] != -1)
{
for(j = 0; j < 3; j++) {
if(stl->v_indices[i].vertex[j] != -1) {
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->v_shared = (stl_vertex*)realloc(stl->v_shared,
stl->stats.shared_malloced * sizeof(stl_vertex));
@ -95,32 +94,22 @@ stl_generate_shared_vertices(stl_file *stl)
facet_num = i;
vnot = (j + 2) % 3;
for(;;)
{
if(vnot > 2)
{
if(direction == 0)
{
for(;;) {
if(vnot > 2) {
if(direction == 0) {
pivot_vertex = (vnot + 2) % 3;
next_edge = pivot_vertex;
direction = 1;
}
else
{
} else {
pivot_vertex = (vnot + 1) % 3;
next_edge = vnot % 3;
direction = 0;
}
}
else
{
if(direction == 0)
{
} else {
if(direction == 0) {
pivot_vertex = (vnot + 1) % 3;
next_edge = vnot;
}
else
{
} else {
pivot_vertex = (vnot + 2) % 3;
next_edge = pivot_vertex;
}
@ -129,28 +118,20 @@ stl_generate_shared_vertices(stl_file *stl)
stl->stats.shared_vertices;
next_facet = stl->neighbors_start[facet_num].neighbor[next_edge];
if(next_facet == -1)
{
if(reversed)
{
if(next_facet == -1) {
if(reversed) {
break;
}
else
{
} else {
direction = 1;
vnot = (j + 1) % 3;
reversed = 1;
facet_num = first_facet;
}
}
else if(next_facet != first_facet)
{
} else if(next_facet != first_facet) {
vnot = stl->neighbors_start[facet_num].
which_vertex_not[next_edge];
facet_num = next_facet;
}
else
{
} else {
break;
}
}
@ -160,37 +141,35 @@ stl_generate_shared_vertices(stl_file *stl)
}
void
stl_write_off(stl_file *stl, char *file)
{
stl_write_off(stl_file *stl, char *file) {
int i;
FILE *fp;
char *error_msg;
if (stl->error) return;
/* Open the file */
fp = fopen(file, "w");
if(fp == NULL)
{
if(fp == NULL) {
error_msg = (char*)
malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */
sprintf(error_msg, "stl_write_ascii: Couldn't open %s for writing",
file);
perror(error_msg);
free(error_msg);
exit(1);
stl->error = 1;
return;
}
fprintf(fp, "OFF\n");
fprintf(fp, "%d %d 0\n",
stl->stats.shared_vertices, stl->stats.number_of_facets);
for(i = 0; i < stl->stats.shared_vertices; i++)
{
for(i = 0; i < stl->stats.shared_vertices; i++) {
fprintf(fp, "\t%f %f %f\n",
stl->v_shared[i].x, stl->v_shared[i].y, stl->v_shared[i].z);
}
for(i = 0; i < stl->stats.number_of_facets; i++)
{
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]);
}
@ -198,24 +177,24 @@ stl_write_off(stl_file *stl, char *file)
}
void
stl_write_vrml(stl_file *stl, char *file)
{
stl_write_vrml(stl_file *stl, char *file) {
int i;
FILE *fp;
char *error_msg;
if (stl->error) return;
/* Open the file */
fp = fopen(file, "w");
if(fp == NULL)
{
if(fp == NULL) {
error_msg = (char*)
malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */
sprintf(error_msg, "stl_write_ascii: Couldn't open %s for writing",
file);
perror(error_msg);
free(error_msg);
exit(1);
stl->error = 1;
return;
}
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\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",
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\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],
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) {
int i;
FILE* fp;
if (stl->error) return;
/* Open the file */
FILE* fp = fopen(file, "w");
fp = fopen(file, "w");
if (fp == NULL) {
char* error_msg = (char*)malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */
sprintf(error_msg, "stl_write_ascii: Couldn't open %s for writing", file);
perror(error_msg);
free(error_msg);
exit(1);
stl->error = 1;
return;
}
for (i = 0; i < stl->stats.shared_vertices; i++) {

View file

@ -1,25 +1,34 @@
/* 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
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Questions, comments, suggestions, etc to <amartin@engr.csulb.edu>
* Questions, comments, suggestions, etc to
* https://github.com/admesh/admesh/issues
*/
#ifndef __admesh_stl__
#define __admesh_stl__
#include <stdio.h>
#ifdef __cplusplus
extern "C" {
#endif
#define STL_MAX(A,B) ((A)>(B)? (A):(B))
#define STL_MIN(A,B) ((A)<(B)? (A):(B))
#define ABS(X) ((X) < 0 ? -(X) : (X))
@ -31,15 +40,13 @@
#define ASCII_LINES_PER_FACET 7
#define SIZEOF_EDGE_SORT 24
typedef struct
{
typedef struct {
float x;
float y;
float z;
} stl_vertex;
typedef struct
{
typedef struct {
float x;
float y;
float z;
@ -47,8 +54,7 @@ typedef struct
typedef char stl_extra[2];
typedef struct
{
typedef struct {
stl_normal normal;
stl_vertex vertex[3];
stl_extra extra;
@ -57,34 +63,29 @@ typedef struct
typedef enum {binary, ascii, inmemory} stl_type;
typedef struct
{
typedef struct {
stl_vertex p1;
stl_vertex p2;
int facet_number;
} stl_edge;
typedef struct stl_hash_edge
{
typedef struct stl_hash_edge {
unsigned key[6];
int facet_number;
int which_edge;
struct stl_hash_edge *next;
} stl_hash_edge;
typedef struct
{
typedef struct {
int neighbor[3];
char which_vertex_not[3];
} stl_neighbors;
typedef struct
{
typedef struct {
int vertex[3];
} v_indices_struct;
typedef struct
{
typedef struct {
char header[81];
stl_type type;
int number_of_facets;
@ -119,8 +120,7 @@ typedef struct
int shared_malloced;
} stl_stats;
typedef struct
{
typedef struct {
FILE *fp;
stl_facet *facet_start;
stl_edge *edge_start;
@ -131,6 +131,7 @@ typedef struct
v_indices_struct *v_indices;
stl_vertex *v_shared;
stl_stats stats;
char error;
} stl_file;
@ -139,8 +140,11 @@ extern void stl_close(stl_file *stl);
extern void stl_stats_out(stl_file *stl, FILE *file, char *input_file);
extern void stl_print_edges(stl_file *stl, FILE *file);
extern void stl_print_neighbors(stl_file *stl, char *file);
extern void stl_put_little_int(FILE *fp, int value_in);
extern void stl_put_little_float(FILE *fp, float value_in);
extern void stl_write_ascii(stl_file *stl, const char *file, const char *label);
extern void stl_write_binary(stl_file *stl, const char *file, const char *label);
extern void stl_write_binary_block(stl_file *stl, FILE *fp);
extern void stl_check_facets_exact(stl_file *stl);
extern void stl_check_facets_nearby(stl_file *stl, float tolerance);
extern void stl_remove_unconnected_facets(stl_file *stl);
@ -154,6 +158,7 @@ extern void stl_fill_holes(stl_file *stl);
extern void stl_fix_normal_directions(stl_file *stl);
extern void stl_fix_normal_values(stl_file *stl);
extern void stl_reverse_all_facets(stl_file *stl);
extern void stl_translate(stl_file *stl, float x, float y, float z);
extern void stl_translate_relative(stl_file *stl, float x, float y, float z);
extern void stl_scale_versor(stl_file *stl, float versor[3]);
extern void stl_scale(stl_file *stl, float factor);
@ -174,11 +179,23 @@ extern void stl_calculate_normal(float normal[], stl_facet *facet);
extern void stl_normalize_vector(float v[]);
extern void stl_calculate_volume(stl_file *stl);
extern void stl_repair(stl_file *stl, int fixall_flag, int exact_flag, int tolerance_flag, float tolerance, int increment_flag, float increment, int nearby_flag, int iterations, int remove_unconnected_flag, int fill_holes_flag, int normal_directions_flag, int normal_values_flag, int reverse_all_flag, int verbose_flag);
extern void stl_initialize(stl_file *stl);
static void stl_count_facets(stl_file *stl, char *file);
extern void stl_count_facets(stl_file *stl, char *file);
extern void stl_allocate(stl_file *stl);
static void stl_read(stl_file *stl, int first_facet, int first);
extern void stl_read(stl_file *stl, int first_facet, int first);
extern void stl_facet_stats(stl_file *stl, stl_facet facet, int first);
extern void stl_reallocate(stl_file *stl);
extern void stl_add_facet(stl_file *stl, stl_facet *new_facet);
extern void stl_get_size(stl_file *stl);
extern void stl_clear_error(stl_file *stl);
extern int stl_get_error(stl_file *stl);
extern void stl_exit_on_error(stl_file *stl);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -1,26 +1,29 @@
/* 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
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Questions, comments, suggestions, etc to <amartin@engr.csulb.edu>
* Questions, comments, suggestions, etc to
* https://github.com/admesh/admesh/issues
*/
#include <cstring>
#include <stdlib.h>
#include <string.h>
#include "stl.h"
#include "config.h"
#if !defined(SEEK_SET)
#define SEEK_SET 0
@ -28,18 +31,15 @@
#define SEEK_END 2
#endif
static void stl_put_little_int(FILE *fp, int value);
static void stl_put_little_float(FILE *fp, float value_in);
void
stl_print_edges(stl_file *stl, FILE *file)
{
stl_print_edges(stl_file *stl, FILE *file) {
int i;
int edges_allocated;
if (stl->error) return;
edges_allocated = stl->stats.number_of_facets * 3;
for(i = 0; i < edges_allocated; i++)
{
for(i = 0; i < edges_allocated; i++) {
fprintf(file, "%d, %f, %f, %f, %f, %f, %f\n",
stl->edge_start[i].facet_number,
stl->edge_start[i].p1.x, stl->edge_start[i].p1.y,
@ -50,19 +50,22 @@ stl_print_edges(stl_file *stl, FILE *file)
void
stl_stats_out(stl_file *stl, FILE *file, char *input_file)
{
stl_stats_out(stl_file *stl, FILE *file, char *input_file) {
if (stl->error) return;
/* this is here for Slic3r, without our config.h
it won't use this part of the code anyway */
#ifndef VERSION
#define VERSION "unknown"
#endif
fprintf(file, "\n\
================= Results produced by ADMesh version 0.95 ================\n");
================= Results produced by ADMesh version " VERSION " ================\n");
fprintf(file, "\
Input file : %s\n", input_file);
if(stl->stats.type == binary)
{
if(stl->stats.type == binary) {
fprintf(file, "\
File type : Binary STL file\n");
}
else
{
} else {
fprintf(file, "\
File type : ASCII STL file\n");
}
@ -121,30 +124,29 @@ Normals fixed : %5d\n", stl->stats.normals_fixed);
}
void
stl_write_ascii(stl_file *stl, const char *file, const char *label)
{
stl_write_ascii(stl_file *stl, const char *file, const char *label) {
int i;
FILE *fp;
char *error_msg;
if (stl->error) return;
/* Open the file */
fp = fopen(file, "w");
if(fp == NULL)
{
if(fp == NULL) {
error_msg = (char*)
malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */
sprintf(error_msg, "stl_write_ascii: Couldn't open %s for writing",
file);
perror(error_msg);
free(error_msg);
exit(1);
stl->error = 1;
return;
}
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",
stl->facet_start[i].normal.x, stl->facet_start[i].normal.y,
stl->facet_start[i].normal.z);
@ -168,27 +170,27 @@ stl_write_ascii(stl_file *stl, const char *file, const char *label)
}
void
stl_print_neighbors(stl_file *stl, char *file)
{
stl_print_neighbors(stl_file *stl, char *file) {
int i;
FILE *fp;
char *error_msg;
if (stl->error) return;
/* Open the file */
fp = fopen(file, "w");
if(fp == NULL)
{
if(fp == NULL) {
error_msg = (char*)
malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */
sprintf(error_msg, "stl_print_neighbors: Couldn't open %s for writing",
file);
perror(error_msg);
free(error_msg);
exit(1);
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",
i,
stl->neighbors_start[i].neighbor[0],
@ -201,12 +203,10 @@ stl_print_neighbors(stl_file *stl, char *file)
fclose(fp);
}
static void
stl_put_little_int(FILE *fp, int value_in)
{
void
stl_put_little_int(FILE *fp, int value_in) {
int new_value;
union
{
union {
int int_value;
char char_value[4];
} value;
@ -220,12 +220,10 @@ stl_put_little_int(FILE *fp, int value_in)
fwrite(&new_value, sizeof(int), 1, fp);
}
static void
stl_put_little_float(FILE *fp, float value_in)
{
void
stl_put_little_float(FILE *fp, float value_in) {
int new_value;
union
{
union {
float float_value;
char char_value[4];
} value;
@ -239,35 +237,10 @@ stl_put_little_float(FILE *fp, float value_in)
fwrite(&new_value, sizeof(int), 1, fp);
}
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;
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++)
{
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[1], fp);
}
}
void
stl_write_binary(stl_file *stl, const char *file, const char *label) {
FILE *fp;
int i;
char *error_msg;
if (stl->error) return;
/* Open the file */
fp = fopen(file, "w");
if(fp == NULL) {
error_msg = (char*)
malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */
sprintf(error_msg, "stl_write_binary: Couldn't open %s for writing",
file);
perror(error_msg);
free(error_msg);
stl->error = 1;
return;
}
fprintf(fp, "%s", label);
for(i = strlen(label); i < LABEL_SIZE; i++) putc(0, fp);
fseek(fp, LABEL_SIZE, SEEK_SET);
stl_put_little_int(fp, stl->stats.number_of_facets);
stl_write_binary_block(stl, fp);
fclose(fp);
}
void
stl_write_vertex(stl_file *stl, int facet, int vertex)
{
stl_write_vertex(stl_file *stl, int facet, int vertex) {
if (stl->error) return;
printf(" vertex %d/%d % .8E % .8E % .8E\n", vertex, facet,
stl->facet_start[facet].vertex[vertex].x,
stl->facet_start[facet].vertex[vertex].y,
@ -299,8 +303,8 @@ stl_write_vertex(stl_file *stl, int facet, int vertex)
}
void
stl_write_facet(stl_file *stl, char *label, int facet)
{
stl_write_facet(stl_file *stl, char *label, int facet) {
if (stl->error) return;
printf("facet (%d)/ %s\n", facet, label);
stl_write_vertex(stl, facet, 0);
stl_write_vertex(stl, facet, 1);
@ -308,24 +312,21 @@ stl_write_facet(stl_file *stl, char *label, int facet)
}
void
stl_write_edge(stl_file *stl, char *label, stl_hash_edge edge)
{
stl_write_edge(stl_file *stl, char *label, stl_hash_edge edge) {
if (stl->error) return;
printf("edge (%d)/(%d) %s\n", edge.facet_number, edge.which_edge, label);
if(edge.which_edge < 3)
{
if(edge.which_edge < 3) {
stl_write_vertex(stl, edge.facet_number, edge.which_edge % 3);
stl_write_vertex(stl, edge.facet_number, (edge.which_edge + 1) % 3);
}
else
{
} else {
stl_write_vertex(stl, edge.facet_number, (edge.which_edge + 1) % 3);
stl_write_vertex(stl, edge.facet_number, edge.which_edge % 3);
}
}
void
stl_write_neighbor(stl_file *stl, int facet)
{
stl_write_neighbor(stl_file *stl, int facet) {
if (stl->error) return;
printf("Neighbors %d: %d, %d, %d ; %d, %d, %d\n", facet,
stl->neighbors_start[facet].neighbor[0],
stl->neighbors_start[facet].neighbor[1],
@ -336,8 +337,7 @@ stl_write_neighbor(stl_file *stl, int facet)
}
void
stl_write_quad_object(stl_file *stl, char *file)
{
stl_write_quad_object(stl_file *stl, char *file) {
FILE *fp;
int i;
int j;
@ -348,17 +348,19 @@ stl_write_quad_object(stl_file *stl, char *file)
stl_vertex uncon_3_color;
stl_vertex color;
if (stl->error) return;
/* Open the file */
fp = fopen(file, "w");
if(fp == NULL)
{
if(fp == NULL) {
error_msg = (char*)
malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */
sprintf(error_msg, "stl_write_quad_object: Couldn't open %s for writing",
file);
perror(error_msg);
free(error_msg);
exit(1);
stl->error = 1;
return;
}
connect_color.x = 0.0;
@ -375,25 +377,17 @@ stl_write_quad_object(stl_file *stl, char *file)
uncon_3_color.z = 0.0;
fprintf(fp, "CQUAD\n");
for(i = 0; i < stl->stats.number_of_facets; i++)
{
for(i = 0; i < stl->stats.number_of_facets; i++) {
j = ((stl->neighbors_start[i].neighbor[0] == -1) +
(stl->neighbors_start[i].neighbor[1] == -1) +
(stl->neighbors_start[i].neighbor[2] == -1));
if(j == 0)
{
if(j == 0) {
color = connect_color;
}
else if(j == 1)
{
} else if(j == 1) {
color = uncon_1_color;
}
else if(j == 2)
{
} else if(j == 2) {
color = uncon_2_color;
}
else
{
} else {
color = uncon_3_color;
}
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
stl_write_dxf(stl_file *stl, char *file, char *label)
{
stl_write_dxf(stl_file *stl, char *file, char *label) {
int i;
FILE *fp;
char *error_msg;
if (stl->error) return;
/* Open the file */
fp = fopen(file, "w");
if(fp == NULL)
{
if(fp == NULL) {
error_msg = (char*)
malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */
sprintf(error_msg, "stl_write_ascii: Couldn't open %s for writing",
file);
perror(error_msg);
free(error_msg);
exit(1);
stl->error = 1;
return;
}
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");
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, "10\n%f\n20\n%f\n30\n%f\n",
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);
}
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
* 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
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Questions, comments, suggestions, etc to <amartin@engr.csulb.edu>
* Questions, comments, suggestions, etc to
* https://github.com/admesh/admesh/issues
*/
#include <stdio.h>
@ -32,19 +34,18 @@
#endif
void
stl_open(stl_file *stl, char *file)
{
stl_open(stl_file *stl, char *file) {
stl_initialize(stl);
stl_count_facets(stl, file);
stl_allocate(stl);
stl_read(stl, 0, 1);
fclose(stl->fp);
if (!stl->error) fclose(stl->fp);
}
void
stl_initialize(stl_file *stl)
{
stl_initialize(stl_file *stl) {
stl->error = 0;
stl->stats.degenerate_facets = 0;
stl->stats.edges_fixed = 0;
stl->stats.facets_added = 0;
@ -63,28 +64,30 @@ stl_initialize(stl_file *stl)
stl->v_shared = NULL;
}
static void
stl_count_facets(stl_file *stl, char *file)
{
void
stl_count_facets(stl_file *stl, char *file) {
long file_size;
int header_num_facets;
int num_facets;
int i, j;
size_t s;
unsigned char chtest[128];
int num_lines = 1;
char *error_msg;
if (stl->error) return;
/* Open the file */
stl->fp = fopen(file, "r");
if(stl->fp == NULL)
{
if(stl->fp == NULL) {
error_msg = (char*)
malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */
sprintf(error_msg, "stl_initialize: Couldn't open %s for reading",
file);
perror(error_msg);
free(error_msg);
exit(1);
stl->error = 1;
return;
}
/* Find size of file */
fseek(stl->fp, 0, SEEK_END);
@ -92,14 +95,16 @@ stl_count_facets(stl_file *stl, char *file)
/* Check for binary or ASCII file */
fseek(stl->fp, HEADER_SIZE, SEEK_SET);
fread(chtest, sizeof(chtest), 1, stl->fp);
if (!fread(chtest, sizeof(chtest), 1, stl->fp)) {
perror("The input is an empty file");
stl->error = 1;
return;
}
stl->stats.type = ascii;
for(i = 0; i < sizeof(chtest); i++)
{
if(chtest[i] > 127)
{
for(s = 0; s < sizeof(chtest); s++) {
if(chtest[s] > 127) {
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);
stl->fp = fopen(file, "rb");
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 */
/* 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 */
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);
exit(1);
stl->error = 1;
return;
}
num_facets = (file_size - HEADER_SIZE) / SIZEOF_STL_FACET;
/* 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';
}
/* 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)
{
if((!fread(&header_num_facets, sizeof(int), 1, stl->fp)) || (num_facets != header_num_facets)) {
fprintf(stderr,
"Warning: File size doesn't match number of facets in the header\n");
}
}
/* Otherwise, if the .STL file is ASCII, then do the following */
else
{
else {
/* Find the number of facets */
j = 0;
for(i = 0; i < file_size ; i++)
{
for(i = 0; i < file_size ; i++) {
j++;
if(getc(stl->fp) == '\n')
{
if(j > 4) /* don't count short lines */
{
if(getc(stl->fp) == '\n') {
if(j > 4) { /* don't count short lines */
num_lines++;
}
j = 0;
@ -164,8 +163,9 @@ stl_count_facets(stl_file *stl, char *file)
}
void
stl_allocate(stl_file *stl)
{
stl_allocate(stl_file *stl) {
if (stl->error) return;
/* Allocate memory for the entire .STL file */
stl->facet_start = (stl_facet*)calloc(stl->stats.number_of_facets,
sizeof(stl_facet));
@ -179,20 +179,54 @@ stl_allocate(stl_file *stl)
}
void
stl_open_merge(stl_file *stl, char *file)
{
int first_facet;
stl_open_merge(stl_file *stl, char *file_to_merge) {
int num_facets_so_far;
stl_type origStlType;
FILE *origFp;
stl_file stl_to_merge;
first_facet = stl->stats.number_of_facets;
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_read(stl, first_facet, 0);
/* Read the file to merge directly into stl, adding it to what we have already.
Start at num_facets_so_far, the index to the first unused facet. Also say
that this isn't our first time so we should augment stats like min and max
instead of erasing them. */
stl_read(stl, num_facets_so_far, 0);
/* Restore the stl information we overwrote (for stl_read) so that it still accurately
reflects the subject part: */
stl->stats.type=origStlType;
stl->fp=origFp;
}
extern void
stl_reallocate(stl_file *stl)
{
stl_reallocate(stl_file *stl) {
if (stl->error) return;
/* Reallocate more memory for the .STL file(s) */
stl->facet_start = (stl_facet*)realloc(stl->facet_start, stl->stats.number_of_facets *
sizeof(stl_facet));
@ -206,47 +240,51 @@ stl_reallocate(stl_file *stl)
if(stl->facet_start == NULL) perror("stl_initialize");
}
static void
stl_read(stl_file *stl, int first_facet, int first)
{
/* Reads the contents of the file pointed to by stl->fp into the stl structure,
starting at facet first_facet. The second argument says if it's our first
time running this for the stl and therefore we should reset our max and min stats. */
void
stl_read(stl_file *stl, int first_facet, int first) {
stl_facet facet;
int i;
if(stl->stats.type == binary)
{
if (stl->error) return;
if(stl->stats.type == binary) {
fseek(stl->fp, HEADER_SIZE, SEEK_SET);
}
else
{
} 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++)
{
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 */
{
// we assume little-endian architecture!
fread(&facet.normal, sizeof(stl_normal), 1, stl->fp);
fread(&facet.vertex, sizeof(stl_vertex), 3, stl->fp);
fread(&facet.extra, sizeof(char), 2, stl->fp);
/* we assume little-endian architecture! */
if (fread(&facet.normal, sizeof(stl_normal), 1, stl->fp) \
+ fread(&facet.vertex, sizeof(stl_vertex), 3, stl->fp) \
+ fread(&facet.extra, sizeof(char), 2, stl->fp) != 6) {
perror("Cannot read facet");
stl->error = 1;
return;
}
else
} else
/* Read a single facet from an ASCII .STL file */
{
fscanf(stl->fp, "%*s %*s %f %f %f\n", &facet.normal.x,
&facet.normal.y, &facet.normal.z);
fscanf(stl->fp, "%*s %*s");
fscanf(stl->fp, "%*s %f %f %f\n", &facet.vertex[0].x,
&facet.vertex[0].y, &facet.vertex[0].z);
fscanf(stl->fp, "%*s %f %f %f\n", &facet.vertex[1].x,
&facet.vertex[1].y, &facet.vertex[1].z);
fscanf(stl->fp, "%*s %f %f %f\n", &facet.vertex[2].x,
&facet.vertex[2].y, &facet.vertex[2].z);
fscanf(stl->fp, "%*s");
fscanf(stl->fp, "%*s");
if((fscanf(stl->fp, "%*s %*s %f %f %f\n", &facet.normal.x, &facet.normal.y, &facet.normal.z) + \
fscanf(stl->fp, "%*s %*s") + \
fscanf(stl->fp, "%*s %f %f %f\n", &facet.vertex[0].x, &facet.vertex[0].y, &facet.vertex[0].z) + \
fscanf(stl->fp, "%*s %f %f %f\n", &facet.vertex[1].x, &facet.vertex[1].y, &facet.vertex[1].z) + \
fscanf(stl->fp, "%*s %f %f %f\n", &facet.vertex[2].x, &facet.vertex[2].y, &facet.vertex[2].z) + \
fscanf(stl->fp, "%*s") + \
fscanf(stl->fp, "%*s")) != 12) {
perror("Something is syntactically very wrong with this ASCII STL!");
stl->error = 1;
return;
}
}
/* Write the facet into memory. */
stl->facet_start[i] = facet;
@ -265,12 +303,14 @@ stl_read(stl_file *stl, int first_facet, int first)
}
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_y;
float diff_z;
float max_diff;
if (stl->error) return;
/* while we are going through all of the facets, let's find the */
/* maximum and minimum values for x, y, and z */
@ -317,8 +357,9 @@ stl_facet_stats(stl_file *stl, stl_facet facet, int first)
}
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->facet_start != NULL)

View file

@ -1,21 +1,23 @@
/* 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
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Questions, comments, suggestions, etc to <amartin@engr.csulb.edu>
* Questions, comments, suggestions, etc to
* https://github.com/admesh/admesh/issues
*/
#include <stdio.h>
@ -31,8 +33,7 @@ static float get_volume(stl_file *stl);
void
stl_verify_neighbors(stl_file *stl)
{
stl_verify_neighbors(stl_file *stl) {
int i;
int j;
stl_edge edge_a;
@ -40,12 +41,12 @@ stl_verify_neighbors(stl_file *stl)
int neighbor;
int vnot;
if (stl->error) return;
stl->stats.backwards_edges = 0;
for(i = 0; i < stl->stats.number_of_facets; i++)
{
for(j = 0; j < 3; j++)
{
for(i = 0; i < stl->stats.number_of_facets; i++) {
for(j = 0; j < 3; j++) {
edge_a.p1 = stl->facet_start[i].vertex[j];
edge_a.p2 = stl->facet_start[i].vertex[(j + 1) % 3];
neighbor = stl->neighbors_start[i].neighbor[j];
@ -53,19 +54,15 @@ stl_verify_neighbors(stl_file *stl)
if(neighbor == -1)
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.p2 = stl->facet_start[neighbor].vertex[(vnot + 1) % 3];
}
else
{
} else {
stl->stats.backwards_edges += 1;
edge_b.p1 = stl->facet_start[neighbor].vertex[(vnot + 1) % 3];
edge_b.p2 = stl->facet_start[neighbor].vertex[(vnot + 2) % 3];
}
if(memcmp(&edge_a, &edge_b, SIZEOF_EDGE_SORT) != 0)
{
if(memcmp(&edge_a, &edge_b, SIZEOF_EDGE_SORT) != 0) {
/* These edges should match but they don't. Print results. */
printf("edge %d of facet %d doesn't match edge %d of facet %d\n",
j, i, vnot + 1, neighbor);
@ -77,15 +74,39 @@ stl_verify_neighbors(stl_file *stl)
}
void
stl_translate_relative(stl_file *stl, float x, float y, float z)
{
stl_translate(stl_file *stl, float x, float y, float z) {
int i;
int j;
for(i = 0; i < stl->stats.number_of_facets; i++)
{
for(j = 0; j < 3; j++)
{
if (stl->error) return;
for(i = 0; i < stl->stats.number_of_facets; i++) {
for(j = 0; j < 3; j++) {
stl->facet_start[i].vertex[j].x -= (stl->stats.min.x - x);
stl->facet_start[i].vertex[j].y -= (stl->stats.min.y - y);
stl->facet_start[i].vertex[j].z -= (stl->stats.min.z - z);
}
}
stl->stats.max.x -= (stl->stats.min.x - x);
stl->stats.max.y -= (stl->stats.min.y - y);
stl->stats.max.z -= (stl->stats.min.z - z);
stl->stats.min.x = x;
stl->stats.min.y = y;
stl->stats.min.z = z;
stl_invalidate_shared_vertices(stl);
}
/* Translates the stl by x,y,z, relatively from wherever it is currently */
void
stl_translate_relative(stl_file *stl, float x, float y, float z) {
int i;
int j;
if (stl->error) return;
for(i = 0; i < stl->stats.number_of_facets; i++) {
for(j = 0; j < 3; j++) {
stl->facet_start[i].vertex[j].x += x;
stl->facet_start[i].vertex[j].y += y;
stl->facet_start[i].vertex[j].z += z;
@ -102,12 +123,13 @@ stl_translate_relative(stl_file *stl, float x, float y, float z)
}
void
stl_scale_versor(stl_file *stl, float versor[3])
{
stl_scale_versor(stl_file *stl, float versor[3]) {
int i;
int j;
// scale extents
if (stl->error) return;
/* scale extents */
stl->stats.min.x *= versor[0];
stl->stats.min.y *= versor[1];
stl->stats.min.z *= versor[2];
@ -115,20 +137,18 @@ stl_scale_versor(stl_file *stl, float versor[3])
stl->stats.max.y *= versor[1];
stl->stats.max.z *= versor[2];
// scale size
/* scale size */
stl->stats.size.x *= versor[0];
stl->stats.size.y *= versor[1];
stl->stats.size.z *= versor[2];
// scale volume
/* scale volume */
if (stl->stats.volume > 0.0) {
stl->stats.volume *= (versor[0] * versor[1] * versor[2]);
}
for(i = 0; i < stl->stats.number_of_facets; i++)
{
for(j = 0; j < 3; j++)
{
for(i = 0; i < stl->stats.number_of_facets; i++) {
for(j = 0; j < 3; j++) {
stl->facet_start[i].vertex[j].x *= versor[0];
stl->facet_start[i].vertex[j].y *= versor[1];
stl->facet_start[i].vertex[j].z *= versor[2];
@ -139,20 +159,23 @@ stl_scale_versor(stl_file *stl, float versor[3])
}
void
stl_scale(stl_file *stl, float factor)
{
stl_scale(stl_file *stl, float factor) {
float versor[3];
if (stl->error) return;
versor[0] = factor;
versor[1] = factor;
versor[2] = factor;
stl_scale_versor(stl, versor);
}
static void calculate_normals(stl_file *stl)
{
static void calculate_normals(stl_file *stl) {
long i;
float normal[3];
if (stl->error) return;
for(i = 0; i < stl->stats.number_of_facets; i++) {
stl_calculate_normal(normal, &stl->facet_start[i]);
stl_normalize_vector(normal);
@ -163,15 +186,14 @@ static void calculate_normals(stl_file *stl)
}
void
stl_rotate_x(stl_file *stl, float angle)
{
stl_rotate_x(stl_file *stl, float angle) {
int i;
int j;
for(i = 0; i < stl->stats.number_of_facets; i++)
{
for(j = 0; j < 3; j++)
{
if (stl->error) return;
for(i = 0; i < stl->stats.number_of_facets; i++) {
for(j = 0; j < 3; j++) {
stl_rotate(&stl->facet_start[i].vertex[j].y,
&stl->facet_start[i].vertex[j].z, angle);
}
@ -181,15 +203,14 @@ stl_rotate_x(stl_file *stl, float angle)
}
void
stl_rotate_y(stl_file *stl, float angle)
{
stl_rotate_y(stl_file *stl, float angle) {
int i;
int j;
for(i = 0; i < stl->stats.number_of_facets; i++)
{
for(j = 0; j < 3; j++)
{
if (stl->error) return;
for(i = 0; i < stl->stats.number_of_facets; i++) {
for(j = 0; j < 3; j++) {
stl_rotate(&stl->facet_start[i].vertex[j].z,
&stl->facet_start[i].vertex[j].x, angle);
}
@ -199,15 +220,14 @@ stl_rotate_y(stl_file *stl, float angle)
}
void
stl_rotate_z(stl_file *stl, float angle)
{
stl_rotate_z(stl_file *stl, float angle) {
int i;
int j;
for(i = 0; i < stl->stats.number_of_facets; i++)
{
for(j = 0; j < 3; j++)
{
if (stl->error) return;
for(i = 0; i < stl->stats.number_of_facets; i++) {
for(j = 0; j < 3; j++) {
stl_rotate(&stl->facet_start[i].vertex[j].x,
&stl->facet_start[i].vertex[j].y, angle);
}
@ -219,8 +239,7 @@ stl_rotate_z(stl_file *stl, float angle)
static void
stl_rotate(float *x, float *y, float angle)
{
stl_rotate(float *x, float *y, float angle) {
double r;
double theta;
double radian_angle;
@ -234,13 +253,13 @@ stl_rotate(float *x, float *y, float angle)
}
extern void
stl_get_size(stl_file *stl)
{
if (stl->stats.number_of_facets == 0) return;
stl_get_size(stl_file *stl) {
int i;
int j;
if (stl->error) return;
if (stl->stats.number_of_facets == 0) return;
stl->stats.min.x = stl->facet_start[0].vertex[0].x;
stl->stats.min.y = stl->facet_start[0].vertex[0].y;
stl->stats.min.z = stl->facet_start[0].vertex[0].z;
@ -248,10 +267,8 @@ stl_get_size(stl_file *stl)
stl->stats.max.y = stl->facet_start[0].vertex[0].y;
stl->stats.max.z = stl->facet_start[0].vertex[0].z;
for(i = 0; i < stl->stats.number_of_facets; i++)
{
for(j = 0; j < 3; j++)
{
for(i = 0; i < stl->stats.number_of_facets; i++) {
for(j = 0; j < 3; j++) {
stl->stats.min.x = STL_MIN(stl->stats.min.x,
stl->facet_start[i].vertex[j].x);
stl->stats.min.y = STL_MIN(stl->stats.min.y,
@ -277,16 +294,15 @@ stl_get_size(stl_file *stl)
}
void
stl_mirror_xy(stl_file *stl)
{
stl_mirror_xy(stl_file *stl) {
int i;
int j;
float temp_size;
for(i = 0; i < stl->stats.number_of_facets; i++)
{
for(j = 0; j < 3; j++)
{
if (stl->error) return;
for(i = 0; i < stl->stats.number_of_facets; i++) {
for(j = 0; j < 3; j++) {
stl->facet_start[i].vertex[j].z *= -1.0;
}
}
@ -296,21 +312,19 @@ stl_mirror_xy(stl_file *stl)
stl->stats.min.z *= -1.0;
stl->stats.max.z *= -1.0;
stl_reverse_all_facets(stl);
stl->stats.facets_reversed -= stl->stats.number_of_facets; // for not altering stats
stl->stats.facets_reversed -= stl->stats.number_of_facets; /* for not altering stats */
}
void
stl_mirror_yz(stl_file *stl)
{
stl_mirror_yz(stl_file *stl) {
int i;
int j;
float temp_size;
for(i = 0; i < stl->stats.number_of_facets; i++)
{
for(j = 0; j < 3; j++)
{
if (stl->error) return;
for(i = 0; i < stl->stats.number_of_facets; i++) {
for(j = 0; j < 3; j++) {
stl->facet_start[i].vertex[j].x *= -1.0;
}
}
@ -320,20 +334,19 @@ stl_mirror_yz(stl_file *stl)
stl->stats.min.x *= -1.0;
stl->stats.max.x *= -1.0;
stl_reverse_all_facets(stl);
stl->stats.facets_reversed -= stl->stats.number_of_facets; // for not altering stats
stl->stats.facets_reversed -= stl->stats.number_of_facets; /* for not altering stats */
}
void
stl_mirror_xz(stl_file *stl)
{
stl_mirror_xz(stl_file *stl) {
int i;
int j;
float temp_size;
for(i = 0; i < stl->stats.number_of_facets; i++)
{
for(j = 0; j < 3; j++)
{
if (stl->error) return;
for(i = 0; i < stl->stats.number_of_facets; i++) {
for(j = 0; j < 3; j++) {
stl->facet_start[i].vertex[j].y *= -1.0;
}
}
@ -343,11 +356,10 @@ stl_mirror_xz(stl_file *stl)
stl->stats.min.y *= -1.0;
stl->stats.max.y *= -1.0;
stl_reverse_all_facets(stl);
stl->stats.facets_reversed -= stl->stats.number_of_facets; // for not altering stats
stl->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;
stl_vertex p0;
stl_vertex p;
@ -356,6 +368,8 @@ static float get_volume(stl_file *stl)
float area;
float volume = 0.0;
if (stl->error) return 0;
/* Choose a point, any point as the reference */
p0.x = stl->facet_start[0].vertex[0].x;
p0.y = stl->facet_start[0].vertex[0].y;
@ -374,8 +388,8 @@ static float get_volume(stl_file *stl)
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);
if(stl->stats.volume < 0.0) {
stl_reverse_all_facets(stl);
@ -383,17 +397,16 @@ void stl_calculate_volume(stl_file *stl)
}
}
static float get_area(stl_facet *facet)
{
static float get_area(stl_facet *facet) {
double cross[3][3];
float sum[3];
float n[3];
float area;
int i;
// cast to double before calculating cross product because large coordinates
// can result in overflowing product
// (bad area is responsible for bad volume and bad facets reversal)
/* 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));
@ -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]);
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.tail = NULL;
this->stl.error = other.stl.error;
if (other.stl.facet_start != NULL) {
this->stl.facet_start = (stl_facet*)calloc(other.stl.stats.number_of_facets, sizeof(stl_facet));
std::copy(other.stl.facet_start, other.stl.facet_start + other.stl.stats.number_of_facets, this->stl.facet_start);
@ -125,6 +126,7 @@ TriangleMesh::repair() {
// fill_holes
if (stl.stats.connected_facets_3_edge < stl.stats.number_of_facets) {
stl_fill_holes(&stl);
stl_clear_error(&stl);
}
// normal_directions
@ -280,6 +282,7 @@ TriangleMesh::split() const
mesh->stl.stats.type = inmemory;
mesh->stl.stats.number_of_facets = facets.size();
mesh->stl.stats.original_num_facets = mesh->stl.stats.number_of_facets;
stl_clear_error(&mesh->stl);
stl_allocate(&mesh->stl);
int first = 1;
@ -389,6 +392,7 @@ TriangleMesh::to_SV() {
void TriangleMesh::ReadFromPerl(SV* vertices, SV* facets)
{
stl.error = 0;
stl.stats.type = inmemory;
// count facets and allocate memory