From be998746e6af5e2db1eec18102c8651bdbcd5aef Mon Sep 17 00:00:00 2001 From: Adrian Mariano Date: Fri, 3 Feb 2023 16:36:40 -0500 Subject: [PATCH 1/4] trapezoid fix --- shapes2d.scad | 73 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 44 insertions(+), 29 deletions(-) diff --git a/shapes2d.scad b/shapes2d.scad index 6b16fd8..d7715fb 100644 --- a/shapes2d.scad +++ b/shapes2d.scad @@ -845,24 +845,26 @@ module right_triangle(size=[1,1], center, anchor, spin=0) { // Function&Module: trapezoid() // Usage: As Module -// trapezoid(h, w1, w2, [shift=], [rounding=], [chamfer=], ...) [ATTACHMENTS]; -// trapezoid(h, w1, angle=, ...) [ATTACHMENTS]; -// trapezoid(h, w2, angle=, ...) [ATTACHMENTS]; -// trapezoid(w1, w2, angle=, ...) [ATTACHMENTS]; +// trapezoid(h, w1, w2, [shift=], [rounding=], [chamfer=], [flip=], ...) [ATTACHMENTS]; +// trapezoid(h, w1, ang=, [rounding=], [chamfer=], [flip=], ...) [ATTACHMENTS]; +// trapezoid(h, w2=, ang=, [rounding=], [chamfer=], [flip=], ...) [ATTACHMENTS]; +// trapezoid(w1=, w2=, ang=, [rounding=], [chamfer=], [flip=], ...) [ATTACHMENTS]; // Usage: As Function // path = trapezoid(...); // Topics: Shapes (2D), Paths (2D), Path Generators, Attachable // See Also: rect(), square() // Description: -// When called as a function, returns a 2D path for a trapezoid with parallel front and back sides. -// When called as a module, creates a 2D trapezoid with parallel front and back sides. +// When called as a function, returns a 2D path for a trapezoid with parallel front and back (top and bottom) sides. +// When called as a module, creates a 2D trapezoid. You can specify the trapezoid by giving its height and the lengths +// of its two bases. Alternatively, you can omit one of those parameters and specify the lower angle(s). +// The shift parameter, which cannot be combined with ang, shifts the back (top) of the trapezoid to the right. // Arguments: // h = The Y axis height of the trapezoid. // w1 = The X axis width of the front end of the trapezoid. // w2 = The X axis width of the back end of the trapezoid. // --- -// angle = If given in place of `h`, `w1`, or `w2`, then the missing value is calculated such that the right side has that angle away from the Y axis. -// shift = Scalar value to shift the back of the trapezoid along the X axis by. Default: 0 +// ang = Specify the bottom angle(s) of the trapezoid. Can give a scalar for an isosceles trapezoid or a list of two angles, the left angle and right angle. You must omit one of `h`, `w1`, or `w2` to allow the freedom to control the angles. +// shift = Scalar value to shift the back of the trapezoid along the X axis by. Cannot be combined with ang. Default: 0 // rounding = The rounding radius for the corners. If given as a list of four numbers, gives individual radii for each corner, in the order [X+Y+,X-Y+,X-Y-,X+Y-]. Default: 0 (no rounding) // chamfer = The Length of the chamfer faces at the corners. If given as a list of four numbers, gives individual chamfers for each corner, in the order [X+Y+,X-Y+,X-Y-,X+Y-]. Default: 0 (no chamfer) // flip = If true, negative roundings and chamfers will point forward and back instead of left and right. Default: `false`. @@ -872,11 +874,11 @@ module right_triangle(size=[1,1], center, anchor, spin=0) { // trapezoid(h=30, w1=40, w2=20); // trapezoid(h=25, w1=20, w2=35); // trapezoid(h=20, w1=40, w2=0); -// trapezoid(h=20, w1=30, angle=30); -// trapezoid(h=20, w1=20, angle=-30); -// trapezoid(h=20, w2=10, angle=30); -// trapezoid(h=20, w2=30, angle=-30); -// trapezoid(w1=30, w2=10, angle=30); +// trapezoid(h=20, w1=30, ang=60); +// trapezoid(h=20, w1=20, ang=120); +// trapezoid(h=20, w2=10, ang=60); +// trapezoid(h=20, w1=40, ang=[40,50]); +// trapezoid(w1=30, w2=10, ang=[30,90]); // Example(2D): Chamfered Trapezoid // trapezoid(h=30, w1=60, w2=40, chamfer=5); // Example(2D): Negative Chamfered Trapezoid @@ -893,20 +895,30 @@ module right_triangle(size=[1,1], center, anchor, spin=0) { // trapezoid(h=30, w1=60, w2=40, rounding=[5,0,-10,0],chamfer=[0,8,0,-15],$fa=1,$fs=1); // Example(2D): Called as Function // stroke(closed=true, trapezoid(h=30, w1=40, w2=20)); -function trapezoid(h, w1, w2, angle, shift=0, chamfer=0, rounding=0, flip=false, anchor=CENTER, spin=0) = +function trapezoid(h, w1, w2, ang, shift, chamfer=0, rounding=0, flip=false, anchor=CENTER, spin=0, angle) = + assert(is_undef(angle), "The angle parameter has been replaced by ang, which specifies trapezoid interior angle") assert(is_undef(h) || is_finite(h)) assert(is_undef(w1) || is_finite(w1)) assert(is_undef(w2) || is_finite(w2)) - assert(is_undef(angle) || is_finite(angle)) - assert(num_defined([h, w1, w2, angle]) == 3, "Must give exactly 3 of the arguments h, w1, w2, and angle.") - assert(is_finite(shift)) + assert(is_undef(ang) || is_finite(ang) || is_vector(ang,2)) + assert(num_defined([h, w1, w2, ang]) == 3, "Must give exactly 3 of the arguments h, w1, w2, and angle.") + assert(is_undef(shift) || is_finite(shift)) + assert(num_defined([shift,ang])<2, "Cannot specify shift and ang together") assert(is_finite(chamfer) || is_vector(chamfer,4)) assert(is_finite(rounding) || is_vector(rounding,4)) + let( + ang = force_list(ang,2), + angOK = ang==[undef,undef] || (all_positive(ang) && ang[0]<180 && ang[1]<180) + ) + assert(angOK, "trapezoid angles must be strictly between 0 and 180") let( simple = chamfer==0 && rounding==0, - h = !is_undef(h)? h : opp_ang_to_adj(abs(w2-w1)/2, abs(angle)), - w1 = !is_undef(w1)? w1 : w2 + 2*(adj_ang_to_opp(h, angle) + shift), - w2 = !is_undef(w2)? w2 : w1 - 2*(adj_ang_to_opp(h, angle) + shift), + h = is_def(h)? h : (w1-w2) * sin(ang[0]) * sin(ang[1]) / sin(ang[0]+ang[1]), + x1 = is_undef(ang[0]) || ang[0]==90 ? 0 : h/tan(ang[0]), + x2 = is_undef(ang[1]) || ang[1]==90 ? 0 : h/tan(ang[1]), + w1 = is_def(w1)? w1 : w2 + x1 + x2, + w2 = is_def(w2)? w2 : w1 - x1 - x2, + shift = first_defined([shift,(x1-x2)/2]), chamfs = is_num(chamfer)? [for (i=[0:3]) chamfer] : assert(len(chamfer)==4) chamfer, rounds = is_num(rounding)? [for (i=[0:3]) rounding] : @@ -966,19 +978,23 @@ function trapezoid(h, w1, w2, angle, shift=0, chamfer=0, rounding=0, flip=false, ), ], path = reverse(cpath) - ) simple + ) true //simple // force regular anchoring ? reorient(anchor,spin, two_d=true, size=[w1,h], size2=w2, shift=shift, p=path) : reorient(anchor,spin, two_d=true, path=path, p=path); -module trapezoid(h, w1, w2, angle, shift=0, chamfer=0, rounding=0, flip=false, anchor=CENTER, spin=0) { - path = trapezoid(h=h, w1=w1, w2=w2, angle=angle, shift=shift, chamfer=chamfer, rounding=rounding, flip=flip); +module trapezoid(h, w1, w2, ang, shift, chamfer=0, rounding=0, flip=false, anchor=CENTER, spin=0, angle) { + path = trapezoid(h=h, w1=w1, w2=w2, ang=ang, shift=shift, chamfer=chamfer, rounding=rounding, flip=flip, angle=angle); union() { - simple = chamfer==0 && rounding==0; - h = !is_undef(h)? h : opp_ang_to_adj(abs(w2-w1)/2, abs(angle)); - w1 = !is_undef(w1)? w1 : w2 + 2*(adj_ang_to_opp(h, angle) + shift); - w2 = !is_undef(w2)? w2 : w1 - 2*(adj_ang_to_opp(h, angle) + shift); + simple = true; //chamfer==0 && rounding==0; // force "normal" anchoring for now + ang = force_list(ang,2); + h = is_def(h)? h : (w1-w2) * sin(ang[0]) * sin(ang[1]) / sin(ang[0]+ang[1]); + x1 = is_undef(ang[0]) || ang[0]==90 ? 0 : h/tan(ang[0]); + x2 = is_undef(ang[1]) || ang[1]==90 ? 0 : h/tan(ang[1]); + w1 = is_def(w1)? w1 : w2 + x1 + x2; + w2 = is_def(w2)? w2 : w1 - x1 - x2; + shift = first_defined([shift,(x1-x2)/2]); if (simple) { attachable(anchor,spin, two_d=true, size=[w1,h], size2=w2, shift=shift) { polygon(path); @@ -1275,8 +1291,7 @@ function teardrop2d(r, ang=45, cap_h, d, circum=false, realign=false, anchor=CEN if (p) [i,p] ], i = last(isect)[0], - p = last(isect)[1], - ff=echo(isect) + p = last(isect)[1] ) [ cap[0], From b81c3638d58fb31486960826cdd90e95a7250c71 Mon Sep 17 00:00:00 2001 From: Adrian Mariano Date: Fri, 3 Feb 2023 17:17:24 -0500 Subject: [PATCH 2/4] add min_area to vnf_vertex_array --- vnf.scad | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/vnf.scad b/vnf.scad index 1f34297..c7cfd15 100644 --- a/vnf.scad +++ b/vnf.scad @@ -131,7 +131,7 @@ function vnf_vertex_array( ) = assert(!(any([caps,cap1,cap2]) && !col_wrap), "col_wrap must be true if caps are requested") assert(!(any([caps,cap1,cap2]) && row_wrap), "Cannot combine caps with row_wrap") - assert(in_list(style,["default","alt","quincunx", "convex","concave", "min_edge"])) + assert(in_list(style,["default","alt","quincunx", "convex","concave", "min_edge","min_area"])) assert(is_matrix(points[0], n=3),"Point array has the wrong shape or points are not 3d") assert(is_consistent(points), "Non-rectangular or invalid point array") let( @@ -174,6 +174,15 @@ function vnf_vertex_array( [[i1,i5,i2],[i2,i5,i3],[i3,i5,i4],[i4,i5,i1]] : style=="alt"? [[i1,i4,i2],[i2,i4,i3]] + : style=="min_area"? + let( + area42 = norm(cross(pts[i2]-pts[i1], pts[14]-pts[i1]))+norm(cross(pts[i4]-pts[i3], pts[i2]-pts[i3])), + area13 = norm(cross(pts[i1]-pts[i4], pts[i3]-pts[i4]))+norm(cross(pts[i3]-pts[i2], pts[i1]-pts[i2])), + minarea_edge = area42 < area13 + EPSILON + ? [[i1,i4,i2],[i2,i4,i3]] + : [[i1,i3,i2],[i1,i4,i3]] + ) + minarea_edge : style=="min_edge"? let( d42=norm(pts[i4]-pts[i2]), From 711050e605afd1917401ea8ff0401e3f321e675f Mon Sep 17 00:00:00 2001 From: Adrian Mariano Date: Fri, 3 Feb 2023 17:17:38 -0500 Subject: [PATCH 3/4] fix doc typo in skin, fix first section docs in distributors --- distributors.scad | 38 +++++++++++++++++++++++++++++++++----- skin.scad | 4 ++-- 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/distributors.scad b/distributors.scad index e4191d7..627d98b 100644 --- a/distributors.scad +++ b/distributors.scad @@ -28,20 +28,38 @@ // parent. This means that `$` variables like `$idx` are not available in assignments, so if you use them you will get a warning about an unknown variable. // Two workarounds exist, neither of which are needed in newer versions of OpenSCAD. The workarounds solve the problem because // **modules** execute after their parent, so the `$` variables **are** available in modules. You can put your assignments -// in a `let()` module, or you can wrap your child in a `union()`. Both methods appear below in the examples. -// Example(2D): This example shows how we can use `$idx` to produce **different** geometry at each index. +// in a `let()` module, or you can wrap your child in a `union()`. Both methods appear below. +// ``` // xcopies(n=10, spacing=10) // text(str($idx)); -// Example(2D): Here the children are sometimes squares and sometimes circles as determined by the conditional `if` module. This use of `if` is OK because no variables are assigned. +// ``` +// Figure(2D): This example shows how we can use `$idx` to produce **different** geometry at each index. +// xcopies(n=10, spacing=10) +// text(str($idx)); +// Continues: +// Figure(2D): Here the children are sometimes squares and sometimes circles as determined by the conditional `if` module. This use of `if` is OK because no variables are assigned. // xcopies(n=4, spacing=10) // if($idx%2==0) circle(r=3,$fn=16); // else rect(6); -// Example(2D): Suppose we would like to color odd and even index copies differently. In this example we compute the color for a given child from `$idx` using the ternary operator. The `let()` module is a module that sets variables and makes them available to its children. Note that multiple assignments in `let()` are separated by commas, not semicolons. +// Continues: +// ``` +// xcopies(n=4, spacing=10) +// if($idx%2==0) circle(r=3,$fn=16); +// else rect(6); +// ``` +// Figure(2D): Suppose we would like to color odd and even index copies differently. In this example we compute the color for a given child from `$idx` using the ternary operator. The `let()` module is a module that sets variables and makes them available to its children. Note that multiple assignments in `let()` are separated by commas, not semicolons. // xcopies(n=6, spacing=10){ // let(c = $idx % 2 == 0 ? "red" : "green") // color(c) rect(6); // } -// Example(2D): This example shows how you can change the position of children adaptively. If you want to avoid repeating your code for each case, this requires storing a transformation matrix in a variable and then applying it using `multmatrix()`. We wrap our code in `union()` to ensure that it works in OpenSCAD 2021.01. +// Continues: +// ``` +// xcopies(n=6, spacing=10){ +// let(c = $idx % 2 == 0 ? "red" : "green") +// color(c) rect(6); +// } +// ``` +// Figure(2D): This example shows how you can change the position of children adaptively. If you want to avoid repeating your code for each case, this requires storing a transformation matrix in a variable and then applying it using `multmatrix()`. We wrap our code in `union()` to ensure that it works in OpenSCAD 2021.01. // xcopies(n=5,spacing=10) // union() // { @@ -49,6 +67,16 @@ // spin = zrot(180*$idx/4); // multmatrix(shiftback*spin) stroke([[-4,0],[4,0]],endcap2="arrow2",width=1/2); // } +// Continues: +// ``` +// xcopies(n=5,spacing=10) +// union() +// { +// shiftback = $idx%2==0 ? back(5) : IDENT; +// spin = zrot(180*$idx/4); +// multmatrix(shiftback*spin) stroke([[-4,0],[4,0]],endcap2="arrow2",width=1/2); +// } +// ``` ////////////////////////////////////////////////////////////////////// diff --git a/skin.scad b/skin.scad index 1e7c8b6..91600f8 100644 --- a/skin.scad +++ b/skin.scad @@ -1064,8 +1064,8 @@ module rotate_sweep( // turns = number of revolutions to spiral up along the height. // --- // d = Diameter of the spiral to extrude along. -// d1|r1 = Bottom inside diameter or radius of spiral to extrude along. -// d2|r2 = Top inside diameter or radius of spiral to extrude along. +// d1/r1 = Bottom inside diameter or radius of spiral to extrude along. +// d2/r2 = Top inside diameter or radius of spiral to extrude along. // taper = Length of tapers for thread ends. Positive to add taper to threads, negative to taper within specified length. Default: 0 // taper1 = Length of taper for bottom thread end // taper2 = Length of taper for top thread end From 4a9ab3b18bf96ca20f562d4f4389592761267dcc Mon Sep 17 00:00:00 2001 From: Adrian Mariano Date: Fri, 3 Feb 2023 17:27:44 -0500 Subject: [PATCH 4/4] doc fix --- shapes2d.scad | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shapes2d.scad b/shapes2d.scad index d7715fb..77d8116 100644 --- a/shapes2d.scad +++ b/shapes2d.scad @@ -877,7 +877,7 @@ module right_triangle(size=[1,1], center, anchor, spin=0) { // trapezoid(h=20, w1=30, ang=60); // trapezoid(h=20, w1=20, ang=120); // trapezoid(h=20, w2=10, ang=60); -// trapezoid(h=20, w1=40, ang=[40,50]); +// trapezoid(h=20, w1=50, ang=[40,60]); // trapezoid(w1=30, w2=10, ang=[30,90]); // Example(2D): Chamfered Trapezoid // trapezoid(h=30, w1=60, w2=40, chamfer=5);