Multiple bugfixes for and argument re-arrangement. Added vfloor() and vceil().

This commit is contained in:
Revar Desmera 2020-03-25 19:50:38 -07:00
parent 7292250162
commit 6b4fb3184c
5 changed files with 191 additions and 171 deletions

View File

@ -400,19 +400,17 @@ module zdistribute(spacing=10, sizes=undef, l=undef)
// Makes a square or hexagonal grid of copies of children.
//
// Usage:
// grid2d(size, spacing, [stagger], [scale], [in_poly]) ...
// grid2d(size, cols, rows, [stagger], [scale], [in_poly]) ...
// grid2d(spacing, cols, rows, [stagger], [scale], [in_poly]) ...
// grid2d(spacing, size, [stagger], [scale], [in_poly]) ...
// grid2d(n, size, [stagger], [scale], [in_poly]) ...
// grid2d(spacing, n, [stagger], [scale], [in_poly]) ...
// grid2d(spacing, in_poly, [stagger], [scale]) ...
// grid2d(cols, rows, in_poly, [stagger], [scale]) ...
// grid2d(n, in_poly, [stagger], [scale]) ...
//
// Arguments:
// size = The [X,Y] size to spread the copies over.
// spacing = Distance between copies in [X,Y] or scalar distance.
// cols = How many columns of copies to make. If staggered, count both staggered and unstaggered columns.
// rows = How many rows of copies to make. If staggered, count both staggered and unstaggered rows.
// n = How many columns and rows of copies to make. Can be given as `[COLS,ROWS]`, or just as a scalar that specifies both. If staggered, count both staggered and unstaggered columns and rows. Default: 2 (3 if staggered)
// stagger = If true, make a staggered (hexagonal) grid. If false, make square grid. If `"alt"`, makes alternate staggered pattern. Default: false
// scale = [X,Y] scaling factors to reshape grid.
// in_poly = If given a list of polygon points, only creates copies whose center would be inside the polygon. Polygon can be concave and/or self crossing.
//
// Side Effects:
@ -421,10 +419,11 @@ module zdistribute(spacing=10, sizes=undef, l=undef)
// `$row` is set to the integer row number for each child.
//
// Examples:
// grid2d(size=50, spacing=10, stagger=false) cylinder(d=10, h=1);
// grid2d(spacing=10, rows=7, cols=13, stagger=true) cylinder(d=6, h=5);
// grid2d(spacing=10, rows=7, cols=13, stagger="alt") cylinder(d=6, h=5);
// grid2d(size=50, rows=11, cols=11, stagger=true) cylinder(d=5, h=1);
// grid2d(size=50, spacing=10) cylinder(d=10, h=1);
// grid2d(size=50, spacing=[10,15]) cylinder(d=10, h=1);
// grid2d(spacing=10, n=[13,7], stagger=true) cylinder(d=6, h=5);
// grid2d(spacing=10, n=[13,7], stagger="alt") cylinder(d=6, h=5);
// grid2d(size=50, n=11, stagger=true) cylinder(d=5, h=1);
//
// Example:
// poly = [[-25,-25], [25,25], [-25,25], [25,-25]];
@ -433,7 +432,7 @@ module zdistribute(spacing=10, sizes=undef, l=undef)
// %polygon(poly);
//
// Example: Using `$row` and `$col`
// grid2d(spacing=[8,8], cols=8, rows=8)
// grid2d(spacing=8], n=8)
// color(($row+$col)%2?"black":"red")
// cube([8,8,0.01], center=false);
//
@ -449,33 +448,35 @@ module zdistribute(spacing=10, sizes=undef, l=undef)
// zrot(180/6)
// cylinder(h=20, d=10/cos(180/6)+0.01, $fn=6);
// }
module grid2d(size=undef, spacing=undef, cols=undef, rows=undef, stagger=false, scale=[1,1,1], in_poly=undef)
module grid2d(spacing, n, size, stagger=false, in_poly=undef)
{
assert(in_list(stagger, [false, true, "alt"]));
scl = vmul(scalar_vec3(scale, 1), (stagger!=false? [0.5, sin(60), 1] : [1,1,1]));
if (!is_undef(size)) {
siz = scalar_vec3(size);
if (!is_undef(spacing)) {
spc = vmul(scalar_vec3(spacing), scl);
maxcols = ceil(siz.x/spc.x);
maxrows = ceil(siz.y/spc.y);
grid2d(spacing=spacing, cols=maxcols, rows=maxrows, stagger=stagger, scale=scale, in_poly=in_poly) children();
} else {
spc = [siz.x/cols, siz.y/rows];
grid2d(spacing=spc, cols=cols, rows=rows, stagger=stagger, scale=scale, in_poly=in_poly) children();
}
} else {
spc = is_list(spacing)? point3d(spacing) : vmul(scalar_vec3(spacing), scl);
bounds = !is_undef(in_poly)? pointlist_bounds(in_poly) : undef;
bnds = !is_undef(bounds)? [for (a=[0,1]) 2*max(vabs([ for (i=[0,1]) bounds[i][a] ]))+1 ] : undef;
mcols = !is_undef(cols)? cols : (!is_undef(spc) && !is_undef(bnds))? quantup(ceil(bnds[0]/spc[0])-1, 4)+1 : undef;
mrows = !is_undef(rows)? rows : (!is_undef(spc) && !is_undef(bnds))? quantup(ceil(bnds[1]/spc[1])-1, 4)+1 : undef;
siz = vmul(spc, [mcols-1, mrows-1, 0])+[0,0,0.01];
staggermod = (stagger == "alt")? 1 : 0;
bounds = is_undef(in_poly)? undef : pointlist_bounds(in_poly);
size = is_num(size)? [size, size] :
is_vector(size)? assert(len(size)==2) size :
bounds!=undef? [
for (i=[0:1]) 2*max(abs(bounds[0][i]),bounds[1][i])
] : undef;
spacing = is_num(spacing)? (
stagger!=false? polar_to_xy(spacing,60) :
[spacing,spacing]
) :
is_vector(spacing)? assert(len(spacing)==2) spacing :
size!=undef? (
is_num(n)? vdiv(size,(n-1)*[1,1]) :
is_vector(n)? assert(len(n)==2) vdiv(size,n-[1,1]) :
vdiv(size,(stagger==false? [1,1] : [2,2]))
) :
undef;
n = is_num(n)? [n,n] :
is_vector(n)? assert(len(n)==2) n :
size!=undef && spacing!=undef? vfloor(vdiv(size,spacing))+[1,1] :
[2,2];
offset = vmul(spacing, n-[1,1])/2;
if (stagger == false) {
for (row = [0:1:mrows-1]) {
for (col = [0:1:mcols-1]) {
pos = [col*spc.x, row*spc.y] - point2d(siz/2);
for (row = [0:1:n.y-1]) {
for (col = [0:1:n.x-1]) {
pos = vmul([col,row],spacing) - offset;
if (is_undef(in_poly) || point_in_polygon(pos, in_poly)>=0) {
$col = col;
$row = row;
@ -486,14 +487,15 @@ module grid2d(size=undef, spacing=undef, cols=undef, rows=undef, stagger=false,
}
} else {
// stagger == true or stagger == "alt"
cols1 = ceil(mcols/2);
cols2 = mcols - cols1;
for (row = [0:1:mrows-1]) {
staggermod = (stagger == "alt")? 1 : 0;
cols1 = ceil(n.x/2);
cols2 = n.x - cols1;
for (row = [0:1:n.y-1]) {
rowcols = ((row%2) == staggermod)? cols1 : cols2;
if (rowcols > 0) {
for (col = [0:1:rowcols-1]) {
rowdx = (row%2 != staggermod)? spc[0] : 0;
pos = [2*col*spc[0]+rowdx, row*spc[1]] - point2d(siz/2);
rowdx = (row%2 != staggermod)? spacing.x : 0;
pos = vmul([2*col,row],spacing) + [rowdx,0] - offset;
if (is_undef(in_poly) || point_in_polygon(pos, in_poly)>=0) {
$col = col * 2 + ((row%2!=staggermod)? 1 : 0);
$row = row;
@ -505,7 +507,6 @@ module grid2d(size=undef, spacing=undef, cols=undef, rows=undef, stagger=false,
}
}
}
}

124
tutorials/Distributors.md Normal file
View File

@ -0,0 +1,124 @@
# BOSL2 Distributors Tutorial
## Distributors
Distributors are modules that are useful for placing multiple copies of a child
across a line, area, volume, or ring. Many transforms also have one or more
distributive variation.
Transforms | Related Distributors
----------------------- | ---------------------
`left()`, `right()` | `xcopies()`
`fwd()`, `back()` | `ycopies()`
`down()`, `up()` | `zcopies()`
`move()`, `translate()` | `move_copies()`, `line_of()`, `grid2d()`, `grid3d()`
`xrot()` | `xrot_copies()`
`yrot()` | `yrot_copies()`
`zrot()` | `zrot_copies()`
`rot()`, `rotate()` | `rot_copies()`, `arc_of()`
`xflip()` | `xflip_copy()`
`yflip()` | `yflip_copy()`
`zflip()` | `zflip_copy()`
`mirror()` | `mirror_copy()`
### Transform Distributors
Using `xcopies()`, you can make a line of evenly spaced copies of a shape
centered along the X axis. To make a line of 5 spheres, spaced every 20
units along the X axis, do:
```openscad
xcopies(20, n=5) sphere(d=10);
```
Note that the first expected argument to `xcopies()` is the spacing argument,
so you do not need to supply the `spacing=` argument name.
Similarly, `ycopies()` makes a line of evenly spaced copies centered along the
Y axis. To make a line of 5 spheres, spaced every 20 units along the Y
axis, do:
```openscad
ycopies(20, n=5) sphere(d=10);
```
And, `zcopies()` makes a line of evenly spaced copies centered along the Z axis.
To make a line of 5 spheres, spaced every 20 units along the Z axis, do:
```openscad
zcopies(20, n=5) sphere(d=10);
```
If you don't give the `n=` argument to `xcopies()`, `ycopies()` or `zcopies()`,
then it defaults to 2 (two) copies:
```openscad
xcopies(20) sphere(d=10);
```
```openscad
ycopies(20) sphere(d=10);
```
```openscad
zcopies(20) sphere(d=10);
```
If you don't know the spacing you want, but instead know how long a line you want
the copies distributed over, you can use the `l=` argument instead of the `spacing=`
argument:
```openscad
xcopies(l=100, n=5) sphere(d=10);
```
```openscad
ycopies(l=100, n=5) sphere(d=10);
```
```openscad
zcopies(l=100, n=5) sphere(d=10);
```
If you don't want the line of copies centered on the origin, you can give a starting
point, `sp=`, and the line of copies will start there. For `xcopies()`, the line of
copies will extend to the right of the starting point.
```openscad
xcopies(20, n=5, sp=[0,0,0]) sphere(d=10);
```
For `ycopies()`, the line of copies will extend to the back of the starting point.
```openscad
ycopies(20, n=5, sp=[0,0,0]) sphere(d=10);
```
For `zcopies()`, the line of copies will extend upwards from the starting point.
```openscad
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
of the line of copies with the `spacing=` argument:
```openscad
line_of(spacing=(BACK+RIGHT)*20, n=5) sphere(d=10);
```
With the `p1=` argument, you can specify the starting point of the line:
```openscad
line_of(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
line_of(p1=[0,100,0], p2=[100,0,0], n=4)
sphere(d=10);
```
You can also spread copies across a 2D area using the `grid2d()`
### Rotational Distributors
You can make six copies of a cone, rotated around a center:
```openscad
zrot_copies(n=6) yrot(90) cylinder(h=50,d1=0,d2=20);
```
To Be Completed

View File

@ -233,119 +233,3 @@ skew(szy=0.5) cube(10,center=false);
```
## Distributors
Distributors are modules that are useful for placing multiple copies of a child
across a line, area, volume, or ring. Many transforms also distributive variation.
Transforms | Related Distributors
----------------------- | ---------------------
`left()`, `right()` | `xcopies()`
`fwd()`, `back()` | `ycopies()`
`down()`, `up()` | `zcopies()`
`move()`, `translate()` | `move_copies()`, `line_of()`, `grid2d()`, `grid3d()`
`xrot()` | `xrot_copies()`
`yrot()` | `yrot_copies()`
`zrot()` | `zrot_copies()`
`rot()`, `rotate()` | `rot_copies()`, `arc_of()`
### Transform Distributors
Using `xcopies()`, you can make a line of evenly spaced copies of a shape
centered along the X axis. To make a line of 5 spheres, spaced every 20
units along the X axis, do:
```openscad
xcopies(20, n=5) sphere(d=10);
```
Note that the first expected argument to `xcopies()` is the spacing argument,
so you do not need to supply the `spacing=` argument name.
Similarly, `ycopies()` makes a line of evenly spaced copies centered along the
Y axis. To make a line of 5 spheres, spaced every 20 units along the Y
axis, do:
```openscad
ycopies(20, n=5) sphere(d=10);
```
And, `zcopies()` makes a line of evenly spaced copies centered along the Z axis.
To make a line of 5 spheres, spaced every 20 units along the Z axis, do:
```openscad
zcopies(20, n=5) sphere(d=10);
```
If you don't give the `n=` argument to `xcopies()`, `ycopies()` or `zcopies()`,
then it defaults to 2 (two) copies:
```openscad
xcopies(20) sphere(d=10);
```
```openscad
ycopies(20) sphere(d=10);
```
```openscad
zcopies(20) sphere(d=10);
```
If you don't know the spacing you want, but instead know how long a line you want
the copies distributed over, you can use the `l=` argument instead of the `spacing=`
argument:
```openscad
xcopies(l=100, n=5) sphere(d=10);
```
```openscad
ycopies(l=100, n=5) sphere(d=10);
```
```openscad
zcopies(l=100, n=5) sphere(d=10);
```
If you don't want the line of copies centered on the origin, you can give a starting
point, `sp=`, and the line of copies will start there. For `xcopies()`, the line of
copies will extend to the right of the starting point.
```openscad
xcopies(20, n=5, sp=[0,0,0]) sphere(d=10);
```
For `ycopies()`, the line of copies will extend to the back of the starting point.
```openscad
ycopies(20, n=5, sp=[0,0,0]) sphere(d=10);
```
For `zcopies()`, the line of copies will extend upwards from the starting point.
```openscad
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
of the line of copies with the `spacing=` argument:
```openscad
line_of(spacing=(BACK+RIGHT)*20, n=5) sphere(d=10);
```
With the `p1=` argument, you can specify the starting point of the line:
```openscad
line_of(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
line_of(p1=[0,100,0], p2=[100,0,0], n=4)
sphere(d=10);
```
### Rotational Distributors
You can make six copies of a cone, rotated around a center:
```openscad
zrot_copies(n=6) yrot(90) cylinder(h=50,d1=0,d2=20);
```
To Be Completed

View File

@ -95,6 +95,17 @@ function vdiv(v1, v2) = [for (i = [0:1:len(v1)-1]) v1[i]/v2[i]];
function vabs(v) = [for (x=v) abs(x)];
// Function: vfloor()
// Description:
// Returns the given vector after performing a `floor()` on all items.
function vfloor(v) = [for (x=v) floor(x)];
// Function: vceil()
// Description:
// Returns the given vector after performing a `ceil()` on all items.
function vceil(v) = [for (x=v) ceil(x)];
// Function: unit()
// Description:

View File

@ -8,7 +8,7 @@
//////////////////////////////////////////////////////////////////////
BOSL_VERSION = [2,0,229];
BOSL_VERSION = [2,0,230];
// Section: BOSL Library Version Functions