diff --git a/attachments.scad b/attachments.scad index 89bd08c..c3f1a45 100644 --- a/attachments.scad +++ b/attachments.scad @@ -39,7 +39,9 @@ $edge_length = undef; $tags_shown = "ALL"; $tags_hidden = []; - +$ghost_this=false; +$ghost=false; +$ghosting=false; // Ghosting is in effect, so don't apply it again _ANCHOR_TYPES = ["intersect","hull"]; @@ -3070,7 +3072,7 @@ module attachable( axis=UP,override, geom, 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(is_undef(anchor) || is_vector(anchor) || is_string(anchor), str("Invalid anchor: ",anchor)) @@ -3104,31 +3106,32 @@ module attachable( $attach_alignment=undef; if (expose_tags || _is_shown()){ if (!keep_color) - _color($color) children(0); + _color($color) + if (($ghost || $ghost_this) && !$ghosting) + %union(){ + $ghosting=true; + children(0); + } + else children(0); else { $save_color=undef; // Force color_this() color in effect to persist for the entire object - children(0); + if (($ghost || $ghost_this) && !$ghosting) + %union(){ + $ghosting=true; + children(0); + } + else children(0); } } - if (is_def($save_tag) && is_def($save_color)){ - $tag=$save_tag; - $save_tag=undef; - $color=$save_color; // Revert to the color before color_this() call - $save_color=undef; - children(1); - } - else if (is_def($save_color)) { - $color=$save_color; // Revert to the color before color_this() call - $save_color=undef; - children(1); - } - else if (is_def($save_tag)) { - $tag=$save_tag; - $save_tag=undef; - children(1); - } - else children(1); - } + let( + $ghost_this=false, + $tag=default($save_tag,$tag), + $save_tag=undef, + $color=default($save_color,$color), + $save_color=undef + ) + children(1); + } } // Function: reorient() @@ -3726,25 +3729,24 @@ function _attach_transform(anchor, spin, orient, geom, p) = spin=default(spin,0), orient=default(orient,UP), two_d = _attach_geom_2d(geom), - m = ($attach_to != undef) ? // $attach_to is the attachment point on this object + m = is_def($attach_to) ? // $attach_to is the attachment point on this object ( // which will attach to the parent - let( - anch = _find_anchor($attach_to, geom), - // if $anchor_override is set it defines the object position anchor (but note not direction or spin). - // Otherwise we use the provided anchor for the object. - pos = is_undef($anchor_override) ? anch[1] - : _find_anchor(_make_anchor_legal($anchor_override,geom),geom)[1] - ) - two_d? - assert(is_num(spin)) - affine3d_zrot(spin) - * rot(to=FWD, from=point3d(anch[2])) - * affine3d_translate(point3d(-pos)) - : - affine3d_yrot(180) - * affine3d_zrot(-anch[3]-spin) - * rot(from=anch[2],to=UP) - * affine3d_translate(point3d(-pos)) + let( + anch = _find_anchor($attach_to, geom), + // if $anchor_override is set it defines the object position anchor (but note not direction or spin). + // Otherwise we use the provided anchor for the object. + pos = is_undef($anchor_override) ? anch[1] + : _find_anchor(_make_anchor_legal($anchor_override,geom),geom)[1] + ) + two_d? + affine3d_zrot(spin) + * rot(to=FWD, from=point3d(anch[2])) + * affine3d_translate(point3d(-pos)) + : + affine3d_yrot(180) + * affine3d_zrot(-anch[3]-spin) + * rot(from=anch[2],to=UP) + * affine3d_translate(point3d(-pos)) ) : let( @@ -3753,17 +3755,14 @@ function _attach_transform(anchor, spin, orient, geom, p) = : _make_anchor_legal(rot(spin, from=UP,to=orient,reverse=true,p=$attach_alignment),geom), pos = _find_anchor(anchor, geom)[1] ) - two_d? - assert(is_num(spin)) - affine3d_zrot(spin) * affine3d_translate(point3d(-pos)) + two_d? affine3d_zrot(spin) * affine3d_translate(point3d(-pos)) : let( axis = vector_axis(UP,orient), // Returns BACK if orient is UP ang = vector_angle(UP,orient) ) affine3d_rot_by_axis(axis,ang) - * ( is_num(spin)? affine3d_zrot(spin) - : affine3d_zrot(spin.z) * affine3d_yrot(spin.y) * affine3d_xrot(spin.x)) + * affine3d_zrot(spin) * affine3d_translate(point3d(-pos)) ) is_undef(p)? m @@ -3926,7 +3925,7 @@ function _find_anchor(anchor, geom)= : oang // face anchors point UP/BACK ) [anchor, final_pos, final_dir, default(override[2],spin), if (is_def(edgeang)) [["edge_angle",edgeang],["edge_length",edgelen], ["vec", endvecs]]] - ) : type == "conoid"? ( //r1, r2, l, shift + ) : type == "conoid"? ( //r1, r2, l, shift, axis let( rr1=geom[1], rr2=geom[2], diff --git a/color.scad b/color.scad index 3c6a51b..5582c07 100644 --- a/color.scad +++ b/color.scad @@ -161,6 +161,50 @@ module color_overlaps(color="red") { %children(); } +// Module: ghost() +// Synopsis: Sets transparency for attachable children and their descendents. +// SynTags: Trans +// Topics: Attachments +// See Also: ghost_this(), recolor(), color_this() +// Usage: +// ghost([ghost]) CHILDREN; +// Description: +// Sets the transparency for the attachable children and their descendents until another {{ghost()}} or {{ghost_this()}}. +// By default, turns transparency on. Give the `false` parameter to disable transparency. +// Do not mix this with user supplied `%` operators anywhere in the geometry tree. +// Arguments: +// ghost = If true set the descendents to be transparent; if false, disable transparency. Default: true +// Example(3D): +// ghost() cuboid(10) +// ghost(false) cuboid(5); +function ghost(ghost) = no_function("ghost"); +module ghost(ghost=true) +{ + $ghost=ghost; + children(); +} + + +// Module: ghost_this() +// Synopsis: Makes the children at a single level transparent. +// SynTags: Trans +// Topics: Attachments +// See Also: ghost(), recolor(), color_this() +// Usage: +// ghost_this() CHILDREN; +// Description: +// Makes the children transparent for one level, reverting to the previous transparency state for further descendents. +// This works only with attachables and you cannot give the `%` operator anywhere in the geometry tree. +// Example(3D): +// ghost_this() cuboid(10) +// cuboid(5); +function ghost_this() = no_function("ghost_this"); +module ghost_this() +{ + $ghost_this=true; + children(); +} + // Section: Colorspace Conversion diff --git a/distributors.scad b/distributors.scad index 915e445..e706adc 100644 --- a/distributors.scad +++ b/distributors.scad @@ -654,6 +654,7 @@ module grid_copies(spacing, n, size, stagger=false, inside=undef, nonzero) is_vector(n)? assert(len(n)==2) n : size!=undef && spacing!=undef? v_floor(v_div(size,spacing))+[1,1] : [2,2]; + dummy2 = assert(is_int(n[0]) && is_int(n[1]), "The number of rows/columns must be an integer"); offset = v_mul(spacing, n-[1,1])/2; poslist = diff --git a/lists.scad b/lists.scad index a343723..6ccb8a6 100644 --- a/lists.scad +++ b/lists.scad @@ -304,7 +304,7 @@ function last(list) = // Example: // hlist1 = list_head(["foo", "bar", "baz"]); // Returns: ["foo", "bar"] // hlist2 = list_head(["foo", "bar", "baz"], -3); // Returns: ["foo"] -// hlist3 = list_head(["foo", "bar", "baz"], 2); // Returns: ["foo","bar"] +// hlist3 = list_head(["foo", "bar", "baz"], 1); // Returns: ["foo","bar"] // hlist4 = list_head(["foo", "bar", "baz"], -5); // Returns: [] // hlist5 = list_head(["foo", "bar", "baz"], 5); // Returns: ["foo","bar","baz"] function list_head(list, to=-2) = diff --git a/tutorials/Transforms.md b/tutorials/Transforms.md index 142d385..3d1a882 100644 --- a/tutorials/Transforms.md +++ b/tutorials/Transforms.md @@ -219,8 +219,9 @@ color("blue",0.25) down(20) cube([40,40,0.1], center=true); ``` -## Skewing -One transform that OpenSCAD does not perform natively is skewing. +## Skewing / Shearing +One transform that OpenSCAD does not perform natively is skewing, also +known as shearing. BOSL2 provides the `skew()` command for that. You give it multipliers for the skews you want to perform. The arguments used all start with `s`, followed by the axis you want to skew along, followed by the axis that