Merge pull request #1749 from amatulic/anachronist_dev

xcyl(), ycyl(), zcyl() pass through all parameters to cyl()
This commit is contained in:
adrianVmariano
2025-07-17 14:27:21 -04:00
committed by GitHub
2 changed files with 369 additions and 307 deletions

View File

@@ -509,10 +509,10 @@ module position(at,from)
if (is_def(from)){
echo("'from' argument of position() has changed to 'at' and will be removed in a future version");
}
dummy0=assert(num_defined([at,from])==1, "Cannot give both `at` argument and the deprectated `from` argument to position()");
dummy0=assert(num_defined([at,from])==1, "\nCannot give both `at` argument and the deprectated `from` argument to position().");
at = first_defined([at,from]);
req_children($children);
dummy1=assert($parent_geom != undef, "No object to position relative to.");
dummy1=assert($parent_geom != undef, "\nNo object to position relative to.");
anchors = (is_vector(at)||is_string(at))? [at] : at;
two_d = _attach_geom_2d($parent_geom);
for (anchr = anchors) {
@@ -563,7 +563,7 @@ module position(at,from)
module orient(anchor, spin) {
req_children($children);
check=
assert($parent_geom != undef, "No parent to orient from!")
assert($parent_geom != undef, "\nNo parent to orient from!")
assert(is_string(anchor) || is_vector(anchor));
anch = _find_anchor(anchor, $parent_geom);
two_d = _attach_geom_2d($parent_geom);
@@ -700,8 +700,8 @@ module align(anchor,align=CENTER,inside=false,inset=0,shiftout=0,overlap)
{
req_children($children);
overlap = (overlap!=undef)? overlap : $overlap;
dummy1=assert($parent_geom != undef, "No object to align to.")
assert(is_undef($attach_to), "Cannot use align() as a child of attach()");
dummy1=assert($parent_geom != undef, "\nNo object to align to.")
assert(is_undef($attach_to), "\nCannot use align() as a child of attach().");
anchor = is_vector(anchor) ? [anchor] : anchor;
align = is_vector(align) ? [align] : align;
two_d = _attach_geom_2d($parent_geom);
@@ -712,19 +712,19 @@ module align(anchor,align=CENTER,inside=false,inset=0,shiftout=0,overlap)
$anchor=face;
dummy=
assert(!is_string(face),
str("Named anchor \"",face,"\" given for anchor, but align() does not support named anchors"))
str("\nNamed anchor \"",face,"\" given for anchor, but align() does not support named anchors."))
assert(is_vector(face) && (len(face)==2 || len(face)==3),
str("Invalid face ",face, ". Must be a 2-vector or 3-vector"));
str("\nInvalid face ",face, ". Must be a 2-vector or 3-vector."));
thisface = two_d? _force_anchor_2d(face) : point3d(face);
for(j = idx(align)) {
edge=align[j];
$idx = j+len(align)*i;
$align=edge;
dummy1=assert(is_vector(edge) && (len(edge)==2 || len(edge)==3),
"align direction must be a 2-vector or 3-vector");
"\nalign direction must be a 2-vector or 3-vector.");
thisedge = two_d? _force_anchor_2d(edge) : point3d(edge);
dummy=assert(all_zero(v_mul(thisedge,thisface)),
str("align (",thisedge,") cannot include component parallel to anchor ",thisface));
str("\nalign (",thisedge,") cannot include component parallel to anchor ",thisface,"."));
thisface_anch = _find_anchor(thisface, $parent_geom);
inset_dir = two_d ? -thisface
: unit(thisface_anch[1]-_find_anchor([thisedge.x,0,0]+thisface, $parent_geom)[1],CTR)
@@ -931,10 +931,10 @@ function _make_anchor_legal(anchor,geom) =
module attach(parent, child, overlap, align, spin=0, norot, inset=0, shiftout=0, inside=false, from, to)
{
dummy3=
assert(num_defined([to,child])<2, "Cannot combine deprecated 'to' argument with 'child' parameter")
assert(num_defined([from,parent])<2, "Cannot combine deprecated 'from' argument with 'parent' parameter")
assert(spin!="align" || is_def(align), "Can only set spin to \"align\" when the 'align' parameter is given")
assert(is_finite(spin) || spin=="align", "Spin must be a number (unless align is given)")
assert(num_defined([to,child])<2, "\nCannot combine deprecated 'to' argument with 'child' parameter.")
assert(num_defined([from,parent])<2, "\nCannot combine deprecated 'from' argument with 'parent' parameter.")
assert(spin!="align" || is_def(align), "\nCan only set spin to \"align\" when the 'align' parameter is given.")
assert(is_finite(spin) || spin=="align", "\nSpin must be a number (unless align is given).")
assert((is_undef(overlap) || is_finite(overlap)) && (is_def(overlap) || is_undef($overlap) || is_finite($overlap)),
str("Provided ",is_def(overlap)?"":"$","overlap is not valid."));
removetag = inside;
@@ -947,10 +947,10 @@ module attach(parent, child, overlap, align, spin=0, norot, inset=0, shiftout=0,
echo("The 'norot' option to attach() is deprecated and will be removed in the future. Use position() instead.");
req_children($children);
dummy=assert($parent_geom != undef, "No object to attach to!")
dummy=assert($parent_geom != undef, "\nNo object to attach to!")
assert(is_undef(child) || is_string(child) || (is_vector(child) && (len(child)==2 || len(child)==3)),
"child must be a named anchor (a string) or a 2-vector or 3-vector")
assert(is_undef(align) || !is_string(child), "child is a named anchor. Named anchors are not supported with align=");
"\nChild must be a named anchor (a string) or a 2-vector or 3-vector.")
assert(is_undef(align) || !is_string(child), "\nChild is a named anchor. Named anchors are not supported with align=.");
two_d = _attach_geom_2d($parent_geom);
basegeom = $parent_geom[0]=="conoid" ? attach_geom(r=2,h=2,axis=$parent_geom[5])
@@ -963,22 +963,22 @@ module attach(parent, child, overlap, align, spin=0, norot, inset=0, shiftout=0,
anchors = is_vector(parent) || is_string(parent) ? [parent] : parent;
align_list = is_undef(align) ? [undef]
: is_vector(align) || is_string(align) ? [align] : align;
dummy4 = assert(is_string(parent) || is_list(parent), "Invalid parent anchor or anchor list")
assert(spin==0 || (!two_d || is_undef(child)), "spin is not allowed for 2d objects when 'child' is given");
dummy4 = assert(is_string(parent) || is_list(parent), "\nInvalid parent anchor or anchor list.")
assert(spin==0 || (!two_d || is_undef(child)), "\nspin is not allowed for 2d objects when 'child' is given.");
child_temp = first_defined([child,to]);
child = two_d ? _force_anchor_2d(child_temp) : child_temp;
dummy2=assert(align_list==[undef] || is_def(child), "Cannot use 'align' without 'child'")
assert(!inside || is_def(child), "Cannot use 'inside' without 'child'")
assert(inset==0 || is_def(child), "Cannot specify 'inset' without 'child'")
assert(inset==0 || is_def(align), "Cannot specify 'inset' without 'align'")
assert(shiftout==0 || is_def(child), "Cannot specify 'shiftout' without 'child'");
dummy2=assert(align_list==[undef] || is_def(child), "\nCannot use 'align' without 'child'.")
assert(!inside || is_def(child), "\nCannot use 'inside' without 'child'.")
assert(inset==0 || is_def(child), "\nCannot specify 'inset' without 'child'.")
assert(inset==0 || is_def(align), "\nCannot specify 'inset' without 'align'.")
assert(shiftout==0 || is_def(child), "\nCannot specify 'shiftout' without 'child'.");
factor = inside?-1:1;
$attach_to = child;
for (anch_ind = idx(anchors)) {
dummy=assert(is_string(anchors[anch_ind]) || (is_vector(anchors[anch_ind]) && (len(anchors[anch_ind])==2 || len(anchors[anch_ind])==3)),
str("parent[",anch_ind,"] is ",anchors[anch_ind]," but it must be a named anchor (string) or a 2-vector or 3-vector"))
str("\nParent[",anch_ind,"] is ",anchors[anch_ind]," but it must be a named anchor (string), a 2-vector, or 3-vector."))
assert(align_list==[undef] || !is_string(anchors[anch_ind]),
str("parent[",anch_ind,"] is a named anchor (",anchors[anch_ind],"), but named anchors are not supported with align="));
str("\nParent[",anch_ind,"] is a named anchor (",anchors[anch_ind],"), but named anchors are not supported with align=."));
anchor = is_string(anchors[anch_ind])? anchors[anch_ind]
: two_d?_force_anchor_2d(anchors[anch_ind])
: point3d(anchors[anch_ind]);
@@ -995,7 +995,7 @@ module attach(parent, child, overlap, align, spin=0, norot, inset=0, shiftout=0,
parent_abstract_anchor = is_vector(anchor) && !two_d ? _find_anchor(_make_anchor_legal(anchor,basegeom),basegeom) : undef;
for(align_ind = idx(align_list)){
align = is_undef(align_list[align_ind]) ? undef
: assert(is_vector(align_list[align_ind],2) || is_vector(align_list[align_ind],3), "align direction must be a 2-vector or 3-vector")
: assert(is_vector(align_list[align_ind],2) || is_vector(align_list[align_ind],3), "\nAlign direction must be a 2-vector or 3-vector.")
two_d ? _force_anchor_2d(align_list[align_ind])
: point3d(align_list[align_ind]);
spin = is_num(spin) ? spin
@@ -1024,10 +1024,10 @@ module attach(parent, child, overlap, align, spin=0, norot, inset=0, shiftout=0,
badcorner = !in_list($parent_geom[0],["conoid","spheroid"]) && !is_undef(align) && align!=CTR && sum(v_abs(anchor))==3;
badsphere = $parent_geom[0]=="spheroid" && !is_undef(align) && align!=CTR;
dummy=assert(is_undef(align) || all_zero(v_mul(anchor,align)),
str("Invalid alignment: align value (",align,") includes component parallel to parent anchor (",anchor,")"))
assert(goodcyl, str("Cannot use align with an anchor on a curved edge or surface of a cylinder at parent anchor (",anchor,")"))
assert(!badcorner, str("Cannot use align at a corner anchor (",anchor,")"))
assert(!badsphere, "Cannot use align on spheres.");
str("\nInvalid alignment: align value (",align,") includes component parallel to parent anchor (",anchor,")."))
assert(goodcyl, str("\nCannot use align with an anchor on a curved edge or surface of a cylinder at parent anchor (",anchor,")."))
assert(!badcorner, str("\nCannot use align at a corner anchor (",anchor,")."))
assert(!badsphere, "\nCannot use align on spheres.");
// Now compute position on the parent (including alignment but not inset) where the child will be anchored
pos = is_undef(align) ? anchor_data[1] : _find_anchor(anchor+align, $parent_geom)[1];
$attach_anchor = list_set(anchor_data, 1, pos); // Never used; For user informational use? Should this be set at all?
@@ -1100,9 +1100,9 @@ module attach(parent, child, overlap, align, spin=0, norot, inset=0, shiftout=0,
module attach_part(name)
{
req_children($children);
dummy=assert(!is_undef($parent_parts), "Parent does not exist or does not have any parts");
dummy=assert(!is_undef($parent_parts), "\nParent does not exist or does not have any parts.");
ind = search([name], $parent_parts, 1,0)[0];
dummy2 = assert(ind!=[], str("Parent does not have a part named ",name));
dummy2 = assert(ind!=[], str("\nParent does not have a part named \"",name,"\"."));
$parent_geom = $parent_parts[ind][1];
$anchor_inside = $parent_parts[ind][2];
T = $parent_parts[ind][3];
@@ -1145,8 +1145,8 @@ module tag(tag)
{
req_children($children);
check=
assert(is_string(tag),"tag must be a string")
assert(undef==str_find(tag," "),str("Tag string \"",tag,"\" contains a space, which is not allowed"));
assert(is_string(tag),"\n'tag' must be a string.")
assert(undef==str_find(tag," "),str("\nTag string \"",tag,"\" contains a space, which is not allowed."));
$tag = str($tag_prefix,tag);
children();
}
@@ -1178,8 +1178,8 @@ module tag_this(tag)
{
req_children($children);
check=
assert(is_string(tag),"tag must be a string")
assert(undef==str_find(tag," "),str("Tag string \"",tag,"\" contains a space, which is not allowed"));
assert(is_string(tag),"\n'tag' must be a string.")
assert(undef==str_find(tag," "),str("\nTag string \"",tag,"\" contains a space, which is not allowed."));
$save_tag=default($tag,"");
$tag = str($tag_prefix,tag);
children();
@@ -1239,9 +1239,9 @@ module tag_this(tag)
module force_tag(tag)
{
req_children($children);
check1=assert(is_undef(tag) || is_string(tag),"tag must be a string");
check1=assert(is_undef(tag) || is_string(tag),"\n'tag' must be a string.");
$tag = str($tag_prefix,default(tag,$tag));
assert(undef==str_find($tag," "),str("Tag string \"",$tag,"\" contains a space, which is not allowed"));
assert(undef==str_find($tag," "),str("\nTag string \"",$tag,"\" contains a space, which is not allowed."));
if(_is_shown())
show_all()
children();
@@ -1382,8 +1382,8 @@ module default_tag(tag,do_tag=true)
module tag_scope(scope){
req_children($children);
scope = is_undef(scope) ? rand_str(20) : scope;
assert(is_string(scope), "scope must be a string");
assert(undef==str_find(scope," "),str("Scope string \"",scope,"\" contains a space, which is not allowed"));
assert(is_string(scope), "\n'scope' must be a string.");
assert(undef==str_find(scope," "),str("\nScope string \"",scope,"\" contains a space, which is not allowed."));
$tag_prefix=scope;
children();
}
@@ -1569,8 +1569,8 @@ module tag_scope(scope){
module diff(remove="remove", keep="keep")
{
req_children($children);
assert(is_string(remove),"remove must be a string of tags");
assert(is_string(keep),"keep must be a string of tags");
assert(is_string(remove),"\n'remove' must be a string of tags.");
assert(is_string(keep),"\n'keep' must be a string of tags.");
if (_is_shown())
{
difference() {
@@ -1637,10 +1637,10 @@ module diff(remove="remove", keep="keep")
module tag_diff(tag="",remove="remove", keep="keep")
{
req_children($children);
assert(is_string(remove),"remove must be a string of tags");
assert(is_string(keep),"keep must be a string of tags");
assert(is_string(tag),"tag must be a string");
assert(undef==str_find(tag," "),str("Tag string \"",tag,"\" contains a space, which is not allowed"));
assert(is_string(remove),"\n'remove' must be a string of tags.");
assert(is_string(keep),"\n'keep' must be a string of tags.");
assert(is_string(tag),"\n'tag' must be a string.");
assert(undef==str_find(tag," "),str("\nTag string \"",tag,"\" contains a space, which is not allowed."));
$tag=str($tag_prefix,tag);
if (_is_shown())
show_all(){
@@ -1715,8 +1715,8 @@ module tag_diff(tag="",remove="remove", keep="keep")
// }
module intersect(intersect="intersect",keep="keep")
{
assert(is_string(intersect),"intersect must be a string of tags");
assert(is_string(keep),"keep must be a string of tags");
assert(is_string(intersect),"\n'intersect' must be a string of tags.");
assert(is_string(keep),"\n'keep' must be a string of tags.");
intersection(){
show_only(intersect) children();
hide(str(intersect," ",keep)) children();
@@ -1765,10 +1765,10 @@ module intersect(intersect="intersect",keep="keep")
// }
module tag_intersect(tag="",intersect="intersect",keep="keep")
{
assert(is_string(intersect),"intersect must be a string of tags");
assert(is_string(keep),"keep must be a string of tags");
assert(is_string(tag),"tag must be a string");
assert(undef==str_find(tag," "),str("Tag string \"",tag,"\" contains a space, which is not allowed"));
assert(is_string(intersect),"\n'intersect' must be a string of tags.");
assert(is_string(keep),"\n'keep' must be a string of tags.");
assert(is_string(tag),"\n'tag' must be a string.");
assert(undef==str_find(tag," "),str("\nTag string \"",tag,"\" contains a space, which is not allowed."));
$tag=str($tag_prefix,tag);
if (_is_shown())
show_all(){
@@ -1813,7 +1813,7 @@ module tag_intersect(tag="",intersect="intersect",keep="keep")
module conv_hull(keep="keep")
{
req_children($children);
assert(is_string(keep),"keep must be a string of tags");
assert(is_string(keep),"\n'keep' must be a string of tags.");
if (_is_shown())
hull() hide(keep) children();
show_int(keep) children();
@@ -1860,9 +1860,9 @@ module conv_hull(keep="keep")
module tag_conv_hull(tag="",keep="keep")
{
req_children($children);
assert(is_string(keep),"keep must be a string of tags");
assert(is_string(tag),"tag must be a string");
assert(undef==str_find(tag," "),str("Tag string \"",tag,"\" contains a space, which is not allowed"));
assert(is_string(keep),"\n'keep' must be a string of tags.");
assert(is_string(tag),"\n'tag' must be a string.");
assert(undef==str_find(tag," "),str("\nTag string \"",tag,"\" contains a space, which is not allowed."));
$tag=str($tag_prefix,tag);
if (_is_shown())
show_all(){
@@ -1900,7 +1900,7 @@ module tag_conv_hull(tag="",keep="keep")
module hide(tags)
{
req_children($children);
dummy=assert(is_string(tags), "tags must be a string");
dummy=assert(is_string(tags), "\n'tags' must be a string.");
taglist = [for(s=str_split(tags," ",keep_nulls=false)) str($tag_prefix,s)];
$tags_hidden = concat($tags_hidden,taglist);
children();
@@ -1961,7 +1961,7 @@ module hide_this()
module show_only(tags)
{
req_children($children);
dummy=assert(is_string(tags), str("tags must be a string",tags));
dummy=assert(is_string(tags), str("\n'tags' must be a string.",tags));
taglist = [for(s=str_split(tags," ",keep_nulls=false)) str($tag_prefix,s)];
$tags_shown = taglist;
children();
@@ -2004,7 +2004,7 @@ module show_all()
module show_int(tags)
{
req_children($children);
dummy=assert(is_string(tags), str("tags must be a string",tags));
dummy=assert(is_string(tags), str("\n'tags' must be a string.",tags));
taglist = [for(s=str_split(tags," ",keep_nulls=false)) str($tag_prefix,s)];
$tags_shown = $tags_shown == "ALL" ? taglist : set_intersection($tags_shown,taglist);
children();
@@ -2049,8 +2049,8 @@ module show_int(tags)
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]), "Vector in faces doesn't point at a face.");
assert($parent_geom != undef, "No object to attach to!");
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();
}
@@ -2094,7 +2094,7 @@ module face_mask(faces=[LEFT,RIGHT,FRONT,BACK,BOT,TOP]) {
// rounding_edge_mask(l=71,r=10);
module edge_mask(edges=EDGES_ALL, except=[]) {
req_children($children);
assert($parent_geom != undef, "No object to attach to!");
assert($parent_geom != undef, "\nNo object to attach to!");
edges = _edges(edges, except=except);
vecs = [
for (i = [0:3], axis=[0:2])
@@ -2104,7 +2104,7 @@ module edge_mask(edges=EDGES_ALL, except=[]) {
for ($idx = idx(vecs)) {
vec = vecs[$idx];
vcount = (vec.x?1:0) + (vec.y?1:0) + (vec.z?1:0);
dummy=assert(vcount == 2, "Not an edge vector!");
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;
@@ -2151,13 +2151,13 @@ module edge_mask(edges=EDGES_ALL, except=[]) {
// }
module corner_mask(corners=CORNERS_ALL, except=[]) {
req_children($children);
assert($parent_geom != undef, "No object to attach to!");
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, "Not an edge vector!");
dummy=assert(vcount == 3, "\nNot an edge vector!");
anch = _find_anchor(vec, $parent_geom);
$attach_to = undef;
$attach_anchor = anch;
@@ -2202,7 +2202,7 @@ module corner_mask(corners=CORNERS_ALL, except=[]) {
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]), "Vector in faces doesn't point at a face.");
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();
@@ -2256,11 +2256,11 @@ module face_profile(faces=[], r, d, excess=0.01, convexity=10) {
module edge_profile(edges=EDGES_ALL, except=[], excess=0.01, convexity=10) {
req_children($children);
check1 = assert($parent_geom != undef, "No object to attach to!");
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])]), "Invalid conoid edge spec.")
assert(all([for (e=edges) in_list(e,[TOP,BOT])]), "\nInvalid conoid edge spec.")
edges;
vecs = conoid
? [for (e=edges) e+FWD]
@@ -2270,7 +2270,7 @@ module edge_profile(edges=EDGES_ALL, except=[], excess=0.01, convexity=10) {
EDGE_OFFSETS[axis][i]
];
all_vecs_are_edges = all([for (vec = vecs) sum(v_abs(vec))==2]);
check2 = assert(all_vecs_are_edges, "All vectors must be edges.");
check2 = assert(all_vecs_are_edges, "\nAll vectors must be edges.");
default_tag("remove")
for ($idx = idx(vecs)) {
vec = vecs[$idx];
@@ -2452,7 +2452,7 @@ module edge_profile_asym(
[BACK+RIGHT, [TOP+BACK, BOT+BACK]],
],
i = search([from], flip_edges, num_returns_per_match=1)[0],
check = assert(i!=[], "Bad edge vector.")
check = assert(i!=[], "\nBad edge vector.")
) in_list(to,flip_edges[i][1]);
function _edge_corner_numbers(vec) =
@@ -2467,7 +2467,7 @@ module edge_profile_asym(
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, "Cannot have three edges that meet at the same corner.")
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]],
@@ -2552,7 +2552,7 @@ module edge_profile_asym(
[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, "No object to attach to!")
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);
@@ -2562,7 +2562,7 @@ module edge_profile_asym(
EDGE_OFFSETS[axis][i]
];
all_vecs_are_edges = all([for (vec = vecs) sum(v_abs(vec))==2]);
check2 = assert(all_vecs_are_edges, "All vectors must be edges.");
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")
@@ -2688,13 +2688,13 @@ module edge_profile_asym(
// mask2d_teardrop(r=10, angle=40);
// }
module corner_profile(corners=CORNERS_ALL, except=[], r, d, convexity=10) {
check1 = assert($parent_geom != undef, "No object to attach to!");
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), "Bad r/d argument.");
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, "All vectors must be corners.");
check3 = assert(all_vecs_are_corners, "\nAll vectors must be corners.");
for ($idx = idx(vecs)) {
vec = vecs[$idx];
anch = _find_anchor(vec, $parent_geom);
@@ -3121,11 +3121,11 @@ module attachable(
expose_tags=false, keep_color=false
) {
dummy1 =
assert($children==2, "attachable() expects exactly two children; the shape to manage, and the union of all attachment candidates.")
assert($children==2, "\nattachable() expects exactly two children: the shape to manage, and the union of all attachment candidates.")
assert(is_undef(anchor) || is_vector(anchor) || is_string(anchor), str("Invalid anchor: ",anchor))
assert(is_undef(spin) || is_finite(spin), str("Invalid spin: ",spin))
assert(is_undef(orient) || is_vector(orient,3), str("Invalid orient: ",orient));
assert(in_list(v_abs(axis),[UP,RIGHT,BACK]), "axis must be a coordinate direction");
assert(is_undef(spin) || is_finite(spin), str("\nInvalid spin: ",spin))
assert(is_undef(orient) || is_vector(orient,3), str("\nInvalid orient: ",orient));
assert(in_list(v_abs(axis),[UP,RIGHT,BACK]), "\n'axis' must be a coordinate direction.");
anchor = default(anchor,CENTER);
spin = default(spin,0);
orient = is_def($anchor_override)? UP : default(orient, UP);
@@ -3300,9 +3300,9 @@ function reorient(
geom,
p=undef
) =
assert(is_undef(anchor) || is_vector(anchor) || is_string(anchor), str("Invalid anchor: ",anchor))
assert(is_undef(spin) || is_finite(spin), str("Invalid spin: ",spin))
assert(is_undef(orient) || is_vector(orient,3), str("Invalid orient: ",orient))
assert(is_undef(anchor) || is_vector(anchor) || is_string(anchor), str("\nInvalid anchor: ",anchor))
assert(is_undef(spin) || is_finite(spin), str("\nInvalid spin: ",spin))
assert(is_undef(orient) || is_vector(orient,3), str("\nInvalid orient: ",orient))
let(
anchor = default(anchor, CENTER),
spin = default(spin, 0),
@@ -3348,15 +3348,15 @@ function reorient(
// rot = A 4x4 rotations matrix, which may include a translation
// flip = If true, flip the anchor the opposite direction. Default: false
function named_anchor(name, pos, orient, spin, rot, flip, info) =
assert(num_defined([orient,spin])==0 || num_defined([rot,flip])==0, "Cannot mix orient or spin with rot or flip")
assert(num_defined([pos,rot])>0, "Must give pos or rot")
assert(num_defined([orient,spin])==0 || num_defined([rot,flip])==0, "\nCannot mix orient or spin with rot or flip.")
assert(num_defined([pos,rot])>0, "\nMust give pos or rot")
is_undef(rot) ? [name, pos, default(orient,UP), default(spin,0), if (info) info]
:
let(
flip = default(flip,false),
pos = default(pos,apply(rot,CTR)),
rotpart = _force_rot(rot),
dummy = assert(approx(det4(rotpart),1), "Input rotation is not a rotation matrix"),
dummy = assert(approx(det4(rotpart),1), "\nInput rotation is not a rotation matrix."),
dir = flip ? apply(rotpart,DOWN)
: apply(rotpart,UP),
rot = flip? affine3d_rot_by_axis(apply(rotpart,BACK),180)*rot
@@ -3540,11 +3540,11 @@ function attach_geom(
assert(is_region(region),2)
let( l = default(l, h) )
two_d==true
? assert(is_undef(l), "Cannot give l/h with region anchor types (when two_d is set)")
? assert(is_undef(l), "\nCannot give l/h with region anchor types (when two_d is set).")
extent==true
? ["rgn_extent", region, cp, offset, anchors]
: ["rgn_isect", region, cp, offset, anchors]
: assert(is_finite(l), "Must give l/h with extrusion anchor types (did you forget to set two_d?)")
: assert(is_finite(l), "\nMust give l/h with extrusion anchor types (did you forget to set two_d?).")
let(
shift = default(shift, [0,0]),
scale = is_num(scale)? [scale,scale] : default(scale, [1,1]),
@@ -3623,10 +3623,10 @@ function attach_geom(
// }
function define_part(name, geom, inside=false, T=IDENT) =
assert(is_string(name), "name must be a string")
assert(_is_geometry(geom), "geometry appears invalid")
assert(is_bool(inside), "inside must be boolean")
assert(is_matrix(T,4), "T must be a 4x4 transformation matrix")
assert(is_string(name), "\n'name' must be a string.")
assert(_is_geometry(geom), "\ngeometry appears invalid.")
assert(is_bool(inside), "\n'inside' must be boolean.")
assert(is_matrix(T,4), "\nT must be a 4×4 transformation matrix.")
[name, geom, inside, T];
@@ -3714,7 +3714,7 @@ function _attach_geom_size(geom) =
delt = mm[1]-mm[0]
) [delt.x, delt.y]
) :
assert(false, "Unknown attachment geometry type.");
assert(false, "\nUnknown attachment geometry type.");
@@ -3727,7 +3727,7 @@ function _attach_geom_size(geom) =
/// Returns the path and post-transform matrix of the indicated edge.
/// If the edge is invalid for the geometry, returns `undef`.
function _attach_geom_edge_path(geom, edge) =
assert(is_vector(edge),str("Invalid edge: edge=",edge))
assert(is_vector(edge),str("\nInvalid edge: ",edge))
let(
type = geom[0],
cp = _get_cp(geom),
@@ -3737,9 +3737,9 @@ function _attach_geom_edge_path(geom, edge) =
)
type == "prismoid"? ( //size, size2, shift, axis
let(all_comps_good = [for (c=edge) if (c!=sign(c)) 1]==[])
assert(all_comps_good, "All components of an edge for a cuboid/prismoid must be -1, 0, or 1")
assert(all_comps_good, "\nAll components of an edge for a cuboid/prismoid must be -1, 0, or 1.")
let(edge_good = len([for (c=edge) if(c) 1])==2)
assert(edge_good, "Invalid edge.")
assert(edge_good, "\nInvalid edge.")
let(
size = geom[1],
size2 = geom[2],
@@ -3776,7 +3776,7 @@ function _attach_geom_edge_path(geom, edge) =
m = rot(from=UP,to=axis) * move(offset)
) [path, [vecs], m]
) : type == "conoid"? ( //r1, r2, l, shift, axis
assert(edge.z && edge.z == sign(edge.z), "The Z component of an edge for a cylinder/cone must be -1 or 1")
assert(edge.z && edge.z == sign(edge.z), "\nThe Z component of an edge for a cylinder/cone must be -1 or 1.")
let(
rr1 = geom[1],
rr2 = geom[2],
@@ -3830,9 +3830,9 @@ function _attach_geom_edge_path(geom, edge) =
/// p = If given as a VNF, path, or point, applies the affine3d transformation matrix to it and returns the result.
function _attach_transform(anchor, spin, orient, geom, p) =
assert(is_undef(anchor) || is_vector(anchor) || is_string(anchor), str("Invalid anchor: ",anchor))
assert(is_undef(spin) || is_finite(spin), str("Invalid spin: ",spin))
assert(is_undef(orient) || is_vector(orient,3), str("Invalid orient: ",orient))
assert(is_undef(anchor) || is_vector(anchor) || is_string(anchor), str("\nInvalid anchor: ",anchor))
assert(is_undef(spin) || is_finite(spin), str("\nInvalid spin: ",spin))
assert(is_undef(orient) || is_vector(orient,3), str("\nInvalid orient: ",orient))
let(
anchor=default(anchor,CENTER),
spin=default(spin,0),
@@ -3888,7 +3888,7 @@ function _get_cp(geom) =
: in_list(geom[0],["extrusion_extent","extrusion_isect"]) ? "xpath"
: "other"
)
assert(type!="other", "Invalid cp value")
assert(type!="other", "\nInvalid cp value.")
cp=="centroid" ? (
type=="vnf" && (len(geom[1][0])==0 || len(geom[1][1])==0) ? [0,0,0] :
[each centroid(geom[1]), if (type=="xpath") 0]
@@ -3896,7 +3896,7 @@ function _get_cp(geom) =
: let(points = type=="vnf"?geom[1][0]:flatten(force_region(geom[1])))
cp=="mean" ? [each mean(points), if (type=="xpath") 0]
: cp=="box" ?[each mean(pointlist_bounds(points)), if (type=="xpath") 0]
: assert(false,"Invalid cp specification");
: assert(false,"\nInvalid cp specification.");
function _get_cp(geom) =
@@ -3913,7 +3913,7 @@ function _get_cp(geom) =
: let(points = is_vnf?geom[1][0]:flatten(force_region(geom[1])))
cp=="mean" ? mean(points)
: cp=="box" ? mean(pointlist_bounds(points))
: assert(false,"Invalid cp specification");
: assert(false,"\nInvalid cp specification.");
@@ -3949,7 +3949,7 @@ function _find_anchor(anchor, geom)=
anchors = last(geom),
found = search([anchor], anchors, num_returns_per_match=1)[0]
)
assert(found!=[], str("Unknown anchor: ",anchor))
assert(found!=[], str("\nUnknown anchor: ",anchor))
anchors[found]
) :
let(
@@ -3958,7 +3958,7 @@ function _find_anchor(anchor, geom)=
offset = [for (i=[0:2]) anchor[i]==0? 0 : offset_raw[i]], // prevents bad centering.
type = geom[0]
)
assert(is_vector(anchor),str("Invalid anchor: anchor=",anchor))
assert(is_vector(anchor),str("\nInvalid anchor: ",anchor))
let(
anchor = point3d(anchor),
oang = (
@@ -3968,7 +3968,7 @@ function _find_anchor(anchor, geom)=
)
type == "prismoid"? ( //size, size2, shift, axis
let(all_comps_good = [for (c=anchor) if (c!=sign(c)) 1]==[])
assert(all_comps_good, "All components of an anchor for a cuboid/prismoid must be -1, 0, or 1")
assert(all_comps_good, "\nAll components of an anchor for a cuboid/prismoid must be -1, 0, or 1.")
let(
size=geom[1],
size2=geom[2],
@@ -4059,7 +4059,7 @@ function _find_anchor(anchor, geom)=
: axis==RIGHT ? "X"
: axis==BACK ? "Y"
: "",
dummy = assert(anch.z == sign(anch.z), str("The ",axisname," component of an anchor for the cylinder/cone must be -1, 0, or 1")),
dummy = assert(anch.z == sign(anch.z), str("\nThe ",axisname," component of an anchor for the cylinder/cone must be -1, 0, or 1.")),
offset = rot(from=axis, to=UP, p=offset),
u = (anch.z+1)/2,
// Returns [point,tangent_dir]
@@ -4144,7 +4144,7 @@ function _find_anchor(anchor, geom)=
for(pt=ptlist) [anchor * (pt-cp), n, pt]
]
)
assert(len(hits)>0, "Anchor vector does not intersect with the shape. Attachment failed.")
assert(len(hits)>0, "\nAnchor vector does not intersect with the shape. Attachment failed.")
let(
furthest = max_index(column(hits,0)),
dist = hits[furthest][0],
@@ -4169,8 +4169,8 @@ function _find_anchor(anchor, geom)=
let(
vnf=geom[1],
override = geom[2](anchor)
,fd=echo(cp=cp)
) // CENTER anchors anchor on cp, "origin" anchors on [0,0]
//,fd=echo(cp=cp)
) // CENTER anchors anchor on cp, "origin" anchors on [0,0]
approx(anchor,CTR)? [anchor, default(override[0],cp),default(override[1],UP),default(override[2], 0)] :
vnf==EMPTY_VNF? [anchor, [0,0,0], unit(anchor,UP), 0] :
let(
@@ -4236,7 +4236,7 @@ function _find_anchor(anchor, geom)=
center = mean(plist)
)
[center,anchor,basic_spin]
: len(vlist)==0 ? assert(false,"Cannot find anchor on the VNF")
: len(vlist)==0 ? assert(false,"\nCannot find anchor on the VNF.")
: let(
vlist = flatten(vlist),
uind = unique_approx_indexed(select(vnf[0],vlist)),
@@ -4266,7 +4266,7 @@ function _find_anchor(anchor, geom)=
) [anchor, default(override[0],res[0]),default(override[1],res[1]),default(override[2],res[2]),if (len(res)==3) res[2]]
) : type == "trapezoid"? ( //size, size2, shift, override
let(all_comps_good = [for (c=anchor) if (c!=sign(c)) 1]==[])
assert(all_comps_good, "All components of an anchor for a rectangle/trapezoid must be -1, 0, or 1")
assert(all_comps_good, "\nAll components of an anchor for a rectangle/trapezoid must be -1, 0, or 1.")
let(
anchor=_force_anchor_2d(anchor),
size=geom[1], size2=geom[2], shift=geom[3],
@@ -4318,7 +4318,7 @@ function _find_anchor(anchor, geom)=
if(!is_undef(isect) && !approx(isect,t[0])) [norm(isect), isect, n2]
]
)
assert(len(isects)>0, "Anchor vector does not intersect with the shape. Attachment failed.")
assert(len(isects)>0, "\nAnchor vector does not intersect with the shape. Attachment failed.")
let(
maxidx = max_index(column(isects,0)),
isect = isects[maxidx],
@@ -4347,7 +4347,7 @@ function _find_anchor(anchor, geom)=
[is_polygon_clockwise(path) ? -normal : normal, vector_angle(corner)]
) [anchor, pos, dir[0], 0, if(len(dir)>1) [["corner_angle",dir[1]]]]
) : type=="extrusion_extent" || type=="extrusion_isect" ? ( // extruded region
assert(in_list(anchor.z,[-1,0,1]), "The Z component of an anchor for an extruded 2D shape must be -1, 0, or 1.")
assert(in_list(anchor.z,[-1,0,1]), "\nThe Z component of an anchor for an extruded 2D shape must be -1, 0, or 1.")
let(
anchor_xy = point2d(anchor),
rgn = geom[1],
@@ -4379,7 +4379,7 @@ function _find_anchor(anchor, geom)=
)
[anchor, pos, vec, oang]
) :
assert(false, "Unknown attachment geometry type.");
assert(false, "\nUnknown attachment geometry type.");
/// Internal Function: _is_shown()
@@ -4396,8 +4396,8 @@ function _is_shown() =
dummy=is_undef($tags) ? 0 : echo("Use tag() instead of $tags for specifying an object's tag."),
$tag = default($tag,$tags)
)
assert(is_string($tag), str("Tag value (",$tag,") is not a string"))
assert(undef==str_find($tag," "),str("Tag string \"",$tag,"\" contains a space, which is not allowed"))
assert(is_string($tag), str("\nTag value (",$tag,") is not a string"))
assert(undef==str_find($tag," "),str("\nTag string \"",$tag,"\" contains a space, which is not allowed."))
let(
shown = $tags_shown=="ALL" || in_list($tag,$tags_shown),
hidden = in_list($tag, $tags_hidden)
@@ -4822,7 +4822,7 @@ function _edge_set(v) =
let(valid_values = ["X", "Y", "Z", "ALL", "NONE"])
assert(
in_list(v, valid_values),
str(v, " must be a vector, edge array, or one of ", valid_values)
str("\n", v, " must be a vector, edge array, or one of ", valid_values, ".")
) v
) :
let(nonz = sum(v_abs(v)))
@@ -4983,7 +4983,7 @@ function _corner_set(v) =
let(valid_values = ["ALL", "NONE"])
assert(
in_list(v, valid_values),
str(v, " must be a vector, corner array, or one of ", valid_values)
str("\n", v, " must be a vector, corner array, or one of ", valid_values, ".")
) v
) :
all([for (i=[0:2]) !v[i] || (v[i]==v2[i])])
@@ -5114,14 +5114,14 @@ function _force_rot(T) =
: 0]];
function _local_struct_val(struct, key)=
assert(is_def(key),"key is missing")
assert(is_def(key),"\nkey is missing.")
let(ind = search([key],struct)[0])
ind == [] ? undef : struct[ind][1];
function _force_anchor_2d(anchor) =
is_undef(anchor) || len(anchor)==2 || is_string(anchor) ? anchor :
assert(anchor.y==0 || anchor.z==0, "Anchor for a 2D shape cannot be fully 3D. It must have either Y or Z component equal to zero.")
assert(anchor.y==0 || anchor.z==0, "\nAnchor for a 2D shape cannot be fully 3D. It must have either Y or Z component equal to zero.")
anchor.y==0 ? [anchor.x,anchor.z] : point2d(anchor);
// Compute spin angle based on a anchor direction and desired spin direction
@@ -5132,7 +5132,7 @@ function _compute_spin(anchor_dir, spin_dir) =
let(
native_dir = rot(from=UP, to=anchor_dir, p=BACK),
spin_dir = spin_dir - (spin_dir*anchor_dir)*anchor_dir, // component of spin_dir perpendicular to anchor_dir
dummy = assert(!approx(spin_dir,[0,0,0]),"spin direction is parallel to anchor"),
dummy = assert(!approx(spin_dir,[0,0,0]),"\nSpin direction is parallel to anchor."),
angle = vector_angle(native_dir,spin_dir),
sign = cross(native_dir,spin_dir)*anchor_dir<0 ? -1 : 1
)
@@ -5216,11 +5216,11 @@ function parent() =
// fillet=1);
function parent_part(name) =
assert(!is_undef($parent_parts), "Parent does not exist or does not have any parts")
assert(!is_undef($parent_parts), "\nParent does not exist or does not have any parts.")
let(
ind = search([name], $parent_parts, 1,0)[0]
)
assert(ind!=[], str("Parent does not have a part named ",name))
assert(ind!=[], str("\nParent does not have a part named \"",name,"\"."))
[$transform * $parent_parts[ind][3], $parent_parts[ind][1]];
@@ -5251,7 +5251,7 @@ module restore(desc)
multmatrix(T) children();
}
else{
check=assert(is_description(desc), "Invalid description");
check=assert(is_description(desc), "\nInvalid description.");
T = linear_solve($transform, desc[0]);
$parent_geom = desc[1];
multmatrix(T) children();
@@ -5286,13 +5286,13 @@ module restore(desc)
// stroke([[0,0,0], desc_point(desc,anchor=TOP+FWD+RIGHT)],width=.5,color="red");
function desc_point(desc, p, anchor) =
is_undef(desc) ?
assert(is_undef(anchor), "Cannot give anchor withot desc")
assert(is_undef(anchor), "\nCannot give 'anchor' withot 'desc'.")
let(
T = matrix_inverse($transform)
)
apply(T, default(p,UP))
: assert(is_description(desc), "Invalid description")
assert(num_defined([anchor,p])<2, "Cannot give both anchor and p")
: assert(is_description(desc), "\nInvalid description.")
assert(num_defined([anchor,p])<2, "\nCannot give both anchor and p")
let (
T = linear_solve($transform, desc[0]),
p = is_def(p) ? p
@@ -5328,14 +5328,14 @@ function desc_point(desc, p, anchor) =
// position(TOP) cyl(d=2,h=15,orient=desc_dir(pris,anchor=FWD),anchor=LEFT);
function desc_dir(desc, dir, anchor) =
is_undef(desc) ?
assert(is_undef(anchor), "Cannot give anchor without desc")
assert(is_undef(anchor), "\nCannot give 'anchor' without 'desc'.")
let(
T = matrix_inverse($transform)
)
move(-apply(T,CENTER), apply(T, default(dir,UP)))
:
assert(is_description(desc), "Invalid description")
assert(num_defined([dir,anchor])<2, "Cannot give both dir and anchor")
assert(num_defined([dir,anchor])<2, "\nCannot give both dir and anchor.")
let(
T = linear_solve($transform, desc[0]),
dir = is_def(dir) ? dir
@@ -5347,7 +5347,7 @@ function desc_dir(desc, dir, anchor) =
move(-apply(T,CENTER),apply(T, dir));
function desc_attach(desc, anchor=UP, p, reverse=false) =
assert(is_description(desc), "Invalid description")
assert(is_description(desc), "\nInvalid description.")
let(
T = linear_solve($transform, desc[0]),
anch = _find_anchor(anchor,desc[1]),
@@ -5385,8 +5385,8 @@ function desc_attach(desc, anchor=UP, p, reverse=false) =
// }
function desc_dist(desc1,anchor1=CENTER, desc2, anchor2=CENTER)=
assert(is_description(desc1),"Invalid description: desc1")
assert(is_description(desc2),"Invalid description: desc2")
assert(is_description(desc1),str("\nInvalid description: desc1=",desc1))
assert(is_description(desc2),str("\nInvalid description: desc2=",desc2))
let(
anch1 = _find_anchor(anchor1, desc1[1]),
anch2 = _find_anchor(anchor2, desc2[1]),
@@ -5415,10 +5415,10 @@ function desc_dist(desc1,anchor1=CENTER, desc2, anchor2=CENTER)=
// desc = description to transform
function transform_desc(T,desc) =
assert(is_description(desc), "Invalid description")
assert(is_description(desc), "\nInvalid description.")
is_consistent(T, ident(4)) ? [for(t=T) [t*desc[0], desc[1]]]
: is_matrix(T,4,4) ? [T*desc[0], desc[1]]
: assert(false,"T must be a 4x4 matrix or list of 4x4 matrices");
: assert(false,"\nT must be a 4×4 matrix or list of 4×4 matrices.");
// Module: desc_copies()

View File

@@ -659,7 +659,7 @@ function cuboid(
// prismoid(size1=[100,75], h=30, xang=50, yang=70);
// Example: Specifying top, height and angle, with asymmetric angles
// prismoid(size2=[100,75], h=30, xang=[50,60], yang=[70,40]);
// Example: Specifying top, bottom and angle for X and using that to define height. Note that giving yang here would likely give a conflicting height calculation, which is not allowed.
// Example: Specifying top, bottom and angle for X and using that to define height. Giving yang here would likely give a conflicting height calculation, which is not allowed.
// prismoid(size1=[100,75], size2=[75,35], xang=50);
// Example: The same as the previous example but we give a shift in Y. Note that shift.x must be undef because you cannot give combine an angle with a shift, so a shift.x value would conflict with xang being defined.
// prismoid(size1=[100,75], size2=[75,35], xang=50, shift=[undef,20]);
@@ -1757,7 +1757,6 @@ function rect_tube(
// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). Default: `FRONT+LEFT+BOTTOM`
// 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`
//
// Named Anchors:
// "hypot" = Center of angled wedge face, perpendicular to that face.
// "hypot_left" = Left side of angled wedge face, bisecting the angle between the left side and angled faces.
@@ -2092,7 +2091,7 @@ function cylinder(h, r1, r2, center, r, d, d1, d2, anchor, spin=0, orient=UP) =
// texture = A texture name string, or a rectangular array of scalar height values (0.0 to 1.0), or a VNF tile that defines the texture to apply to vertical surfaces. See {{texture()}} for what named textures are supported.
// tex_size = An optional 2D target size (2-vector or scalar) for the textures. Actual texture sizes will be scaled somewhat to evenly fit the available surface. Default: `[5,5]`
// tex_reps = If given instead of tex_size, a scalar or 2-vector giving the integer number of texture tile repetitions in the horizontal and vertical directions.
// tex_inset = If numeric, lowers the texture into the surface by the specified proportion, e.g. 0.5 would lower it half way into the surface. If `true`, insets by exactly its full depth. Default: `false`
// tex_inset = If numeric, lowers the texture into the surface by the specified proportion, e.g. 0.5 would lower it halfway into the surface. If `true`, insets by exactly its full depth. Default: `false`
// tex_rot = Rotate texture by specified angle, which must be a multiple of 90 degrees. Default: 0
// tex_depth = Specify texture depth; if negative, invert the texture. Default: 1.
// tex_samples = Minimum number of "bend points" to have in VNF texture tiles. Default: 8
@@ -2101,20 +2100,16 @@ function cylinder(h, r1, r2, center, r, d, d1, d2, anchor, spin=0, orient=UP) =
// 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`
//
//
// Example: By Radius
// Example: By radius
// xdistribute(30) {
// cyl(l=40, r=10);
// cyl(l=40, r1=10, r2=5);
// }
//
// Example: By Diameter
// Example: By diameter
// xdistribute(30) {
// cyl(l=40, d=25);
// cyl(l=40, d1=25, d2=10);
// }
//
// Example: Chamferring
// xdistribute(60) {
// // Shown Left to right.
@@ -2122,16 +2117,12 @@ function cylinder(h, r1, r2, center, r, d, d1, d2, anchor, spin=0, orient=UP) =
// cyl(l=40, d=40, chamfer=7, chamfang=30, from_end=false);
// cyl(l=40, d=40, chamfer=7, chamfang=30, from_end=true);
// }
//
// Example: Rounding
// cyl(l=40, d=40, rounding=10);
//
// Example(VPD=175;VPR=[90,0,0]): Teardrop Bottom Rounding
// cyl(l=40, d=40, rounding=10, teardrop=true);
//
// Example(VPD=175;VPR=[90,0,0]): Clipped Bottom Rounding
// cyl(l=40, d=40, rounding=10, clip_angle=40);
//
// Example: Heterogenous Chamfers and Rounding
// ydistribute(80) {
// // Shown Front to Back.
@@ -2139,63 +2130,50 @@ function cylinder(h, r1, r2, center, r, d, d1, d2, anchor, spin=0, orient=UP) =
// cyl(l=40, d=40, chamfer2=5, orient=UP);
// cyl(l=40, d=40, chamfer1=12, rounding2=10, orient=UP);
// }
//
// Example: Putting it all together
// cyl(
// l=20, d1=25, d2=15,
// chamfer1=5, chamfang1=60,
// from_end=true, rounding2=5
// );
//
// Example: External Chamfers
// Example: External chamfers
// cyl(l=50, r=30, chamfer=-5, chamfang=30, $fa=1, $fs=1);
//
// Example: External Roundings
// cyl(l=50, r=30, rounding1=-5, rounding2=5, $fa=1, $fs=1);
//
// Example(Med): Standard Connectors
// xdistribute(40) {
// cyl(l=30, d=25) show_anchors();
// cyl(l=30, d1=25, d2=10) show_anchors();
// }
//
// Example: Texturing with heightfield diamonds
// cyl(h=40, r=20, texture="diamonds", tex_size=[5,5]);
//
// Example: Texturing with heightfield pyramids
// cyl(h=40, r1=20, r2=15,
// texture="pyramids", tex_size=[5,5],
// style="convex");
//
// Example: Texturing with heightfield truncated pyramids
// cyl(h=40, r1=20, r2=15, chamfer=5,
// texture="trunc_pyramids",
// tex_size=[5,5], style="convex");
//
// Example: Texturing with VNF tile "dots"
// cyl(h=40, r1=20, r2=15, rounding=9,
// texture="dots", tex_size=[5,5],
// tex_samples=6);
//
// Example: Texturing with VNF tile "bricks_vnf"
// cyl(h=50, r1=25, r2=20, shift=[0,10], rounding1=-10,
// texture="bricks_vnf", tex_size=[10,10],
// tex_depth=0.5, style="concave");
//
// Example: No Texture Taper
// cyl(d1=25, d2=20, h=30, rounding=5,
// texture="trunc_ribs", tex_size=[5,1]);
//
// Example: Taper Texure at Extreme Ends
// cyl(d1=25, d2=20, h=30, rounding=5,
// texture="trunc_ribs", tex_taper=0,
// tex_size=[5,1]);
//
// Example: Taper Texture over First and Last 10%
// cyl(d1=25, d2=20, h=30, rounding=5,
// texture="trunc_ribs", tex_taper=0.1,
// tex_size=[5,1]);
//
// Example(3D,Med,NoAxes): Making a Clay Pattern Roller
// tex = [
// [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,],
@@ -2347,7 +2325,7 @@ function cyl(
from_end, from_end1, from_end2,
texture, tex_size=[5,5], tex_reps, tex_counts,
tex_inset=false, tex_rot=0,
tex_scale, tex_depth, tex_samples, length, height,
tex_scale, tex_depth, tex_samples,
tex_taper, style, tex_style,
extra, extra1, extra2,
anchor, spin=0, orient=UP
@@ -2455,6 +2433,7 @@ module cyl(
h, r, center,
l, r1, r2,
d, d1, d2,
length, height,
chamfer, chamfer1, chamfer2,
chamfang, chamfang1, chamfang2,
rounding, rounding1, rounding2,
@@ -2463,7 +2442,7 @@ module cyl(
from_end, from_end1, from_end2,
texture, tex_size=[5,5], tex_reps, tex_counts,
tex_inset=false, tex_rot=0,
tex_scale, tex_depth, tex_samples, length, height,
tex_scale, tex_depth, tex_samples,
tex_taper, style, tex_style,
extra, extra1, extra2,
anchor, spin=0, orient=UP
@@ -2516,251 +2495,334 @@ module cyl(
// Module: xcyl()
// Synopsis: creates a cylinder oriented along the X axis.
// SynTags: Geom
// Function&Module: xcyl()
// Synopsis: Creates a cylinder oriented along the X axis.
// SynTags: Geom, VNF
// Topics: Cylinders, Textures, Rounding, Chamfers
// See Also: texture(), rotate_sweep(), cyl()
// Description:
// Creates an attachable cylinder with roundovers and chamfering oriented along the X axis.
//
// Usage: Typical
// xcyl(l|h|length|height, r|d=, [anchor=], ...) [ATTACHMENTS];
// xcyl(l|h|length|height, r1=|d1=, r2=|d2=, [anchor=], ...) [ATTACHMENTS];
//
// Arguments:
// l / h / length / height = Length of cylinder along oriented axis. Default: 1
// r = Radius of cylinder. Default: 1
// ---
// r1 = Optional radius of left (X-) end of cylinder.
// r2 = Optional radius of right (X+) end of cylinder.
// d = Optional diameter of cylinder. (use instead of `r`)
// d1 = Optional diameter of left (X-) end of cylinder.
// d2 = Optional diameter of right (X+) end of cylinder.
// circum = If true, cylinder should circumscribe the circle of the given size. Otherwise inscribes. Default: `false`
// chamfer = The size of the chamfers on the ends of the cylinder. Default: none.
// chamfer1 = The size of the chamfer on the left end of the cylinder. Default: none.
// chamfer2 = The size of the chamfer on the right end of the cylinder. Default: none.
// chamfang = The angle in degrees of the chamfers on the ends of the cylinder.
// chamfang1 = The angle in degrees of the chamfer on the left end of the cylinder.
// chamfang2 = The angle in degrees of the chamfer on the right end of the cylinder.
// from_end = If true, chamfer is measured from the end of the cylinder, instead of inset from the edge. Default: `false`.
// rounding = The radius of the rounding on the ends of the cylinder. Default: none.
// rounding1 = The radius of the rounding on the left end of the cylinder.
// rounding2 = The radius of the rounding on the right end of the cylinder.
// realign = If true, rotate the cylinder by half the angle of one face.
// 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`
//
// Example: By Radius
// Description:
// Creates an attachable cylinder with roundovers, chamfering, and optional texture, oriented along the X axis.
// .
// Used as a function, this is a shortcut for `cyl()` with `orient=RIGHT`, but otherwise using the same arguments excluding `orient`, which is not accepted.
// Used as a module, the difference from cyl() is in the anchors, which don't get reoriented with the cylinder but maintain
// the orientations you specify.
// For example, top and right anchors on xcyl() are on the top curved surface and the right (positive x) end,
// respectively, whereas with cyl() these anchors are associated with the top end and right side.
// .
// See [cyl()] for more detailed usage and arguments.
// Example: By radius. The cone shows anchor arrows for `TOP` and `RIGHT`.
// ydistribute(50) {
// xcyl(l=35, r=10);
// xcyl(l=35, r1=15, r2=5);
// xcyl(l=35, r1=15, r2=5) {
// attach(TOP) anchor_arrow();
// attach(RIGHT) anchor_arrow();
// }
// }
//
// Example: By Diameter
// Example: By diameter
// ydistribute(50) {
// xcyl(l=35, d=20);
// xcyl(l=35, d1=30, d2=10);
// }
function xcyl(
h, r, d, r1, r2, d1, d2, l,
h, r, center,
l, r1, r2,
d, d1, d2,
length, height,
chamfer, chamfer1, chamfer2,
chamfang, chamfang1, chamfang2,
rounding, rounding1, rounding2,
circum=false, realign=false, from_end=false, length, height,
anchor=CENTER, spin=0, orient=UP
) = no_function("xcyl");
circum=false, realign=false, shift=[0,0],
teardrop=false, clip_angle,
from_end, from_end1, from_end2,
texture, tex_size=[5,5], tex_reps, tex_counts,
tex_inset=false, tex_rot=0,
tex_scale, tex_depth, tex_samples,
tex_taper, style, tex_style,
extra, extra1, extra2,
anchor, spin=0
) = let(
r1 = get_radius(r1=r1, r=r, d1=d1, d=d, dflt=1),
r2 = get_radius(r1=r2, r=r, d1=d2, d=d, dflt=1),
l = one_defined([l,h,length,height],"l,h,length,height",1),
vnf=cyl(h=h, r=r, center=center,
l=l, r1=r1, r2=r2,
d=d, d1=d1, d2=d2,
length=length, height=height,
chamfer=chamfer, chamfer1=chamfer1, chamfer2=chamfer2,
chamfang=chamfang, chamfang1=chamfang1, chamfang2=chamfang2,
rounding=rounding, rounding1=rounding1, rounding2=rounding2,
circum=circum, realign=realign, shift=shift,
teardrop=teardrop, clip_angle=clip_angle,
from_end=from_end, from_end1=from_end1, from_end2=from_end2,
texture=texture, tex_size=tex_size, tex_reps=tex_reps, tex_counts=tex_counts,
tex_inset=tex_inset, tex_rot=tex_rot,
tex_scale=tex_scale, tex_depth=tex_depth, tex_samples=tex_samples,
tex_taper=tex_taper, style=style, tex_style=tex_style,
extra=extra, extra1=extra1, extra2=extra2,
anchor=CENTER, spin=0, orient=RIGHT)
) reorient(anchor, spin, UP, p=vnf, r1=r1, r2=r2, l=l, axis=RIGHT);
module xcyl(
h, r, d, r1, r2, d1, d2, l,
h, r, center,
l, r1, r2,
d, d1, d2,
length, height,
chamfer, chamfer1, chamfer2,
chamfang, chamfang1, chamfang2,
rounding, rounding1, rounding2,
circum=false, realign=false, from_end=false, length, height,
anchor=CENTER, spin=0, orient=UP
circum=false, realign=false, shift=[0,0],
teardrop=false, clip_angle,
from_end, from_end1, from_end2,
texture, tex_size=[5,5], tex_reps, tex_counts,
tex_inset=false, tex_rot=0,
tex_scale, tex_depth, tex_samples,
tex_taper, style, tex_style,
extra, extra1, extra2,
anchor=CENTER, spin=0
) {
r1 = get_radius(r1=r1, r=r, d1=d1, d=d, dflt=1);
r2 = get_radius(r1=r2, r=r, d1=d2, d=d, dflt=1);
l = one_defined([l,h,length,height],"l,h,length,height",1);
attachable(anchor,spin,orient, r1=r1, r2=r2, l=l, axis=RIGHT) {
attachable(anchor,spin,orient=UP, r1=r1, r2=r2, l=l, axis=RIGHT) {
cyl(
center=center,
l=l, r1=r1, r2=r2,
chamfer=chamfer, chamfer1=chamfer1, chamfer2=chamfer2,
chamfang=chamfang, chamfang1=chamfang1, chamfang2=chamfang2,
rounding=rounding, rounding1=rounding1, rounding2=rounding2,
circum=circum, realign=realign, from_end=from_end,
anchor=CENTER, orient=RIGHT
circum=circum, realign=realign, shift=shift,
teardrop=teardrop, clip_angle=clip_angle,
from_end=from_end, from_end1=from_end1, from_end2=from_end2,
texture=texture, tex_size=tex_size, tex_reps=tex_reps, tex_counts=tex_counts,
tex_inset=tex_inset, tex_rot=tex_rot,
tex_scale=tex_scale, tex_depth=tex_depth, tex_samples=tex_samples,
tex_taper=tex_taper, style=style, tex_style=tex_style,
extra=extra, extra1=extra1, extra2=extra2,
anchor=CENTER, spin=0, orient=RIGHT
);
children();
}
}
// Module: ycyl()
// Function&Module: ycyl()
// Synopsis: Creates a cylinder oriented along the y axis.
// SynTags: Geom
// SynTags: Geom, VNF
// Topics: Cylinders, Textures, Rounding, Chamfers
// See Also: texture(), rotate_sweep(), cyl()
// Description:
// Creates an attachable cylinder with roundovers and chamfering oriented along the y axis.
//
// Usage: Typical
// ycyl(l|h|length|height, r|d=, [anchor=], ...) [ATTACHMENTS];
// ycyl(l|h|length|height, r1=|d1=, r2=|d2=, [anchor=], ...) [ATTACHMENTS];
//
// Arguments:
// l / h / length / height = Length of cylinder along oriented axis. (Default: `1.0`)
// r = Radius of cylinder.
// ---
// r1 = Radius of front (Y-) end of cone.
// r2 = Radius of back (Y+) end of one.
// d = Diameter of cylinder.
// d1 = Diameter of front (Y-) end of one.
// d2 = Diameter of back (Y+) end of one.
// circum = If true, cylinder should circumscribe the circle of the given size. Otherwise inscribes. Default: `false`
// chamfer = The size of the chamfers on the ends of the cylinder. Default: none.
// chamfer1 = The size of the chamfer on the front end of the cylinder. Default: none.
// chamfer2 = The size of the chamfer on the back end of the cylinder. Default: none.
// chamfang = The angle in degrees of the chamfers on the ends of the cylinder.
// chamfang1 = The angle in degrees of the chamfer on the front end of the cylinder.
// chamfang2 = The angle in degrees of the chamfer on the back end of the cylinder.
// from_end = If true, chamfer is measured from the end of the cylinder, instead of inset from the edge. Default: `false`.
// rounding = The radius of the rounding on the ends of the cylinder. Default: none.
// rounding1 = The radius of the rounding on the front end of the cylinder.
// rounding2 = The radius of the rounding on the back end of the cylinder.
// realign = If true, rotate the cylinder by half the angle of one face.
// 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`
//
// Example: By Radius
// Creates an attachable cylinder with roundovers, chamfering, and optional texture, oriented along the Y axis.
// .
// Used as a function, this is a shortcut for `cyl()` with `orient=BACK`, but otherwise using the same arguments excluding `orient`, which is not accepted.
// Used as a module, the difference from cyl() is in the anchors, which don't get reoriented with the cylinder but maintain
// the orientations you specify.
// For example, top and right anchors on ycyl() are on the top and right of the curved cylinder surface,
// respectively, whereas with cyl() these anchors are associated with the top end and right side.
// .
// See [cyl()] for more detailed usage and arguments.
// Example: By radius. The cone shows anchor arrows for `TOP` and `RIGHT`.
// xdistribute(50) {
// ycyl(l=35, r=10);
// ycyl(l=35, r1=15, r2=5);
// ycyl(l=35, r1=15, r2=5) {
// attach(TOP) anchor_arrow();
// attach(RIGHT) anchor_arrow();
// }
// }
//
// Example: By Diameter
// Example: By diameter
// xdistribute(50) {
// ycyl(l=35, d=20);
// ycyl(l=35, d1=30, d2=10);
// }
function ycyl(
h, r, d, r1, r2, d1, d2, l,
h, r, center,
l, r1, r2,
d, d1, d2,
length, height,
chamfer, chamfer1, chamfer2,
chamfang, chamfang1, chamfang2,
rounding, rounding1, rounding2,
circum=false, realign=false, from_end=false,height,length,
anchor=CENTER, spin=0, orient=UP
) = no_function("ycyl");
circum=false, realign=false, shift=[0,0],
teardrop=false, clip_angle,
from_end, from_end1, from_end2,
texture, tex_size=[5,5], tex_reps, tex_counts,
tex_inset=false, tex_rot=0,
tex_scale, tex_depth, tex_samples, length, height,
tex_taper, style, tex_style,
extra, extra1, extra2,
anchor, spin=0
) = let(
r1 = get_radius(r1=r1, r=r, d1=d1, d=d, dflt=1),
r2 = get_radius(r1=r2, r=r, d1=d2, d=d, dflt=1),
l = one_defined([l,h,length,height],"l,h,length,height",1),
vnf=cyl(h=h, r=r, center=center,
l=l, r1=r1, r2=r2,
d=d, d1=d1, d2=d2,
length=length, height=height,
chamfer=chamfer, chamfer1=chamfer1, chamfer2=chamfer2,
chamfang=chamfang, chamfang1=chamfang1, chamfang2=chamfang2,
rounding=rounding, rounding1=rounding1, rounding2=rounding2,
circum=circum, realign=realign, shift=shift,
teardrop=teardrop, clip_angle=clip_angle,
from_end=from_end, from_end1=from_end1, from_end2=from_end2,
texture=texture, tex_size=tex_size, tex_reps=tex_reps, tex_counts=tex_counts,
tex_inset=tex_inset, tex_rot=tex_rot,
tex_scale=tex_scale, tex_depth=tex_depth, tex_samples=tex_samples,
tex_taper=tex_taper, style=style, tex_style=tex_style,
extra=extra, extra1=extra1, extra2=extra2,
anchor=CENTER, spin=0, orient=BACK)
) reorient(anchor, spin, UP, p=vnf, r1=r1, r2=r2, l=l, axis=BACK);
module ycyl(
h, r, d, r1, r2, d1, d2, l,
h, r, center,
l, r1, r2,
d, d1, d2,
length, height,
chamfer, chamfer1, chamfer2,
chamfang, chamfang1, chamfang2,
rounding, rounding1, rounding2,
circum=false, realign=false, from_end=false,height,length,
anchor=CENTER, spin=0, orient=UP
circum=false, realign=false, shift=[0,0],
teardrop=false, clip_angle,
from_end, from_end1, from_end2,
texture, tex_size=[5,5], tex_reps, tex_counts,
tex_inset=false, tex_rot=0,
tex_scale, tex_depth, tex_samples,
tex_taper, style, tex_style,
extra, extra1, extra2,
anchor, spin=0
) {
r1 = get_radius(r1=r1, r=r, d1=d1, d=d, dflt=1);
r2 = get_radius(r1=r2, r=r, d1=d2, d=d, dflt=1);
l = one_defined([l,h,length,height],"l,h,length,height",1);
attachable(anchor,spin,orient, r1=r1, r2=r2, l=l, axis=BACK) {
attachable(anchor,spin,orient=UP, r1=r1, r2=r2, l=l, axis=BACK) {
cyl(
center=center,
l=l, r1=r1, r2=r2,
chamfer=chamfer, chamfer1=chamfer1, chamfer2=chamfer2,
chamfang=chamfang, chamfang1=chamfang1, chamfang2=chamfang2,
rounding=rounding, rounding1=rounding1, rounding2=rounding2,
circum=circum, realign=realign, from_end=from_end,
anchor=CENTER, orient=BACK
circum=circum, realign=realign, shift=shift,
teardrop=teardrop, clip_angle=clip_angle,
from_end=from_end, from_end1=from_end1, from_end2=from_end2,
texture=texture, tex_size=tex_size, tex_reps=tex_reps, tex_counts=tex_counts,
tex_inset=tex_inset, tex_rot=tex_rot,
tex_scale=tex_scale, tex_depth=tex_depth, tex_samples=tex_samples,
tex_taper=tex_taper, style=style, tex_style=tex_style,
extra=extra, extra1=extra1, extra2=extra2,
anchor=CENTER, spin=0, orient=BACK
);
children();
}
}
// Module: zcyl()
// Synopsis: Creates a cylinder oriented along the Z axis.
// SynTags: Geom
// Synopsis: Creates a cylinder oriented along the y axis.
// SynTags: Geom, VNF
// Topics: Cylinders, Textures, Rounding, Chamfers
// See Also: texture(), rotate_sweep(), cyl()
// Description:
// Creates an attachable cylinder with roundovers and chamfering oriented along the Z axis.
//
// Usage: Typical
// zcyl(l|h|length|height, r|d=, [anchor=],...) [ATTACHMENTS];
// zcyl(l|h|length|height, r1=|d1=, r2=|d2=, [anchor=],...);
//
// Arguments:
// l / h / length / height = Length of cylinder along oriented axis. (Default: 1.0)
// r = Radius of cylinder.
// ---
// r1 = Radius of front (Y-) end of cone.
// r2 = Radius of back (Y+) end of one.
// d = Diameter of cylinder.
// d1 = Diameter of front (Y-) end of one.
// d2 = Diameter of back (Y+) end of one.
// circum = If true, cylinder should circumscribe the circle of the given size. Otherwise inscribes. Default: `false`
// chamfer = The size of the chamfers on the ends of the cylinder. Default: none.
// chamfer1 = The size of the chamfer on the bottom end of the cylinder. Default: none.
// chamfer2 = The size of the chamfer on the top end of the cylinder. Default: none.
// chamfang = The angle in degrees of the chamfers on the ends of the cylinder.
// chamfang1 = The angle in degrees of the chamfer on the bottom end of the cylinder.
// chamfang2 = The angle in degrees of the chamfer on the top end of the cylinder.
// from_end = If true, chamfer is measured from the end of the cylinder, instead of inset from the edge. Default: `false`.
// rounding = The radius of the rounding on the ends of the cylinder. Default: none.
// rounding1 = The radius of the rounding on the bottom end of the cylinder.
// rounding2 = The radius of the rounding on the top end of the cylinder.
// realign = If true, rotate the cylinder by half the angle of one face.
// 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`
//
// Example: By Radius
// Pass-through to [cyl()]. Creates an attachable cylinder with roundovers, chamfering, and optional texture, oriented along the Z axis.
// .
// This is a shortcut for `cyl()` with `orient=UP` (which is also the default for [cyl()]), but otherwise using the same arguments excluding `orient`, which is not accepted. Unlike `xcyl()` and `ycyl()`, anchoring for `zcyl()` works the same as for `cyl()`.
// .
// See [cyl()] for more detailed usage and arguments.
// Example: By radius. The cone shows anchor arrows for `TOP` and `RIGHT`, which for `zcyl()` work the same as for `cyl()`.
// xdistribute(50) {
// zcyl(l=35, r=10);
// zcyl(l=35, r1=15, r2=5);
// zcyl(l=35, r1=15, r2=5) {
// attach(TOP) anchor_arrow();
// attach(RIGHT) anchor_arrow();
// }
// }
//
// Example: By Diameter
// Example: By diameter
// xdistribute(50) {
// zcyl(l=35, d=20);
// zcyl(l=35, d1=30, d2=10);
// }
function zcyl(
h, r, d, r1, r2, d1, d2, l,
h, r, center,
l, r1, r2,
d, d1, d2,
length, height,
chamfer, chamfer1, chamfer2,
chamfang, chamfang1, chamfang2,
rounding, rounding1, rounding2,
circum=false, realign=false, from_end=false, length, height,
anchor=CENTER, spin=0, orient=UP
) = no_function("zcyl");
circum=false, realign=false, shift=[0,0],
teardrop=false, clip_angle,
from_end, from_end1, from_end2,
texture, tex_size=[5,5], tex_reps, tex_counts,
tex_inset=false, tex_rot=0,
tex_scale, tex_depth, tex_samples, length, height,
tex_taper, style, tex_style,
extra, extra1, extra2,
anchor, spin=0
) = let(
r1 = get_radius(r1=r1, r=r, d1=d1, d=d, dflt=1),
r2 = get_radius(r1=r2, r=r, d1=d2, d=d, dflt=1),
l = one_defined([l,h,length,height],"l,h,length,height",1),
vnf=cyl(h=h, r=r, center=center,
l=l, r1=r1, r2=r2,
d=d, d1=d1, d2=d2,
length=length, height=height,
chamfer=chamfer, chamfer1=chamfer1, chamfer2=chamfer2,
chamfang=chamfang, chamfang1=chamfang1, chamfang2=chamfang2,
rounding=rounding, rounding1=rounding1, rounding2=rounding2,
circum=circum, realign=realign, shift=shift,
teardrop=teardrop, clip_angle=clip_angle,
from_end=from_end, from_end1=from_end1, from_end2=from_end2,
texture=texture, tex_size=tex_size, tex_reps=tex_reps, tex_counts=tex_counts,
tex_inset=tex_inset, tex_rot=tex_rot,
tex_scale=tex_scale, tex_depth=tex_depth, tex_samples=tex_samples,
tex_taper=tex_taper, style=style, tex_style=tex_style,
extra=extra, extra1=extra1, extra2=extra2,
anchor=CENTER, spin=0, orient=UP)
) reorient(anchor, spin, UP, p=vnf, r1=r1, r2=r2, l=l, axis=UP);
module zcyl(
h, r, d, r1, r2, d1, d2, l,
h, r, center,
l, r1, r2,
d, d1, d2,
chamfer, chamfer1, chamfer2,
chamfang, chamfang1, chamfang2,
rounding, rounding1, rounding2,
circum=false, realign=false, from_end=false, length, height,
anchor=CENTER, spin=0, orient=UP
circum=false, realign=false, shift=[0,0],
teardrop=false, clip_angle,
from_end, from_end1, from_end2,
texture, tex_size=[5,5], tex_reps, tex_counts,
tex_inset=false, tex_rot=0,
tex_scale, tex_depth, tex_samples, length, height,
tex_taper, style, tex_style,
extra, extra1, extra2,
anchor, spin=0
) {
r1 = get_radius(r1=r1, r=r, d1=d1, d=d, dflt=1);
r2 = get_radius(r1=r2, r=r, d1=d2, d=d, dflt=1);
l = one_defined([l,h,length,height],"l,h,length,height",1);
attachable(anchor,spin,orient, r1=r1, r2=r2, l=l) {
attachable(anchor,spin,orient=UP, r1=r1, r2=r2, l=l) {
cyl(
center=center,
l=l, r1=r1, r2=r2,
chamfer=chamfer, chamfer1=chamfer1, chamfer2=chamfer2,
chamfang=chamfang, chamfang1=chamfang1, chamfang2=chamfang2,
rounding=rounding, rounding1=rounding1, rounding2=rounding2,
circum=circum, realign=realign, from_end=from_end,
anchor=CENTER
circum=circum, realign=realign, shift=shift,
teardrop=teardrop, clip_angle=clip_angle,
from_end=from_end, from_end1=from_end1, from_end2=from_end2,
texture=texture, tex_size=tex_size, tex_reps=tex_reps, tex_counts=tex_counts,
tex_inset=tex_inset, tex_rot=tex_rot,
tex_scale=tex_scale, tex_depth=tex_depth, tex_samples=tex_samples,
tex_taper=tex_taper, style=style, tex_style=tex_style,
extra=extra, extra1=extra1, extra2=extra2,
anchor=CENTER, spin=0, orient=UP
);
children();
}
@@ -3193,7 +3255,7 @@ function sphere(r, d, anchor=CENTER, spin=0, orient=UP) =
// With style="align", the circumscribed sphere has its maximum radius on the X and Y axes
// but is undersized on the Z axis. With style="octa" the circumscribed sphere has faces at each axis, so
// the radius on the axes is equal to the specified radius, which is the *minimum* radius of the circumscribed sphere.
// The same thing is true for style="icosa" when $fn is a multiple of 10. This would enable you to create spherical
// The same thing is true for style="icosa" when $fn is a multiple of 10. This enables you to create spherical
// holes with guaranteed on-axis dimensions.
// Arguments:
// r = Radius of the spheroid.
@@ -3825,7 +3887,7 @@ function teardrop(h, r, ang=45, cap_h, r1, r2, d, d1, d2, cap_h1, cap_h2, chamf
//
// Named Anchors:
// "cap" = The center of the top of the cap, oriented with the cap face normal.
// "tip" = The position where an un-capped onion would come to a point, oriented in the direction the point is from the center.
// "tip" = The position where an un-capped onion comes to a point, oriented in the direction the point is from the center.
//
// Example: Typical Shape
// onion(r=30, ang=30);