Merge pull request #976 from adrianVmariano/master

distributors fixes
This commit is contained in:
Revar Desmera 2022-10-23 18:15:13 -07:00 committed by GitHub
commit 3dd605f87b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 319 additions and 299 deletions

View file

@ -835,7 +835,7 @@ module tag_scope(scope){
// right(20)
// circle(5);
// }
// Example: Here is another example where two children are intersected using the native intersection operator, and then tagged with {{force_tag()}}. Note that because the children are at the save level, you don't need to use a tagged operator for their intersection.
// Example: Here is another example where two children are intersected using the native intersection operator, and then tagged with {{force_tag()}}. Note that because the children are at the same level, you don't need to use a tagged operator for their intersection.
// $fn=32;
// diff()
// cuboid(10){

View file

@ -1,13 +1,10 @@
module translate_copies(a=[[0,0,0]]) move_copies(a) children();
module xmove(x) right(x) children();
module ymove(y) back(y) children();
module zmove(z) up(z) children();
module xspread(spacing, n, l, sp) xcopies(spacing=spacing, n=n, l=l, sp=sp) children();
module yspread(spacing, n, l, sp) ycopies(spacing=spacing, n=n, l=l, sp=sp) children();
module zspread(spacing, n, l, sp) zcopies(spacing=spacing, n=n, l=l, sp=sp) children();
module spread(p1=[0,0,0], p2=[10,0,0], spacing, l, n=2) line_of(p1=p1, p2=p2, spacing=spacing, l=l, n=n) children();
module spread(p1=[0,0,0], p2=[10,0,0], spacing, l, n=2) line_copies(p1=p1, p2=p2, spacing=spacing, l=l, n=n) children();
module grid_of(xa=[0],ya=[0],za=[0],count,spacing) grid3d(xa=xa, ya=ya, za=za, n=count, spacing=spacing) children();
module xring(n=2,r=0,sa=0,cp=[0,0,0],rot=true) xrot_copies(n=n,r=r,sa=sa,cp=cp,subrot=rot) children();

View file

@ -46,113 +46,6 @@ module move_copies(a=[[0,0,0]])
}
// Function&Module: line_of()
//
// Usage: Place `n` copies at a given spacing along the line
// line_of(spacing, [n], [p1=]) CHILDREN;
// Usage: Place as many copies as will fit at a given spacing
// line_of(spacing, [l=], [p1=]) CHILDREN;
// Usage: Place `n` copies along the length of the line
// line_of([n=], [l=], [p1=]) CHILDREN;
// Usage: Place `n` copies along the line from `p1` to `p2`
// line_of([n=], [p1=], [p2=]) CHILDREN;
// Usage: Place copies at the given spacing, centered along the line from `p1` to `p2`
// line_of([spacing], [p1=], [p2=]) CHILDREN;
// Usage: As a function
// pts = line_of([spacing], [n], [p1=]);
// pts = line_of([spacing], [l=], [p1=]);
// pts = line_of([n=], [l=], [p1=]);
// pts = line_of([n=], [p1=], [p2=]);
// pts = line_of([spacing], [p1=], [p2=]);
// Description:
// When called as a function, returns a list of points at evenly spaced positions along a line.
// When called as a module, copies `children()` at one or more evenly spaced positions along a line.
// By default, the line will be centered at the origin, unless the starting point `p1` is given.
// The line will be pointed towards `RIGHT` (X+) unless otherwise given as a vector in `l`,
// `spacing`, or `p1`/`p2`. The psotion of the copies is specified in one of several ways:
// .
// If You Know... | Then Use Something Like...
// -------------------------------- | --------------------------------
// Spacing distance, Count | `line_of(spacing=10, n=5) ...` or `line_of(10, n=5) ...`
// Spacing vector, Count | `line_of(spacing=[10,5], n=5) ...` or `line_of([10,5], n=5) ...`
// Spacing distance, Line length | `line_of(spacing=10, l=50) ...` or `line_of(10, l=50) ...`
// Spacing distance, Line vector | `line_of(spacing=10, l=[50,30]) ...` or `line_of(10, l=[50,30]) ...`
// Spacing vector, Line length | `line_of(spacing=[10,5], l=50) ...` or `line_of([10,5], l=50) ...`
// Line length, Count | `line_of(l=50, n=5) ...`
// Line vector, Count | `line_of(l=[50,40], n=5) ...`
// Line endpoints, Count | `line_of(p1=[10,10], p2=[60,-10], n=5) ...`
// Line endpoints, Spacing distance | `line_of(p1=[10,10], p2=[60,-10], spacing=10) ...`
//
// Arguments:
// spacing = Either the scalar spacing distance along the X+ direction, or the vector giving both the direction and spacing distance between each set of copies.
// n = Number of copies to distribute along the line. (Default: 2)
// ---
// l = Either the scalar length of the line, or a vector giving both the direction and length of the line.
// p1 = If given, specifies the starting point of the line.
// p2 = If given with `p1`, specifies the ending point of line, and indirectly calculates the line length.
//
// Side Effects:
// `$pos` is set to the relative centerpoint of each child copy, and can be used to modify each child individually.
// `$idx` is set to the index number of each child being copied.
//
// Examples:
// line_of(10) sphere(d=1);
// line_of(10, n=5) sphere(d=1);
// line_of([10,5], n=5) sphere(d=1);
// line_of(spacing=10, n=6) sphere(d=1);
// line_of(spacing=[10,5], n=6) sphere(d=1);
// line_of(spacing=10, l=50) sphere(d=1);
// line_of(spacing=10, l=[50,30]) sphere(d=1);
// line_of(spacing=[10,5], l=50) sphere(d=1);
// line_of(l=50, n=4) sphere(d=1);
// line_of(l=[50,-30], n=4) sphere(d=1);
// Example(FlatSpin,VPD=133):
// line_of(p1=[0,0,0], p2=[5,5,20], n=6) cube(size=[3,2,1],center=true);
// Example(FlatSpin,VPD=133):
// line_of(p1=[0,0,0], p2=[5,5,20], spacing=6) cube(size=[3,2,1],center=true);
// Example: All children are copied to each position
// line_of(l=20, n=3) {
// cube(size=[1,3,1],center=true);
// cube(size=[3,1,1],center=true);
// }
// Example(2D): The functional form of line_of() returns a list of points.
// pts = line_of([10,5],n=5);
// move_copies(pts) circle(d=2);
module line_of(spacing, n, l, p1, p2)
{
req_children($children);
pts = line_of(spacing=spacing, n=n, l=l, p1=p1, p2=p2);
for (i=idx(pts)) {
$idx = i;
$pos = pts[i];
translate($pos) children();
}
}
function line_of(spacing, n, l, p1, p2) =
assert(is_undef(spacing) || is_finite(spacing) || is_vector(spacing))
assert(is_undef(n) || is_finite(n))
assert(is_undef(l) || is_finite(l) || is_vector(l))
assert(is_undef(p1) || is_vector(p1))
assert(is_undef(p2) || is_vector(p2))
let(
ll = !is_undef(l)? scalar_vec3(l, 0) :
(!is_undef(spacing) && !is_undef(n))? ((n-1) * scalar_vec3(spacing, 0)) :
(!is_undef(p1) && !is_undef(p2))? point3d(p2-p1) :
undef,
cnt = !is_undef(n)? n :
(!is_undef(spacing) && !is_undef(ll))? floor(norm(ll) / norm(scalar_vec3(spacing, 0)) + 1.000001) :
2,
spc = cnt<=1? [0,0,0] :
is_undef(spacing)? (ll/(cnt-1)) :
is_num(spacing) && !is_undef(ll)? (ll/(cnt-1)) :
scalar_vec3(spacing, 0)
)
assert(!is_undef(cnt), "Need two of `spacing`, 'l', 'n', or `p1`/`p2` arguments in `line_of()`.")
let( spos = !is_undef(p1)? point3d(p1) : -(cnt-1)/2 * spc )
[for (i=[0:1:cnt-1]) i * spc + spos];
// Module: xcopies()
//
// Description:
@ -192,12 +85,14 @@ module xcopies(spacing, n, l, sp)
sp = is_finite(sp)? (sp*dir) : sp;
if (is_vector(spacing)) {
translate(default(sp,[0,0,0])) {
for (x = spacing) {
translate(x*dir) children();
for (i = idx(spacing)) {
$idx = i;
$pos = spacing[i]*dir;
translate($pos) children();
}
}
} else {
line_of(
line_copies(
l=u_mul(l,dir),
spacing=u_mul(spacing,dir),
n=n, p1=sp
@ -245,12 +140,14 @@ module ycopies(spacing, n, l, sp)
sp = is_finite(sp)? (sp*dir) : sp;
if (is_vector(spacing)) {
translate(default(sp,[0,0,0])) {
for (x = spacing) {
translate(x*dir) children();
for (i = idx(spacing)) {
$idx = i;
$pos = spacing[i]*dir;
translate($pos) children();
}
}
} else {
line_of(
line_copies(
l=u_mul(l,dir),
spacing=u_mul(spacing,dir),
n=n, p1=sp
@ -312,12 +209,14 @@ module zcopies(spacing, n, l, sp)
sp = is_finite(sp)? (sp*dir) : sp;
if (is_vector(spacing)) {
translate(default(sp,[0,0,0])) {
for (x = spacing) {
translate(x*dir) children();
for (i = idx(spacing)) {
$idx = i;
$pos = spacing[i]*dir;
translate($pos) children();
}
}
} else {
line_of(
line_copies(
l=u_mul(l,dir),
spacing=u_mul(spacing,dir),
n=n, p1=sp
@ -327,6 +226,121 @@ module zcopies(spacing, n, l, sp)
// Function&Module: line_copies()
//
// Usage: Place `n` copies at a given spacing along the line
// line_copies(spacing, [n], [p1=]) CHILDREN;
// Usage: Place as many copies as will fit at a given spacing
// line_copies(spacing, [l=], [p1=]) CHILDREN;
// Usage: Place `n` copies along the length of the line
// line_copies([n=], [l=], [p1=]) CHILDREN;
// Usage: Place `n` copies along the line from `p1` to `p2`
// line_copies([n=], [p1=], [p2=]) CHILDREN;
// Usage: Place copies at the given spacing, centered along the line from `p1` to `p2`
// line_copies([spacing], [p1=], [p2=]) CHILDREN;
// Usage: As a function
// pts = line_copies([spacing], [n], [p1=]);
// pts = line_copies([spacing], [l=], [p1=]);
// pts = line_copies([n=], [l=], [p1=]);
// pts = line_copies([n=], [p1=], [p2=]);
// pts = line_copies([spacing], [p1=], [p2=]);
// Description:
// When called as a function, returns a list of points at evenly spaced positions along a line.
// When called as a module, copies `children()` at one or more evenly spaced positions along a line.
// By default, the line will be centered at the origin, unless the starting point `p1` is given.
// The line will be pointed towards `RIGHT` (X+) unless otherwise given as a vector in `l`,
// `spacing`, or `p1`/`p2`. The psotion of the copies is specified in one of several ways:
// .
// If You Know... | Then Use Something Like...
// -------------------------------- | --------------------------------
// Spacing distance, Count | `line_copies(spacing=10, n=5) ...` or `line_copies(10, n=5) ...`
// Spacing vector, Count | `line_copies(spacing=[10,5], n=5) ...` or `line_copies([10,5], n=5) ...`
// Spacing distance, Line length | `line_copies(spacing=10, l=50) ...` or `line_copies(10, l=50) ...`
// Spacing distance, Line vector | `line_copies(spacing=10, l=[50,30]) ...` or `line_copies(10, l=[50,30]) ...`
// Spacing vector, Line length | `line_copies(spacing=[10,5], l=50) ...` or `line_copies([10,5], l=50) ...`
// Line length, Count | `line_copies(l=50, n=5) ...`
// Line vector, Count | `line_copies(l=[50,40], n=5) ...`
// Line endpoints, Count | `line_copies(p1=[10,10], p2=[60,-10], n=5) ...`
// Line endpoints, Spacing distance | `line_copies(p1=[10,10], p2=[60,-10], spacing=10) ...`
//
// Arguments:
// spacing = Either the scalar spacing distance along the X+ direction, or the vector giving both the direction and spacing distance between each set of copies.
// n = Number of copies to distribute along the line. (Default: 2)
// ---
// l = Either the scalar length of the line, or a vector giving both the direction and length of the line.
// p1 = If given, specifies the starting point of the line.
// p2 = If given with `p1`, specifies the ending point of line, and indirectly calculates the line length.
//
// Side Effects:
// `$pos` is set to the relative centerpoint of each child copy, and can be used to modify each child individually.
// `$idx` is set to the index number of each child being copied.
//
// Examples:
// line_copies(10) sphere(d=1);
// line_copies(10, n=5) sphere(d=1);
// line_copies([10,5], n=5) sphere(d=1);
// line_copies(spacing=10, n=6) sphere(d=1);
// line_copies(spacing=[10,5], n=6) sphere(d=1);
// line_copies(spacing=10, l=50) sphere(d=1);
// line_copies(spacing=10, l=[50,30]) sphere(d=1);
// line_copies(spacing=[10,5], l=50) sphere(d=1);
// line_copies(l=50, n=4) sphere(d=1);
// line_copies(l=[50,-30], n=4) sphere(d=1);
// Example(FlatSpin,VPD=133):
// line_copies(p1=[0,0,0], p2=[5,5,20], n=6) cube(size=[3,2,1],center=true);
// Example(FlatSpin,VPD=133):
// line_copies(p1=[0,0,0], p2=[5,5,20], spacing=6) cube(size=[3,2,1],center=true);
// Example: All children are copied to each position
// line_copies(l=20, n=3) {
// cube(size=[1,3,1],center=true);
// cube(size=[3,1,1],center=true);
// }
// Example(2D): The functional form of line_copies() returns a list of points.
// pts = line_copies([10,5],n=5);
// move_copies(pts) circle(d=2);
module line_of(spacing, n, l, p1, p2) {
deprecate("line_copies");
line_copies(spacing, n, l, p1, p2);
}
module line_copies(spacing, n, l, p1, p2)
{
req_children($children);
pts = line_copies(spacing=spacing, n=n, l=l, p1=p1, p2=p2);
for (i=idx(pts)) {
$idx = i;
$pos = pts[i];
translate($pos) children();
}
}
function line_copies(spacing, n, l, p1, p2) =
assert(is_undef(spacing) || is_finite(spacing) || is_vector(spacing))
assert(is_undef(n) || is_finite(n))
assert(is_undef(l) || is_finite(l) || is_vector(l))
assert(is_undef(p1) || is_vector(p1))
assert(is_undef(p2) || is_vector(p2))
let(
ll = !is_undef(l)? scalar_vec3(l, 0) :
(!is_undef(spacing) && !is_undef(n))? ((n-1) * scalar_vec3(spacing, 0)) :
(!is_undef(p1) && !is_undef(p2))? point3d(p2-p1) :
undef,
cnt = !is_undef(n)? n :
(!is_undef(spacing) && !is_undef(ll))? floor(norm(ll) / norm(scalar_vec3(spacing, 0)) + 1.000001) :
2,
spc = cnt<=1? [0,0,0] :
is_undef(spacing)? (ll/(cnt-1)) :
is_num(spacing) && !is_undef(ll)? (ll/(cnt-1)) :
scalar_vec3(spacing, 0)
)
assert(!is_undef(cnt), "Need two of `spacing`, 'l', 'n', or `p1`/`p2` arguments in `line_copies()`.")
let( spos = !is_undef(p1)? point3d(p1) : -(cnt-1)/2 * spc )
[for (i=[0:1:cnt-1]) i * spc + spos];
// Module: grid_copies()
@ -578,7 +592,7 @@ module rot_copies(rots=[], v=undef, cp=[0,0,0], n, sa=0, offset=0, delta=[0,0,0]
// Arguments:
// rots = Optional array of rotation angles, in degrees, to make copies at.
// cp = Centerpoint to rotate around.
// --
// ---
// n = Optional number of evenly distributed copies to be rotated around the ring.
// sa = Starting angle, in degrees. For use with `n`. Angle is in degrees counter-clockwise from Y+, when facing the origin from X+. First unrotated copy is placed at that angle.
// r = If given, makes a ring of child copies around the X axis, at the given radius. Default: 0
@ -743,14 +757,14 @@ module zrot_copies(rots=[], cp=[0,0,0], n, sa=0, r, d, subrot=true)
}
// Module: arc_of()
// Module: arc_copies()
//
// Description:
// Evenly distributes n duplicate children around an ovoid arc on the XY plane.
//
// Usage:
// arc_of(n, r|d=, [sa=], [ea=], [rot=]) CHILDREN;
// arc_of(n, rx=|dx=, ry=|dy=, [sa=], [ea=], [rot=]) CHILDREN;
// arc_copies(n, r|d=, [sa=], [ea=], [rot=]) CHILDREN;
// arc_copies(n, rx=|dx=, ry=|dy=, [sa=], [ea=], [rot=]) CHILDREN;
//
// Arguments:
// n = number of copies to distribute around the circle. (Default: 6)
@ -772,24 +786,30 @@ module zrot_copies(rots=[], cp=[0,0,0], n, sa=0, r, d, subrot=true)
//
// Example:
// #cube(size=[10,3,3],center=true);
// arc_of(d=40, n=5) cube(size=[10,3,3],center=true);
// arc_copies(d=40, n=5) cube(size=[10,3,3],center=true);
//
// Example:
// #cube(size=[10,3,3],center=true);
// arc_of(d=40, n=5, sa=45, ea=225) cube(size=[10,3,3],center=true);
// arc_copies(d=40, n=5, sa=45, ea=225) cube(size=[10,3,3],center=true);
//
// Example:
// #cube(size=[10,3,3],center=true);
// arc_of(r=15, n=8, rot=false) cube(size=[10,3,3],center=true);
// arc_copies(r=15, n=8, rot=false) cube(size=[10,3,3],center=true);
//
// Example:
// #cube(size=[10,3,3],center=true);
// arc_of(rx=20, ry=10, n=8) cube(size=[10,3,3],center=true);
// arc_copies(rx=20, ry=10, n=8) cube(size=[10,3,3],center=true);
// Example(2D): Using `$idx` to alternate shapes
// arc_of(r=50, n=19, sa=0, ea=180)
// arc_copies(r=50, n=19, sa=0, ea=180)
// if ($idx % 2 == 0) rect(6);
// else circle(d=6);
module arc_of(
function arc_copies(n=6,r,rx,ry,d,dx,dy,sa=0,ea=360,rot=true) = no_function("arc_copies");
module arc_of(n=6,r,rx,ry,d,dx,dy,sa=0,ea=360,rot=true){
deprecate("arc_copies");
arc_copies(n,r,rx,ry,d,dx,dy,sa,ea,rot);
}
module arc_copies(
n=6,
r=undef,
rx=undef, ry=undef,
@ -1046,61 +1066,6 @@ module path_copies(path, n, spacing, sp=undef, dist, rotate_children=true, dist,
//////////////////////////////////////////////////////////////////////
// Module: mirror_copy()
//
// Description:
// Makes a copy of the children, mirrored across the given plane.
//
// Usage:
// mirror_copy(v, [cp], [offset]) CHILDREN;
//
// Arguments:
// v = The normal vector of the plane to mirror across.
// offset = distance to offset away from the plane.
// cp = A point that lies on the mirroring plane.
//
// Side Effects:
// `$orig` is true for the original instance of children. False for the copy.
// `$idx` is set to the index value of each copy.
//
// Example:
// mirror_copy([1,-1,0]) zrot(-45) yrot(90) cylinder(d1=10, d2=0, h=20);
// color("blue",0.25) zrot(-45) cube([0.01,15,15], center=true);
//
// Example:
// mirror_copy([1,1,0], offset=5) rot(a=90,v=[-1,1,0]) cylinder(d1=10, d2=0, h=20);
// color("blue",0.25) zrot(45) cube([0.01,15,15], center=true);
//
// Example:
// mirror_copy(UP+BACK, cp=[0,-5,-5]) rot(from=UP, to=BACK+UP) cylinder(d1=10, d2=0, h=20);
// color("blue",0.25) translate([0,-5,-5]) rot(from=UP, to=BACK+UP) cube([15,15,0.01], center=true);
module mirror_copy(v=[0,0,1], offset=0, cp)
{
req_children($children);
cp = is_vector(v,4)? plane_normal(v) * v[3] :
is_vector(cp)? cp :
is_num(cp)? cp*unit(v) :
[0,0,0];
nv = is_vector(v,4)? plane_normal(v) : unit(v);
off = nv*offset;
if (cp == [0,0,0]) {
translate(off) {
$orig = true;
$idx = 0;
children();
}
mirror(nv) translate(off) {
$orig = false;
$idx = 1;
children();
}
} else {
translate(off) children();
translate(cp) mirror(nv) translate(-cp) translate(off) children();
}
}
// Module: xflip_copy()
//
// Description:
@ -1202,56 +1167,67 @@ module zflip_copy(offset=0, z=0)
mirror_copy(v=[0,0,1], offset=offset, cp=[0,0,z]) children();
}
////////////////////
// Section: Distributing children individually along a line
///////////////////
// Module: distribute()
// Module: mirror_copy()
//
// Description:
// Spreads out the children individually along the direction `dir`.
// Every child is placed at a different position, in order.
// This is useful for laying out groups of disparate objects
// where you only really care about the spacing between them.
// Makes a copy of the children, mirrored across the given plane.
//
// Usage:
// distribute(spacing, sizes, dir) CHILDREN;
// distribute(l=, [sizes=], [dir=]) CHILDREN;
// mirror_copy(v, [cp], [offset]) CHILDREN;
//
// Arguments:
// spacing = Spacing to add between each child. (Default: 10.0)
// sizes = Array containing how much space each child will need.
// dir = Vector direction to distribute copies along. Default: RIGHT
// l = Length to distribute copies along.
// v = The normal vector of the plane to mirror across.
// offset = distance to offset away from the plane.
// cp = A point that lies on the mirroring plane.
//
// Side Effects:
// `$pos` is set to the relative centerpoint of each child copy, and can be used to modify each child individually.
// `$idx` is set to the index number of each child being copied.
// `$orig` is true for the original instance of children. False for the copy.
// `$idx` is set to the index value of each copy.
//
// Example:
// distribute(sizes=[100, 30, 50], dir=UP) {
// sphere(r=50);
// cube([10,20,30], center=true);
// cylinder(d=30, h=50, center=true);
// }
module distribute(spacing=undef, sizes=undef, dir=RIGHT, l=undef)
// mirror_copy([1,-1,0]) zrot(-45) yrot(90) cylinder(d1=10, d2=0, h=20);
// color("blue",0.25) zrot(-45) cube([0.01,15,15], center=true);
//
// Example:
// mirror_copy([1,1,0], offset=5) rot(a=90,v=[-1,1,0]) cylinder(d1=10, d2=0, h=20);
// color("blue",0.25) zrot(45) cube([0.01,15,15], center=true);
//
// Example:
// mirror_copy(UP+BACK, cp=[0,-5,-5]) rot(from=UP, to=BACK+UP) cylinder(d1=10, d2=0, h=20);
// color("blue",0.25) translate([0,-5,-5]) rot(from=UP, to=BACK+UP) cube([15,15,0.01], center=true);
module mirror_copy(v=[0,0,1], offset=0, cp)
{
req_children($children);
gaps = ($children < 2)? [0] :
!is_undef(sizes)? [for (i=[0:1:$children-2]) sizes[i]/2 + sizes[i+1]/2] :
[for (i=[0:1:$children-2]) 0];
spc = !is_undef(l)? ((l - sum(gaps)) / ($children-1)) : default(spacing, 10);
gaps2 = [for (gap = gaps) gap+spc];
spos = dir * -sum(gaps2)/2;
spacings = cumsum([0, each gaps2]);
for (i=[0:1:$children-1]) {
$pos = spos + spacings[i] * dir;
$idx = i;
translate($pos) children(i);
cp = is_vector(v,4)? plane_normal(v) * v[3] :
is_vector(cp)? cp :
is_num(cp)? cp*unit(v) :
[0,0,0];
nv = is_vector(v,4)? plane_normal(v) : unit(v);
off = nv*offset;
if (cp == [0,0,0]) {
translate(off) {
$orig = true;
$idx = 0;
children();
}
mirror(nv) translate(off) {
$orig = false;
$idx = 1;
children();
}
} else {
translate(off) children();
translate(cp) mirror(nv) translate(-cp) translate(off) children();
}
}
////////////////////
// Section: Distributing children individually along a line
///////////////////
// Module: xdistribute()
//
// Description:
@ -1391,5 +1367,53 @@ module zdistribute(spacing=10, sizes=undef, l=undef)
// Module: distribute()
//
// Description:
// Spreads out the children individually along the direction `dir`.
// Every child is placed at a different position, in order.
// This is useful for laying out groups of disparate objects
// where you only really care about the spacing between them.
//
// Usage:
// distribute(spacing, sizes, dir) CHILDREN;
// distribute(l=, [sizes=], [dir=]) CHILDREN;
//
// Arguments:
// spacing = Spacing to add between each child. (Default: 10.0)
// sizes = Array containing how much space each child will need.
// dir = Vector direction to distribute copies along. Default: RIGHT
// l = Length to distribute copies along.
//
// Side Effects:
// `$pos` is set to the relative centerpoint of each child copy, and can be used to modify each child individually.
// `$idx` is set to the index number of each child being copied.
//
// Example:
// distribute(sizes=[100, 30, 50], dir=UP) {
// sphere(r=50);
// cube([10,20,30], center=true);
// cylinder(d=30, h=50, center=true);
// }
module distribute(spacing=undef, sizes=undef, dir=RIGHT, l=undef)
{
req_children($children);
gaps = ($children < 2)? [0] :
!is_undef(sizes)? [for (i=[0:1:$children-2]) sizes[i]/2 + sizes[i+1]/2] :
[for (i=[0:1:$children-2]) 0];
spc = !is_undef(l)? ((l - sum(gaps)) / ($children-1)) : default(spacing, 10);
gaps2 = [for (gap = gaps) gap+spc];
spos = dir * -sum(gaps2)/2;
spacings = cumsum([0, each gaps2]);
for (i=[0:1:$children-1]) {
$pos = spos + spacings[i] * dir;
$idx = i;
translate($pos) children(i);
}
}
// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap

View file

@ -1595,13 +1595,13 @@ function reuleaux_polygon(n=3, r, d, anchor=CENTER, spin=0) =
// text("Foobar", size=12, font="Helvetica");
// text("Foobar", anchor=CENTER);
// text("Foobar", anchor=str("baseline",CENTER));
// Example: Using line_of() distributor
// Example: Using line_copies() distributor
// txt = "This is the string.";
// line_of(spacing=[10,-5],n=len(txt))
// line_copies(spacing=[10,-5],n=len(txt))
// text(txt[$idx], size=10, anchor=CENTER);
// Example: Using arc_of() distributor
// Example: Using arc_copies() distributor
// txt = "This is the string";
// arc_of(r=50, n=len(txt), sa=0, ea=180)
// arc_copies(r=50, n=len(txt), sa=0, ea=180)
// text(select(txt,-1-$idx), size=10, anchor=str("baseline",CENTER), spin=-90);
module text(text, size=10, font="Helvetica", halign, valign, spacing=1.0, direction="ltr", language="en", script="latin", anchor="baseline", spin=0) {
no_children($children);

View file

@ -1,18 +1,18 @@
include <../std.scad>
module test_line_of() {
assert_equal(line_of(l=100,n=5), [[-50,0,0],[-25,0,0],[0,0,0],[25,0,0],[50,0,0]]);
assert_equal(line_of(20,n=5), [[-40,0,0],[-20,0,0],[0,0,0],[20,0,0],[40,0,0]]);
assert_equal(line_of(spacing=20,n=5), [[-40,0,0],[-20,0,0],[0,0,0],[20,0,0],[40,0,0]]);
assert_equal(line_of(spacing=[0,20],n=5), [[0,-40,0],[0,-20,0],[0,0,0],[0,20,0],[0,40,0]]);
module test_line_copies() {
assert_equal(line_copies(l=100,n=5), [[-50,0,0],[-25,0,0],[0,0,0],[25,0,0],[50,0,0]]);
assert_equal(line_copies(20,n=5), [[-40,0,0],[-20,0,0],[0,0,0],[20,0,0],[40,0,0]]);
assert_equal(line_copies(spacing=20,n=5), [[-40,0,0],[-20,0,0],[0,0,0],[20,0,0],[40,0,0]]);
assert_equal(line_copies(spacing=[0,20],n=5), [[0,-40,0],[0,-20,0],[0,0,0],[0,20,0],[0,40,0]]);
assert_equal(line_of(p1=[0,0],l=100,n=5), [[0,0,0],[25,0,0],[50,0,0],[75,0,0],[100,0,0]]);
assert_equal(line_of(p1=[0,0],20,n=5), [[0,0,0],[20,0,0],[40,0,0],[60,0,0],[80,0,0]]);
assert_equal(line_of(p1=[0,0],spacing=20,n=5), [[0,0,0],[20,0,0],[40,0,0],[60,0,0],[80,0,0]]);
assert_equal(line_of(p1=[0,0],spacing=[0,20],n=5), [[0,0,0],[0,20,0],[0,40,0],[0,60,0],[0,80,0]]);
assert_equal(line_copies(p1=[0,0],l=100,n=5), [[0,0,0],[25,0,0],[50,0,0],[75,0,0],[100,0,0]]);
assert_equal(line_copies(p1=[0,0],20,n=5), [[0,0,0],[20,0,0],[40,0,0],[60,0,0],[80,0,0]]);
assert_equal(line_copies(p1=[0,0],spacing=20,n=5), [[0,0,0],[20,0,0],[40,0,0],[60,0,0],[80,0,0]]);
assert_equal(line_copies(p1=[0,0],spacing=[0,20],n=5), [[0,0,0],[0,20,0],[0,40,0],[0,60,0],[0,80,0]]);
}
test_line_of();
test_line_copies();

View file

@ -140,7 +140,7 @@ module threaded_rod(
// shape = specifies shape of nut, either "hex" or "square". Default: "hex"
// left_handed = if true, create left-handed threads. Default = false
// starts = The number of lead starts. Default: 1
// bevel = if true, bevel the outside of the nut.
// bevel = if true, bevel the outside of the nut. Default: true for hex nuts, false for square nuts
// bevel1 = if true, bevel the outside of the nut bottom.
// bevel2 = if true, bevel the outside of the nut top.
// bevang = set the angle for the outside nut bevel. Default: 15
@ -347,7 +347,7 @@ module trapezoidal_threaded_rod(
// shape = specifies shape of nut, either "hex" or "square". Default: "hex"
// left_handed = if true, create left-handed threads. Default = false
// starts = The number of lead starts. Default = 1
// bevel = if true, bevel the outside of the nut.
// bevel = if true, bevel the outside of the nut. Default: true for hex nuts, false for square nuts
// bevel1 = if true, bevel the outside of the nut bottom.
// bevel2 = if true, bevel the outside of the nut top.
// bevang = set the angle for the outside nut bevel. Default: 15
@ -497,7 +497,7 @@ module acme_threaded_rod(
// shape = specifies shape of nut, either "hex" or "square". Default: "hex"
// left_handed = if true, create left-handed threads. Default = false
// starts = Number of lead starts. Default: 1
// bevel = if true, bevel the outside of the nut.
// bevel = if true, bevel the outside of the nut. Default: true for hex nuts, false for square nuts
// bevel1 = if true, bevel the outside of the nut bottom.
// bevel2 = if true, bevel the outside of the nut top.
// bevang = set the angle for the outside nut bevel. Default: 15
@ -766,7 +766,7 @@ module buttress_threaded_rod(
// shape = specifies shape of nut, either "hex" or "square". Default: "hex"
// left_handed = if true, create left-handed threads. Default = false
// starts = The number of lead starts. Default: 1
// bevel = if true, bevel the outside of the nut.
// bevel = if true, bevel the outside of the nut. Default: true for hex nuts, false for square nuts
// bevel1 = if true, bevel the outside of the nut bottom.
// bevel2 = if true, bevel the outside of the nut top.
// bevang = set the angle for the outside nut bevel. Default: 15
@ -904,7 +904,7 @@ module square_threaded_rod(
// shape = specifies shape of nut, either "hex" or "square". Default: "hex"
// left_handed = if true, create left-handed threads. Default = false
// starts = The number of lead starts. Default = 1
// bevel = if true, bevel the outside of the nut.
// bevel = if true, bevel the outside of the nut. Default: true for hex nuts, false for square nuts
// bevel1 = if true, bevel the outside of the nut bottom.
// bevel2 = if true, bevel the outside of the nut top.
// bevang = set the angle for the outside nut bevel. Default: 15
@ -1274,7 +1274,7 @@ module generic_threaded_rod(
// shape = specifies shape of nut, either "hex" or "square". Default: "hex"
// left_handed = if true, create left-handed threads. Default = false
// starts = The number of lead starts. Default = 1
// bevel = if true, bevel the outside of the nut.
// bevel = if true, bevel the outside of the nut. Default: true for hex nuts, false for square nuts
// bevel1 = if true, bevel the outside of the nut bottom.
// bevel2 = if true, bevel the outside of the nut top.
// bevang = set the angle for the outside nut bevel. Default: 15
@ -1315,6 +1315,7 @@ module generic_threaded_nut(
id1,id2, height, thickness,
anchor, spin, orient
) {
extra = 0.01;
id1 = first_defined([id1,id]);
id2 = first_defined([id2,id]);
@ -1328,8 +1329,8 @@ module generic_threaded_nut(
full_id2 = id2+slope*extra/2;
ibevel1 = first_defined([ibevel1,ibevel,true]);
ibevel2 = first_defined([ibevel2,ibevel,true]);
bevel1 = first_defined([bevel1,bevel,false]);
bevel2 = first_defined([bevel2,bevel,false]);
bevel1 = first_defined([bevel1,bevel,shape=="hex"?true:false]);
bevel2 = first_defined([bevel2,bevel,shape=="hex"?true:false]);
depth = -pitch*min(column(profile,1));
bevel_d=0.975;
IBEV=0.05;
@ -1497,30 +1498,6 @@ module thread_helix(
// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
// Changes
// internal: can set bevel to true and get non-garbage result
// bevel is always set by thread depth
// acme takes tpi
// square threads are at angle 0
// added generic_threaded_{rod,nut}
// eliminated metric_trapezoidal_*
// cleaned up matrices some in generic_threaded_rod
// threaded_rod can produce spec-true ISO/UTS profile with a triplet input for the diameter.
// Added bevel1 and bevel2 to all modules. Made default uniformly false for every case instead of
// sometimes true, sometimes false
// Profiles that go over zero are not clipped, and bevels are based on actual profile top, not nominal
// When bevel is given to nuts it bevels the outside of the nut by thread depth
// higbee looks best with quincunx, but it's more expensive. Select quincunx when higbee is used, min_edge otherwise
// Current code uses difference to remove excess length in the rod. This gives faster renders at the cost
// of more complex code and green top/bottom surfaces.
// Changed slop to 4 * $slop. I got good results printing with $slop=0.05 with this setting.
// Don't generate excess threads when starts>1, and don't force threads to be even
//
// Fixed higbee in spiral_sweep for properly centered scaling and for staying on the internal/external base of threads
// Fixed bug in spiral_sweep where two segments were missing if higbee is zero
// Fixed faceting bugs in spiral_sweep where segments weren't aligned with requested number of segments, and higbee
// would pull away from the cylinder by using a higher count and following a true circle
//
// Questions
// Should nut modules take d1/d2 for tapered nuts?
//

View file

@ -403,10 +403,11 @@ cylinder(h=100, d=100, center=true)
## Tagged Operations
BOSL2 introduces the concept of tags. Tags are names that can be given to attachables, so that
you can refer to them when performing `diff()`, `intersect()`, and `conv_hull()` operations.
Each object can have no more than one tag at a time.
### `diff(remove, <keep>)`
### `diff([remove], [keep])`
The `diff()` operator is used to difference away all shapes marked with the tag(s) given to
`remove=`, from the other shapes.
`remove`, from the other shapes.
For example, to difference away a child cylinder from the middle of a parent cube, you can
do this:
@ -445,7 +446,7 @@ tag("keep")cube(100, center=true)
```
If you need to mark multiple children with a tag, you can use the `tag()` module.
You can of course apply `tag()` to several children.
```openscad-3D
include <BOSL2/std.scad>
@ -458,14 +459,28 @@ cube(100, center=true)
}
```
Many of the modules that use tags have default values for their tags. For diff the default
remove tag is "remove" and the default keep tag is "keep". In this example we rely on the
default values:
```openscad-3D
include <BOSL2/std.scad>
diff()
sphere(d=100) {
tag("keep")xcyl(d=40, l=120);
tag("remove")cuboid([40,120,100]);
}
```
The parent object can be differenced away from other shapes. Tags are inherited by children,
though, so you will need to set the tags of the children as well as the parent.
```openscad-3D
include <BOSL2/std.scad>
diff("hole")
cube([20,11,45], center=true, $tag="hole")
cube([40,10,90], center=true, $tag="body");
tag("hole")cube([20,11,45], center=true)
tag("body")cube([40,10,90], center=true);
```
Tags (and therefore tag-based operations like `diff()`) only work correctly with attachable
@ -488,55 +503,62 @@ cuboid(50)
square(10,center=true);
```
### `intersect(a, <b>, <keep>)`
### `intersect([intersect], [keep])`
To perform an intersection of attachables, you can use the `intersect()` module. If given one
argument to `a=`, the parent and all children *not* tagged with that will be intersected by
everything that *is* tagged with it.
To perform an intersection of attachables, you can use the `intersect()` module. This is
specifically intended to address the situation where you want intersections involving a parent
and a child, something that is impossible with the native `intersection()` module. This module
treats the children in three groups: objects matching the `intersect` tags, objects matching
the tags listed in `keep` and the remaining objects that don't match any listed tags. The
intersection is computed between the union of the `intersect` tagged objects and the union of
the objects that don't match any listed tags. Finally the objects lsited in `keep` are union
ed with the result.
In this example the parent is intersected with a conical bounding shape.
```openscad-3D
include <BOSL2/std.scad>
intersect("bounds")
cube(100, center=true)
cylinder(h=100, d1=120, d2=95, center=true, $fn=72, $tag="bounds");
tag("bounds") cylinder(h=100, d1=120, d2=95, center=true, $fn=72);
```
If given both the `a=` and `b=` arguments, then shapes marked with tags given to `a=` will be
intersected with shapes marked with tags given to `b=`, then unioned with all other shapes.
In this example the child objects are intersected with the bounding box parent.
```openscad-3D
include <BOSL2/std.scad>
intersect("pole", "cap")
intersect("pole cap")
cube(100, center=true)
attach([TOP,RIGHT]) {
cube([40,40,80],center=true, $tag="pole");
sphere(d=40*sqrt(2), $tag="cap");
tag("pole")cube([40,40,80],center=true);
tag("cap")sphere(d=40*sqrt(2));
}
```
If the `keep=` argument is given, anything marked with tags passed to it will be unioned with
the result of the union:
The default `intersect` tag is "intersect" and the default `keep` tag is "keep". Here is an
example where "keep" is used to keep the pole from being removed by the intersection.
```openscad-3D
include <BOSL2/std.scad>
intersect("bounds", keep="pole")
intersect()
cube(100, center=true) {
cylinder(h=100, d1=120, d2=95, center=true, $fn=72, $tag="bounds");
zrot(45) xcyl(h=140, d=20, $fn=36, $tag="pole");
tag("intersect")cylinder(h=100, d1=120, d2=95, center=true, $fn=72);
tag("keep")zrot(45) xcyl(h=140, d=20, $fn=36);
}
```
### `conv_hull(keep)`
You can use the `conv_hull()` module to hull shapes together the
shapes not marked with the keep tags, before unioning the keep shapes
into the final result.
### `conv_hull([keep])`
You can use the `conv_hull()` module to hull shapes together. Objects
marked with the keep tags are excluded from the hull and unioned into the final result.
The default keep tag is "keep".
```openscad-3D
include <BOSL2/std.scad>
conv_hull("pole")
cube(50, center=true, $tag="hull") {
conv_hull()
cube(50, center=true) {
cyl(h=100, d=20);
xcyl(h=100, d=20, $tag="pole");
tag("keep")xcyl(h=100, d=20);
}
```

View file

@ -13,11 +13,11 @@ Transforms | Related Distributors
`left()`, `right()` | `xcopies()`
`fwd()`, `back()` | `ycopies()`
`down()`, `up()` | `zcopies()`
`move()`, `translate()` | `move_copies()`, `line_of()`, `grid_copies()`
`move()`, `translate()` | `move_copies()`, `line_copies()`, `grid_copies()`
`xrot()` | `xrot_copies()`
`yrot()` | `yrot_copies()`
`zrot()` | `zrot_copies()`
`rot()`, `rotate()` | `rot_copies()`, `arc_of()`
`rot()`, `rotate()` | `rot_copies()`, `arc_copies()`
`xflip()` | `xflip_copy()`
`yflip()` | `yflip_copy()`
`zflip()` | `zflip_copy()`
@ -106,24 +106,24 @@ zcopies(20, n=5, sp=[0,0,0]) sphere(d=10);
```
If you need to distribute copies along an arbitrary line, you can use the
`line_of()` command. You can give both the direction vector and the spacing
`line_copies()` command. You can give both the direction vector and the spacing
of the line of copies with the `spacing=` argument:
```openscad-3D
include <BOSL2/std.scad>
line_of(spacing=(BACK+RIGHT)*20, n=5) sphere(d=10);
line_copies(spacing=(BACK+RIGHT)*20, n=5) sphere(d=10);
```
With the `p1=` argument, you can specify the starting point of the line:
```openscad-3D
include <BOSL2/std.scad>
line_of(spacing=(BACK+RIGHT)*20, n=5, p1=[0,0,0]) sphere(d=10);
line_copies(spacing=(BACK+RIGHT)*20, n=5, p1=[0,0,0]) sphere(d=10);
```
If you give both `p1=` and `p2=`, you can nail down both the start and
endpoints of the line of copies:
```openscad-2D
include <BOSL2/std.scad>
line_of(p1=[0,100,0], p2=[100,0,0], n=4)
line_copies(p1=[0,100,0], p2=[100,0,0], n=4)
sphere(d=10);
```

View file

@ -1418,7 +1418,7 @@ module debug_vnf(vnf, faces=true, vertices=true, opacity=0.5, size=1, convexity=
// Arguments:
// vnf = The VNF to validate.
// size = The width of the lines and diameter of points used to highlight edges and vertices. Module only. Default: 1
// --
// ---
// show_warns = If true show warnings for non-triangular faces. Default: true
// check_isects = If true, performs slow checks for intersecting faces. Default: false
// opacity = The opacity level to show the polyhedron itself with. (Module only) Default: 0.67