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
data/src/cmd_audit.h
ADDED
data/src/commands.c
CHANGED
@@ -1,11 +1,13 @@
|
|
1
1
|
#include <string.h>
|
2
2
|
#include "dbg.h"
|
3
3
|
|
4
|
+
#include "util.h"
|
4
5
|
#include "commands.h"
|
5
6
|
#include "mesh.h"
|
6
7
|
#include "bsp.h"
|
7
8
|
#include "bsp_mesh.h"
|
8
9
|
#include "export.h"
|
10
|
+
#include "cmd_audit.h"
|
9
11
|
|
10
12
|
typedef bsp_node_t* (*bsp_binary_op)(bsp_node_t *, bsp_node_t *);
|
11
13
|
|
@@ -26,14 +28,14 @@ bsp_node_t* bsp_binary_operation(char *path1, char *path2, bsp_binary_op op) {
|
|
26
28
|
check(file1 != NULL, "Failed to read mesh from '%s'", path1);
|
27
29
|
log_info("Loaded file: %s %d facets", path1, file1->poly_count(file1));
|
28
30
|
bsp1 = mesh_to_bsp(file1);
|
29
|
-
|
31
|
+
assert_mem(bsp1);
|
30
32
|
|
31
33
|
// Read 2
|
32
34
|
file2 = mesh_read_file(path2);
|
33
35
|
check(file2 != NULL, "Failed to read mesh from '%s'", path2);
|
34
36
|
log_info("Loaded file: %s %d facets", path2, file2->poly_count(file2));
|
35
37
|
bsp2 = mesh_to_bsp(file2);
|
36
|
-
|
38
|
+
assert_mem(bsp2);
|
37
39
|
|
38
40
|
// Operate
|
39
41
|
result = op(bsp1, bsp2);
|
@@ -89,11 +91,54 @@ MAKE_CSG_COMMAND(intersect);
|
|
89
91
|
MAKE_CSG_COMMAND(union);
|
90
92
|
MAKE_CSG_COMMAND(subtract);
|
91
93
|
|
94
|
+
// Commands that exist only when built with `DEBUG` defined
|
95
|
+
// these generally don't do anything useful
|
96
|
+
#ifdef DEBUG
|
97
|
+
int cmd_DEBUG_bsp(int argc, char **argv) {
|
98
|
+
const char *suffix = ".bsp.stl";
|
99
|
+
char *name = argv[0];
|
100
|
+
char *out_name = NULL;
|
101
|
+
mesh_t *in = NULL;
|
102
|
+
mesh_t *out = NULL;
|
103
|
+
bsp_node_t *bsp = NULL;
|
104
|
+
check(argc >= 1, "Too few args");
|
105
|
+
assert_mem(out_name = calloc(strlen(name) + strlen(suffix) + 1, 1));
|
106
|
+
check(sprintf(out_name, "%s%s", name, suffix) == (strlen(name) + strlen(suffix)), "Failed to build out name.");
|
107
|
+
|
108
|
+
check(in = mesh_read_file(name), "Failed to READ");
|
109
|
+
check(bsp = in->to_bsp(in), "Failed to BSP");
|
110
|
+
check(out = bsp_to_mesh(bsp, 0), "Failed to BSP->mesh wrap");
|
111
|
+
bsp = NULL; // Make it obvs that out now holds the ref
|
112
|
+
|
113
|
+
log_info("Read: [%s]", argv[0]);
|
114
|
+
log_info("Poly Count: [%d]", in->poly_count(in));
|
115
|
+
log_info("BSP: [%p]", out);
|
116
|
+
log_info("BSP Poly Count: [%d]", out->poly_count(out));
|
117
|
+
log_info("Write: [%s](%d)", out_name, out->write(out, out_name, "STL"));
|
118
|
+
|
119
|
+
if(out != NULL) out->destroy(out);
|
120
|
+
if(in != NULL) in->destroy(in);
|
121
|
+
if(out_name != NULL) free(out_name);
|
122
|
+
return 0;
|
123
|
+
error:
|
124
|
+
if(out != NULL) out->destroy(out);
|
125
|
+
if(in != NULL) in->destroy(in);
|
126
|
+
if(out_name != NULL) free(out_name);
|
127
|
+
return -1;
|
128
|
+
}
|
129
|
+
#endif
|
130
|
+
|
92
131
|
// Available commands
|
93
132
|
const cmd_t commands[] = {
|
94
133
|
{"intersect", "Intersect two geometries", cmd_intersect},
|
95
134
|
{"subtract", "Subtract two geometries", cmd_subtract},
|
96
135
|
{"union", "Union two geometries", cmd_union},
|
136
|
+
{"audit", "Audit a mesh on disk for errors", cmd_audit},
|
137
|
+
|
138
|
+
#ifdef DEBUG
|
139
|
+
{"bsp", "Identity through BSP", cmd_DEBUG_bsp},
|
140
|
+
#endif
|
141
|
+
|
97
142
|
{NULL, NULL, NULL}
|
98
143
|
};
|
99
144
|
|
data/src/export.c
CHANGED
@@ -1,9 +1,9 @@
|
|
1
|
+
#include "util.h"
|
1
2
|
#include "export.h"
|
2
3
|
#include "bsp_mesh.h"
|
3
4
|
|
4
5
|
stl_object *stl_from_polys(klist_t(poly) *polygons) {
|
5
6
|
stl_object *stl = stl_alloc(NULL, polygons->size);
|
6
|
-
check_mem(stl);
|
7
7
|
|
8
8
|
kliter_t(poly) *iter = kl_begin(polygons);
|
9
9
|
stl_facet *facet = stl->facets;
|
@@ -49,13 +49,11 @@ bsp_node_t *stl_to_bsp(stl_object *stl) {
|
|
49
49
|
poly = poly_make_triangle(stl->facets[i].vertices[0],
|
50
50
|
stl->facets[i].vertices[1],
|
51
51
|
stl->facets[i].vertices[2]);
|
52
|
-
check_mem(polys);
|
53
52
|
*kl_pushp(poly, polys) = poly;
|
54
53
|
}
|
55
54
|
check(polys->size == stl->facet_count, "Wrong number of faces generated.");
|
56
55
|
|
57
56
|
tree = bsp_build(NULL, polys, 1);
|
58
|
-
check_mem(tree);
|
59
57
|
|
60
58
|
kl_destroy(poly, polys);
|
61
59
|
return tree;
|
@@ -77,33 +75,56 @@ mesh_t* bsp_to_mesh(bsp_node_t* bsp, int copy) {
|
|
77
75
|
return NEW(bsp_mesh_t, "BSP", input);
|
78
76
|
}
|
79
77
|
|
80
|
-
klist_t(poly)*
|
78
|
+
klist_t(poly) *poly_to_tris(klist_t(poly)* dst, poly_t *poly) {
|
81
79
|
klist_t(poly) *result = dst;
|
82
80
|
if(result == NULL) result = kl_init(poly);
|
83
81
|
|
84
|
-
|
85
|
-
for(iter = kl_begin(src); iter != kl_end(src); iter = kl_next(iter)) {
|
86
|
-
poly_t *poly = kl_val(iter);
|
87
|
-
int vertex_count = poly_vertex_count(poly);
|
82
|
+
int vertex_count = poly_vertex_count(poly);
|
88
83
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
84
|
+
// Copy triangles, split higher-vertex polygons into triangle fans.
|
85
|
+
if(vertex_count == 3) {
|
86
|
+
*kl_pushp(poly, result) = clone_poly(poly);
|
87
|
+
}
|
88
|
+
else if(vertex_count > 3) {
|
89
|
+
float3 *v_cur, *v_prev;
|
90
|
+
for(int i = 2; i < vertex_count; i++) {
|
91
|
+
v_cur = &poly->vertices[i];
|
92
|
+
v_prev = &poly->vertices[i - 1];
|
93
|
+
poly_t *tri = poly_make_triangle(poly->vertices[0], *v_prev, *v_cur);
|
94
|
+
|
95
|
+
// If we don't create a valid polygon, don't include it in the result.
|
96
|
+
if(tri != NULL) {
|
102
97
|
*kl_pushp(poly, result) = tri;
|
103
98
|
}
|
104
|
-
|
105
|
-
|
99
|
+
else {
|
100
|
+
#ifdef DEBUG
|
101
|
+
log_warn("Failed to build triangle:\n(%f, %f, %f)\n(%f, %f, %f)\n(%f, %f, %f)",
|
102
|
+
FLOAT3_FORMAT(poly->vertices[0]), FLOAT3_FORMAT(*v_prev), FLOAT3_FORMAT(*v_cur));
|
103
|
+
log_warn("Original:");
|
104
|
+
poly_print(poly, dbg_get_log());
|
105
|
+
#endif
|
106
|
+
}
|
106
107
|
}
|
108
|
+
} else {
|
109
|
+
sentinel("polygon(%p) has less than three(%d) vertices.", poly, poly_vertex_count(poly));
|
110
|
+
}
|
111
|
+
|
112
|
+
return result;
|
113
|
+
error:
|
114
|
+
if(result != dst) if(result != NULL) kl_destroy(poly, result);
|
115
|
+
return NULL;
|
116
|
+
}
|
117
|
+
|
118
|
+
klist_t(poly)* polys_to_tris(klist_t(poly) *dst, klist_t(poly) *src) {
|
119
|
+
klist_t(poly) *result = dst;
|
120
|
+
if(result == NULL) result = kl_init(poly);
|
121
|
+
|
122
|
+
kliter_t(poly) *iter = NULL;
|
123
|
+
for(iter = kl_begin(src); iter != kl_end(src); iter = kl_next(iter)) {
|
124
|
+
poly_t *poly = kl_val(iter);
|
125
|
+
check(poly_to_tris(result, poly) != NULL,
|
126
|
+
"Failed to tesselate %p(%d) into triangles.",
|
127
|
+
poly, poly_vertex_count(poly));
|
107
128
|
}
|
108
129
|
|
109
130
|
return result;
|
data/src/export.h
CHANGED
@@ -15,6 +15,7 @@ stl_object *bsp_to_stl(bsp_node_t *tree);
|
|
15
15
|
bsp_node_t *stl_to_bsp(stl_object *stl);
|
16
16
|
bsp_node_t *mesh_to_bsp(mesh_t *mesh);
|
17
17
|
mesh_t* bsp_to_mesh(bsp_node_t *tree, int copy);
|
18
|
+
klist_t(poly) *poly_to_tris(klist_t(poly)* dst, poly_t *src);
|
18
19
|
klist_t(poly)* polys_to_tris(klist_t(poly)* dst, klist_t(poly)* src);
|
19
20
|
|
20
21
|
#endif
|
data/src/poly.c
CHANGED
@@ -1,14 +1,16 @@
|
|
1
|
+
#include <stdio.h>
|
1
2
|
#include <assert.h>
|
3
|
+
#include <stdbool.h>
|
2
4
|
|
3
5
|
#include "poly.h"
|
6
|
+
#include "util.h"
|
7
|
+
#include "export.h"
|
4
8
|
|
5
9
|
poly_t *alloc_poly(void) {
|
6
10
|
poly_t *poly = malloc(sizeof(poly_t));
|
7
|
-
|
11
|
+
assert_mem(poly);
|
8
12
|
poly_init(poly);
|
9
13
|
return poly;
|
10
|
-
error:
|
11
|
-
return NULL;
|
12
14
|
}
|
13
15
|
|
14
16
|
void free_poly(poly_t *p, int free_self) {
|
@@ -20,6 +22,24 @@ void free_poly(poly_t *p, int free_self) {
|
|
20
22
|
if(free_self) free(p);
|
21
23
|
}
|
22
24
|
|
25
|
+
void poly_print(poly_t *p, FILE *stream) {
|
26
|
+
fprintf(stream, "Poly(%p) Verts: %d Area: %f:\n", p, poly_vertex_count(p), poly_area(p));
|
27
|
+
for(int i = 0; i < poly_vertex_count(p); i++) {
|
28
|
+
fprintf(stream,"\tV[%d]: (%f, %f, %f)\n", i, FLOAT3_FORMAT(p->vertices[i]));
|
29
|
+
}
|
30
|
+
}
|
31
|
+
|
32
|
+
void poly_print_with_plane_info(poly_t *p, poly_t *plane, FILE *stream) {
|
33
|
+
fprintf(stream, "Poly(%p) w(%f) Verts: %d Area: %f:\n", p, p->w, poly_vertex_count(p), poly_area(p));
|
34
|
+
for(int i = 0; i < poly_vertex_count(p); i++) {
|
35
|
+
float3 diff = FLOAT3_INIT;
|
36
|
+
f3_sub(&diff, p->vertices[i], plane->vertices[0]);
|
37
|
+
float distance = f3_dot(plane->normal, diff);
|
38
|
+
fprintf(stream,"\tV[%d]: (%f, %f, %f) [%s] - %f from plane\n",
|
39
|
+
i, FLOAT3_FORMAT(p->vertices[i]), poly_classify_vertex_string(plane, p->vertices[i]), distance);
|
40
|
+
}
|
41
|
+
}
|
42
|
+
|
23
43
|
poly_t *poly_init(poly_t *poly) {
|
24
44
|
poly->vertex_count = 0;
|
25
45
|
poly->vertex_max = POLY_MAX_VERTS;
|
@@ -28,8 +48,7 @@ poly_t *poly_init(poly_t *poly) {
|
|
28
48
|
}
|
29
49
|
|
30
50
|
poly_t *clone_poly(poly_t *poly) {
|
31
|
-
poly_t *copy =
|
32
|
-
check_mem(copy = alloc_poly());
|
51
|
+
poly_t *copy = alloc_poly();
|
33
52
|
memcpy(copy, poly, sizeof(poly_t));
|
34
53
|
|
35
54
|
// Either point the clone at its own copied
|
@@ -41,14 +60,11 @@ poly_t *clone_poly(poly_t *poly) {
|
|
41
60
|
// We can lean on the `copy->*` memebers
|
42
61
|
// since they would have been memcpy'd over
|
43
62
|
copy->vertices = malloc(poly_vertex_max(copy) * sizeof(float3));
|
44
|
-
|
63
|
+
assert_mem(copy->vertices);
|
45
64
|
memcpy(copy->vertices, poly->vertices, poly_vertex_max(copy) * sizeof(float3));
|
46
65
|
}
|
47
66
|
|
48
67
|
return copy;
|
49
|
-
error:
|
50
|
-
if(copy != NULL) free_poly(copy, 1);
|
51
|
-
return NULL;
|
52
68
|
}
|
53
69
|
|
54
70
|
int poly_update(poly_t *poly) {
|
@@ -70,6 +86,65 @@ int poly_update(poly_t *poly) {
|
|
70
86
|
return 0;
|
71
87
|
}
|
72
88
|
|
89
|
+
// Return two times the area of a triangle.
|
90
|
+
// Avoids the division in half unless it's required to avoid
|
91
|
+
// failing `f > 0.0` when area is used as a predicate
|
92
|
+
float poly_triangle_2area(poly_t *triangle) {
|
93
|
+
if(poly_vertex_count(triangle) != 3) return NAN;
|
94
|
+
|
95
|
+
return triangle_2area(
|
96
|
+
triangle->vertices[0],
|
97
|
+
triangle->vertices[1],
|
98
|
+
triangle->vertices[2]
|
99
|
+
);
|
100
|
+
}
|
101
|
+
|
102
|
+
// The actual area of a triangle `triangle`
|
103
|
+
// Works through poly_triangle_2area
|
104
|
+
float poly_triangle_area(poly_t *triangle) {
|
105
|
+
return 0.5 * poly_triangle_2area(triangle);
|
106
|
+
}
|
107
|
+
|
108
|
+
float poly_area(poly_t *poly) {
|
109
|
+
return poly_2area(poly) / 2.0;
|
110
|
+
}
|
111
|
+
|
112
|
+
float poly_2area(poly_t *poly) {
|
113
|
+
float area2 = 0.0;
|
114
|
+
const int vertex_count = poly_vertex_count(poly);
|
115
|
+
|
116
|
+
// Sanity check that we have at least a polygon
|
117
|
+
if(vertex_count < 3) return NAN;
|
118
|
+
|
119
|
+
// Before we get into this tesselating bullshit, is this just a triangle?
|
120
|
+
if(vertex_count == 3) return poly_triangle_2area(poly);
|
121
|
+
|
122
|
+
// Break the poly into a triangle fan and sum the 2areas of the components
|
123
|
+
// Note that i = 2 on first iteration so that `i - 1` is defined and != 0
|
124
|
+
// This starts the loop on the first triangle in the poly.
|
125
|
+
// Since we're only caring about the magnitude of the cross inside
|
126
|
+
// triangle_2area, the vertex order doesn't matter.
|
127
|
+
for(int i = 2; i < vertex_count; i++) {
|
128
|
+
area2 += triangle_2area(
|
129
|
+
poly->vertices[0], // Root vertex
|
130
|
+
poly->vertices[i - 1], // Previous vertex
|
131
|
+
poly->vertices[i] // Current vertex
|
132
|
+
);
|
133
|
+
}
|
134
|
+
|
135
|
+
|
136
|
+
return area2;
|
137
|
+
}
|
138
|
+
|
139
|
+
bool poly_has_area(poly_t *poly) {
|
140
|
+
float area = poly_2area(poly);
|
141
|
+
check_debug(!isnan(area), "Polygon(%p) area is NaN", poly);
|
142
|
+
|
143
|
+
return area > 0.0;
|
144
|
+
error:
|
145
|
+
return false;
|
146
|
+
}
|
147
|
+
|
73
148
|
int poly_vertex_count(poly_t *poly) {
|
74
149
|
return poly->vertex_count;
|
75
150
|
}
|
@@ -91,7 +166,7 @@ int poly_vertex_expand(poly_t *poly) {
|
|
91
166
|
// Not using realloc because the original buffer may be struct-owned
|
92
167
|
int new_size = poly->vertex_max * 2;
|
93
168
|
float3 *new_verts = malloc(new_size * sizeof(float3));
|
94
|
-
|
169
|
+
assert_mem(new_verts);
|
95
170
|
|
96
171
|
memcpy(new_verts, poly->vertices, poly->vertex_max * sizeof(float3));
|
97
172
|
poly->vertex_max = new_size;
|
@@ -105,17 +180,28 @@ int poly_vertex_expand(poly_t *poly) {
|
|
105
180
|
poly->vertices = new_verts;
|
106
181
|
|
107
182
|
return 0;
|
108
|
-
error:
|
109
|
-
if(new_verts != NULL) free(new_verts);
|
110
|
-
return -1;
|
111
183
|
}
|
112
184
|
|
113
|
-
// add a vertex to the end of the polygon vertex list
|
114
|
-
|
185
|
+
// add a vertex to the end of the polygon vertex list, if
|
186
|
+
// `guard` is true, a check will be performed to reject
|
187
|
+
// verts that cause 0-length edges to appear.
|
188
|
+
bool poly_push_vertex_guarded(poly_t *poly, float3 v, bool guard) {
|
115
189
|
if(poly_vertex_available(poly) == 0) {
|
116
190
|
poly_vertex_expand(poly);
|
117
191
|
}
|
118
192
|
|
193
|
+
// We only need to perform zero-length-edge checks if we are
|
194
|
+
// actually going to create an edge through this push.
|
195
|
+
if(guard && (poly_vertex_count(poly) > 0)) {
|
196
|
+
int last_idx = poly_vertex_count(poly) - 1;
|
197
|
+
bool duplicate_first = !(f3_distance2(poly->vertices[0], v) > 0.0);
|
198
|
+
bool duplicate_last = !(f3_distance2(poly->vertices[last_idx], v) > 0.0);
|
199
|
+
|
200
|
+
// Fail out the addition if we're adding a duplucate first or last vertex
|
201
|
+
// as the new last vert. This would create an edge of length zero.
|
202
|
+
if(duplicate_first || duplicate_last) return false;
|
203
|
+
}
|
204
|
+
|
119
205
|
// Dat assignment copy
|
120
206
|
poly->vertices[poly->vertex_count][0] = v[0];
|
121
207
|
poly->vertices[poly->vertex_count][1] = v[1];
|
@@ -126,9 +212,20 @@ int poly_push_vertex(poly_t *poly, float3 v) {
|
|
126
212
|
check(poly_update(poly) == 0, "Failed to update polygon during poly_push_vertex(%p)", poly);
|
127
213
|
}
|
128
214
|
|
129
|
-
return
|
215
|
+
return true;
|
130
216
|
error:
|
131
|
-
return
|
217
|
+
return false;
|
218
|
+
}
|
219
|
+
|
220
|
+
// The default interface to pushing a vertex, force the guard to on
|
221
|
+
bool poly_push_vertex(poly_t *poly, float3 v) {
|
222
|
+
return poly_push_vertex_guarded(poly, v, true);
|
223
|
+
}
|
224
|
+
|
225
|
+
// Unsafe poly push, forces the guard off, allowing 0-length edges
|
226
|
+
// to form. Useful in the `audit` command
|
227
|
+
bool poly_push_vertex_unsafe(poly_t *poly, float3 v) {
|
228
|
+
return poly_push_vertex_guarded(poly, v, false);
|
132
229
|
}
|
133
230
|
|
134
231
|
int poly_classify_vertex(poly_t *poly, float3 v) {
|
@@ -138,6 +235,21 @@ int poly_classify_vertex(poly_t *poly, float3 v) {
|
|
138
235
|
return COPLANAR;
|
139
236
|
}
|
140
237
|
|
238
|
+
const char* poly_classify_vertex_string(poly_t *poly, float3 v) {
|
239
|
+
const char *classification = "UNKNOWN";
|
240
|
+
switch(poly_classify_vertex(poly, v)) {
|
241
|
+
case FRONT:
|
242
|
+
classification = "FRONT";
|
243
|
+
break;
|
244
|
+
case BACK:
|
245
|
+
classification = "BACK";
|
246
|
+
break;
|
247
|
+
case COPLANAR:
|
248
|
+
classification = "COPLANAR";
|
249
|
+
}
|
250
|
+
return classification;
|
251
|
+
}
|
252
|
+
|
141
253
|
int poly_classify_poly(poly_t *this, poly_t *other) {
|
142
254
|
int front, back;
|
143
255
|
int count = poly_vertex_count(other);
|
@@ -180,6 +292,10 @@ int poly_split(poly_t *divider, poly_t *poly, poly_t **front, poly_t **back) {
|
|
180
292
|
int count = poly_vertex_count(poly);
|
181
293
|
for(i = 0; i < count; i++) {
|
182
294
|
j = (i + 1) % count;
|
295
|
+
|
296
|
+
// Fill v_cur[..] and v_next[..] with the values of
|
297
|
+
// the current (i) and next (j) vertex (x,y,z) data
|
298
|
+
// from `poly`
|
183
299
|
for(int k = 0; k < 3; k++) {
|
184
300
|
v_cur[k] = poly->vertices[i][k];
|
185
301
|
v_next[k] = poly->vertices[j][k];
|
@@ -204,31 +320,38 @@ int poly_split(poly_t *divider, poly_t *poly, poly_t **front, poly_t **back) {
|
|
204
320
|
float t = divider->w;
|
205
321
|
t = t - f3_dot(divider->normal, v_cur);
|
206
322
|
t = t / f3_dot(divider->normal, diff);
|
323
|
+
t = clampf(t, 0.0, 1.0);
|
207
324
|
|
208
325
|
float3 mid_f = {v_cur[0], v_cur[1], v_cur[2]};
|
209
326
|
f3_interpolate(&mid_f, v_cur, v_next, t);
|
210
327
|
|
211
|
-
|
212
|
-
|
213
|
-
check(poly_push_vertex(*back, mid_f) == 0,
|
214
|
-
"Failed to push midpoint to back poly(%p):", back);
|
328
|
+
poly_push_vertex(*front, mid_f);
|
329
|
+
poly_push_vertex(*back, mid_f);
|
215
330
|
}
|
216
331
|
}
|
217
332
|
|
333
|
+
// Clear any polygons that are not finished by this point
|
334
|
+
if((*front != NULL) && (poly_vertex_count(*front) < 3)) {
|
335
|
+
free_poly(*front, true);
|
336
|
+
*front = NULL;
|
337
|
+
}
|
338
|
+
|
339
|
+
if((*back != NULL) && (poly_vertex_count(*back) < 3)) {
|
340
|
+
free_poly(*back, true);
|
341
|
+
*back = NULL;
|
342
|
+
}
|
343
|
+
|
218
344
|
return 0;
|
219
|
-
error:
|
220
|
-
return -1;
|
221
345
|
}
|
222
346
|
|
223
|
-
poly_t *
|
224
|
-
poly_t *p =
|
225
|
-
check_mem(p = alloc_poly());
|
347
|
+
poly_t *poly_make_triangle_guarded(float3 a, float3 b, float3 c, bool guard) {
|
348
|
+
poly_t *p = alloc_poly();
|
226
349
|
|
227
|
-
|
350
|
+
check_debug(poly_push_vertex_guarded(p, a, guard),
|
228
351
|
"Failed to add vertex a to poly(%p): (%f, %f, %f)", p, FLOAT3_FORMAT(a));
|
229
|
-
|
352
|
+
check_debug(poly_push_vertex_guarded(p, b, guard),
|
230
353
|
"Failed to add vertex b to poly(%p): (%f, %f, %f)", p, FLOAT3_FORMAT(b));
|
231
|
-
|
354
|
+
check_debug(poly_push_vertex_guarded(p, c, guard),
|
232
355
|
"Failed to add vertex c to poly(%p): (%f, %f, %f)", p, FLOAT3_FORMAT(c));
|
233
356
|
|
234
357
|
return p;
|
@@ -237,6 +360,14 @@ error:
|
|
237
360
|
return NULL;
|
238
361
|
}
|
239
362
|
|
363
|
+
poly_t *poly_make_triangle(float3 a, float3 b, float3 c) {
|
364
|
+
return poly_make_triangle_guarded(a, b, c, true);
|
365
|
+
}
|
366
|
+
|
367
|
+
poly_t *poly_make_triangle_unsafe(float3 a, float3 b, float3 c) {
|
368
|
+
return poly_make_triangle_guarded(a, b, c, false);
|
369
|
+
}
|
370
|
+
|
240
371
|
poly_t *poly_invert(poly_t *poly) {
|
241
372
|
f3_scale(&poly->normal, -1.0);
|
242
373
|
poly->w *= -1.0;
|
@@ -262,3 +393,45 @@ poly_t *poly_invert(poly_t *poly) {
|
|
262
393
|
|
263
394
|
return poly;
|
264
395
|
}
|
396
|
+
|
397
|
+
// Compute the length of the lognest edge squared
|
398
|
+
float poly_max_edge_length2(poly_t *poly) {
|
399
|
+
const int count = poly_vertex_count(poly);
|
400
|
+
float longest = -INFINITY;
|
401
|
+
|
402
|
+
for(int i = 0; i < count; i++) {
|
403
|
+
int j = (i + 1) % count;
|
404
|
+
float d2 = f3_distance2(poly->vertices[i], poly->vertices[j]);
|
405
|
+
|
406
|
+
longest = (d2 > longest) ? d2 : longest;
|
407
|
+
}
|
408
|
+
|
409
|
+
return longest;
|
410
|
+
}
|
411
|
+
|
412
|
+
float poly_min_edge_length2(poly_t *poly) {
|
413
|
+
const int count = poly_vertex_count(poly);
|
414
|
+
float min = INFINITY;
|
415
|
+
|
416
|
+
for(int i = 0; i < count; i++) {
|
417
|
+
int j = (i + 1) % count;
|
418
|
+
float d2 = f3_distance2(poly->vertices[i], poly->vertices[j]);
|
419
|
+
|
420
|
+
min = (d2 < min) ? d2 : min;
|
421
|
+
}
|
422
|
+
|
423
|
+
return min;
|
424
|
+
}
|
425
|
+
|
426
|
+
float triangle_2area(float3 a, float3 b, float3 c) {
|
427
|
+
float3 b_a = FLOAT3_INIT;
|
428
|
+
float3 c_a = FLOAT3_INIT;
|
429
|
+
|
430
|
+
f3_sub(&b_a, b, a);
|
431
|
+
f3_sub(&c_a, c, a);
|
432
|
+
|
433
|
+
float3 cross = FLOAT3_INIT;
|
434
|
+
f3_cross(&cross, b_a, c_a);
|
435
|
+
|
436
|
+
return f3_magnitude(&cross);
|
437
|
+
}
|