mirror of
https://github.com/BelfrySCAD/BOSL2.git
synced 2024-12-29 00:09:41 +00:00
fix doc errors
extend path_text to 2d
This commit is contained in:
parent
c7fd5d05fa
commit
814a3981ce
3 changed files with 322 additions and 288 deletions
524
attachments.scad
524
attachments.scad
|
@ -497,6 +497,257 @@ module hulling(a)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Section: Attachable Masks
|
||||
|
||||
|
||||
// Module: edge_mask()
|
||||
// Usage:
|
||||
// edge_mask([edges], [except]) {...}
|
||||
// Topics: Attachments
|
||||
// See Also: attachable(), position(), attach(), face_profile(), edge_profile(), corner_mask()
|
||||
// Description:
|
||||
// Takes a 3D mask shape, and attaches it to the given edges, with the appropriate orientation to be
|
||||
// `diff()`ed 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. For a more
|
||||
// step-by-step explanation of attachments, see the [[Attachments Tutorial|Tutorial-Attachments]].
|
||||
// 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 the docs for [`edges()`](edges.scad#edges) to see acceptable values. Default: All edges.
|
||||
// except = Edges to explicitly NOT mask. See the docs for [`edges()`](edges.scad#edges) to see acceptable values. Default: No edges.
|
||||
// Side Effects:
|
||||
// Sets `$tags = "mask"` for all children.
|
||||
// Example:
|
||||
// diff("mask")
|
||||
// cube([50,60,70],center=true)
|
||||
// edge_mask([TOP,"Z"],except=[BACK,TOP+LEFT])
|
||||
// rounding_mask_z(l=71,r=10);
|
||||
module edge_mask(edges=EDGES_ALL, except=[]) {
|
||||
assert($parent_geom != undef, "No 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 (vec = vecs) {
|
||||
vcount = (vec.x?1:0) + (vec.y?1:0) + (vec.z?1:0);
|
||||
assert(vcount == 2, "Not an edge vector!");
|
||||
anch = _find_anchor(vec, $parent_geom);
|
||||
$attach_to = undef;
|
||||
$attach_anchor = anch;
|
||||
$attach_norot = true;
|
||||
$tags = "mask";
|
||||
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) children();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Module: corner_mask()
|
||||
// Usage:
|
||||
// corner_mask([corners], [except]) {...}
|
||||
// Topics: Attachments
|
||||
// See Also: attachable(), position(), attach(), face_profile(), edge_profile(), edge_mask()
|
||||
// Description:
|
||||
// Takes a 3D mask shape, and attaches it to the given corners, with the appropriate orientation to
|
||||
// be `diff()`ed away. The 3D corner mask shape should be designed to mask away the X+Y+Z+ octant.
|
||||
// For a more step-by-step explanation of attachments, see the [[Attachments Tutorial|Tutorial-Attachments]].
|
||||
// Arguments:
|
||||
// corners = Edges to mask. See the docs for [`corners()`](edges.scad#corners) to see acceptable values. Default: All corners.
|
||||
// except = Edges to explicitly NOT mask. See the docs for [`corners()`](edges.scad#corners) to see acceptable values. Default: No corners.
|
||||
// Side Effects:
|
||||
// Sets `$tags = "mask"` for all children.
|
||||
// Example:
|
||||
// diff("mask")
|
||||
// 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=[]) {
|
||||
assert($parent_geom != undef, "No object to attach to!");
|
||||
corners = corners(corners, except=except);
|
||||
vecs = [for (i = [0:7]) if (corners[i]>0) CORNER_OFFSETS[i]];
|
||||
for (vec = vecs) {
|
||||
vcount = (vec.x?1:0) + (vec.y?1:0) + (vec.z?1:0);
|
||||
assert(vcount == 3, "Not an edge vector!");
|
||||
anch = _find_anchor(vec, $parent_geom);
|
||||
$attach_to = undef;
|
||||
$attach_anchor = anch;
|
||||
$attach_norot = true;
|
||||
$tags = "mask";
|
||||
rotang = vec.z<0?
|
||||
[ 0,0,180+v_theta(vec)-45] :
|
||||
[180,0,-90+v_theta(vec)-45];
|
||||
translate(anch[1]) rot(rotang) children();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Module: face_profile()
|
||||
// Usage:
|
||||
// face_profile(faces, r|d=, [convexity=]) {...}
|
||||
// Topics: Attachments
|
||||
// See Also: attachable(), position(), attach(), edge_profile(), corner_profile()
|
||||
// Description:
|
||||
// Given a 2D edge profile, extrudes it into a mask for all edges and corners bounding each given face.
|
||||
// For a more step-by-step explanation of attachments, see the [[Attachments Tutorial|Tutorial-Attachments]].
|
||||
// Arguments:
|
||||
// faces = Faces to mask edges and corners of.
|
||||
// r = Radius of corner mask.
|
||||
// ---
|
||||
// d = Diameter of corner mask.
|
||||
// convexity = Max number of times a line could intersect the perimeter of the mask shape. Default: 10
|
||||
// Side Effects:
|
||||
// Sets `$tags = "mask"` for all children.
|
||||
// Example:
|
||||
// diff("mask")
|
||||
// cube([50,60,70],center=true)
|
||||
// face_profile(TOP,r=10)
|
||||
// mask2d_roundover(r=10);
|
||||
module face_profile(faces=[], r, d, convexity=10) {
|
||||
faces = is_vector(faces)? [faces] : faces;
|
||||
assert(all([for (face=faces) is_vector(face) && sum([for (x=face) x!=0? 1 : 0])==1]), "Vector 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) children();
|
||||
corner_profile(faces, convexity=convexity, r=r) children();
|
||||
}
|
||||
|
||||
|
||||
// Module: edge_profile()
|
||||
// Usage:
|
||||
// edge_profile([edges], [except], [convexity]) {...}
|
||||
// Topics: Attachments
|
||||
// See Also: attachable(), position(), attach(), face_profile(), corner_profile()
|
||||
// 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. For a more step-by-step
|
||||
// explanation of attachments, see the [[Attachments Tutorial|Tutorial-Attachments]].
|
||||
// Arguments:
|
||||
// edges = Edges to mask. See the docs for [`edges()`](edges.scad#edges) to see acceptable values. Default: All edges.
|
||||
// except = Edges to explicitly NOT mask. See the docs for [`edges()`](edges.scad#edges) to see acceptable values. Default: No edges.
|
||||
// convexity = Max number of times a line could intersect the perimeter of the mask shape. Default: 10
|
||||
// Side Effects:
|
||||
// Sets `$tags = "mask"` for all children.
|
||||
// Example:
|
||||
// diff("mask")
|
||||
// cube([50,60,70],center=true)
|
||||
// edge_profile([TOP,"Z"],except=[BACK,TOP+LEFT])
|
||||
// mask2d_roundover(r=10, inset=2);
|
||||
module edge_profile(edges=EDGES_ALL, except=[], convexity=10) {
|
||||
assert($parent_geom != undef, "No 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 (vec = vecs) {
|
||||
vcount = (vec.x?1:0) + (vec.y?1:0) + (vec.z?1:0);
|
||||
assert(vcount == 2, "Not an edge vector!");
|
||||
anch = _find_anchor(vec, $parent_geom);
|
||||
$attach_to = undef;
|
||||
$attach_anchor = anch;
|
||||
$attach_norot = true;
|
||||
$tags = "mask";
|
||||
psize = point3d($parent_size);
|
||||
length = [for (i=[0:2]) if(!vec[i]) psize[i]][0]+0.1;
|
||||
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) {
|
||||
linear_extrude(height=length, center=true, convexity=convexity) {
|
||||
children();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Module: corner_profile()
|
||||
// Usage:
|
||||
// corner_profile([corners], [except], <r=|d=>, [convexity=]) {...}
|
||||
// Topics: Attachments
|
||||
// See Also: attachable(), position(), attach(), face_profile(), edge_profile()
|
||||
// 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. Tags it as a "mask" to allow it to be
|
||||
// `diff()`ed away, to give the corner a matching profile. For a more step-by-step explanation of
|
||||
// attachments, see the [[Attachments Tutorial|Tutorial-Attachments]].
|
||||
// Arguments:
|
||||
// corners = Edges to mask. See the docs for [`corners()`](edges.scad#corners) to see acceptable values. Default: All corners.
|
||||
// except = Edges to explicitly NOT mask. See the docs for [`corners()`](edges.scad#corners) to see acceptable values. Default: No corners.
|
||||
// ---
|
||||
// r = Radius of corner mask.
|
||||
// d = Diameter of corner mask.
|
||||
// convexity = Max number of times a line could intersect the perimeter of the mask shape. Default: 10
|
||||
// Side Effects:
|
||||
// Sets `$tags = "mask"` for all children.
|
||||
// Example:
|
||||
// diff("mask")
|
||||
// cuboid([50,60,70],rounding=10,edges="Z",anchor=CENTER) {
|
||||
// corner_profile(BOT,r=10)
|
||||
// mask2d_teardrop(r=10, angle=40);
|
||||
// }
|
||||
module corner_profile(corners=CORNERS_ALL, except=[], r, d, convexity=10) {
|
||||
assert($parent_geom != undef, "No object to attach to!");
|
||||
r = get_radius(r=r, d=d, dflt=undef);
|
||||
assert(is_num(r));
|
||||
corners = corners(corners, except=except);
|
||||
vecs = [for (i = [0:7]) if (corners[i]>0) CORNER_OFFSETS[i]];
|
||||
for (vec = vecs) {
|
||||
vcount = (vec.x?1:0) + (vec.y?1:0) + (vec.z?1:0);
|
||||
assert(vcount == 3, "Not an edge vector!");
|
||||
anch = _find_anchor(vec, $parent_geom);
|
||||
$attach_to = undef;
|
||||
$attach_anchor = anch;
|
||||
$attach_norot = true;
|
||||
$tags = "mask";
|
||||
rotang = vec.z<0?
|
||||
[ 0,0,180+v_theta(vec)-45] :
|
||||
[180,0,-90+v_theta(vec)-45];
|
||||
translate(anch[1]) {
|
||||
rot(rotang) {
|
||||
render(convexity=convexity)
|
||||
difference() {
|
||||
translate(-0.1*[1,1,1]) cube(r+0.1, center=false);
|
||||
right(r) back(r) zrot(180) {
|
||||
rotate_extrude(angle=90, convexity=convexity) {
|
||||
xflip() left(r) {
|
||||
difference() {
|
||||
square(r,center=false);
|
||||
children();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Section: Making your objects attachable
|
||||
|
||||
|
||||
|
@ -915,8 +1166,8 @@ function reorient(
|
|||
// Usage: VNF Geometry
|
||||
// geom = _attach_geom(vnf=, [extent=], ...);
|
||||
//
|
||||
// Topics: Attachments
|
||||
// See Also: reorient(), attachable()
|
||||
/// Topics: Attachments
|
||||
/// See Also: reorient(), attachable()
|
||||
//
|
||||
// Description:
|
||||
// Given arguments that describe the geometry of an attachable object, returns the internal geometry description.
|
||||
|
@ -1093,8 +1344,8 @@ function _attach_geom(
|
|||
/// Internal Function: _attach_geom_2d()
|
||||
// Usage:
|
||||
// bool = _attach_geom_2d(geom);
|
||||
// Topics: Attachments
|
||||
// See Also: reorient(), attachable()
|
||||
/// Topics: Attachments
|
||||
/// See Also: reorient(), attachable()
|
||||
// Description:
|
||||
// Returns true if the given attachment geometry description is for a 2D shape.
|
||||
function _attach_geom_2d(geom) =
|
||||
|
@ -1106,8 +1357,8 @@ function _attach_geom_2d(geom) =
|
|||
/// Internal Function: _attach_geom_size()
|
||||
// Usage:
|
||||
// bounds = _attach_geom_size(geom);
|
||||
// Topics: Attachments
|
||||
// See Also: reorient(), attachable()
|
||||
/// Topics: Attachments
|
||||
/// See Also: reorient(), attachable()
|
||||
// Description:
|
||||
// Returns the `[X,Y,Z]` bounding size for the given attachment geometry description.
|
||||
function _attach_geom_size(geom) =
|
||||
|
@ -1172,8 +1423,8 @@ function _attach_geom_size(geom) =
|
|||
// mat = _attach_transform(anchor, spin, orient, geom);
|
||||
// Usage: To Transform Points, Paths, Patches, or VNFs
|
||||
// new_p = _attach_transform(anchor, spin, orient, geom, p);
|
||||
// Topics: Attachments
|
||||
// See Also: reorient(), attachable()
|
||||
/// Topics: Attachments
|
||||
/// See Also: reorient(), attachable()
|
||||
// Description:
|
||||
// Returns the affine3d transformation matrix needed to `anchor`, `spin`, and `orient`
|
||||
// the given geometry `geom` shape into position.
|
||||
|
@ -1245,261 +1496,12 @@ function _attach_transform(anchor, spin, orient, geom, p) =
|
|||
apply(m, p);
|
||||
|
||||
|
||||
// Section: Attachable Masks
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Module: edge_mask()
|
||||
// Usage:
|
||||
// edge_mask([edges], [except]) {...}
|
||||
// Topics: Attachments
|
||||
// See Also: attachable(), position(), attach(), face_profile(), edge_profile(), corner_mask()
|
||||
// Description:
|
||||
// Takes a 3D mask shape, and attaches it to the given edges, with the appropriate orientation to be
|
||||
// `diff()`ed 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. For a more
|
||||
// step-by-step explanation of attachments, see the [[Attachments Tutorial|Tutorial-Attachments]].
|
||||
// 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 the docs for [`edges()`](edges.scad#edges) to see acceptable values. Default: All edges.
|
||||
// except = Edges to explicitly NOT mask. See the docs for [`edges()`](edges.scad#edges) to see acceptable values. Default: No edges.
|
||||
// Side Effects:
|
||||
// Sets `$tags = "mask"` for all children.
|
||||
// Example:
|
||||
// diff("mask")
|
||||
// cube([50,60,70],center=true)
|
||||
// edge_mask([TOP,"Z"],except=[BACK,TOP+LEFT])
|
||||
// rounding_mask_z(l=71,r=10);
|
||||
module edge_mask(edges=EDGES_ALL, except=[]) {
|
||||
assert($parent_geom != undef, "No 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 (vec = vecs) {
|
||||
vcount = (vec.x?1:0) + (vec.y?1:0) + (vec.z?1:0);
|
||||
assert(vcount == 2, "Not an edge vector!");
|
||||
anch = _find_anchor(vec, $parent_geom);
|
||||
$attach_to = undef;
|
||||
$attach_anchor = anch;
|
||||
$attach_norot = true;
|
||||
$tags = "mask";
|
||||
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) children();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Module: corner_mask()
|
||||
// Usage:
|
||||
// corner_mask([corners], [except]) {...}
|
||||
// Topics: Attachments
|
||||
// See Also: attachable(), position(), attach(), face_profile(), edge_profile(), edge_mask()
|
||||
// Description:
|
||||
// Takes a 3D mask shape, and attaches it to the given corners, with the appropriate orientation to
|
||||
// be `diff()`ed away. The 3D corner mask shape should be designed to mask away the X+Y+Z+ octant.
|
||||
// For a more step-by-step explanation of attachments, see the [[Attachments Tutorial|Tutorial-Attachments]].
|
||||
// Arguments:
|
||||
// corners = Edges to mask. See the docs for [`corners()`](edges.scad#corners) to see acceptable values. Default: All corners.
|
||||
// except = Edges to explicitly NOT mask. See the docs for [`corners()`](edges.scad#corners) to see acceptable values. Default: No corners.
|
||||
// Side Effects:
|
||||
// Sets `$tags = "mask"` for all children.
|
||||
// Example:
|
||||
// diff("mask")
|
||||
// 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=[]) {
|
||||
assert($parent_geom != undef, "No object to attach to!");
|
||||
corners = corners(corners, except=except);
|
||||
vecs = [for (i = [0:7]) if (corners[i]>0) CORNER_OFFSETS[i]];
|
||||
for (vec = vecs) {
|
||||
vcount = (vec.x?1:0) + (vec.y?1:0) + (vec.z?1:0);
|
||||
assert(vcount == 3, "Not an edge vector!");
|
||||
anch = _find_anchor(vec, $parent_geom);
|
||||
$attach_to = undef;
|
||||
$attach_anchor = anch;
|
||||
$attach_norot = true;
|
||||
$tags = "mask";
|
||||
rotang = vec.z<0?
|
||||
[ 0,0,180+v_theta(vec)-45] :
|
||||
[180,0,-90+v_theta(vec)-45];
|
||||
translate(anch[1]) rot(rotang) children();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Module: face_profile()
|
||||
// Usage:
|
||||
// face_profile(faces, r|d=, [convexity=]) {...}
|
||||
// Topics: Attachments
|
||||
// See Also: attachable(), position(), attach(), edge_profile(), corner_profile()
|
||||
// Description:
|
||||
// Given a 2D edge profile, extrudes it into a mask for all edges and corners bounding each given face.
|
||||
// For a more step-by-step explanation of attachments, see the [[Attachments Tutorial|Tutorial-Attachments]].
|
||||
// Arguments:
|
||||
// faces = Faces to mask edges and corners of.
|
||||
// r = Radius of corner mask.
|
||||
// ---
|
||||
// d = Diameter of corner mask.
|
||||
// convexity = Max number of times a line could intersect the perimeter of the mask shape. Default: 10
|
||||
// Side Effects:
|
||||
// Sets `$tags = "mask"` for all children.
|
||||
// Example:
|
||||
// diff("mask")
|
||||
// cube([50,60,70],center=true)
|
||||
// face_profile(TOP,r=10)
|
||||
// mask2d_roundover(r=10);
|
||||
module face_profile(faces=[], r, d, convexity=10) {
|
||||
faces = is_vector(faces)? [faces] : faces;
|
||||
assert(all([for (face=faces) is_vector(face) && sum([for (x=face) x!=0? 1 : 0])==1]), "Vector 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) children();
|
||||
corner_profile(faces, convexity=convexity, r=r) children();
|
||||
}
|
||||
|
||||
|
||||
// Module: edge_profile()
|
||||
// Usage:
|
||||
// edge_profile([edges], [except], [convexity]) {...}
|
||||
// Topics: Attachments
|
||||
// See Also: attachable(), position(), attach(), face_profile(), corner_profile()
|
||||
// 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. For a more step-by-step
|
||||
// explanation of attachments, see the [[Attachments Tutorial|Tutorial-Attachments]].
|
||||
// Arguments:
|
||||
// edges = Edges to mask. See the docs for [`edges()`](edges.scad#edges) to see acceptable values. Default: All edges.
|
||||
// except = Edges to explicitly NOT mask. See the docs for [`edges()`](edges.scad#edges) to see acceptable values. Default: No edges.
|
||||
// convexity = Max number of times a line could intersect the perimeter of the mask shape. Default: 10
|
||||
// Side Effects:
|
||||
// Sets `$tags = "mask"` for all children.
|
||||
// Example:
|
||||
// diff("mask")
|
||||
// cube([50,60,70],center=true)
|
||||
// edge_profile([TOP,"Z"],except=[BACK,TOP+LEFT])
|
||||
// mask2d_roundover(r=10, inset=2);
|
||||
module edge_profile(edges=EDGES_ALL, except=[], convexity=10) {
|
||||
assert($parent_geom != undef, "No 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 (vec = vecs) {
|
||||
vcount = (vec.x?1:0) + (vec.y?1:0) + (vec.z?1:0);
|
||||
assert(vcount == 2, "Not an edge vector!");
|
||||
anch = _find_anchor(vec, $parent_geom);
|
||||
$attach_to = undef;
|
||||
$attach_anchor = anch;
|
||||
$attach_norot = true;
|
||||
$tags = "mask";
|
||||
psize = point3d($parent_size);
|
||||
length = [for (i=[0:2]) if(!vec[i]) psize[i]][0]+0.1;
|
||||
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) {
|
||||
linear_extrude(height=length, center=true, convexity=convexity) {
|
||||
children();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Module: corner_profile()
|
||||
// Usage:
|
||||
// corner_profile([corners], [except], <r=|d=>, [convexity=]) {...}
|
||||
// Topics: Attachments
|
||||
// See Also: attachable(), position(), attach(), face_profile(), edge_profile()
|
||||
// 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. Tags it as a "mask" to allow it to be
|
||||
// `diff()`ed away, to give the corner a matching profile. For a more step-by-step explanation of
|
||||
// attachments, see the [[Attachments Tutorial|Tutorial-Attachments]].
|
||||
// Arguments:
|
||||
// corners = Edges to mask. See the docs for [`corners()`](edges.scad#corners) to see acceptable values. Default: All corners.
|
||||
// except = Edges to explicitly NOT mask. See the docs for [`corners()`](edges.scad#corners) to see acceptable values. Default: No corners.
|
||||
// ---
|
||||
// r = Radius of corner mask.
|
||||
// d = Diameter of corner mask.
|
||||
// convexity = Max number of times a line could intersect the perimeter of the mask shape. Default: 10
|
||||
// Side Effects:
|
||||
// Sets `$tags = "mask"` for all children.
|
||||
// Example:
|
||||
// diff("mask")
|
||||
// cuboid([50,60,70],rounding=10,edges="Z",anchor=CENTER) {
|
||||
// corner_profile(BOT,r=10)
|
||||
// mask2d_teardrop(r=10, angle=40);
|
||||
// }
|
||||
module corner_profile(corners=CORNERS_ALL, except=[], r, d, convexity=10) {
|
||||
assert($parent_geom != undef, "No object to attach to!");
|
||||
r = get_radius(r=r, d=d, dflt=undef);
|
||||
assert(is_num(r));
|
||||
corners = corners(corners, except=except);
|
||||
vecs = [for (i = [0:7]) if (corners[i]>0) CORNER_OFFSETS[i]];
|
||||
for (vec = vecs) {
|
||||
vcount = (vec.x?1:0) + (vec.y?1:0) + (vec.z?1:0);
|
||||
assert(vcount == 3, "Not an edge vector!");
|
||||
anch = _find_anchor(vec, $parent_geom);
|
||||
$attach_to = undef;
|
||||
$attach_anchor = anch;
|
||||
$attach_norot = true;
|
||||
$tags = "mask";
|
||||
rotang = vec.z<0?
|
||||
[ 0,0,180+v_theta(vec)-45] :
|
||||
[180,0,-90+v_theta(vec)-45];
|
||||
translate(anch[1]) {
|
||||
rot(rotang) {
|
||||
render(convexity=convexity)
|
||||
difference() {
|
||||
translate(-0.1*[1,1,1]) cube(r+0.1, center=false);
|
||||
right(r) back(r) zrot(180) {
|
||||
rotate_extrude(angle=90, convexity=convexity) {
|
||||
xflip() left(r) {
|
||||
difference() {
|
||||
square(r,center=false);
|
||||
children();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Internal Function: _find_anchor()
|
||||
// Usage:
|
||||
// anchorinfo = _find_anchor(anchor, geom);
|
||||
// Topics: Attachments
|
||||
// See Also: reorient(), attachable()
|
||||
/// Topics: Attachments
|
||||
/// See Also: reorient(), attachable()
|
||||
// Description:
|
||||
// Calculates the anchor data for the given `anchor` vector or name, in the given attachment
|
||||
// geometry. Returns `[ANCHOR, POS, VEC, ANG]` where `ANCHOR` is the requested anchorname
|
||||
|
@ -1743,8 +1745,8 @@ function _find_anchor(anchor, geom) =
|
|||
/// Internal Function: _attachment_is_shown()
|
||||
// Usage:
|
||||
// bool = _attachment_is_shown(tags);
|
||||
// Topics: Attachments
|
||||
// See Also: reorient(), attachable()
|
||||
/// Topics: Attachments
|
||||
/// See Also: reorient(), attachable()
|
||||
// Description:
|
||||
// Returns true if shapes tagged with any of the given space-delimited string of tag names should currently be shown.
|
||||
function _attachment_is_shown(tags) =
|
||||
|
|
|
@ -365,7 +365,7 @@ module expose_anchors(opacity=0.2) {
|
|||
// cube(50, center=true) show_anchors();
|
||||
module show_anchors(s=10, std=true, custom=true) {
|
||||
check = assert($parent_geom != undef) 1;
|
||||
two_d = attach_geom_2d($parent_geom);
|
||||
two_d = _attach_geom_2d($parent_geom);
|
||||
if (std) {
|
||||
for (anchor=standard_anchors(two_d=two_d)) {
|
||||
if(two_d) {
|
||||
|
|
84
paths.scad
84
paths.scad
|
@ -1476,16 +1476,17 @@ function _cut_interp(pathcut, path, data) =
|
|||
// path_text(path, text, [size], [thickness], [font], [lettersize], [offset], [reverse], [normal], [top], [textmetrics])
|
||||
// Description:
|
||||
// Place the text letter by letter onto the specified path using textmetrics (if available and requested)
|
||||
// or user specified letter spacing. By default letters are positioned on the tangent line to the path with the path normal
|
||||
// or user specified letter spacing. The path can be 2D or 3D. In 2D the text appears along the path with letters upright
|
||||
// as determined by the path direction. In 3D by default letters are positioned on the tangent line to the path with the path normal
|
||||
// pointing toward the reader. The path normal points away from the center of curvature (the opposite of the normal produced
|
||||
// by path_normals()). Note that this means that if the center of curvature switches sides the text will flip upside down.
|
||||
// If you want text on such a path you must supply your own normal or top vector.
|
||||
// If you want text on such a path you must supply your own normal or top vector.
|
||||
// .
|
||||
// Text appears starting at the beginning of the path, so if the path moves right to left
|
||||
// then a left-to-right reading language will display in the wrong order. The text appears positioned to be
|
||||
// read from "outside" of the curve (from a point on the other side of the curve from the center of curvature).
|
||||
// If you need the text to read properly from the inside, you can set reverse to true to flip the text, or supply
|
||||
// your own normal.
|
||||
// Text appears starting at the beginning of the path, so if the 3D path moves right to left
|
||||
// then a left-to-right reading language will display in the wrong order. (For a 2D path text will appear upside down.)
|
||||
// The text for a 3D path appears positioned to be read from "outside" of the curve (from a point on the other side of the
|
||||
// curve from the center of curvature). If you need the text to read properly from the inside, you can set reverse to
|
||||
// true to flip the text, or supply your own normal.
|
||||
// .
|
||||
// If you do not have the experimental textmetrics feature enabled then you must specify the space for the letters
|
||||
// using lettersize, which can be a scalar or array. You will have the easiest time getting good results by using
|
||||
|
@ -1505,14 +1506,14 @@ function _cut_interp(pathcut, path, data) =
|
|||
// path = path to place the text on
|
||||
// text = text to create
|
||||
// size = font size
|
||||
// thickness = thickness of letters
|
||||
// thickness = thickness of letters (not allowed for 2D path)
|
||||
// font = font to use
|
||||
// ---
|
||||
// lettersize = scalar or array giving size of letters
|
||||
// offset = distance to shift letters "up" (towards the reader). Default: 0
|
||||
// normal = direction or list of directions pointing towards the reader of the text
|
||||
// offset = distance to shift letters "up" (towards the reader). Not allowed for 2D path. Default: 0
|
||||
// normal = direction or list of directions pointing towards the reader of the text. Not allowed for 2D path.
|
||||
// top = direction or list of directions pointing toward the top of the text
|
||||
// reverse = reverse the letters if true. Default: false
|
||||
// reverse = reverse the letters if true. Not allowed for 2D path. Default: false
|
||||
// textmetrics = if set to true and lettersize is not given then use the experimental textmetrics feature. You must be running a dev snapshot that includes this feature and have the feature turned on in your preferences. Default: false
|
||||
// Example: The examples use Courier, a monospaced font. The width is 1/1.2 times the specified size for this font. This text could wrap around a cylinder.
|
||||
// path = path3d(arc(100, r=25, angle=[245, 370]));
|
||||
|
@ -1550,6 +1551,14 @@ function _cut_interp(pathcut, path, data) =
|
|||
// path = arc(100, points = [[-20, 0, 20], [0,0,5], [20,0,20]]);
|
||||
// color("red")stroke(path,width=.2);
|
||||
// path_text(path, "Example Text", size=5, lettersize=5/1.2, font="Courier", top=UP);
|
||||
// Example: This sine wave wrapped around the cylinder has a twisting normal that produces wild letter layout. We fix it with a custom normal which is different at every path point.
|
||||
// path = [for(theta = [0:360]) [25*cos(theta), 25*sin(theta), 4*cos(theta*4)]];
|
||||
// normal = [for(theta = [0:360]) [cos(theta), sin(theta),0]];
|
||||
// zrot(-120)
|
||||
// difference(){
|
||||
// cyl(r=25, h=20, $fn=120);
|
||||
// path_text(path, "A sine wave wiggles", font="Courier", lettersize=5/1.2, size=5, normal=normal);
|
||||
// }
|
||||
// Example: The path center of curvature changes, and the text flips.
|
||||
// path = zrot(-120,p=path3d( concat(arc(100, r=25, angle=[0,90]), back(50,p=arc(100, r=25, angle=[268, 180])))));
|
||||
// color("red")stroke(path,width=.2);
|
||||
|
@ -1558,14 +1567,30 @@ function _cut_interp(pathcut, path, data) =
|
|||
// path = zrot(-120,p=path3d( concat(arc(100, r=25, angle=[0,90]), back(50,p=arc(100, r=25, angle=[268, 180])))));
|
||||
// color("red")stroke(path,width=.2);
|
||||
// path_text(path, "A shorter example", size=5, lettersize=5/1.2, font="Courier", thickness=2, top=UP);
|
||||
module path_text(path, text, font, size, thickness=1, lettersize, offset=0, reverse=false, normal, top, textmetrics=false)
|
||||
// Example(2D): With a 2D path instead of 3D there's no ambiguity about direction and it works by default:
|
||||
// path = zrot(-120,p=concat(arc(100, r=25, angle=[0,90]), back(50,p=arc(100, r=25, angle=[268, 180]))));
|
||||
// color("red")stroke(path,width=.2);
|
||||
// path_text(path, "A shorter example", size=5, lettersize=5/1.2, font="Courier");
|
||||
module path_text(path, text, font, size, thickness, lettersize, offset=0, reverse=false, normal, top, textmetrics=false)
|
||||
{
|
||||
dummy2=assert(num_defined([normal,top])<=1, "Cannot define both normal and top");
|
||||
normal = is_def(normal) && len(normal)==3 ? repeat(normal, len(path))
|
||||
dummy2=assert(is_path(path,[2,3]),"Must supply a 2d or 3d path")
|
||||
assert(num_defined([normal,top])<=1, "Cannot define both \"normal\" and \"top\"");
|
||||
dim = len(path[0]);
|
||||
normalok = is_undef(normal) || is_vector(normal,3) || (is_path(normal,3) && len(normal)==len(path));
|
||||
topok = is_undef(top) || is_vector(top,dim) || (dim==2 && is_vector(top,3) && top[2]==0)
|
||||
|| (is_path(top,dim) && len(top)==len(path));
|
||||
dummy4 = assert(dim==3 || is_undef(thickness), "Cannot give a thickness with 2d path")
|
||||
assert(dim==3 || !reverse, "Reverse not allowed with 2d path")
|
||||
assert(dim==3 || offset==0, "Cannot give offset with 2d path")
|
||||
assert(dim==3 || is_undef(normal), "Cannot define \"normal\" for a 2d path, only \"top\"")
|
||||
assert(normalok,"\"normal\" must be a vector or path compatible with the given path")
|
||||
assert(topok,"\"top\" must be a vector or path compatible with the given path");
|
||||
thickness = first_defined([thickness,1]);
|
||||
normal = is_vector(normal) ? repeat(normal, len(path))
|
||||
: is_def(normal) ? normal
|
||||
: undef;
|
||||
|
||||
top = is_def(top) && len(top)==3 ? repeat(top, len(path))
|
||||
top = is_vector(top) ? repeat(dim==2?point2d(top):top, len(path))
|
||||
: is_def(top) ? top
|
||||
: undef;
|
||||
|
||||
|
@ -1583,25 +1608,32 @@ module path_text(path, text, font, size, thickness=1, lettersize, offset=0, reve
|
|||
normpts = is_undef(normal) ? (reverse?1:-1)*subindex(pts,3) : _cut_interp(pts,path, normal);
|
||||
toppts = is_undef(top) ? undef : _cut_interp(pts,path,top);
|
||||
for(i=idx(text))
|
||||
assert(!usetop || !approx(pts[i][2]*toppts[i],norm(top[i])*norm(pts[i][2])),
|
||||
let( tangent = pts[i][2] )
|
||||
assert(!usetop || !approx(tangent*toppts[i],norm(top[i])*norm(tangent)),
|
||||
str("Specified top direction parallel to path at character ",i))
|
||||
assert(usetop || !approx(pts[i][2]*normpts[i],norm(normpts[i])*norm(pts[i][2])),
|
||||
assert(usetop || !approx(tangent*normpts[i],norm(normpts[i])*norm(tangent)),
|
||||
str("Specified normal direction parallel to path at character ",i))
|
||||
let(
|
||||
adjustment = usetop ? (pts[i][2]*toppts[i])*toppts[i]/(toppts[i]*toppts[i])
|
||||
: usernorm ? (pts[i][2]*normpts[i])*normpts[i]/(normpts[i]*normpts[i])
|
||||
adjustment = usetop ? (tangent*toppts[i])*toppts[i]/(toppts[i]*toppts[i])
|
||||
: usernorm ? (tangent*normpts[i])*normpts[i]/(normpts[i]*normpts[i])
|
||||
: [0,0,0]
|
||||
|
||||
)
|
||||
move(pts[i][0])
|
||||
frame_map(x=pts[i][2]-adjustment,
|
||||
z=usetop ? undef : normpts[i],
|
||||
y=usetop ? toppts[i] : undef)
|
||||
up(offset-thickness/2)
|
||||
linear_extrude(height=thickness)
|
||||
left(lsize[0]/2)text(text[i], font=font, size=size);
|
||||
if(dim==3){
|
||||
frame_map(x=tangent-adjustment,
|
||||
z=usetop ? undef : normpts[i],
|
||||
y=usetop ? toppts[i] : undef)
|
||||
up(offset-thickness/2)
|
||||
linear_extrude(height=thickness)
|
||||
left(lsize[0]/2)text(text[i], font=font, size=size);
|
||||
} else {
|
||||
frame_map(x=point3d(tangent-adjustment), y=point3d(usetop ? toppts[i] : -normpts[i]))
|
||||
left(lsize[0]/2)text(text[i], font=font, size=size);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
|
||||
|
|
Loading…
Reference in a new issue