mirror of
https://github.com/BelfrySCAD/BOSL2.git
synced 2024-12-29 16:29:40 +00:00
Reworked attachable() internals, and provided geometry only function equivalent called reorient().
This commit is contained in:
parent
863398eb24
commit
6ec5013835
5 changed files with 434 additions and 190 deletions
417
attachments.scad
417
attachments.scad
|
@ -89,7 +89,6 @@ $tags_hidden = [];
|
||||||
|
|
||||||
// Section: Functions
|
// Section: Functions
|
||||||
|
|
||||||
|
|
||||||
// Function: anchorpt()
|
// Function: anchorpt()
|
||||||
// Usage:
|
// Usage:
|
||||||
// anchor(name, pos, [dir], [rot])
|
// anchor(name, pos, [dir], [rot])
|
||||||
|
@ -103,6 +102,142 @@ $tags_hidden = [];
|
||||||
function anchorpt(name, pos=[0,0,0], orient=UP, spin=0) = [name, pos, orient, spin];
|
function anchorpt(name, pos=[0,0,0], orient=UP, spin=0) = [name, pos, orient, spin];
|
||||||
|
|
||||||
|
|
||||||
|
// Function: attach_geom()
|
||||||
|
//
|
||||||
|
// Usage:
|
||||||
|
// geom = attach_geom(anchor, spin, [orient], two_d, size, [size2], [shift], [offset], [anchors]);
|
||||||
|
// geom = attach_geom(anchor, spin, [orient], two_d, r|d, [offset], [anchors]);
|
||||||
|
// geom = attach_geom(anchor, spin, [orient], two_d, path, [extent], [offset], [anchors]);
|
||||||
|
// geom = attach_geom(anchor, spin, [orient], size, [size2], [shift], [offset], [anchors]);
|
||||||
|
// geom = attach_geom(anchor, spin, [orient], r|d, l, [offset], [anchors]);
|
||||||
|
// geom = attach_geom(anchor, spin, [orient], r1|d1, r2|d2, l, [offset], [anchors]);
|
||||||
|
// geom = attach_geom(anchor, spin, [orient], r|d, [offset], [anchors]);
|
||||||
|
// geom = attach_geom(anchor, spin, [orient], vnf, [extent], [offset], [anchors]);
|
||||||
|
//
|
||||||
|
// Description:
|
||||||
|
// Given arguments that describe the geometry of an attachable object, returns the internal geometry description.
|
||||||
|
//
|
||||||
|
// Arguments:
|
||||||
|
// size = If given as a 3D vector, contains the XY size of the bottom of the cuboidal/prismoidal volume, and the Z height. If given as a 2D vector, contains the front X width of the rectangular/trapezoidal shape, and the Y length.
|
||||||
|
// size2 = If given as a 2D vector, contains the XY size of the top of the prismoidal volume. If given as a number, contains the back width of the trapezoidal shape.
|
||||||
|
// shift = If given as a 2D vector, shifts the top of the prismoidal or conical shape by the given amount. If given as a number, shifts the back of the trapezoidal shape right by that amount. Default: No shift.
|
||||||
|
// r = Radius of the cylindrical/conical volume.
|
||||||
|
// d = Diameter of the cylindrical/conical volume.
|
||||||
|
// r1 = Radius of the bottom of the conical volume.
|
||||||
|
// r2 = Radius of the top of the conical volume.
|
||||||
|
// d1 = Diameter of the bottom of the conical volume.
|
||||||
|
// d2 = Diameter of the top of the conical volume.
|
||||||
|
// l = Length of the cylindrical/conical volume along axis.
|
||||||
|
// vnf = The [VNF](vnf.scad) of the volume.
|
||||||
|
// path = The path to generate a polygon from.
|
||||||
|
// extent = If true, calculate anchors by extents, rather than intersection. Default: false.
|
||||||
|
// offset = If given, offsets the center of the volume.
|
||||||
|
// anchors = If given as a list of anchor points, allows named anchor points.
|
||||||
|
// two_d = If true, the attachable shape is 2D. If false, 3D. Default: false (3D)
|
||||||
|
//
|
||||||
|
// Example(NORENDER): Cubical Shape
|
||||||
|
// geom = attach_geom(anchor, spin, orient, size=size);
|
||||||
|
//
|
||||||
|
// Example(NORENDER): Prismoidal Shape
|
||||||
|
// geom = attach_geom(
|
||||||
|
// anchor, spin, orient,
|
||||||
|
// size=point3d(botsize,h),
|
||||||
|
// size2=topsize, shift=shift
|
||||||
|
// );
|
||||||
|
//
|
||||||
|
// Example(NORENDER): Cylindrical Shape
|
||||||
|
// geom = attach_geom(anchor, spin, orient, r=r, h=h);
|
||||||
|
//
|
||||||
|
// Example(NORENDER): Conical Shape
|
||||||
|
// geom = attach_geom(anchor, spin, orient, r1=r1, r2=r2, h=h);
|
||||||
|
//
|
||||||
|
// Example(NORENDER): Spherical Shape
|
||||||
|
// geom = attach_geom(anchor, spin, orient, r=r);
|
||||||
|
//
|
||||||
|
// Example(NORENDER): Arbitrary VNF Shape
|
||||||
|
// geom = attach_geom(anchor, spin, orient, vnf=vnf);
|
||||||
|
//
|
||||||
|
// Example(NORENDER): 2D Rectangular Shape
|
||||||
|
// geom = attach_geom(anchor, spin, orient, size=size);
|
||||||
|
//
|
||||||
|
// Example(NORENDER): 2D Trapezoidal Shape
|
||||||
|
// geom = attach_geom(
|
||||||
|
// anchor, spin, orient,
|
||||||
|
// size=[x1,y], size2=x2, shift=shift
|
||||||
|
// );
|
||||||
|
//
|
||||||
|
// Example(NORENDER): 2D Circular Shape
|
||||||
|
// geom = attach_geom(anchor, spin, orient, two_d=true, r=r);
|
||||||
|
//
|
||||||
|
// Example(NORENDER): Arbitrary 2D Polygon Shape
|
||||||
|
// geom = attach_geom(anchor, spin, orient, path=path);
|
||||||
|
//
|
||||||
|
function attach_geom(
|
||||||
|
size, size2, shift,
|
||||||
|
r,r1,r2, d,d1,d2, l,h,
|
||||||
|
vnf, path,
|
||||||
|
extent=true,
|
||||||
|
offset=[0,0,0],
|
||||||
|
anchors=[],
|
||||||
|
two_d=false
|
||||||
|
) =
|
||||||
|
assert(is_vector(offset))
|
||||||
|
assert(is_list(anchors))
|
||||||
|
!is_undef(size)? (
|
||||||
|
two_d? (
|
||||||
|
let(
|
||||||
|
size2 = default(size2, size.x),
|
||||||
|
shift = default(shift, 0)
|
||||||
|
)
|
||||||
|
assert(is_vector(size) && len(size)==2)
|
||||||
|
assert(is_num(size2))
|
||||||
|
assert(is_num(shift))
|
||||||
|
["rect", point2d(size), size2, shift, offset, anchors]
|
||||||
|
) : (
|
||||||
|
let(
|
||||||
|
size2 = default(size2, point2d(size)),
|
||||||
|
shift = default(shift, [0,0])
|
||||||
|
)
|
||||||
|
assert(is_vector(size) && len(size)==3)
|
||||||
|
assert(is_vector(size2) && len(size2)==2)
|
||||||
|
assert(is_vector(shift) && len(shift)==2)
|
||||||
|
["cuboid", size, size2, shift, offset, anchors]
|
||||||
|
)
|
||||||
|
) : !is_undef(vnf)? (
|
||||||
|
assert(is_vnf(vnf))
|
||||||
|
assert(two_d == false)
|
||||||
|
extent? ["vnf_extent", vnf, offset, anchors] :
|
||||||
|
["vnf_isect", vnf, offset, anchors]
|
||||||
|
) : !is_undef(path)? (
|
||||||
|
assert(is_path(path))
|
||||||
|
assert(two_d == true)
|
||||||
|
extent? ["path_extent", path, offset, anchors] :
|
||||||
|
["path_isect", path, offset, anchors]
|
||||||
|
) :
|
||||||
|
let(
|
||||||
|
r1 = get_radius(r1=r1,d1=d1,r=r,d=d,dflt=undef)
|
||||||
|
)
|
||||||
|
!is_undef(r1)? (
|
||||||
|
assert(is_num(r1))
|
||||||
|
let( l = default(l, h) )
|
||||||
|
!is_undef(l)? (
|
||||||
|
let(
|
||||||
|
shift = default(shift, [0,0]),
|
||||||
|
r2 = get_radius(r1=r2,d1=d2,r=r,d=d,dflt=undef)
|
||||||
|
)
|
||||||
|
assert(is_num(l))
|
||||||
|
assert(is_num(r2))
|
||||||
|
assert(is_vector(shift) && len(shift)==2)
|
||||||
|
["cyl", r1, r2, l, shift, offset, anchors]
|
||||||
|
) : (
|
||||||
|
two_d? ["circle", r1, offset, anchors] :
|
||||||
|
["spheroid", r1, offset, anchors]
|
||||||
|
)
|
||||||
|
) :
|
||||||
|
assert(false, "Unrecognizable geometry description.");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Function: attach_geom_2d()
|
// Function: attach_geom_2d()
|
||||||
// Usage:
|
// Usage:
|
||||||
// attach_geom_2d(geom);
|
// attach_geom_2d(geom);
|
||||||
|
@ -156,6 +291,65 @@ function attach_geom_size(geom) =
|
||||||
assert(false, "Unknown attachment geometry type.");
|
assert(false, "Unknown attachment geometry type.");
|
||||||
|
|
||||||
|
|
||||||
|
// Function: attach_transform()
|
||||||
|
// Usage:
|
||||||
|
// mat = attach_transform(anchor=CENTER, spin=0, orient=UP, geom);
|
||||||
|
// Description:
|
||||||
|
// Returns the affine3d transformation matrix needed to `anchor`, `spin`, and `orient`
|
||||||
|
// the given geometry `geom` shape into position.
|
||||||
|
// Arguments:
|
||||||
|
// anchor = Anchor point to translate to the origin `[0,0,0]`. See [anchor](attachments.scad#anchor). Default: `CENTER`
|
||||||
|
// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#spin). Default: `0`
|
||||||
|
// orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#orient). Default: `UP`
|
||||||
|
// geom = The geometry description of the shape.
|
||||||
|
// p = If given as a VNF, path, or point, applies the affine3d transformation matrix to it and returns the result.
|
||||||
|
function attach_transform(anchor=CENTER, spin=0, orient=UP, geom, p) =
|
||||||
|
assert(is_string(anchor) || is_vector(anchor))
|
||||||
|
assert(is_num(spin))
|
||||||
|
assert(is_vector(orient))
|
||||||
|
let(
|
||||||
|
two_d = attach_geom_2d(geom),
|
||||||
|
m = ($attach_to != undef)? (
|
||||||
|
let(
|
||||||
|
anch = find_anchor($attach_to, geom),
|
||||||
|
pos = anch[1]
|
||||||
|
) two_d? (
|
||||||
|
let(
|
||||||
|
ang = vector_angle(anch[2], BACK)
|
||||||
|
)
|
||||||
|
affine3d_zrot(ang+spin) *
|
||||||
|
affine3d_translate(point3d(-pos))
|
||||||
|
) : (
|
||||||
|
let(
|
||||||
|
ang = vector_angle(anch[2], DOWN),
|
||||||
|
axis = vector_axis(anch[2], DOWN),
|
||||||
|
ang2 = (anch[2]==UP || anch[2]==DOWN)? 0 : 180-anch[3],
|
||||||
|
axis2 = rotate_points3d([axis],[0,0,ang2])[0]
|
||||||
|
)
|
||||||
|
affine3d_rot_by_axis(axis2,ang) *
|
||||||
|
affine3d_zrot(ang2+spin) *
|
||||||
|
affine3d_translate(point3d(-pos))
|
||||||
|
)
|
||||||
|
) : (
|
||||||
|
let(
|
||||||
|
pos = find_anchor(anchor, geom)[1]
|
||||||
|
) two_d? (
|
||||||
|
affine3d_zrot(spin) *
|
||||||
|
affine3d_translate(point3d(-pos))
|
||||||
|
) : (
|
||||||
|
let(
|
||||||
|
axis = vector_axis(UP,orient),
|
||||||
|
ang = vector_angle(UP,orient)
|
||||||
|
)
|
||||||
|
affine3d_rot_by_axis(axis,ang) *
|
||||||
|
affine3d_zrot(spin) *
|
||||||
|
affine3d_translate(point3d(-pos))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
) is_undef(p)? m :
|
||||||
|
is_vnf(p)? [apply(m, p[0]), p[1]] :
|
||||||
|
apply(m, p);
|
||||||
|
|
||||||
|
|
||||||
// Function: find_anchor()
|
// Function: find_anchor()
|
||||||
// Usage:
|
// Usage:
|
||||||
|
@ -325,6 +519,18 @@ function find_anchor(anchor, geom) =
|
||||||
assert(false, "Unknown attachment geometry type.");
|
assert(false, "Unknown attachment geometry type.");
|
||||||
|
|
||||||
|
|
||||||
|
// Function: attachment_is_shown()
|
||||||
|
// Usage:
|
||||||
|
// attachment_is_shown(tags);
|
||||||
|
// Description:
|
||||||
|
// Returns true if the given space-delimited string of tag names should currently be shown.
|
||||||
|
function attachment_is_shown(tags) =
|
||||||
|
let(
|
||||||
|
tags = _str_char_split(tags, " "),
|
||||||
|
shown = !$tags_shown || any([for (tag=tags) in_list(tag, $tags_shown)]),
|
||||||
|
hidden = any([for (tag=tags) in_list(tag, $tags_hidden)])
|
||||||
|
) shown && !hidden;
|
||||||
|
|
||||||
|
|
||||||
function _str_char_split(s,delim,n=0,acc=[],word="") =
|
function _str_char_split(s,delim,n=0,acc=[],word="") =
|
||||||
(n>=len(s))? concat(acc, [word]) :
|
(n>=len(s))? concat(acc, [word]) :
|
||||||
|
@ -333,10 +539,88 @@ function _str_char_split(s,delim,n=0,acc=[],word="") =
|
||||||
_str_char_split(s,delim,n+1,acc,str(word,s[n]));
|
_str_char_split(s,delim,n+1,acc,str(word,s[n]));
|
||||||
|
|
||||||
|
|
||||||
|
// Function: reorient()
|
||||||
|
//
|
||||||
|
// Usage:
|
||||||
|
// reorient(anchor, spin, [orient], two_d, size, [size2], [shift], [offset], [anchors], [p]);
|
||||||
|
// reorient(anchor, spin, [orient], two_d, r|d, [offset], [anchors], [p]);
|
||||||
|
// reorient(anchor, spin, [orient], two_d, path, [extent], [offset], [anchors], [p]);
|
||||||
|
// reorient(anchor, spin, [orient], size, [size2], [shift], [offset], [anchors], [p]);
|
||||||
|
// reorient(anchor, spin, [orient], r|d, l, [offset], [anchors], [p]);
|
||||||
|
// reorient(anchor, spin, [orient], r1|d1, r2|d2, l, [offset], [anchors], [p]);
|
||||||
|
// reorient(anchor, spin, [orient], r|d, [offset], [anchors], [p]);
|
||||||
|
// reorient(anchor, spin, [orient], vnf, [extent], [offset], [anchors], [p]);
|
||||||
|
//
|
||||||
|
// Description:
|
||||||
|
// Given anchor, spin, orient, and general geometry info for a managed volume, this calculates
|
||||||
|
// the transformation matrix needed to be applied to the contents of that volume. A managed 3D
|
||||||
|
// volume is assumed to be vertically (Z-axis) oriented, and centered. A managed 2D area is just
|
||||||
|
// assumed to be centered.
|
||||||
|
//
|
||||||
|
// If `p` is not given, then the transformation matrix will be returned.
|
||||||
|
// If `p` contains a VNF, a new VNF will be returned with the vertices transformed by the matrix.
|
||||||
|
// If `p` contains a path, a new path will be returned with the vertices transformed by the matrix.
|
||||||
|
// If `p` contains a point, a new point will be returned, transformed by the matrix.
|
||||||
|
//
|
||||||
|
// If `$attach_to` is not defined, then the following transformations are performed in order:
|
||||||
|
// * Translates so the `anchor` point is at the origin (0,0,0).
|
||||||
|
// * Rotates around the Z axis by `spin` degrees counter-clockwise.
|
||||||
|
// * Rotates so the top of the part points towards the vector `orient`.
|
||||||
|
//
|
||||||
|
// If `$attach_to` is defined, as a consequence of `attach(from,to)`, then
|
||||||
|
// the following transformations are performed in order:
|
||||||
|
// * Translates this part so it's anchor position matches the parent's anchor position.
|
||||||
|
// * Rotates this part so it's anchor direction vector exactly opposes the parent's anchor direction vector.
|
||||||
|
// * Rotates this part so it's anchor spin matches the parent's anchor spin.
|
||||||
|
//
|
||||||
|
// Arguments:
|
||||||
|
// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#anchor). Default: `CENTER`
|
||||||
|
// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#spin). Default: `0`
|
||||||
|
// orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#orient). Default: `UP`
|
||||||
|
// size = If given as a 3D vector, contains the XY size of the bottom of the cuboidal/prismoidal volume, and the Z height. If given as a 2D vector, contains the front X width of the rectangular/trapezoidal shape, and the Y length.
|
||||||
|
// size2 = If given as a 2D vector, contains the XY size of the top of the prismoidal volume. If given as a number, contains the back width of the trapezoidal shape.
|
||||||
|
// shift = If given as a 2D vector, shifts the top of the prismoidal or conical shape by the given amount. If given as a number, shifts the back of the trapezoidal shape right by that amount. Default: No shift.
|
||||||
|
// r = Radius of the cylindrical/conical volume.
|
||||||
|
// d = Diameter of the cylindrical/conical volume.
|
||||||
|
// r1 = Radius of the bottom of the conical volume.
|
||||||
|
// r2 = Radius of the top of the conical volume.
|
||||||
|
// d1 = Diameter of the bottom of the conical volume.
|
||||||
|
// d2 = Diameter of the top of the conical volume.
|
||||||
|
// l = Length of the cylindrical/conical volume along axis.
|
||||||
|
// vnf = The [VNF](vnf.scad) of the volume.
|
||||||
|
// path = The path to generate a polygon from.
|
||||||
|
// extent = If true, calculate anchors by extents, rather than intersection. Default: false.
|
||||||
|
// offset = If given, offsets the center of the volume.
|
||||||
|
// anchors = If given as a list of anchor points, allows named anchor points.
|
||||||
|
// two_d = If true, the attachable shape is 2D. If false, 3D. Default: false (3D)
|
||||||
|
// p = The VNF, path, or point to transform.
|
||||||
|
function reorient(
|
||||||
|
anchor=CENTER,
|
||||||
|
spin=0,
|
||||||
|
orient=UP,
|
||||||
|
size, size2, shift,
|
||||||
|
r,r1,r2, d,d1,d2, l,h,
|
||||||
|
vnf, path,
|
||||||
|
extent=true,
|
||||||
|
offset=[0,0,0],
|
||||||
|
anchors=[],
|
||||||
|
two_d=false,
|
||||||
|
p=undef
|
||||||
|
) = let(
|
||||||
|
geom = attach_geom(
|
||||||
|
size=size, size2=size2, shift=shift,
|
||||||
|
r=r, r1=r1, r2=r2, h=h,
|
||||||
|
d=d, d1=d1, d2=d2, l=l,
|
||||||
|
vnf=vnf, path=path, extent=extent,
|
||||||
|
offset=offset, anchors=anchors,
|
||||||
|
two_d=two_d
|
||||||
|
)
|
||||||
|
) attach_transform(anchor,spin,orient,geom,p);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Section: Attachability Modules
|
// Section: Attachability Modules
|
||||||
|
|
||||||
|
|
||||||
// Module: attachable()
|
// Module: attachable()
|
||||||
//
|
//
|
||||||
// Usage:
|
// Usage:
|
||||||
|
@ -478,7 +762,7 @@ module attachable(
|
||||||
spin=0,
|
spin=0,
|
||||||
orient=UP,
|
orient=UP,
|
||||||
size, size2, shift,
|
size, size2, shift,
|
||||||
r,r1,r2, d,d1,d2, l,
|
r,r1,r2, d,d1,d2, l,h,
|
||||||
vnf, path,
|
vnf, path,
|
||||||
extent=true,
|
extent=true,
|
||||||
offset=[0,0,0],
|
offset=[0,0,0],
|
||||||
|
@ -486,110 +770,32 @@ module attachable(
|
||||||
two_d=false
|
two_d=false
|
||||||
) {
|
) {
|
||||||
assert($children==2);
|
assert($children==2);
|
||||||
assert(is_string(anchor) || is_vector(anchor));
|
geom = attach_geom(
|
||||||
assert(is_num(spin));
|
size=size, size2=size2, shift=shift,
|
||||||
assert(is_vector(orient));
|
r=r, r1=r1, r2=r2, h=h,
|
||||||
assert(is_vector(offset));
|
d=d, d1=d1, d2=d2, l=l,
|
||||||
assert(is_list(anchors));
|
vnf=vnf, path=path, extent=extent,
|
||||||
|
offset=offset, anchors=anchors,
|
||||||
|
two_d=two_d
|
||||||
|
);
|
||||||
|
m = attach_transform(anchor,spin,orient,geom);
|
||||||
|
multmatrix(m) {
|
||||||
|
if (attachment_is_shown($tags)) {
|
||||||
|
$parent_anchor = anchor;
|
||||||
|
$parent_spin = spin;
|
||||||
|
$parent_orient = orient;
|
||||||
|
$parent_geom = geom;
|
||||||
|
$parent_size = attach_geom_size(geom);
|
||||||
|
|
||||||
geom = !is_undef(size)? (
|
$attach_to = undef;
|
||||||
two_d? (
|
$tags_shown = undef;
|
||||||
let(
|
$tags_hidden = undef;
|
||||||
size2 = default(size2, size.x),
|
|
||||||
shift = default(shift, 0)
|
|
||||||
)
|
|
||||||
assert(is_vector(size) && len(size)==2)
|
|
||||||
assert(is_num(size2))
|
|
||||||
assert(is_num(shift))
|
|
||||||
["rect", point2d(size), size2, shift, offset, anchors]
|
|
||||||
) : (
|
|
||||||
let(
|
|
||||||
size2 = default(size2, point2d(size)),
|
|
||||||
shift = default(shift, [0,0])
|
|
||||||
)
|
|
||||||
assert(is_vector(size) && len(size)==3)
|
|
||||||
assert(is_vector(size2) && len(size2)==2)
|
|
||||||
assert(is_vector(shift) && len(shift)==2)
|
|
||||||
["cuboid", size, size2, shift, offset, anchors]
|
|
||||||
)
|
|
||||||
) : !is_undef(vnf)? (
|
|
||||||
assert(is_vnf(vnf))
|
|
||||||
assert(two_d == false)
|
|
||||||
extent? ["vnf_extent", vnf, offset, anchors] :
|
|
||||||
["vnf_isect", vnf, offset, anchors]
|
|
||||||
) : !is_undef(path)? (
|
|
||||||
assert(is_path(path))
|
|
||||||
assert(two_d == true)
|
|
||||||
extent? ["path_extent", path, offset, anchors] :
|
|
||||||
["path_isect", path, offset, anchors]
|
|
||||||
) :
|
|
||||||
let(
|
|
||||||
r1 = get_radius(r1=r1,d1=d1,r=r,d=d,dflt=undef)
|
|
||||||
)
|
|
||||||
!is_undef(r1)? (
|
|
||||||
assert(is_num(r1))
|
|
||||||
!is_undef(l)? (
|
|
||||||
let(
|
|
||||||
shift = default(shift, [0,0]),
|
|
||||||
r2 = get_radius(r1=r2,d1=d2,r=r,d=d,dflt=undef)
|
|
||||||
)
|
|
||||||
assert(is_num(l))
|
|
||||||
assert(is_num(r2))
|
|
||||||
assert(is_vector(shift) && len(shift)==2)
|
|
||||||
["cyl", r1, r2, l, shift, offset, anchors]
|
|
||||||
) : (
|
|
||||||
two_d? ["circle", r1, offset, anchors] :
|
|
||||||
["spheroid", r1, offset, anchors]
|
|
||||||
)
|
|
||||||
) :
|
|
||||||
assert(false, "attachable(): Unrecognizable geometry description.");
|
|
||||||
|
|
||||||
pos = find_anchor(anchor, geom)[1];
|
if (is_undef($color)) {
|
||||||
size = attach_geom_size(geom);
|
children(0);
|
||||||
|
} else color($color) {
|
||||||
$parent_anchor = anchor;
|
$color = undef;
|
||||||
$parent_spin = spin;
|
children(0);
|
||||||
$parent_orient = orient;
|
|
||||||
$parent_geom = geom;
|
|
||||||
$parent_size = size;
|
|
||||||
|
|
||||||
tags = _str_char_split($tags, " ");
|
|
||||||
s_tags = $tags_shown;
|
|
||||||
h_tags = $tags_hidden;
|
|
||||||
shown = !s_tags || any([for (tag=tags) in_list(tag, s_tags)]);
|
|
||||||
hidden = any([for (tag=tags) in_list(tag, h_tags)]);
|
|
||||||
if ($attach_to != undef) {
|
|
||||||
anch = find_anchor($attach_to, geom);
|
|
||||||
ang = vector_angle(anch[2], two_d? BACK : DOWN);
|
|
||||||
axis = two_d? UP : vector_axis(anch[2], DOWN);
|
|
||||||
ang2 = (anch[2]==UP || anch[2]==DOWN)? 0 : 180-anch[3];
|
|
||||||
axis2 = rotate_points3d([axis],[0,0,ang2])[0];
|
|
||||||
$attach_to = undef;
|
|
||||||
|
|
||||||
rot(ang, v=axis2)
|
|
||||||
rotate(ang2+spin)
|
|
||||||
translate(-anch[1]) {
|
|
||||||
if(shown && !hidden) {
|
|
||||||
if (is_undef($color)) {
|
|
||||||
children(0);
|
|
||||||
} else color($color) {
|
|
||||||
$color = undef;
|
|
||||||
children(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
children(1);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
rot(from=UP,to=orient)
|
|
||||||
rotate(spin)
|
|
||||||
translate(-pos) {
|
|
||||||
if(shown && !hidden) {
|
|
||||||
if (is_undef($color)) {
|
|
||||||
children(0);
|
|
||||||
} else color($color) {
|
|
||||||
$color = undef;
|
|
||||||
children(0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
children(1);
|
children(1);
|
||||||
}
|
}
|
||||||
|
@ -600,7 +806,6 @@ module attachable(
|
||||||
|
|
||||||
// Section: Attachment Positioning
|
// Section: Attachment Positioning
|
||||||
|
|
||||||
|
|
||||||
// Module: position()
|
// Module: position()
|
||||||
// Usage:
|
// Usage:
|
||||||
// position(from, [overlap]) ...
|
// position(from, [overlap]) ...
|
||||||
|
|
|
@ -241,6 +241,8 @@ module gear_tooth_profile(
|
||||||
// clearance = Gap between top of a tooth on one gear and bottom of valley on a meshing gear (in millimeters)
|
// clearance = Gap between top of a tooth on one gear and bottom of valley on a meshing gear (in millimeters)
|
||||||
// backlash = Gap between two meshing teeth, in the direction along the circumference of the pitch circle
|
// backlash = Gap between two meshing teeth, in the direction along the circumference of the pitch circle
|
||||||
// interior = If true, create a mask for difference()ing from something else.
|
// interior = If true, create a mask for difference()ing from something else.
|
||||||
|
// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#anchor). Default: `CENTER`
|
||||||
|
// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#spin). Default: `0`
|
||||||
// Example(2D): Typical Gear Shape
|
// Example(2D): Typical Gear Shape
|
||||||
// gear2d(pitch=5, teeth=20);
|
// gear2d(pitch=5, teeth=20);
|
||||||
// Example(2D): Lower Pressure Angle
|
// Example(2D): Lower Pressure Angle
|
||||||
|
@ -254,8 +256,11 @@ function gear2d(
|
||||||
PA = 28,
|
PA = 28,
|
||||||
clearance = undef,
|
clearance = undef,
|
||||||
backlash = 0.0,
|
backlash = 0.0,
|
||||||
interior = false
|
interior = false,
|
||||||
|
anchor = CENTER,
|
||||||
|
spin = 0
|
||||||
) = let(
|
) = let(
|
||||||
|
pr = pitch_radius(pitch=pitch, teeth=teeth),
|
||||||
pts = concat(
|
pts = concat(
|
||||||
[for (tooth = [0:1:teeth-hide-1])
|
[for (tooth = [0:1:teeth-hide-1])
|
||||||
each rot(tooth*360/teeth,
|
each rot(tooth*360/teeth,
|
||||||
|
@ -273,7 +278,7 @@ function gear2d(
|
||||||
],
|
],
|
||||||
hide>0? [[0,0]] : []
|
hide>0? [[0,0]] : []
|
||||||
)
|
)
|
||||||
) pts;
|
) attachable(anchor,spin, two_d=true, r=pr, p=pts);
|
||||||
|
|
||||||
|
|
||||||
module gear2d(
|
module gear2d(
|
||||||
|
@ -283,19 +288,23 @@ module gear2d(
|
||||||
PA = 28,
|
PA = 28,
|
||||||
clearance = undef,
|
clearance = undef,
|
||||||
backlash = 0.0,
|
backlash = 0.0,
|
||||||
interior = false
|
interior = false,
|
||||||
|
anchor = CENTER,
|
||||||
|
spin = 0
|
||||||
) {
|
) {
|
||||||
polygon(
|
path = gear2d(
|
||||||
gear2d(
|
pitch = pitch,
|
||||||
pitch = pitch,
|
teeth = teeth,
|
||||||
teeth = teeth,
|
hide = hide,
|
||||||
hide = hide,
|
PA = PA,
|
||||||
PA = PA,
|
clearance = clearance,
|
||||||
clearance = clearance,
|
backlash = backlash,
|
||||||
backlash = backlash,
|
interior = interior
|
||||||
interior = interior
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
attachable(anchor,spin, two_d=true, r=pr) {
|
||||||
|
polygon(path);
|
||||||
|
children();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -60,7 +60,8 @@ function square(size=1, center, rounding=0, chamfer=0, anchor, spin=0) =
|
||||||
assert(is_num(rounding) || len(rounding)==4)
|
assert(is_num(rounding) || len(rounding)==4)
|
||||||
let(
|
let(
|
||||||
size = is_num(size)? [size,size] : point2d(size),
|
size = is_num(size)? [size,size] : point2d(size),
|
||||||
anchor = get_anchor(anchor, center, FRONT+LEFT, FRONT+LEFT)
|
anchor = get_anchor(anchor, center, FRONT+LEFT, FRONT+LEFT),
|
||||||
|
complex = rounding!=0 || chamfer!=0
|
||||||
)
|
)
|
||||||
(rounding==0 && chamfer==0)? let(
|
(rounding==0 && chamfer==0)? let(
|
||||||
path = [
|
path = [
|
||||||
|
@ -97,7 +98,9 @@ function square(size=1, center, rounding=0, chamfer=0, anchor, spin=0) =
|
||||||
)
|
)
|
||||||
each [for (a = angs) cp + inset*[cos(a),sin(a)]]
|
each [for (a = angs) cp + inset*[cos(a),sin(a)]]
|
||||||
]
|
]
|
||||||
) rot(spin, p=move(-vmul(anchor,size/2), p=path));
|
) complex?
|
||||||
|
reorient(anchor,spin, two_d=true, path=path, p=path) :
|
||||||
|
reorient(anchor,spin, two_d=true, size=size, p=path);
|
||||||
|
|
||||||
|
|
||||||
// Function&Module: circle()
|
// Function&Module: circle()
|
||||||
|
@ -142,7 +145,7 @@ function circle(r, d, realign=false, circum=false, anchor=CENTER, spin=0) =
|
||||||
offset = realign? 180/sides : 0,
|
offset = realign? 180/sides : 0,
|
||||||
rr = r / (circum? cos(180/sides) : 1),
|
rr = r / (circum? cos(180/sides) : 1),
|
||||||
pts = [for (i=[0:1:sides-1]) let(a=360-offset-i*360/sides) rr*[cos(a),sin(a)]]
|
pts = [for (i=[0:1:sides-1]) let(a=360-offset-i*360/sides) rr*[cos(a),sin(a)]]
|
||||||
) rot(spin, p=move(-unit(anchor)*rr, p=pts));
|
) reorient(anchor,spin, two_d=true, r=rr, p=pts);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -235,7 +238,6 @@ module cylinder(h, r1, r2, center, l, r, d, d1, d2, anchor, spin=0, orient=UP)
|
||||||
l = first_defined([h, l, 1]);
|
l = first_defined([h, l, 1]);
|
||||||
hh = l/2;
|
hh = l/2;
|
||||||
sides = segs(max(r1,r2));
|
sides = segs(max(r1,r2));
|
||||||
size = [r1*2, r1*2, l];
|
|
||||||
path = [[0,hh],[r2,hh],[r1,-hh],[0,-hh]];
|
path = [[0,hh],[r2,hh],[r1,-hh],[0,-hh]];
|
||||||
attachable(anchor,spin,orient, r1=r1, r2=r2, l=l) {
|
attachable(anchor,spin,orient, r1=r1, r2=r2, l=l) {
|
||||||
rotate_extrude(convexity=2, $fn=sides) {
|
rotate_extrude(convexity=2, $fn=sides) {
|
||||||
|
@ -275,7 +277,6 @@ module sphere(r, d, anchor=CENTER, spin=0, orient=UP)
|
||||||
{
|
{
|
||||||
r = get_radius(r=r, d=d, dflt=1);
|
r = get_radius(r=r, d=d, dflt=1);
|
||||||
sides = segs(r);
|
sides = segs(r);
|
||||||
size = [r*2, r*2, r*2];
|
|
||||||
attachable(anchor,spin,orient, r=r) {
|
attachable(anchor,spin,orient, r=r) {
|
||||||
rotate_extrude(convexity=2) {
|
rotate_extrude(convexity=2) {
|
||||||
difference() {
|
difference() {
|
||||||
|
|
159
shapes2d.scad
159
shapes2d.scad
|
@ -562,13 +562,11 @@ function _turtle_command(command, parm, parm2, state, index) =
|
||||||
rot(delta_angle,p=state[step],planar=true)
|
rot(delta_angle,p=state[step],planar=true)
|
||||||
]
|
]
|
||||||
) :
|
) :
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
assert(false,str("Unknown turtle command \"",command,"\" at index",index))
|
assert(false,str("Unknown turtle command \"",command,"\" at index",index))
|
||||||
[];
|
[];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Section: 2D N-Gons
|
// Section: 2D N-Gons
|
||||||
|
|
||||||
// Function&Module: regular_ngon()
|
// Function&Module: regular_ngon()
|
||||||
|
@ -625,7 +623,7 @@ function regular_ngon(n=6, r, d, or, od, ir, id, side, rounding=0, realign=false
|
||||||
(r-rounding*sc)*[cos(a),sin(a)] +
|
(r-rounding*sc)*[cos(a),sin(a)] +
|
||||||
rounding*[cos(b),sin(b)]
|
rounding*[cos(b),sin(b)]
|
||||||
]
|
]
|
||||||
) rot(spin, p=move(-r*unit(anchor), p=path));
|
) reorient(anchor,spin, two_d=true, path=path, extent=false, p=path);
|
||||||
|
|
||||||
|
|
||||||
module regular_ngon(n=6, r, d, or, od, ir, id, side, rounding=0, realign=false, anchor=CENTER, spin=0) {
|
module regular_ngon(n=6, r, d, or, od, ir, id, side, rounding=0, realign=false, anchor=CENTER, spin=0) {
|
||||||
|
@ -643,8 +641,8 @@ module regular_ngon(n=6, r, d, or, od, ir, id, side, rounding=0, realign=false,
|
||||||
// Function&Module: pentagon()
|
// Function&Module: pentagon()
|
||||||
// Usage:
|
// Usage:
|
||||||
// pentagon(or|od, [realign]);
|
// pentagon(or|od, [realign]);
|
||||||
// pentagon(ir|id, [realign];
|
// pentagon(ir|id, [realign]);
|
||||||
// pentagon(side, [realign];
|
// pentagon(side, [realign]);
|
||||||
// Description:
|
// Description:
|
||||||
// When called as a function, returns a 2D path for a regular pentagon.
|
// When called as a function, returns a 2D path for a regular pentagon.
|
||||||
// When called as a module, creates a 2D regular pentagon.
|
// When called as a module, creates a 2D regular pentagon.
|
||||||
|
@ -786,14 +784,13 @@ module octagon(r, d, or, od, ir, id, side, rounding=0, realign=false, anchor=CEN
|
||||||
// stroke(closed=true, trapezoid(h=30, w1=40, w2=20));
|
// stroke(closed=true, trapezoid(h=30, w1=40, w2=20));
|
||||||
function trapezoid(h, w1, w2, anchor=CENTER, spin=0) =
|
function trapezoid(h, w1, w2, anchor=CENTER, spin=0) =
|
||||||
let(
|
let(
|
||||||
s = anchor.y>0? [w2,h] : anchor.y<0? [w1,h] : [(w1+w2)/2,h],
|
|
||||||
path = [[w1/2,-h/2], [-w1/2,-h/2], [-w2/2,h/2], [w2/2,h/2]]
|
path = [[w1/2,-h/2], [-w1/2,-h/2], [-w2/2,h/2], [w2/2,h/2]]
|
||||||
) rot(spin, p=move(-vmul(anchor,s/2), p=path));
|
) reorient(anchor,spin, two_d=true, size=[w1,h], size2=w2, p=path);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
module trapezoid(h, w1, w2, anchor=CENTER, spin=0) {
|
module trapezoid(h, w1, w2, anchor=CENTER, spin=0) {
|
||||||
path = trapezoid(h=h, w1=w1, w2=w2);
|
path = [[w1/2,-h/2], [-w1/2,-h/2], [-w2/2,h/2], [w2/2,h/2]];
|
||||||
attachable(anchor,spin, two_d=true, size=[w1,h], size2=w2) {
|
attachable(anchor,spin, two_d=true, size=[w1,h], size2=w2) {
|
||||||
polygon(path);
|
polygon(path);
|
||||||
children();
|
children();
|
||||||
|
@ -846,12 +843,14 @@ function teardrop2d(r, d, ang=45, cap_h, anchor=CENTER, spin=0) =
|
||||||
ea = 360 + ang,
|
ea = 360 + ang,
|
||||||
steps = segs(r)*(ea-sa)/360,
|
steps = segs(r)*(ea-sa)/360,
|
||||||
step = (ea-sa)/steps,
|
step = (ea-sa)/steps,
|
||||||
path = concat(
|
path = deduplicate(
|
||||||
[[ cap_w/2,cap_h]],
|
[
|
||||||
[for (i=[0:1:steps]) let(a=ea-i*step) r*[cos(a),sin(a)]],
|
[ cap_w/2,cap_h],
|
||||||
[[-cap_w/2,cap_h]]
|
for (i=[0:1:steps]) let(a=ea-i*step) r*[cos(a),sin(a)],
|
||||||
|
[-cap_w/2,cap_h]
|
||||||
|
], closed=true
|
||||||
)
|
)
|
||||||
) rot(spin, p=move(-vmul(anchor,[r,cap_h]), p=deduplicate(path,closed=true)));
|
) reorient(anchor,spin, two_d=true, path=path, p=path);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -891,14 +890,13 @@ function glued_circles(r, d, spread=10, tangent=30, anchor=CENTER, spin=0) =
|
||||||
subarc = ea2-sa2,
|
subarc = ea2-sa2,
|
||||||
arcsegs = ceil(segs(r2)*abs(subarc)/360),
|
arcsegs = ceil(segs(r2)*abs(subarc)/360),
|
||||||
arcstep = subarc / arcsegs,
|
arcstep = subarc / arcsegs,
|
||||||
s = [spread/2+r, r],
|
|
||||||
path = concat(
|
path = concat(
|
||||||
[for (i=[0:1:lobesegs]) let(a=sa1+i*lobestep) r * [cos(a),sin(a)] - cp1],
|
[for (i=[0:1:lobesegs]) let(a=sa1+i*lobestep) r * [cos(a),sin(a)] - cp1],
|
||||||
tangent==0? [] : [for (i=[0:1:arcsegs]) let(a=ea2-i*arcstep+180) r2 * [cos(a),sin(a)] - cp2],
|
tangent==0? [] : [for (i=[0:1:arcsegs]) let(a=ea2-i*arcstep+180) r2 * [cos(a),sin(a)] - cp2],
|
||||||
[for (i=[0:1:lobesegs]) let(a=sa1+i*lobestep+180) r * [cos(a),sin(a)] + cp1],
|
[for (i=[0:1:lobesegs]) let(a=sa1+i*lobestep+180) r * [cos(a),sin(a)] + cp1],
|
||||||
tangent==0? [] : [for (i=[0:1:arcsegs]) let(a=ea2-i*arcstep) r2 * [cos(a),sin(a)] + cp2]
|
tangent==0? [] : [for (i=[0:1:arcsegs]) let(a=ea2-i*arcstep) r2 * [cos(a),sin(a)] + cp2]
|
||||||
)
|
)
|
||||||
) rot(spin, p=move(-vmul(anchor,s), p=path));
|
) reorient(anchor,spin, two_d=true, path=path, extent=true, p=path);
|
||||||
|
|
||||||
|
|
||||||
module glued_circles(r, d, spread=10, tangent=30, anchor=CENTER, spin=0) {
|
module glued_circles(r, d, spread=10, tangent=30, anchor=CENTER, spin=0) {
|
||||||
|
@ -951,12 +949,12 @@ function star(n, r, d, or, od, ir, id, step, realign=false, anchor=CENTER, spin=
|
||||||
ir = get_radius(r=ir, d=id, dflt=stepr),
|
ir = get_radius(r=ir, d=id, dflt=stepr),
|
||||||
offset = 90+(realign? 180/n : 0),
|
offset = 90+(realign? 180/n : 0),
|
||||||
path = [for(i=[0:1:2*n-1]) let(theta=180*i/n+offset, radius=(i%2)?ir:r) radius*[cos(theta), sin(theta)]]
|
path = [for(i=[0:1:2*n-1]) let(theta=180*i/n+offset, radius=(i%2)?ir:r) radius*[cos(theta), sin(theta)]]
|
||||||
) rot(spin, p=move(-r*unit(anchor), p=path));
|
) reorient(anchor,spin, two_d=true, path=path, p=path);
|
||||||
|
|
||||||
|
|
||||||
module star(n, r, d, or, od, ir, id, step, realign=false, anchor=CENTER, spin=0) {
|
module star(n, r, d, or, od, ir, id, step, realign=false, anchor=CENTER, spin=0) {
|
||||||
path = star(n=n, r=r, d=d, od=od, or=or, ir=ir, id=id, step=step, realign=realign);
|
path = star(n=n, r=r, d=d, od=od, or=or, ir=ir, id=id, step=step, realign=realign);
|
||||||
attachable(anchor,spin, two_d=true, path=path, extent=true) {
|
attachable(anchor,spin, two_d=true, path=path) {
|
||||||
polygon(path);
|
polygon(path);
|
||||||
children();
|
children();
|
||||||
}
|
}
|
||||||
|
@ -1023,11 +1021,11 @@ function supershape(step=0.5,m1=4,m2=undef,n1=1,n2=undef,n3=undef,a=1,b=undef,r=
|
||||||
rads = [for (theta = angs) _superformula(theta=theta,m1=m1,m2=m2,n1=n1,n2=n2,n3=n3,a=a,b=b)],
|
rads = [for (theta = angs) _superformula(theta=theta,m1=m1,m2=m2,n1=n1,n2=n2,n3=n3,a=a,b=b)],
|
||||||
scale = is_def(r) ? r/max(rads) : 1,
|
scale = is_def(r) ? r/max(rads) : 1,
|
||||||
path = [for (i = [0:steps-1]) let(a=angs[i]) scale*rads[i]*[cos(a), sin(a)]]
|
path = [for (i = [0:steps-1]) let(a=angs[i]) scale*rads[i]*[cos(a), sin(a)]]
|
||||||
) rot(spin, p=move(-scale*max(rads)*unit(anchor), p=path));
|
) reorient(anchor,spin, two_d=true, path=path, p=path);
|
||||||
|
|
||||||
module supershape(step=0.5,m1=4,m2=undef,n1,n2=undef,n3=undef,a=1,b=undef, r=undef, d=undef, anchor=CENTER, spin=0) {
|
module supershape(step=0.5,m1=4,m2=undef,n1,n2=undef,n3=undef,a=1,b=undef, r=undef, d=undef, anchor=CENTER, spin=0) {
|
||||||
path = supershape(step=step,m1=m1,m2=m2,n1=n1,n2=n2,n3=n3,a=a,b=b,r=r,d=d);
|
path = supershape(step=step,m1=m1,m2=m2,n1=n1,n2=n2,n3=n3,a=a,b=b,r=r,d=d);
|
||||||
attachable(anchor,spin, two_d=true, path=path, extent=true) {
|
attachable(anchor,spin, two_d=true, path=path) {
|
||||||
polygon(path);
|
polygon(path);
|
||||||
children();
|
children();
|
||||||
}
|
}
|
||||||
|
@ -1057,11 +1055,15 @@ module supershape(step=0.5,m1=4,m2=undef,n1,n2=undef,n3=undef,a=1,b=undef, r=und
|
||||||
// cube([50,60,70],center=true)
|
// cube([50,60,70],center=true)
|
||||||
// edge_profile([TOP,"Z"],except=[BACK,TOP+LEFT])
|
// edge_profile([TOP,"Z"],except=[BACK,TOP+LEFT])
|
||||||
// mask2d_roundover(r=10, inset=2);
|
// mask2d_roundover(r=10, inset=2);
|
||||||
module mask2d_roundover(r, d, excess, inset=0) {
|
module mask2d_roundover(r, d, excess, inset=0, anchor=CENTER,spin=0) {
|
||||||
polygon(mask2d_roundover(r=r,d=d,excess=excess,inset=inset));
|
path = mask2d_roundover(r=r,d=d,excess=excess,inset=inset);
|
||||||
|
attachable(anchor,spin, two_d=true, path=path, p=path) {
|
||||||
|
polygon(path);
|
||||||
|
children();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function mask2d_roundover(r, d, excess, inset=0) =
|
function mask2d_roundover(r, d, excess, inset=0, anchor=CENTER,spin=0) =
|
||||||
assert(is_num(r)||is_num(d))
|
assert(is_num(r)||is_num(d))
|
||||||
assert(is_undef(excess)||is_num(excess))
|
assert(is_undef(excess)||is_num(excess))
|
||||||
assert(is_num(inset)||(is_vector(inset)&&len(inset)==2))
|
assert(is_num(inset)||(is_vector(inset)&&len(inset)==2))
|
||||||
|
@ -1070,12 +1072,13 @@ function mask2d_roundover(r, d, excess, inset=0) =
|
||||||
excess = default(excess,$overlap),
|
excess = default(excess,$overlap),
|
||||||
r = get_radius(r=r,d=d,dflt=1),
|
r = get_radius(r=r,d=d,dflt=1),
|
||||||
steps = quantup(segs(r),4)/4,
|
steps = quantup(segs(r),4)/4,
|
||||||
step = 90/steps
|
step = 90/steps,
|
||||||
) [
|
path = [
|
||||||
[-excess,-excess], [-excess, r+inset.y],
|
[-excess,-excess], [-excess, r+inset.y],
|
||||||
for (i=[0:1:steps]) [r,r] + inset + polar_to_xy(r,180+i*step),
|
for (i=[0:1:steps]) [r,r] + inset + polar_to_xy(r,180+i*step),
|
||||||
[r+inset.x,-excess]
|
[r+inset.x,-excess]
|
||||||
];
|
]
|
||||||
|
) reorient(anchor,spin, two_d=true, path=path, extent=false, p=path);
|
||||||
|
|
||||||
|
|
||||||
// Function&Module: mask2d_cove()
|
// Function&Module: mask2d_cove()
|
||||||
|
@ -1099,11 +1102,15 @@ function mask2d_roundover(r, d, excess, inset=0) =
|
||||||
// cube([50,60,70],center=true)
|
// cube([50,60,70],center=true)
|
||||||
// edge_profile([TOP,"Z"],except=[BACK,TOP+LEFT])
|
// edge_profile([TOP,"Z"],except=[BACK,TOP+LEFT])
|
||||||
// mask2d_cove(r=10, inset=2);
|
// mask2d_cove(r=10, inset=2);
|
||||||
module mask2d_cove(r, d, inset=0, excess) {
|
module mask2d_cove(r, d, inset=0, excess, anchor=CENTER,spin=0) {
|
||||||
polygon(mask2d_cove(r=r,d=d,excess=excess,inset=inset));
|
path = mask2d_cove(r=r,d=d,excess=excess,inset=inset);
|
||||||
|
attachable(anchor,spin, two_d=true, path=path) {
|
||||||
|
polygon(path);
|
||||||
|
children();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function mask2d_cove(r, d, inset=0, excess) =
|
function mask2d_cove(r, d, inset=0, excess, anchor=CENTER,spin=0) =
|
||||||
assert(is_num(r)||is_num(d))
|
assert(is_num(r)||is_num(d))
|
||||||
assert(is_undef(excess)||is_num(excess))
|
assert(is_undef(excess)||is_num(excess))
|
||||||
assert(is_num(inset)||(is_vector(inset)&&len(inset)==2))
|
assert(is_num(inset)||(is_vector(inset)&&len(inset)==2))
|
||||||
|
@ -1112,12 +1119,13 @@ function mask2d_cove(r, d, inset=0, excess) =
|
||||||
excess = default(excess,$overlap),
|
excess = default(excess,$overlap),
|
||||||
r = get_radius(r=r,d=d,dflt=1),
|
r = get_radius(r=r,d=d,dflt=1),
|
||||||
steps = quantup(segs(r),4)/4,
|
steps = quantup(segs(r),4)/4,
|
||||||
step = 90/steps
|
step = 90/steps,
|
||||||
) [
|
path = [
|
||||||
[-excess,-excess], [-excess, r+inset.y],
|
[-excess,-excess], [-excess, r+inset.y],
|
||||||
for (i=[0:1:steps]) inset + polar_to_xy(r,90-i*step),
|
for (i=[0:1:steps]) inset + polar_to_xy(r,90-i*step),
|
||||||
[r+inset.x,-excess]
|
[r+inset.x,-excess]
|
||||||
];
|
]
|
||||||
|
) reorient(anchor,spin, two_d=true, path=path, p=path);
|
||||||
|
|
||||||
|
|
||||||
// Function&Module: mask2d_chamfer()
|
// Function&Module: mask2d_chamfer()
|
||||||
|
@ -1147,11 +1155,15 @@ function mask2d_cove(r, d, inset=0, excess) =
|
||||||
// cube([50,60,70],center=true)
|
// cube([50,60,70],center=true)
|
||||||
// edge_profile([TOP,"Z"],except=[BACK,TOP+LEFT])
|
// edge_profile([TOP,"Z"],except=[BACK,TOP+LEFT])
|
||||||
// mask2d_chamfer(x=10, inset=2);
|
// mask2d_chamfer(x=10, inset=2);
|
||||||
module mask2d_chamfer(x, y, edge, angle=45, excess, inset=0) {
|
module mask2d_chamfer(x, y, edge, angle=45, excess, inset=0, anchor=CENTER,spin=0) {
|
||||||
polygon(mask2d_chamfer(x=x, y=y, edge=edge, angle=angle, excess=excess, inset=inset));
|
path = mask2d_chamfer(x=x, y=y, edge=edge, angle=angle, excess=excess, inset=inset);
|
||||||
|
attachable(anchor,spin, two_d=true, path=path, extent=true) {
|
||||||
|
polygon(path);
|
||||||
|
children();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function mask2d_chamfer(x, y, edge, angle=45, excess, inset=0) =
|
function mask2d_chamfer(x, y, edge, angle=45, excess, inset=0, anchor=CENTER,spin=0) =
|
||||||
assert(num_defined([x,y,edge])==1)
|
assert(num_defined([x,y,edge])==1)
|
||||||
assert(is_num(first_defined([x,y,edge])))
|
assert(is_num(first_defined([x,y,edge])))
|
||||||
assert(is_num(angle))
|
assert(is_num(angle))
|
||||||
|
@ -1163,12 +1175,13 @@ function mask2d_chamfer(x, y, edge, angle=45, excess, inset=0) =
|
||||||
x = !is_undef(x)? x :
|
x = !is_undef(x)? x :
|
||||||
!is_undef(y)? adj_ang_to_opp(adj=y,ang=angle) :
|
!is_undef(y)? adj_ang_to_opp(adj=y,ang=angle) :
|
||||||
hyp_ang_to_opp(hyp=edge,ang=angle),
|
hyp_ang_to_opp(hyp=edge,ang=angle),
|
||||||
y = opp_ang_to_adj(opp=x,ang=angle)
|
y = opp_ang_to_adj(opp=x,ang=angle),
|
||||||
) [
|
path = [
|
||||||
[-excess, -excess], [-excess, y+inset.y],
|
[-excess, -excess], [-excess, y+inset.y],
|
||||||
[inset.x, y+inset.y], [x+inset.x, inset.y],
|
[inset.x, y+inset.y], [x+inset.x, inset.y],
|
||||||
[x+inset.x, -excess]
|
[x+inset.x, -excess]
|
||||||
];
|
]
|
||||||
|
) reorient(anchor,spin, two_d=true, path=path, extent=true, p=path);
|
||||||
|
|
||||||
|
|
||||||
// Function&Module: mask2d_rabbet()
|
// Function&Module: mask2d_rabbet()
|
||||||
|
@ -1191,19 +1204,25 @@ function mask2d_chamfer(x, y, edge, angle=45, excess, inset=0) =
|
||||||
// cube([50,60,70],center=true)
|
// cube([50,60,70],center=true)
|
||||||
// edge_profile([TOP,"Z"],except=[BACK,TOP+LEFT])
|
// edge_profile([TOP,"Z"],except=[BACK,TOP+LEFT])
|
||||||
// mask2d_rabbet(size=10);
|
// mask2d_rabbet(size=10);
|
||||||
module mask2d_rabbet(size, excess) {
|
module mask2d_rabbet(size, excess, anchor=CENTER,spin=0) {
|
||||||
polygon(mask2d_rabbet(size=size, excess=excess));
|
path = mask2d_rabbet(size=size, excess=excess);
|
||||||
|
attachable(anchor,spin, two_d=true, path=path, extent=false, p=path) {
|
||||||
|
polygon(path);
|
||||||
|
children();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function mask2d_rabbet(size, excess) =
|
function mask2d_rabbet(size, excess, anchor=CENTER,spin=0) =
|
||||||
assert(is_num(size)||(is_vector(size)&&len(size)==2))
|
assert(is_num(size)||(is_vector(size)&&len(size)==2))
|
||||||
assert(is_undef(excess)||is_num(excess))
|
assert(is_undef(excess)||is_num(excess))
|
||||||
let(
|
let(
|
||||||
excess = default(excess,$overlap),
|
excess = default(excess,$overlap),
|
||||||
size = is_list(size)? size : [size,size]
|
size = is_list(size)? size : [size,size],
|
||||||
) [
|
path = [
|
||||||
[-excess, -excess], [-excess, size.y], size, [size.x, -excess]
|
[-excess, -excess], [-excess, size.y],
|
||||||
];
|
size, [size.x, -excess]
|
||||||
|
]
|
||||||
|
) reorient(anchor,spin, two_d=true, path=path, extent=false, p=path);
|
||||||
|
|
||||||
|
|
||||||
// Function&Module: mask2d_dovetail()
|
// Function&Module: mask2d_dovetail()
|
||||||
|
@ -1234,11 +1253,15 @@ function mask2d_rabbet(size, excess) =
|
||||||
// cube([50,60,70],center=true)
|
// cube([50,60,70],center=true)
|
||||||
// edge_profile([TOP,"Z"],except=[BACK,TOP+LEFT])
|
// edge_profile([TOP,"Z"],except=[BACK,TOP+LEFT])
|
||||||
// mask2d_dovetail(x=10, inset=2);
|
// mask2d_dovetail(x=10, inset=2);
|
||||||
module mask2d_dovetail(x, y, edge, angle=30, inset=0, shelf=0, excess) {
|
module mask2d_dovetail(x, y, edge, angle=30, inset=0, shelf=0, excess, anchor=CENTER, spin=0) {
|
||||||
polygon(mask2d_dovetail(x=x, y=y, edge=edge, angle=angle, inset=inset, shelf=shelf, excess=excess));
|
path = mask2d_dovetail(x=x, y=y, edge=edge, angle=angle, inset=inset, shelf=shelf, excess=excess);
|
||||||
|
attachable(anchor,spin, two_d=true, path=path) {
|
||||||
|
polygon(path);
|
||||||
|
children();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function mask2d_dovetail(x, y, edge, angle=30, inset=0, shelf=0, excess) =
|
function mask2d_dovetail(x, y, edge, angle=30, inset=0, shelf=0, excess, anchor=CENTER, spin=0) =
|
||||||
assert(num_defined([x,y,edge])==1)
|
assert(num_defined([x,y,edge])==1)
|
||||||
assert(is_num(first_defined([x,y,edge])))
|
assert(is_num(first_defined([x,y,edge])))
|
||||||
assert(is_num(angle))
|
assert(is_num(angle))
|
||||||
|
@ -1250,11 +1273,12 @@ function mask2d_dovetail(x, y, edge, angle=30, inset=0, shelf=0, excess) =
|
||||||
x = !is_undef(x)? x :
|
x = !is_undef(x)? x :
|
||||||
!is_undef(y)? adj_ang_to_opp(adj=y,ang=angle) :
|
!is_undef(y)? adj_ang_to_opp(adj=y,ang=angle) :
|
||||||
hyp_ang_to_opp(hyp=edge,ang=angle),
|
hyp_ang_to_opp(hyp=edge,ang=angle),
|
||||||
y = opp_ang_to_adj(opp=x,ang=angle)
|
y = opp_ang_to_adj(opp=x,ang=angle),
|
||||||
) [
|
path = [
|
||||||
[-excess, 0], [-excess, y+inset.y+shelf],
|
[-excess, 0], [-excess, y+inset.y+shelf],
|
||||||
inset+[x,y+shelf], inset+[x,y], inset, [inset.x,0]
|
inset+[x,y+shelf], inset+[x,y], inset, [inset.x,0]
|
||||||
];
|
]
|
||||||
|
) reorient(anchor,spin, two_d=true, path=path, p=path);
|
||||||
|
|
||||||
|
|
||||||
// Function&Module: mask2d_ogee()
|
// Function&Module: mask2d_ogee()
|
||||||
|
@ -1289,7 +1313,11 @@ function mask2d_dovetail(x, y, edge, angle=30, inset=0, shelf=0, excess) =
|
||||||
// "ystep",1, "xstep",1 // Ending shoulder.
|
// "ystep",1, "xstep",1 // Ending shoulder.
|
||||||
// ]);
|
// ]);
|
||||||
module mask2d_ogee(pattern, excess) {
|
module mask2d_ogee(pattern, excess) {
|
||||||
polygon(mask2d_ogee(pattern, excess=excess));
|
path = mask2d_ogee(pattern, excess=excess);
|
||||||
|
attachable(anchor,spin, two_d=true, path=path) {
|
||||||
|
polygon(path);
|
||||||
|
children();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function mask2d_ogee(pattern, excess) =
|
function mask2d_ogee(pattern, excess) =
|
||||||
|
@ -1356,8 +1384,9 @@ function mask2d_ogee(pattern, excess) =
|
||||||
a = pat[0]=="round"? (180+i*step) : (90-i*step)
|
a = pat[0]=="round"? (180+i*step) : (90-i*step)
|
||||||
) pat[2] + abs(r)*[cos(a),sin(a)]
|
) pat[2] + abs(r)*[cos(a),sin(a)]
|
||||||
]
|
]
|
||||||
]
|
],
|
||||||
) deduplicate(path);
|
path2 = deduplicate(path)
|
||||||
|
) reorient(anchor,spin, two_d=true, path=path2, p=path2);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
BOSL_VERSION = [2,0,162];
|
BOSL_VERSION = [2,0,163];
|
||||||
|
|
||||||
|
|
||||||
// Section: BOSL Library Version Functions
|
// Section: BOSL Library Version Functions
|
||||||
|
|
Loading…
Reference in a new issue