mirror of
https://github.com/BelfrySCAD/BOSL2.git
synced 2024-12-28 15:59:45 +00:00
organize masks into massk3d.scad and masks2d.scad
This commit is contained in:
parent
477dd55781
commit
6d1c754ed8
7 changed files with 523 additions and 594 deletions
|
@ -187,7 +187,7 @@ function all_nonnegative(x,eps=0) =
|
|||
// eps = Set to tolerance for approximate equality. Default: 0
|
||||
function all_equal(vec,eps=0) =
|
||||
eps==0 ? [for(v=vec) if (v!=vec[0]) v] == []
|
||||
: [for(v=vec) if (!approx(v,vec[0])) v] == [];
|
||||
: [for(v=vec) if (!approx(v,vec[0],eps)) v] == [];
|
||||
|
||||
|
||||
|
||||
|
|
503
masks2d.scad
Normal file
503
masks2d.scad
Normal file
|
@ -0,0 +1,503 @@
|
|||
//////////////////////////////////////////////////////////////////////
|
||||
// LibFile: masks2d.scad
|
||||
// This file provides 2D masking shapes that you can use with {{edge_profile()}} to mask edges.
|
||||
// The shapes include the simple roundover and chamfer as well as more elaborate shapes
|
||||
// like the cove and ogee found in furniture and architecture. You can make the masks
|
||||
// as geometry or as 2D paths.
|
||||
// Includes:
|
||||
// include <BOSL2/std.scad>
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
// Section: 2D Masking Shapes
|
||||
|
||||
// Function&Module: mask2d_roundover()
|
||||
// Usage: As Module
|
||||
// mask2d_roundover(r|d, [inset], [excess]);
|
||||
// Usage: With Attachments
|
||||
// mask2d_roundover(r|d, [inset], [excess]) { attachments }
|
||||
// Usage: As Module
|
||||
// path = mask2d_roundover(r|d, [inset], [excess]);
|
||||
// Topics: Shapes (2D), Paths (2D), Path Generators, Attachable, Masks (2D)
|
||||
// See Also: corner_profile(), edge_profile(), face_profile()
|
||||
// Description:
|
||||
// Creates a 2D roundover/bead mask shape that is useful for extruding into a 3D mask for a 90° edge.
|
||||
// This 2D mask is designed to be differenced away from the edge of a shape that is in the first (X+Y+) quadrant.
|
||||
// If called as a function, this just returns a 2D path of the outline of the mask shape.
|
||||
// Arguments:
|
||||
// r = Radius of the roundover.
|
||||
// inset = Optional bead inset size. Default: 0
|
||||
// excess = Extra amount of mask shape to creates on the X- and Y- sides of the shape. Default: 0.01
|
||||
// ---
|
||||
// d = Diameter of the roundover.
|
||||
// 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): 2D Roundover Mask
|
||||
// mask2d_roundover(r=10);
|
||||
// Example(2D): 2D Bead Mask
|
||||
// mask2d_roundover(r=10,inset=2);
|
||||
// Example: Masking by Edge Attachment
|
||||
// diff("mask")
|
||||
// cube([50,60,70],center=true)
|
||||
// edge_profile([TOP,"Z"],except=[BACK,TOP+LEFT])
|
||||
// mask2d_roundover(r=10, inset=2);
|
||||
module mask2d_roundover(r, inset=0, excess=0.01, d, anchor=CENTER,spin=0) {
|
||||
path = mask2d_roundover(r=r,d=d,excess=excess,inset=inset);
|
||||
attachable(anchor,spin, two_d=true, path=path) {
|
||||
polygon(path);
|
||||
children();
|
||||
}
|
||||
}
|
||||
|
||||
function mask2d_roundover(r, inset=0, excess=0.01, d, anchor=CENTER,spin=0) =
|
||||
assert(is_num(r)||is_num(d))
|
||||
assert(is_undef(excess)||is_num(excess))
|
||||
assert(is_num(inset)||(is_vector(inset)&&len(inset)==2))
|
||||
let(
|
||||
inset = is_list(inset)? inset : [inset,inset],
|
||||
excess = default(excess,$overlap),
|
||||
r = get_radius(r=r,d=d,dflt=1),
|
||||
steps = quantup(segs(r),4)/4,
|
||||
step = 90/steps,
|
||||
path = [
|
||||
[r+inset.x,-excess],
|
||||
[-excess,-excess],
|
||||
[-excess, r+inset.y],
|
||||
for (i=[0:1:steps]) [r,r] + inset + polar_to_xy(r,180+i*step)
|
||||
]
|
||||
) reorient(anchor,spin, two_d=true, path=path, extent=false, p=path);
|
||||
|
||||
|
||||
// Function&Module: mask2d_cove()
|
||||
// Usage: As Module
|
||||
// mask2d_cove(r|d, [inset], [excess]);
|
||||
// Usage: With Attachments
|
||||
// mask2d_cove(r|d, [inset], [excess]) { attachments }
|
||||
// Usage: As Function
|
||||
// path = mask2d_cove(r|d, [inset], [excess]);
|
||||
// Topics: Shapes (2D), Paths (2D), Path Generators, Attachable, Masks (2D)
|
||||
// See Also: corner_profile(), edge_profile(), face_profile()
|
||||
// Description:
|
||||
// Creates a 2D cove mask shape that is useful for extruding into a 3D mask for a 90° edge.
|
||||
// This 2D mask is designed to be differenced away from the edge of a shape that is in the first (X+Y+) quadrant.
|
||||
// If called as a function, this just returns a 2D path of the outline of the mask shape.
|
||||
// Arguments:
|
||||
// r = Radius of the cove.
|
||||
// inset = Optional amount to inset code from corner. Default: 0
|
||||
// excess = Extra amount of mask shape to creates on the X- and Y- sides of the shape. Default: 0.01
|
||||
// ---
|
||||
// d = Diameter of the cove.
|
||||
// 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): 2D Cove Mask
|
||||
// mask2d_cove(r=10);
|
||||
// Example(2D): 2D Inset Cove Mask
|
||||
// mask2d_cove(r=10,inset=3);
|
||||
// Example: Masking by Edge Attachment
|
||||
// diff("mask")
|
||||
// cube([50,60,70],center=true)
|
||||
// edge_profile([TOP,"Z"],except=[BACK,TOP+LEFT])
|
||||
// mask2d_cove(r=10, inset=2);
|
||||
module mask2d_cove(r, inset=0, excess=0.01, d, anchor=CENTER,spin=0) {
|
||||
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, inset=0, excess=0.01, d, anchor=CENTER,spin=0) =
|
||||
assert(is_num(r)||is_num(d))
|
||||
assert(is_undef(excess)||is_num(excess))
|
||||
assert(is_num(inset)||(is_vector(inset)&&len(inset)==2))
|
||||
let(
|
||||
inset = is_list(inset)? inset : [inset,inset],
|
||||
excess = default(excess,$overlap),
|
||||
r = get_radius(r=r,d=d,dflt=1),
|
||||
steps = quantup(segs(r),4)/4,
|
||||
step = 90/steps,
|
||||
path = [
|
||||
[r+inset.x,-excess],
|
||||
[-excess,-excess],
|
||||
[-excess, r+inset.y],
|
||||
for (i=[0:1:steps]) inset + polar_to_xy(r,90-i*step)
|
||||
]
|
||||
) reorient(anchor,spin, two_d=true, path=path, p=path);
|
||||
|
||||
|
||||
// Function&Module: mask2d_chamfer()
|
||||
// Usage: As Module
|
||||
// mask2d_chamfer(edge, [angle], [inset], [excess]);
|
||||
// mask2d_chamfer(y, [angle], [inset], [excess]);
|
||||
// mask2d_chamfer(x, [angle], [inset], [excess]);
|
||||
// Usage: With Attachments
|
||||
// mask2d_chamfer(edge, [angle], [inset], [excess]) { attachments }
|
||||
// Usage: As Function
|
||||
// path = mask2d_chamfer(edge, [angle], [inset], [excess]);
|
||||
// path = mask2d_chamfer(y, [angle], [inset], [excess]);
|
||||
// path = mask2d_chamfer(x, [angle], [inset], [excess]);
|
||||
// Topics: Shapes (2D), Paths (2D), Path Generators, Attachable, Masks (2D)
|
||||
// See Also: corner_profile(), edge_profile(), face_profile()
|
||||
// Description:
|
||||
// Creates a 2D chamfer mask shape that is useful for extruding into a 3D mask for a 90° edge.
|
||||
// This 2D mask is designed to be differenced away from the edge of a shape that is in the first (X+Y+) quadrant.
|
||||
// If called as a function, this just returns a 2D path of the outline of the mask shape.
|
||||
// Arguments:
|
||||
// edge = The length of the edge of the chamfer.
|
||||
// angle = The angle of the chamfer edge, away from vertical. Default: 45.
|
||||
// inset = Optional amount to inset code from corner. Default: 0
|
||||
// excess = Extra amount of mask shape to creates on the X- and Y- sides of the shape. Default: 0.01
|
||||
// ---
|
||||
// x = The width of the chamfer.
|
||||
// y = The height of the chamfer.
|
||||
// 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): 2D Chamfer Mask
|
||||
// mask2d_chamfer(x=10);
|
||||
// Example(2D): 2D Chamfer Mask by Width.
|
||||
// mask2d_chamfer(x=10, angle=30);
|
||||
// Example(2D): 2D Chamfer Mask by Height.
|
||||
// mask2d_chamfer(y=10, angle=30);
|
||||
// Example(2D): 2D Inset Chamfer Mask
|
||||
// mask2d_chamfer(x=10, inset=2);
|
||||
// Example: Masking by Edge Attachment
|
||||
// diff("mask")
|
||||
// cube([50,60,70],center=true)
|
||||
// edge_profile([TOP,"Z"],except=[BACK,TOP+LEFT])
|
||||
// mask2d_chamfer(x=10, inset=2);
|
||||
module mask2d_chamfer(edge, angle=45, inset=0, excess=0.01, x, y, anchor=CENTER,spin=0) {
|
||||
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(edge, angle=45, inset=0, excess=0.01, x, y, anchor=CENTER,spin=0) =
|
||||
assert(num_defined([x,y,edge])==1)
|
||||
assert(is_num(first_defined([x,y,edge])))
|
||||
assert(is_num(angle))
|
||||
assert(is_undef(excess)||is_num(excess))
|
||||
assert(is_num(inset)||(is_vector(inset)&&len(inset)==2))
|
||||
let(
|
||||
inset = is_list(inset)? inset : [inset,inset],
|
||||
excess = default(excess,$overlap),
|
||||
x = !is_undef(x)? x :
|
||||
!is_undef(y)? adj_ang_to_opp(adj=y,ang=angle) :
|
||||
hyp_ang_to_opp(hyp=edge,ang=angle),
|
||||
y = opp_ang_to_adj(opp=x,ang=angle),
|
||||
path = [
|
||||
[x+inset.x, -excess],
|
||||
[-excess, -excess],
|
||||
[-excess, y+inset.y],
|
||||
[inset.x, y+inset.y],
|
||||
[x+inset.x, inset.y]
|
||||
]
|
||||
) reorient(anchor,spin, two_d=true, path=path, extent=true, p=path);
|
||||
|
||||
|
||||
// Function&Module: mask2d_rabbet()
|
||||
// Usage: As Module
|
||||
// mask2d_rabbet(size, [excess]);
|
||||
// Usage: With Attachments
|
||||
// mask2d_rabbet(size, [excess]) { attachments }
|
||||
// Usage: As Function
|
||||
// path = mask2d_rabbet(size, [excess]);
|
||||
// Topics: Shapes (2D), Paths (2D), Path Generators, Attachable, Masks (2D)
|
||||
// See Also: corner_profile(), edge_profile(), face_profile()
|
||||
// Description:
|
||||
// Creates a 2D rabbet mask shape that is useful for extruding into a 3D mask for a 90° edge.
|
||||
// This 2D mask is designed to be differenced away from the edge of a shape that is in the first (X+Y+) quadrant.
|
||||
// If called as a function, this just returns a 2D path of the outline of the mask shape.
|
||||
// Arguments:
|
||||
// size = The size of the rabbet, either as a scalar or an [X,Y] list.
|
||||
// excess = Extra amount of mask shape to creates on the X- and Y- sides of the shape. Default: 0.01
|
||||
// ---
|
||||
// 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): 2D Rabbet Mask
|
||||
// mask2d_rabbet(size=10);
|
||||
// Example(2D): 2D Asymmetrical Rabbet Mask
|
||||
// mask2d_rabbet(size=[5,10]);
|
||||
// Example: Masking by Edge Attachment
|
||||
// diff("mask")
|
||||
// cube([50,60,70],center=true)
|
||||
// edge_profile([TOP,"Z"],except=[BACK,TOP+LEFT])
|
||||
// mask2d_rabbet(size=10);
|
||||
module mask2d_rabbet(size, excess=0.01, anchor=CENTER,spin=0) {
|
||||
path = mask2d_rabbet(size=size, excess=excess);
|
||||
attachable(anchor,spin, two_d=true, path=path, extent=false) {
|
||||
polygon(path);
|
||||
children();
|
||||
}
|
||||
}
|
||||
|
||||
function mask2d_rabbet(size, excess=0.01, anchor=CENTER,spin=0) =
|
||||
assert(is_num(size)||(is_vector(size)&&len(size)==2))
|
||||
assert(is_undef(excess)||is_num(excess))
|
||||
let(
|
||||
excess = default(excess,$overlap),
|
||||
size = is_list(size)? size : [size,size],
|
||||
path = [
|
||||
[size.x, -excess],
|
||||
[-excess, -excess],
|
||||
[-excess, size.y],
|
||||
size
|
||||
]
|
||||
) reorient(anchor,spin, two_d=true, path=path, extent=false, p=path);
|
||||
|
||||
|
||||
// Function&Module: mask2d_dovetail()
|
||||
// Usage: As Module
|
||||
// mask2d_dovetail(edge, [angle], [inset], [shelf], [excess], ...);
|
||||
// mask2d_dovetail(x=, [angle=], [inset=], [shelf=], [excess=], ...);
|
||||
// mask2d_dovetail(y=, [angle=], [inset=], [shelf=], [excess=], ...);
|
||||
// Usage: With Attachments
|
||||
// mask2d_dovetail(edge, [angle], [inset], [shelf], ...) { attachments }
|
||||
// Usage: As Function
|
||||
// path = mask2d_dovetail(edge, [angle], [inset], [shelf], [excess]);
|
||||
// Topics: Shapes (2D), Paths (2D), Path Generators, Attachable, Masks (2D)
|
||||
// See Also: corner_profile(), edge_profile(), face_profile()
|
||||
// Description:
|
||||
// Creates a 2D dovetail mask shape that is useful for extruding into a 3D mask for a 90° edge.
|
||||
// This 2D mask is designed to be differenced away from the edge of a shape that is in the first (X+Y+) quadrant.
|
||||
// If called as a function, this just returns a 2D path of the outline of the mask shape.
|
||||
// Arguments:
|
||||
// edge = The length of the edge of the dovetail.
|
||||
// angle = The angle of the chamfer edge, away from vertical. Default: 30.
|
||||
// inset = Optional amount to inset code from corner. Default: 0
|
||||
// shelf = The extra height to add to the inside corner of the dovetail. Default: 0
|
||||
// excess = Extra amount of mask shape to creates on the X- and Y- sides of the shape. Default: 0.01
|
||||
// ---
|
||||
// x = The width of the dovetail.
|
||||
// y = The height of the dovetail.
|
||||
// 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): 2D Dovetail Mask
|
||||
// mask2d_dovetail(x=10);
|
||||
// Example(2D): 2D Dovetail Mask by Width.
|
||||
// mask2d_dovetail(x=10, angle=30);
|
||||
// Example(2D): 2D Dovetail Mask by Height.
|
||||
// mask2d_dovetail(y=10, angle=30);
|
||||
// Example(2D): 2D Inset Dovetail Mask
|
||||
// mask2d_dovetail(x=10, inset=2);
|
||||
// Example: Masking by Edge Attachment
|
||||
// diff("mask")
|
||||
// cube([50,60,70],center=true)
|
||||
// edge_profile([TOP,"Z"],except=[BACK,TOP+LEFT])
|
||||
// mask2d_dovetail(x=10, inset=2);
|
||||
module mask2d_dovetail(edge, angle=30, inset=0, shelf=0, excess=0.01, x, y, anchor=CENTER, spin=0) {
|
||||
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(edge, angle=30, inset=0, shelf=0, excess=0.01, x, y, anchor=CENTER, spin=0) =
|
||||
assert(num_defined([x,y,edge])==1)
|
||||
assert(is_num(first_defined([x,y,edge])))
|
||||
assert(is_num(angle))
|
||||
assert(is_undef(excess)||is_num(excess))
|
||||
assert(is_num(inset)||(is_vector(inset)&&len(inset)==2))
|
||||
let(
|
||||
inset = is_list(inset)? inset : [inset,inset],
|
||||
excess = default(excess,$overlap),
|
||||
x = !is_undef(x)? x :
|
||||
!is_undef(y)? adj_ang_to_opp(adj=y,ang=angle) :
|
||||
hyp_ang_to_opp(hyp=edge,ang=angle),
|
||||
y = opp_ang_to_adj(opp=x,ang=angle),
|
||||
path = [
|
||||
[inset.x,0],
|
||||
[-excess, 0],
|
||||
[-excess, y+inset.y+shelf],
|
||||
inset+[x,y+shelf],
|
||||
inset+[x,y],
|
||||
inset
|
||||
]
|
||||
) reorient(anchor,spin, two_d=true, path=path, p=path);
|
||||
|
||||
|
||||
// Function&Module: mask2d_teardrop()
|
||||
// Usage: As Module
|
||||
// mask2d_teardrop(r|d, [angle], [excess]);
|
||||
// Usage: With Attachments
|
||||
// mask2d_teardrop(r|d, [angle], [excess]) { attachments }
|
||||
// Usage: As Function
|
||||
// path = mask2d_teardrop(r|d, [angle], [excess]);
|
||||
// Topics: Shapes (2D), Paths (2D), Path Generators, Attachable, Masks (2D)
|
||||
// See Also: corner_profile(), edge_profile(), face_profile()
|
||||
// Description:
|
||||
// Creates a 2D teardrop mask shape that is useful for extruding into a 3D mask for a 90° edge.
|
||||
// This 2D mask is designed to be differenced away from the edge of a shape that is in the first (X+Y+) quadrant.
|
||||
// If called as a function, this just returns a 2D path of the outline of the mask shape.
|
||||
// This is particularly useful to make partially rounded bottoms, that don't need support to print.
|
||||
// Arguments:
|
||||
// r = Radius of the rounding.
|
||||
// angle = The maximum angle from vertical.
|
||||
// excess = Extra amount of mask shape to creates on the X- and Y- sides of the shape. Default: 0.01
|
||||
// ---
|
||||
// d = Diameter of the rounding.
|
||||
// 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): 2D Teardrop Mask
|
||||
// mask2d_teardrop(r=10);
|
||||
// Example(2D): Using a Custom Angle
|
||||
// mask2d_teardrop(r=10,angle=30);
|
||||
// Example: Masking by Edge Attachment
|
||||
// diff("mask")
|
||||
// cube([50,60,70],center=true)
|
||||
// edge_profile(BOT)
|
||||
// mask2d_teardrop(r=10, angle=40);
|
||||
function mask2d_teardrop(r, angle=45, excess=0.01, d, anchor=CENTER, spin=0) =
|
||||
assert(is_num(angle))
|
||||
assert(angle>0 && angle<90)
|
||||
assert(is_num(excess))
|
||||
let(
|
||||
r = get_radius(r=r, d=d, dflt=1),
|
||||
n = ceil(segs(r) * angle/360),
|
||||
cp = [r,r],
|
||||
tp = cp + polar_to_xy(r,180+angle),
|
||||
bp = [tp.x+adj_ang_to_opp(tp.y,angle), 0],
|
||||
step = angle/n,
|
||||
path = [
|
||||
bp, bp-[0,excess], [-excess,-excess], [-excess,r],
|
||||
for (i=[0:1:n]) cp+polar_to_xy(r,180+i*step)
|
||||
]
|
||||
) reorient(anchor,spin, two_d=true, path=path, p=path);
|
||||
|
||||
module mask2d_teardrop(r, angle=45, excess=0.01, d, anchor=CENTER, spin=0) {
|
||||
path = mask2d_teardrop(r=r, d=d, angle=angle, excess=excess);
|
||||
attachable(anchor,spin, two_d=true, path=path) {
|
||||
polygon(path);
|
||||
children();
|
||||
}
|
||||
}
|
||||
|
||||
// Function&Module: mask2d_ogee()
|
||||
// Usage: As Module
|
||||
// mask2d_ogee(pattern, [excess], ...);
|
||||
// Usage: With Attachments
|
||||
// mask2d_ogee(pattern, [excess], ...) { attachments }
|
||||
// Usage: As Function
|
||||
// path = mask2d_ogee(pattern, [excess], ...);
|
||||
// Topics: Shapes (2D), Paths (2D), Path Generators, Attachable, Masks (2D)
|
||||
// See Also: corner_profile(), edge_profile(), face_profile()
|
||||
//
|
||||
// Description:
|
||||
// Creates a 2D Ogee mask shape that is useful for extruding into a 3D mask for a 90° edge.
|
||||
// This 2D mask is designed to be `difference()`d away from the edge of a shape that is in the first (X+Y+) quadrant.
|
||||
// Since there are a number of shapes that fall under the name ogee, the shape of this mask is given as a pattern.
|
||||
// Patterns are given as TYPE, VALUE pairs. ie: `["fillet",10, "xstep",2, "step",[5,5], ...]`. See Patterns below.
|
||||
// If called as a function, this just returns a 2D path of the outline of the mask shape.
|
||||
// .
|
||||
// ### Patterns
|
||||
// .
|
||||
// Type | Argument | Description
|
||||
// -------- | --------- | ----------------
|
||||
// "step" | [x,y] | Makes a line to a point `x` right and `y` down.
|
||||
// "xstep" | dist | Makes a `dist` length line towards X+.
|
||||
// "ystep" | dist | Makes a `dist` length line towards Y-.
|
||||
// "round" | radius | Makes an arc that will mask a roundover.
|
||||
// "fillet" | radius | Makes an arc that will mask a fillet.
|
||||
//
|
||||
// Arguments:
|
||||
// pattern = A list of pattern pieces to describe the Ogee.
|
||||
// excess = Extra amount of mask shape to creates on the X- and Y- sides of the shape. Default: 0.01
|
||||
// ---
|
||||
// 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): 2D Ogee Mask
|
||||
// mask2d_ogee([
|
||||
// "xstep",1, "ystep",1, // Starting shoulder.
|
||||
// "fillet",5, "round",5, // S-curve.
|
||||
// "ystep",1, "xstep",1 // Ending shoulder.
|
||||
// ]);
|
||||
// Example: Masking by Edge Attachment
|
||||
// diff("mask")
|
||||
// cube([50,60,70],center=true)
|
||||
// edge_profile(TOP)
|
||||
// mask2d_ogee([
|
||||
// "xstep",1, "ystep",1, // Starting shoulder.
|
||||
// "fillet",5, "round",5, // S-curve.
|
||||
// "ystep",1, "xstep",1 // Ending shoulder.
|
||||
// ]);
|
||||
module mask2d_ogee(pattern, excess=0.01, anchor=CENTER,spin=0) {
|
||||
path = mask2d_ogee(pattern, excess=excess);
|
||||
attachable(anchor,spin, two_d=true, path=path) {
|
||||
polygon(path);
|
||||
children();
|
||||
}
|
||||
}
|
||||
|
||||
function mask2d_ogee(pattern, excess=0.01, anchor=CENTER, spin=0) =
|
||||
assert(is_list(pattern))
|
||||
assert(len(pattern)>0)
|
||||
assert(len(pattern)%2==0,"pattern must be a list of TYPE, VAL pairs.")
|
||||
assert(all([for (i = idx(pattern,step=2)) in_list(pattern[i],["step","xstep","ystep","round","fillet"])]))
|
||||
let(
|
||||
excess = default(excess,$overlap),
|
||||
x = concat([0], cumsum([
|
||||
for (i=idx(pattern,step=2)) let(
|
||||
type = pattern[i],
|
||||
val = pattern[i+1]
|
||||
) (
|
||||
type=="step"? val.x :
|
||||
type=="xstep"? val :
|
||||
type=="round"? val :
|
||||
type=="fillet"? val :
|
||||
0
|
||||
)
|
||||
])),
|
||||
y = concat([0], cumsum([
|
||||
for (i=idx(pattern,step=2)) let(
|
||||
type = pattern[i],
|
||||
val = pattern[i+1]
|
||||
) (
|
||||
type=="step"? val.y :
|
||||
type=="ystep"? val :
|
||||
type=="round"? val :
|
||||
type=="fillet"? val :
|
||||
0
|
||||
)
|
||||
])),
|
||||
tot_x = last(x),
|
||||
tot_y = last(y),
|
||||
data = [
|
||||
for (i=idx(pattern,step=2)) let(
|
||||
type = pattern[i],
|
||||
val = pattern[i+1],
|
||||
pt = [x[i/2], tot_y-y[i/2]] + (
|
||||
type=="step"? [val.x,-val.y] :
|
||||
type=="xstep"? [val,0] :
|
||||
type=="ystep"? [0,-val] :
|
||||
type=="round"? [val,0] :
|
||||
type=="fillet"? [0,-val] :
|
||||
[0,0]
|
||||
)
|
||||
) [type, val, pt]
|
||||
],
|
||||
path = [
|
||||
[tot_x,-excess],
|
||||
[-excess,-excess],
|
||||
[-excess,tot_y],
|
||||
for (pat = data) each
|
||||
pat[0]=="step"? [pat[2]] :
|
||||
pat[0]=="xstep"? [pat[2]] :
|
||||
pat[0]=="ystep"? [pat[2]] :
|
||||
let(
|
||||
r = pat[1],
|
||||
steps = segs(abs(r)),
|
||||
step = 90/steps
|
||||
) [
|
||||
for (i=[0:1:steps]) let(
|
||||
a = pat[0]=="round"? (180+i*step) : (90-i*step)
|
||||
) pat[2] + abs(r)*[cos(a),sin(a)]
|
||||
]
|
||||
],
|
||||
path2 = deduplicate(path)
|
||||
) reorient(anchor,spin, two_d=true, path=path2, p=path2);
|
||||
|
||||
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
//////////////////////////////////////////////////////////////////////
|
||||
// LibFile: masks.scad
|
||||
// Masking shapes.
|
||||
// LibFile: masks3d.scad
|
||||
// This file defines 3D masks for applying chamfers, roundovers, and teardrop roundovers to straight edges and circular
|
||||
// edges in three dimensions.
|
||||
// Includes:
|
||||
// include <BOSL2/std.scad>
|
||||
//////////////////////////////////////////////////////////////////////
|
504
shapes2d.scad
504
shapes2d.scad
|
@ -1,15 +1,13 @@
|
|||
//////////////////////////////////////////////////////////////////////
|
||||
// LibFile: shapes2d.scad
|
||||
// This file includes redefinitions of the core modules to
|
||||
// work with attachment. You can also create regular polygons
|
||||
// work with attachment, and functional forms of those modules
|
||||
// that produce paths. You can create regular polygons
|
||||
// with optional rounded corners and alignment features not
|
||||
// available with circle(). The file also provides teardrop2d,
|
||||
// which is useful for 3d printable holes. Lastly you can use the
|
||||
// masks to produce edge treatments common in furniture from the
|
||||
// simple roundover or cove molding to the more elaborate ogee.
|
||||
// which is useful for 3D printable holes.
|
||||
// Many of the commands have module forms that produce geometry and
|
||||
// function forms that produce a path. This file defines function
|
||||
// forms of the core OpenSCAD modules that produce paths.
|
||||
// function forms that produce a path.
|
||||
// Includes:
|
||||
// include <BOSL2/std.scad>
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
@ -1224,498 +1222,4 @@ function reuleaux_polygon(N=3, r, d, anchor=CENTER, spin=0) =
|
|||
) reorient(anchor,spin, two_d=true, path=path, anchors=anchors, p=path);
|
||||
|
||||
|
||||
// Section: 2D Masking Shapes
|
||||
|
||||
// Function&Module: mask2d_roundover()
|
||||
// Usage: As Module
|
||||
// mask2d_roundover(r|d, [inset], [excess]);
|
||||
// Usage: With Attachments
|
||||
// mask2d_roundover(r|d, [inset], [excess]) { attachments }
|
||||
// Usage: As Module
|
||||
// path = mask2d_roundover(r|d, [inset], [excess]);
|
||||
// Topics: Shapes (2D), Paths (2D), Path Generators, Attachable, Masks (2D)
|
||||
// See Also: corner_profile(), edge_profile(), face_profile()
|
||||
// Description:
|
||||
// Creates a 2D roundover/bead mask shape that is useful for extruding into a 3D mask for a 90º edge.
|
||||
// This 2D mask is designed to be differenced away from the edge of a shape that is in the first (X+Y+) quadrant.
|
||||
// If called as a function, this just returns a 2D path of the outline of the mask shape.
|
||||
// Arguments:
|
||||
// r = Radius of the roundover.
|
||||
// inset = Optional bead inset size. Default: 0
|
||||
// excess = Extra amount of mask shape to creates on the X- and Y- sides of the shape. Default: 0.01
|
||||
// ---
|
||||
// d = Diameter of the roundover.
|
||||
// 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): 2D Roundover Mask
|
||||
// mask2d_roundover(r=10);
|
||||
// Example(2D): 2D Bead Mask
|
||||
// mask2d_roundover(r=10,inset=2);
|
||||
// Example: Masking by Edge Attachment
|
||||
// diff("mask")
|
||||
// cube([50,60,70],center=true)
|
||||
// edge_profile([TOP,"Z"],except=[BACK,TOP+LEFT])
|
||||
// mask2d_roundover(r=10, inset=2);
|
||||
module mask2d_roundover(r, inset=0, excess=0.01, d, anchor=CENTER,spin=0) {
|
||||
path = mask2d_roundover(r=r,d=d,excess=excess,inset=inset);
|
||||
attachable(anchor,spin, two_d=true, path=path) {
|
||||
polygon(path);
|
||||
children();
|
||||
}
|
||||
}
|
||||
|
||||
function mask2d_roundover(r, inset=0, excess=0.01, d, anchor=CENTER,spin=0) =
|
||||
assert(is_num(r)||is_num(d))
|
||||
assert(is_undef(excess)||is_num(excess))
|
||||
assert(is_num(inset)||(is_vector(inset)&&len(inset)==2))
|
||||
let(
|
||||
inset = is_list(inset)? inset : [inset,inset],
|
||||
excess = default(excess,$overlap),
|
||||
r = get_radius(r=r,d=d,dflt=1),
|
||||
steps = quantup(segs(r),4)/4,
|
||||
step = 90/steps,
|
||||
path = [
|
||||
[r+inset.x,-excess],
|
||||
[-excess,-excess],
|
||||
[-excess, r+inset.y],
|
||||
for (i=[0:1:steps]) [r,r] + inset + polar_to_xy(r,180+i*step)
|
||||
]
|
||||
) reorient(anchor,spin, two_d=true, path=path, extent=false, p=path);
|
||||
|
||||
|
||||
// Function&Module: mask2d_cove()
|
||||
// Usage: As Module
|
||||
// mask2d_cove(r|d, [inset], [excess]);
|
||||
// Usage: With Attachments
|
||||
// mask2d_cove(r|d, [inset], [excess]) { attachments }
|
||||
// Usage: As Function
|
||||
// path = mask2d_cove(r|d, [inset], [excess]);
|
||||
// Topics: Shapes (2D), Paths (2D), Path Generators, Attachable, Masks (2D)
|
||||
// See Also: corner_profile(), edge_profile(), face_profile()
|
||||
// Description:
|
||||
// Creates a 2D cove mask shape that is useful for extruding into a 3D mask for a 90º edge.
|
||||
// This 2D mask is designed to be differenced away from the edge of a shape that is in the first (X+Y+) quadrant.
|
||||
// If called as a function, this just returns a 2D path of the outline of the mask shape.
|
||||
// Arguments:
|
||||
// r = Radius of the cove.
|
||||
// inset = Optional amount to inset code from corner. Default: 0
|
||||
// excess = Extra amount of mask shape to creates on the X- and Y- sides of the shape. Default: 0.01
|
||||
// ---
|
||||
// d = Diameter of the cove.
|
||||
// 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): 2D Cove Mask
|
||||
// mask2d_cove(r=10);
|
||||
// Example(2D): 2D Inset Cove Mask
|
||||
// mask2d_cove(r=10,inset=3);
|
||||
// Example: Masking by Edge Attachment
|
||||
// diff("mask")
|
||||
// cube([50,60,70],center=true)
|
||||
// edge_profile([TOP,"Z"],except=[BACK,TOP+LEFT])
|
||||
// mask2d_cove(r=10, inset=2);
|
||||
module mask2d_cove(r, inset=0, excess=0.01, d, anchor=CENTER,spin=0) {
|
||||
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, inset=0, excess=0.01, d, anchor=CENTER,spin=0) =
|
||||
assert(is_num(r)||is_num(d))
|
||||
assert(is_undef(excess)||is_num(excess))
|
||||
assert(is_num(inset)||(is_vector(inset)&&len(inset)==2))
|
||||
let(
|
||||
inset = is_list(inset)? inset : [inset,inset],
|
||||
excess = default(excess,$overlap),
|
||||
r = get_radius(r=r,d=d,dflt=1),
|
||||
steps = quantup(segs(r),4)/4,
|
||||
step = 90/steps,
|
||||
path = [
|
||||
[r+inset.x,-excess],
|
||||
[-excess,-excess],
|
||||
[-excess, r+inset.y],
|
||||
for (i=[0:1:steps]) inset + polar_to_xy(r,90-i*step)
|
||||
]
|
||||
) reorient(anchor,spin, two_d=true, path=path, p=path);
|
||||
|
||||
|
||||
// Function&Module: mask2d_chamfer()
|
||||
// Usage: As Module
|
||||
// mask2d_chamfer(edge, [angle], [inset], [excess]);
|
||||
// mask2d_chamfer(y, [angle], [inset], [excess]);
|
||||
// mask2d_chamfer(x, [angle], [inset], [excess]);
|
||||
// Usage: With Attachments
|
||||
// mask2d_chamfer(edge, [angle], [inset], [excess]) { attachments }
|
||||
// Usage: As Function
|
||||
// path = mask2d_chamfer(edge, [angle], [inset], [excess]);
|
||||
// path = mask2d_chamfer(y, [angle], [inset], [excess]);
|
||||
// path = mask2d_chamfer(x, [angle], [inset], [excess]);
|
||||
// Topics: Shapes (2D), Paths (2D), Path Generators, Attachable, Masks (2D)
|
||||
// See Also: corner_profile(), edge_profile(), face_profile()
|
||||
// Description:
|
||||
// Creates a 2D chamfer mask shape that is useful for extruding into a 3D mask for a 90º edge.
|
||||
// This 2D mask is designed to be differenced away from the edge of a shape that is in the first (X+Y+) quadrant.
|
||||
// If called as a function, this just returns a 2D path of the outline of the mask shape.
|
||||
// Arguments:
|
||||
// edge = The length of the edge of the chamfer.
|
||||
// angle = The angle of the chamfer edge, away from vertical. Default: 45.
|
||||
// inset = Optional amount to inset code from corner. Default: 0
|
||||
// excess = Extra amount of mask shape to creates on the X- and Y- sides of the shape. Default: 0.01
|
||||
// ---
|
||||
// x = The width of the chamfer.
|
||||
// y = The height of the chamfer.
|
||||
// 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): 2D Chamfer Mask
|
||||
// mask2d_chamfer(x=10);
|
||||
// Example(2D): 2D Chamfer Mask by Width.
|
||||
// mask2d_chamfer(x=10, angle=30);
|
||||
// Example(2D): 2D Chamfer Mask by Height.
|
||||
// mask2d_chamfer(y=10, angle=30);
|
||||
// Example(2D): 2D Inset Chamfer Mask
|
||||
// mask2d_chamfer(x=10, inset=2);
|
||||
// Example: Masking by Edge Attachment
|
||||
// diff("mask")
|
||||
// cube([50,60,70],center=true)
|
||||
// edge_profile([TOP,"Z"],except=[BACK,TOP+LEFT])
|
||||
// mask2d_chamfer(x=10, inset=2);
|
||||
module mask2d_chamfer(edge, angle=45, inset=0, excess=0.01, x, y, anchor=CENTER,spin=0) {
|
||||
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(edge, angle=45, inset=0, excess=0.01, x, y, anchor=CENTER,spin=0) =
|
||||
assert(num_defined([x,y,edge])==1)
|
||||
assert(is_num(first_defined([x,y,edge])))
|
||||
assert(is_num(angle))
|
||||
assert(is_undef(excess)||is_num(excess))
|
||||
assert(is_num(inset)||(is_vector(inset)&&len(inset)==2))
|
||||
let(
|
||||
inset = is_list(inset)? inset : [inset,inset],
|
||||
excess = default(excess,$overlap),
|
||||
x = !is_undef(x)? x :
|
||||
!is_undef(y)? adj_ang_to_opp(adj=y,ang=angle) :
|
||||
hyp_ang_to_opp(hyp=edge,ang=angle),
|
||||
y = opp_ang_to_adj(opp=x,ang=angle),
|
||||
path = [
|
||||
[x+inset.x, -excess],
|
||||
[-excess, -excess],
|
||||
[-excess, y+inset.y],
|
||||
[inset.x, y+inset.y],
|
||||
[x+inset.x, inset.y]
|
||||
]
|
||||
) reorient(anchor,spin, two_d=true, path=path, extent=true, p=path);
|
||||
|
||||
|
||||
// Function&Module: mask2d_rabbet()
|
||||
// Usage: As Module
|
||||
// mask2d_rabbet(size, [excess]);
|
||||
// Usage: With Attachments
|
||||
// mask2d_rabbet(size, [excess]) { attachments }
|
||||
// Usage: As Function
|
||||
// path = mask2d_rabbet(size, [excess]);
|
||||
// Topics: Shapes (2D), Paths (2D), Path Generators, Attachable, Masks (2D)
|
||||
// See Also: corner_profile(), edge_profile(), face_profile()
|
||||
// Description:
|
||||
// Creates a 2D rabbet mask shape that is useful for extruding into a 3D mask for a 90º edge.
|
||||
// This 2D mask is designed to be differenced away from the edge of a shape that is in the first (X+Y+) quadrant.
|
||||
// If called as a function, this just returns a 2D path of the outline of the mask shape.
|
||||
// Arguments:
|
||||
// size = The size of the rabbet, either as a scalar or an [X,Y] list.
|
||||
// excess = Extra amount of mask shape to creates on the X- and Y- sides of the shape. Default: 0.01
|
||||
// ---
|
||||
// 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): 2D Rabbet Mask
|
||||
// mask2d_rabbet(size=10);
|
||||
// Example(2D): 2D Asymmetrical Rabbet Mask
|
||||
// mask2d_rabbet(size=[5,10]);
|
||||
// Example: Masking by Edge Attachment
|
||||
// diff("mask")
|
||||
// cube([50,60,70],center=true)
|
||||
// edge_profile([TOP,"Z"],except=[BACK,TOP+LEFT])
|
||||
// mask2d_rabbet(size=10);
|
||||
module mask2d_rabbet(size, excess=0.01, anchor=CENTER,spin=0) {
|
||||
path = mask2d_rabbet(size=size, excess=excess);
|
||||
attachable(anchor,spin, two_d=true, path=path, extent=false) {
|
||||
polygon(path);
|
||||
children();
|
||||
}
|
||||
}
|
||||
|
||||
function mask2d_rabbet(size, excess=0.01, anchor=CENTER,spin=0) =
|
||||
assert(is_num(size)||(is_vector(size)&&len(size)==2))
|
||||
assert(is_undef(excess)||is_num(excess))
|
||||
let(
|
||||
excess = default(excess,$overlap),
|
||||
size = is_list(size)? size : [size,size],
|
||||
path = [
|
||||
[size.x, -excess],
|
||||
[-excess, -excess],
|
||||
[-excess, size.y],
|
||||
size
|
||||
]
|
||||
) reorient(anchor,spin, two_d=true, path=path, extent=false, p=path);
|
||||
|
||||
|
||||
// Function&Module: mask2d_dovetail()
|
||||
// Usage: As Module
|
||||
// mask2d_dovetail(edge, [angle], [inset], [shelf], [excess], ...);
|
||||
// mask2d_dovetail(x=, [angle=], [inset=], [shelf=], [excess=], ...);
|
||||
// mask2d_dovetail(y=, [angle=], [inset=], [shelf=], [excess=], ...);
|
||||
// Usage: With Attachments
|
||||
// mask2d_dovetail(edge, [angle], [inset], [shelf], ...) { attachments }
|
||||
// Usage: As Function
|
||||
// path = mask2d_dovetail(edge, [angle], [inset], [shelf], [excess]);
|
||||
// Topics: Shapes (2D), Paths (2D), Path Generators, Attachable, Masks (2D)
|
||||
// See Also: corner_profile(), edge_profile(), face_profile()
|
||||
// Description:
|
||||
// Creates a 2D dovetail mask shape that is useful for extruding into a 3D mask for a 90º edge.
|
||||
// This 2D mask is designed to be differenced away from the edge of a shape that is in the first (X+Y+) quadrant.
|
||||
// If called as a function, this just returns a 2D path of the outline of the mask shape.
|
||||
// Arguments:
|
||||
// edge = The length of the edge of the dovetail.
|
||||
// angle = The angle of the chamfer edge, away from vertical. Default: 30.
|
||||
// inset = Optional amount to inset code from corner. Default: 0
|
||||
// shelf = The extra height to add to the inside corner of the dovetail. Default: 0
|
||||
// excess = Extra amount of mask shape to creates on the X- and Y- sides of the shape. Default: 0.01
|
||||
// ---
|
||||
// x = The width of the dovetail.
|
||||
// y = The height of the dovetail.
|
||||
// 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): 2D Dovetail Mask
|
||||
// mask2d_dovetail(x=10);
|
||||
// Example(2D): 2D Dovetail Mask by Width.
|
||||
// mask2d_dovetail(x=10, angle=30);
|
||||
// Example(2D): 2D Dovetail Mask by Height.
|
||||
// mask2d_dovetail(y=10, angle=30);
|
||||
// Example(2D): 2D Inset Dovetail Mask
|
||||
// mask2d_dovetail(x=10, inset=2);
|
||||
// Example: Masking by Edge Attachment
|
||||
// diff("mask")
|
||||
// cube([50,60,70],center=true)
|
||||
// edge_profile([TOP,"Z"],except=[BACK,TOP+LEFT])
|
||||
// mask2d_dovetail(x=10, inset=2);
|
||||
module mask2d_dovetail(edge, angle=30, inset=0, shelf=0, excess=0.01, x, y, anchor=CENTER, spin=0) {
|
||||
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(edge, angle=30, inset=0, shelf=0, excess=0.01, x, y, anchor=CENTER, spin=0) =
|
||||
assert(num_defined([x,y,edge])==1)
|
||||
assert(is_num(first_defined([x,y,edge])))
|
||||
assert(is_num(angle))
|
||||
assert(is_undef(excess)||is_num(excess))
|
||||
assert(is_num(inset)||(is_vector(inset)&&len(inset)==2))
|
||||
let(
|
||||
inset = is_list(inset)? inset : [inset,inset],
|
||||
excess = default(excess,$overlap),
|
||||
x = !is_undef(x)? x :
|
||||
!is_undef(y)? adj_ang_to_opp(adj=y,ang=angle) :
|
||||
hyp_ang_to_opp(hyp=edge,ang=angle),
|
||||
y = opp_ang_to_adj(opp=x,ang=angle),
|
||||
path = [
|
||||
[inset.x,0],
|
||||
[-excess, 0],
|
||||
[-excess, y+inset.y+shelf],
|
||||
inset+[x,y+shelf],
|
||||
inset+[x,y],
|
||||
inset
|
||||
]
|
||||
) reorient(anchor,spin, two_d=true, path=path, p=path);
|
||||
|
||||
|
||||
// Function&Module: mask2d_teardrop()
|
||||
// Usage: As Module
|
||||
// mask2d_teardrop(r|d, [angle], [excess]);
|
||||
// Usage: With Attachments
|
||||
// mask2d_teardrop(r|d, [angle], [excess]) { attachments }
|
||||
// Usage: As Function
|
||||
// path = mask2d_teardrop(r|d, [angle], [excess]);
|
||||
// Topics: Shapes (2D), Paths (2D), Path Generators, Attachable, Masks (2D)
|
||||
// See Also: corner_profile(), edge_profile(), face_profile()
|
||||
// Description:
|
||||
// Creates a 2D teardrop mask shape that is useful for extruding into a 3D mask for a 90º edge.
|
||||
// This 2D mask is designed to be differenced away from the edge of a shape that is in the first (X+Y+) quadrant.
|
||||
// If called as a function, this just returns a 2D path of the outline of the mask shape.
|
||||
// This is particularly useful to make partially rounded bottoms, that don't need support to print.
|
||||
// Arguments:
|
||||
// r = Radius of the rounding.
|
||||
// angle = The maximum angle from vertical.
|
||||
// excess = Extra amount of mask shape to creates on the X- and Y- sides of the shape. Default: 0.01
|
||||
// ---
|
||||
// d = Diameter of the rounding.
|
||||
// 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): 2D Teardrop Mask
|
||||
// mask2d_teardrop(r=10);
|
||||
// Example(2D): Using a Custom Angle
|
||||
// mask2d_teardrop(r=10,angle=30);
|
||||
// Example: Masking by Edge Attachment
|
||||
// diff("mask")
|
||||
// cube([50,60,70],center=true)
|
||||
// edge_profile(BOT)
|
||||
// mask2d_teardrop(r=10, angle=40);
|
||||
function mask2d_teardrop(r, angle=45, excess=0.01, d, anchor=CENTER, spin=0) =
|
||||
assert(is_num(angle))
|
||||
assert(angle>0 && angle<90)
|
||||
assert(is_num(excess))
|
||||
let(
|
||||
r = get_radius(r=r, d=d, dflt=1),
|
||||
n = ceil(segs(r) * angle/360),
|
||||
cp = [r,r],
|
||||
tp = cp + polar_to_xy(r,180+angle),
|
||||
bp = [tp.x+adj_ang_to_opp(tp.y,angle), 0],
|
||||
step = angle/n,
|
||||
path = [
|
||||
bp, bp-[0,excess], [-excess,-excess], [-excess,r],
|
||||
for (i=[0:1:n]) cp+polar_to_xy(r,180+i*step)
|
||||
]
|
||||
) reorient(anchor,spin, two_d=true, path=path, p=path);
|
||||
|
||||
module mask2d_teardrop(r, angle=45, excess=0.01, d, anchor=CENTER, spin=0) {
|
||||
path = mask2d_teardrop(r=r, d=d, angle=angle, excess=excess);
|
||||
attachable(anchor,spin, two_d=true, path=path) {
|
||||
polygon(path);
|
||||
children();
|
||||
}
|
||||
}
|
||||
|
||||
// Function&Module: mask2d_ogee()
|
||||
// Usage: As Module
|
||||
// mask2d_ogee(pattern, [excess], ...);
|
||||
// Usage: With Attachments
|
||||
// mask2d_ogee(pattern, [excess], ...) { attachments }
|
||||
// Usage: As Function
|
||||
// path = mask2d_ogee(pattern, [excess], ...);
|
||||
// Topics: Shapes (2D), Paths (2D), Path Generators, Attachable, Masks (2D)
|
||||
// See Also: corner_profile(), edge_profile(), face_profile()
|
||||
//
|
||||
// Description:
|
||||
// Creates a 2D Ogee mask shape that is useful for extruding into a 3D mask for a 90º edge.
|
||||
// This 2D mask is designed to be `difference()`d away from the edge of a shape that is in the first (X+Y+) quadrant.
|
||||
// Since there are a number of shapes that fall under the name ogee, the shape of this mask is given as a pattern.
|
||||
// Patterns are given as TYPE, VALUE pairs. ie: `["fillet",10, "xstep",2, "step",[5,5], ...]`. See Patterns below.
|
||||
// If called as a function, this just returns a 2D path of the outline of the mask shape.
|
||||
// .
|
||||
// ### Patterns
|
||||
// .
|
||||
// Type | Argument | Description
|
||||
// -------- | --------- | ----------------
|
||||
// "step" | [x,y] | Makes a line to a point `x` right and `y` down.
|
||||
// "xstep" | dist | Makes a `dist` length line towards X+.
|
||||
// "ystep" | dist | Makes a `dist` length line towards Y-.
|
||||
// "round" | radius | Makes an arc that will mask a roundover.
|
||||
// "fillet" | radius | Makes an arc that will mask a fillet.
|
||||
//
|
||||
// Arguments:
|
||||
// pattern = A list of pattern pieces to describe the Ogee.
|
||||
// excess = Extra amount of mask shape to creates on the X- and Y- sides of the shape. Default: 0.01
|
||||
// ---
|
||||
// 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): 2D Ogee Mask
|
||||
// mask2d_ogee([
|
||||
// "xstep",1, "ystep",1, // Starting shoulder.
|
||||
// "fillet",5, "round",5, // S-curve.
|
||||
// "ystep",1, "xstep",1 // Ending shoulder.
|
||||
// ]);
|
||||
// Example: Masking by Edge Attachment
|
||||
// diff("mask")
|
||||
// cube([50,60,70],center=true)
|
||||
// edge_profile(TOP)
|
||||
// mask2d_ogee([
|
||||
// "xstep",1, "ystep",1, // Starting shoulder.
|
||||
// "fillet",5, "round",5, // S-curve.
|
||||
// "ystep",1, "xstep",1 // Ending shoulder.
|
||||
// ]);
|
||||
module mask2d_ogee(pattern, excess=0.01, anchor=CENTER,spin=0) {
|
||||
path = mask2d_ogee(pattern, excess=excess);
|
||||
attachable(anchor,spin, two_d=true, path=path) {
|
||||
polygon(path);
|
||||
children();
|
||||
}
|
||||
}
|
||||
|
||||
function mask2d_ogee(pattern, excess=0.01, anchor=CENTER, spin=0) =
|
||||
assert(is_list(pattern))
|
||||
assert(len(pattern)>0)
|
||||
assert(len(pattern)%2==0,"pattern must be a list of TYPE, VAL pairs.")
|
||||
assert(all([for (i = idx(pattern,step=2)) in_list(pattern[i],["step","xstep","ystep","round","fillet"])]))
|
||||
let(
|
||||
excess = default(excess,$overlap),
|
||||
x = concat([0], cumsum([
|
||||
for (i=idx(pattern,step=2)) let(
|
||||
type = pattern[i],
|
||||
val = pattern[i+1]
|
||||
) (
|
||||
type=="step"? val.x :
|
||||
type=="xstep"? val :
|
||||
type=="round"? val :
|
||||
type=="fillet"? val :
|
||||
0
|
||||
)
|
||||
])),
|
||||
y = concat([0], cumsum([
|
||||
for (i=idx(pattern,step=2)) let(
|
||||
type = pattern[i],
|
||||
val = pattern[i+1]
|
||||
) (
|
||||
type=="step"? val.y :
|
||||
type=="ystep"? val :
|
||||
type=="round"? val :
|
||||
type=="fillet"? val :
|
||||
0
|
||||
)
|
||||
])),
|
||||
tot_x = last(x),
|
||||
tot_y = last(y),
|
||||
data = [
|
||||
for (i=idx(pattern,step=2)) let(
|
||||
type = pattern[i],
|
||||
val = pattern[i+1],
|
||||
pt = [x[i/2], tot_y-y[i/2]] + (
|
||||
type=="step"? [val.x,-val.y] :
|
||||
type=="xstep"? [val,0] :
|
||||
type=="ystep"? [0,-val] :
|
||||
type=="round"? [val,0] :
|
||||
type=="fillet"? [0,-val] :
|
||||
[0,0]
|
||||
)
|
||||
) [type, val, pt]
|
||||
],
|
||||
path = [
|
||||
[tot_x,-excess],
|
||||
[-excess,-excess],
|
||||
[-excess,tot_y],
|
||||
for (pat = data) each
|
||||
pat[0]=="step"? [pat[2]] :
|
||||
pat[0]=="xstep"? [pat[2]] :
|
||||
pat[0]=="ystep"? [pat[2]] :
|
||||
let(
|
||||
r = pat[1],
|
||||
steps = segs(abs(r)),
|
||||
step = 90/steps
|
||||
) [
|
||||
for (i=[0:1:steps]) let(
|
||||
a = pat[0]=="round"? (180+i*step) : (90-i*step)
|
||||
) pat[2] + abs(r)*[cos(a),sin(a)]
|
||||
]
|
||||
],
|
||||
path2 = deduplicate(path)
|
||||
) reorient(anchor,spin, two_d=true, path=path2, p=path2);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
|
||||
|
|
3
std.scad
3
std.scad
|
@ -17,7 +17,8 @@ include <attachments.scad>
|
|||
include <shapes3d.scad>
|
||||
include <shapes2d.scad>
|
||||
include <drawing.scad>
|
||||
include <masks.scad>
|
||||
include <masks3d.scad>
|
||||
include <masks2d.scad>
|
||||
include <paths.scad>
|
||||
include <edges.scad>
|
||||
include <lists.scad>
|
||||
|
|
|
@ -164,6 +164,16 @@ module test_all_zero() {
|
|||
test_all_zero();
|
||||
|
||||
|
||||
module test_all_equal() {
|
||||
assert(all_equal([1,1,1,1]));
|
||||
assert(all_equal([[3,4],[3,4],[3,4]]));
|
||||
assert(!all_equal([1,2,1,1]));
|
||||
assert(!all_equal([1,1.001,1,1.001,.999]));
|
||||
assert(all_equal([1,1.001,1,1.001,.999],eps=.01));
|
||||
}
|
||||
test_all_equal();
|
||||
|
||||
|
||||
module test_all_nonzero() {
|
||||
assert(!all_nonzero(0));
|
||||
assert(!all_nonzero([0,0,0]));
|
||||
|
|
|
@ -126,95 +126,5 @@ module test_reuleaux_polygon() {
|
|||
test_reuleaux_polygon();
|
||||
|
||||
|
||||
module test_mask2d_chamfer() {
|
||||
assert_approx(mask2d_chamfer(x=10),[[10,-0.01],[-0.01,-0.01],[-0.01,10],[0,10],[10,0]]);
|
||||
assert_approx(mask2d_chamfer(y=10),[[10,-0.01],[-0.01,-0.01],[-0.01,10],[0,10],[10,0]]);
|
||||
assert_approx(mask2d_chamfer(edge=10),[[7.07106781187,-0.01],[-0.01,-0.01],[-0.01,7.07106781187],[0,7.07106781187],[7.07106781187,0]]);
|
||||
assert_approx(mask2d_chamfer(x=10,angle=30),[[10,-0.01],[-0.01,-0.01],[-0.01,17.3205080757],[0,17.3205080757],[10,0]]);
|
||||
assert_approx(mask2d_chamfer(y=10,angle=30),[[5.7735026919,-0.01],[-0.01,-0.01],[-0.01,10],[0,10],[5.7735026919,0]]);
|
||||
assert_approx(mask2d_chamfer(edge=10,angle=30),[[5,-0.01],[-0.01,-0.01],[-0.01,8.66025403784],[0,8.66025403784],[5,0]]);
|
||||
assert_approx(mask2d_chamfer(x=10,angle=30,inset=1),[[11,-0.01],[-0.01,-0.01],[-0.01,18.3205080757],[1,18.3205080757],[11,1]]);
|
||||
assert_approx(mask2d_chamfer(y=10,angle=30,inset=1),[[6.7735026919,-0.01],[-0.01,-0.01],[-0.01,11],[1,11],[6.7735026919,1]]);
|
||||
assert_approx(mask2d_chamfer(edge=10,angle=30,inset=1),[[6,-0.01],[-0.01,-0.01],[-0.01,9.66025403784],[1,9.66025403784],[6,1]]);
|
||||
assert_approx(mask2d_chamfer(x=10,angle=30,inset=1,excess=1),[[11,-1],[-1,-1],[-1,18.3205080757],[1,18.3205080757],[11,1]]);
|
||||
assert_approx(mask2d_chamfer(y=10,angle=30,inset=1,excess=1),[[6.7735026919,-1],[-1,-1],[-1,11],[1,11],[6.7735026919,1]]);
|
||||
assert_approx(mask2d_chamfer(edge=10,angle=30,inset=1,excess=1),[[6,-1],[-1,-1],[-1,9.66025403784],[1,9.66025403784],[6,1]]);
|
||||
}
|
||||
test_mask2d_chamfer();
|
||||
|
||||
|
||||
module test_mask2d_cove() {
|
||||
$fn = 24;
|
||||
assert_approx(mask2d_cove(r=10),[[10,-0.01],[-0.01,-0.01],[-0.01,10],[0,10],[2.58819045103,9.65925826289],[5,8.66025403784],[7.07106781187,7.07106781187],[8.66025403784,5],[9.65925826289,2.58819045103],[10,0]]);
|
||||
assert_approx(mask2d_cove(d=20),[[10,-0.01],[-0.01,-0.01],[-0.01,10],[0,10],[2.58819045103,9.65925826289],[5,8.66025403784],[7.07106781187,7.07106781187],[8.66025403784,5],[9.65925826289,2.58819045103],[10,0]]);
|
||||
assert_approx(mask2d_cove(r=10,inset=1),[[11,-0.01],[-0.01,-0.01],[-0.01,11],[1,11],[3.58819045103,10.6592582629],[6,9.66025403784],[8.07106781187,8.07106781187],[9.66025403784,6],[10.6592582629,3.58819045103],[11,1]]);
|
||||
assert_approx(mask2d_cove(d=20,inset=1),[[11,-0.01],[-0.01,-0.01],[-0.01,11],[1,11],[3.58819045103,10.6592582629],[6,9.66025403784],[8.07106781187,8.07106781187],[9.66025403784,6],[10.6592582629,3.58819045103],[11,1]]);
|
||||
assert_approx(mask2d_cove(r=10,inset=1,excess=1),[[11,-1],[-1,-1],[-1,11],[1,11],[3.58819045103,10.6592582629],[6,9.66025403784],[8.07106781187,8.07106781187],[9.66025403784,6],[10.6592582629,3.58819045103],[11,1]]);
|
||||
assert_approx(mask2d_cove(d=20,inset=1,excess=1),[[11,-1],[-1,-1],[-1,11],[1,11],[3.58819045103,10.6592582629],[6,9.66025403784],[8.07106781187,8.07106781187],[9.66025403784,6],[10.6592582629,3.58819045103],[11,1]]);
|
||||
}
|
||||
test_mask2d_cove();
|
||||
|
||||
|
||||
module test_mask2d_roundover() {
|
||||
$fn = 24;
|
||||
assert_approx(mask2d_roundover(r=10),[[10,-0.01],[-0.01,-0.01],[-0.01,10],[0,10],[0.340741737109,7.41180954897],[1.33974596216,5],[2.92893218813,2.92893218813],[5,1.33974596216],[7.41180954897,0.340741737109],[10,0]]);
|
||||
assert_approx(mask2d_roundover(d=20),[[10,-0.01],[-0.01,-0.01],[-0.01,10],[0,10],[0.340741737109,7.41180954897],[1.33974596216,5],[2.92893218813,2.92893218813],[5,1.33974596216],[7.41180954897,0.340741737109],[10,0]]);
|
||||
assert_approx(mask2d_roundover(r=10,inset=1),[[11,-0.01],[-0.01,-0.01],[-0.01,11],[1,11],[1.34074173711,8.41180954897],[2.33974596216,6],[3.92893218813,3.92893218813],[6,2.33974596216],[8.41180954897,1.34074173711],[11,1]]);
|
||||
assert_approx(mask2d_roundover(d=20,inset=1),[[11,-0.01],[-0.01,-0.01],[-0.01,11],[1,11],[1.34074173711,8.41180954897],[2.33974596216,6],[3.92893218813,3.92893218813],[6,2.33974596216],[8.41180954897,1.34074173711],[11,1]]);
|
||||
assert_approx(mask2d_roundover(r=10,inset=1,excess=1),[[11,-1],[-1,-1],[-1,11],[1,11],[1.34074173711,8.41180954897],[2.33974596216,6],[3.92893218813,3.92893218813],[6,2.33974596216],[8.41180954897,1.34074173711],[11,1]]);
|
||||
assert_approx(mask2d_roundover(d=20,inset=1,excess=1),[[11,-1],[-1,-1],[-1,11],[1,11],[1.34074173711,8.41180954897],[2.33974596216,6],[3.92893218813,3.92893218813],[6,2.33974596216],[8.41180954897,1.34074173711],[11,1]]);
|
||||
}
|
||||
test_mask2d_roundover();
|
||||
|
||||
|
||||
module test_mask2d_dovetail() {
|
||||
assert_approx(mask2d_dovetail(x=10),[[0,0],[-0.01,0],[-0.01,17.3205080757],[10,17.3205080757],[10,17.3205080757],[0,0]]);
|
||||
assert_approx(mask2d_dovetail(y=10),[[0,0],[-0.01,0],[-0.01,10],[5.7735026919,10],[5.7735026919,10],[0,0]]);
|
||||
assert_approx(mask2d_dovetail(edge=10),[[0,0],[-0.01,0],[-0.01,8.66025403784],[5,8.66025403784],[5,8.66025403784],[0,0]]);
|
||||
assert_approx(mask2d_dovetail(x=10,angle=30),[[0,0],[-0.01,0],[-0.01,17.3205080757],[10,17.3205080757],[10,17.3205080757],[0,0]]);
|
||||
assert_approx(mask2d_dovetail(y=10,angle=30),[[0,0],[-0.01,0],[-0.01,10],[5.7735026919,10],[5.7735026919,10],[0,0]]);
|
||||
assert_approx(mask2d_dovetail(edge=10,angle=30),[[0,0],[-0.01,0],[-0.01,8.66025403784],[5,8.66025403784],[5,8.66025403784],[0,0]]);
|
||||
assert_approx(mask2d_dovetail(x=10,angle=30,inset=1),[[1,0],[-0.01,0],[-0.01,18.3205080757],[11,18.3205080757],[11,18.3205080757],[1,1]]);
|
||||
assert_approx(mask2d_dovetail(y=10,angle=30,inset=1),[[1,0],[-0.01,0],[-0.01,11],[6.7735026919,11],[6.7735026919,11],[1,1]]);
|
||||
assert_approx(mask2d_dovetail(edge=10,angle=30,inset=1),[[1,0],[-0.01,0],[-0.01,9.66025403784],[6,9.66025403784],[6,9.66025403784],[1,1]]);
|
||||
assert_approx(mask2d_dovetail(x=10,angle=30,inset=1,excess=1),[[1,0],[-1,0],[-1,18.3205080757],[11,18.3205080757],[11,18.3205080757],[1,1]]);
|
||||
assert_approx(mask2d_dovetail(y=10,angle=30,inset=1,excess=1),[[1,0],[-1,0],[-1,11],[6.7735026919,11],[6.7735026919,11],[1,1]]);
|
||||
assert_approx(mask2d_dovetail(edge=10,angle=30,inset=1,excess=1),[[1,0],[-1,0],[-1,9.66025403784],[6,9.66025403784],[6,9.66025403784],[1,1]]);
|
||||
}
|
||||
test_mask2d_dovetail();
|
||||
|
||||
|
||||
module test_mask2d_rabbet() {
|
||||
assert_approx(mask2d_rabbet(10), [[10,-0.01],[-0.01,-0.01],[-0.01,10],[10,10]]);
|
||||
assert_approx(mask2d_rabbet(size=10), [[10,-0.01],[-0.01,-0.01],[-0.01,10],[10,10]]);
|
||||
assert_approx(mask2d_rabbet(size=[10,15]), [[10,-0.01],[-0.01,-0.01],[-0.01,15],[10,15]]);
|
||||
assert_approx(mask2d_rabbet(size=[10,15],excess=1), [[10,-1],[-1,-1],[-1,15],[10,15]]);
|
||||
}
|
||||
test_mask2d_rabbet();
|
||||
|
||||
|
||||
module test_mask2d_teardrop() {
|
||||
$fn=24;
|
||||
assert_approx(mask2d_teardrop(r=10), [[5.85786437627,0],[5.85786437627,-0.01],[-0.01,-0.01],[-0.01,10],[0,10],[0.340741737109,7.41180954897],[1.33974596216,5],[2.92893218813,2.92893218813]]);
|
||||
assert_approx(mask2d_teardrop(d=20), [[5.85786437627,0],[5.85786437627,-0.01],[-0.01,-0.01],[-0.01,10],[0,10],[0.340741737109,7.41180954897],[1.33974596216,5],[2.92893218813,2.92893218813]]);
|
||||
assert_approx(mask2d_teardrop(r=10,angle=30), [[4.2264973081,0],[4.2264973081,-0.01],[-0.01,-0.01],[-0.01,10],[0,10],[0.340741737109,7.41180954897],[1.33974596216,5]]);
|
||||
assert_approx(mask2d_teardrop(r=10,angle=30,excess=1), [[4.2264973081,0],[4.2264973081,-1],[-1,-1],[-1,10],[0,10],[0.340741737109,7.41180954897],[1.33974596216,5]]);
|
||||
}
|
||||
test_mask2d_teardrop();
|
||||
|
||||
|
||||
module test_mask2d_ogee() {
|
||||
$fn=24;
|
||||
assert_approx(
|
||||
mask2d_ogee([
|
||||
"xstep",1, "ystep",1, // Starting shoulder.
|
||||
"fillet",5, "round",5, // S-curve.
|
||||
"ystep",1, "xstep",1 // Ending shoulder.
|
||||
]),
|
||||
[[12,-0.01],[-0.01,-0.01],[-0.01,12],[1,12],[1,11],[1.32701564615,10.9892946162],[1.6526309611,10.9572243069],[1.97545161008,10.903926402],[2.29409522551,10.8296291314],[2.60719732652,10.7346506475],[2.91341716183,10.6193976626],[3.2114434511,10.4843637077],[3.5,10.3301270189],[3.7778511651,10.1573480615],[4.04380714504,9.96676670146],[4.2967290755,9.75919903739],[4.53553390593,9.53553390593],[4.75919903739,9.2967290755],[4.96676670146,9.04380714504],[5.15734806151,8.7778511651],[5.33012701892,8.5],[5.48436370766,8.2114434511],[5.61939766256,7.91341716183],[5.73465064748,7.60719732652],[5.82962913145,7.29409522551],[5.90392640202,6.97545161008],[5.95722430687,6.6526309611],[5.98929461619,6.32701564615],[6,6],[6.01070538381,5.67298435385],[6.04277569313,5.3473690389],[6.09607359798,5.02454838992],[6.17037086855,4.70590477449],[6.26534935252,4.39280267348],[6.38060233744,4.08658283817],[6.51563629234,3.7885565489],[6.66987298108,3.5],[6.84265193849,3.2221488349],[7.03323329854,2.95619285496],[7.24080096261,2.7032709245],[7.46446609407,2.46446609407],[7.7032709245,2.24080096261],[7.95619285496,2.03323329854],[8.2221488349,1.84265193849],[8.5,1.66987298108],[8.7885565489,1.51563629234],[9.08658283817,1.38060233744],[9.39280267348,1.26534935252],[9.70590477449,1.17037086855],[10.0245483899,1.09607359798],[10.3473690389,1.04277569313],[10.6729843538,1.01070538381],[11,1],[11,0],[12,0]]
|
||||
);
|
||||
}
|
||||
test_mask2d_ogee();
|
||||
|
||||
|
||||
// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
|
||||
|
|
Loading…
Reference in a new issue