csg 0.1.3 → 0.1.4
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 +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
|
+
}
|