allow non-convex polygons in linear_extrude
This commit is contained in:
parent
1d955a5131
commit
f51e7fb820
14 changed files with 439 additions and 254 deletions
20
Makefile
20
Makefile
|
|
@ -170,11 +170,11 @@ TEST_STL.stl := \
|
|||
TEST_STL.jsgz := \
|
||||
$(addprefix test-out/,$(notdir $(TEST_STL.scad:.scad=.js.gz)))
|
||||
|
||||
FAIL_STL.stl := \
|
||||
$(addprefix test-out/,$(notdir $(FAIL_STL.scad:.scad=.stl)))
|
||||
FAIL_STL := \
|
||||
$(addprefix test-out/fail-,$(notdir $(FAIL_STL.scad:.scad=.stl)))
|
||||
|
||||
FAIL_STL.jsgz := \
|
||||
$(addprefix test-out/,$(notdir $(FAIL_STL.scad:.scad=.js.gz)))
|
||||
FAIL_JS := \
|
||||
$(addprefix test-out/fail-,$(notdir $(FAIL_JS.scad:.scad=.js)))
|
||||
|
||||
######################################################################
|
||||
# header files
|
||||
|
|
@ -395,10 +395,10 @@ test-stl: $(TEST_STL.stl)
|
|||
test-js: $(TEST_STL.jsgz)
|
||||
|
||||
.PHONY: fail-stl
|
||||
fail-stl: $(FAIL_STL.stl)
|
||||
fail-stl: $(FAIL_STL)
|
||||
|
||||
.PHONY: fail-js
|
||||
fail-js: $(FAIL_STL.jsgz)
|
||||
fail-js: $(FAIL_JS)
|
||||
|
||||
.PHONY: test-jsgz
|
||||
test-jsgz: test-js
|
||||
|
|
@ -418,6 +418,10 @@ test-out/%.stl: scad-test/%.scad hob3l.exe
|
|||
$(HOB3L) $< -o $@.new.stl
|
||||
mv $@.new.stl $@
|
||||
|
||||
test-out/fail-%.stl: scad-test/%.scad hob3l.exe
|
||||
! $(HOB3L) $< -o $@.new.stl
|
||||
echo >| $@
|
||||
|
||||
test-out/%.stl: $(SCAD_DIR)/%.scad hob3l.exe
|
||||
openscad $< -o $@.new.csg
|
||||
$(HOB3L) $@.new.csg -o $@.new.stl
|
||||
|
|
@ -430,6 +434,10 @@ test-out/%.js: scad-test/%.scad hob3l.exe
|
|||
mv $@.new2.js $@
|
||||
rm $@.new.js
|
||||
|
||||
test-out/fail-%.js: scad-test/%.scad hob3l.exe
|
||||
! $(HOB3L) $< -o $@.new.js
|
||||
echo >| $@
|
||||
|
||||
test-out/%.js: $(SCAD_DIR)/%.scad hob3l.exe
|
||||
openscad $< -o $@.new.csg
|
||||
$(HOB3L) $@.new.csg -o $@.new.js
|
||||
|
|
|
|||
|
|
@ -701,10 +701,6 @@ is not usually helpful in 3D space). This means that the
|
|||
`--dump-csg3` output cannot be read back as input file. The XOR node
|
||||
is represented by a `hob3l_xor` functor.
|
||||
|
||||
BUG: Currently, this has the same restriction as the `polyhedron`: it
|
||||
cannot correctly handle non-convex polygons. (Actually, it works
|
||||
surprisingly well most of the time, but it is really still broken.)
|
||||
|
||||
_OpenSCAD compatibility_:
|
||||
|
||||
* `slices`:
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@
|
|||
* space from the polygons for storing the result.
|
||||
*/
|
||||
extern void cp_csg2_op_reduce(
|
||||
cp_pool_t *pool,
|
||||
cp_pool_t *tmp,
|
||||
cp_csg2_lazy_t *r);
|
||||
|
||||
/**
|
||||
|
|
@ -34,7 +34,7 @@ extern void cp_csg2_op_reduce(
|
|||
* \p r and/or \p b are reused and cleared to construct r. This may happen
|
||||
* immediately or later in cp_csg2_op_reduce().
|
||||
*
|
||||
* Uses \p pool for all temporary allocations (but not for constructing r).
|
||||
* Uses \p tmp for all temporary allocations (but not for constructing r).
|
||||
*
|
||||
* This uses the algorithm of Martinez, Rueda, Feito (2009), based on a
|
||||
* Bentley-Ottmann plain sweep. The algorithm is modified:
|
||||
|
|
@ -74,7 +74,7 @@ extern void cp_csg2_op_reduce(
|
|||
*/
|
||||
extern void cp_csg2_op_lazy(
|
||||
cp_csg_opt_t const *opt,
|
||||
cp_pool_t *pool,
|
||||
cp_pool_t *tmp,
|
||||
cp_csg2_lazy_t *r,
|
||||
cp_csg2_lazy_t *b,
|
||||
cp_bool_op_t op);
|
||||
|
|
@ -94,7 +94,7 @@ extern void cp_csg2_op_lazy(
|
|||
*/
|
||||
extern void cp_csg2_op_add_layer(
|
||||
cp_csg_opt_t const *opt,
|
||||
cp_pool_t *pool,
|
||||
cp_pool_t *tmp,
|
||||
cp_csg2_tree_t *r,
|
||||
cp_csg2_tree_t *a,
|
||||
size_t zi);
|
||||
|
|
@ -118,7 +118,7 @@ extern void cp_csg2_op_add_layer(
|
|||
*/
|
||||
extern cp_csg2_poly_t *cp_csg2_flatten(
|
||||
cp_csg_opt_t const *opt,
|
||||
cp_pool_t *pool,
|
||||
cp_pool_t *tmp,
|
||||
cp_v_obj_p_t *root);
|
||||
|
||||
/**
|
||||
|
|
@ -134,7 +134,7 @@ extern cp_csg2_poly_t *cp_csg2_flatten(
|
|||
*/
|
||||
extern void cp_csg2_op_diff_layer(
|
||||
cp_csg_opt_t const *opt,
|
||||
cp_pool_t *pool,
|
||||
cp_pool_t *tmp,
|
||||
cp_csg2_tree_t *a,
|
||||
size_t zi);
|
||||
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@
|
|||
* Additionally, the improper start case has a special case if vertices
|
||||
* coincide.
|
||||
*
|
||||
* Uses \p pool for all temporary allocations (but not for constructing
|
||||
* Uses \p tmp for all temporary allocations (but not for constructing
|
||||
* point_arr or tri).
|
||||
*
|
||||
* Runtime: O(n log n)
|
||||
|
|
@ -64,7 +64,7 @@
|
|||
* Where n = number of points.
|
||||
*/
|
||||
extern bool cp_csg2_tri_set(
|
||||
cp_pool_t *pool,
|
||||
cp_pool_t *tmp,
|
||||
cp_err_t *t,
|
||||
cp_vec2_arr_ref_t *point_arr,
|
||||
cp_v_size3_t *tri,
|
||||
|
|
@ -79,14 +79,14 @@ extern bool cp_csg2_tri_set(
|
|||
* This uses cp_csg2_tri_set() internally, so the path is contrained
|
||||
* in the way described for that function.
|
||||
*
|
||||
* Uses \p pool for all temporary allocations (but not for constructing g).
|
||||
* Uses \p tmp for all temporary allocations (but not for constructing g).
|
||||
*
|
||||
* Runtime: O(n log n)
|
||||
* Space: O(n)
|
||||
* Where n = number of points.
|
||||
*/
|
||||
extern bool cp_csg2_tri_path(
|
||||
cp_pool_t *pool,
|
||||
cp_pool_t *tmp,
|
||||
cp_err_t *t,
|
||||
cp_csg2_poly_t *g,
|
||||
cp_csg2_path_t *s);
|
||||
|
|
@ -100,17 +100,26 @@ extern bool cp_csg2_tri_path(
|
|||
* the paths in one data structure, so the set of paths of the given
|
||||
* polygon is contrained in the way described for that function.
|
||||
*
|
||||
* Uses \p pool for all temporary allocations (but not for constructing r).
|
||||
* Uses \p tmp for all temporary allocations (but not for constructing r).
|
||||
*
|
||||
* Runtime: O(n log n)
|
||||
* Space: O(n)
|
||||
* Where n = number of points.
|
||||
*/
|
||||
extern bool cp_csg2_tri_poly(
|
||||
cp_pool_t *pool,
|
||||
cp_pool_t *tmp,
|
||||
cp_err_t *t,
|
||||
cp_csg2_poly_t *g);
|
||||
|
||||
/**
|
||||
* Same as cp_csg2_tri_poly, but triangulates a reference array of vec2.
|
||||
*/
|
||||
extern bool cp_csg2_tri_vec2_arr_ref(
|
||||
cp_v_size3_t *tri,
|
||||
cp_pool_t *tmp,
|
||||
cp_err_t *t,
|
||||
cp_vec2_arr_ref_t *a2);
|
||||
|
||||
/**
|
||||
* Triangulate a given layer
|
||||
*
|
||||
|
|
@ -125,7 +134,7 @@ extern bool cp_csg2_tri_poly(
|
|||
* tree, so the set of paths of each polygon in the tree is contrained
|
||||
* in the way described for that function.
|
||||
*
|
||||
* Uses \p pool for all temporary allocations (but not for constructing r).
|
||||
* Uses \p tmp for all temporary allocations (but not for constructing r).
|
||||
*
|
||||
* Runtime: O(m * n log n)
|
||||
* Space: O(max(n))
|
||||
|
|
@ -135,7 +144,7 @@ extern bool cp_csg2_tri_poly(
|
|||
* max(n) = the maximum n among the polygons.
|
||||
*/
|
||||
extern bool cp_csg2_tri_layer(
|
||||
cp_pool_t *pool,
|
||||
cp_pool_t *tmp,
|
||||
cp_err_t *t,
|
||||
cp_csg2_tree_t *r,
|
||||
size_t zi);
|
||||
|
|
@ -149,7 +158,7 @@ extern bool cp_csg2_tri_layer(
|
|||
* Runtime and space: see cp_csg2_tri_layer.
|
||||
*/
|
||||
extern bool cp_csg2_tri_layer_diff(
|
||||
cp_pool_t *pool,
|
||||
cp_pool_t *tmp,
|
||||
cp_err_t *t,
|
||||
cp_csg2_tree_t *r,
|
||||
size_t zi);
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ extern void cp_csg3_tree_bb(
|
|||
* Convert a SCAD AST into a CSG3 tree.
|
||||
*/
|
||||
extern bool cp_csg3_from_scad_tree(
|
||||
cp_pool_t *pool,
|
||||
cp_pool_t *tmp,
|
||||
cp_csg3_tree_t *r,
|
||||
cp_err_t *t,
|
||||
cp_scad_tree_t const *scad);
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ typedef enum {
|
|||
((__x != 0) && ((__x & (__x - 1)) == 0)); \
|
||||
})
|
||||
|
||||
#define cp_offsetof(T,F) (__builtin_offsetof(T,F))
|
||||
#define cp_offsetof(T,F) (__builtin_offsetof(__typeof__(T),F))
|
||||
|
||||
#define cp_alignof(X) (__alignof__(X))
|
||||
|
||||
|
|
|
|||
|
|
@ -571,4 +571,65 @@ static inline bool cp_vec3_left_normal3(
|
|||
return cp_vec3_right_normal3(r,b,o,a);
|
||||
}
|
||||
|
||||
static inline cp_vec2_t *cp_vec2_arr_ref(
|
||||
cp_vec2_arr_ref_t *a,
|
||||
size_t i)
|
||||
{
|
||||
assert(i < a->count);
|
||||
assert(((i * a->size) / a->size) == i);
|
||||
void *r = ((char*)a->base_vec2) + (a->size * i);
|
||||
return r;
|
||||
}
|
||||
|
||||
static inline cp_loc_t cp_vec2_arr_loc(
|
||||
cp_vec2_arr_ref_t *a,
|
||||
size_t i)
|
||||
{
|
||||
assert(i < a->count);
|
||||
assert(((i * a->size) / a->size) == i);
|
||||
cp_loc_t *r = (void*)(((char*)a->base_loc) + (a->size * i));
|
||||
return *r;
|
||||
}
|
||||
|
||||
static inline size_t cp_vec2_arr_idx(
|
||||
cp_vec2_arr_ref_t *a,
|
||||
cp_vec2_t *p)
|
||||
{
|
||||
size_t o = CP_PTRDIFF((char*)p, (char*)a->base_vec2);
|
||||
assert((o % a->size) == 0);
|
||||
return o / a->size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert to vec2 array.
|
||||
*/
|
||||
static inline void cp_vec2_arr_ref_from_v_vec2_loc(
|
||||
cp_vec2_arr_ref_t *a,
|
||||
cp_v_vec2_loc_t *v)
|
||||
{
|
||||
a->base_vec2 = (char*)v->data + cp_offsetof(*v->data, coord);
|
||||
a->base_loc = (char*)v->data + cp_offsetof(*v->data, loc);
|
||||
a->size = sizeof(*v->data);
|
||||
a->count = v->size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert to vec2 array.
|
||||
*/
|
||||
static inline void cp_vec2_arr_ref_from_a_vec3_loc(
|
||||
cp_vec2_arr_ref_t *a,
|
||||
cp_a_vec3_loc_t *v,
|
||||
bool yz_plane)
|
||||
{
|
||||
a->base_vec2 =
|
||||
(char*)v->data +
|
||||
(yz_plane ?
|
||||
cp_offsetof(*v->data, coord.be)
|
||||
: cp_offsetof(*v->data, coord.b));
|
||||
|
||||
a->base_loc = (char*)v->data + cp_offsetof(*v->data, loc);
|
||||
a->size = sizeof(*v->data);
|
||||
a->count = v->size;
|
||||
}
|
||||
|
||||
#endif /* __CP_MAT_H */
|
||||
|
|
|
|||
|
|
@ -35,6 +35,10 @@ typedef union {
|
|||
cp_vec2_t b;
|
||||
cp_dim_t w;
|
||||
};
|
||||
struct {
|
||||
cp_dim_t we;
|
||||
cp_vec2_t be;
|
||||
};
|
||||
} cp_vec3_t;
|
||||
|
||||
typedef struct {
|
||||
|
|
@ -57,6 +61,10 @@ typedef union {
|
|||
struct {
|
||||
cp_vec3_t b;
|
||||
};
|
||||
struct {
|
||||
cp_dim_t we;
|
||||
cp_vec3_t be;
|
||||
};
|
||||
} cp_vec4_t;
|
||||
|
||||
typedef struct {
|
||||
|
|
|
|||
|
|
@ -86,52 +86,12 @@ typedef CP_ARR_T(cp_vec3_loc_ref_t) cp_a_vec3_loc_ref_t;
|
|||
* Pointer to base of array of entries with vec2 slot plus info to access array.
|
||||
*/
|
||||
typedef struct {
|
||||
void *base;
|
||||
void *base_vec2;
|
||||
void *base_loc;
|
||||
size_t size;
|
||||
size_t count;
|
||||
} cp_vec2_arr_ref_t;
|
||||
|
||||
static inline cp_vec2_t *cp_vec2_arr_ref(
|
||||
cp_vec2_arr_ref_t *a,
|
||||
size_t i)
|
||||
{
|
||||
assert(i < a->count);
|
||||
assert(((i * a->size) / a->size) == i);
|
||||
void *r = ((char*)a->base) + (a->size * i);
|
||||
return r;
|
||||
}
|
||||
|
||||
static inline size_t cp_vec2_arr_idx(
|
||||
cp_vec2_arr_ref_t *a,
|
||||
cp_vec2_t *p)
|
||||
{
|
||||
size_t o = CP_PTRDIFF((char*)p, (char*)a->base);
|
||||
assert((o % a->size) == 0);
|
||||
return o / a->size;
|
||||
}
|
||||
|
||||
static inline cp_vec2_arr_ref_t *__cp_vec2_arr_ref_set(
|
||||
cp_vec2_arr_ref_t *a,
|
||||
cp_vec2_arr_ref_t x)
|
||||
{
|
||||
*a = x;
|
||||
return a;
|
||||
}
|
||||
|
||||
#define CP_VEC2_ARR_REF(arr, slot) \
|
||||
(*__cp_vec2_arr_ref_set( \
|
||||
&(cp_vec2_arr_ref_t){ .base=0 }, \
|
||||
({ \
|
||||
__typeof__(*(arr)) *__arr = (arr); \
|
||||
void *__base = __arr->data; \
|
||||
cp_vec2_arr_ref_t __r = { \
|
||||
.base = (char*)__base + cp_offsetof(__typeof__(__arr->data[0]), slot), \
|
||||
.size = sizeof(__arr->data[0]), \
|
||||
.count = __arr->size \
|
||||
}; \
|
||||
__r; \
|
||||
})))
|
||||
|
||||
#define CP_V01(p) (p).v[0], (p).v[1]
|
||||
#define CP_V012(p) (p).v[0], (p).v[1], (p).v[2]
|
||||
#define CP_V0123(p) (p).v[0], (p).v[1], (p).v[2], (p).v[3]
|
||||
|
|
|
|||
|
|
@ -238,6 +238,10 @@ sub gen_type_vec($$$)
|
|||
$s.= " X_dim_t w;\n";
|
||||
}
|
||||
$s.= " };\n";
|
||||
$s.= " struct {\n";
|
||||
$s.= " X_dim_t we;\n";
|
||||
$s.= " X_$ts->{name}_t be;\n";
|
||||
$s.= " };\n";
|
||||
}
|
||||
$s.= "} X_$t->{name}_t;\n";
|
||||
publish($oc, 'tam_h', $s);
|
||||
|
|
|
|||
|
|
@ -184,7 +184,7 @@ typedef CP_VEC_T(event_t*) v_event_p_t;
|
|||
*/
|
||||
typedef struct {
|
||||
/** Memory pool to use */
|
||||
cp_pool_t *pool;
|
||||
cp_pool_t *tmp;
|
||||
|
||||
/** Error output */
|
||||
cp_err_t *err;
|
||||
|
|
@ -221,7 +221,7 @@ typedef struct {
|
|||
*/
|
||||
typedef struct {
|
||||
cp_csg_opt_t const *opt;
|
||||
cp_pool_t *pool;
|
||||
cp_pool_t *tmp;
|
||||
} op_ctxt_t;
|
||||
|
||||
|
||||
|
|
@ -483,7 +483,7 @@ static point_t *pt_new(
|
|||
return CP_BOX_OF(pt, point_t, node_pt);
|
||||
}
|
||||
|
||||
point_t *p = CP_POOL_NEW(c->pool, *p);
|
||||
point_t *p = CP_POOL_NEW(c->tmp, *p);
|
||||
p->v.coord = coord;
|
||||
p->v.loc = loc;
|
||||
p->v.color = *color;
|
||||
|
|
@ -505,7 +505,7 @@ static event_t *ev_new(
|
|||
bool left,
|
||||
event_t *other)
|
||||
{
|
||||
event_t *r = CP_POOL_NEW(c->pool, *r);
|
||||
event_t *r = CP_POOL_NEW(c->tmp, *r);
|
||||
r->loc = loc;
|
||||
r->p = p;
|
||||
r->left = left;
|
||||
|
|
@ -1757,7 +1757,7 @@ static bool csg2_op_v_csg2(
|
|||
return false;
|
||||
}
|
||||
LOG("ADD\n");
|
||||
cp_csg2_op_lazy(c->opt, c->pool, o, &oi, CP_OP_ADD);
|
||||
cp_csg2_op_lazy(c->opt, c->tmp, o, &oi, CP_OP_ADD);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
|
@ -1795,7 +1795,7 @@ static bool csg2_op_cut(
|
|||
return false;
|
||||
}
|
||||
LOG("CUT\n");
|
||||
cp_csg2_op_lazy(c->opt, c->pool, o, &oc, CP_OP_CUT);
|
||||
cp_csg2_op_lazy(c->opt, c->tmp, o, &oc, CP_OP_CUT);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
|
@ -1822,7 +1822,7 @@ static bool csg2_op_xor(
|
|||
return false;
|
||||
}
|
||||
LOG("XOR\n");
|
||||
cp_csg2_op_lazy(c->opt, c->pool, o, &oc, CP_OP_XOR);
|
||||
cp_csg2_op_lazy(c->opt, c->tmp, o, &oc, CP_OP_XOR);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
|
@ -1858,7 +1858,7 @@ static bool csg2_op_sub(
|
|||
return false;
|
||||
}
|
||||
LOG("SUB\n");
|
||||
cp_csg2_op_lazy(c->opt, c->pool, o, &os, CP_OP_SUB);
|
||||
cp_csg2_op_lazy(c->opt, c->tmp, o, &os, CP_OP_SUB);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -1924,14 +1924,14 @@ static bool csg2_op_csg2(
|
|||
* them. Any poly but r->data[0] will be left completely untouched.
|
||||
*/
|
||||
static void cp_csg2_op_poly(
|
||||
cp_pool_t *pool,
|
||||
cp_pool_t *tmp,
|
||||
cp_csg2_poly_t *o,
|
||||
cp_csg2_lazy_t const *r)
|
||||
{
|
||||
TRACE();
|
||||
/* make context */
|
||||
ctxt_t c = {
|
||||
.pool = pool,
|
||||
.tmp = tmp,
|
||||
.comb = &r->comb,
|
||||
.comb_size = (1U << r->size),
|
||||
};
|
||||
|
|
@ -1980,7 +1980,7 @@ static void cp_csg2_op_poly(
|
|||
|
||||
static cp_csg2_poly_t *poly_sub(
|
||||
cp_csg_opt_t const *opt,
|
||||
cp_pool_t *pool,
|
||||
cp_pool_t *tmp,
|
||||
cp_csg2_poly_t *a0,
|
||||
cp_csg2_poly_t *a1)
|
||||
{
|
||||
|
|
@ -1995,11 +1995,11 @@ static cp_csg2_poly_t *poly_sub(
|
|||
CP_ZERO(&o1);
|
||||
csg2_op_poly(&o1, a1);
|
||||
|
||||
cp_csg2_op_lazy(opt, pool, &o0, &o1, CP_OP_SUB);
|
||||
cp_csg2_op_lazy(opt, tmp, &o0, &o1, CP_OP_SUB);
|
||||
assert(o0.size == 2);
|
||||
|
||||
cp_csg2_poly_t *o = CP_CLONE(a1);
|
||||
cp_csg2_op_poly(pool, o, &o0);
|
||||
cp_csg2_op_poly(tmp, o, &o0);
|
||||
|
||||
/* check that the originals really haven't changed */
|
||||
assert(a0->point.size == a0_point_sz);
|
||||
|
|
@ -2010,7 +2010,7 @@ static cp_csg2_poly_t *poly_sub(
|
|||
|
||||
static void csg2_op_diff2_poly(
|
||||
cp_csg_opt_t const *opt,
|
||||
cp_pool_t *pool,
|
||||
cp_pool_t *tmp,
|
||||
cp_csg2_poly_t *a0,
|
||||
cp_csg2_poly_t *a1)
|
||||
{
|
||||
|
|
@ -2019,13 +2019,13 @@ static void csg2_op_diff2_poly(
|
|||
return;
|
||||
}
|
||||
|
||||
a0->diff_above = poly_sub(opt, pool, a0, a1);
|
||||
a1->diff_below = poly_sub(opt, pool, a1, a0);
|
||||
a0->diff_above = poly_sub(opt, tmp, a0, a1);
|
||||
a1->diff_below = poly_sub(opt, tmp, a1, a0);
|
||||
}
|
||||
|
||||
static void csg2_op_diff2(
|
||||
cp_csg_opt_t const *opt,
|
||||
cp_pool_t *pool,
|
||||
cp_pool_t *tmp,
|
||||
cp_csg2_t *a0,
|
||||
cp_csg2_t *a1)
|
||||
{
|
||||
|
|
@ -2038,12 +2038,12 @@ static void csg2_op_diff2(
|
|||
if (p1 == NULL) {
|
||||
return;
|
||||
}
|
||||
csg2_op_diff2_poly(opt, pool, p0, p1);
|
||||
csg2_op_diff2_poly(opt, tmp, p0, p1);
|
||||
}
|
||||
|
||||
static void csg2_op_diff2_layer(
|
||||
cp_csg_opt_t const *opt,
|
||||
cp_pool_t *pool,
|
||||
cp_pool_t *tmp,
|
||||
cp_csg2_layer_t *a0,
|
||||
cp_csg2_layer_t *a1)
|
||||
{
|
||||
|
|
@ -2054,14 +2054,14 @@ static void csg2_op_diff2_layer(
|
|||
if (cp_csg_add_size(a1->root) != 1) {
|
||||
return;
|
||||
}
|
||||
csg2_op_diff2(opt, pool,
|
||||
csg2_op_diff2(opt, tmp,
|
||||
cp_csg2_cast(cp_csg2_t, cp_v_nth(&a0->root->add,0)),
|
||||
cp_csg2_cast(cp_csg2_t, cp_v_nth(&a1->root->add,0)));
|
||||
}
|
||||
|
||||
static void csg2_op_diff_stack(
|
||||
cp_csg_opt_t const *opt,
|
||||
cp_pool_t *pool,
|
||||
cp_pool_t *tmp,
|
||||
size_t zi,
|
||||
cp_csg2_stack_t *a)
|
||||
{
|
||||
|
|
@ -2080,12 +2080,12 @@ static void csg2_op_diff_stack(
|
|||
return;
|
||||
}
|
||||
|
||||
csg2_op_diff2_layer(opt, pool, l0, l1);
|
||||
csg2_op_diff2_layer(opt, tmp, l0, l1);
|
||||
}
|
||||
|
||||
static void csg2_op_diff_csg2(
|
||||
cp_csg_opt_t const *opt,
|
||||
cp_pool_t *pool,
|
||||
cp_pool_t *tmp,
|
||||
size_t zi,
|
||||
cp_csg2_t *a)
|
||||
{
|
||||
|
|
@ -2093,7 +2093,7 @@ static void csg2_op_diff_csg2(
|
|||
/* only work on stacks, ignore anything else */
|
||||
switch (a->type) {
|
||||
case CP_CSG2_STACK:
|
||||
csg2_op_diff_stack(opt, pool, zi, cp_csg2_cast(cp_csg2_stack_t, a));
|
||||
csg2_op_diff_stack(opt, tmp, zi, cp_csg2_cast(cp_csg2_stack_t, a));
|
||||
return;
|
||||
default:
|
||||
return;
|
||||
|
|
@ -2116,14 +2116,14 @@ static void csg2_op_diff_csg2(
|
|||
* space from the polygons for storing the result.
|
||||
*/
|
||||
extern void cp_csg2_op_reduce(
|
||||
cp_pool_t *pool,
|
||||
cp_pool_t *tmp,
|
||||
cp_csg2_lazy_t *r)
|
||||
{
|
||||
TRACE();
|
||||
if (r->size <= 1) {
|
||||
return;
|
||||
}
|
||||
cp_csg2_op_poly(pool, r->data[0], r);
|
||||
cp_csg2_op_poly(tmp, r->data[0], r);
|
||||
if (r->data[0]->point.size == 0) {
|
||||
CP_ZERO(r);
|
||||
return;
|
||||
|
|
@ -2142,7 +2142,7 @@ extern void cp_csg2_op_reduce(
|
|||
* \p r and/or \p b are reused and cleared to construct r. This may happen
|
||||
* immediately or later in cp_csg2_op_reduce().
|
||||
*
|
||||
* Uses \p pool for all temporary allocations (but not for constructing r).
|
||||
* Uses \p tmp for all temporary allocations (but not for constructing r).
|
||||
*
|
||||
* This uses the algorithm of Martinez, Rueda, Feito (2009), based on a
|
||||
* Bentley-Ottmann plain sweep. The algorithm is modified:
|
||||
|
|
@ -2182,7 +2182,7 @@ extern void cp_csg2_op_reduce(
|
|||
*/
|
||||
extern void cp_csg2_op_lazy(
|
||||
cp_csg_opt_t const *opt,
|
||||
cp_pool_t *pool,
|
||||
cp_pool_t *tmp,
|
||||
cp_csg2_lazy_t *r,
|
||||
cp_csg2_lazy_t *b,
|
||||
cp_bool_op_t op)
|
||||
|
|
@ -2217,11 +2217,11 @@ extern void cp_csg2_op_lazy(
|
|||
|
||||
/* otherwise reduce the larger one */
|
||||
if (r->size > b->size) {
|
||||
cp_csg2_op_reduce(pool, r);
|
||||
cp_csg2_op_reduce(tmp, r);
|
||||
assert(r->size <= 1);
|
||||
}
|
||||
else {
|
||||
cp_csg2_op_reduce(pool, b);
|
||||
cp_csg2_op_reduce(tmp, b);
|
||||
assert(b->size <= 1);
|
||||
}
|
||||
}
|
||||
|
|
@ -2264,7 +2264,7 @@ extern void cp_csg2_op_lazy(
|
|||
*/
|
||||
extern void cp_csg2_op_add_layer(
|
||||
cp_csg_opt_t const *opt,
|
||||
cp_pool_t *pool,
|
||||
cp_pool_t *tmp,
|
||||
cp_csg2_tree_t *r,
|
||||
cp_csg2_tree_t *a,
|
||||
size_t zi)
|
||||
|
|
@ -2275,14 +2275,14 @@ extern void cp_csg2_op_add_layer(
|
|||
|
||||
op_ctxt_t c = {
|
||||
.opt = opt,
|
||||
.pool = pool,
|
||||
.tmp = tmp,
|
||||
};
|
||||
|
||||
cp_csg2_lazy_t ol;
|
||||
CP_ZERO(&ol);
|
||||
bool ok __unused = csg2_op_csg2(&c, zi, &ol, a->root);
|
||||
assert(ok && "Unexpected object in tree.");
|
||||
cp_csg2_op_reduce(pool, &ol);
|
||||
cp_csg2_op_reduce(tmp, &ol);
|
||||
|
||||
cp_csg2_poly_t *o = ol.data[0];
|
||||
if (o != NULL) {
|
||||
|
|
@ -2321,20 +2321,20 @@ extern void cp_csg2_op_add_layer(
|
|||
*/
|
||||
extern cp_csg2_poly_t *cp_csg2_flatten(
|
||||
cp_csg_opt_t const *opt,
|
||||
cp_pool_t *pool,
|
||||
cp_pool_t *tmp,
|
||||
cp_v_obj_p_t *root)
|
||||
{
|
||||
TRACE();
|
||||
op_ctxt_t c = {
|
||||
.opt = opt,
|
||||
.pool = pool,
|
||||
.tmp = tmp,
|
||||
};
|
||||
|
||||
cp_csg2_lazy_t ol;
|
||||
CP_ZERO(&ol);
|
||||
bool ok __unused = csg2_op_v_csg2(&c, 0, &ol, root);
|
||||
assert(ok && "Unexpected object in tree.");
|
||||
cp_csg2_op_reduce(pool, &ol);
|
||||
cp_csg2_op_reduce(tmp, &ol);
|
||||
|
||||
return ol.data[0];
|
||||
}
|
||||
|
|
@ -2352,7 +2352,7 @@ extern cp_csg2_poly_t *cp_csg2_flatten(
|
|||
*/
|
||||
extern void cp_csg2_op_diff_layer(
|
||||
cp_csg_opt_t const *opt,
|
||||
cp_pool_t *pool,
|
||||
cp_pool_t *tmp,
|
||||
cp_csg2_tree_t *a,
|
||||
size_t zi)
|
||||
{
|
||||
|
|
@ -2360,7 +2360,7 @@ extern void cp_csg2_op_diff_layer(
|
|||
cp_csg2_stack_t *s __unused = cp_csg2_cast(*s, a->root);
|
||||
assert(zi < s->layer.size);
|
||||
|
||||
csg2_op_diff_csg2(opt, pool, zi, a->root);
|
||||
csg2_op_diff_csg2(opt, tmp, zi, a->root);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1083,24 +1083,24 @@ static bool transition(
|
|||
}
|
||||
|
||||
static bool csg2_tri_v_csg2(
|
||||
cp_pool_t *pool,
|
||||
cp_pool_t *tmp,
|
||||
cp_err_t *t,
|
||||
cp_v_obj_p_t *r,
|
||||
size_t zi);
|
||||
|
||||
static bool csg2_tri_layer(
|
||||
cp_pool_t *pool,
|
||||
cp_pool_t *tmp,
|
||||
cp_err_t *t,
|
||||
cp_csg2_layer_t *r)
|
||||
{
|
||||
if (r->root == NULL) {
|
||||
return true;
|
||||
}
|
||||
return csg2_tri_v_csg2(pool, t, &r->root->add, r->zi);
|
||||
return csg2_tri_v_csg2(tmp, t, &r->root->add, r->zi);
|
||||
}
|
||||
|
||||
static bool csg2_tri_stack(
|
||||
cp_pool_t *pool,
|
||||
cp_pool_t *tmp,
|
||||
cp_err_t *t,
|
||||
cp_csg2_stack_t *r,
|
||||
size_t zi)
|
||||
|
|
@ -1109,37 +1109,37 @@ static bool csg2_tri_stack(
|
|||
if ((l == NULL) || (l->root == NULL)) {
|
||||
return true;
|
||||
}
|
||||
return csg2_tri_layer(pool, t, l);
|
||||
return csg2_tri_layer(tmp, t, l);
|
||||
}
|
||||
|
||||
static bool csg2_tri_sub(
|
||||
cp_pool_t *pool,
|
||||
cp_pool_t *tmp,
|
||||
cp_err_t *t,
|
||||
cp_csg_sub_t *r,
|
||||
size_t zi)
|
||||
{
|
||||
return
|
||||
csg2_tri_v_csg2(pool, t, &r->add->add, zi) &&
|
||||
csg2_tri_v_csg2(pool, t, &r->sub->add, zi);
|
||||
csg2_tri_v_csg2(tmp, t, &r->add->add, zi) &&
|
||||
csg2_tri_v_csg2(tmp, t, &r->sub->add, zi);
|
||||
}
|
||||
|
||||
static bool csg2_tri_add(
|
||||
cp_pool_t *pool,
|
||||
cp_pool_t *tmp,
|
||||
cp_err_t *t,
|
||||
cp_csg_add_t *r,
|
||||
size_t zi)
|
||||
{
|
||||
return csg2_tri_v_csg2(pool, t, &r->add, zi);
|
||||
return csg2_tri_v_csg2(tmp, t, &r->add, zi);
|
||||
}
|
||||
|
||||
static bool csg2_tri_cut(
|
||||
cp_pool_t *pool,
|
||||
cp_pool_t *tmp,
|
||||
cp_err_t *t,
|
||||
cp_csg_cut_t *r,
|
||||
size_t zi)
|
||||
{
|
||||
for (cp_v_each(i, &r->cut)) {
|
||||
if (!csg2_tri_v_csg2(pool, t, &r->cut.data[i]->add, zi)) {
|
||||
if (!csg2_tri_v_csg2(tmp, t, &r->cut.data[i]->add, zi)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -1147,13 +1147,13 @@ static bool csg2_tri_cut(
|
|||
}
|
||||
|
||||
static bool csg2_tri_xor(
|
||||
cp_pool_t *pool,
|
||||
cp_pool_t *tmp,
|
||||
cp_err_t *t,
|
||||
cp_csg_xor_t *r,
|
||||
size_t zi)
|
||||
{
|
||||
for (cp_v_each(i, &r->xor)) {
|
||||
if (!csg2_tri_v_csg2(pool, t, &r->xor.data[i]->add, zi)) {
|
||||
if (!csg2_tri_v_csg2(tmp, t, &r->xor.data[i]->add, zi)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -1161,42 +1161,42 @@ static bool csg2_tri_xor(
|
|||
}
|
||||
|
||||
static bool csg2_tri_csg2(
|
||||
cp_pool_t *pool,
|
||||
cp_pool_t *tmp,
|
||||
cp_err_t *t,
|
||||
cp_csg2_t *r,
|
||||
size_t zi)
|
||||
{
|
||||
switch (r->type) {
|
||||
case CP_CSG2_POLY:
|
||||
return cp_csg2_tri_poly(pool, t, cp_csg2_cast(cp_csg2_poly_t, r));
|
||||
return cp_csg2_tri_poly(tmp, t, cp_csg2_cast(cp_csg2_poly_t, r));
|
||||
|
||||
case CP_CSG2_STACK:
|
||||
return csg2_tri_stack(pool, t, cp_csg2_cast(cp_csg2_stack_t, r), zi);
|
||||
return csg2_tri_stack(tmp, t, cp_csg2_cast(cp_csg2_stack_t, r), zi);
|
||||
|
||||
case CP_CSG_ADD:
|
||||
return csg2_tri_add(pool, t, cp_csg_cast(cp_csg_add_t, r), zi);
|
||||
return csg2_tri_add(tmp, t, cp_csg_cast(cp_csg_add_t, r), zi);
|
||||
|
||||
case CP_CSG_XOR:
|
||||
return csg2_tri_xor(pool, t, cp_csg_cast(cp_csg_xor_t, r), zi);
|
||||
return csg2_tri_xor(tmp, t, cp_csg_cast(cp_csg_xor_t, r), zi);
|
||||
|
||||
case CP_CSG_SUB:
|
||||
return csg2_tri_sub(pool, t, cp_csg_cast(cp_csg_sub_t, r), zi);
|
||||
return csg2_tri_sub(tmp, t, cp_csg_cast(cp_csg_sub_t, r), zi);
|
||||
|
||||
case CP_CSG_CUT:
|
||||
return csg2_tri_cut(pool, t, cp_csg_cast(cp_csg_cut_t, r), zi);
|
||||
return csg2_tri_cut(tmp, t, cp_csg_cast(cp_csg_cut_t, r), zi);
|
||||
}
|
||||
|
||||
CP_DIE("2D object type: %#x", r->type);
|
||||
}
|
||||
|
||||
static bool csg2_tri_v_csg2(
|
||||
cp_pool_t *pool,
|
||||
cp_pool_t *tmp,
|
||||
cp_err_t *t,
|
||||
cp_v_obj_p_t *r,
|
||||
size_t zi)
|
||||
{
|
||||
for (cp_v_each(i, r)) {
|
||||
if (!csg2_tri_csg2(pool, t, cp_csg2_cast(cp_csg2_t, cp_v_nth(r,i)), zi)) {
|
||||
if (!csg2_tri_csg2(tmp, t, cp_csg2_cast(cp_csg2_t, cp_v_nth(r,i)), zi)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -1204,24 +1204,24 @@ static bool csg2_tri_v_csg2(
|
|||
}
|
||||
|
||||
static bool csg2_tri_diff_v_csg2(
|
||||
cp_pool_t *pool,
|
||||
cp_pool_t *tmp,
|
||||
cp_err_t *t,
|
||||
cp_v_obj_p_t *r,
|
||||
size_t zi);
|
||||
|
||||
static bool csg2_tri_diff_layer(
|
||||
cp_pool_t *pool,
|
||||
cp_pool_t *tmp,
|
||||
cp_err_t *t,
|
||||
cp_csg2_layer_t *r)
|
||||
{
|
||||
if (r->root == NULL) {
|
||||
return true;
|
||||
}
|
||||
return csg2_tri_diff_v_csg2(pool, t, &r->root->add, r->zi);
|
||||
return csg2_tri_diff_v_csg2(tmp, t, &r->root->add, r->zi);
|
||||
}
|
||||
|
||||
static bool csg2_tri_diff_stack(
|
||||
cp_pool_t *pool,
|
||||
cp_pool_t *tmp,
|
||||
cp_err_t *t,
|
||||
cp_csg2_stack_t *r,
|
||||
size_t zi)
|
||||
|
|
@ -1230,21 +1230,21 @@ static bool csg2_tri_diff_stack(
|
|||
if (l == NULL) {
|
||||
return true;
|
||||
}
|
||||
return csg2_tri_diff_layer(pool, t, l);
|
||||
return csg2_tri_diff_layer(tmp, t, l);
|
||||
}
|
||||
|
||||
static bool csg2_tri_diff_poly(
|
||||
cp_pool_t *pool,
|
||||
cp_pool_t *tmp,
|
||||
cp_err_t *t,
|
||||
cp_csg2_poly_t *g)
|
||||
{
|
||||
if (g->diff_above != NULL) {
|
||||
if (!cp_csg2_tri_poly(pool, t, g->diff_above)) {
|
||||
if (!cp_csg2_tri_poly(tmp, t, g->diff_above)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (g->diff_below != NULL) {
|
||||
if (!cp_csg2_tri_poly(pool, t, g->diff_below)) {
|
||||
if (!cp_csg2_tri_poly(tmp, t, g->diff_below)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -1252,29 +1252,29 @@ static bool csg2_tri_diff_poly(
|
|||
}
|
||||
|
||||
static bool csg2_tri_diff_csg2(
|
||||
cp_pool_t *pool,
|
||||
cp_pool_t *tmp,
|
||||
cp_err_t *t,
|
||||
cp_csg2_t *r,
|
||||
size_t zi)
|
||||
{
|
||||
switch (r->type) {
|
||||
case CP_CSG2_POLY:
|
||||
return csg2_tri_diff_poly(pool, t, cp_csg2_cast(cp_csg2_poly_t, r));
|
||||
return csg2_tri_diff_poly(tmp, t, cp_csg2_cast(cp_csg2_poly_t, r));
|
||||
case CP_CSG2_STACK:
|
||||
return csg2_tri_diff_stack(pool, t, cp_csg2_cast(cp_csg2_stack_t, r), zi);
|
||||
return csg2_tri_diff_stack(tmp, t, cp_csg2_cast(cp_csg2_stack_t, r), zi);
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static bool csg2_tri_diff_v_csg2(
|
||||
cp_pool_t *pool,
|
||||
cp_pool_t *tmp,
|
||||
cp_err_t *t,
|
||||
cp_v_obj_p_t *r,
|
||||
size_t zi)
|
||||
{
|
||||
for (cp_v_each(i, r)) {
|
||||
if (!csg2_tri_diff_csg2(pool, t, cp_csg2_cast(cp_csg2_t, cp_v_nth(r,i)), zi)) {
|
||||
if (!csg2_tri_diff_csg2(tmp, t, cp_csg2_cast(cp_csg2_t, cp_v_nth(r,i)), zi)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -1332,7 +1332,7 @@ static bool csg2_tri_diff_v_csg2(
|
|||
* Additionally, the improper start case has a special case if vertices
|
||||
* coincide.
|
||||
*
|
||||
* Uses \p pool for all temporary allocations (but not for constructing
|
||||
* Uses \p tmp for all temporary allocations (but not for constructing
|
||||
* point_arr or tri).
|
||||
*
|
||||
* Runtime: O(n log n)
|
||||
|
|
@ -1340,7 +1340,7 @@ static bool csg2_tri_diff_v_csg2(
|
|||
* Where n = number of points.
|
||||
*/
|
||||
extern bool cp_csg2_tri_set(
|
||||
cp_pool_t *pool,
|
||||
cp_pool_t *tmp,
|
||||
cp_err_t *t,
|
||||
cp_vec2_arr_ref_t *point_arr,
|
||||
cp_v_size3_t *tri,
|
||||
|
|
@ -1363,7 +1363,7 @@ extern bool cp_csg2_tri_set(
|
|||
|
||||
/* allocate list cells */
|
||||
size_t list_size = node->size * 2;
|
||||
list_t *list_data = CP_POOL_NEW_ARR(pool, *list_data, list_size);
|
||||
list_t *list_data = CP_POOL_NEW_ARR(tmp, *list_data, list_size);
|
||||
assert(cp_mem_is0(list_data, sizeof(*list_data) * list_size));
|
||||
|
||||
/* init context */
|
||||
|
|
@ -1421,14 +1421,14 @@ extern bool cp_csg2_tri_set(
|
|||
* This uses cp_csg2_tri_set() internally, so the path is contrained
|
||||
* in the way described for that function.
|
||||
*
|
||||
* Uses \p pool for all temporary allocations (but not for constructing g).
|
||||
* Uses \p tmp for all temporary allocations (but not for constructing g).
|
||||
*
|
||||
* Runtime: O(n log n)
|
||||
* Space: O(n)
|
||||
* Where n = number of points.
|
||||
*/
|
||||
extern bool cp_csg2_tri_path(
|
||||
cp_pool_t *pool,
|
||||
cp_pool_t *tmp,
|
||||
cp_err_t *t,
|
||||
cp_csg2_poly_t *g,
|
||||
cp_csg2_path_t *s)
|
||||
|
|
@ -1436,8 +1436,8 @@ extern bool cp_csg2_tri_path(
|
|||
size_t n = s->point_idx.size;
|
||||
|
||||
/* allocate */
|
||||
node_t *node = CP_POOL_NEW_ARR(pool, *node, n);
|
||||
edge_t *edge = CP_POOL_NEW_ARR(pool, *edge, n);
|
||||
node_t *node = CP_POOL_NEW_ARR(tmp, *node, n);
|
||||
edge_t *edge = CP_POOL_NEW_ARR(tmp, *edge, n);
|
||||
|
||||
/* Init nodes and edges and insert into X structure 'px'
|
||||
* To do multiple paths in one go, this would need to be
|
||||
|
|
@ -1455,7 +1455,9 @@ extern bool cp_csg2_tri_path(
|
|||
|
||||
cp_a_csg2_3node_t a = CP_A_INIT_WITH(node, n);
|
||||
|
||||
return cp_csg2_tri_set(pool, t, &CP_VEC2_ARR_REF(&g->point, coord), &g->triangle, &a);
|
||||
cp_vec2_arr_ref_t a2;
|
||||
cp_vec2_arr_ref_from_v_vec2_loc(&a2, &g->point);
|
||||
return cp_csg2_tri_set(tmp, t, &a2, &g->triangle, &a);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1467,14 +1469,14 @@ extern bool cp_csg2_tri_path(
|
|||
* the paths in one data structure, so the set of paths of the given
|
||||
* polygon is contrained in the way described for that function.
|
||||
*
|
||||
* Uses \p pool for all temporary allocations (but not for constructing r).
|
||||
* Uses \p tmp for all temporary allocations (but not for constructing r).
|
||||
*
|
||||
* Runtime: O(n log n)
|
||||
* Space: O(n)
|
||||
* Where n = number of points.
|
||||
*/
|
||||
extern bool cp_csg2_tri_poly(
|
||||
cp_pool_t *pool,
|
||||
cp_pool_t *tmp,
|
||||
cp_err_t *t,
|
||||
cp_csg2_poly_t *g)
|
||||
{
|
||||
|
|
@ -1489,8 +1491,8 @@ extern bool cp_csg2_tri_poly(
|
|||
}
|
||||
|
||||
/* allocate */
|
||||
node_t *node = CP_POOL_NEW_ARR(pool, *node, n);
|
||||
edge_t *edge = CP_POOL_NEW_ARR(pool, *edge, n);
|
||||
node_t *node = CP_POOL_NEW_ARR(tmp, *node, n);
|
||||
edge_t *edge = CP_POOL_NEW_ARR(tmp, *edge, n);
|
||||
|
||||
/* make edges */
|
||||
size_t m = g->path.size;
|
||||
|
|
@ -1523,13 +1525,57 @@ extern bool cp_csg2_tri_poly(
|
|||
cp_a_csg2_3node_t a = CP_A_INIT_WITH(node, n);
|
||||
|
||||
/* run the triangulation algorithm */
|
||||
if (!cp_csg2_tri_set(pool, t, &CP_VEC2_ARR_REF(&g->point, coord), &g->triangle, &a)) {
|
||||
cp_vec2_arr_ref_t a2;
|
||||
cp_vec2_arr_ref_from_v_vec2_loc(&a2, &g->point);
|
||||
if (!cp_csg2_tri_set(tmp, t, &a2, &g->triangle, &a)) {
|
||||
return false;
|
||||
}
|
||||
assert(g->triangle.size <= tri_cnt);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as cp_csg2_tri_poly, but triangulates a reference array of vec2.
|
||||
*/
|
||||
extern bool cp_csg2_tri_vec2_arr_ref(
|
||||
cp_v_size3_t *tri,
|
||||
cp_pool_t *tmp,
|
||||
cp_err_t *t,
|
||||
cp_vec2_arr_ref_t *a2)
|
||||
{
|
||||
/* count edges */
|
||||
size_t n = a2->count;
|
||||
if (n < 2) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* allocate */
|
||||
node_t *node = CP_POOL_NEW_ARR(tmp, *node, n);
|
||||
edge_t *edge = CP_POOL_NEW_ARR(tmp, *edge, n);
|
||||
|
||||
/* make edges */
|
||||
for (cp_size_each(j, n)) {
|
||||
node_t *p = &node[j];
|
||||
p->loc = cp_vec2_arr_loc(a2, j);
|
||||
p->coord = cp_vec2_arr_ref(a2, j);
|
||||
p->out = &edge[j];
|
||||
p->in = &edge[cp_wrap_sub1(j,n)];
|
||||
}
|
||||
|
||||
/* Expect n triangles (that's about in the middle of the worst case, and
|
||||
* slightly larger than what's expected). */
|
||||
cp_v_clear(tri, n);
|
||||
|
||||
cp_a_csg2_3node_t a = CP_A_INIT_WITH(node, n);
|
||||
|
||||
/* run the triangulation algorithm */
|
||||
if (!cp_csg2_tri_set(tmp, t, a2, tri, &a)) {
|
||||
return false;
|
||||
}
|
||||
assert(tri->size <= n);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Triangulate a given layer
|
||||
*
|
||||
|
|
@ -1544,7 +1590,7 @@ extern bool cp_csg2_tri_poly(
|
|||
* tree, so the set of paths of each polygon in the tree is contrained
|
||||
* in the way described for that function.
|
||||
*
|
||||
* Uses \p pool for all temporary allocations (but not for constructing r).
|
||||
* Uses \p tmp for all temporary allocations (but not for constructing r).
|
||||
*
|
||||
* Runtime: O(m * n log n)
|
||||
* Space: O(max(n))
|
||||
|
|
@ -1554,7 +1600,7 @@ extern bool cp_csg2_tri_poly(
|
|||
* max(n) = the maximum n among the polygons.
|
||||
*/
|
||||
extern bool cp_csg2_tri_layer(
|
||||
cp_pool_t *pool,
|
||||
cp_pool_t *tmp,
|
||||
cp_err_t *t,
|
||||
cp_csg2_tree_t *r,
|
||||
size_t zi)
|
||||
|
|
@ -1562,7 +1608,7 @@ extern bool cp_csg2_tri_layer(
|
|||
if (r->root == NULL) {
|
||||
return true;
|
||||
}
|
||||
return csg2_tri_csg2(pool, t, r->root, zi);
|
||||
return csg2_tri_csg2(tmp, t, r->root, zi);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1574,7 +1620,7 @@ extern bool cp_csg2_tri_layer(
|
|||
* Runtime and space: see cp_csg2_tri_layer.
|
||||
*/
|
||||
extern bool cp_csg2_tri_layer_diff(
|
||||
cp_pool_t *pool,
|
||||
cp_pool_t *tmp,
|
||||
cp_err_t *t,
|
||||
cp_csg2_tree_t *r,
|
||||
size_t zi)
|
||||
|
|
@ -1582,5 +1628,5 @@ extern bool cp_csg2_tri_layer_diff(
|
|||
if (r->root == NULL) {
|
||||
return true;
|
||||
}
|
||||
return csg2_tri_diff_csg2(pool, t, r->root, zi);
|
||||
return csg2_tri_diff_csg2(tmp, t, r->root, zi);
|
||||
}
|
||||
|
|
|
|||
270
src/csg3.c
270
src/csg3.c
|
|
@ -22,12 +22,13 @@
|
|||
#define TRI_RIGHT 2
|
||||
|
||||
typedef struct {
|
||||
cp_pool_t *tmp;
|
||||
cp_mat3wi_t const *mat;
|
||||
cp_gc_t gc;
|
||||
} mat_ctxt_t;
|
||||
|
||||
typedef struct {
|
||||
cp_pool_t *pool;
|
||||
cp_pool_t *tmp;
|
||||
cp_csg3_tree_t *tree;
|
||||
cp_csg_opt_t const *opt;
|
||||
cp_err_t *err;
|
||||
|
|
@ -693,6 +694,99 @@ static size_t get_fn(
|
|||
return fn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that all paths of the polygon run clockwise.
|
||||
*
|
||||
* If a path needs to be reversed, do it.
|
||||
*
|
||||
* Return whether any path needed reversal.
|
||||
*/
|
||||
static bool polygon_make_clockwise(
|
||||
cp_csg2_poly_t *p)
|
||||
{
|
||||
bool rev = false;
|
||||
for (cp_v_each(i, &p->path)) {
|
||||
cp_csg2_path_t *q = &cp_v_nth(&p->path, i);
|
||||
double sum = 0;
|
||||
for (cp_v_each(j0, &q->point_idx)) {
|
||||
size_t j1 = cp_wrap_add1(j0, q->point_idx.size);
|
||||
size_t j2 = cp_wrap_add1(j1, q->point_idx.size);
|
||||
sum += cp_vec2_right_cross3_z(
|
||||
&cp_v_nth(&p->point, cp_v_nth(&q->point_idx, j0)).coord,
|
||||
&cp_v_nth(&p->point, cp_v_nth(&q->point_idx, j1)).coord,
|
||||
&cp_v_nth(&p->point, cp_v_nth(&q->point_idx, j2)).coord);
|
||||
}
|
||||
assert(!cp_eq(sum, 0));
|
||||
if (sum < 0) {
|
||||
rev = true;
|
||||
cp_v_reverse(&q->point_idx, 0, -(size_t)1);
|
||||
}
|
||||
}
|
||||
return rev;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/**
|
||||
* Whether a sequence of 3 points is convex.
|
||||
*
|
||||
* Returns a bitmask:
|
||||
* bit 0: XY is concave
|
||||
* bit 1: XY is collinear
|
||||
* bit 2: XY is convex
|
||||
* bit 3: YZ is concave
|
||||
* bit 4: YZ is collinear
|
||||
* bit 5: YZ is convex
|
||||
*/
|
||||
static int vec3_face_normal3_z(
|
||||
cp_vec3_t const *a,
|
||||
cp_vec3_t const *o,
|
||||
cp_vec3_t const *b)
|
||||
{
|
||||
return
|
||||
(1 << (1 + cp_vec2_right_normal3_z(&a->b, &o->b, &b->b))) |
|
||||
(1 << (4 + cp_vec2_right_normal3_z(&a->be, &o->be, &b->be)));
|
||||
}
|
||||
#endif
|
||||
|
||||
static void face_from_tri_or_poly(
|
||||
size_t *k,
|
||||
cp_csg3_poly_t *o,
|
||||
cp_v_size3_t *tri,
|
||||
cp_loc_t loc,
|
||||
size_t fn,
|
||||
bool rev,
|
||||
bool top)
|
||||
{
|
||||
size_t j_offset = top ? o->point.size - fn : 0;
|
||||
|
||||
cp_csg3_face_t *f;
|
||||
if (tri->size > 0) {
|
||||
/* from triangulation */
|
||||
for (cp_v_each(i, tri)) {
|
||||
f = &cp_v_nth(&o->face, (*k)++);
|
||||
cp_v_init0(&f->point, 3);
|
||||
for (cp_size_each(j, 3)) {
|
||||
cp_vec3_loc_ref_t *v = &cp_v_nth(&f->point, j);
|
||||
v->ref = &cp_v_nth(&o->point, cp_v_nth(tri, i).p[j] + j_offset);
|
||||
v->loc = loc;
|
||||
}
|
||||
face_basics(f, rev ^ top, loc);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* from convex path */
|
||||
f = &cp_v_nth(&o->face, (*k)++);
|
||||
cp_v_init0(&f->point, fn);
|
||||
for (cp_size_each(j, fn)) {
|
||||
cp_vec3_loc_ref_t *v = &cp_v_nth(&f->point, j);
|
||||
v->ref = &cp_v_nth(&o->point, j + j_offset);
|
||||
v->loc = loc;
|
||||
}
|
||||
face_basics(f, rev ^ top, loc);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* From an array of points in the rough shape of a tower,
|
||||
* make a polyhedron. 'Tower' means the shape consists
|
||||
|
|
@ -719,15 +813,62 @@ static size_t get_fn(
|
|||
*
|
||||
* This also runs xform and minmax, but not make_edges.
|
||||
*/
|
||||
static void faces_from_tower(
|
||||
static bool faces_n_edges_from_tower(
|
||||
cp_csg3_poly_t *o,
|
||||
ctxt_t *c,
|
||||
cp_mat3wi_t const *m,
|
||||
cp_loc_t loc,
|
||||
size_t fn,
|
||||
size_t fnz,
|
||||
bool rev,
|
||||
unsigned tri_side)
|
||||
unsigned tri_side,
|
||||
bool may_need_tri)
|
||||
{
|
||||
/* FIXME:
|
||||
* To cope with non-convex bottom and top:
|
||||
*
|
||||
* * Check here whether top/bottom will be non-convex.
|
||||
*
|
||||
* * Assume the face will be broken into triangles, so face
|
||||
* count is known.
|
||||
*
|
||||
* * Instead of '1', use computed face count in init0.
|
||||
*
|
||||
* * Instead of normal face construction, use a callback
|
||||
* based call into csg2-triangle module. That module
|
||||
* needs to be changed so that 'add_triangle' can be
|
||||
* a callback.
|
||||
*/
|
||||
unsigned orient = 0;
|
||||
bool need_tri = false;
|
||||
if (may_need_tri) {
|
||||
for (cp_size_each(i, fn)) {
|
||||
size_t j = cp_wrap_add1(i, fn);
|
||||
size_t k = cp_wrap_add1(j, fn);
|
||||
orient |= 1U << (1 + cp_vec2_right_normal3_z(
|
||||
&cp_v_nth(&o->point, i).coord.b,
|
||||
&cp_v_nth(&o->point, j).coord.b,
|
||||
&cp_v_nth(&o->point, k).coord.b));
|
||||
if ((orient & 5) == 5) { /* both directions in path */
|
||||
need_tri = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* check whether rev was passed correctly */
|
||||
cp_v_size3_t tri = {0};
|
||||
if (need_tri) {
|
||||
cp_vec2_arr_ref_t a2;
|
||||
cp_vec2_arr_ref_from_a_vec3_loc(&a2, &o->point, false);
|
||||
assert(a2.count >= fn);
|
||||
a2.count = fn;
|
||||
|
||||
if (!cp_csg2_tri_vec2_arr_ref(&tri, c->tmp, c->err, &a2)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* reverse based on determinant */
|
||||
if (m->d < 0) {
|
||||
rev = !rev;
|
||||
|
|
@ -743,36 +884,24 @@ static void faces_from_tower(
|
|||
|
||||
/* generate faces */
|
||||
size_t k = 0;
|
||||
size_t bt_cnt = tri.size ? tri.size : 1U; /* faces in bottom (and top) */
|
||||
cp_v_init0(&o->face,
|
||||
1U + /* bottom */
|
||||
!!has_top + /* top */
|
||||
(bt_cnt * (
|
||||
1U + /* bottom */
|
||||
!!has_top)) + /* top */
|
||||
((fnz - 2) * fn * (1U + !!tri_side)) + /* rings */
|
||||
(fn * (1U + !!(tri_side && has_top)))); /* roof */
|
||||
|
||||
|
||||
/* bottom */
|
||||
cp_csg3_face_t *f = &cp_v_nth(&o->face, k++);
|
||||
cp_v_init0(&f->point, fn);
|
||||
for (cp_size_each(j, fn)) {
|
||||
cp_vec3_loc_ref_t *v = &cp_v_nth(&f->point, j);
|
||||
v->ref = &cp_v_nth(&o->point, j);
|
||||
v->loc = loc;
|
||||
}
|
||||
face_basics(f, rev, loc);
|
||||
face_from_tri_or_poly(&k, o, &tri, loc, fn, rev, false);
|
||||
|
||||
/* top */
|
||||
if (has_top) {
|
||||
/* top */
|
||||
f = &cp_v_nth(&o->face, k++);
|
||||
cp_v_init0(&f->point, fn);
|
||||
for (cp_size_each(j, fn)) {
|
||||
cp_vec3_loc_ref_t *v = &cp_v_nth(&f->point, j);
|
||||
v->ref = &cp_v_nth(&o->point, o->point.size - j - 1);
|
||||
v->loc = loc;
|
||||
}
|
||||
face_basics(f, rev, loc);
|
||||
face_from_tri_or_poly(&k, o, &tri, loc, fn, rev, true);
|
||||
}
|
||||
|
||||
/* sides */
|
||||
cp_csg3_face_t *f;
|
||||
for (cp_size_each(i, fnz, 1, !has_top)) {
|
||||
size_t k1 = i * fn;
|
||||
size_t k0 = k1 - fn;
|
||||
|
|
@ -817,6 +946,7 @@ static void faces_from_tower(
|
|||
}
|
||||
|
||||
assert(o->face.size == k);
|
||||
return poly_make_edges(o, c);
|
||||
}
|
||||
|
||||
static void set_vec3_loc(
|
||||
|
|
@ -830,8 +960,9 @@ static void set_vec3_loc(
|
|||
p->loc = loc;
|
||||
}
|
||||
|
||||
static void csg3_poly_make_sphere(
|
||||
static bool csg3_poly_make_sphere(
|
||||
cp_csg3_poly_t *o,
|
||||
ctxt_t *c,
|
||||
cp_mat3wi_t const *m,
|
||||
cp_scad_sphere_t const *s,
|
||||
size_t fn)
|
||||
|
|
@ -856,8 +987,8 @@ static void csg3_poly_make_sphere(
|
|||
p += fn;
|
||||
}
|
||||
|
||||
/* make faces */
|
||||
faces_from_tower(o, m, s->loc, fn, fnz, true, TRI_NONE);
|
||||
/* make faces and edges */
|
||||
return faces_n_edges_from_tower(o, c, m, s->loc, fn, fnz, true, TRI_NONE, false);
|
||||
}
|
||||
|
||||
static bool csg3_from_sphere(
|
||||
|
|
@ -887,11 +1018,11 @@ static bool csg3_from_sphere(
|
|||
|
||||
size_t fn = get_fn(c->opt, s->_fn, true);
|
||||
if (fn > 0) {
|
||||
/* all faces are convex */
|
||||
cp_csg3_poly_t *o = cp_csg3_new_obj(*o, s->loc, mo->gc);
|
||||
cp_v_push(r, cp_obj(o));
|
||||
|
||||
csg3_poly_make_sphere(o, m, s, fn);
|
||||
if (!poly_make_edges(o, c)) {
|
||||
if (!csg3_poly_make_sphere(o, c, m, s, fn)) {
|
||||
return msg(c, CP_ERR_FAIL, NULL, NULL,
|
||||
" Internal Error: 'sphere' polyhedron construction algorithm is broken.\n");
|
||||
}
|
||||
|
|
@ -949,6 +1080,7 @@ static bool csg3_from_polyhedron(
|
|||
s->faces.size);
|
||||
}
|
||||
|
||||
/* FIXME: possibly concave faces */
|
||||
cp_csg3_poly_t *o = cp_csg3_new_obj(*o, s->loc, m->gc);
|
||||
cp_v_push(r, cp_obj(o));
|
||||
|
||||
|
|
@ -1010,37 +1142,6 @@ static void xform_2d(
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that all paths of the polygon run clockwise.
|
||||
*
|
||||
* If a path needs to be reversed, do it.
|
||||
*
|
||||
* Return whether any path needed reversal.
|
||||
*/
|
||||
static bool polygon_clockwise(
|
||||
cp_csg2_poly_t *p)
|
||||
{
|
||||
bool rev = false;
|
||||
for (cp_v_each(i, &p->path)) {
|
||||
cp_csg2_path_t *q = &cp_v_nth(&p->path, i);
|
||||
double sum = 0;
|
||||
for (cp_v_each(j0, &q->point_idx)) {
|
||||
size_t j1 = cp_wrap_add1(j0, q->point_idx.size);
|
||||
size_t j2 = cp_wrap_add1(j1, q->point_idx.size);
|
||||
sum += cp_vec2_right_cross3_z(
|
||||
&cp_v_nth(&p->point, cp_v_nth(&q->point_idx, j0)).coord,
|
||||
&cp_v_nth(&p->point, cp_v_nth(&q->point_idx, j1)).coord,
|
||||
&cp_v_nth(&p->point, cp_v_nth(&q->point_idx, j2)).coord);
|
||||
}
|
||||
assert(!cp_eq(sum, 0));
|
||||
if (sum < 0) {
|
||||
rev = true;
|
||||
cp_v_reverse(&q->point_idx, 0, -(size_t)1);
|
||||
}
|
||||
}
|
||||
return rev;
|
||||
}
|
||||
|
||||
static bool csg3_from_polygon(
|
||||
bool *no,
|
||||
cp_v_obj_p_t *r,
|
||||
|
|
@ -1098,7 +1199,7 @@ static bool csg3_from_polygon(
|
|||
}
|
||||
|
||||
/* normalise to paths to be clockwise */
|
||||
(void)polygon_clockwise(o);
|
||||
(void)polygon_make_clockwise(o);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1144,6 +1245,7 @@ static bool csg3_from_cube(
|
|||
}
|
||||
|
||||
/* make points */
|
||||
/* all faces are convex */
|
||||
cp_csg3_poly_t *o = cp_csg3_new_obj(*o, s->loc, mo->gc);
|
||||
cp_v_push(r, cp_obj(o));
|
||||
|
||||
|
|
@ -1160,11 +1262,8 @@ static bool csg3_from_cube(
|
|||
set_vec3_loc(&cp_v_nth(&o->point, i), !(i&1)^!(i&2), !(i&2), !(i&4), s->loc);
|
||||
}
|
||||
|
||||
/* make faces */
|
||||
faces_from_tower(o, m, s->loc, 4, 2, false, TRI_NONE);
|
||||
|
||||
/* make edges */
|
||||
if (!poly_make_edges(o, c)) {
|
||||
/* make faces & edges */
|
||||
if (!faces_n_edges_from_tower(o, c, m, s->loc, 4, 2, false, TRI_NONE, false)) {
|
||||
return msg(c, CP_ERR_FAIL, NULL, NULL,
|
||||
" Internal Error: 'cube' polyhedron construction algorithm is broken.\n");
|
||||
}
|
||||
|
|
@ -1228,7 +1327,7 @@ static bool csg3_from_circle(
|
|||
mn.mat = m;
|
||||
xform_2d(&mn, o);
|
||||
|
||||
bool rev __unused = polygon_clockwise(o);
|
||||
bool rev __unused = polygon_make_clockwise(o);
|
||||
assert(!rev);
|
||||
|
||||
return true;
|
||||
|
|
@ -1277,9 +1376,11 @@ static bool csg3_from_square(
|
|||
cp_csg2_poly_t *o = cp_csg2_new(*o, s->loc);
|
||||
cp_v_push(r, cp_obj(o));
|
||||
|
||||
cp_csg2_path_t *path = cp_v_push0(&o->path);
|
||||
cp_v_init0(&o->path, 1);
|
||||
cp_csg2_path_t *path = &cp_v_nth(&o->path, 0);
|
||||
cp_v_init0(&o->point, 4);
|
||||
for (cp_size_each(i, 4)) {
|
||||
cp_vec2_loc_t *p = cp_v_push0(&o->point);
|
||||
cp_vec2_loc_t *p = &cp_v_nth(&o->point, i);
|
||||
p->coord.x = cp_dim(!!(i & 1));
|
||||
p->coord.y = cp_dim(!!(i & 2));
|
||||
p->loc = s->loc;
|
||||
|
|
@ -1296,7 +1397,7 @@ static bool csg3_from_square(
|
|||
cp_v_push(&path->point_idx, 3);
|
||||
cp_v_push(&path->point_idx, 1);
|
||||
|
||||
bool rev __unused = polygon_clockwise(o);
|
||||
bool rev __unused = polygon_make_clockwise(o);
|
||||
assert(!rev);
|
||||
|
||||
return true;
|
||||
|
|
@ -1311,6 +1412,7 @@ static bool csg3_poly_cylinder(
|
|||
cp_scale_t r2,
|
||||
size_t fn)
|
||||
{
|
||||
/* all faces are convex */
|
||||
cp_csg3_poly_t *o = cp_csg3_new_obj(*o, s->loc, mo->gc);
|
||||
cp_v_push(r, cp_obj(o));
|
||||
|
||||
|
|
@ -1332,11 +1434,8 @@ static bool csg3_poly_cylinder(
|
|||
}
|
||||
}
|
||||
|
||||
/* make faces */
|
||||
faces_from_tower(o, m, s->loc, fn, 2, false, TRI_NONE);
|
||||
|
||||
/* make edges */
|
||||
if (!poly_make_edges(o, c)) {
|
||||
/* make faces & edges */
|
||||
if (!faces_n_edges_from_tower(o, c, m, s->loc, fn, 2, false, TRI_NONE, false)) {
|
||||
return msg(c, CP_ERR_FAIL, NULL, NULL,
|
||||
" Internal Error: 'cylinder' polyhedron construction algorithm is broken.\n");
|
||||
}
|
||||
|
|
@ -1489,8 +1588,8 @@ static bool csg3_from_linext(
|
|||
}
|
||||
|
||||
/* get polygon */
|
||||
cp_csg2_poly_t *p = cp_csg2_flatten(c->opt, c->pool, &rc);
|
||||
cp_pool_clear(c->pool);
|
||||
cp_csg2_poly_t *p = cp_csg2_flatten(c->opt, c->tmp, &rc);
|
||||
cp_pool_clear(c->tmp);
|
||||
|
||||
/* empty? */
|
||||
if ((p == NULL) || (p->path.size == 0)) {
|
||||
|
|
@ -1513,7 +1612,7 @@ static bool csg3_from_linext(
|
|||
tri = TRI_LEFT;
|
||||
}
|
||||
|
||||
|
||||
/* Use 3D XOR to handle 2D XOR semantics of polygon paths */
|
||||
cp_v_csg_add_p_t *xo = NULL;
|
||||
if (p->path.size >= 2) {
|
||||
cp_csg_xor_t *xor = cp_csg_new(*xor, s->loc);
|
||||
|
|
@ -1521,17 +1620,13 @@ static bool csg3_from_linext(
|
|||
xo = &xor->xor;
|
||||
}
|
||||
|
||||
/* FIXME:
|
||||
* Some paths are negative and cannot simply be generated as a separate
|
||||
* linext, but must be considered as a single one.
|
||||
* Identify which ones are negative (or use XOR on linear extrusions).
|
||||
*/
|
||||
for (cp_v_each(i, &p->path)) {
|
||||
cp_csg2_path_t const *q = &cp_v_nth(&p->path, i);
|
||||
|
||||
size_t pcnt = q->point_idx.size;
|
||||
size_t tcnt = (zcnt * pcnt) + is_cone;
|
||||
|
||||
/* possibly concave faces: handled by faces_n_edge_from_tower. */
|
||||
cp_csg3_poly_t *o = cp_csg3_new_obj(*o, s->loc, mo->gc);
|
||||
if (xo != NULL) {
|
||||
cp_csg_add_t *o2 = cp_csg_new(*o2, s->loc);
|
||||
|
|
@ -1567,17 +1662,12 @@ static bool csg3_from_linext(
|
|||
w->loc = s->loc;
|
||||
}
|
||||
|
||||
faces_from_tower(o, m, s->loc, pcnt, s->slices + 1, true, tri);
|
||||
|
||||
if (!poly_make_edges(o, c)) {
|
||||
if (!faces_n_edges_from_tower(o, c, m, s->loc, pcnt, s->slices + 1, true, tri, true)) {
|
||||
return msg(c, CP_ERR_FAIL, NULL, NULL,
|
||||
" Internal Error: 'linear_extrude' polyhedron construction algorithm is broken.\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* FIXME: continue */
|
||||
(void)r;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -1901,7 +1991,7 @@ extern void cp_csg3_tree_bb(
|
|||
* Convert a SCAD AST into a CSG3 tree.
|
||||
*/
|
||||
extern bool cp_csg3_from_scad_tree(
|
||||
cp_pool_t *pool,
|
||||
cp_pool_t *tmp,
|
||||
cp_csg3_tree_t *r,
|
||||
cp_err_t *t,
|
||||
cp_scad_tree_t const *scad)
|
||||
|
|
@ -1911,7 +2001,7 @@ extern bool cp_csg3_from_scad_tree(
|
|||
assert(t != NULL);
|
||||
assert(r->opt != NULL);
|
||||
ctxt_t c = {
|
||||
.pool = pool,
|
||||
.tmp = tmp,
|
||||
.tree = r,
|
||||
.opt = r->opt,
|
||||
.err = t,
|
||||
|
|
|
|||
9
test.mk
9
test.mk
|
|
@ -163,9 +163,12 @@ TEST_STL.scad := \
|
|||
scad-test/test13.scad \
|
||||
scad-test/test14.scad \
|
||||
scad-test/test31d.scad \
|
||||
scad-test/test30a.scad
|
||||
scad-test/test30a.scad \
|
||||
scad-test/test13b.scad
|
||||
|
||||
FAIL_STL.scad := \
|
||||
scad-test/chain1.scad \
|
||||
scad-test/linext5.scad \
|
||||
scad-test/test13b.scad
|
||||
|
||||
FAIL_JS.scad := \
|
||||
scad-test/chain1.scad \
|
||||
scad-test/linext5.scad
|
||||
|
|
|
|||
Loading…
Reference in a new issue