From a246027a68e35c6aa54a9cfd414c7ce7b68337a1 Mon Sep 17 00:00:00 2001 From: Adrian Mariano Date: Sat, 24 Feb 2024 21:56:11 -0500 Subject: [PATCH 1/8] fix example by adding $fn --- rounding.scad | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rounding.scad b/rounding.scad index f4c68cb..9468502 100644 --- a/rounding.scad +++ b/rounding.scad @@ -956,12 +956,12 @@ function _path_join(paths,joint,k=0.5,i=0,result=[],relocate=true,closed=false) // path = [[0,0],[6,2],[9,7],[8,10]]; // xdistribute(spacing=10){ // offset_stroke(path, width = 2); -// offset_stroke(path, start="round", end="round", width = 2); +// offset_stroke(path, start="round", end="round", width = 2, $fn=32); // offset_stroke(path, start="pointed", end="pointed", width = 2); // } // fwd(10) xdistribute(spacing=10){ // offset_stroke(arc, width = 2); -// offset_stroke(arc, start="round", end="round", width = 2); +// offset_stroke(arc, start="round", end="round", width = 2, $fn=32); // offset_stroke(arc, start="pointed", end="pointed", width = 2); // } // Example(2D): The effect of the `rounded` and `chamfer` options is most evident at sharp corners. This only affects the middle of the path, not the ends. From 5034c6667a879bd61e6b08a6552a72530f7a7c9e Mon Sep 17 00:00:00 2001 From: Adrian Mariano Date: Sat, 24 Feb 2024 21:56:26 -0500 Subject: [PATCH 2/8] Add end anchors to path_sweep --- attachments.scad | 92 +++++++++++++++++++++++++++++++----------------- skin.scad | 56 +++++++++++++++++++++++------ 2 files changed, 106 insertions(+), 42 deletions(-) diff --git a/attachments.scad b/attachments.scad index 33e1aac..dbb6dc6 100644 --- a/attachments.scad +++ b/attachments.scad @@ -2774,6 +2774,41 @@ function reorient( function named_anchor(name, pos, orient=UP, spin=0) = [name, pos, orient, spin]; +function _force_rot(T) = + [for(i=[0:3]) + [for(j=[0:3]) j<3 ? T[i][j] : + i==3 ? 1 + : 0]]; + +// Function: transform_anchor() +// Synopsis: Creates an anchor data structure from a transformation matrix +// Topics: Attachments +// See Also: reorient(), attachable() +// Usage: +// a = transform_anchor(name, transform, [flip]); +// Description: +// Creates an anchor data structure from a transformation matrix. For a step-by-step explanation of attachments, +// see the [Attachments Tutorial](Tutorial-Attachments). +// Arguments: +// name = The string name of the anchor. Lowercase. Words separated by single dashes. No spaces. +// transform = A rotation matrix (which may include translation) +// flip = If true, flip the anchor the opposite direction. Default: false + +function transform_anchor(name, transform, flip=false) = + let( + pos = apply(transform,CTR), + rotpart = _force_rot(transform), + dir = flip ? apply(rotpart,DOWN) + : apply(rotpart,UP), + transform = flip? affine3d_rot_by_axis(apply(rotpart,BACK),180)*transform + : transform, + decode=rot_decode(rot(to=UP,from=dir)*_force_rot(transform)), + spin = decode[0]*sign(decode[1].z) + ) + [name, pos,dir,spin]; + + + // Function: attach_geom() // Synopsis: Returns the internal geometry description of an attachable object. // Topics: Attachments @@ -3201,7 +3236,6 @@ function _attach_transform(anchor, spin, orient, geom, p) = assert(is_undef(orient) || is_vector(orient,3), str("Got: ",orient)) let( anchor = default(anchor, CENTER), - spin = default(spin, 0), orient = default(orient, UP), two_d = _attach_geom_2d(geom), @@ -3209,12 +3243,13 @@ function _attach_transform(anchor, spin, orient, geom, p) = let( anch = _find_anchor($attach_to, geom), pos = anch[1] - ) two_d? ( - assert(two_d && is_num(spin)) - affine3d_zrot(spin) * - rot(to=FWD, from=point3d(anch[2])) * - affine3d_translate(point3d(-pos)) - ) : ( + ) + two_d? + assert(is_num(spin)) + affine3d_zrot(spin) + * rot(to=FWD, from=point3d(anch[2])) + * affine3d_translate(point3d(-pos)) + : assert(is_num(spin) || is_vector(spin,3)) let( ang = vector_angle(anch[2], DOWN), @@ -3222,40 +3257,33 @@ function _attach_transform(anchor, spin, orient, geom, p) = ang2 = (anch[2]==UP || anch[2]==DOWN)? 0 : 180-anch[3], axis2 = rot(p=axis,[0,0,ang2]) ) - affine3d_rot_by_axis(axis2,ang) * ( - is_num(spin)? affine3d_zrot(ang2+spin) : ( - affine3d_zrot(spin.z) * - affine3d_yrot(spin.y) * - affine3d_xrot(spin.x) * - affine3d_zrot(ang2) - ) - ) * affine3d_translate(point3d(-pos)) - ) + affine3d_rot_by_axis(axis2,ang) + * (is_num(spin)? affine3d_zrot(ang2+spin) + : affine3d_zrot(spin.z) * affine3d_yrot(spin.y) * affine3d_xrot(spin.x) + * affine3d_zrot(ang2)) + * affine3d_translate(point3d(-pos)) ) : ( let( pos = _find_anchor(anchor, geom)[1] - ) two_d? ( - assert(two_d && is_num(spin)) - affine3d_zrot(spin) * - affine3d_translate(point3d(-pos)) - ) : ( + ) + two_d? + assert(is_num(spin)) + affine3d_zrot(spin) * affine3d_translate(point3d(-pos)) + : assert(is_num(spin) || is_vector(spin,3)) let( axis = vector_axis(UP,orient), 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_translate(point3d(-pos)) - ) + 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_translate(point3d(-pos)) ) - ) is_undef(p)? m : - is_vnf(p)? [(p==EMPTY_VNF? p : apply(m, p[0])), p[1]] : - apply(m, p); + ) + is_undef(p)? m + : is_vnf(p) && p==EMPTY_VNF? p + : apply(m, p); function _get_cp(geom) = diff --git a/skin.scad b/skin.scad index cb08842..2464251 100644 --- a/skin.scad +++ b/skin.scad @@ -1481,6 +1481,11 @@ module spiral_sweep(poly, h, r, turns=1, taper, r1, r2, d, d1, d2, internal=fals // Anchor Types: // "hull" = Anchors to the virtual convex hull of the shape. // "intersect" = Anchors to the surface of the shape. +// Extra Anchors: +// start = When `closed==false`, the origin point of the shape, on the starting face of the object +// end = When `closed==false`, the origin point of the shape, on the ending face of the object +// start-centroid = When `closed==false`, the centroid of the shape, on the starting face of the object +// end-centroid = When `closed==false`, the centroid of the shape, on the ending face of the object // Example(NoScales): A simple sweep of a square along a sine wave: // path = [for(theta=[-180:5:180]) [theta/10, 10*sin(theta)]]; // sq = square(6,center=true); @@ -1755,29 +1760,60 @@ module spiral_sweep(poly, h, r, turns=1, taper, r1, r2, d, d1, d2, internal=fals // path_sweep(left(.05,square([1.1,1])), curve, closed=true, // method="manual", normal=UP); // } +// Example(Med,NoScales,VPR=[78.1,0,43.2],VPT=[2.18042,-0.485127,1.90371],VPD=74.4017): The "start" and "end" anchors are located at the origin point of the swept shape. +// shape = back_half(right_half(star(n=5,id=5,od=10)),y=-1); +// path = arc(angle=[0,180],d=30); +// path_sweep(shape,path,method="natural"){ +// attach(["start","end"]) anchor_arrow(s=5); +// } +// Example(Med,NoScales,VPR=[78.1,0,43.2],VPT=[2.18042,-0.485127,1.90371],VPD=74.4017): The "start" and "end" anchors are located at the origin point of the swept shape. +// shape = back_half(right_half(star(n=5,id=5,od=10)),y=-1); +// path = arc(angle=[0,180],d=30); +// path_sweep(shape,path,method="natural"){ +// attach(["start-centroid","end-centroid"]) anchor_arrow(s=5); +// } +// Example(Med,NoScales,VPR=[78.1,0,43.2],VPT=[2.18042,-0.485127,1.90371],VPD=74.4017): Note that the "start" anchors are backwards compared to the direction of the sweep, so you have to attach the TOP to align the shape with its ends. +// shape = back_half(right_half(star(n=5,id=5,od=10)),y=-1); +// path = arc(angle=[0,180],d=30); +// path_sweep(shape,path,method="natural") +// recolor("red"){ +// attach("start",TOP) stroke([path3d(shape[0])],width=.5); +// attach("end") stroke([path3d(last(shape))],width=.5); +// } + module path_sweep(shape, path, method="incremental", normal, closed, twist=0, twist_by_length=true, scale=1, scale_by_length=true, symmetry=1, last_normal, tangent, uniform=true, relaxed=false, caps, style="min_edge", convexity=10, anchor="origin",cp="centroid",spin=0, orient=UP, atype="hull",profiles=false,width=1) { - dummy = assert(is_region(shape) || is_path(shape,2), "shape must be a 2D path or region"); - vnf = path_sweep(shape, path, method, normal, closed, twist, twist_by_length, scale, scale_by_length, - symmetry, last_normal, tangent, uniform, relaxed, caps, style); - + dummy = assert(is_region(shape) || is_path(shape,2), "shape must be a 2D path or region") + assert(in_list(atype, _ANCHOR_TYPES), "Anchor type must be \"hull\" or \"intersect\""); + transforms = path_sweep(shape, path, method, normal, closed, twist, twist_by_length, scale, scale_by_length, + symmetry, last_normal, tangent, uniform, relaxed, caps, style, transforms=true); + vnf = sweep(is_path(shape)?clockwise_polygon(shape):shape, transforms, closed=false, caps=caps,style=style); + shapecent = point3d(centroid(shape)); + $transforms = transforms; + anchors = closed ? [] + : + [ + transform_anchor("start", transforms[0], invert=true), + transform_anchor("end", last(transforms)), + transform_anchor("start-centroid", transforms[0]*move(shapecent), invert=true), + transform_anchor("end-centroid", last(transforms)*move(shapecent)) + ]; if (profiles){ - assert(in_list(atype, _ANCHOR_TYPES), "Anchor type must be \"hull\" or \"intersect\""); - tran = path_sweep(shape, path, method, normal, closed, twist, twist_by_length, scale, scale_by_length, - symmetry, last_normal, tangent, uniform, relaxed,transforms=true); rshape = is_path(shape) ? [path3d(shape)] : [for(s=shape) path3d(s)]; - attachable(anchor,spin,orient, vnf=vnf, extent=atype=="hull", cp=cp) { - for(T=tran) stroke([for(part=rshape)apply(T,part)],width=width); + attachable(anchor,spin,orient, vnf=vnf, extent=atype=="hull", cp=cp, anchors=anchors) { + for(T=transforms) stroke([for(part=rshape)apply(T,part)],width=width); children(); } } else - vnf_polyhedron(vnf,convexity=convexity,anchor=anchor, spin=spin, orient=orient, atype=atype, cp=cp) + attachable(anchor,spin,orient,vnf=vnf,extent=atype=="hull", cp=cp,anchors=anchors){ + vnf_polyhedron(vnf,convexity=convexity); children(); + } } From b01d1edc1bb087102a15b840afed3fc73d2066ca Mon Sep 17 00:00:00 2001 From: Adrian Mariano Date: Sat, 24 Feb 2024 22:20:44 -0500 Subject: [PATCH 3/8] bugfix --- skin.scad | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/skin.scad b/skin.scad index 2464251..5888521 100644 --- a/skin.scad +++ b/skin.scad @@ -1796,9 +1796,9 @@ module path_sweep(shape, path, method="incremental", normal, closed, twist=0, tw anchors = closed ? [] : [ - transform_anchor("start", transforms[0], invert=true), + transform_anchor("start", transforms[0], flip=true), transform_anchor("end", last(transforms)), - transform_anchor("start-centroid", transforms[0]*move(shapecent), invert=true), + transform_anchor("start-centroid", transforms[0]*move(shapecent), flip=true), transform_anchor("end-centroid", last(transforms)*move(shapecent)) ]; if (profiles){ From aa8dc7ce25f96bbf1e4e4fdcd95aafb7eb67afbe Mon Sep 17 00:00:00 2001 From: Adrian Mariano Date: Sat, 24 Feb 2024 22:32:25 -0500 Subject: [PATCH 4/8] add pass-through tag example to Attachments tutorial --- tutorials/Attachments.md | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/tutorials/Attachments.md b/tutorials/Attachments.md index 9efa7c5..3bcb102 100644 --- a/tutorials/Attachments.md +++ b/tutorials/Attachments.md @@ -1242,7 +1242,36 @@ create using `linear_extrude()` or `rotate_extrude()`. To make a shape attachable, you just need to wrap it with an `attachable()` module with a basic description of the shape's geometry. By default, the shape is expected to be centered at the origin. The `attachable()` module expects exactly two children. The first will be -the shape to make attachable, and the second will be `children()`, literally. +the shape to make attachable, and the second will be `children()`, +literally. + +### Pass-through Attachables +The simplest way to make your own attachable module is to simply pass +through to a pre-existing attachable submodule. This could be +appropriate if you want to rename a module, or if the anchors of an +existing module are suited to (or good enough for) your object. In +order for your attachable module to work properly you need to accept +the `anchor`, `spin` and `orient` parameters, give them suitable +defaults, and pass them to the attachable submodule. Don't forget to +pass the children to the attachable submodule as well, or your new +module will ignore its children. + +```openscad-3D +include +module cutcube(anchor=CENTER,spin=0,orient=UP) +{ + tag_scope(){ + diff() + cuboid(15, rounding=2, anchor=anchor,spin=spin,orient=orient){ + tag("remove")attach(TOP)cuboid(5); + children(); + } + } +} +diff() +cutcube() + tag("remove")attach(RIGHT) cyl(d=2,h=8); +``` ### Prismoidal/Cuboidal Attachables To make a cuboidal or prismoidal shape attachable, you use the `size`, `size2`, and `offset` From 097cace9cdc765b897777c7f5f993513eabe0178 Mon Sep 17 00:00:00 2001 From: Adrian Mariano Date: Sat, 24 Feb 2024 22:36:10 -0500 Subject: [PATCH 5/8] document $transforms --- skin.scad | 2 ++ 1 file changed, 2 insertions(+) diff --git a/skin.scad b/skin.scad index 5888521..0a9afc3 100644 --- a/skin.scad +++ b/skin.scad @@ -1478,6 +1478,8 @@ module spiral_sweep(poly, h, r, turns=1, taper, r1, r2, d, d1, d2, internal=fals // orient = Vector to rotate top towards after spin // atype = Select "hull" or "intersect" anchor types. Default: "hull" // cp = Centerpoint for determining "intersect" anchors or centering the shape. Determintes the base of the anchor vector. Can be "centroid", "mean", "box" or a 3D point. Default: "centroid" +// Side Effects: +// `$transforms` is set to the array of transformation matrices that define the swept object. // Anchor Types: // "hull" = Anchors to the virtual convex hull of the shape. // "intersect" = Anchors to the surface of the shape. From 392b67c9c809c5c449321e41c69ee8148c9354bf Mon Sep 17 00:00:00 2001 From: Adrian Mariano Date: Sun, 25 Feb 2024 09:49:43 -0500 Subject: [PATCH 6/8] merge transform_anchor into named anchor; make path_sweep anchors work with scaling. --- attachments.scad | 59 ++++++++++++++++++++++-------------------------- skin.scad | 38 +++++++++++++++++++------------ 2 files changed, 50 insertions(+), 47 deletions(-) diff --git a/attachments.scad b/attachments.scad index dbb6dc6..34e45e5 100644 --- a/attachments.scad +++ b/attachments.scad @@ -2763,16 +2763,40 @@ function reorient( // See Also: reorient(), attachable() // Usage: // a = named_anchor(name, pos, [orient], [spin]); +// a = named_anchor(name, [pos], rot=, [flip=]); // Description: -// Creates an anchor data structure. For a step-by-step explanation of attachments, +// Creates an anchor data structure. You can specify the position, orient direction and spin directly. +// Alternatively for the 3D case you can give a 4x4 rotation matrix which can specify the orient and spin, and optionally +// the position, using a translation component of the matrix. If you specify `pos` along with `rot` then the position you +// give overrides any translation included in `rot`. For a step-by-step explanation of attachments, // see the [Attachments Tutorial](Tutorial-Attachments). // Arguments: // name = The string name of the anchor. Lowercase. Words separated by single dashes. No spaces. // pos = The [X,Y,Z] position of the anchor. // orient = A vector pointing in the direction parts should project from the anchor position. Default: UP // spin = If needed, the angle to rotate the part around the direction vector. Default: 0 -function named_anchor(name, pos, orient=UP, spin=0) = [name, pos, orient, spin]; - +// --- +// 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) = + 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") + is_undef(rot) ? [name, pos, default(orient,UP), default(spin,0)] + : + 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"), + dir = flip ? apply(rotpart,DOWN) + : apply(rotpart,UP), + rot = flip? affine3d_rot_by_axis(apply(rotpart,BACK),180)*rot + : rot, + decode=rot_decode(rot(to=UP,from=dir)*_force_rot(rot)), + spin = decode[0]*sign(decode[1].z) + ) + [name, pos, dir, spin]; + function _force_rot(T) = [for(i=[0:3]) @@ -2780,35 +2804,6 @@ function _force_rot(T) = i==3 ? 1 : 0]]; -// Function: transform_anchor() -// Synopsis: Creates an anchor data structure from a transformation matrix -// Topics: Attachments -// See Also: reorient(), attachable() -// Usage: -// a = transform_anchor(name, transform, [flip]); -// Description: -// Creates an anchor data structure from a transformation matrix. For a step-by-step explanation of attachments, -// see the [Attachments Tutorial](Tutorial-Attachments). -// Arguments: -// name = The string name of the anchor. Lowercase. Words separated by single dashes. No spaces. -// transform = A rotation matrix (which may include translation) -// flip = If true, flip the anchor the opposite direction. Default: false - -function transform_anchor(name, transform, flip=false) = - let( - pos = apply(transform,CTR), - rotpart = _force_rot(transform), - dir = flip ? apply(rotpart,DOWN) - : apply(rotpart,UP), - transform = flip? affine3d_rot_by_axis(apply(rotpart,BACK),180)*transform - : transform, - decode=rot_decode(rot(to=UP,from=dir)*_force_rot(transform)), - spin = decode[0]*sign(decode[1].z) - ) - [name, pos,dir,spin]; - - - // Function: attach_geom() // Synopsis: Returns the internal geometry description of an attachable object. // Topics: Attachments diff --git a/skin.scad b/skin.scad index 0a9afc3..70ce9c4 100644 --- a/skin.scad +++ b/skin.scad @@ -1479,7 +1479,8 @@ module spiral_sweep(poly, h, r, turns=1, taper, r1, r2, d, d1, d2, internal=fals // atype = Select "hull" or "intersect" anchor types. Default: "hull" // cp = Centerpoint for determining "intersect" anchors or centering the shape. Determintes the base of the anchor vector. Can be "centroid", "mean", "box" or a 3D point. Default: "centroid" // Side Effects: -// `$transforms` is set to the array of transformation matrices that define the swept object. +// `$transforms` is set to the array of transformation matrices that define the swept object. +// `$scales` is set to the array of scales that were applied at each point to create the swept object. // Anchor Types: // "hull" = Anchors to the virtual convex hull of the shape. // "intersect" = Anchors to the surface of the shape. @@ -1775,33 +1776,38 @@ module spiral_sweep(poly, h, r, turns=1, taper, r1, r2, d, d1, d2, internal=fals // attach(["start-centroid","end-centroid"]) anchor_arrow(s=5); // } // Example(Med,NoScales,VPR=[78.1,0,43.2],VPT=[2.18042,-0.485127,1.90371],VPD=74.4017): Note that the "start" anchors are backwards compared to the direction of the sweep, so you have to attach the TOP to align the shape with its ends. -// shape = back_half(right_half(star(n=5,id=5,od=10)),y=-1); +// shape = back_half(right_half(star(n=5,id=5,od=10)),y=-1)[0]; // path = arc(angle=[0,180],d=30); -// path_sweep(shape,path,method="natural") +// path_sweep(shape,path,method="natural",scale=[1,1.5]) // recolor("red"){ -// attach("start",TOP) stroke([path3d(shape[0])],width=.5); -// attach("end") stroke([path3d(last(shape))],width=.5); +// attach("start",TOP) stroke([path3d(shape)],width=.5); +// attach("end") stroke([path3d(yscale(1.5,shape))],width=.5); // } - module path_sweep(shape, path, method="incremental", normal, closed, twist=0, twist_by_length=true, scale=1, scale_by_length=true, symmetry=1, last_normal, tangent, uniform=true, relaxed=false, caps, style="min_edge", convexity=10, anchor="origin",cp="centroid",spin=0, orient=UP, atype="hull",profiles=false,width=1) { dummy = assert(is_region(shape) || is_path(shape,2), "shape must be a 2D path or region") assert(in_list(atype, _ANCHOR_TYPES), "Anchor type must be \"hull\" or \"intersect\""); - transforms = path_sweep(shape, path, method, normal, closed, twist, twist_by_length, scale, scale_by_length, - symmetry, last_normal, tangent, uniform, relaxed, caps, style, transforms=true); + trans_scale = path_sweep(shape, path, method, normal, closed, twist, twist_by_length, scale, scale_by_length, + symmetry, last_normal, tangent, uniform, relaxed, caps, style, transforms=true,_return_scales=true); + transforms = trans_scale[0]; + scales = trans_scale[1]; + firstscale = [1/scales[0].x, 1/scales[0].y]; + lastscale = [1/last(scales).x, 1/last(scales).y]; + echo(scales=firstscale,lastscale); vnf = sweep(is_path(shape)?clockwise_polygon(shape):shape, transforms, closed=false, caps=caps,style=style); shapecent = point3d(centroid(shape)); $transforms = transforms; + $scales = scales; anchors = closed ? [] : [ - transform_anchor("start", transforms[0], flip=true), - transform_anchor("end", last(transforms)), - transform_anchor("start-centroid", transforms[0]*move(shapecent), flip=true), - transform_anchor("end-centroid", last(transforms)*move(shapecent)) + named_anchor("start", rot=transforms[0]*scale(firstscale), flip=true), + named_anchor("end", rot=last(transforms)*scale(lastscale)), + named_anchor("start-centroid", rot=transforms[0]*move(shapecent)*scale(firstscale), flip=true), + named_anchor("end-centroid", rot=last(transforms)*move(shapecent)*scale(lastscale)) ]; if (profiles){ rshape = is_path(shape) ? [path3d(shape)] @@ -1821,11 +1827,11 @@ module path_sweep(shape, path, method="incremental", normal, closed, twist=0, tw function path_sweep(shape, path, method="incremental", normal, closed, twist=0, twist_by_length=true, scale=1, scale_by_length=true, symmetry=1, last_normal, tangent, uniform=true, relaxed=false, caps, style="min_edge", transforms=false, - anchor="origin",cp="centroid",spin=0, orient=UP, atype="hull") = + anchor="origin",cp="centroid",spin=0, orient=UP, atype="hull",_return_scales=false) = is_1region(path) ? path_sweep(shape=shape,path=path[0], method=method, normal=normal, closed=default(closed,true), twist=twist, scale=scale, scale_by_length=scale_by_length, twist_by_length=twist_by_length, symmetry=symmetry, last_normal=last_normal, tangent=tangent, uniform=uniform, relaxed=relaxed, caps=caps, style=style, transforms=transforms, - anchor=anchor, cp=cp, spin=spin, orient=orient, atype=atype) : + anchor=anchor, cp=cp, spin=spin, orient=orient, atype=atype, _return_scales=_return_scales) : let(closed=default(closed,false)) assert(in_list(atype, _ANCHOR_TYPES), "Anchor type must be \"hull\" or \"intersect\"") assert(!closed || twist % (360/symmetry)==0, str("For a closed sweep, twist must be a multiple of 360/symmetry = ",360/symmetry)) @@ -1977,7 +1983,9 @@ function path_sweep(shape, path, method="incremental", normal, closed, twist=0, apply(transform_list[L], rshape)), dummy = ends_match ? 0 : echo("WARNING: ***** The points do not match when closing the model in path_sweep() *****") ) - transforms ? transform_list + transforms && _return_scales + ? [transform_list,scale] +: transforms ? transform_lislt : sweep(is_path(shape)?clockwise_polygon(shape):shape, transform_list, closed=false, caps=fullcaps,style=style, anchor=anchor,cp=cp,spin=spin,orient=orient,atype=atype); From 5d30951ef14f722a15dcc3432ce7db1fb362c4e6 Mon Sep 17 00:00:00 2001 From: Adrian Mariano Date: Sun, 25 Feb 2024 10:49:56 -0500 Subject: [PATCH 7/8] fix typo --- skin.scad | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/skin.scad b/skin.scad index 70ce9c4..693d1bb 100644 --- a/skin.scad +++ b/skin.scad @@ -1985,7 +1985,7 @@ function path_sweep(shape, path, method="incremental", normal, closed, twist=0, ) transforms && _return_scales ? [transform_list,scale] -: transforms ? transform_lislt +: transforms ? transform_list : sweep(is_path(shape)?clockwise_polygon(shape):shape, transform_list, closed=false, caps=fullcaps,style=style, anchor=anchor,cp=cp,spin=spin,orient=orient,atype=atype); From 3ce62afcd4e5b4cb95078270bea468c2cb1de6c3 Mon Sep 17 00:00:00 2001 From: Adrian Mariano Date: Sun, 25 Feb 2024 12:50:57 -0500 Subject: [PATCH 8/8] handle scalar scale case --- skin.scad | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/skin.scad b/skin.scad index 693d1bb..ca1e3fd 100644 --- a/skin.scad +++ b/skin.scad @@ -1794,9 +1794,8 @@ module path_sweep(shape, path, method="incremental", normal, closed, twist=0, tw symmetry, last_normal, tangent, uniform, relaxed, caps, style, transforms=true,_return_scales=true); transforms = trans_scale[0]; scales = trans_scale[1]; - firstscale = [1/scales[0].x, 1/scales[0].y]; - lastscale = [1/last(scales).x, 1/last(scales).y]; - echo(scales=firstscale,lastscale); + firstscale = is_num(scales[0]) ? 1/scales[0] : [1/scales[0].x, 1/scales[0].y]; + lastscale = is_num(last(scales)) ? 1/last(scales) : [1/last(scales).x, 1/last(scales).y]; vnf = sweep(is_path(shape)?clockwise_polygon(shape):shape, transforms, closed=false, caps=caps,style=style); shapecent = point3d(centroid(shape)); $transforms = transforms;