mirror of
https://github.com/BelfrySCAD/BOSL2.git
synced 2025-12-07 19:32:06 +00:00
Merge pull request #1828 from adrianVmariano/master
masks reorg + polygon_edge_mask()
This commit is contained in:
commit
fc2e57cf56
7 changed files with 2627 additions and 2541 deletions
802
attachments.scad
802
attachments.scad
|
|
@ -748,7 +748,8 @@ function _quant_anch(x) = approx(x,0) ? 0 : sign(x);
|
|||
|
||||
// Make arbitrary anchor legal for a given geometry
|
||||
function _make_anchor_legal(anchor,geom) =
|
||||
in_list(geom[0], ["prismoid","trapezoid"]) ? [for(v=anchor) _quant_anch(v)]
|
||||
is_string(anchor) ? anchor
|
||||
: in_list(geom[0], ["prismoid","trapezoid"]) ? [for(v=anchor) _quant_anch(v)]
|
||||
: in_list(geom[0], ["conoid", "extrusion_extent"]) ? [anchor.x,anchor.y, _quant_anch(anchor.z)]
|
||||
: anchor;
|
||||
|
||||
|
|
@ -2021,797 +2022,6 @@ module show_int(tags)
|
|||
}
|
||||
|
||||
|
||||
// Section: Mask Attachment
|
||||
|
||||
|
||||
// Module: face_mask()
|
||||
// Synopsis: Ataches a 3d mask shape to the given faces of the parent.
|
||||
// SynTags: Trans
|
||||
// Topics: Attachments, Masking
|
||||
// See Also: attachable(), position(), attach(), edge_mask(), corner_mask(), face_profile(), edge_profile(), corner_profile()
|
||||
// Usage:
|
||||
// PARENT() face_mask(faces) CHILDREN;
|
||||
// Description:
|
||||
// Takes a 3D mask shape, and attaches it to the given faces, with the appropriate orientation to be
|
||||
// differenced away. The mask shape should be vertically oriented (Z-aligned) with the bottom half
|
||||
// (Z-) shaped to be diffed away from the face of parent attachable shape. If no tag is set then
|
||||
// `face_mask()` sets the tag for children to "remove" so that it works with the default {{diff()}} tag.
|
||||
// For details on specifying the faces to mask see [Specifying Faces](attachments.scad#subsection-specifying-faces).
|
||||
// For a step-by-step explanation of masking attachments, see the [Attachments Tutorial](Tutorial-Attachment-Edge-Profiling).
|
||||
// Arguments:
|
||||
// edges = Faces to mask. See [Specifying Faces](attachments.scad#subsection-specifying-faces) for information on specifying faces. Default: All faces
|
||||
// Side Effects:
|
||||
// Tags the children with "remove" (and hence sets `$tag`) if no tag is already set.
|
||||
// `$idx` is set to the index number of each face in the list of faces given.
|
||||
// `$attach_anchor` is set for each face given, to the `[ANCHOR, POSITION, ORIENT, SPIN]` information for that anchor.
|
||||
// Example:
|
||||
// diff()
|
||||
// cylinder(r=30, h=60)
|
||||
// face_mask(TOP) {
|
||||
// rounding_cylinder_mask(r=30,rounding=5);
|
||||
// cuboid([5,61,10]);
|
||||
// }
|
||||
// Example: Using `$idx`
|
||||
// diff()
|
||||
// cylinder(r=30, h=60)
|
||||
// face_mask([TOP, BOT])
|
||||
// zrot(45*$idx) zrot_copies([0,90]) cuboid([5,61,10]);
|
||||
module face_mask(faces=[LEFT,RIGHT,FRONT,BACK,BOT,TOP]) {
|
||||
req_children($children);
|
||||
faces = is_vector(faces)? [faces] : faces;
|
||||
assert(all([for (face=faces) is_vector(face) && sum([for (x=face) x!=0? 1 : 0])==1]), "\nVector in faces doesn't point at a face.");
|
||||
assert($parent_geom != undef, "\nNo object to attach to!");
|
||||
attach(faces) {
|
||||
default_tag("remove") children();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Module: edge_mask()
|
||||
// Synopsis: Attaches a 3D mask shape to the given edges of the parent.
|
||||
// SynTags: Trans
|
||||
// Topics: Attachments, Masking
|
||||
// See Also: attachable(), position(), attach(), face_mask(), corner_mask(), face_profile(), edge_profile(), corner_profile()
|
||||
// Usage:
|
||||
// PARENT() edge_mask([edges], [except]) CHILDREN;
|
||||
// Description:
|
||||
// Takes a 3D mask shape, and attaches it to the given edges of a cuboid parent, with the appropriate orientation to be
|
||||
// differenced away. The mask shape should be vertically oriented (Z-aligned) with the back-right
|
||||
// quadrant (X+Y+) shaped to be diffed away from the edge of parent attachable shape. If no tag is set
|
||||
// then `edge_mask` sets the tag for children to "remove" so that it works with the default {{diff()}} tag.
|
||||
// For details on specifying the edges to mask see [Specifying Edges](attachments.scad#subsection-specifying-edges).
|
||||
// For a step-by-step explanation of masking attachments, see the [Attachments Tutorial](Tutorial-Attachment-Edge-Profiling).
|
||||
// Figure: A Typical Edge Rounding Mask
|
||||
// module roundit(l,r) difference() {
|
||||
// translate([-1,-1,-l/2])
|
||||
// cube([r+1,r+1,l]);
|
||||
// translate([r,r])
|
||||
// cylinder(h=l+1,r=r,center=true, $fn=quantup(segs(r),4));
|
||||
// }
|
||||
// roundit(l=30,r=10);
|
||||
// Arguments:
|
||||
// edges = Edges to mask. See [Specifying Edges](attachments.scad#subsection-specifying-edges). Default: All edges.
|
||||
// except = Edges to explicitly NOT mask. See [Specifying Edges](attachments.scad#subsection-specifying-edges). Default: No edges.
|
||||
// Side Effects:
|
||||
// Tags the children with "remove" (and hence sets `$tag`) if no tag is already set.
|
||||
// `$idx` is set to the index number of each edge.
|
||||
// `$attach_anchor` is set for each edge given, to the `[ANCHOR, POSITION, ORIENT, SPIN]` information for that anchor.
|
||||
// `$parent_size` is set to the size of the parent object.
|
||||
// Example:
|
||||
// diff()
|
||||
// cube([50,60,70],center=true)
|
||||
// edge_mask([TOP,"Z"],except=[BACK,TOP+LEFT])
|
||||
// rounding_edge_mask(l=71,r=10);
|
||||
module edge_mask(edges=EDGES_ALL, except=[]) {
|
||||
req_children($children);
|
||||
assert($parent_geom != undef, "\nNo object to attach to!");
|
||||
edges = _edges(edges, except=except);
|
||||
vecs = [
|
||||
for (i = [0:3], axis=[0:2])
|
||||
if (edges[axis][i]>0)
|
||||
EDGE_OFFSETS[axis][i]
|
||||
];
|
||||
for ($idx = idx(vecs)) {
|
||||
vec = vecs[$idx];
|
||||
vcount = (vec.x?1:0) + (vec.y?1:0) + (vec.z?1:0);
|
||||
dummy=assert(vcount == 2, "\nNot an edge vector!");
|
||||
anch = _find_anchor(vec, $parent_geom);
|
||||
$edge_angle = len(anch)==5 ? struct_val(anch[4],"edge_angle") : undef;
|
||||
$edge_length = len(anch)==5 ? struct_val(anch[4],"edge_length") : undef;
|
||||
$attach_to = undef;
|
||||
$attach_anchor = anch;
|
||||
rotang =
|
||||
vec.z<0? [90,0,180+v_theta(vec)] :
|
||||
vec.z==0 && sign(vec.x)==sign(vec.y)? 135+v_theta(vec) :
|
||||
vec.z==0 && sign(vec.x)!=sign(vec.y)? [0,180,45+v_theta(vec)] :
|
||||
[-90,0,180+v_theta(vec)];
|
||||
translate(anch[1]) rot(rotang)
|
||||
default_tag("remove") children();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Module: corner_mask()
|
||||
// Synopsis: Attaches a 3d mask shape to the given corners of the parent.
|
||||
// SynTags: Trans
|
||||
// Topics: Attachments, Masking
|
||||
// See Also: attachable(), position(), attach(), face_mask(), edge_mask(), face_profile(), edge_profile(), corner_profile()
|
||||
// Usage:
|
||||
// PARENT() corner_mask([corners], [except]) CHILDREN;
|
||||
// Description:
|
||||
// Takes a 3D mask shape, and attaches it to the specified corners, with the appropriate orientation to
|
||||
// be differenced away. The 3D corner mask shape should be designed to mask away the X+Y+Z+ octant. If no tag is set
|
||||
// then `corner_mask` sets the tag for children to "remove" so that it works with the default {{diff()}} tag.
|
||||
// See [Specifying Corners](attachments.scad#subsection-specifying-corners) for information on how to specify corner sets.
|
||||
// For a step-by-step explanation of masking attachments, see the [Attachments Tutorial](Tutorial-Attachment-Edge-Profiling).
|
||||
// Arguments:
|
||||
// corners = Corners to mask. See [Specifying Corners](attachments.scad#subsection-specifying-corners). Default: All corners.
|
||||
// except = Corners to explicitly NOT mask. See [Specifying Corners](attachments.scad#subsection-specifying-corners). Default: No corners.
|
||||
// Side Effects:
|
||||
// Tags the children with "remove" (and hence sets `$tag`) if no tag is already set.
|
||||
// `$idx` is set to the index number of each corner.
|
||||
// `$attach_anchor` is set for each corner given, to the `[ANCHOR, POSITION, ORIENT, SPIN]` information for that anchor.
|
||||
// Example:
|
||||
// diff()
|
||||
// cube(100, center=true)
|
||||
// corner_mask([TOP,FRONT],LEFT+FRONT+TOP)
|
||||
// difference() {
|
||||
// translate(-0.01*[1,1,1]) cube(20);
|
||||
// translate([20,20,20]) sphere(r=20);
|
||||
// }
|
||||
module corner_mask(corners=CORNERS_ALL, except=[]) {
|
||||
req_children($children);
|
||||
assert($parent_geom != undef, "\nNo object to attach to!");
|
||||
corners = _corners(corners, except=except);
|
||||
vecs = [for (i = [0:7]) if (corners[i]>0) CORNER_OFFSETS[i]];
|
||||
for ($idx = idx(vecs)) {
|
||||
vec = vecs[$idx];
|
||||
vcount = (vec.x?1:0) + (vec.y?1:0) + (vec.z?1:0);
|
||||
dummy=assert(vcount == 3, "\nNot an edge vector!");
|
||||
anch = _find_anchor(vec, $parent_geom);
|
||||
$attach_to = undef;
|
||||
$attach_anchor = anch;
|
||||
rotang = vec.z<0?
|
||||
[ 0,0,180+v_theta(vec)-45] :
|
||||
[180,0,-90+v_theta(vec)-45];
|
||||
translate(anch[1]) rot(rotang)
|
||||
default_tag("remove") children();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Module: face_profile()
|
||||
// Synopsis: Extrudes a 2D edge profile into a mask for all edges and corners of the given faces on the parent.
|
||||
// SynTags: Geom
|
||||
// Topics: Attachments, Masking
|
||||
// See Also: attachable(), position(), attach(), edge_profile(), corner_profile(), face_mask(), edge_mask(), corner_mask()
|
||||
// Usage:
|
||||
// PARENT() face_profile(faces, r|d=, [convexity=]) CHILDREN;
|
||||
// Description:
|
||||
// Given a 2D edge profile, extrudes it into a mask for all edges and corners bounding each given face. If no tag is set
|
||||
// then `face_profile` sets the tag for children to "remove" so that it works with the default {{diff()}} tag.
|
||||
// See [Specifying Faces](attachments.scad#subsection-specifying-faces) for information on specifying faces.
|
||||
// For a step-by-step explanation of masking attachments, see the [Attachments Tutorial](Tutorial-Attachment-Edge-Profiling).
|
||||
// Arguments:
|
||||
// faces = Faces to mask edges and corners of.
|
||||
// r = Radius of corner mask.
|
||||
// ---
|
||||
// d = Diameter of corner mask.
|
||||
// excess = Excess length to extrude the profile to make edge masks. Default: 0.01
|
||||
// convexity = Max number of times a line could intersect the perimeter of the mask shape. Default: 10
|
||||
// Side Effects:
|
||||
// Tags the children with "remove" (and hence sets `$tag`) if no tag is already set.
|
||||
// `$idx` is set to the index number of each face.
|
||||
// `$attach_anchor` is set for each edge or corner given, to the `[ANCHOR, POSITION, ORIENT, SPIN]` information for that anchor.
|
||||
// `$profile_type` is set to `"edge"` or `"corner"`, depending on what is being masked.
|
||||
// Example:
|
||||
// diff()
|
||||
// cube([50,60,70],center=true)
|
||||
// face_profile(TOP,r=10)
|
||||
// mask2d_roundover(r=10);
|
||||
module face_profile(faces=[], r, d, excess=0.01, convexity=10) {
|
||||
req_children($children);
|
||||
faces = is_vector(faces)? [faces] : faces;
|
||||
assert(all([for (face=faces) is_vector(face) && sum([for (x=face) x!=0? 1 : 0])==1]), "\nVector in faces doesn't point at a face.");
|
||||
r = get_radius(r=r, d=d, dflt=undef);
|
||||
assert(is_num(r) && r>=0);
|
||||
edge_profile(faces, excess=excess) children();
|
||||
corner_profile(faces, convexity=convexity, r=r) children();
|
||||
}
|
||||
|
||||
|
||||
// Module: edge_profile()
|
||||
// Synopsis: Extrudes a 2d edge profile into a mask on the given edges of the parent.
|
||||
// SynTags: Geom
|
||||
// Topics: Attachments, Masking
|
||||
// See Also: attachable(), position(), attach(), face_profile(), edge_profile_asym(), corner_profile(), edge_mask(), face_mask(), corner_mask()
|
||||
// Usage:
|
||||
// PARENT() edge_profile([edges], [except], [convexity]) CHILDREN;
|
||||
// Description:
|
||||
// Takes a 2D mask shape and attaches it to the selected edges, with the appropriate orientation and
|
||||
// extruded length to be `diff()`ed away, to give the edge a matching profile. If no tag is set
|
||||
// then `edge_profile` sets the tag for children to "remove" so that it works with the default {{diff()}} tag.
|
||||
// For details on specifying the edges to mask see [Specifying Edges](attachments.scad#subsection-specifying-edges).
|
||||
// For a step-by-step explanation of masking attachments, see the [Attachments Tutorial](Tutorial-Attachment-Edge-Profiling).
|
||||
// Arguments:
|
||||
// edges = Edges to mask. See [Specifying Edges](attachments.scad#subsection-specifying-edges). Default: All edges.
|
||||
// except = Edges to explicitly NOT mask. See [Specifying Edges](attachments.scad#subsection-specifying-edges). Default: No edges.
|
||||
// excess = Excess length to extrude the profile to make edge masks. Default: 0.01
|
||||
// convexity = Max number of times a line could intersect the perimeter of the mask shape. Default: 10
|
||||
// Side Effects:
|
||||
// Tags the children with "remove" (and hence sets `$tag`) if no tag is already set.
|
||||
// `$idx` is set to the index number of each edge.
|
||||
// `$attach_anchor` is set for each edge given, to the `[ANCHOR, POSITION, ORIENT, SPIN]` information for that anchor.
|
||||
// `$profile_type` is set to `"edge"`.
|
||||
// `$edge_angle` is set to the inner angle of the current edge.
|
||||
// Example:
|
||||
// diff()
|
||||
// cube([50,60,70],center=true)
|
||||
// edge_profile([TOP,"Z"],except=[BACK,TOP+LEFT])
|
||||
// mask2d_roundover(r=10, inset=2);
|
||||
// Example: Using $edge_angle on a conoid
|
||||
// diff()
|
||||
// cyl(d1=50, d2=30, l=40, anchor=BOT) {
|
||||
// edge_profile([TOP,BOT], excess=10, convexity=6) {
|
||||
// mask2d_roundover(r=8, inset=1, excess=1, mask_angle=$edge_angle);
|
||||
// }
|
||||
// }
|
||||
// Example: Using $edge_angle on a prismoid
|
||||
// diff()
|
||||
// prismoid([60,50],[30,20],h=40,shift=[-25,15]) {
|
||||
// edge_profile(excess=10, convexity=20) {
|
||||
// mask2d_roundover(r=5,inset=1,mask_angle=$edge_angle,$fn=32);
|
||||
// }
|
||||
// }
|
||||
|
||||
module edge_profile(edges=EDGES_ALL, except=[], excess=0.01, convexity=10) {
|
||||
req_children($children);
|
||||
check1 = assert($parent_geom != undef, "\nNo object to attach to!");
|
||||
conoid = $parent_geom[0] == "conoid";
|
||||
edges = !conoid? _edges(edges, except=except) :
|
||||
edges==EDGES_ALL? [TOP,BOT] :
|
||||
assert(all([for (e=edges) in_list(e,[TOP,BOT])]), "\nInvalid conoid edge spec.")
|
||||
edges;
|
||||
vecs = conoid
|
||||
? [for (e=edges) e+FWD]
|
||||
: [
|
||||
for (i = [0:3], axis=[0:2])
|
||||
if (edges[axis][i]>0)
|
||||
EDGE_OFFSETS[axis][i]
|
||||
];
|
||||
all_vecs_are_edges = all([for (vec = vecs) sum(v_abs(vec))==2]);
|
||||
check2 = assert(all_vecs_are_edges, "\nAll vectors must be edges.");
|
||||
default_tag("remove")
|
||||
for ($idx = idx(vecs)) {
|
||||
vec = vecs[$idx];
|
||||
anch = _find_anchor(vec, $parent_geom);
|
||||
path_angs_T = _attach_geom_edge_path($parent_geom, vec);
|
||||
path = path_angs_T[0];
|
||||
vecs = path_angs_T[1];
|
||||
post_T = path_angs_T[2];
|
||||
$attach_to = undef;
|
||||
$attach_anchor = anch;
|
||||
$profile_type = "edge";
|
||||
multmatrix(post_T) {
|
||||
for (i = idx(path,e=-2)) {
|
||||
pt1 = select(path,i);
|
||||
pt2 = select(path,i+1);
|
||||
cp = (pt1 + pt2) / 2;
|
||||
v1 = vecs[i][0];
|
||||
v2 = vecs[i][1];
|
||||
$edge_angle = 180 - vector_angle(v1,v2);
|
||||
if (!approx(pt1,pt2)) {
|
||||
seglen = norm(pt2-pt1) + 2 * excess;
|
||||
move(cp) {
|
||||
frame_map(x=-v2, z=unit(pt2-pt1)) {
|
||||
linear_extrude(height=seglen, center=true, convexity=convexity)
|
||||
mirror([-1,1]) children();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Module: edge_profile_asym()
|
||||
// Synopsis: Extrudes an asymmetric 2D profile into a mask on the given edges and corners of the parent.
|
||||
// SynTags: Geom
|
||||
// Topics: Attachments, Masking
|
||||
// See Also: attachable(), position(), attach(), face_profile(), edge_profile(), corner_profile(), edge_mask(), face_mask(), corner_mask()
|
||||
// Usage:
|
||||
// PARENT() edge_profile([edges], [except], [convexity=], [flip=], [corner_type=]) CHILDREN;
|
||||
// Description:
|
||||
// Takes an asymmetric 2D mask shape and attaches it to the selected edges and corners, with the appropriate
|
||||
// orientation and extruded length to be `diff()`ed away, to give the edges and corners a matching profile.
|
||||
// If no tag is set then `edge_profile_asym()` sets the tag for children to "remove" so that it works
|
||||
// with the default {{diff()}} tag. For details on specifying the edges to mask see [Specifying Edges](attachments.scad#subsection-specifying-edges).
|
||||
// For a step-by-step explanation of masking attachments, see the [Attachments Tutorial](Tutorial-Attachment-Edge-Profiling).
|
||||
// The asymmetric profiles are joined consistently at the corners. This is impossible if all three edges at a corner use the profile, hence
|
||||
// this situation is not permitted. The profile orientation can be inverted using the `flip=true` parameter.
|
||||
// .
|
||||
// The standard profiles are located in the first quadrant and have positive X values. If you provide a profile located in the second quadrant,
|
||||
// where the X values are negative, then it produces a fillet. You can flip any of the standard profiles using {{xflip()}}.
|
||||
// Do **not** flip one of the standard first quadrant masks into the 3rd quadrant $(y<0)$ using {{yflip()}}, as this will not work correctly.
|
||||
// Fillets are always asymmetric because at a given edge, they can blend in two different directions, so even for symmetric profiles,
|
||||
// the asymmetric logic is required. You can set the `corner_type` parameter to select rounded, chamfered or sharp corners.
|
||||
// However, when the corners are inside (concave) corners, you must provide the size of the profile ([width,height]), because the
|
||||
// this information is required to produce the correct corner and cannot be obtain from the profile itself, which is a child object.
|
||||
// .
|
||||
// Because the profiles are asymmetric they can be placed on a given edge in two different orientations. It is easiest to understand
|
||||
// the orientation by thinking about fillets and in which direction a filleted cube will make a smooth joint. Given a string of connected
|
||||
// edges, we must identify the orientation of the fillet at just one edge; the orentation of the fillets on the remaining edges is forced
|
||||
// to maintain consistency across the string of edges. The module uses a set of priority rules as follows:
|
||||
// .
|
||||
// 1. Bottom
|
||||
// 2. Top
|
||||
// 3. Front or Back
|
||||
// .
|
||||
// What this means is that if an edge string contains any edge on the bottom then the bottom edges will be oriented to join the bottom face
|
||||
// to something, and the rest of the string consistently oriented. If the string contains no bottom edges but it has top edges then
|
||||
// the edge string will be oriented so that the object can join its top face to something. If the string has no top or bottom edges then it
|
||||
// must be just a single edge and it will be is oriented so that either the front or back face of the cube can make a smooth joint.
|
||||
// If the edge orientation is reversed from what you need, set `flip=true`. If these rules seem complicated, just create your model,
|
||||
// examine the edges, and flip them as required. Note that creating fillets with {{yflip()}} may seem similar to setting `flip=true` and
|
||||
// may partially work but is **not** the correct way to flip edge profile; it can produce incomplete results.
|
||||
//
|
||||
// Arguments:
|
||||
// edges = Edges to mask. See [Specifying Edges](attachments.scad#subsection-specifying-edges). Default: All edges.
|
||||
// except = Edges to explicitly NOT mask. See [Specifying Edges](attachments.scad#subsection-specifying-edges). Default: No edges.
|
||||
// ---
|
||||
// excess = Excess length to extrude the profile to make edge masks. Default: 0.01
|
||||
// convexity = Max number of times a line could intersect the perimeter of the mask shape. Default: 10
|
||||
// flip = If true, reverses the orientation of any external profile parts at each edge. Default false
|
||||
// corner_type = Specifies how exterior corners should be formed. Must be one of `"none"`, `"chamfer"`, `"round"`, or `"sharp"`. Default: `"none"`
|
||||
// size = If given the width and height of the 2D profile, enable rounding and chamfering of internal corners when given a negative profile.
|
||||
// Side Effects:
|
||||
// Tags the children with "remove" (and hence sets `$tag`) if no tag is already set.
|
||||
// `$idx` is set to the index number of each edge.
|
||||
// `$attach_anchor` is set for each edge given, to the `[ANCHOR, POSITION, ORIENT, SPIN]` information for that anchor.
|
||||
// `$profile_type` is set to `"edge"`.
|
||||
// `$edge_angle` is set to the inner angle of the current edge.
|
||||
// Example:
|
||||
// ogee = [
|
||||
// "xstep",1, "ystep",1, // Starting shoulder.
|
||||
// "fillet",5, "round",5, // S-curve.
|
||||
// "ystep",1, "xstep",1 // Ending shoulder.
|
||||
// ];
|
||||
// diff()
|
||||
// cuboid(50) {
|
||||
// edge_profile_asym(FRONT)
|
||||
// mask2d_ogee(ogee);
|
||||
// }
|
||||
// Example: Flipped
|
||||
// ogee = [
|
||||
// "xstep",1, "ystep",1, // Starting shoulder.
|
||||
// "fillet",5, "round",5, // S-curve.
|
||||
// "ystep",1, "xstep",1 // Ending shoulder.
|
||||
// ];
|
||||
// diff()
|
||||
// cuboid(50) {
|
||||
// edge_profile_asym(FRONT, flip=true)
|
||||
// mask2d_ogee(ogee);
|
||||
// }
|
||||
// Example: Negative Chamfering
|
||||
// cuboid(50) {
|
||||
// edge_profile_asym(FWD, flip=false)
|
||||
// xflip() mask2d_chamfer(10);
|
||||
// edge_profile_asym(BACK, flip=true, corner_type="sharp")
|
||||
// xflip() mask2d_chamfer(10);
|
||||
// }
|
||||
// Example: Negative Roundings
|
||||
// cuboid(50) {
|
||||
// edge_profile_asym(FWD, flip=false)
|
||||
// xflip() mask2d_roundover(10);
|
||||
// edge_profile_asym(BACK, flip=true, corner_type="round")
|
||||
// xflip() mask2d_roundover(10);
|
||||
// }
|
||||
// Example: Cornerless
|
||||
// cuboid(50) {
|
||||
// edge_profile_asym(
|
||||
// "ALL", except=[TOP+FWD+RIGHT, BOT+BACK+LEFT]
|
||||
// ) xflip() mask2d_roundover(10);
|
||||
// }
|
||||
// Example: More complicated edge sets
|
||||
// cuboid(50) {
|
||||
// edge_profile_asym(
|
||||
// [FWD,BACK,BOT+RIGHT], except=[FWD+RIGHT,BOT+BACK],
|
||||
// corner_type="round"
|
||||
// ) xflip() mask2d_roundover(10);
|
||||
// }
|
||||
// Example: Mixing it up a bit.
|
||||
// diff()
|
||||
// cuboid(60) {
|
||||
// tag("keep") edge_profile_asym(LEFT, flip=true, corner_type="chamfer")
|
||||
// xflip() mask2d_chamfer(10);
|
||||
// edge_profile_asym(RIGHT)
|
||||
// mask2d_roundover(10);
|
||||
// }
|
||||
// Example: Chamfering internal corners.
|
||||
// cuboid(40) {
|
||||
// edge_profile_asym(
|
||||
// [FWD+DOWN,FWD+LEFT],
|
||||
// corner_type="chamfer", size=[10,10]/sqrt(2)
|
||||
// ) xflip() mask2d_chamfer(10);
|
||||
// }
|
||||
// Example: Rounding internal corners.
|
||||
// cuboid(40) {
|
||||
// edge_profile_asym(
|
||||
// [FWD+DOWN,FWD+LEFT],
|
||||
// corner_type="round", size=[10,10]
|
||||
// ) xflip() mask2d_roundover(10);
|
||||
// }
|
||||
// Example(3D,NoScales): This string of 3 edges rounds so that the cuboid joins smoothly to the bottom
|
||||
// color_this("lightblue")cuboid([70,70,10])
|
||||
// attach(TOP,BOT,align=RIGHT+BACK)
|
||||
// cuboid(50)
|
||||
// edge_profile_asym([BOT+FRONT, RIGHT+FRONT, TOP+RIGHT],corner_type="round")
|
||||
// xflip()mask2d_roundover(10);
|
||||
// Example(3D,NoScales): No top or bottom edges appear in the edge set, so the edges are oriented to joint smoothly to the FRONT and BACK
|
||||
// color_this("lightblue") cuboid([90,10,50])
|
||||
// align(FWD) cuboid(50){
|
||||
// edge_profile_asym("Z",corner_type="round")
|
||||
// xflip() mask2d_roundover(10);
|
||||
// align(FWD)
|
||||
// color_this("lightblue") cuboid([90,10,50]);
|
||||
// }
|
||||
|
||||
module edge_profile_asym(
|
||||
edges=EDGES_ALL, except=[],
|
||||
excess=0.01, convexity=10,
|
||||
flip=false, corner_type="none",
|
||||
size=[0,0]
|
||||
) {
|
||||
function _corner_orientation(pos,pvec) =
|
||||
let(
|
||||
j = [for (i=[0:2]) if (pvec[i]) i][0],
|
||||
T = (pos.x>0? xflip() : ident(4)) *
|
||||
(pos.y>0? yflip() : ident(4)) *
|
||||
(pos.z>0? zflip() : ident(4)) *
|
||||
rot(-120*(2-j), v=[1,1,1])
|
||||
) T;
|
||||
|
||||
function _default_edge_orientation(edge) =
|
||||
edge.z < 0? [[-edge.x,-edge.y,0], UP] :
|
||||
edge.z > 0? [[-edge.x,-edge.y,0], DOWN] :
|
||||
edge.y < 0? [[-edge.x,0,0], BACK] :
|
||||
[[-edge.x,0,0], FWD] ;
|
||||
|
||||
function _edge_transition_needs_flip(from,to) =
|
||||
let(
|
||||
flip_edges = [
|
||||
[BOT+FWD, [FWD+LEFT, FWD+RIGHT]],
|
||||
[BOT+BACK, [BACK+LEFT, BACK+RIGHT]],
|
||||
[BOT+LEFT, []],
|
||||
[BOT+RIGHT, []],
|
||||
[TOP+FWD, [FWD+LEFT, FWD+RIGHT]],
|
||||
[TOP+BACK, [BACK+LEFT, BACK+RIGHT]],
|
||||
[TOP+LEFT, []],
|
||||
[TOP+RIGHT, []],
|
||||
[FWD+LEFT, [TOP+FWD, BOT+FWD]],
|
||||
[FWD+RIGHT, [TOP+FWD, BOT+FWD]],
|
||||
[BACK+LEFT, [TOP+BACK, BOT+BACK]],
|
||||
[BACK+RIGHT, [TOP+BACK, BOT+BACK]],
|
||||
],
|
||||
i = search([from], flip_edges, num_returns_per_match=1)[0],
|
||||
check = assert(i!=[], "\nBad edge vector.")
|
||||
) in_list(to,flip_edges[i][1]);
|
||||
|
||||
function _edge_corner_numbers(vec) =
|
||||
let(
|
||||
v2 = [for (i=idx(vec)) vec[i]? (vec[i]+1)/2*pow(2,i) : 0],
|
||||
off = v2.x + v2.y + v2.z,
|
||||
xs = [0, if (!vec.x) 1],
|
||||
ys = [0, if (!vec.y) 2],
|
||||
zs = [0, if (!vec.z) 4]
|
||||
) [for (x=xs, y=ys, z=zs) x+y+z + off];
|
||||
|
||||
function _gather_contiguous_edges(edge_corners) =
|
||||
let(
|
||||
no_tri_corners = all([for(cn = [0:7]) len([for (ec=edge_corners) if(in_list(cn,ec[1])) 1])<3]),
|
||||
check = assert(no_tri_corners, "\nCannot have three edges that meet at the same corner.")
|
||||
)
|
||||
_gather_contiguous_edges_r(
|
||||
[for (i=idx(edge_corners)) if(i) edge_corners[i]],
|
||||
edge_corners[0][1],
|
||||
[edge_corners[0][0]], []);
|
||||
|
||||
function _gather_contiguous_edges_r(edge_corners, ecns, curr, out) =
|
||||
len(edge_corners)==0? [each out, curr] :
|
||||
let(
|
||||
i1 = [
|
||||
for (i = idx(edge_corners))
|
||||
if (in_list(ecns[0], edge_corners[i][1]))
|
||||
i
|
||||
],
|
||||
i2 = [
|
||||
for (i = idx(edge_corners))
|
||||
if (in_list(ecns[1], edge_corners[i][1]))
|
||||
i
|
||||
]
|
||||
) !i1 && !i2? _gather_contiguous_edges_r(
|
||||
[for (i=idx(edge_corners)) if(i) edge_corners[i]],
|
||||
edge_corners[0][1],
|
||||
[edge_corners[0][0]],
|
||||
[each out, curr]
|
||||
) : let(
|
||||
nu_curr = [
|
||||
if (i1) edge_corners[i1[0]][0],
|
||||
each curr,
|
||||
if (i2) edge_corners[i2[0]][0],
|
||||
],
|
||||
nu_ecns = [
|
||||
if (!i1) ecns[0] else [
|
||||
for (ecn = edge_corners[i1[0]][1])
|
||||
if (ecn != ecns[0]) ecn
|
||||
][0],
|
||||
if (!i2) ecns[1] else [
|
||||
for (ecn = edge_corners[i2[0]][1])
|
||||
if (ecn != ecns[1]) ecn
|
||||
][0],
|
||||
],
|
||||
rem = [
|
||||
for (i = idx(edge_corners))
|
||||
if (i != i1[0] && i != i2[0])
|
||||
edge_corners[i]
|
||||
]
|
||||
)
|
||||
_gather_contiguous_edges_r(rem, nu_ecns, nu_curr, out);
|
||||
|
||||
function _edge_transition_inversions(edge_string) =
|
||||
let(
|
||||
// boolean cumulative sum
|
||||
bcs = function(list, i=0, inv=false, out=[])
|
||||
i>=len(list)? out :
|
||||
let( nu_inv = list[i]? !inv : inv )
|
||||
bcs(list, i+1, nu_inv, [each out, nu_inv]),
|
||||
inverts = bcs([
|
||||
false,
|
||||
for(i = idx(edge_string)) if (i)
|
||||
_edge_transition_needs_flip(
|
||||
edge_string[i-1],
|
||||
edge_string[i]
|
||||
)
|
||||
]),
|
||||
boti = [for(i = idx(edge_string)) if (edge_string[i].z<0) i],
|
||||
topi = [for(i = idx(edge_string)) if (edge_string[i].z>0) i],
|
||||
lfti = [for(i = idx(edge_string)) if (edge_string[i].x<0) i],
|
||||
rgti = [for(i = idx(edge_string)) if (edge_string[i].x>0) i],
|
||||
idx = [for (m = [boti, topi, lfti, rgti]) if(m) m[0]][0],
|
||||
rinverts = inverts[idx] == false? inverts : [for (x = inverts) !x]
|
||||
) rinverts;
|
||||
|
||||
function _is_closed_edge_loop(edge_string) =
|
||||
let(
|
||||
e1 = edge_string[0],
|
||||
e2 = last(edge_string)
|
||||
)
|
||||
len([for (i=[0:2]) if (abs(e1[i])==1 && e1[i]==e2[i]) 1]) == 1 &&
|
||||
len([for (i=[0:2]) if (e1[i]==0 && abs(e2[i])==1) 1]) == 1 &&
|
||||
len([for (i=[0:2]) if (e2[i]==0 && abs(e1[i])==1) 1]) == 1;
|
||||
|
||||
function _edge_pair_perp_vec(e1,e2) =
|
||||
[for (i=[0:2]) if (abs(e1[i])==1 && e1[i]==e2[i]) -e1[i] else 0];
|
||||
|
||||
req_children($children);
|
||||
check1 = assert($parent_geom != undef, "\nNo object to attach to!")
|
||||
assert(in_list(corner_type, ["none", "round", "chamfer", "sharp"]))
|
||||
assert(is_bool(flip));
|
||||
edges = _edges(edges, except=except);
|
||||
vecs = [
|
||||
for (i = [0:3], axis=[0:2])
|
||||
if (edges[axis][i]>0)
|
||||
EDGE_OFFSETS[axis][i]
|
||||
];
|
||||
all_vecs_are_edges = all([for (vec = vecs) sum(v_abs(vec))==2]);
|
||||
check2 = assert(all_vecs_are_edges, "\nAll vectors must be edges.");
|
||||
edge_corners = [for (vec = vecs) [vec, _edge_corner_numbers(vec)]];
|
||||
edge_strings = _gather_contiguous_edges(edge_corners);
|
||||
default_tag("remove")
|
||||
for (edge_string = edge_strings) {
|
||||
inverts = _edge_transition_inversions(edge_string);
|
||||
flipverts = [for (x = inverts) flip? !x : x];
|
||||
vecpairs = [
|
||||
for (i = idx(edge_string))
|
||||
let (p = _default_edge_orientation(edge_string[i]))
|
||||
flipverts[i]? [p.y,p.x] : p
|
||||
];
|
||||
is_loop = _is_closed_edge_loop(edge_string);
|
||||
for (i = idx(edge_string)) {
|
||||
if (corner_type!="none" && (i || is_loop)) {
|
||||
e1 = select(edge_string,i-1);
|
||||
e2 = select(edge_string,i);
|
||||
vp1 = select(vecpairs,i-1);
|
||||
vp2 = select(vecpairs,i);
|
||||
pvec = _edge_pair_perp_vec(e1,e2);
|
||||
pos = [for (i=[0:2]) e1[i]? e1[i] : e2[i]];
|
||||
mirT = _corner_orientation(pos, pvec);
|
||||
$attach_to = undef;
|
||||
$attach_anchor = _find_anchor(pos, $parent_geom);
|
||||
$profile_type = "corner";
|
||||
position(pos) {
|
||||
multmatrix(mirT) {
|
||||
if (vp1.x == vp2.x && size.y > 0) {
|
||||
zflip() {
|
||||
if (corner_type=="chamfer") {
|
||||
fn = $fn;
|
||||
move([size.y,size.y]) {
|
||||
rotate_extrude(angle=90, $fn=4)
|
||||
left_half(planar=true, $fn=fn)
|
||||
zrot(-90) fwd(size.y) children();
|
||||
}
|
||||
difference() {
|
||||
down(0.01) cube([size.x, size.x, size.y+0.01]);
|
||||
move([size.x+0.01, size.x+0.01])
|
||||
zrot(180)
|
||||
rotate_extrude(angle=90, $fn=4)
|
||||
square([size.x+0.01, size.y+0.01]);
|
||||
}
|
||||
} else if (corner_type=="round") {
|
||||
move([size.y,size.y]) {
|
||||
rotate_extrude(angle=90)
|
||||
left_half(planar=true)
|
||||
zrot(-90) fwd(size.y) children();
|
||||
}
|
||||
difference() {
|
||||
down(0.01) cube([size.x, size.x, size.y+0.01]);
|
||||
move([size.x+0.01, size.x+0.01])
|
||||
zrot(180)
|
||||
rotate_extrude(angle=90)
|
||||
square([size.x+0.01, size.y+0.01]);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (vp1.y == vp2.y) {
|
||||
if (corner_type=="chamfer") {
|
||||
fn = $fn;
|
||||
rotate_extrude(angle=90, $fn=4)
|
||||
right_half(planar=true, $fn=fn)
|
||||
children();
|
||||
rotate_extrude(angle=90, $fn=4)
|
||||
left_half(planar=true, $fn=fn)
|
||||
children();
|
||||
} else if (corner_type=="round") {
|
||||
rotate_extrude(angle=90)
|
||||
right_half(planar=true)
|
||||
children();
|
||||
rotate_extrude(angle=90)
|
||||
left_half(planar=true)
|
||||
children();
|
||||
} else { //corner_type == "sharp"
|
||||
intersection() {
|
||||
rot([90,0, 0]) linear_extrude(height=100,center=true,convexity=convexity) children();
|
||||
rot([90,0,90]) linear_extrude(height=100,center=true,convexity=convexity) children();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (i = idx(edge_string)) {
|
||||
$attach_to = undef;
|
||||
$attach_anchor = _find_anchor(edge_string[i], $parent_geom);
|
||||
$profile_type = "edge";
|
||||
edge_profile(edge_string[i], excess=excess, convexity=convexity) {
|
||||
if (flipverts[i]) {
|
||||
mirror([-1,1]) children();
|
||||
} else {
|
||||
children();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Module: corner_profile()
|
||||
// Synopsis: Rotationally extrudes a 2d edge profile into corner mask on the given corners of the parent.
|
||||
// SynTags: Geom
|
||||
// Topics: Attachments, Masking
|
||||
// See Also: attachable(), position(), attach(), face_profile(), edge_profile(), corner_mask(), face_mask(), edge_mask()
|
||||
// Usage:
|
||||
// PARENT() corner_profile([corners], [except], [r=|d=], [convexity=]) CHILDREN;
|
||||
// Description:
|
||||
// Takes a 2D mask shape, rotationally extrudes and converts it into a corner mask, and attaches it
|
||||
// to the selected corners with the appropriate orientation. If no tag is set then `corner_profile()`
|
||||
// sets the tag for children to "remove" so that it works with the default {{diff()}} tag.
|
||||
// See [Specifying Corners](attachments.scad#subsection-specifying-corners) for information on how to specify corner sets.
|
||||
// For a step-by-step explanation of masking attachments, see the [Attachments Tutorial](Tutorial-Attachment-Edge-Profiling).
|
||||
// Arguments:
|
||||
// corners = Corners to mask. See [Specifying Corners](attachments.scad#subsection-specifying-corners). Default: All corners.
|
||||
// except = Corners to explicitly NOT mask. See [Specifying Corners](attachments.scad#subsection-specifying-corners). Default: No corners.
|
||||
// ---
|
||||
// r = Radius of corner mask.
|
||||
// d = Diameter of corner mask.
|
||||
// axis = Can be set to "X", "Y", or "Z" to specify the axis that the corner mask will be rotated around. Default: "Z"
|
||||
// convexity = Max number of times a line could intersect the perimeter of the mask shape. Default: 10
|
||||
// Side Effects:
|
||||
// Tags the children with "remove" (and hence sets `$tag`) if no tag is already set.
|
||||
// `$idx` is set to the index number of each corner.
|
||||
// `$attach_anchor` is set for each corner given, to the `[ANCHOR, POSITION, ORIENT, SPIN]` information for that anchor.
|
||||
// `$profile_type` is set to `"corner"`.
|
||||
// Example:
|
||||
// diff()
|
||||
// cuboid([50,60,70],rounding=10,edges="Z",anchor=CENTER) {
|
||||
// corner_profile(TOP,r=10)
|
||||
// mask2d_teardrop(r=10, angle=40);
|
||||
// }
|
||||
// Example: Rotate the mask around the X axis instead.
|
||||
// diff()
|
||||
// cuboid([50,60,70],rounding=10,edges="Z",anchor=CENTER) {
|
||||
// corner_profile(TOP,r=10,axis="X")
|
||||
// mask2d_teardrop(r=10, angle=40);
|
||||
// }
|
||||
module corner_profile(corners=CORNERS_ALL, except=[], r, d, axis="Z", convexity=10) {
|
||||
check1 = assert($parent_geom != undef, "\nNo object to attach to!");
|
||||
r = max(0.01, get_radius(r=r, d=d, dflt=undef));
|
||||
check2 = assert(is_num(r), "\nBad r/d argument.");
|
||||
corners = _corners(corners, except=except);
|
||||
vecs = [for (i = [0:7]) if (corners[i]>0) CORNER_OFFSETS[i]];
|
||||
all_vecs_are_corners = all([for (vec = vecs) sum(v_abs(vec))==3]);
|
||||
check3 = assert(all_vecs_are_corners, "\nAll vectors must be corners.");
|
||||
module rot_to_axis(axis) {
|
||||
if (axis == "X")
|
||||
rot(120, v=[1,1,1]) children();
|
||||
else if (axis == "Y")
|
||||
rot(-120, v=[1,1,1]) children();
|
||||
else
|
||||
children();
|
||||
}
|
||||
module mirror_if(cond,plane) {
|
||||
if (cond) mirror(plane) children();
|
||||
else children();
|
||||
}
|
||||
module mirror_to_corner(corner) {
|
||||
mirror_if(corner.x > 0, RIGHT)
|
||||
mirror_if(corner.y > 0, BACK)
|
||||
mirror_if(corner.z > 0, UP)
|
||||
children();
|
||||
}
|
||||
module corner_round_mask2d(r) {
|
||||
excess = 0.01;
|
||||
path = [
|
||||
[-excess,-excess],
|
||||
[-excess, r],
|
||||
each arc(cp=[r,r], r=r, start=180, angle=90),
|
||||
[r, -excess]
|
||||
];
|
||||
polygon(path);
|
||||
}
|
||||
for ($idx = idx(vecs)) {
|
||||
vec = vecs[$idx];
|
||||
anch = _find_anchor(vec, $parent_geom);
|
||||
$attach_to = undef;
|
||||
$attach_anchor = anch;
|
||||
$profile_type = "corner";
|
||||
default_tag("remove") attachable() {
|
||||
translate(anch[1]) {
|
||||
mirror_to_corner(vec) {
|
||||
rot_to_axis(axis) {
|
||||
down(0.01) {
|
||||
linear_extrude(height=r+0.01, center=false, convexity=convexity) {
|
||||
corner_round_mask2d(r);
|
||||
}
|
||||
}
|
||||
translate([r,r]) zrot(180) {
|
||||
rotate_extrude(angle=90, convexity=convexity) {
|
||||
right(r) xflip() {
|
||||
children();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
union();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Section: Making your objects attachable
|
||||
|
||||
|
||||
|
|
@ -2994,14 +2204,14 @@ module corner_profile(corners=CORNERS_ALL, except=[], r, d, axis="Z", convexity=
|
|||
// }
|
||||
//
|
||||
// Example(NORENDER): Extruded Polygon Shape, by Extents
|
||||
// attachable(anchor, spin, orient, path=path, l=length) {
|
||||
// attachable(anchor, spin, orient, path=path, l=length, scale=scale) {
|
||||
// linear_extrude(height=length, center=true)
|
||||
// polygon(path);
|
||||
// children();
|
||||
// }
|
||||
//
|
||||
// Example(NORENDER): Extruded Polygon Shape, by Intersection
|
||||
// attachable(anchor, spin, orient, path=path, l=length, extent=false) {
|
||||
// attachable(anchor, spin, orient, path=path, l=length, extent=false, scale=scale) {
|
||||
// linear_extrude(height=length, center=true)
|
||||
// polygon(path);
|
||||
// children();
|
||||
|
|
@ -3192,7 +2402,7 @@ module attachable(
|
|||
anchor, spin, orient,
|
||||
size, size2, shift,
|
||||
r,r1,r2, d,d1,d2, l,h,
|
||||
vnf, path, region,
|
||||
vnf, path, region, scale,
|
||||
extent=true,
|
||||
cp=[0,0,0],
|
||||
offset=[0,0,0],
|
||||
|
|
@ -3219,7 +2429,7 @@ module attachable(
|
|||
attach_geom(
|
||||
size=size, size2=size2, shift=shift,
|
||||
r=r, r1=r1, r2=r2, h=h,
|
||||
d=d, d1=d1, d2=d2, l=l,
|
||||
d=d, d1=d1, d2=d2, l=l, scale=scale,
|
||||
vnf=vnf, region=region, extent=extent,
|
||||
cp=cp, offset=offset, anchors=anchors,
|
||||
two_d=two_d, axis=axis, override=override
|
||||
|
|
|
|||
76
gears.scad
76
gears.scad
|
|
@ -2788,7 +2788,7 @@ function worm(
|
|||
helical=helical,
|
||||
profile_shift=0
|
||||
), 1, -2),
|
||||
ff=echo(tooth=tooth, rack_profile=rack_profile,nrp=nrp),
|
||||
// ff=echo(tooth=tooth, rack_profile=rack_profile,nrp=nrp),
|
||||
steps = max(36, segs(d/2)),
|
||||
step = 360 / steps,
|
||||
zsteps = ceil(l / trans_pitch / starts * steps),
|
||||
|
|
@ -3142,7 +3142,7 @@ function worm_gear(
|
|||
)
|
||||
assert(is_finite(worm_diam) && worm_diam>0)
|
||||
assert(is_integer(teeth) && teeth>7)
|
||||
assert(is_finite(worm_arc) && worm_arc>0 && worm_arc <= 60)
|
||||
// assert(is_finite(worm_arc) && worm_arc>0 && worm_arc <= 60)
|
||||
assert(is_integer(worm_starts) && worm_starts>0)
|
||||
assert(is_bool(left_handed))
|
||||
assert(is_finite(backlash))
|
||||
|
|
@ -3153,31 +3153,43 @@ function worm_gear(
|
|||
gear_arc = 2 * PA,
|
||||
helical = asin(worm_starts * circ_pitch / PI / worm_diam),
|
||||
//fee=echo(helical=helical),
|
||||
full_tooth = apply(
|
||||
zrot(90) * scale(0.99),
|
||||
_gear_tooth_profile(
|
||||
circ_pitch, teeth=teeth,
|
||||
pressure_angle=PA,
|
||||
profile_shift=-profile_shift,
|
||||
clearance=clearance,
|
||||
helical=helical, internal=false,
|
||||
center=true
|
||||
)
|
||||
),
|
||||
full_tooth = path3d(reverse(zrot(90, _gear_tooth_profile(
|
||||
circ_pitch, teeth=teeth,
|
||||
pressure_angle=PA,
|
||||
profile_shift=profile_shift,
|
||||
clearance=clearance,shorten=.3,
|
||||
helical=helical, internal=false,
|
||||
center=true)))),
|
||||
bnd = pointlist_bounds(full_tooth),
|
||||
fdeewqqq= echo(toothbounds = bnd)echo(toothlength = bnd[1].x-bnd[0].x),
|
||||
tooth_bot = pointlist_bounds(full_tooth)[1].x,
|
||||
ftl = len(full_tooth),
|
||||
tooth_half1 = (select(full_tooth, 0, ftl/2-1)),
|
||||
tooth_half2 = (select(full_tooth, ftl/2, -1)),
|
||||
tooth_half1 = select(full_tooth, 0, ftl/2-1),
|
||||
tooth_half2 = select(full_tooth, ftl/2, -1),
|
||||
//eer= echo(full_tooth=full_tooth),
|
||||
//fdewq= echo(tooth_half1=tooth_half1)echo(tooth_half2=tooth_half2),
|
||||
tang = 360 / teeth,
|
||||
rteeth = (quantdn(teeth * gear_arc / 360, 2) / 2 + 0.5),
|
||||
|
||||
pr = pitch_radius(circ_pitch, teeth, helical=helical),
|
||||
//feee=echo(pr_worm = pr, circ_pitch, teeth, helical),
|
||||
circum = 2*PI*pr,
|
||||
tan_helical = tan(helical),
|
||||
|
||||
// Compute thickness based on tooth form and worm_arc for no crowning
|
||||
half_thickness = sin(worm_arc/2)*(worm_diam/2+tooth_bot),
|
||||
// Update worm_arc to account for crowning and produce same thickness
|
||||
worm_arc = 2*asin(half_thickness / (worm_diam/2 + crowning + tooth_bot)),
|
||||
feee=echo(pr_worm = pr, teeth=teeth ,helical= helical),
|
||||
|
||||
// When multiplied by z this gives the spin required to rotationally shear
|
||||
// a straight tooth so that it follows the specified helical angle.
|
||||
shear_angle_per_z = (left_handed?-1:1) * 360 * tan(helical) / (2*PI*pr),
|
||||
|
||||
oslices = slices * 4,
|
||||
// Tooth is in xy plane, centered, pointing in Y+ direction
|
||||
//
|
||||
|
||||
rows = [
|
||||
for (data = [[tooth_half1,1], [tooth_half2,-1]])
|
||||
let (
|
||||
tooth_half = (data[0]),
|
||||
tooth_half = data[0],
|
||||
dir = data[1]
|
||||
)
|
||||
for (pt = tooth_half) [
|
||||
|
|
@ -3185,16 +3197,17 @@ function worm_gear(
|
|||
let (
|
||||
u = i / oslices,
|
||||
w_ang = worm_arc * (u - 0.5),
|
||||
g_ang_delta = w_ang/360 * tang * worm_starts * (left_handed?1:-1) *0 ,
|
||||
m = //zrot(dir*rteeth*tang+g_ang_delta, cp=[worm_diam/2+pr,0,0]) *
|
||||
left(crowning) *
|
||||
m = left(crowning) *
|
||||
yrot(w_ang) *
|
||||
right(worm_diam/2+crowning) *
|
||||
//zrot(-dir*rteeth*tang+g_ang_delta, cp=[pr,0,0]) *
|
||||
xrot(180),
|
||||
pt = apply(m, point3d(pt)),
|
||||
angled_pt = zrot((left_handed?-1:1)*360*pt.z*tan_helical/circum,pt,cp=[worm_diam/2+pr,0,0])
|
||||
) angled_pt
|
||||
right(worm_diam/2+crowning),
|
||||
pt = apply(m, pt),
|
||||
L = 2*PI*worm_diam/2*w_ang/360 * tan(helical),
|
||||
// zang = -360*L/(2*PI*pr),
|
||||
// zang = -asin(L/pr),
|
||||
// angled_pt = zrot(shear_angle_per_z * pt.z, pt, cp=[worm_diam/2+pr,0,0])
|
||||
// angled_pt = zrot(zang, pt, cp=[worm_diam/2+pr,0,0])
|
||||
angled_pt = back(L,pt)
|
||||
) angled_pt
|
||||
]
|
||||
],
|
||||
midrow = len(rows)/2,
|
||||
|
|
@ -3226,6 +3239,7 @@ function worm_gear(
|
|||
)
|
||||
get_thickness? zmax*2 :
|
||||
let(
|
||||
feef=echo(actual_thick=zmax*2, est=half_thickness*2),
|
||||
gear_rows = [
|
||||
for (i = [0:1:teeth-1])
|
||||
let(
|
||||
|
|
@ -3271,7 +3285,7 @@ module worm_gear(
|
|||
assert(is_integer(teeth) && teeth>10)
|
||||
assert(is_finite(worm_diam) && worm_diam>0)
|
||||
assert(is_integer(worm_starts) && worm_starts>0)
|
||||
assert(is_finite(worm_arc) && worm_arc>0 && worm_arc<90)
|
||||
// assert(is_finite(worm_arc) && worm_arc>0 && worm_arc<90)
|
||||
assert(is_finite(crowning) && crowning>=0)
|
||||
assert(is_bool(left_handed))
|
||||
assert(is_finite(PA) && PA>=0 && PA<90, "Bad pressure_angle value.")
|
||||
|
|
@ -3371,6 +3385,7 @@ function _gear_tooth_profile(
|
|||
|
||||
// Calculate the important circle radii
|
||||
arad = outer_radius(circ_pitch, teeth, helical=helical, profile_shift=profile_shift, internal=internal, shorten=shorten),
|
||||
ffe=echo(arad=arad),
|
||||
prad = pitch_radius(circ_pitch, teeth, helical=helical),
|
||||
brad = _base_radius(circ_pitch, teeth, pressure_angle, helical=helical),
|
||||
rrad = _root_radius_basic(circ_pitch, teeth, clear, helical=helical, profile_shift=profile_shift, internal=internal),
|
||||
|
|
@ -3989,7 +4004,6 @@ function outer_radius(circ_pitch, teeth, clearance, internal=false, helical=0, p
|
|||
// root radius so that you can, for example, place a partial tooth gear onto a matching circle. The `backlash` parameter may seem
|
||||
// unnecessary, but when large pressure angle teeth are clipped, the value of backlash changes the clipping radius. For regular
|
||||
// gear teeth, `backlash` has no effect on the radius.
|
||||
|
||||
// Arguments:
|
||||
// teeth = The number of teeth on the gear.
|
||||
// helical = The helical angle (from vertical) of the teeth on the gear. Default: 0
|
||||
|
|
|
|||
2571
masks.scad
Normal file
2571
masks.scad
Normal file
File diff suppressed because it is too large
Load diff
1001
masks2d.scad
1001
masks2d.scad
File diff suppressed because it is too large
Load diff
707
masks3d.scad
707
masks3d.scad
|
|
@ -1,707 +0,0 @@
|
|||
//////////////////////////////////////////////////////////////////////
|
||||
// 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>
|
||||
// FileGroup: Basic Modeling
|
||||
// FileSummary: 3D masks for rounding or chamfering edges and corners.
|
||||
// FileFootnotes: STD=Included in std.scad
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
// Section: Chamfer Masks
|
||||
|
||||
|
||||
// Module: chamfer_edge_mask()
|
||||
// Synopsis: Creates a shape to chamfer a 90° edge.
|
||||
// SynTags: Geom
|
||||
// Topics: Masking, Chamfers, Shapes (3D)
|
||||
// See Also: chamfer_corner_mask(), chamfer_cylinder_mask(), chamfer_edge_mask(), default_tag(), diff()
|
||||
// Usage:
|
||||
// chamfer_edge_mask(l|h=|length=|height=, chamfer, [excess]) [ATTACHMENTS];
|
||||
// Description:
|
||||
// Creates a shape that can be used to chamfer a 90° edge.
|
||||
// Difference it from the object to be chamfered. The center of
|
||||
// the mask object should align exactly with the edge to be chamfered.
|
||||
// Arguments:
|
||||
// l/h/length/height = Length of mask. Default: $edge_length if defined
|
||||
// chamfer = Size of chamfer.
|
||||
// excess = The extra amount to add to the length of the mask so that it differences away from other shapes cleanly. Default: `0.1`
|
||||
// ---
|
||||
// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). Default: `CENTER`
|
||||
// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#subsection-spin). Default: `0`
|
||||
// orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#subsection-orient). Default: `UP`
|
||||
// Side Effects:
|
||||
// Tags the children with "remove" (and hence sets `$tag`) if no tag is already set.
|
||||
// Example:
|
||||
// chamfer_edge_mask(l=50, chamfer=10);
|
||||
// Example:
|
||||
// difference() {
|
||||
// cube(50, anchor=BOTTOM+FRONT);
|
||||
// #chamfer_edge_mask(l=50, chamfer=10, orient=RIGHT);
|
||||
// }
|
||||
// Example: Masking by Attachment
|
||||
// diff()
|
||||
// cube(50, center=true) {
|
||||
// edge_mask(TOP+RIGHT)
|
||||
// #chamfer_edge_mask(l=50, chamfer=10);
|
||||
// }
|
||||
function chamfer_edge_mask(l, chamfer=1, excess=0.1, h, length, height, anchor=CENTER, spin=0, orient=UP) = no_function("chamfer_edge_mask");
|
||||
module chamfer_edge_mask(l, chamfer=1, excess=0.1, h, length, height, anchor=CENTER, spin=0, orient=UP) {
|
||||
l = is_def($edge_length) && !any_defined([l,length,h,height]) ? $edge_length
|
||||
: one_defined([l,length,h,height],"l,length,h,height");
|
||||
default_tag("remove") {
|
||||
attachable(anchor,spin,orient, size=[chamfer*2, chamfer*2, l]) {
|
||||
cylinder(r=chamfer, h=l+excess, center=true, $fn=4);
|
||||
children();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Module: chamfer_corner_mask()
|
||||
// Synopsis: Creates a shape to chamfer a 90° corner.
|
||||
// SynTags: Geom
|
||||
// Topics: Masking, Chamfers, Shapes (3D)
|
||||
// See Also: chamfer_corner_mask(), chamfer_cylinder_mask(), chamfer_edge_mask(), default_tag(), diff()
|
||||
// Usage:
|
||||
// chamfer_corner_mask(chamfer) [ATTACHMENTS];
|
||||
// Description:
|
||||
// Creates a shape that can be used to chamfer a 90° corner.
|
||||
// Difference it from the object to be chamfered. The center of
|
||||
// the mask object should align exactly with the corner to be chamfered.
|
||||
// Arguments:
|
||||
// chamfer = Size of chamfer.
|
||||
// ---
|
||||
// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). Default: `CENTER`
|
||||
// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#subsection-spin). Default: `0`
|
||||
// orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#subsection-orient). Default: `UP`
|
||||
// Side Effects:
|
||||
// Tags the children with "remove" (and hence sets `$tag`) if no tag is already set.
|
||||
// Example:
|
||||
// chamfer_corner_mask(chamfer=10);
|
||||
// Example:
|
||||
// difference() {
|
||||
// cuboid(50, chamfer=10, trimcorners=false);
|
||||
// move(25*[1,-1,1]) #chamfer_corner_mask(chamfer=10);
|
||||
// }
|
||||
// Example: Masking by Attachment
|
||||
// diff()
|
||||
// cuboid(100, chamfer=20, trimcorners=false) {
|
||||
// corner_mask(TOP+FWD+RIGHT)
|
||||
// chamfer_corner_mask(chamfer=20);
|
||||
// }
|
||||
// Example: Anchors
|
||||
// chamfer_corner_mask(chamfer=20)
|
||||
// show_anchors();
|
||||
function chamfer_corner_mask(chamfer=1, anchor=CENTER, spin=0, orient=UP) = no_function("chamfer_corner_mask");
|
||||
module chamfer_corner_mask(chamfer=1, anchor=CENTER, spin=0, orient=UP) {
|
||||
default_tag("remove") {
|
||||
octahedron(chamfer*4, anchor=anchor, spin=spin, orient=orient) children();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Module: chamfer_cylinder_mask()
|
||||
// Synopsis: Creates a shape to chamfer the end of a cylinder.
|
||||
// SynTags: Geom
|
||||
// Topics: Masking, Chamfers, Cylinders
|
||||
// See Also: chamfer_corner_mask(), chamfer_cylinder_mask(), chamfer_edge_mask(), default_tag(), diff()
|
||||
// Usage:
|
||||
// chamfer_cylinder_mask(r|d=, chamfer, [ang], [from_end]) [ATTACHMENTS];
|
||||
// Description:
|
||||
// Create a mask that can be used to bevel/chamfer the end of a cylindrical region.
|
||||
// Difference it from the end of the region to be chamfered. The center of the mask
|
||||
// object should align exactly with the center of the end of the cylindrical region
|
||||
// to be chamfered.
|
||||
// Arguments:
|
||||
// r = Radius of cylinder to chamfer.
|
||||
// chamfer = Size of the edge chamfered, inset from edge.
|
||||
// ---
|
||||
// d = Diameter of cylinder to chamfer. Use instead of r.
|
||||
// ang = Angle of chamfer in degrees from the horizontal. (Default: 45)
|
||||
// from_end = If true, chamfer size is measured from end of cylinder. If false, chamfer is measured outset from the radius of the cylinder. (Default: false)
|
||||
// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). Default: `CENTER`
|
||||
// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#subsection-spin). Default: `0`
|
||||
// orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#subsection-orient). Default: `UP`
|
||||
// Side Effects:
|
||||
// Tags the children with "remove" (and hence sets `$tag`) if no tag is already set.
|
||||
// Example:
|
||||
// difference() {
|
||||
// cylinder(r=50, h=100, center=true);
|
||||
// up(50) #chamfer_cylinder_mask(r=50, chamfer=10);
|
||||
// }
|
||||
// Example:
|
||||
// difference() {
|
||||
// cylinder(r=50, h=100, center=true);
|
||||
// up(50) chamfer_cylinder_mask(r=50, chamfer=10);
|
||||
// }
|
||||
// Example: Changing the chamfer angle
|
||||
// difference() {
|
||||
// cylinder(r=50, h=100, center=true);
|
||||
// up(50) #chamfer_cylinder_mask(r=50, chamfer=10, ang=70);
|
||||
// }
|
||||
// Example:
|
||||
// difference() {
|
||||
// cylinder(r=50, h=100, center=true);
|
||||
// up(50) chamfer_cylinder_mask(r=50, chamfer=10, ang=70);
|
||||
// }
|
||||
// Example: Masking by Attachment
|
||||
// diff()
|
||||
// cyl(d=100,h=40)
|
||||
// attach([TOP,BOT])
|
||||
// tag("remove")chamfer_cylinder_mask(d=100, chamfer=10);
|
||||
function chamfer_cylinder_mask(r, chamfer, d, ang=45, from_end=false, anchor=CENTER, spin=0, orient=UP) = no_function("chamfer_cylinder_mask");
|
||||
module chamfer_cylinder_mask(r, chamfer, d, ang=45, from_end=false, anchor=CENTER, spin=0, orient=UP)
|
||||
{
|
||||
r = get_radius(r=r, d=d, dflt=1);
|
||||
dummy = assert(all_nonnegative([chamfer]), "Chamfer must be a nonnegative number");
|
||||
ch = from_end? chamfer : opp_ang_to_adj(chamfer,90-ang);
|
||||
default_tag("remove"){
|
||||
attachable(anchor,spin,orient, r=r, l=ch*2) {
|
||||
difference() {
|
||||
cyl(r=r+chamfer, l=ch*2, anchor=CENTER);
|
||||
cyl(r=r, l=ch*3, chamfer=chamfer, chamfang=ang, from_end=from_end, anchor=TOP);
|
||||
}
|
||||
children();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Section: Rounding Masks
|
||||
|
||||
// Module: rounding_edge_mask()
|
||||
// Synopsis: Creates a shape to round an arbitrary 3d edge.
|
||||
// SynTags: Geom
|
||||
// Topics: Masks, Rounding, Shapes (3D)
|
||||
// See Also: edge_profile(), rounding_corner_mask(), default_tag(), diff()
|
||||
// Usage:
|
||||
// rounding_edge_mask(l|h=|length=|height=, r|d=, [ang], [excess=], [rounding=|chamfer=], ) [ATTACHMENTS];
|
||||
// rounding_edge_mask(l|h=|length=|height=, r1=|d1=, r2=|d2=, [ang=], [excess=], [rounding=|chamfer=]) [ATTACHMENTS];
|
||||
// Description:
|
||||
// Creates a mask shape that can be used to round a straight edge at any angle, with
|
||||
// different rounding radii at each end. The corner of the mask appears on the Z axis with one face on the XZ plane.
|
||||
// You must align the mask corner with the edge you want to round. If your parent object is a cuboid, the easiest way to
|
||||
// do this is to use {{diff()}} and {{edge_mask()}}. However, this method is somewhat inflexible regarding orientation of a tapered
|
||||
// mask, and it does not support other parent shapes. You can attach the mask to a larger range of shapes using
|
||||
// {{attach()}} to anchor the `LEFT+FWD` anchor of the mask to a desired corner on the parent with `inside=true`.
|
||||
// Many shapes propagate `$edge_angle` and `$edge_length` which can aid in configuring the mask, and you can adjust the
|
||||
// mask as needed to align the taper as desired. The default "remove" tag is set so {{diff()}} will automatically difference
|
||||
// away the mask. You can of course also position the mask manually and use `difference()`.
|
||||
// .
|
||||
// For mating with other roundings or chamfers on cuboids or regular prisms, you can choose end roundings and end chamfers. These affect
|
||||
// only the curved edge of the mask ends and will only work if the terminating face is perpendicular to the masked edge. The `excess`
|
||||
// parameter will add extra length to the mask when you use these settings.
|
||||
//
|
||||
// Arguments:
|
||||
// l/h/length/height = Length of mask. Default: $edge_length if defined
|
||||
// r = Radius of the rounding.
|
||||
// ang = Angle between faces for rounding. Default: $edge_angle if defined, otherwise 90
|
||||
// ---
|
||||
// r1 = Bottom radius of rounding.
|
||||
// r2 = Top radius of rounding.
|
||||
// d = Diameter of the rounding.
|
||||
// d1 = Bottom diameter of rounding.
|
||||
// d2 = Top diameter of rounding.
|
||||
// excess = Extra size for the mask. Defaults: 0.1
|
||||
// rounding = Radius of roundong along ends. Default: 0
|
||||
// rounding1 = Radius of rounding along bottom end
|
||||
// rounding2 = Radius of rounding along top end
|
||||
// chamfer = Chamfer size of end chamfers. Default: 0
|
||||
// chamfer1 = Chamfer size of chamfer at bottom end
|
||||
// chamfer2 = Chamfer size of chamfer at top end
|
||||
// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). Default: `CENTER`
|
||||
// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#subsection-spin). Default: `0`
|
||||
// orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#subsection-orient). Default: `UP`
|
||||
// Side Effects:
|
||||
// Tags the children with "remove" (and hence sets `$tag`) if no tag is already set.
|
||||
// Example(VPD=200,VPR=[55,0,120]):
|
||||
// rounding_edge_mask(l=50, r=15);
|
||||
// Example(VPD=200,VPR=[55,0,120]): With different radii at each end
|
||||
// rounding_edge_mask(l=50, r1=10, r2=25);
|
||||
// Example(VPD=200,VPR=[55,0,120]): Acute angle
|
||||
// rounding_edge_mask(l=50, r=10, ang=45);
|
||||
// Example(VPD=200,VPR=[55,0,120]): A large excess
|
||||
// rounding_edge_mask(l=50, r=15,excess=4);
|
||||
// Example: Subtracting from a cube
|
||||
// difference() {
|
||||
// cube(size=100, center=false);
|
||||
// #rounding_edge_mask(l=100, r=25, anchor=BOTTOM);
|
||||
// }
|
||||
// Example: Varying Rounding Radius
|
||||
// difference() {
|
||||
// cube(size=50, center=false);
|
||||
// down(1)rounding_edge_mask(l=52, r1=25, r2=10, anchor=BOTTOM);
|
||||
// }
|
||||
// Example: Angle not 90 degrees
|
||||
// difference() {
|
||||
// pie_slice(ang=70, h=50, d=100, center=true);
|
||||
// #rounding_edge_mask(h=51, r=20.0, ang=70, $fn=32);
|
||||
// }
|
||||
// Example: Varying Rounding Radius
|
||||
// difference() {
|
||||
// pie_slice(ang=70, h=50, d=100, center=true);
|
||||
// #rounding_edge_mask(h=51, r1=10, r2=25, ang=70, $fn=32);
|
||||
// }
|
||||
// Example: Rounding a non-right angled edge, with a zero radius at the bottom.
|
||||
// difference(){
|
||||
// linear_extrude(height=50)xflip(x=25)right_triangle([50,50]);
|
||||
// rounding_edge_mask(l=51, ang=45, r1=0, r2=15, anchor=BOT);
|
||||
// }
|
||||
// Example: Masking by Attachment
|
||||
// diff()
|
||||
// cube(100, center=true)
|
||||
// edge_mask(FRONT+RIGHT)
|
||||
// #rounding_edge_mask(l=$parent_size.z+0.01, r=25);
|
||||
// Example: Multiple Masking by Attachment
|
||||
// diff()
|
||||
// cube([80,90,100], center=true) {
|
||||
// let(p = $parent_size*1.01) {
|
||||
// edge_mask(TOP)
|
||||
// rounding_edge_mask(l=p.z, r=25);
|
||||
// }
|
||||
// }
|
||||
// Example(3D,VPT=[5.02872,6.37039,-0.503894],VPR=[75.3,0,107.4],VPD=74.4017): Mask shape with end rounding at the top, chamfer at the bottom, and a large excess value:
|
||||
// rounding_edge_mask(r=10,h=20, chamfer1=3, rounding2=3, excess=1);
|
||||
// Example(3D,VPT=[1.05892,1.10442,2.20513],VPR=[60.6,0,118.1],VPD=74.4017): Attaching masks using {{attach()}} with automatic angle and length from the parent. Note that sometimes the automatic length is too short because it is the length of the edge itself.
|
||||
// diff()
|
||||
// prismoid([20,30],[12,19], h=10,shift=[4,7])
|
||||
// attach([TOP+RIGHT,RIGHT+FRONT],LEFT+FWD,inside=true)
|
||||
// rounding_edge_mask(r1=2,r2=4);
|
||||
// Example(3D): The mask does not need to be the full length of the edge
|
||||
// diff()
|
||||
// cuboid(20)
|
||||
// attach(RIGHT+TOP,LEFT+FWD,inside=true,inset=-.1,align=FWD)
|
||||
// rounding_edge_mask(r1=0,r2=10,length=10);
|
||||
|
||||
function rounding_edge_mask(l, r, ang=90, r1, r2, d, d1, d2, excess=0.1, anchor=CENTER, spin=0, orient=UP, h,height,length) = no_function("rounding_edge_mask");
|
||||
module rounding_edge_mask(l, r, ang, r1, r2, excess=0.01, d1, d2,d,r,length, h, height, anchor=CENTER, spin=0, orient=UP,
|
||||
rounding,rounding1,rounding2,chamfer,chamfer1,chamfer2,
|
||||
_remove_tag=true)
|
||||
{
|
||||
ang = first_defined([ang,$edge_angle,90]);
|
||||
length = is_def($edge_length) && !any_defined([l,length,h,height]) ? $edge_length
|
||||
: one_defined([l,length,h,height],"l,length,h,height");
|
||||
r1 = get_radius(r1=r1, d1=d1,d=d,r=r);
|
||||
r2 = get_radius(r2=r2, d1=d2,d=d,r=r);
|
||||
dummy1 = assert(num_defined([chamfer,rounding])<2, "Cannot give both rounding and chamfer")
|
||||
assert(num_defined([chamfer1,rounding1])<2, "Cannot give both rounding1 and chamfer1")
|
||||
assert(num_defined([chamfer2,rounding2])<2, "Cannot give both rounding2 and chamfer2");
|
||||
rounding1 = first_defined([rounding1,rounding,0]);
|
||||
rounding2 = first_defined([rounding2,rounding,0]);
|
||||
chamfer1 = first_defined([chamfer1,chamfer,0]);
|
||||
chamfer2 = first_defined([chamfer2,chamfer,0]);
|
||||
dummy = assert(all_nonnegative([r1,r2]), "radius/diameter value(s) must be nonnegative")
|
||||
assert(all_positive([length]), "length/l/h/height must be a positive value")
|
||||
assert(is_finite(ang) && ang>0 && ang<180, "ang must be a number between 0 and 180")
|
||||
assert(all_nonnegative([chamfer1,chamfer2,rounding1,rounding2]), "chamfers and roundings must be nonnegative");
|
||||
steps = max(2,segs(max(r1,r2), 180-ang));
|
||||
function make_path(r) =
|
||||
r==0 ? repeat([0,0],steps+1)
|
||||
: arc(n=steps+1, r=r, corner=[polar_to_xy(r,ang),[0,0],[r,0]]);
|
||||
path1 = path3d(make_path(r1),-length/2);
|
||||
path2 = path3d(make_path(r2),length/2);
|
||||
|
||||
function getarc(bigr,r,chamfer,p1,p2,h,print=false) =
|
||||
r==0 && chamfer==0? [p2]
|
||||
:
|
||||
let(
|
||||
steps = ceil(segs(r)/4)+1,
|
||||
center = [bigr/tan(ang/2), bigr,h],
|
||||
refplane = plane_from_normal([-(p2-center).y, (p2-center).x, 0], p2),
|
||||
refnormal = plane_normal(refplane),
|
||||
mplane = plane3pt(p2,p1,center),
|
||||
A = plane_normal(mplane),
|
||||
basept = lerp(p2,p1,max(r,chamfer)/2/h),
|
||||
corner = [basept+refnormal*(refplane[3]-basept*refnormal)/(refnormal*refnormal),
|
||||
p2,
|
||||
center],
|
||||
bare_arc = chamfer ? [p2+chamfer*unit(corner[0]-corner[1]),p2+chamfer*unit(corner[2]-corner[1])]
|
||||
: arc(r=r, corner = corner, n=steps),
|
||||
arc_with_excess = [each bare_arc, up(excess, last(bare_arc))],
|
||||
arc = [for(pt=arc_with_excess) pt+refnormal*(mplane[3]-pt*A)/(refnormal*A)]
|
||||
)
|
||||
arc;
|
||||
cp = [-excess/tan(ang/2), -excess];
|
||||
extra1 = rounding1 || chamfer1 ? [0,0,excess] : CTR;
|
||||
extra2 = rounding2 || chamfer2 ? [0,0,excess] : CTR;
|
||||
pathlist = [for(i=[0:len(path1)-1])
|
||||
let(
|
||||
path = [
|
||||
if (i==0) move(polar_to_xy( excess, 90+ang),path1[i]-extra1)
|
||||
else if (i==len(path1)-1) fwd(excess,last(path1)-extra1)
|
||||
else point3d(cp,-length/2-extra1.z),
|
||||
each reverse(zflip(getarc(r1,rounding1,chamfer1,zflip(path2[i]), zflip(path1[i]),length/2))),
|
||||
each getarc(r2,rounding2,chamfer2,path1[i],path2[i],length/2,print=rounding2!=0&&!is_undef(rounding2)&&i==3),
|
||||
if (i==0) move(polar_to_xy( excess, 90+ang),path2[i]+extra2)
|
||||
else if (i==len(path2)-1) fwd(excess,last(path2)+extra2)
|
||||
else point3d(cp, length/2+extra2.z),
|
||||
]
|
||||
)
|
||||
path];
|
||||
|
||||
left_normal = cylindrical_to_xyz(1,90+ang,0);
|
||||
left_dir = cylindrical_to_xyz(1,ang,0);
|
||||
zdir = unit([length, 0,-(r2-r1)/tan(ang/2)]);
|
||||
cutfact = 1/sin(ang/2)-1;
|
||||
|
||||
v=unit(zrot(ang,zdir)+left_normal);
|
||||
ref = UP - (v*UP)*v;
|
||||
backleft_spin=-vector_angle(rot(from=UP,to=v,p=BACK),ref);
|
||||
|
||||
override = [
|
||||
[CENTER, [CENTER,UP]],
|
||||
[TOP, [[0,0,length/2]]],
|
||||
[BOT, [[0,0,-length/2]]],
|
||||
[FWD, [[(r1+r2)/tan(ang/2)/4,0,0]]],
|
||||
[FWD+BOT, [[r1/tan(ang/2)/2,0,-length/2]]],
|
||||
[FWD+TOP, [[r2/tan(ang/2)/2,0,length/2]]],
|
||||
[LEFT, [(r1+r2)/tan(ang/2)/4*left_dir, left_normal,ang-180]],
|
||||
[LEFT+BOT, [down(length/2,r1/tan(ang/2)/2*left_dir), rot(v=left_dir,-45,p=left_normal),ang-180]],
|
||||
[LEFT+TOP, [up(length/2,r2/tan(ang/2)/2*left_dir), rot(v=left_dir, 45, p=left_normal),ang-180]],
|
||||
[LEFT+FWD, [CENTER, left_normal+FWD,ang/2-90]],
|
||||
[LEFT+FWD+TOP, [[0,0,length/2], left_normal+FWD+UP,ang/2-90]],
|
||||
[LEFT+FWD+BOT, [[0,0,-length/2], left_normal+FWD+DOWN,ang/2-90]],
|
||||
[RIGHT, [[(r1+r2)/2/tan(ang/2),0,0],zdir]],
|
||||
[RIGHT+TOP, [[r2/tan(ang/2),0,length/2],zdir+UP]],
|
||||
[RIGHT+BOT, [[r1/tan(ang/2),0,-length/2],zdir+DOWN]],
|
||||
[RIGHT+FWD, [[(r1+r2)/2/tan(ang/2),0,0],zdir+FWD]],
|
||||
[RIGHT+TOP+FWD, [[r2/tan(ang/2),0,length/2],zdir+UP+FWD]],
|
||||
[RIGHT+BOT+FWD, [[r1/tan(ang/2),0,-length/2],zdir+DOWN+FWD]],
|
||||
[BACK, [ (r1+r2)/2/tan(ang/2)*left_dir,zrot(ang,zdir),ang+90]],
|
||||
[BACK+BOT, [ down(length/2,r1/tan(ang/2)*left_dir),zrot(ang,zdir)+DOWN,ang+90]],
|
||||
[BACK+UP, [ up(length/2,r2/tan(ang/2)*left_dir),zrot(ang,zdir)+UP,ang+90]],
|
||||
[BACK+LEFT, [ (r1+r2)/2/tan(ang/2)*left_dir,zrot(ang,zdir)+left_normal, backleft_spin]],
|
||||
[BACK+BOT+LEFT, [ down(length/2,r1/tan(ang/2)*left_dir),zrot(ang,zdir)+left_normal+DOWN,backleft_spin]],
|
||||
[BACK+UP+LEFT, [ up(length/2,r2/tan(ang/2)*left_dir),zrot(ang,zdir)+left_normal+UP,backleft_spin]],
|
||||
[BACK+RIGHT, [cylindrical_to_xyz(cutfact*(r1+r2)/2,ang/2,0), zrot(ang/2,zdir),ang/2+90]],
|
||||
[BACK+RIGHT+TOP, [cylindrical_to_xyz(cutfact*r2,ang/2,length/2), zrot(ang/2,zdir)+UP,ang/2+90]],
|
||||
[BACK+RIGHT+BOT, [cylindrical_to_xyz(cutfact*r1,ang/2,-length/2), zrot(ang/2,zdir)+DOWN,ang/2+90]],
|
||||
];
|
||||
vnf = vnf_vertex_array(reverse(pathlist), col_wrap=true,caps=true);
|
||||
default_tag("remove", _remove_tag)
|
||||
attachable(anchor,spin,orient,size=[1,1,length],override=override){
|
||||
vnf_polyhedron(vnf);
|
||||
children();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Module: rounding_corner_mask()
|
||||
// Synopsis: Creates a shape to round 90° corners.
|
||||
// SynTags: Geom
|
||||
// Topics: Masking, Rounding, Shapes (3D)
|
||||
// See Also: rounding_edge_mask(), default_tag(), diff()
|
||||
// Usage:
|
||||
// rounding_corner_mask(r|d, [ang], [excess=], [style=]) [ATTACHMENTS];
|
||||
// Description:
|
||||
// Creates a shape that you can use to round corners where the top and bottom faces are parallel and the two side
|
||||
// faces are perpendicular to the top and bottom, e.g. cubes or pie_slice corners.
|
||||
// Difference it from the object to be rounded. The center of the mask
|
||||
// object should align exactly with the corner to be rounded.
|
||||
// Arguments:
|
||||
// r = Radius of corner rounding.
|
||||
// ang = Angle of corner (measured around the z axis). Default: 90
|
||||
// ---
|
||||
// d = Diameter of corner rounding.
|
||||
// excess = Extra size for the mask. Defaults: 0.1
|
||||
// style = The style of the sphere cutout's construction. One of "orig", "aligned", "stagger", "octa", or "icosa". Default: "octa"
|
||||
// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). Default: `CENTER`
|
||||
// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#subsection-spin). Default: `0`
|
||||
// orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#subsection-orient). Default: `UP`
|
||||
// Side Effects:
|
||||
// Tags the children with "remove" (and hence sets `$tag`) if no tag is already set.
|
||||
// Example:
|
||||
// rounding_corner_mask(r=20);
|
||||
// Example: Adding a huge excess
|
||||
// rounding_corner_mask(r=20, excess=5);
|
||||
// Example: Position masks manually
|
||||
// difference() {
|
||||
// cube(size=[50, 60, 70], center=true);
|
||||
// translate([-25, -30, 35])
|
||||
// #rounding_corner_mask(r=20, spin=90, orient=DOWN);
|
||||
// translate([25, -30, 35])
|
||||
// #rounding_corner_mask(r=20, orient=DOWN);
|
||||
// translate([25, -30, -35])
|
||||
// #rounding_corner_mask(r=20, spin=90);
|
||||
// }
|
||||
// Example: Masking by Attachment
|
||||
// diff()
|
||||
// cube(size=[50, 60, 70]) {
|
||||
// corner_mask(TOP)
|
||||
// #rounding_corner_mask(r=20);
|
||||
// }
|
||||
// Example(VPR=[71.8,0,345.8],VPT=[57.0174,43.8496,24.5863],VPD=263.435,NoScales): Acute angle
|
||||
// ang=60;
|
||||
// difference() {
|
||||
// pie_slice(ang=ang, h=50, r=100);
|
||||
// zflip_copy(z=25)
|
||||
// #rounding_corner_mask(r=20, ang=ang);
|
||||
// }
|
||||
// Example(VPR=[62.7,0,5.4],VPT=[6.9671,22.7592,20.7513],VPD=192.044): Obtuse angle
|
||||
// ang=120;
|
||||
// difference() {
|
||||
// pie_slice(ang=ang, h=50, r=30);
|
||||
// zflip_copy(z=25)
|
||||
// #rounding_corner_mask(r=20, ang=ang);
|
||||
// }
|
||||
|
||||
function rounding_corner_mask(r, ang, d, style="octa", excess=0.1, anchor=CENTER, spin=0, orient=UP) = no_function("rounding_corner_mask");
|
||||
module rounding_corner_mask(r, ang=90, d, style="octa", excess=0.1, anchor=CENTER, spin=0, orient=UP)
|
||||
{
|
||||
r = get_radius(r=r, d=d, dflt=1);
|
||||
joint = r/tan(ang/2);
|
||||
path = [
|
||||
[joint,r],
|
||||
[joint,-excess],
|
||||
[-excess/tan(ang/2),-excess],
|
||||
polar_to_xy(joint,ang)+polar_to_xy(excess,90+ang)
|
||||
];
|
||||
default_tag("remove") {
|
||||
attachable(anchor,spin,orient, size=[2,2,2]*r) {
|
||||
difference() {
|
||||
down(excess)
|
||||
linear_extrude(height=r+excess) polygon(path);
|
||||
translate([joint,r,r])
|
||||
spheroid(r=r, style=style);
|
||||
}
|
||||
children();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function rounding_angled_edge_mask(h, r, r1, r2, d, d1, d2, ang=90, anchor=CENTER, spin=0, orient=UP,l,height,length) = no_function("rounding_angled_edge_mask");
|
||||
module rounding_angled_edge_mask(h, r, r1, r2, d, d1, d2, ang=90, anchor=CENTER, spin=0, orient=UP,l,height,length)
|
||||
{
|
||||
deprecate("angled_edge_mask");
|
||||
rounding_edge_mask(h=h,r=r,r1=r1,r2=r2,d=d,d1=d1,d2=d1,ang=ang,anchor=anchor,spin=spin,orient=orient,l=l,height=height,length=length)
|
||||
children();
|
||||
}
|
||||
|
||||
|
||||
function rounding_angled_corner_mask(r, ang=90, d, anchor=CENTER, spin=0, orient=UP) = no_function("rounding_angled_corner_mask");
|
||||
module rounding_angled_corner_mask(r, ang=90, d, anchor=CENTER, spin=0, orient=UP)
|
||||
{
|
||||
deprecate("rounding_corner_mask");
|
||||
zflip()rounding_corner_mask(r=r,ang=ang,d=d,anchor=anchor,spin=spin,orient=orient)
|
||||
children();
|
||||
}
|
||||
|
||||
|
||||
// Module: rounding_cylinder_mask()
|
||||
// Synopsis: Creates a shape to round the end of a cylinder.
|
||||
// SynTags: Geom
|
||||
// Topics: Masking, Rounding, Cylinders
|
||||
// See Also: rounding_hole_mask(), rounding_corner_mask(), default_tag(), diff()
|
||||
// Usage:
|
||||
// rounding_cylinder_mask(r|d=, rounding);
|
||||
// Description:
|
||||
// Create a mask that can be used to round the end of a cylinder.
|
||||
// Difference it from the cylinder to be rounded. The center of the
|
||||
// mask object should align exactly with the center of the end of the
|
||||
// cylinder to be rounded.
|
||||
// Arguments:
|
||||
// r = Radius of cylinder.
|
||||
// rounding = Radius of the edge rounding.
|
||||
// ---
|
||||
// d = Diameter of cylinder.
|
||||
// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). Default: `CENTER`
|
||||
// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#subsection-spin). Default: `0`
|
||||
// orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#subsection-orient). Default: `UP`
|
||||
// Side Effects:
|
||||
// Tags the children with "remove" (and hence sets `$tag`) if no tag is already set.
|
||||
// Example:
|
||||
// difference() {
|
||||
// cylinder(r=50, h=50, center=false);
|
||||
// up(50) #rounding_cylinder_mask(r=50, rounding=10);
|
||||
// }
|
||||
// Example:
|
||||
// difference() {
|
||||
// cylinder(r=50, h=50, center=false);
|
||||
// up(50) rounding_cylinder_mask(r=50, rounding=10);
|
||||
// }
|
||||
// Example: Masking by Attachment
|
||||
// diff()
|
||||
// cyl(h=30, d=30) {
|
||||
// attach(TOP)
|
||||
// #tag("remove")
|
||||
// rounding_cylinder_mask(d=30, rounding=5);
|
||||
// }
|
||||
function rounding_cylinder_mask(r, rounding, d, anchor, spin, orient) = no_function("rounding_cylinder_mask");
|
||||
module rounding_cylinder_mask(r, rounding, d, anchor=CENTER, spin=0, orient=UP)
|
||||
{
|
||||
r = get_radius(r=r, d=d, dflt=1);
|
||||
default_tag("remove") {
|
||||
attachable(anchor,spin,orient, r=r+rounding, l=rounding*2) {
|
||||
difference() {
|
||||
cyl(r=r+rounding, l=rounding*2, anchor=CENTER);
|
||||
cyl(r=r, l=rounding*3, rounding=rounding, anchor=TOP);
|
||||
}
|
||||
children();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Module: rounding_hole_mask()
|
||||
// Synopsis: Creates a shape to round the edge of a round hole.
|
||||
// SynTags: Geom
|
||||
// Topics: Masking, Rounding
|
||||
// See Also: rounding_cylinder_mask(), rounding_hole_mask(), rounding_corner_mask(), default_tag(), diff()
|
||||
// Usage:
|
||||
// rounding_hole_mask(r|d, rounding, [excess]) [ATTACHMENTS];
|
||||
// Description:
|
||||
// Create a mask that can be used to round the edge of a circular hole.
|
||||
// Difference it from the hole to be rounded. The center of the
|
||||
// mask object should align exactly with the center of the end of the
|
||||
// hole to be rounded.
|
||||
// Arguments:
|
||||
// r = Radius of hole.
|
||||
// rounding = Radius of the rounding.
|
||||
// excess = The extra thickness of the mask. Default: `0.1`.
|
||||
// ---
|
||||
// d = Diameter of hole to rounding.
|
||||
// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). Default: `CENTER`
|
||||
// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#subsection-spin). Default: `0`
|
||||
// orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#subsection-orient). Default: `UP`
|
||||
// Side Effects:
|
||||
// Tags the children with "remove" (and hence sets `$tag`) if no tag is already set.
|
||||
// Example:
|
||||
// rounding_hole_mask(r=40, rounding=20, $fa=2, $fs=2);
|
||||
// Example(Med):
|
||||
// difference() {
|
||||
// cube([150,150,100], center=true);
|
||||
// cylinder(r=50, h=100.1, center=true);
|
||||
// up(50) #rounding_hole_mask(r=50, rounding=10);
|
||||
// }
|
||||
// Example(Med):
|
||||
// difference() {
|
||||
// cube([150,150,100], center=true);
|
||||
// cylinder(r=50, h=100.1, center=true);
|
||||
// up(50) rounding_hole_mask(r=50, rounding=10);
|
||||
// }
|
||||
function rounding_hole_mask(r, rounding, excess=0.1, d, anchor=CENTER, spin=0, orient=UP) = no_function("rounding_hole_mask");
|
||||
module rounding_hole_mask(r, rounding, excess=0.1, d, anchor=CENTER, spin=0, orient=UP)
|
||||
{
|
||||
r = get_radius(r=r, d=d, dflt=1);
|
||||
default_tag("remove") {
|
||||
attachable(anchor,spin,orient, r=r+rounding, l=2*rounding) {
|
||||
rotate_extrude(convexity=4) {
|
||||
difference() {
|
||||
right(r-excess) fwd(rounding) square(rounding+excess, center=false);
|
||||
right(r+rounding) fwd(rounding) circle(r=rounding);
|
||||
}
|
||||
}
|
||||
children();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Section: Teardrop Masking
|
||||
|
||||
// Module: teardrop_edge_mask()
|
||||
// Synopsis: Creates a shape to round a 90° edge but limit the angle of overhang.
|
||||
// SynTags: Geom
|
||||
// Topics: Masking, Rounding, Shapes (3D), FDM Optimized
|
||||
// See Also: teardrop_corner_mask(), teardrop_edge_mask(), default_tag(), diff()
|
||||
// Usage:
|
||||
// teardrop_edge_mask(l|h=|length=|height=, r|d=, [angle], [excess], [anchor], [spin], [orient]) [ATTACHMENTS];
|
||||
// Description:
|
||||
// Makes an apropriate 3D edge rounding mask that keeps within `angle` degrees of vertical.
|
||||
// Arguments:
|
||||
// l/h/length/height = length of mask
|
||||
// r = Radius of the mask rounding.
|
||||
// angle = Maximum angle from vertical. Default: 45
|
||||
// excess = Excess mask size. Default: 0.1
|
||||
// ---
|
||||
// d = Diameter of the mask rounding.
|
||||
// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). Default: `CENTER`
|
||||
// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#subsection-spin). Default: `0`
|
||||
// orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#subsection-orient). Default: `UP`
|
||||
// Side Effects:
|
||||
// Tags the children with "remove" (and hence sets `$tag`) if no tag is already set.
|
||||
// Example(VPD=50,VPR=[55,0,120]):
|
||||
// teardrop_edge_mask(l=20, r=10, angle=40);
|
||||
// Example(VPD=300,VPR=[75,0,25]):
|
||||
// diff()
|
||||
// cuboid([50,60,70],rounding=10,edges="Z",anchor=CENTER) {
|
||||
// edge_mask(BOT)
|
||||
// teardrop_edge_mask(l=max($parent_size)+1, r=10, angle=40);
|
||||
// corner_mask(BOT)
|
||||
// teardrop_corner_mask(r=10, angle=40);
|
||||
// }
|
||||
function teardrop_edge_mask(l, r, angle=45, excess=0.1, d, anchor, spin, orient,h,height,length) = no_function("teardrop_edge_mask");
|
||||
module teardrop_edge_mask(l, r, angle=45, excess=0.1, d, anchor=CTR, spin=0, orient=UP,h,height,length)
|
||||
{
|
||||
l = one_defined([l, h, height, length], "l,h,height,length");
|
||||
check =
|
||||
assert(is_num(l) && l>0, "Length of mask must be positive")
|
||||
assert(is_num(angle) && angle>0 && angle<90, "Angle must be a number between 0 and 90")
|
||||
assert(is_num(excess));
|
||||
r = get_radius(r=r, d=d, dflt=1);
|
||||
path = mask2d_teardrop(r=r, angle=angle, excess=excess);
|
||||
default_tag("remove") {
|
||||
linear_sweep(path, height=l, center=true, atype="bbox", anchor=anchor, spin=spin, orient=orient) children();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Module: teardrop_corner_mask()
|
||||
// Synopsis: Creates a shape to round a 90° corner but limit the angle of overhang.
|
||||
// SynTags: Geom
|
||||
// Topics: Masking, Rounding, Shapes (3D), FDM Optimized
|
||||
// See Also: teardrop_corner_mask(), teardrop_edge_mask(), default_tag(), diff()
|
||||
// Usage:
|
||||
// teardrop_corner_mask(r|d=, [angle], [excess], [anchor], [spin], [orient]) [ATTACHMENTS];
|
||||
// Description:
|
||||
// Makes an apropriate 3D corner rounding mask that keeps within `angle` degrees of vertical.
|
||||
// Arguments:
|
||||
// r = Radius of the mask rounding.
|
||||
// angle = Maximum angle from vertical. Default: 45
|
||||
// excess = Excess mask size. Default: 0.1
|
||||
// ---
|
||||
// d = Diameter of the mask rounding.
|
||||
// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). Default: `CENTER`
|
||||
// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#subsection-spin). Default: `0`
|
||||
// orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#subsection-orient). Default: `UP`
|
||||
// Side Effects:
|
||||
// Tags the children with "remove" (and hence sets `$tag`) if no tag is already set.
|
||||
// Example:
|
||||
// teardrop_corner_mask(r=20, angle=40);
|
||||
// Example:
|
||||
// diff()
|
||||
// cuboid([50,60,70],rounding=10,edges="Z",anchor=CENTER) {
|
||||
// edge_profile(BOT)
|
||||
// mask2d_teardrop(r=10, angle=40);
|
||||
// corner_mask(BOT)
|
||||
// teardrop_corner_mask(r=10, angle=40);
|
||||
// }
|
||||
function teardrop_corner_mask(r, angle=45, excess=0.1, d, anchor, spin, orient) = no_function("teardrop_corner_mask");
|
||||
module teardrop_corner_mask(r, angle=45, excess=0.1, d, anchor=CTR, spin=0, orient=UP)
|
||||
{
|
||||
assert(is_num(angle));
|
||||
assert(is_num(excess));
|
||||
assert(angle>0 && angle<90);
|
||||
r = get_radius(r=r, d=d, dflt=1);
|
||||
size = (r+excess) * [1,1,1];
|
||||
midpt = (r-excess)/2 * [1,1,1];
|
||||
default_tag("remove") {
|
||||
attachable(anchor,spin,orient, size=size, offset=midpt) {
|
||||
difference() {
|
||||
translate(-[1,1,1]*excess) cube(r+excess, center=false);
|
||||
translate([1,1,1]*r) onion(r=r, ang=angle, orient=DOWN);
|
||||
}
|
||||
children();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
|
||||
3
std.scad
3
std.scad
|
|
@ -20,8 +20,7 @@ include <beziers.scad>
|
|||
include <shapes3d.scad>
|
||||
include <shapes2d.scad>
|
||||
include <drawing.scad>
|
||||
include <masks3d.scad>
|
||||
include <masks2d.scad>
|
||||
include <masks.scad>
|
||||
include <math.scad>
|
||||
include <paths.scad>
|
||||
include <lists.scad>
|
||||
|
|
|
|||
|
|
@ -179,7 +179,7 @@ cuboid(50){
|
|||
}
|
||||
```
|
||||
|
||||
See [mask2d_roundover()](https://github.com/BelfrySCAD/BOSL2/wiki/masks2d.scad#functionmodule-mask2d_roundover) for additional mask parameters. Here we use the *inset* parameter to produce a bead.
|
||||
See [mask2d_roundover()](https://github.com/BelfrySCAD/BOSL2/wiki/masks.scad#functionmodule-mask2d_roundover) for additional mask parameters. Here we use the *inset* parameter to produce a bead.
|
||||
|
||||
```openscad-3D
|
||||
include <BOSL2/std.scad>
|
||||
|
|
@ -189,7 +189,7 @@ diff()
|
|||
mask2d_roundover(h=12, inset=4);
|
||||
```
|
||||
|
||||
You can use [edge-profile()](https://github.com/BelfrySCAD/BOSL2/wiki/attachments.scad#module-edge_profile) to round the top or bottom of a [prismoid()](https://github.com/BelfrySCAD/BOSL2/wiki/shapes3d.scad#functionmodule-prismoid). Because the side faces of a [prismoid()](https://github.com/BelfrySCAD/BOSL2/wiki/shapes3d.scad#functionmodule-prismoid) are not strictly vertical, it's is necessary to increase the length of the masks using the *excess* parameter in [edge_profile()](https://github.com/BelfrySCAD/BOSL2/wiki/attachments.scad#module-edge_profile), and to set the mask\_angle to $edge\_angle in [mask2d\_roundover()](https://github.com/BelfrySCAD/BOSL2/wiki/masks2d.scad#functionmodule-mask2d_roundover).
|
||||
You can use [edge-profile()](https://github.com/BelfrySCAD/BOSL2/wiki/attachments.scad#module-edge_profile) to round the top or bottom of a [prismoid()](https://github.com/BelfrySCAD/BOSL2/wiki/shapes3d.scad#functionmodule-prismoid). Because the side faces of a [prismoid()](https://github.com/BelfrySCAD/BOSL2/wiki/shapes3d.scad#functionmodule-prismoid) are not strictly vertical, it's is necessary to increase the length of the masks using the *excess* parameter in [edge_profile()](https://github.com/BelfrySCAD/BOSL2/wiki/attachments.scad#module-edge_profile), and to set the mask\_angle to $edge\_angle in [mask2d\_roundover()](https://github.com/BelfrySCAD/BOSL2/wiki/masks.scad#functionmodule-mask2d_roundover).
|
||||
|
||||
```openscad-3D
|
||||
include<BOSL2/std.scad>
|
||||
|
|
@ -219,7 +219,7 @@ diff()
|
|||
mask2d_roundover(h = 20, $fn = 64);
|
||||
```
|
||||
|
||||
The [mask2d_teardrop()](https://github.com/BelfrySCAD/BOSL2/wiki/masks2d.scad#functionmodule-mask2d_teardrop) mask can be used to round the bottom of a cube-like object. It limits the overhang angle to 45° or a value you specify in with the **angle** argument.
|
||||
The [mask2d_teardrop()](https://github.com/BelfrySCAD/BOSL2/wiki/masks.scad#functionmodule-mask2d_teardrop) mask can be used to round the bottom of a cube-like object. It limits the overhang angle to 45° or a value you specify in with the **angle** argument.
|
||||
|
||||
```
|
||||
include<BOSL2/std.scad>
|
||||
|
|
@ -237,7 +237,7 @@ diff()
|
|||
mask2d_teardrop(h = 5, angle = 50, mask_angle = $edge_angle, $fn = 64);
|
||||
```
|
||||
|
||||
In addition to the simple [roundover](https://github.com/BelfrySCAD/BOSL2/wiki/masks2d.scad#functionmodule-mask2d_roundover) mask, and the [teardrop](https://github.com/BelfrySCAD/BOSL2/wiki/masks2d.scad#functionmodule-mask2d_teardrop) mask, there are masks for [cove](https://github.com/BelfrySCAD/BOSL2/wiki/masks2d.scad#functionmodule-mask2d_cove), [chamfer](https://github.com/BelfrySCAD/BOSL2/wiki/masks2d.scad#functionmodule-mask2d_chamfer), [rabbet](https://github.com/BelfrySCAD/BOSL2/wiki/masks2d.scad#functionmodule-mask2d_rabbet), [dovetail](https://github.com/BelfrySCAD/BOSL2/wiki/masks2d.scad#functionmodule-mask2d_dovetail) and [ogee](https://github.com/BelfrySCAD/BOSL2/wiki/masks2d.scad#functionmodule-mask2d_ogee) edges.
|
||||
In addition to the simple [roundover](https://github.com/BelfrySCAD/BOSL2/wiki/masks.scad#functionmodule-mask2d_roundover) mask, and the [teardrop](https://github.com/BelfrySCAD/BOSL2/wiki/masks.scad#functionmodule-mask2d_teardrop) mask, there are masks for [cove](https://github.com/BelfrySCAD/BOSL2/wiki/masks.scad#functionmodule-mask2d_cove), [chamfer](https://github.com/BelfrySCAD/BOSL2/wiki/masks.scad#functionmodule-mask2d_chamfer), [rabbet](https://github.com/BelfrySCAD/BOSL2/wiki/masks.scad#functionmodule-mask2d_rabbet), [dovetail](https://github.com/BelfrySCAD/BOSL2/wiki/masks.scad#functionmodule-mask2d_dovetail) and [ogee](https://github.com/BelfrySCAD/BOSL2/wiki/masks.scad#functionmodule-mask2d_ogee) edges.
|
||||
|
||||
The mask2d_ogee() only works on [cube()](https://github.com/BelfrySCAD/BOSL2/wiki/shapes3d.scad#functionmodule-cube) and [cuboid()](https://github.com/BelfrySCAD/BOSL2/wiki/shapes3d.scad#module-cuboid) shapes, or a [prismoid()](https://github.com/BelfrySCAD/BOSL2/wiki/shapes3d.scad#functionmodule-prismoid) where size2 >= size1 in both the X and Y dimensions.
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue