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.
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
+ }