admesh 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/ext/admesh/admesh/AUTHORS +11 -0
- data/ext/admesh/admesh/COPYING +339 -0
- data/ext/admesh/admesh/ChangeLog +143 -0
- data/ext/admesh/admesh/ChangeLog.old +42 -0
- data/ext/admesh/admesh/INSTALL +14 -0
- data/ext/admesh/admesh/Makefile.am +62 -0
- data/ext/admesh/admesh/Makefile.in +1100 -0
- data/ext/admesh/admesh/README.md +115 -0
- data/ext/admesh/admesh/aclocal.m4 +1183 -0
- data/ext/admesh/admesh/admesh-doc.txt +475 -0
- data/ext/admesh/admesh/admesh.1 +173 -0
- data/ext/admesh/admesh/block.stl +86 -0
- data/ext/admesh/admesh/compile +347 -0
- data/ext/admesh/admesh/config.guess +1420 -0
- data/ext/admesh/admesh/config.h.in +65 -0
- data/ext/admesh/admesh/config.sub +1798 -0
- data/ext/admesh/admesh/configure +14671 -0
- data/ext/admesh/admesh/configure.ac +90 -0
- data/ext/admesh/admesh/depcomp +791 -0
- data/ext/admesh/admesh/install-sh +527 -0
- data/ext/admesh/admesh/libadmesh.pc.in +11 -0
- data/ext/admesh/admesh/ltmain.sh +9655 -0
- data/ext/admesh/admesh/m4/libtool.m4 +7992 -0
- data/ext/admesh/admesh/m4/ltoptions.m4 +384 -0
- data/ext/admesh/admesh/m4/ltsugar.m4 +123 -0
- data/ext/admesh/admesh/m4/ltversion.m4 +23 -0
- data/ext/admesh/admesh/m4/lt~obsolete.m4 +98 -0
- data/ext/admesh/admesh/missing +215 -0
- data/ext/admesh/admesh/src/admesh.c +425 -0
- data/ext/admesh/admesh/src/connect.c +971 -0
- data/ext/admesh/admesh/src/normals.c +333 -0
- data/ext/admesh/admesh/src/shared.c +262 -0
- data/ext/admesh/admesh/src/stl.h +201 -0
- data/ext/admesh/admesh/src/stl_io.c +479 -0
- data/ext/admesh/admesh/src/stlinit.c +377 -0
- data/ext/admesh/admesh/src/util.c +557 -0
- data/ext/admesh/extconf.rb +14 -0
- data/lib/admesh.rb +40 -0
- metadata +84 -0
@@ -0,0 +1,377 @@
|
|
1
|
+
/* ADMesh -- process triangulated solid meshes
|
2
|
+
* Copyright (C) 1995, 1996 Anthony D. Martin <amartin@engr.csulb.edu>
|
3
|
+
* Copyright (C) 2013, 2014 several contributors, see AUTHORS
|
4
|
+
*
|
5
|
+
* This program is free software; you can redistribute it and/or modify
|
6
|
+
* it under the terms of the GNU General Public License as published by
|
7
|
+
* the Free Software Foundation; either version 2 of the License, or
|
8
|
+
* (at your option) any later version.
|
9
|
+
|
10
|
+
* This program is distributed in the hope that it will be useful,
|
11
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
* GNU General Public License for more details.
|
14
|
+
|
15
|
+
* You should have received a copy of the GNU General Public License along
|
16
|
+
* with this program; if not, write to the Free Software Foundation, Inc.,
|
17
|
+
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
18
|
+
*
|
19
|
+
* Questions, comments, suggestions, etc to
|
20
|
+
* https://github.com/admesh/admesh/issues
|
21
|
+
*/
|
22
|
+
|
23
|
+
#include <stdio.h>
|
24
|
+
#include <stdlib.h>
|
25
|
+
#include <string.h>
|
26
|
+
#include <math.h>
|
27
|
+
|
28
|
+
#include "stl.h"
|
29
|
+
|
30
|
+
#if !defined(SEEK_SET)
|
31
|
+
#define SEEK_SET 0
|
32
|
+
#define SEEK_CUR 1
|
33
|
+
#define SEEK_END 2
|
34
|
+
#endif
|
35
|
+
|
36
|
+
void
|
37
|
+
stl_open(stl_file *stl, char *file) {
|
38
|
+
stl_initialize(stl);
|
39
|
+
stl_count_facets(stl, file);
|
40
|
+
stl_allocate(stl);
|
41
|
+
stl_read(stl, 0, 1);
|
42
|
+
if (!stl->error) fclose(stl->fp);
|
43
|
+
}
|
44
|
+
|
45
|
+
|
46
|
+
void
|
47
|
+
stl_initialize(stl_file *stl) {
|
48
|
+
stl->error = 0;
|
49
|
+
stl->stats.backwards_edges = 0;
|
50
|
+
stl->stats.degenerate_facets = 0;
|
51
|
+
stl->stats.edges_fixed = 0;
|
52
|
+
stl->stats.facets_added = 0;
|
53
|
+
stl->stats.facets_removed = 0;
|
54
|
+
stl->stats.facets_reversed = 0;
|
55
|
+
stl->stats.normals_fixed = 0;
|
56
|
+
stl->stats.number_of_parts = 0;
|
57
|
+
stl->stats.original_num_facets = 0;
|
58
|
+
stl->stats.number_of_facets = 0;
|
59
|
+
stl->stats.facets_malloced = 0;
|
60
|
+
stl->stats.volume = -1.0;
|
61
|
+
|
62
|
+
stl->neighbors_start = NULL;
|
63
|
+
stl->facet_start = NULL;
|
64
|
+
stl->v_indices = NULL;
|
65
|
+
stl->v_shared = NULL;
|
66
|
+
}
|
67
|
+
|
68
|
+
void
|
69
|
+
stl_count_facets(stl_file *stl, char *file) {
|
70
|
+
long file_size;
|
71
|
+
int header_num_facets;
|
72
|
+
int num_facets;
|
73
|
+
int i, j;
|
74
|
+
size_t s;
|
75
|
+
unsigned char chtest[128];
|
76
|
+
int num_lines = 1;
|
77
|
+
char *error_msg;
|
78
|
+
|
79
|
+
if (stl->error) return;
|
80
|
+
|
81
|
+
/* Open the file in binary mode first */
|
82
|
+
stl->fp = fopen(file, "rb");
|
83
|
+
if(stl->fp == NULL) {
|
84
|
+
error_msg = (char*)
|
85
|
+
malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */
|
86
|
+
sprintf(error_msg, "stl_initialize: Couldn't open %s for reading",
|
87
|
+
file);
|
88
|
+
perror(error_msg);
|
89
|
+
free(error_msg);
|
90
|
+
stl->error = 1;
|
91
|
+
return;
|
92
|
+
}
|
93
|
+
/* Find size of file */
|
94
|
+
fseek(stl->fp, 0, SEEK_END);
|
95
|
+
file_size = ftell(stl->fp);
|
96
|
+
|
97
|
+
/* Check for binary or ASCII file */
|
98
|
+
fseek(stl->fp, HEADER_SIZE, SEEK_SET);
|
99
|
+
if (!fread(chtest, sizeof(chtest), 1, stl->fp)) {
|
100
|
+
perror("The input is an empty file");
|
101
|
+
stl->error = 1;
|
102
|
+
return;
|
103
|
+
}
|
104
|
+
stl->stats.type = ascii;
|
105
|
+
for(s = 0; s < sizeof(chtest); s++) {
|
106
|
+
if(chtest[s] > 127) {
|
107
|
+
stl->stats.type = binary;
|
108
|
+
break;
|
109
|
+
}
|
110
|
+
}
|
111
|
+
rewind(stl->fp);
|
112
|
+
|
113
|
+
/* Get the header and the number of facets in the .STL file */
|
114
|
+
/* If the .STL file is binary, then do the following */
|
115
|
+
if(stl->stats.type == binary) {
|
116
|
+
/* Test if the STL file has the right size */
|
117
|
+
if(((file_size - HEADER_SIZE) % SIZEOF_STL_FACET != 0)
|
118
|
+
|| (file_size < STL_MIN_FILE_SIZE)) {
|
119
|
+
fprintf(stderr, "The file %s has the wrong size.\n", file);
|
120
|
+
stl->error = 1;
|
121
|
+
return;
|
122
|
+
}
|
123
|
+
num_facets = (file_size - HEADER_SIZE) / SIZEOF_STL_FACET;
|
124
|
+
|
125
|
+
/* Read the header */
|
126
|
+
if (fread(stl->stats.header, LABEL_SIZE, 1, stl->fp) > 79) {
|
127
|
+
stl->stats.header[80] = '\0';
|
128
|
+
}
|
129
|
+
|
130
|
+
/* Read the int following the header. This should contain # of facets */
|
131
|
+
if((!fread(&header_num_facets, sizeof(int), 1, stl->fp)) || (num_facets != header_num_facets)) {
|
132
|
+
fprintf(stderr,
|
133
|
+
"Warning: File size doesn't match number of facets in the header\n");
|
134
|
+
}
|
135
|
+
}
|
136
|
+
/* Otherwise, if the .STL file is ASCII, then do the following */
|
137
|
+
else {
|
138
|
+
/* Reopen the file in text mode (for getting correct newlines on Windows) */
|
139
|
+
if (freopen(file, "r", stl->fp) == NULL) {
|
140
|
+
perror("Could not reopen the file, something went wrong");
|
141
|
+
stl->error = 1;
|
142
|
+
return;
|
143
|
+
}
|
144
|
+
|
145
|
+
/* Find the number of facets */
|
146
|
+
j = 0;
|
147
|
+
for(i = 0; i < file_size ; i++) {
|
148
|
+
j++;
|
149
|
+
if(getc(stl->fp) == '\n') {
|
150
|
+
if(j > 4) { /* don't count short lines */
|
151
|
+
num_lines++;
|
152
|
+
}
|
153
|
+
j = 0;
|
154
|
+
}
|
155
|
+
}
|
156
|
+
rewind(stl->fp);
|
157
|
+
|
158
|
+
/* Get the header */
|
159
|
+
for(i = 0;
|
160
|
+
(i < 80) && (stl->stats.header[i] = getc(stl->fp)) != '\n'; i++);
|
161
|
+
stl->stats.header[i] = '\0'; /* Lose the '\n' */
|
162
|
+
stl->stats.header[80] = '\0';
|
163
|
+
|
164
|
+
num_facets = num_lines / ASCII_LINES_PER_FACET;
|
165
|
+
}
|
166
|
+
stl->stats.number_of_facets += num_facets;
|
167
|
+
stl->stats.original_num_facets = stl->stats.number_of_facets;
|
168
|
+
}
|
169
|
+
|
170
|
+
void
|
171
|
+
stl_allocate(stl_file *stl) {
|
172
|
+
if (stl->error) return;
|
173
|
+
|
174
|
+
/* Allocate memory for the entire .STL file */
|
175
|
+
stl->facet_start = (stl_facet*)calloc(stl->stats.number_of_facets,
|
176
|
+
sizeof(stl_facet));
|
177
|
+
if(stl->facet_start == NULL) perror("stl_initialize");
|
178
|
+
stl->stats.facets_malloced = stl->stats.number_of_facets;
|
179
|
+
|
180
|
+
/* Allocate memory for the neighbors list */
|
181
|
+
stl->neighbors_start = (stl_neighbors*)
|
182
|
+
calloc(stl->stats.number_of_facets, sizeof(stl_neighbors));
|
183
|
+
if(stl->facet_start == NULL) perror("stl_initialize");
|
184
|
+
}
|
185
|
+
|
186
|
+
void
|
187
|
+
stl_open_merge(stl_file *stl, char *file_to_merge) {
|
188
|
+
int num_facets_so_far;
|
189
|
+
stl_type origStlType;
|
190
|
+
FILE *origFp;
|
191
|
+
stl_file stl_to_merge;
|
192
|
+
|
193
|
+
if (stl->error) return;
|
194
|
+
|
195
|
+
/* Record how many facets we have so far from the first file. We will start putting
|
196
|
+
facets in the next position. Since we're 0-indexed, it'l be the same position. */
|
197
|
+
num_facets_so_far = stl->stats.number_of_facets;
|
198
|
+
|
199
|
+
/* Record the file type we started with: */
|
200
|
+
origStlType=stl->stats.type;
|
201
|
+
/* Record the file pointer too: */
|
202
|
+
origFp=stl->fp;
|
203
|
+
|
204
|
+
/* Initialize the sturucture with zero stats, header info and sizes: */
|
205
|
+
stl_initialize(&stl_to_merge);
|
206
|
+
stl_count_facets(&stl_to_merge, file_to_merge);
|
207
|
+
|
208
|
+
/* Copy what we need to into stl so that we can read the file_to_merge directly into it
|
209
|
+
using stl_read: Save the rest of the valuable info: */
|
210
|
+
stl->stats.type=stl_to_merge.stats.type;
|
211
|
+
stl->fp=stl_to_merge.fp;
|
212
|
+
|
213
|
+
/* Add the number of facets we already have in stl with what we we found in stl_to_merge but
|
214
|
+
haven't read yet. */
|
215
|
+
stl->stats.number_of_facets=num_facets_so_far+stl_to_merge.stats.number_of_facets;
|
216
|
+
|
217
|
+
/* Allocate enough room for stl->stats.number_of_facets facets and neighbors: */
|
218
|
+
stl_reallocate(stl);
|
219
|
+
|
220
|
+
/* Read the file to merge directly into stl, adding it to what we have already.
|
221
|
+
Start at num_facets_so_far, the index to the first unused facet. Also say
|
222
|
+
that this isn't our first time so we should augment stats like min and max
|
223
|
+
instead of erasing them. */
|
224
|
+
stl_read(stl, num_facets_so_far, 0);
|
225
|
+
|
226
|
+
/* Restore the stl information we overwrote (for stl_read) so that it still accurately
|
227
|
+
reflects the subject part: */
|
228
|
+
stl->stats.type=origStlType;
|
229
|
+
stl->fp=origFp;
|
230
|
+
}
|
231
|
+
|
232
|
+
extern void
|
233
|
+
stl_reallocate(stl_file *stl) {
|
234
|
+
if (stl->error) return;
|
235
|
+
/* Reallocate more memory for the .STL file(s) */
|
236
|
+
stl->facet_start = (stl_facet*)realloc(stl->facet_start, stl->stats.number_of_facets *
|
237
|
+
sizeof(stl_facet));
|
238
|
+
if(stl->facet_start == NULL) perror("stl_initialize");
|
239
|
+
stl->stats.facets_malloced = stl->stats.number_of_facets;
|
240
|
+
|
241
|
+
/* Reallocate more memory for the neighbors list */
|
242
|
+
stl->neighbors_start = (stl_neighbors*)
|
243
|
+
realloc(stl->neighbors_start, stl->stats.number_of_facets *
|
244
|
+
sizeof(stl_neighbors));
|
245
|
+
if(stl->facet_start == NULL) perror("stl_initialize");
|
246
|
+
}
|
247
|
+
|
248
|
+
|
249
|
+
/* Reads the contents of the file pointed to by stl->fp into the stl structure,
|
250
|
+
starting at facet first_facet. The second argument says if it's our first
|
251
|
+
time running this for the stl and therefore we should reset our max and min stats. */
|
252
|
+
void
|
253
|
+
stl_read(stl_file *stl, int first_facet, int first) {
|
254
|
+
stl_facet facet;
|
255
|
+
int i;
|
256
|
+
|
257
|
+
if (stl->error) return;
|
258
|
+
|
259
|
+
if(stl->stats.type == binary) {
|
260
|
+
fseek(stl->fp, HEADER_SIZE, SEEK_SET);
|
261
|
+
} else {
|
262
|
+
rewind(stl->fp);
|
263
|
+
/* Skip the first line of the file */
|
264
|
+
while(getc(stl->fp) != '\n');
|
265
|
+
}
|
266
|
+
|
267
|
+
for(i = first_facet; i < stl->stats.number_of_facets; i++) {
|
268
|
+
if(stl->stats.type == binary)
|
269
|
+
/* Read a single facet from a binary .STL file */
|
270
|
+
{
|
271
|
+
/* we assume little-endian architecture! */
|
272
|
+
if (fread(&facet.normal, sizeof(stl_normal), 1, stl->fp) \
|
273
|
+
+ fread(&facet.vertex, sizeof(stl_vertex), 3, stl->fp) \
|
274
|
+
+ fread(&facet.extra, sizeof(char), 2, stl->fp) != 6) {
|
275
|
+
perror("Cannot read facet");
|
276
|
+
stl->error = 1;
|
277
|
+
return;
|
278
|
+
}
|
279
|
+
} else
|
280
|
+
/* Read a single facet from an ASCII .STL file */
|
281
|
+
{
|
282
|
+
if((fscanf(stl->fp, "%*s %*s %f %f %f\n", &facet.normal.x, &facet.normal.y, &facet.normal.z) + \
|
283
|
+
fscanf(stl->fp, "%*s %*s") + \
|
284
|
+
fscanf(stl->fp, "%*s %f %f %f\n", &facet.vertex[0].x, &facet.vertex[0].y, &facet.vertex[0].z) + \
|
285
|
+
fscanf(stl->fp, "%*s %f %f %f\n", &facet.vertex[1].x, &facet.vertex[1].y, &facet.vertex[1].z) + \
|
286
|
+
fscanf(stl->fp, "%*s %f %f %f\n", &facet.vertex[2].x, &facet.vertex[2].y, &facet.vertex[2].z) + \
|
287
|
+
fscanf(stl->fp, "%*s") + \
|
288
|
+
fscanf(stl->fp, "%*s")) != 12) {
|
289
|
+
perror("Something is syntactically very wrong with this ASCII STL!");
|
290
|
+
stl->error = 1;
|
291
|
+
return;
|
292
|
+
}
|
293
|
+
}
|
294
|
+
/* Write the facet into memory. */
|
295
|
+
stl->facet_start[i] = facet;
|
296
|
+
|
297
|
+
stl_facet_stats(stl, facet, first);
|
298
|
+
first = 0;
|
299
|
+
}
|
300
|
+
stl->stats.size.x = stl->stats.max.x - stl->stats.min.x;
|
301
|
+
stl->stats.size.y = stl->stats.max.y - stl->stats.min.y;
|
302
|
+
stl->stats.size.z = stl->stats.max.z - stl->stats.min.z;
|
303
|
+
stl->stats.bounding_diameter = sqrt(
|
304
|
+
stl->stats.size.x * stl->stats.size.x +
|
305
|
+
stl->stats.size.y * stl->stats.size.y +
|
306
|
+
stl->stats.size.z * stl->stats.size.z
|
307
|
+
);
|
308
|
+
}
|
309
|
+
|
310
|
+
void
|
311
|
+
stl_facet_stats(stl_file *stl, stl_facet facet, int first) {
|
312
|
+
float diff_x;
|
313
|
+
float diff_y;
|
314
|
+
float diff_z;
|
315
|
+
float max_diff;
|
316
|
+
|
317
|
+
if (stl->error) return;
|
318
|
+
|
319
|
+
/* while we are going through all of the facets, let's find the */
|
320
|
+
/* maximum and minimum values for x, y, and z */
|
321
|
+
|
322
|
+
/* Initialize the max and min values the first time through*/
|
323
|
+
if (first) {
|
324
|
+
stl->stats.max.x = facet.vertex[0].x;
|
325
|
+
stl->stats.min.x = facet.vertex[0].x;
|
326
|
+
stl->stats.max.y = facet.vertex[0].y;
|
327
|
+
stl->stats.min.y = facet.vertex[0].y;
|
328
|
+
stl->stats.max.z = facet.vertex[0].z;
|
329
|
+
stl->stats.min.z = facet.vertex[0].z;
|
330
|
+
|
331
|
+
diff_x = ABS(facet.vertex[0].x - facet.vertex[1].x);
|
332
|
+
diff_y = ABS(facet.vertex[0].y - facet.vertex[1].y);
|
333
|
+
diff_z = ABS(facet.vertex[0].z - facet.vertex[1].z);
|
334
|
+
max_diff = STL_MAX(diff_x, diff_y);
|
335
|
+
max_diff = STL_MAX(diff_z, max_diff);
|
336
|
+
stl->stats.shortest_edge = max_diff;
|
337
|
+
|
338
|
+
first = 0;
|
339
|
+
}
|
340
|
+
|
341
|
+
/* now find the max and min values */
|
342
|
+
stl->stats.max.x = STL_MAX(stl->stats.max.x, facet.vertex[0].x);
|
343
|
+
stl->stats.min.x = STL_MIN(stl->stats.min.x, facet.vertex[0].x);
|
344
|
+
stl->stats.max.y = STL_MAX(stl->stats.max.y, facet.vertex[0].y);
|
345
|
+
stl->stats.min.y = STL_MIN(stl->stats.min.y, facet.vertex[0].y);
|
346
|
+
stl->stats.max.z = STL_MAX(stl->stats.max.z, facet.vertex[0].z);
|
347
|
+
stl->stats.min.z = STL_MIN(stl->stats.min.z, facet.vertex[0].z);
|
348
|
+
|
349
|
+
stl->stats.max.x = STL_MAX(stl->stats.max.x, facet.vertex[1].x);
|
350
|
+
stl->stats.min.x = STL_MIN(stl->stats.min.x, facet.vertex[1].x);
|
351
|
+
stl->stats.max.y = STL_MAX(stl->stats.max.y, facet.vertex[1].y);
|
352
|
+
stl->stats.min.y = STL_MIN(stl->stats.min.y, facet.vertex[1].y);
|
353
|
+
stl->stats.max.z = STL_MAX(stl->stats.max.z, facet.vertex[1].z);
|
354
|
+
stl->stats.min.z = STL_MIN(stl->stats.min.z, facet.vertex[1].z);
|
355
|
+
|
356
|
+
stl->stats.max.x = STL_MAX(stl->stats.max.x, facet.vertex[2].x);
|
357
|
+
stl->stats.min.x = STL_MIN(stl->stats.min.x, facet.vertex[2].x);
|
358
|
+
stl->stats.max.y = STL_MAX(stl->stats.max.y, facet.vertex[2].y);
|
359
|
+
stl->stats.min.y = STL_MIN(stl->stats.min.y, facet.vertex[2].y);
|
360
|
+
stl->stats.max.z = STL_MAX(stl->stats.max.z, facet.vertex[2].z);
|
361
|
+
stl->stats.min.z = STL_MIN(stl->stats.min.z, facet.vertex[2].z);
|
362
|
+
}
|
363
|
+
|
364
|
+
void
|
365
|
+
stl_close(stl_file *stl) {
|
366
|
+
if (stl->error) return;
|
367
|
+
|
368
|
+
if(stl->neighbors_start != NULL)
|
369
|
+
free(stl->neighbors_start);
|
370
|
+
if(stl->facet_start != NULL)
|
371
|
+
free(stl->facet_start);
|
372
|
+
if(stl->v_indices != NULL)
|
373
|
+
free(stl->v_indices);
|
374
|
+
if(stl->v_shared != NULL)
|
375
|
+
free(stl->v_shared);
|
376
|
+
}
|
377
|
+
|
@@ -0,0 +1,557 @@
|
|
1
|
+
/* ADMesh -- process triangulated solid meshes
|
2
|
+
* Copyright (C) 1995, 1996 Anthony D. Martin <amartin@engr.csulb.edu>
|
3
|
+
* Copyright (C) 2013, 2014 several contributors, see AUTHORS
|
4
|
+
*
|
5
|
+
* This program is free software; you can redistribute it and/or modify
|
6
|
+
* it under the terms of the GNU General Public License as published by
|
7
|
+
* the Free Software Foundation; either version 2 of the License, or
|
8
|
+
* (at your option) any later version.
|
9
|
+
|
10
|
+
* This program is distributed in the hope that it will be useful,
|
11
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
* GNU General Public License for more details.
|
14
|
+
|
15
|
+
* You should have received a copy of the GNU General Public License along
|
16
|
+
* with this program; if not, write to the Free Software Foundation, Inc.,
|
17
|
+
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
18
|
+
*
|
19
|
+
* Questions, comments, suggestions, etc to
|
20
|
+
* https://github.com/admesh/admesh/issues
|
21
|
+
*/
|
22
|
+
|
23
|
+
#include <stdio.h>
|
24
|
+
#include <stdlib.h>
|
25
|
+
#include <string.h>
|
26
|
+
#include <math.h>
|
27
|
+
|
28
|
+
#include "stl.h"
|
29
|
+
|
30
|
+
static void stl_rotate(float *x, float *y, float angle);
|
31
|
+
static float get_area(stl_facet *facet);
|
32
|
+
static float get_volume(stl_file *stl);
|
33
|
+
|
34
|
+
|
35
|
+
void
|
36
|
+
stl_verify_neighbors(stl_file *stl) {
|
37
|
+
int i;
|
38
|
+
int j;
|
39
|
+
stl_edge edge_a;
|
40
|
+
stl_edge edge_b;
|
41
|
+
int neighbor;
|
42
|
+
int vnot;
|
43
|
+
|
44
|
+
if (stl->error) return;
|
45
|
+
|
46
|
+
stl->stats.backwards_edges = 0;
|
47
|
+
|
48
|
+
for(i = 0; i < stl->stats.number_of_facets; i++) {
|
49
|
+
for(j = 0; j < 3; j++) {
|
50
|
+
edge_a.p1 = stl->facet_start[i].vertex[j];
|
51
|
+
edge_a.p2 = stl->facet_start[i].vertex[(j + 1) % 3];
|
52
|
+
neighbor = stl->neighbors_start[i].neighbor[j];
|
53
|
+
vnot = stl->neighbors_start[i].which_vertex_not[j];
|
54
|
+
|
55
|
+
if(neighbor == -1)
|
56
|
+
continue; /* this edge has no neighbor... Continue. */
|
57
|
+
if(vnot < 3) {
|
58
|
+
edge_b.p1 = stl->facet_start[neighbor].vertex[(vnot + 2) % 3];
|
59
|
+
edge_b.p2 = stl->facet_start[neighbor].vertex[(vnot + 1) % 3];
|
60
|
+
} else {
|
61
|
+
stl->stats.backwards_edges += 1;
|
62
|
+
edge_b.p1 = stl->facet_start[neighbor].vertex[(vnot + 1) % 3];
|
63
|
+
edge_b.p2 = stl->facet_start[neighbor].vertex[(vnot + 2) % 3];
|
64
|
+
}
|
65
|
+
if(memcmp(&edge_a, &edge_b, SIZEOF_EDGE_SORT) != 0) {
|
66
|
+
/* These edges should match but they don't. Print results. */
|
67
|
+
printf("edge %d of facet %d doesn't match edge %d of facet %d\n",
|
68
|
+
j, i, vnot + 1, neighbor);
|
69
|
+
stl_write_facet(stl, (char*)"first facet", i);
|
70
|
+
stl_write_facet(stl, (char*)"second facet", neighbor);
|
71
|
+
}
|
72
|
+
}
|
73
|
+
}
|
74
|
+
}
|
75
|
+
|
76
|
+
void
|
77
|
+
stl_translate(stl_file *stl, float x, float y, float z) {
|
78
|
+
int i;
|
79
|
+
int j;
|
80
|
+
|
81
|
+
if (stl->error) return;
|
82
|
+
|
83
|
+
for(i = 0; i < stl->stats.number_of_facets; i++) {
|
84
|
+
for(j = 0; j < 3; j++) {
|
85
|
+
stl->facet_start[i].vertex[j].x -= (stl->stats.min.x - x);
|
86
|
+
stl->facet_start[i].vertex[j].y -= (stl->stats.min.y - y);
|
87
|
+
stl->facet_start[i].vertex[j].z -= (stl->stats.min.z - z);
|
88
|
+
}
|
89
|
+
}
|
90
|
+
stl->stats.max.x -= (stl->stats.min.x - x);
|
91
|
+
stl->stats.max.y -= (stl->stats.min.y - y);
|
92
|
+
stl->stats.max.z -= (stl->stats.min.z - z);
|
93
|
+
stl->stats.min.x = x;
|
94
|
+
stl->stats.min.y = y;
|
95
|
+
stl->stats.min.z = z;
|
96
|
+
|
97
|
+
stl_invalidate_shared_vertices(stl);
|
98
|
+
}
|
99
|
+
|
100
|
+
/* Translates the stl by x,y,z, relatively from wherever it is currently */
|
101
|
+
void
|
102
|
+
stl_translate_relative(stl_file *stl, float x, float y, float z) {
|
103
|
+
int i;
|
104
|
+
int j;
|
105
|
+
|
106
|
+
if (stl->error) return;
|
107
|
+
|
108
|
+
for(i = 0; i < stl->stats.number_of_facets; i++) {
|
109
|
+
for(j = 0; j < 3; j++) {
|
110
|
+
stl->facet_start[i].vertex[j].x += x;
|
111
|
+
stl->facet_start[i].vertex[j].y += y;
|
112
|
+
stl->facet_start[i].vertex[j].z += z;
|
113
|
+
}
|
114
|
+
}
|
115
|
+
stl->stats.min.x += x;
|
116
|
+
stl->stats.min.y += y;
|
117
|
+
stl->stats.min.z += z;
|
118
|
+
stl->stats.max.x += x;
|
119
|
+
stl->stats.max.y += y;
|
120
|
+
stl->stats.max.z += z;
|
121
|
+
|
122
|
+
stl_invalidate_shared_vertices(stl);
|
123
|
+
}
|
124
|
+
|
125
|
+
void
|
126
|
+
stl_scale_versor(stl_file *stl, float versor[3]) {
|
127
|
+
int i;
|
128
|
+
int j;
|
129
|
+
|
130
|
+
if (stl->error) return;
|
131
|
+
|
132
|
+
/* scale extents */
|
133
|
+
stl->stats.min.x *= versor[0];
|
134
|
+
stl->stats.min.y *= versor[1];
|
135
|
+
stl->stats.min.z *= versor[2];
|
136
|
+
stl->stats.max.x *= versor[0];
|
137
|
+
stl->stats.max.y *= versor[1];
|
138
|
+
stl->stats.max.z *= versor[2];
|
139
|
+
|
140
|
+
/* scale size */
|
141
|
+
stl->stats.size.x *= versor[0];
|
142
|
+
stl->stats.size.y *= versor[1];
|
143
|
+
stl->stats.size.z *= versor[2];
|
144
|
+
|
145
|
+
/* scale volume */
|
146
|
+
if (stl->stats.volume > 0.0) {
|
147
|
+
stl->stats.volume *= (versor[0] * versor[1] * versor[2]);
|
148
|
+
}
|
149
|
+
|
150
|
+
for(i = 0; i < stl->stats.number_of_facets; i++) {
|
151
|
+
for(j = 0; j < 3; j++) {
|
152
|
+
stl->facet_start[i].vertex[j].x *= versor[0];
|
153
|
+
stl->facet_start[i].vertex[j].y *= versor[1];
|
154
|
+
stl->facet_start[i].vertex[j].z *= versor[2];
|
155
|
+
}
|
156
|
+
}
|
157
|
+
|
158
|
+
stl_invalidate_shared_vertices(stl);
|
159
|
+
}
|
160
|
+
|
161
|
+
void
|
162
|
+
stl_scale(stl_file *stl, float factor) {
|
163
|
+
float versor[3];
|
164
|
+
|
165
|
+
if (stl->error) return;
|
166
|
+
|
167
|
+
versor[0] = factor;
|
168
|
+
versor[1] = factor;
|
169
|
+
versor[2] = factor;
|
170
|
+
stl_scale_versor(stl, versor);
|
171
|
+
}
|
172
|
+
|
173
|
+
static void calculate_normals(stl_file *stl) {
|
174
|
+
long i;
|
175
|
+
float normal[3];
|
176
|
+
|
177
|
+
if (stl->error) return;
|
178
|
+
|
179
|
+
for(i = 0; i < stl->stats.number_of_facets; i++) {
|
180
|
+
stl_calculate_normal(normal, &stl->facet_start[i]);
|
181
|
+
stl_normalize_vector(normal);
|
182
|
+
stl->facet_start[i].normal.x = normal[0];
|
183
|
+
stl->facet_start[i].normal.y = normal[1];
|
184
|
+
stl->facet_start[i].normal.z = normal[2];
|
185
|
+
}
|
186
|
+
}
|
187
|
+
|
188
|
+
void
|
189
|
+
stl_rotate_x(stl_file *stl, float angle) {
|
190
|
+
int i;
|
191
|
+
int j;
|
192
|
+
|
193
|
+
if (stl->error) return;
|
194
|
+
|
195
|
+
for(i = 0; i < stl->stats.number_of_facets; i++) {
|
196
|
+
for(j = 0; j < 3; j++) {
|
197
|
+
stl_rotate(&stl->facet_start[i].vertex[j].y,
|
198
|
+
&stl->facet_start[i].vertex[j].z, angle);
|
199
|
+
}
|
200
|
+
}
|
201
|
+
stl_get_size(stl);
|
202
|
+
calculate_normals(stl);
|
203
|
+
}
|
204
|
+
|
205
|
+
void
|
206
|
+
stl_rotate_y(stl_file *stl, float angle) {
|
207
|
+
int i;
|
208
|
+
int j;
|
209
|
+
|
210
|
+
if (stl->error) return;
|
211
|
+
|
212
|
+
for(i = 0; i < stl->stats.number_of_facets; i++) {
|
213
|
+
for(j = 0; j < 3; j++) {
|
214
|
+
stl_rotate(&stl->facet_start[i].vertex[j].z,
|
215
|
+
&stl->facet_start[i].vertex[j].x, angle);
|
216
|
+
}
|
217
|
+
}
|
218
|
+
stl_get_size(stl);
|
219
|
+
calculate_normals(stl);
|
220
|
+
}
|
221
|
+
|
222
|
+
void
|
223
|
+
stl_rotate_z(stl_file *stl, float angle) {
|
224
|
+
int i;
|
225
|
+
int j;
|
226
|
+
|
227
|
+
if (stl->error) return;
|
228
|
+
|
229
|
+
for(i = 0; i < stl->stats.number_of_facets; i++) {
|
230
|
+
for(j = 0; j < 3; j++) {
|
231
|
+
stl_rotate(&stl->facet_start[i].vertex[j].x,
|
232
|
+
&stl->facet_start[i].vertex[j].y, angle);
|
233
|
+
}
|
234
|
+
}
|
235
|
+
stl_get_size(stl);
|
236
|
+
calculate_normals(stl);
|
237
|
+
}
|
238
|
+
|
239
|
+
|
240
|
+
|
241
|
+
static void
|
242
|
+
stl_rotate(float *x, float *y, float angle) {
|
243
|
+
double r;
|
244
|
+
double theta;
|
245
|
+
double radian_angle;
|
246
|
+
|
247
|
+
radian_angle = (angle / 180.0) * M_PI;
|
248
|
+
|
249
|
+
r = sqrt((*x **x) + (*y **y));
|
250
|
+
theta = atan2(*y, *x);
|
251
|
+
*x = r * cos(theta + radian_angle);
|
252
|
+
*y = r * sin(theta + radian_angle);
|
253
|
+
}
|
254
|
+
|
255
|
+
extern void
|
256
|
+
stl_get_size(stl_file *stl) {
|
257
|
+
int i;
|
258
|
+
int j;
|
259
|
+
|
260
|
+
if (stl->error) return;
|
261
|
+
if (stl->stats.number_of_facets == 0) return;
|
262
|
+
|
263
|
+
stl->stats.min.x = stl->facet_start[0].vertex[0].x;
|
264
|
+
stl->stats.min.y = stl->facet_start[0].vertex[0].y;
|
265
|
+
stl->stats.min.z = stl->facet_start[0].vertex[0].z;
|
266
|
+
stl->stats.max.x = stl->facet_start[0].vertex[0].x;
|
267
|
+
stl->stats.max.y = stl->facet_start[0].vertex[0].y;
|
268
|
+
stl->stats.max.z = stl->facet_start[0].vertex[0].z;
|
269
|
+
|
270
|
+
for(i = 0; i < stl->stats.number_of_facets; i++) {
|
271
|
+
for(j = 0; j < 3; j++) {
|
272
|
+
stl->stats.min.x = STL_MIN(stl->stats.min.x,
|
273
|
+
stl->facet_start[i].vertex[j].x);
|
274
|
+
stl->stats.min.y = STL_MIN(stl->stats.min.y,
|
275
|
+
stl->facet_start[i].vertex[j].y);
|
276
|
+
stl->stats.min.z = STL_MIN(stl->stats.min.z,
|
277
|
+
stl->facet_start[i].vertex[j].z);
|
278
|
+
stl->stats.max.x = STL_MAX(stl->stats.max.x,
|
279
|
+
stl->facet_start[i].vertex[j].x);
|
280
|
+
stl->stats.max.y = STL_MAX(stl->stats.max.y,
|
281
|
+
stl->facet_start[i].vertex[j].y);
|
282
|
+
stl->stats.max.z = STL_MAX(stl->stats.max.z,
|
283
|
+
stl->facet_start[i].vertex[j].z);
|
284
|
+
}
|
285
|
+
}
|
286
|
+
stl->stats.size.x = stl->stats.max.x - stl->stats.min.x;
|
287
|
+
stl->stats.size.y = stl->stats.max.y - stl->stats.min.y;
|
288
|
+
stl->stats.size.z = stl->stats.max.z - stl->stats.min.z;
|
289
|
+
stl->stats.bounding_diameter = sqrt(
|
290
|
+
stl->stats.size.x * stl->stats.size.x +
|
291
|
+
stl->stats.size.y * stl->stats.size.y +
|
292
|
+
stl->stats.size.z * stl->stats.size.z
|
293
|
+
);
|
294
|
+
}
|
295
|
+
|
296
|
+
void
|
297
|
+
stl_mirror_xy(stl_file *stl) {
|
298
|
+
int i;
|
299
|
+
int j;
|
300
|
+
float temp_size;
|
301
|
+
|
302
|
+
if (stl->error) return;
|
303
|
+
|
304
|
+
for(i = 0; i < stl->stats.number_of_facets; i++) {
|
305
|
+
for(j = 0; j < 3; j++) {
|
306
|
+
stl->facet_start[i].vertex[j].z *= -1.0;
|
307
|
+
}
|
308
|
+
}
|
309
|
+
temp_size = stl->stats.min.z;
|
310
|
+
stl->stats.min.z = stl->stats.max.z;
|
311
|
+
stl->stats.max.z = temp_size;
|
312
|
+
stl->stats.min.z *= -1.0;
|
313
|
+
stl->stats.max.z *= -1.0;
|
314
|
+
stl_reverse_all_facets(stl);
|
315
|
+
stl->stats.facets_reversed -= stl->stats.number_of_facets; /* for not altering stats */
|
316
|
+
}
|
317
|
+
|
318
|
+
void
|
319
|
+
stl_mirror_yz(stl_file *stl) {
|
320
|
+
int i;
|
321
|
+
int j;
|
322
|
+
float temp_size;
|
323
|
+
|
324
|
+
if (stl->error) return;
|
325
|
+
|
326
|
+
for(i = 0; i < stl->stats.number_of_facets; i++) {
|
327
|
+
for(j = 0; j < 3; j++) {
|
328
|
+
stl->facet_start[i].vertex[j].x *= -1.0;
|
329
|
+
}
|
330
|
+
}
|
331
|
+
temp_size = stl->stats.min.x;
|
332
|
+
stl->stats.min.x = stl->stats.max.x;
|
333
|
+
stl->stats.max.x = temp_size;
|
334
|
+
stl->stats.min.x *= -1.0;
|
335
|
+
stl->stats.max.x *= -1.0;
|
336
|
+
stl_reverse_all_facets(stl);
|
337
|
+
stl->stats.facets_reversed -= stl->stats.number_of_facets; /* for not altering stats */
|
338
|
+
}
|
339
|
+
|
340
|
+
void
|
341
|
+
stl_mirror_xz(stl_file *stl) {
|
342
|
+
int i;
|
343
|
+
int j;
|
344
|
+
float temp_size;
|
345
|
+
|
346
|
+
if (stl->error) return;
|
347
|
+
|
348
|
+
for(i = 0; i < stl->stats.number_of_facets; i++) {
|
349
|
+
for(j = 0; j < 3; j++) {
|
350
|
+
stl->facet_start[i].vertex[j].y *= -1.0;
|
351
|
+
}
|
352
|
+
}
|
353
|
+
temp_size = stl->stats.min.y;
|
354
|
+
stl->stats.min.y = stl->stats.max.y;
|
355
|
+
stl->stats.max.y = temp_size;
|
356
|
+
stl->stats.min.y *= -1.0;
|
357
|
+
stl->stats.max.y *= -1.0;
|
358
|
+
stl_reverse_all_facets(stl);
|
359
|
+
stl->stats.facets_reversed -= stl->stats.number_of_facets; /* for not altering stats */
|
360
|
+
}
|
361
|
+
|
362
|
+
static float get_volume(stl_file *stl) {
|
363
|
+
long i;
|
364
|
+
stl_vertex p0;
|
365
|
+
stl_vertex p;
|
366
|
+
stl_normal n;
|
367
|
+
float height;
|
368
|
+
float area;
|
369
|
+
float volume = 0.0;
|
370
|
+
|
371
|
+
if (stl->error) return 0;
|
372
|
+
|
373
|
+
/* Choose a point, any point as the reference */
|
374
|
+
p0.x = stl->facet_start[0].vertex[0].x;
|
375
|
+
p0.y = stl->facet_start[0].vertex[0].y;
|
376
|
+
p0.z = stl->facet_start[0].vertex[0].z;
|
377
|
+
|
378
|
+
for(i = 0; i < stl->stats.number_of_facets; i++) {
|
379
|
+
p.x = stl->facet_start[i].vertex[0].x - p0.x;
|
380
|
+
p.y = stl->facet_start[i].vertex[0].y - p0.y;
|
381
|
+
p.z = stl->facet_start[i].vertex[0].z - p0.z;
|
382
|
+
/* Do dot product to get distance from point to plane */
|
383
|
+
n = stl->facet_start[i].normal;
|
384
|
+
height = (n.x * p.x) + (n.y * p.y) + (n.z * p.z);
|
385
|
+
area = get_area(&stl->facet_start[i]);
|
386
|
+
volume += (area * height) / 3.0;
|
387
|
+
}
|
388
|
+
return volume;
|
389
|
+
}
|
390
|
+
|
391
|
+
void stl_calculate_volume(stl_file *stl) {
|
392
|
+
if (stl->error) return;
|
393
|
+
stl->stats.volume = get_volume(stl);
|
394
|
+
}
|
395
|
+
|
396
|
+
static float get_area(stl_facet *facet) {
|
397
|
+
double cross[3][3];
|
398
|
+
float sum[3];
|
399
|
+
float n[3];
|
400
|
+
float area;
|
401
|
+
int i;
|
402
|
+
|
403
|
+
/* cast to double before calculating cross product because large coordinates
|
404
|
+
can result in overflowing product
|
405
|
+
(bad area is responsible for bad volume and bad facets reversal) */
|
406
|
+
for(i = 0; i < 3; i++) {
|
407
|
+
cross[i][0]=(((double)facet->vertex[i].y * (double)facet->vertex[(i + 1) % 3].z) -
|
408
|
+
((double)facet->vertex[i].z * (double)facet->vertex[(i + 1) % 3].y));
|
409
|
+
cross[i][1]=(((double)facet->vertex[i].z * (double)facet->vertex[(i + 1) % 3].x) -
|
410
|
+
((double)facet->vertex[i].x * (double)facet->vertex[(i + 1) % 3].z));
|
411
|
+
cross[i][2]=(((double)facet->vertex[i].x * (double)facet->vertex[(i + 1) % 3].y) -
|
412
|
+
((double)facet->vertex[i].y * (double)facet->vertex[(i + 1) % 3].x));
|
413
|
+
}
|
414
|
+
|
415
|
+
sum[0] = cross[0][0] + cross[1][0] + cross[2][0];
|
416
|
+
sum[1] = cross[0][1] + cross[1][1] + cross[2][1];
|
417
|
+
sum[2] = cross[0][2] + cross[1][2] + cross[2][2];
|
418
|
+
|
419
|
+
/* This should already be done. But just in case, let's do it again */
|
420
|
+
stl_calculate_normal(n, facet);
|
421
|
+
stl_normalize_vector(n);
|
422
|
+
|
423
|
+
area = 0.5 * (n[0] * sum[0] + n[1] * sum[1] + n[2] * sum[2]);
|
424
|
+
return area;
|
425
|
+
}
|
426
|
+
|
427
|
+
void stl_repair(stl_file *stl,
|
428
|
+
int fixall_flag,
|
429
|
+
int exact_flag,
|
430
|
+
int tolerance_flag,
|
431
|
+
float tolerance,
|
432
|
+
int increment_flag,
|
433
|
+
float increment,
|
434
|
+
int nearby_flag,
|
435
|
+
int iterations,
|
436
|
+
int remove_unconnected_flag,
|
437
|
+
int fill_holes_flag,
|
438
|
+
int normal_directions_flag,
|
439
|
+
int normal_values_flag,
|
440
|
+
int reverse_all_flag,
|
441
|
+
int verbose_flag) {
|
442
|
+
|
443
|
+
int i;
|
444
|
+
int last_edges_fixed = 0;
|
445
|
+
|
446
|
+
if (stl->error) return;
|
447
|
+
|
448
|
+
if(exact_flag || fixall_flag || nearby_flag || remove_unconnected_flag
|
449
|
+
|| fill_holes_flag || normal_directions_flag) {
|
450
|
+
if (verbose_flag)
|
451
|
+
printf("Checking exact...\n");
|
452
|
+
exact_flag = 1;
|
453
|
+
stl_check_facets_exact(stl);
|
454
|
+
stl->stats.facets_w_1_bad_edge =
|
455
|
+
(stl->stats.connected_facets_2_edge -
|
456
|
+
stl->stats.connected_facets_3_edge);
|
457
|
+
stl->stats.facets_w_2_bad_edge =
|
458
|
+
(stl->stats.connected_facets_1_edge -
|
459
|
+
stl->stats.connected_facets_2_edge);
|
460
|
+
stl->stats.facets_w_3_bad_edge =
|
461
|
+
(stl->stats.number_of_facets -
|
462
|
+
stl->stats.connected_facets_1_edge);
|
463
|
+
}
|
464
|
+
|
465
|
+
if(nearby_flag || fixall_flag) {
|
466
|
+
if(!tolerance_flag) {
|
467
|
+
tolerance = stl->stats.shortest_edge;
|
468
|
+
}
|
469
|
+
if(!increment_flag) {
|
470
|
+
increment = stl->stats.bounding_diameter / 10000.0;
|
471
|
+
}
|
472
|
+
|
473
|
+
if(stl->stats.connected_facets_3_edge < stl->stats.number_of_facets) {
|
474
|
+
for(i = 0; i < iterations; i++) {
|
475
|
+
if(stl->stats.connected_facets_3_edge <
|
476
|
+
stl->stats.number_of_facets) {
|
477
|
+
if (verbose_flag)
|
478
|
+
printf("\
|
479
|
+
Checking nearby. Tolerance= %f Iteration=%d of %d...",
|
480
|
+
tolerance, i + 1, iterations);
|
481
|
+
stl_check_facets_nearby(stl, tolerance);
|
482
|
+
if (verbose_flag)
|
483
|
+
printf(" Fixed %d edges.\n",
|
484
|
+
stl->stats.edges_fixed - last_edges_fixed);
|
485
|
+
last_edges_fixed = stl->stats.edges_fixed;
|
486
|
+
tolerance += increment;
|
487
|
+
} else {
|
488
|
+
if (verbose_flag)
|
489
|
+
printf("\
|
490
|
+
All facets connected. No further nearby check necessary.\n");
|
491
|
+
break;
|
492
|
+
}
|
493
|
+
}
|
494
|
+
} else {
|
495
|
+
if (verbose_flag)
|
496
|
+
printf("All facets connected. No nearby check necessary.\n");
|
497
|
+
}
|
498
|
+
}
|
499
|
+
|
500
|
+
if(remove_unconnected_flag || fixall_flag || fill_holes_flag) {
|
501
|
+
if(stl->stats.connected_facets_3_edge < stl->stats.number_of_facets) {
|
502
|
+
if (verbose_flag)
|
503
|
+
printf("Removing unconnected facets...\n");
|
504
|
+
stl_remove_unconnected_facets(stl);
|
505
|
+
} else
|
506
|
+
if (verbose_flag)
|
507
|
+
printf("No unconnected need to be removed.\n");
|
508
|
+
}
|
509
|
+
|
510
|
+
if(fill_holes_flag || fixall_flag) {
|
511
|
+
if(stl->stats.connected_facets_3_edge < stl->stats.number_of_facets) {
|
512
|
+
if (verbose_flag)
|
513
|
+
printf("Filling holes...\n");
|
514
|
+
stl_fill_holes(stl);
|
515
|
+
} else
|
516
|
+
if (verbose_flag)
|
517
|
+
printf("No holes need to be filled.\n");
|
518
|
+
}
|
519
|
+
|
520
|
+
if(reverse_all_flag) {
|
521
|
+
if (verbose_flag)
|
522
|
+
printf("Reversing all facets...\n");
|
523
|
+
stl_reverse_all_facets(stl);
|
524
|
+
}
|
525
|
+
|
526
|
+
if(normal_directions_flag || fixall_flag) {
|
527
|
+
if (verbose_flag)
|
528
|
+
printf("Checking normal directions...\n");
|
529
|
+
stl_fix_normal_directions(stl);
|
530
|
+
}
|
531
|
+
|
532
|
+
if(normal_values_flag || fixall_flag) {
|
533
|
+
if (verbose_flag)
|
534
|
+
printf("Checking normal values...\n");
|
535
|
+
stl_fix_normal_values(stl);
|
536
|
+
}
|
537
|
+
|
538
|
+
/* Always calculate the volume. It shouldn't take too long */
|
539
|
+
if (verbose_flag)
|
540
|
+
printf("Calculating volume...\n");
|
541
|
+
stl_calculate_volume(stl);
|
542
|
+
|
543
|
+
if(fixall_flag) {
|
544
|
+
if(stl->stats.volume < 0.0) {
|
545
|
+
if (verbose_flag)
|
546
|
+
printf("Reversing all facets because volume is negative...\n");
|
547
|
+
stl_reverse_all_facets(stl);
|
548
|
+
stl->stats.volume = -stl->stats.volume;
|
549
|
+
}
|
550
|
+
}
|
551
|
+
|
552
|
+
if(exact_flag) {
|
553
|
+
if (verbose_flag)
|
554
|
+
printf("Verifying neighbors...\n");
|
555
|
+
stl_verify_neighbors(stl);
|
556
|
+
}
|
557
|
+
}
|