Merge pull request #1042 from adrianVmariano/master

tapezoid angle fix (angle->ang)
This commit is contained in:
Revar Desmera 2023-02-03 15:08:24 -08:00 committed by GitHub
commit 9e752547d7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 89 additions and 37 deletions

View file

@ -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. // 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 // 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 // **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. // in a `let()` module, or you can wrap your child in a `union()`. Both methods appear below.
// Example(2D): This example shows how we can use `$idx` to produce **different** geometry at each index. // ```
// xcopies(n=10, spacing=10) // xcopies(n=10, spacing=10)
// text(str($idx)); // 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) // xcopies(n=4, spacing=10)
// if($idx%2==0) circle(r=3,$fn=16); // if($idx%2==0) circle(r=3,$fn=16);
// else rect(6); // 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){ // xcopies(n=6, spacing=10){
// let(c = $idx % 2 == 0 ? "red" : "green") // let(c = $idx % 2 == 0 ? "red" : "green")
// color(c) rect(6); // 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) // xcopies(n=5,spacing=10)
// union() // union()
// { // {
@ -49,6 +67,16 @@
// spin = zrot(180*$idx/4); // spin = zrot(180*$idx/4);
// multmatrix(shiftback*spin) stroke([[-4,0],[4,0]],endcap2="arrow2",width=1/2); // 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);
// }
// ```
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////

View file

