csg 0.1.3 → 0.1.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Makefile +17 -2
- data/lib/csg.rb +9 -7
- data/src/bsp.c +41 -54
- data/src/cmd_audit.c +72 -0
- data/src/cmd_audit.h +9 -0
- data/src/commands.c +47 -2
- data/src/export.c +44 -23
- data/src/export.h +1 -0
- data/src/poly.c +202 -29
- data/src/poly.h +24 -1
- data/src/stl.c +6 -11
- data/src/stl_mesh.c +18 -12
- data/src/stl_mesh.h +7 -0
- data/src/util.c +14 -19
- data/src/util.h +9 -0
- data/src/vector.c +18 -3
- data/src/vector.h +3 -0
- metadata +20 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 75fa78d0a7457950ab6f58724d12d6889a1ad040
|
4
|
+
data.tar.gz: e42df82e618300fd3ecbb378b5671e30c241adc0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f38fca9b843039bd79aee405e6b25fb9284f925cb3799ab9b11438800c76960c47a688bf5ed4e6946a52ae8f915712dbae7152103c1df9c582153dd2d7bd42ff
|
7
|
+
data.tar.gz: 8aa32fdda09f7abba5cbac125581ac258cee68761a97eddd659749a6408268846dc377e85a319c2716c71f7ba6e05c97c810e5384dcd0f548d4c27f430560a58
|
data/Makefile
CHANGED
@@ -10,6 +10,17 @@ CPPFLAGS = $(OPTCPPFLAGS)
|
|
10
10
|
LIBS = -lm $(OPTLIBS)
|
11
11
|
CFLAGS = -D_POSIX_C_SOURCE=200112L -g -std=c99 $(INCLUDE) -Wall -Werror $(OPTFLAGS)
|
12
12
|
|
13
|
+
# If DEBUG is set, we build a new set of objects and a new target
|
14
|
+
ifneq ($(origin DEBUG), undefined)
|
15
|
+
OBJS = $(patsubst %.c,%.dbg.o,$(SOURCES))
|
16
|
+
TARGET := $(TARGET).dbg
|
17
|
+
endif
|
18
|
+
|
19
|
+
# If RELEASE is set, we turn on NDEBUG and NO_LINENOS
|
20
|
+
ifneq ($(origin RELEASE), undefined)
|
21
|
+
CFLAGS += -DNDEBUG -DNO_LINENOS -UDEBUG
|
22
|
+
endif
|
23
|
+
|
13
24
|
ifeq ($(shell uname),Darwin)
|
14
25
|
LIB_TARGET = libcsg.dylib
|
15
26
|
else
|
@@ -20,11 +31,11 @@ endif
|
|
20
31
|
all: $(TARGET) $(LIB_TARGET)
|
21
32
|
|
22
33
|
clean:
|
23
|
-
|
34
|
+
$(MAKE) -C tests clean
|
24
35
|
rm -rf $(OBJS) $(TARGET) $(TARGET).o $(TARGET).new $(LIB_TARGET)
|
25
36
|
|
26
37
|
test:
|
27
|
-
|
38
|
+
@$(MAKE) -C tests clean test
|
28
39
|
|
29
40
|
.PHONY: all clean test libcsg loc
|
30
41
|
|
@@ -37,6 +48,10 @@ $(LIB_TARGET): $(OBJS)
|
|
37
48
|
|
38
49
|
libcsg: $(LIB_TARGET)
|
39
50
|
|
51
|
+
|
52
|
+
%.dbg.o: %.c
|
53
|
+
$(CC) -fPIC $(CFLAGS) -DDEBUG -o $@ -c $^
|
54
|
+
|
40
55
|
%.o: %.c
|
41
56
|
$(CC) -fPIC $(CFLAGS) -o $@ -c $^
|
42
57
|
|
data/lib/csg.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
require 'ffi'
|
2
2
|
|
3
3
|
module CSG
|
4
|
+
class Error < StandardError; end
|
5
|
+
|
4
6
|
module Native
|
5
7
|
extend FFI::Library
|
6
8
|
|
@@ -70,7 +72,7 @@ module CSG
|
|
70
72
|
if not mesh_ptr.null?
|
71
73
|
@mesh = CSG::Native::Mesh.new mesh_ptr
|
72
74
|
else
|
73
|
-
raise
|
75
|
+
raise CSG::Error.new("Failed to produce Mesh from #{path}")
|
74
76
|
end
|
75
77
|
end
|
76
78
|
|
@@ -83,25 +85,25 @@ module CSG
|
|
83
85
|
define_method name do |solid|
|
84
86
|
# I'm so paranoid because ruby will gladly FFI through a
|
85
87
|
# *NULL and explode if you ask, and that's much worse.
|
86
|
-
raise
|
87
|
-
raise
|
88
|
+
raise CSG::Error.new("The calling mesh is a NULL pointer") if mesh.null?
|
89
|
+
raise CSG::Error.new("The parameter mesh is a NULL pointer") if solid.mesh.null?
|
88
90
|
|
89
|
-
raise
|
91
|
+
raise CSG::Error.new("My BSP tree is NULL.") if (my_bsp_ptr = mesh[:to_bsp].call mesh).null?
|
90
92
|
# Assign ASAP in case the exception triggers an unwind, and I want the GC to know about this
|
91
93
|
my_bsp = CSG::Native::BSPNode.new(my_bsp_ptr)
|
92
94
|
|
93
|
-
raise
|
95
|
+
raise CSG::Error.new("My BSP tree is NULL.") if (their_bsp_ptr = solid.mesh[:to_bsp].call solid.mesh).null?
|
94
96
|
their_bsp = CSG::Native::BSPNode.new(their_bsp_ptr)
|
95
97
|
|
96
98
|
result_ptr = CSG::Native.send "bsp_#{name}", my_bsp, their_bsp
|
97
|
-
raise
|
99
|
+
raise CSG::Error.new("Result of #{name} is NULL") if result_ptr.null?
|
98
100
|
|
99
101
|
# We will not wrap the result in a CSG::Native::BSPNode because
|
100
102
|
# to avoid garbage collection, and we'll manage this pointer
|
101
103
|
# inside of the CSG::Native::Mesh object we get with
|
102
104
|
# bsp_to_mesh(.., 0) - which will not clone the input parameter
|
103
105
|
result_mesh_ptr = CSG::Native.bsp_to_mesh result_ptr, 0
|
104
|
-
raise
|
106
|
+
raise CSG::Error.new("Failed to wrap BSPNode(#{result_mesh_ptr} pointer as a Mesh, got NULL") if result_mesh_ptr.null?
|
105
107
|
CSG::Solid.new :mesh => CSG::Native::Mesh.new(result_mesh_ptr)
|
106
108
|
end
|
107
109
|
end
|
data/src/bsp.c
CHANGED
@@ -2,33 +2,29 @@
|
|
2
2
|
|
3
3
|
#include "bsp.h"
|
4
4
|
#include "dbg.h"
|
5
|
+
#include "util.h"
|
5
6
|
#include "export.h"
|
6
7
|
#include "bsp_mesh.h"
|
7
8
|
|
8
9
|
bsp_node_t *alloc_bsp_node(void) {
|
9
10
|
bsp_node_t *node = NULL;
|
10
|
-
|
11
|
+
assert_mem(node = calloc(1, sizeof(bsp_node_t)));
|
11
12
|
node->polygons = kl_init(poly);
|
12
13
|
return node;
|
13
|
-
error:
|
14
|
-
return NULL;
|
15
14
|
}
|
16
15
|
|
17
16
|
bsp_node_t *clone_bsp_tree(bsp_node_t *tree) {
|
18
17
|
bsp_node_t *copy = alloc_bsp_node();
|
19
|
-
check_mem(copy);
|
20
18
|
|
21
19
|
kliter_t(poly) *iter = kl_begin(tree->polygons);
|
22
20
|
for(; iter != kl_end(tree->polygons); iter = kl_next(iter)) {
|
23
21
|
poly_t *poly_copy = clone_poly(kl_val(iter));
|
24
|
-
check_mem(poly_copy);
|
25
22
|
*kl_pushp(poly, copy->polygons) = poly_copy;
|
26
23
|
}
|
27
24
|
|
28
25
|
free_poly(copy->divider, 1);
|
29
26
|
if(tree->divider) {
|
30
27
|
copy->divider = clone_poly(tree->divider);
|
31
|
-
check_mem(copy->divider);
|
32
28
|
}
|
33
29
|
else {
|
34
30
|
copy->divider = NULL;
|
@@ -36,17 +32,12 @@ bsp_node_t *clone_bsp_tree(bsp_node_t *tree) {
|
|
36
32
|
|
37
33
|
if(tree->front != NULL) {
|
38
34
|
copy->front = clone_bsp_tree(tree->front);
|
39
|
-
check_mem(copy->front);
|
40
35
|
}
|
41
36
|
if(tree->back != NULL) {
|
42
37
|
copy->back = clone_bsp_tree(tree->back);
|
43
|
-
check_mem(copy->back);
|
44
38
|
}
|
45
39
|
|
46
40
|
return copy;
|
47
|
-
error:
|
48
|
-
if(copy != NULL) free_bsp_tree(copy);
|
49
|
-
return NULL;
|
50
41
|
}
|
51
42
|
|
52
43
|
void free_bsp_node(bsp_node_t *node) {
|
@@ -98,11 +89,21 @@ int bsp_subdivide(poly_t *divider, poly_t *poly,
|
|
98
89
|
poly_t *b = NULL;
|
99
90
|
check(poly_split(divider, poly, &f, &b) == 0,
|
100
91
|
"Failed to split polygon(%p) with divider(%p)", poly, divider);
|
101
|
-
front[*n_front] = f;
|
102
|
-
*n_front += 1;
|
103
92
|
|
104
|
-
|
105
|
-
|
93
|
+
// TODO: This is where shit can get weird.
|
94
|
+
// When we create polygons we have the option of rejecting them
|
95
|
+
// by freeing and setting them to NULL, preventing them from
|
96
|
+
// being added to the result lists
|
97
|
+
|
98
|
+
// Append to the front and back lists and counts
|
99
|
+
if(f != NULL) {
|
100
|
+
front[*n_front] = f;
|
101
|
+
*n_front += 1;
|
102
|
+
}
|
103
|
+
if(b != NULL) {
|
104
|
+
back[*n_back] = b;
|
105
|
+
*n_back += 1;
|
106
|
+
}
|
106
107
|
|
107
108
|
// Do we care about telling the caller about polygons
|
108
109
|
// who's pointers are not in any of the "real" lists?
|
@@ -113,10 +114,14 @@ int bsp_subdivide(poly_t *divider, poly_t *poly,
|
|
113
114
|
|
114
115
|
// How about polygons that we just made?
|
115
116
|
if(created != NULL) {
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
117
|
+
if(f != NULL) {
|
118
|
+
created[*n_created] = f;
|
119
|
+
*n_created += 1;
|
120
|
+
}
|
121
|
+
if(b != NULL) {
|
122
|
+
created[*n_created] = b;
|
123
|
+
*n_created += 1;
|
124
|
+
}
|
120
125
|
}
|
121
126
|
break;
|
122
127
|
}
|
@@ -129,7 +134,7 @@ error:
|
|
129
134
|
|
130
135
|
bsp_node_t *bsp_build(bsp_node_t *node, klist_t(poly) *polygons, int copy) {
|
131
136
|
poly_t **polys = NULL;
|
132
|
-
|
137
|
+
assert_mem(polys = malloc(sizeof(poly_t*) * polygons->size));
|
133
138
|
|
134
139
|
kliter_t(poly) *iter = NULL;
|
135
140
|
int i = 0;
|
@@ -178,7 +183,6 @@ bsp_node_t *bsp_build_array(bsp_node_t *node, poly_t **polygons, size_t n_polys,
|
|
178
183
|
// Allocate a node if we weren't given one. It's the nice
|
179
184
|
// thing to do for people.
|
180
185
|
node = alloc_bsp_node();
|
181
|
-
check_mem(node);
|
182
186
|
}
|
183
187
|
|
184
188
|
if(n_polys == 0) return node;
|
@@ -193,14 +197,13 @@ bsp_node_t *bsp_build_array(bsp_node_t *node, poly_t **polygons, size_t n_polys,
|
|
193
197
|
poly_i += 1;
|
194
198
|
|
195
199
|
node->divider = clone_poly(polygons[0]);
|
196
|
-
check_mem(node->divider);
|
197
200
|
}
|
198
201
|
|
199
202
|
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
203
|
+
assert_mem(coplanar = malloc(sizeof(poly_t*) * n_polys));
|
204
|
+
assert_mem(front_p = malloc(sizeof(poly_t*) * n_polys));
|
205
|
+
assert_mem(back_p = malloc(sizeof(poly_t*) * n_polys));
|
206
|
+
assert_mem(unused = malloc(sizeof(poly_t*) * n_polys));
|
204
207
|
for(; poly_i < n_polys; poly_i++) {
|
205
208
|
poly = polygons[poly_i];
|
206
209
|
rc = bsp_subdivide(node->divider, poly,
|
@@ -236,13 +239,11 @@ bsp_node_t *bsp_build_array(bsp_node_t *node, poly_t **polygons, size_t n_polys,
|
|
236
239
|
|
237
240
|
if((n_front > 0)) {
|
238
241
|
if(node->front == NULL) node->front = alloc_bsp_node();
|
239
|
-
check_mem(node->front);
|
240
242
|
check(bsp_build_array(node->front, front_p, n_front, free_unused) != NULL,
|
241
243
|
"Failed to build front tree of bsp_node_array(%p)", node);
|
242
244
|
}
|
243
245
|
if((n_back > 0)) {
|
244
246
|
if(node->back == NULL) node->back = alloc_bsp_node();
|
245
|
-
check_mem(node->back);
|
246
247
|
check(bsp_build_array(node->back, back_p, n_back, free_unused) != NULL,
|
247
248
|
"Failed to build back tree of bsp_node(%p)", node);
|
248
249
|
}
|
@@ -267,7 +268,6 @@ int bsp_copy_node_polygons(bsp_node_t *node, int make_triangles, klist_t(poly) *
|
|
267
268
|
int vertex_count = poly_vertex_count(poly);
|
268
269
|
if(!make_triangles || vertex_count == 3) {
|
269
270
|
poly_t *copy = clone_poly(poly);
|
270
|
-
check_mem(copy);
|
271
271
|
*kl_pushp(poly, dst) = copy;
|
272
272
|
}
|
273
273
|
else if(vertex_count > 3){
|
@@ -278,7 +278,6 @@ int bsp_copy_node_polygons(bsp_node_t *node, int make_triangles, klist_t(poly) *
|
|
278
278
|
v_cur = &poly->vertices[i];
|
279
279
|
v_prev = &poly->vertices[i - 1];
|
280
280
|
poly_t *tri = poly_make_triangle(poly->vertices[0], *v_prev, *v_cur);
|
281
|
-
check_mem(tri);
|
282
281
|
*kl_pushp(poly, dst) = tri;
|
283
282
|
}
|
284
283
|
}
|
@@ -369,7 +368,7 @@ klist_t(poly) *bsp_clip_polygon_array(bsp_node_t *node, poly_t **polygons, size_
|
|
369
368
|
|
370
369
|
if(node->divider != NULL) {
|
371
370
|
if((n_polys * 4) > STATIC_POLY_BUFFER_SIZE) {
|
372
|
-
|
371
|
+
assert_mem(poly_buffer = malloc((sizeof(poly_t*) * n_polys) * 4));
|
373
372
|
}
|
374
373
|
front_array = poly_buffer;
|
375
374
|
back_array = poly_buffer + n_polys;
|
@@ -394,7 +393,6 @@ klist_t(poly) *bsp_clip_polygon_array(bsp_node_t *node, poly_t **polygons, size_
|
|
394
393
|
else {
|
395
394
|
for(i = 0; i < n_front; i++) {
|
396
395
|
copy = clone_poly(front_array[i]);
|
397
|
-
check_mem(copy);
|
398
396
|
*kl_pushp(poly, result) = copy;
|
399
397
|
}
|
400
398
|
}
|
@@ -418,8 +416,7 @@ klist_t(poly) *bsp_clip_polygon_array(bsp_node_t *node, poly_t **polygons, size_
|
|
418
416
|
else {
|
419
417
|
// If we don't have a divider we just copy out the polygons
|
420
418
|
for(i = 0; i < n_polys; i++) {
|
421
|
-
|
422
|
-
*kl_pushp(poly, result) = p;
|
419
|
+
*kl_pushp(poly, result) = clone_poly(polygons[i]);
|
423
420
|
}
|
424
421
|
}
|
425
422
|
|
@@ -433,7 +430,6 @@ error:
|
|
433
430
|
klist_t(poly) *bsp_clip_polygons(bsp_node_t *node, klist_t(poly) *polygons, klist_t(poly) *dst) {
|
434
431
|
klist_t(poly) *result = dst != NULL ? dst : kl_init(poly);
|
435
432
|
kliter_t(poly) *iter = NULL;
|
436
|
-
poly_t *p = NULL;
|
437
433
|
int rc = -1;
|
438
434
|
|
439
435
|
poly_t *static_poly_buffer[STATIC_POLY_BUFFER_SIZE];
|
@@ -450,7 +446,7 @@ klist_t(poly) *bsp_clip_polygons(bsp_node_t *node, klist_t(poly) *polygons, klis
|
|
450
446
|
|
451
447
|
if(node->divider != NULL) {
|
452
448
|
if((polygons->size * 4) > STATIC_POLY_BUFFER_SIZE) {
|
453
|
-
|
449
|
+
assert_mem(poly_buffer = malloc(sizeof(poly_t*) * polygons->size * 4));
|
454
450
|
}
|
455
451
|
front_array = poly_buffer;
|
456
452
|
back_array = poly_buffer + polygons->size;
|
@@ -465,7 +461,6 @@ klist_t(poly) *bsp_clip_polygons(bsp_node_t *node, klist_t(poly) *polygons, klis
|
|
465
461
|
}
|
466
462
|
|
467
463
|
int i;
|
468
|
-
poly_t *copy = NULL;
|
469
464
|
// Recur to the front tree, or copy my current front nodes to result.
|
470
465
|
if(node->front) {
|
471
466
|
result = bsp_clip_polygon_array(node->front, front_array, n_front, result);
|
@@ -473,9 +468,7 @@ klist_t(poly) *bsp_clip_polygons(bsp_node_t *node, klist_t(poly) *polygons, klis
|
|
473
468
|
}
|
474
469
|
else {
|
475
470
|
for(i = 0; i < n_front; i++) {
|
476
|
-
|
477
|
-
check_mem(copy);
|
478
|
-
*kl_pushp(poly, result) = copy;
|
471
|
+
*kl_pushp(poly, result) = clone_poly(front_array[i]);
|
479
472
|
}
|
480
473
|
}
|
481
474
|
|
@@ -498,8 +491,7 @@ klist_t(poly) *bsp_clip_polygons(bsp_node_t *node, klist_t(poly) *polygons, klis
|
|
498
491
|
else {
|
499
492
|
// If we don't have a divider we just copy out the polygons
|
500
493
|
for(iter = kl_begin(polygons); iter != kl_end(polygons); iter = kl_next(iter)) {
|
501
|
-
|
502
|
-
*kl_pushp(poly, result) = p;
|
494
|
+
*kl_pushp(poly, result) = clone_poly(kl_val(iter));
|
503
495
|
}
|
504
496
|
}
|
505
497
|
|
@@ -527,8 +519,8 @@ bsp_node_t *bsp_subtract(bsp_node_t *tree_a, bsp_node_t *tree_b) {
|
|
527
519
|
bsp_node_t *result = NULL;
|
528
520
|
klist_t(poly) *b_polys = NULL;
|
529
521
|
|
530
|
-
|
531
|
-
|
522
|
+
a = clone_bsp_tree(tree_a);
|
523
|
+
b = clone_bsp_tree(tree_b);
|
532
524
|
|
533
525
|
check(bsp_invert(a) != NULL, "Failed to invert A");
|
534
526
|
check(bsp_clip(a, b) != NULL, "Failed to clip(A, B)");
|
@@ -544,7 +536,6 @@ bsp_node_t *bsp_subtract(bsp_node_t *tree_a, bsp_node_t *tree_b) {
|
|
544
536
|
// TODO: Build a more balanced trees from the polys of
|
545
537
|
// a instead of cloning a tree with potential gaps.
|
546
538
|
result = clone_bsp_tree(a);
|
547
|
-
check_mem(result);
|
548
539
|
|
549
540
|
if(b_polys != NULL) kl_destroy(poly, b_polys);
|
550
541
|
if(a != NULL) free_bsp_tree(a);
|
@@ -564,8 +555,8 @@ bsp_node_t *bsp_union(bsp_node_t *tree_a, bsp_node_t *tree_b) {
|
|
564
555
|
bsp_node_t *result = NULL;
|
565
556
|
klist_t(poly) *b_polys = NULL;
|
566
557
|
|
567
|
-
|
568
|
-
|
558
|
+
a = clone_bsp_tree(tree_a);
|
559
|
+
b = clone_bsp_tree(tree_b);
|
569
560
|
|
570
561
|
check(bsp_clip(a, b) != NULL, "Failed to clip(A, B)");
|
571
562
|
check(bsp_clip(b, a) != NULL, "Failed clip(B, A)");
|
@@ -579,7 +570,6 @@ bsp_node_t *bsp_union(bsp_node_t *tree_a, bsp_node_t *tree_b) {
|
|
579
570
|
// TODO: Build a more balanced trees from the polys of
|
580
571
|
// a instead of cloning a tree with potential gaps.
|
581
572
|
result = clone_bsp_tree(a);
|
582
|
-
check_mem(result);
|
583
573
|
|
584
574
|
if(b_polys != NULL) kl_destroy(poly, b_polys);
|
585
575
|
if(a != NULL) free_bsp_tree(a);
|
@@ -599,8 +589,8 @@ bsp_node_t *bsp_intersect(bsp_node_t *tree_a, bsp_node_t *tree_b) {
|
|
599
589
|
bsp_node_t *result = NULL;
|
600
590
|
klist_t(poly) *b_polys = NULL;
|
601
591
|
|
602
|
-
|
603
|
-
|
592
|
+
a = clone_bsp_tree(tree_a);
|
593
|
+
b = clone_bsp_tree(tree_b);
|
604
594
|
|
605
595
|
check(bsp_invert(a) != NULL, "Failed to invert A");
|
606
596
|
check(bsp_clip(b, a) != NULL, "Failed clip(B, A)");
|
@@ -616,7 +606,6 @@ bsp_node_t *bsp_intersect(bsp_node_t *tree_a, bsp_node_t *tree_b) {
|
|
616
606
|
// TODO: Build a more balanced trees from the polys of
|
617
607
|
// a instead of cloning a tree with potential gaps.
|
618
608
|
result = clone_bsp_tree(a);
|
619
|
-
check_mem(result);
|
620
609
|
|
621
610
|
if(b_polys != NULL) kl_destroy(poly, b_polys);
|
622
611
|
if(a != NULL) free_bsp_tree(a);
|
@@ -642,14 +631,12 @@ int bsp_count_polygons(bsp_node_t *tree) {
|
|
642
631
|
int bsp_mesh_init(void *self, void *data) {
|
643
632
|
bsp_mesh_t *mesh = (bsp_mesh_t*)self;
|
644
633
|
if(data == NULL) {
|
645
|
-
|
634
|
+
mesh->bsp = alloc_bsp_node();
|
646
635
|
}
|
647
636
|
else {
|
648
637
|
mesh->bsp = (bsp_node_t*)data;
|
649
638
|
}
|
650
639
|
return 0;
|
651
|
-
error:
|
652
|
-
return -1;
|
653
640
|
}
|
654
641
|
|
655
642
|
void bsp_mesh_destroy(void *self) {
|
data/src/cmd_audit.c
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
#include "cmd_audit.h"
|
2
|
+
|
3
|
+
#include "stl_mesh.h"
|
4
|
+
|
5
|
+
// The finalizer for `cmd_audit`. Cleans up the structures
|
6
|
+
// used, and then returns the value passed.
|
7
|
+
// Because I fuckign hate spelling this shit out twice, like I
|
8
|
+
// do literally everywhere else in this codebase.
|
9
|
+
#define __FINISH_CMD_AUDIT(ret) do { \
|
10
|
+
if(in != NULL) free_mesh(in); \
|
11
|
+
if(polys != NULL) kl_destroy(poly, polys); \
|
12
|
+
} while(false); \
|
13
|
+
return (ret)
|
14
|
+
|
15
|
+
// `audit` command entry point.
|
16
|
+
// Takes one mesh as the last arg then walks it looking for
|
17
|
+
// abnormalities.
|
18
|
+
int cmd_audit(int argc, char *argv[]) {
|
19
|
+
char *name = argv[argc - 1];
|
20
|
+
mesh_t *in = NULL;
|
21
|
+
klist_t(poly)* polys = NULL;
|
22
|
+
|
23
|
+
check(argc >= 1, "Too few args");
|
24
|
+
check(in = mesh_read_file(name), "Failed to read [%s]", name);
|
25
|
+
check(in->poly_count(in) > 0, "Mesh does not contain any polygons.");
|
26
|
+
|
27
|
+
// If we load an STL, we need to patch mesh->to_polygons(..) to
|
28
|
+
// a version that bypasses the `poly_push_vertex` checks, otherwise
|
29
|
+
// invalid polygons simply won't be created, and a shitload of warning
|
30
|
+
// spam will appear.
|
31
|
+
const char *stl_type = "STL";
|
32
|
+
if(strncmp(in->type, stl_type, strlen(stl_type)) == 0) {
|
33
|
+
log_info("Patching mesh to produce unsafe polygons.");
|
34
|
+
in->to_polygons = stl_mesh_to_polygons_unsafe;
|
35
|
+
}
|
36
|
+
|
37
|
+
|
38
|
+
log_info("Converting mesh to polygon list for walk.");
|
39
|
+
check(polys = in->to_polygons(in), "Failed to get polygons from mesh.");
|
40
|
+
|
41
|
+
// We should get the same number of polygons as we had in the original structure
|
42
|
+
// after conversion.
|
43
|
+
check(in->poly_count(in) == polys->size,
|
44
|
+
"Polygon counts differ after polygon list conversion. Mesh(%d) vs List(%zd)", in->poly_count(in), polys->size);
|
45
|
+
|
46
|
+
log_info("Loaded [%d] polys from '%s', beginning walk", in->poly_count(in), name);
|
47
|
+
kliter_t(poly) *iter = kl_begin(polys);
|
48
|
+
poly_t *poly = NULL;
|
49
|
+
size_t count = 0;
|
50
|
+
size_t bad_count = 0;
|
51
|
+
for(; iter != kl_end(polys); iter = kl_next(iter), count++) {
|
52
|
+
poly = kl_val(iter);
|
53
|
+
if(poly == NULL) {
|
54
|
+
log_warn("Failed to get polygon %zd from mesh, it is NULL", count);
|
55
|
+
bad_count++;
|
56
|
+
continue;
|
57
|
+
}
|
58
|
+
|
59
|
+
// If a squard edge length is zero, it's zero.
|
60
|
+
if(poly_min_edge_length2(poly) == 0.0) {
|
61
|
+
bad_count++;
|
62
|
+
log_warn("Poly %zd has an edge of length2 = %f", count, poly_min_edge_length2(poly));
|
63
|
+
poly_print(poly, stderr);
|
64
|
+
}
|
65
|
+
}
|
66
|
+
|
67
|
+
log_info("Checked %zd polygons. %zd had problems.", count, bad_count);
|
68
|
+
|
69
|
+
__FINISH_CMD_AUDIT(bad_count);
|
70
|
+
error:
|
71
|
+
__FINISH_CMD_AUDIT(-1);
|
72
|
+
}
|