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