@ -845,24 +845,26 @@ module right_triangle(size=[1,1], center, anchor, spin=0) {
// Function&Module: trapezoid() // Function&Module: trapezoid()
// Usage: As Module // Usage: As Module
// trapezoid(h, w1, w2, [shift=], [rounding=], [chamfer=], ...) [ATTACHMENTS]; // trapezoid(h, w1, w2, [shift=], [rounding=], [chamfer=], [flip=], ...) [ATTACHMENTS];
// trapezoid(h, w1, angle=, ...) [ATTACHMENTS]; // trapezoid(h, w1, ang=, [rounding=], [chamfer=], [flip=], ...) [ATTACHMENTS];
// trapezoid(h, w2, angle=, ...) [ATTACHMENTS]; // trapezoid(h, w2=, ang=, [rounding=], [chamfer=], [flip=], ...) [ATTACHMENTS];
// trapezoid(w1, w2, angle=, ...) [ATTACHMENTS]; // trapezoid(w1=, w2=, ang=, [rounding=], [chamfer=], [flip=], ...) [ATTACHMENTS];
// Usage: As Function // Usage: As Function
// path = trapezoid(...); // path = trapezoid(...);
// Topics: Shapes (2D), Paths (2D), Path Generators, Attachable // Topics: Shapes (2D), Paths (2D), Path Generators, Attachable
// See Also: rect(), square() // See Also: rect(), square()
// Description: // Description:
// When called as a function, returns a 2D path for a 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 with parallel front and back 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: // Arguments:
// h = The Y axis height of the trapezoid. // h = The Y axis height of the trapezoid.
// w1 = The X axis width of the front end 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. // 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. // 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. Default: 0 // 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) // 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) // 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`. // 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=30, w1=40, w2=20);
// trapezoid(h=25, w1=20, w2=35); // trapezoid(h=25, w1=20, w2=35);
// trapezoid(h=20, w1=40, w2=0); // trapezoid(h=20, w1=40, w2=0);
// trapezoid(h=20, w1=30, angle=30); // trapezoid(h=20, w1=30, ang=60);
// trapezoid(h=20, w1=20, angle=-30); // trapezoid(h=20, w1=20, ang=120);
// trapezoid(h=20, w2=10, angle=30); // trapezoid(h=20, w2=10, ang=60);
// trapezoid(h=20, w2=30, angle=-30); // trapezoid(h=20, w1=50, ang=[40,60]);
// trapezoid(w1=30, w2=10, angle=30); // trapezoid(w1=30, w2=10, ang=[30,90]);
// Example(2D): Chamfered Trapezoid // Example(2D): Chamfered Trapezoid
// trapezoid(h=30, w1=60, w2=40, chamfer=5); // trapezoid(h=30, w1=60, w2=40, chamfer=5);
// Example(2D): Negative Chamfered Trapezoid // 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); // 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 // Example(2D): Called as Function
// stroke(closed=true, trapezoid(h=30, w1=40, w2=20)); // 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(h) || is_finite(h))
assert(is_undef(w1) || is_finite(w1)) assert(is_undef(w1) || is_finite(w1))
assert(is_undef(w2) || is_finite(w2)) assert(is_undef(w2) || is_finite(w2))
assert(is_undef(angle) || is_finite(angle)) assert(is_undef(ang) || is_finite(ang) || is_vector(ang,2))
assert(num_defined([h, w1, w2, angle]) == 3, "Must give exactly 3 of the arguments h, w1, w2, and angle.") assert(num_defined([h, w1, w2, ang]) == 3, "Must give exactly 3 of the arguments h, w1, w2, and angle.")
assert(is_finite(shift)) 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(chamfer) || is_vector(chamfer,4))
assert(is_finite(rounding) || is_vector(rounding,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( let(
simple = chamfer==0 && rounding==0, simple = chamfer==0 && rounding==0,
h = !is_undef(h)? h : opp_ang_to_adj(abs(w2-w1)/2, abs(angle)), h = is_def(h)? h : (w1-w2) * sin(ang[0]) * sin(ang[1]) / sin(ang[0]+ang[1]),
w1 = !is_undef(w1)? w1 : w2 + 2*(adj_ang_to_opp(h, angle) + shift), x1 = is_undef(ang[0]) || ang[0]==90 ? 0 : h/tan(ang[0]),
w2 = !is_undef(w2)? w2 : w1 - 2*(adj_ang_to_opp(h, angle) + shift), 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] : chamfs = is_num(chamfer)? [for (i=[0:3]) chamfer] :
assert(len(chamfer)==4) chamfer, assert(len(chamfer)==4) chamfer,
rounds = is_num(rounding)? [for (i=[0:3]) rounding] : 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) 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, size=[w1,h], size2=w2, shift=shift, p=path)
: reorient(anchor,spin, two_d=true, path=path, 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) { 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, angle=angle, shift=shift, chamfer=chamfer, rounding=rounding, flip=flip); path = trapezoid(h=h, w1=w1, w2=w2, ang=ang, shift=shift, chamfer=chamfer, rounding=rounding, flip=flip, angle=angle);
union() { union() {
simple = chamfer==0 && rounding==0; simple = true; //chamfer==0 && rounding==0; // force "normal" anchoring for now
h = !is_undef(h)? h : opp_ang_to_adj(abs(w2-w1)/2, abs(angle)); ang = force_list(ang,2);
w1 = !is_undef(w1)? w1 : w2 + 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]);
w2 = !is_undef(w2)? w2 : w1 - 2*(adj_ang_to_opp(h, angle) + shift); 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) { if (simple) {
attachable(anchor,spin, two_d=true, size=[w1,h], size2=w2, shift=shift) { attachable(anchor,spin, two_d=true, size=[w1,h], size2=w2, shift=shift) {
polygon(path); polygon(path);
@ -1275,8 +1291,7 @@ function teardrop2d(r, ang=45, cap_h, d, circum=false, realign=false, anchor=CEN
if (p) [i,p] if (p) [i,p]
], ],
i = last(isect)[0], i = last(isect)[0],
p = last(isect)[1], p = last(isect)[1]
ff=echo(isect)
) )
[ [
cap[0], cap[0],

View file

@ -1064,8 +1064,8 @@ module rotate_sweep(
// turns = number of revolutions to spiral up along the height. // turns = number of revolutions to spiral up along the height.
// --- // ---
// d = Diameter of the spiral to extrude along. // d = Diameter of the spiral to extrude along.
// d1|r1 = Bottom 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. // 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 // 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 // taper1 = Length of taper for bottom thread end
// taper2 = Length of taper for top thread end // taper2 = Length of taper for top thread end

View file

@ -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]) && !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(!(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_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") assert(is_consistent(points), "Non-rectangular or invalid point array")
let( let(
@ -174,6 +174,15 @@ function vnf_vertex_array(
[[i1,i5,i2],[i2,i5,i3],[i3,i5,i4],[i4,i5,i1]] [[i1,i5,i2],[i2,i5,i3],[i3,i5,i4],[i4,i5,i1]]
: style=="alt"? : style=="alt"?
[[i1,i4,i2],[i2,i4,i3]] [[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"? : style=="min_edge"?
let( let(
d42=norm(pts[i4]-pts[i2]), d42=norm(pts[i4]-pts[i2]),