mirror of
https://github.com/BelfrySCAD/BOSL2.git
synced 2025-12-07 11:22:07 +00:00
masks reorg
This commit is contained in:
parent
b657290835
commit
4b533144a9
3 changed files with 11 additions and 802 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
|
||||
|
|
|
|||
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