mirror of
https://github.com/BelfrySCAD/BOSL2.git
synced 2024-12-29 00:09:41 +00:00
Enabled various shapes to not barf on zero or negative sizes.
This commit is contained in:
parent
ee4e098e47
commit
d37917c671
4 changed files with 103 additions and 74 deletions
|
@ -3248,7 +3248,11 @@ function _find_anchor(anchor, geom) =
|
|||
let(
|
||||
size=geom[1], size2=geom[2],
|
||||
shift=point2d(geom[3]), axis=point3d(geom[4]),
|
||||
override = geom[5](anchor),
|
||||
override = geom[5](anchor)
|
||||
)
|
||||
let(
|
||||
size = [for (c = size) max(0,c)],
|
||||
size2 = [for (c = size2) max(0,c)],
|
||||
anch = rot(from=axis, to=UP, p=anchor),
|
||||
offset = rot(from=axis, to=UP, p=offset),
|
||||
h = size.z,
|
||||
|
@ -3259,8 +3263,8 @@ function _find_anchor(anchor, geom) =
|
|||
pos = point3d(cp) + lerp(bot,top,u) + offset,
|
||||
vecs = anchor==CENTER? [UP]
|
||||
: [
|
||||
if (anch.x!=0) unit(rot(from=UP, to=[(top-bot).x,0,h], p=[axy.x,0,0]), UP),
|
||||
if (anch.y!=0) unit(rot(from=UP, to=[0,(top-bot).y,h], p=[0,axy.y,0]), UP),
|
||||
if (anch.x!=0) unit(rot(from=UP, to=[(top-bot).x,0,max(0.01,h)], p=[axy.x,0,0]), UP),
|
||||
if (anch.y!=0) unit(rot(from=UP, to=[0,(top-bot).y,max(0.01,h)], p=[0,axy.y,0]), UP),
|
||||
if (anch.z!=0) unit([0,0,anch.z],UP)
|
||||
],
|
||||
vec2 = anchor==CENTER? UP
|
||||
|
@ -3385,10 +3389,12 @@ function _find_anchor(anchor, geom) =
|
|||
size=geom[1], size2=geom[2], shift=geom[3],
|
||||
u = (anchor.y+1)/2, // 0<=u<=1
|
||||
frpt = [size.x/2*anchor.x, -size.y/2],
|
||||
bkpt = [size2/2*anchor.x+shift, size.y/2],
|
||||
bkpt = [size2/2*anchor.x+shift, size.y/2],
|
||||
override = geom[4](anchor),
|
||||
pos = default(override[0],point2d(cp) + lerp(frpt, bkpt, u) + point2d(offset)),
|
||||
svec = point3d(line_normal(bkpt,frpt)*anchor.x),
|
||||
pos = override[0] != undef? override[0] :
|
||||
point2d(cp) + lerp(frpt, bkpt, u) + point2d(offset),
|
||||
svec = approx(bkpt,frpt)? [anchor.x,0,0] :
|
||||
point3d(line_normal(bkpt,frpt)*anchor.x),
|
||||
vec = is_def(override[1]) ? override[1]
|
||||
: anchor.y == 0? ( anchor.x == 0? BACK : svec )
|
||||
: anchor.x == 0? [0,anchor.y,0]
|
||||
|
@ -3398,13 +3404,16 @@ function _find_anchor(anchor, geom) =
|
|||
let(
|
||||
anchor = unit(_force_anchor_2d(anchor),[0,0]),
|
||||
r = force_list(geom[1],2),
|
||||
pos = approx(anchor.x,0) ? [0,sign(anchor.y)*r.y]
|
||||
: let(
|
||||
m = anchor.y/anchor.x,
|
||||
px = sign(anchor.x) * sqrt(1/(1/sqr(r.x) + m*m/sqr(r.y)))
|
||||
)
|
||||
[px,m*px],
|
||||
vec = unit([r.y/r.x*pos.x, r.x/r.y*pos.y],BACK)
|
||||
pos = approx(anchor.x,0)
|
||||
? [0,sign(anchor.y)*r.y]
|
||||
: let(
|
||||
m = anchor.y/anchor.x,
|
||||
px = approx(min(r),0)? 0 :
|
||||
sign(anchor.x) * sqrt(1/(1/sqr(r.x) + m*m/sqr(r.y)))
|
||||
)
|
||||
[px,m*px],
|
||||
vec = approx(min(r),0)? (approx(norm(anchor),0)? BACK : anchor) :
|
||||
unit([r.y/r.x*pos.x, r.x/r.y*pos.y],BACK)
|
||||
) [anchor, point2d(cp+offset)+pos, vec, 0]
|
||||
) : type == "rgn_isect"? ( //region
|
||||
let(
|
||||
|
|
|
@ -151,16 +151,16 @@ function move_copies(a=[[0,0,0]],p=_NO_ARG) =
|
|||
// See Also: move_copies(), ycopies(), zcopies(), line_copies(), grid_copies(), rot_copies(), xrot_copies(), yrot_copies(), zrot_copies(), arc_copies(), sphere_copies()
|
||||
//
|
||||
// Usage:
|
||||
// xcopies(spacing, [n], [sp]) CHILDREN;
|
||||
// xcopies(l, [n], [sp]) CHILDREN;
|
||||
// xcopies(spacing, [n], [sp=]) CHILDREN;
|
||||
// xcopies(l=, [n=], [sp=]) CHILDREN;
|
||||
// xcopies(LIST) CHILDREN;
|
||||
// Usage: As a function to translate points, VNF, or Bezier patches
|
||||
// copies = xcopies(spacing, [n], [sp], p=);
|
||||
// copies = xcopies(l, [n], [sp], p=);
|
||||
// copies = xcopies(spacing, [n], [sp=], p=);
|
||||
// copies = xcopies(l=, [n=], [sp=], p=);
|
||||
// copies = xcopies(LIST, p=);
|
||||
// Usage: Get Translation Matrices
|
||||
// mats = xcopies(spacing, [n], [sp]);
|
||||
// mats = xcopies(l, [n], [sp]);
|
||||
// mats = xcopies(spacing, [n], [sp=]);
|
||||
// mats = xcopies(l=, [n=], [sp=]);
|
||||
// mats = xcopies(LIST);
|
||||
// Description:
|
||||
// When called as a module, places `n` copies of the children along a line on the X axis.
|
||||
|
@ -168,10 +168,10 @@ function move_copies(a=[[0,0,0]],p=_NO_ARG) =
|
|||
// When called as a function, *with* a `p=` argument, returns a list of transformed copies of `p=`.
|
||||
//
|
||||
// Arguments:
|
||||
// ---
|
||||
// spacing = Given a scalar, specifies a uniform spacing between copies. Given a list of scalars, each one gives a specific position along the line. (Default: 1.0)
|
||||
// n = Number of copies to place. (Default: 2)
|
||||
// l = Length to place copies over.
|
||||
// ---
|
||||
// l = If given, the length to place copies over.
|
||||
// sp = If given as a point, copies will be placed on a line to the right of starting position `sp`. If given as a scalar, copies will be placed on a line segment to the right of starting position `[sp,0,0]`. If not given, copies will be placed along a line segment that is centered at [0,0,0].
|
||||
// p = Either a point, pointlist, VNF or Bezier patch to be translated when used as a function.
|
||||
//
|
||||
|
@ -179,7 +179,6 @@ function move_copies(a=[[0,0,0]],p=_NO_ARG) =
|
|||
// `$pos` is set to the relative centerpoint of each child copy, and can be used to modify each child individually.
|
||||
// `$idx` is set to the index number of each child being copied.
|
||||
//
|
||||
//
|
||||
// Examples:
|
||||
// xcopies(20) sphere(3);
|
||||
// xcopies(20, n=3) sphere(3);
|
||||
|
@ -237,16 +236,16 @@ function xcopies(spacing, n, l, sp, p=_NO_ARG) =
|
|||
// See Also: move_copies(), xcopies(), zcopies(), line_copies(), grid_copies(), rot_copies(), xrot_copies(), yrot_copies(), zrot_copies(), arc_copies(), sphere_copies()
|
||||
//
|
||||
// Usage:
|
||||
// ycopies(spacing, [n], [sp]) CHILDREN;
|
||||
// ycopies(l, [n], [sp]) CHILDREN;
|
||||
// ycopies(spacing, [n], [sp=]) CHILDREN;
|
||||
// ycopies(l=, [n=], [sp=]) CHILDREN;
|
||||
// ycopies(LIST) CHILDREN;
|
||||
// Usage: As a function to translate points, VNF, or Bezier patches
|
||||
// copies = ycopies(spacing, [n], [sp], p=);
|
||||
// copies = ycopies(l, [n], [sp], p=);
|
||||
// copies = ycopies(spacing, [n], [sp=], p=);
|
||||
// copies = ycopies(l=, [n=], [sp=], p=);
|
||||
// copies = ycopies(LIST, p=);
|
||||
// Usage: Get Translation Matrices
|
||||
// mats = ycopies(spacing, [n], [sp]);
|
||||
// mats = ycopies(l, [n], [sp]);
|
||||
// mats = ycopies(spacing, [n], [sp=]);
|
||||
// mats = ycopies(l=, [n=], [sp=]);
|
||||
// mats = ycopies(LIST);
|
||||
// Description:
|
||||
// When called as a module, places `n` copies of the children along a line on the Y axis.
|
||||
|
@ -254,10 +253,10 @@ function xcopies(spacing, n, l, sp, p=_NO_ARG) =
|
|||
// When called as a function, *with* a `p=` argument, returns a list of transformed copies of `p=`.
|
||||
//
|
||||
// Arguments:
|
||||
// ---
|
||||
// spacing = Given a scalar, specifies a uniform spacing between copies. Given a list of scalars, each one gives a specific position along the line. (Default: 1.0)
|
||||
// n = Number of copies to place on the line. (Default: 2)
|
||||
// l = Length to place copies over.
|
||||
// ---
|
||||
// l = If given, the length to place copies over.
|
||||
// sp = If given as a point, copies will be place on a line back from starting position `sp`. If given as a scalar, copies will be placed on a line back from starting position `[0,sp,0]`. If not given, copies will be placed along a line that is centered at [0,0,0].
|
||||
// p = Either a point, pointlist, VNF or Bezier patch to be translated when used as a function.
|
||||
//
|
||||
|
@ -265,7 +264,6 @@ function xcopies(spacing, n, l, sp, p=_NO_ARG) =
|
|||
// `$pos` is set to the relative centerpoint of each child copy, and can be used to modify each child individually.
|
||||
// `$idx` is set to the index number of each child being copied.
|
||||
//
|
||||
//
|
||||
// Examples:
|
||||
// ycopies(20) sphere(3);
|
||||
// ycopies(20, n=3) sphere(3);
|
||||
|
@ -323,16 +321,16 @@ function ycopies(spacing, n, l, sp, p=_NO_ARG) =
|
|||
// See Also: move_copies(), xcopies(), ycopies(), line_copies(), grid_copies(), rot_copies(), xrot_copies(), yrot_copies(), zrot_copies(), arc_copies(), sphere_copies()
|
||||
//
|
||||
// Usage:
|
||||
// zcopies(spacing, [n], [sp]) CHILDREN;
|
||||
// zcopies(l, [n], [sp]) CHILDREN;
|
||||
// zcopies(spacing, [n], [sp=]) CHILDREN;
|
||||
// zcopies(l=, [n=], [sp=]) CHILDREN;
|
||||
// zcopies(LIST) CHILDREN;
|
||||
// Usage: As a function to translate points, VNF, or Bezier patches
|
||||
// copies = zcopies(spacing, [n], [sp], p=);
|
||||
// copies = zcopies(l, [n], [sp], p=);
|
||||
// copies = zcopies(spacing, [n], [sp=], p=);
|
||||
// copies = zcopies(l=, [n=], [sp=], p=);
|
||||
// copies = zcopies(LIST, p=);
|
||||
// Usage: Get Translation Matrices
|
||||
// mats = zcopies(spacing, [n], [sp]);
|
||||
// mats = zcopies(l, [n], [sp]);
|
||||
// mats = zcopies(spacing, [n], [sp=]);
|
||||
// mats = zcopies(l=, [n=], [sp=]);
|
||||
// mats = zcopies(LIST);
|
||||
// Description:
|
||||
// When called as a module, places `n` copies of the children along a line on the Z axis.
|
||||
|
@ -340,10 +338,10 @@ function ycopies(spacing, n, l, sp, p=_NO_ARG) =
|
|||
// When called as a function, *with* a `p=` argument, returns a list of transformed copies of `p=`.
|
||||
//
|
||||
// Arguments:
|
||||
// ---
|
||||
// spacing = Given a scalar, specifies a uniform spacing between copies. Given a list of scalars, each one gives a specific position along the line. (Default: 1.0)
|
||||
// n = Number of copies to place. (Default: 2)
|
||||
// l = Length to place copies over.
|
||||
// ---
|
||||
// l = If given, the length to place copies over.
|
||||
// sp = If given as a point, copies will be placed on a line up from starting position `sp`. If given as a scalar, copies will be placed on a line up from starting position `[0,0,sp]`. If not given, copies will be placed on a line that is centered at [0,0,0].
|
||||
// p = Either a point, pointlist, VNF or Bezier patch to be translated when used as a function.
|
||||
//
|
||||
|
@ -351,7 +349,6 @@ function ycopies(spacing, n, l, sp, p=_NO_ARG) =
|
|||
// `$pos` is set to the relative centerpoint of each child copy, and can be used to modify each child individually.
|
||||
// `$idx` is set to the index number of each child being copied.
|
||||
//
|
||||
//
|
||||
// Examples:
|
||||
// zcopies(20) sphere(3);
|
||||
// zcopies(20, n=3) sphere(3);
|
||||
|
@ -478,7 +475,6 @@ function zcopies(spacing, n, l, sp, p=_NO_ARG) =
|
|||
// `$pos` is set to the relative centerpoint of each child copy, and can be used to modify each child individually.
|
||||
// `$idx` is set to the index number of each child being copied.
|
||||
//
|
||||
//
|
||||
// Examples:
|
||||
// line_copies(10) sphere(d=1.5);
|
||||
// line_copies(10, n=5) sphere(d=3);
|
||||
|
@ -592,7 +588,6 @@ function line_copies(spacing, n, l, p1, p2, p=_NO_ARG) =
|
|||
// `$col` is set to the integer column number for each child.
|
||||
// `$row` is set to the integer row number for each child.
|
||||
//
|
||||
//
|
||||
// Examples:
|
||||
// grid_copies(size=50, spacing=10) cylinder(d=10, h=1);
|
||||
// grid_copies(size=50, spacing=[10,15]) cylinder(d=10, h=1);
|
||||
|
@ -851,7 +846,7 @@ function grid_copies(spacing, n, size, stagger=false, inside=undef, nonzero, p=_
|
|||
// rot_copies(n=6, v=DOWN+BACK, delta=[20,0,0], subrot=false)
|
||||
// yrot(90) cylinder(h=20, r1=5, r2=0);
|
||||
// color("red",0.333) yrot(90) cylinder(h=20, r1=5, r2=0);
|
||||
module rot_copies(rots=[], v=undef, cp=[0,0,0], n, sa=0, offset=0, delta=[0,0,0], subrot=true)
|
||||
module rot_copies(rots=[], v, cp=[0,0,0], n, sa=0, offset=0, delta=[0,0,0], subrot=true)
|
||||
{
|
||||
req_children($children);
|
||||
sang = sa + offset;
|
||||
|
|
|
@ -51,21 +51,26 @@ use <builtins.scad>
|
|||
function square(size=1, center, anchor, spin=0) =
|
||||
let(
|
||||
anchor = get_anchor(anchor, center, [-1,-1], [-1,-1]),
|
||||
size = is_num(size)? [size,size] : point2d(size),
|
||||
size = is_num(size)? [size,size] : point2d(size)
|
||||
)
|
||||
assert(all_positive(size), "All components of size must be positive.")
|
||||
let(
|
||||
path = [
|
||||
[ size.x,-size.y],
|
||||
[-size.x,-size.y],
|
||||
[-size.x, size.y],
|
||||
[ size.x, size.y]
|
||||
[ size.x, size.y],
|
||||
] / 2
|
||||
) reorient(anchor,spin, two_d=true, size=size, p=path);
|
||||
|
||||
|
||||
module square(size=1, center, anchor, spin) {
|
||||
anchor = get_anchor(anchor, center, [-1,-1], [-1,-1]);
|
||||
size = is_num(size)? [size,size] : point2d(size);
|
||||
rsize = is_num(size)? [size,size] : point2d(size);
|
||||
size = [for (c = rsize) max(0,c)];
|
||||
attachable(anchor,spin, two_d=true, size=size) {
|
||||
_square(size, center=true);
|
||||
if (all_positive(size))
|
||||
_square(size, center=true);
|
||||
children();
|
||||
}
|
||||
}
|
||||
|
@ -127,8 +132,13 @@ module square(size=1, center, anchor, spin) {
|
|||
// move_copies(path) color("blue") circle(d=2,$fn=8);
|
||||
module rect(size=1, rounding=0, atype="box", chamfer=0, anchor=CENTER, spin=0) {
|
||||
errchk = assert(in_list(atype, ["box", "perim"]));
|
||||
size = force_list(size,2);
|
||||
if (rounding==0 && chamfer==0) {
|
||||
size = [for (c = force_list(size,2)) max(0,c)];
|
||||
if (!all_positive(size)) {
|
||||
attachable(anchor,spin, two_d=true, size=size) {
|
||||
union();
|
||||
children();
|
||||
}
|
||||
} else if (rounding==0 && chamfer==0) {
|
||||
attachable(anchor, spin, two_d=true, size=size) {
|
||||
square(size, center=true);
|
||||
children();
|
||||
|
@ -138,8 +148,8 @@ module rect(size=1, rounding=0, atype="box", chamfer=0, anchor=CENTER, spin=0) {
|
|||
pts = pts_over[0];
|
||||
override = pts_over[1];
|
||||
attachable(anchor, spin, two_d=true, size=size,override=override) {
|
||||
polygon(pts);
|
||||
children();
|
||||
polygon(pts);
|
||||
children();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -153,18 +163,19 @@ function rect(size=1, rounding=0, chamfer=0, atype="box", anchor=CENTER, spin=0,
|
|||
assert(in_list(atype, ["box", "perim"]))
|
||||
let(
|
||||
anchor=_force_anchor_2d(anchor),
|
||||
size = force_list(size,2),
|
||||
size = [for (c = force_list(size,2)) max(0,c)],
|
||||
chamfer = force_list(chamfer,4),
|
||||
rounding = force_list(rounding,4)
|
||||
)
|
||||
assert(all_positive(size), "All components of size must be positive")
|
||||
all_zero(concat(chamfer,rounding),0) ?
|
||||
let(
|
||||
path = [
|
||||
[ size.x/2, -size.y/2],
|
||||
[-size.x/2, -size.y/2],
|
||||
[-size.x/2, size.y/2],
|
||||
[ size.x/2, size.y/2]
|
||||
]
|
||||
[ size.x/2, -size.y/2],
|
||||
[-size.x/2, -size.y/2],
|
||||
[-size.x/2, size.y/2],
|
||||
[ size.x/2, size.y/2],
|
||||
]
|
||||
)
|
||||
rot(spin, p=move(-v_mul(anchor,size/2), p=path))
|
||||
:
|
||||
|
@ -278,6 +289,9 @@ function circle(r, d, points, corner, anchor=CENTER, spin=0) =
|
|||
) [cp, r],
|
||||
cp = data[0],
|
||||
r = data[1],
|
||||
)
|
||||
assert(r>0, "Radius/diameter must be positive")
|
||||
let(
|
||||
sides = segs(r),
|
||||
path = [for (i=[0:1:sides-1]) let(a=360-i*360/sides) r*[cos(a),sin(a)]+cp]
|
||||
) reorient(anchor,spin, two_d=true, r=r, p=path);
|
||||
|
@ -290,7 +304,7 @@ module circle(r, d, points, corner, anchor=CENTER, spin=0) {
|
|||
r = c[1];
|
||||
translate(cp) {
|
||||
attachable(anchor,spin, two_d=true, r=r) {
|
||||
_circle(r=r);
|
||||
if (r>0) _circle(r=r);
|
||||
children();
|
||||
}
|
||||
}
|
||||
|
@ -301,14 +315,14 @@ module circle(r, d, points, corner, anchor=CENTER, spin=0) {
|
|||
cp = c[0];
|
||||
translate(cp) {
|
||||
attachable(anchor,spin, two_d=true, r=r) {
|
||||
_circle(r=r);
|
||||
if (r>0) _circle(r=r);
|
||||
children();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
r = get_radius(r=r, d=d, dflt=1);
|
||||
attachable(anchor,spin, two_d=true, r=r) {
|
||||
_circle(r=r);
|
||||
if (r>0) _circle(r=r);
|
||||
children();
|
||||
}
|
||||
}
|
||||
|
@ -485,18 +499,26 @@ function ellipse(r, d, realign=false, circum=false, uniform=false, anchor=CENTER
|
|||
r = force_list(get_radius(r=r, d=d, dflt=1),2),
|
||||
sides = segs(max(r))
|
||||
)
|
||||
uniform ? assert(!circum, "Circum option not allowed when \"uniform\" is true")
|
||||
reorient(anchor,spin,two_d=true,r=[r.x,r.y],
|
||||
p=realign ? reverse(_ellipse_refine_realign(r.x,r.y,sides))
|
||||
: reverse_polygon(_ellipse_refine(r.x,r.y,sides)))
|
||||
:
|
||||
let(
|
||||
offset = realign? 180/sides : 0,
|
||||
sc = circum? (1 / cos(180/sides)) : 1,
|
||||
rx = r.x * sc,
|
||||
ry = r.y * sc,
|
||||
pts = [for (i=[0:1:sides-1]) let(a=360-offset-i*360/sides) [rx*cos(a), ry*sin(a)]]
|
||||
) reorient(anchor,spin, two_d=true, r=[rx,ry], p=pts);
|
||||
assert(all_positive(r), "All components of the radius must be positive.")
|
||||
uniform
|
||||
? assert(!circum, "Circum option not allowed when \"uniform\" is true")
|
||||
reorient(anchor,spin,
|
||||
two_d=true, r=[r.x,r.y],
|
||||
p=realign
|
||||
? reverse(_ellipse_refine_realign(r.x,r.y,sides))
|
||||
: reverse_polygon(_ellipse_refine(r.x,r.y,sides))
|
||||
)
|
||||
: let(
|
||||
offset = realign? 180/sides : 0,
|
||||
sc = circum? (1 / cos(180/sides)) : 1,
|
||||
rx = r.x * sc,
|
||||
ry = r.y * sc,
|
||||
pts = [
|
||||
for (i=[0:1:sides-1])
|
||||
let (a = 360-offset-i*360/sides)
|
||||
[rx*cos(a), ry*sin(a)]
|
||||
]
|
||||
) reorient(anchor,spin, two_d=true, r=[rx,ry], p=pts);
|
||||
|
||||
|
||||
// Section: Polygons
|
||||
|
|
|
@ -67,7 +67,10 @@ module cube(size=1, center, anchor, spin=0, orient=UP)
|
|||
|
||||
function cube(size=1, center, anchor, spin=0, orient=UP) =
|
||||
let(
|
||||
siz = scalar_vec3(size),
|
||||
siz = scalar_vec3(size)
|
||||
)
|
||||
assert(all_positive(siz), "All size components must be positive.")
|
||||
let(
|
||||
anchor = get_anchor(anchor, center, -[1,1,1], -[1,1,1]),
|
||||
unscaled = [
|
||||
[-1,-1,-1],[1,-1,-1],[1,1,-1],[-1,1,-1],
|
||||
|
@ -332,7 +335,7 @@ module cuboid(
|
|||
rounding = approx(rounding,0) ? undef : rounding;
|
||||
checks =
|
||||
assert(is_vector(size,3))
|
||||
assert(all_positive(size))
|
||||
assert(all_nonnegative(size), "All components of size= must be >=0")
|
||||
assert(is_undef(chamfer) || is_finite(chamfer),"chamfer must be a finite value")
|
||||
assert(is_undef(rounding) || is_finite(rounding),"rounding must be a finite value")
|
||||
assert(is_undef(rounding) || is_undef(chamfer), "Cannot specify nonzero value for both chamfer and rounding")
|
||||
|
|
Loading…
Reference in a new issue