admesh 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +7 -0
  2. data/ext/admesh/admesh/AUTHORS +11 -0
  3. data/ext/admesh/admesh/COPYING +339 -0
  4. data/ext/admesh/admesh/ChangeLog +143 -0
  5. data/ext/admesh/admesh/ChangeLog.old +42 -0
  6. data/ext/admesh/admesh/INSTALL +14 -0
  7. data/ext/admesh/admesh/Makefile.am +62 -0
  8. data/ext/admesh/admesh/Makefile.in +1100 -0
  9. data/ext/admesh/admesh/README.md +115 -0
  10. data/ext/admesh/admesh/aclocal.m4 +1183 -0
  11. data/ext/admesh/admesh/admesh-doc.txt +475 -0
  12. data/ext/admesh/admesh/admesh.1 +173 -0
  13. data/ext/admesh/admesh/block.stl +86 -0
  14. data/ext/admesh/admesh/compile +347 -0
  15. data/ext/admesh/admesh/config.guess +1420 -0
  16. data/ext/admesh/admesh/config.h.in +65 -0
  17. data/ext/admesh/admesh/config.sub +1798 -0
  18. data/ext/admesh/admesh/configure +14671 -0
  19. data/ext/admesh/admesh/configure.ac +90 -0
  20. data/ext/admesh/admesh/depcomp +791 -0
  21. data/ext/admesh/admesh/install-sh +527 -0
  22. data/ext/admesh/admesh/libadmesh.pc.in +11 -0
  23. data/ext/admesh/admesh/ltmain.sh +9655 -0
  24. data/ext/admesh/admesh/m4/libtool.m4 +7992 -0
  25. data/ext/admesh/admesh/m4/ltoptions.m4 +384 -0
  26. data/ext/admesh/admesh/m4/ltsugar.m4 +123 -0
  27. data/ext/admesh/admesh/m4/ltversion.m4 +23 -0
  28. data/ext/admesh/admesh/m4/lt~obsolete.m4 +98 -0
  29. data/ext/admesh/admesh/missing +215 -0
  30. data/ext/admesh/admesh/src/admesh.c +425 -0
  31. data/ext/admesh/admesh/src/connect.c +971 -0
  32. data/ext/admesh/admesh/src/normals.c +333 -0
  33. data/ext/admesh/admesh/src/shared.c +262 -0
  34. data/ext/admesh/admesh/src/stl.h +201 -0
  35. data/ext/admesh/admesh/src/stl_io.c +479 -0
  36. data/ext/admesh/admesh/src/stlinit.c +377 -0
  37. data/ext/admesh/admesh/src/util.c +557 -0
  38. data/ext/admesh/extconf.rb +14 -0
  39. data/lib/admesh.rb +40 -0
  40. 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
+ }