Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ The BOSL2 library is an enormous library that provides many different kinds of c
* **Building Blocks.** OpenSCAD provides cubes, cones and spheres. The BOSL2 library extends this to provide different kinds of prisms, tubes, and other abstract geometrical building blocks. In many cases the BOSL2 objects include options to round their edges. Basic objects have extensions like the ability to specify the **inner** radius of a circle to create holes with a guaranteed minimum size.
* **Texturing.** Many kinds of objects can be created with [textures](https://github.com/BelfrySCAD/BOSL2/wiki/skin.scad#section-texturing) applied. This can create knurling, but it can do much more than that. A texture can be any repeating pattern, and applying a texture can actually replace the base object with something different based on repeating copies of the texture element. A texture can also be an image; using texturing you can emboss an arbitrary image onto your model.
* **Parts library.** The parts library includes many useful specific functional parts including [gears](https://github.com/BelfrySCAD/BOSL2/wiki/gears.scad), generic [threading](https://github.com/BelfrySCAD/BOSL2/wiki/threading.scad#section-generic-threading), and specific threading to match plastic [bottles](https://github.com/BelfrySCAD/BOSL2/wiki/bottlecaps.scad), [pipe fittings](https://github.com/BelfrySCAD/BOSL2/wiki/threading.scad#module-npt_threaded_rod), or standard [screws.](https://github.com/BelfrySCAD/BOSL2/wiki/screws.scad) Also included are [clips](https://github.com/BelfrySCAD/BOSL2/wiki/joiners.scad#section-tension-clips), [hinges](https://github.com/BelfrySCAD/BOSL2/wiki/hinges.scad), and [dovetail joints.](https://github.com/BelfrySCAD/BOSL2/wiki/joiners.scad#section-dovetails)
* **Shorthands.** The shorthands make your code a little shorter, and more importantly, they can make it significantly easier to read. Compare `up(z)` to `translate([0,0,z])`. The shorthands include operations for creating [copies of objects](https://github.com/BelfrySCAD/BOSL2/wiki/distributors.scad) and for applying [transformations](https://github.com/BelfrySCAD/BOSL2/wiki/transforms.scad) to objects, including [rot()](https://github.com/BelfrySCAD/BOSL2/wiki/transforms.scad#functionmodule-rot) which extends rotate in some useful ways that are not easy to do directly.
* **Shorthands.** The shorthands make your code a little shorter, and more importantly, they can make it significantly easier to read. Compare `up(z)` to `translate([0,0,z])`. The shorthands include operations for creating [copies of objects](https://github.com/BelfrySCAD/BOSL2/wiki/distributors.scad) and for applying [transformations](https://github.com/BelfrySCAD/BOSL2/wiki/transforms.scad) to objects, including [rot()](https://github.com/BelfrySCAD/BOSL2/wiki/transforms.scad#functionmodule-rot) which extends `rotate()` in some useful ways that are not easy to do directly.
* **Geometrical operations on data.** In OpenSCAD, geometrical operations happen on geometry, and information can never be extracted from geometry. The BOLS2 library provides operations on 2d point lists (called "paths" or "regions") to make [rounded paths](https://github.com/BelfrySCAD/BOSL2/wiki/rounding.scad#function-round_corners) from ones with corners or do operations like [intersection](https://github.com/BelfrySCAD/BOSL2/wiki/regions.scad#functionmodule-intersection) and [offset](https://github.com/BelfrySCAD/BOSL2/wiki/regions.scad#function-offset). It can also do some limited operations on three dimensional data.
* **Programming aids.** The library provides basic [mathematical operations](https://github.com/BelfrySCAD/BOSL2/wiki/math.scad) including solutions to [linear systems of equations](https://github.com/BelfrySCAD/BOSL2/wiki/linalg.scad#function-linear_solve) and [generic](https://github.com/BelfrySCAD/BOSL2/wiki/math.scad#function-root_find) and [polynomial](https://github.com/BelfrySCAD/BOSL2/wiki/math.scad#function-real_roots) numerical root finding. It provides [geometrical operations](https://github.com/BelfrySCAD/BOSL2/wiki/geometry.scad) like [line intersection](https://github.com/BelfrySCAD/BOSL2/wiki/geometry.scad#function-line_intersection) or [circle intersection](https://github.com/BelfrySCAD/BOSL2/wiki/geometry.scad#function-circle_circle_intersection), [coordinate transformations](https://github.com/BelfrySCAD/BOSL2/wiki/coords.scad), [string manipulation,](https://github.com/BelfrySCAD/BOSL2/wiki/strings.scad) and [list processing](https://github.com/BelfrySCAD/BOSL2/wiki/lists.scad).

Expand Down
18 changes: 14 additions & 4 deletions attachments.scad
Original file line number Diff line number Diff line change
Expand Up @@ -4233,12 +4233,22 @@ function _find_anchor(anchor, geom)=
approx(anchor,[0,0])? [anchor, cp, BACK, 0] : // CENTER anchors anchor on cp, "origin" anchors on [0,0]
let(
rgn = force_region(geom[1]),
rpts = rot(from=anchor, to=RIGHT, p=flatten(rgn)),
indexed_pts = [for(i=idx(rgn), j=idx(rgn[i])) [i,j,rgn[i][j]]],
rpts = rot(from=anchor, to=RIGHT, p=column(indexed_pts,2)),
maxx = max(column(rpts,0)),
ys = [for (pt=rpts) if (approx(pt.x, maxx)) pt.y],
index = [for (i=idx(rpts)) if (approx(rpts[i].x, maxx)) i],
ys = [for (i=index) rpts[i].y],
midy = (min(ys)+max(ys))/2,
pos = rot(from=RIGHT, to=anchor, p=[maxx,midy])
) [anchor, pos, unit(anchor,BACK), 0]
pos = rot(from=RIGHT, to=anchor, p=[maxx,midy]),
dir = len(ys) > 1 ? [unit(anchor)]
: let(
path = rgn[indexed_pts[index[0]][0]],
ctr = indexed_pts[index[0]][1],
corner = select(path, [ctr-1,ctr,ctr+1]),
normal = unit(unit(corner[0]-corner[1])+unit(corner[2]-corner[1]))
)
[is_polygon_clockwise(path) ? -normal : normal, vector_angle(corner)]
) [anchor, pos, dir[0], 0, if(len(dir)>1) [["corner_angle",dir[1]]]]
) : type=="extrusion_extent" || type=="extrusion_isect" ? ( // extruded region
assert(in_list(anchor.z,[-1,0,1]), "The Z component of an anchor for an extruded 2D shape must be -1, 0, or 1.")
let(
Expand Down
13 changes: 12 additions & 1 deletion skin.scad
Original file line number Diff line number Diff line change
Expand Up @@ -2037,7 +2037,18 @@ module spiral_sweep(poly, h, r, turns=1, taper, r1, r2, d, d1, d2, internal=fals
// knot_path = [ for (i=[0:k-1]) knot(360*i/k/gcd(p,q),R,r,p,q) ];
// normals = [ for (i=[0:k-1]) knot_normal(360*i/k/gcd(p,q),R,r,p,q) ];
// path_sweep(ushape,knot_path,normal=normals, method="manual", closed=true);
// Example(NoScales): You can request the transformations and manipulate them before passing them on to sweep. Here we construct a tube that changes scale by first generating the transforms and then applying the scale factor and connecting the inside and outside. The wall thickness varies because it is produced by scaling.
// Example(Med,NoScales,VPR=[355.50,0.00,355.60],VPD=140.00,VPT=[0.00,0.00,0.00],): The left hand example uses the automatically computed derivatives. The example on the right uses a user-supplied tangent to ensure that the ends are aligned with the coordinate system. Even with a simple circular arc you may find that the ends are not aligned as expedted by the automatically computed approximate tangent vectors.
// $fa=1; $fs=0.5;
// theta_range=[180:2:450];
// path = [for (theta = theta_range)
// polar_to_xy(0.5*PHI^(2*theta/180), theta)];
// tangents = [for (theta = theta_range)
// [-sin(theta), cos(theta), 0]];
// circ = circle(1, $fn=32);
// path_sweep(circ, path);
// right(8)
// path_sweep(circ, path, tangent=tangents);
// Example(NoScales): You can request the transformations and manipulate them before passing them on to sweep. Here we construct a tube that changes scale by first generating the transforms and then applying the scale factor and connecting the inside and outside. Note that the wall thickness varies because it is produced by scaling.
// shape = star(n=5, r=10, ir=5);
// rpath = arc(25, points=[[29,6,-4], [3,4,6], [1,1,7]]);
// trans = path_sweep(shape, rpath, transforms=true);
Expand Down
127 changes: 127 additions & 0 deletions tutorials/Attachment-Align.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
# Aligning children with align()

You may have noticed that with position() and orient(), specifying the
child anchors to position objects flush with their parent can be
annoying, or sometimes even tricky. You can simplify this task by
using the align() module. This module positions children on faces
of a parent and aligns to edges or corners, while picking the correct anchor points on
the children so that the children line up correctly with the
parent. Like `position()`, align does not change the orientation of
the child object.

In the simplest case, if you want to place a child on the RIGHT side
of its parent, you need to anchor the child to its LEFT anchor:

```openscad-3D
include<BOSL2/std.scad>
cuboid([50,40,15])
position(RIGHT)
color("lightblue")cuboid(5,anchor=LEFT);
```

When you use align() it automatically determines the correct anchor to
use for the child and this anchor overrides any anchor specified to
the child: any anchor you specify for the child is ignored.

```openscad-3D
include<BOSL2/std.scad>
cuboid([50,40,15])
align(RIGHT)
color("lightblue")cuboid(5);
```

To place the child on top of the parent in the corner you can do use
align as shown below instead of specifying the RIGHT+FRONT+BOT anchor
with position():

```openscad-3D
include<BOSL2/std.scad>
cuboid([50,40,15])
align(TOP,RIGHT+FRONT)
color("lightblue")prismoid([10,5],[7,4],height=4);
```

Both position() and align() can accept a list of anchor locations and
makes several copies of the children, but
if you want the children positioned flush, each copy
requires a different anchor, so it is impossible to do this with a
single call to position(), but easily done using align():

```openscad-3D
include<BOSL2/std.scad>
cuboid([50,40,15])
align(TOP,[RIGHT,LEFT])
color("lightblue")prismoid([10,5],[7,4],height=4);
```

If you want the children close to the edge but not actually flush you
can use the `inset=` parameter of align to achieve this:

```openscad-3D
include<BOSL2/std.scad>
cuboid([50,40,15])
align(TOP,[FWD,RIGHT,LEFT,BACK],inset=3)
color("lightblue")prismoid([10,5],[7,4],height=4);
```

If you spin the children then align will still do the right thing

```openscad-3D
include<BOSL2/std.scad>
cuboid([50,40,15])
align(TOP,[RIGHT,LEFT])
color("lightblue")prismoid([10,5],[7,4],height=4,spin=90);
```

If you orient the object DOWN it will be attached from its top anchor,
correctly aligned.

```openscad-3D
include<BOSL2/std.scad>
cuboid([50,40,15])
align(TOP,RIGHT)
color("lightblue")prismoid([10,5],[7,4],height=4,orient=DOWN);
```

Note that align() never changes the orientation of the children. If
you put the blue prismoid on the right side the anchors line up but
the edges of the child and parent don't.

```openscad-3D
include<BOSL2/std.scad>
prismoid(50,30,25){
align(RIGHT,TOP)
color("lightblue")prismoid([10,5],[7,4],height=4);
}
```

If you apply spin that is not a multiple of 90 degrees then alignment
will line up the corner

```openscad-3D
include<BOSL2/std.scad>
cuboid([50,40,15])
align(TOP,RIGHT)
color("lightblue")cuboid(8,spin=33);
```

You can also attach objects to a cylinder. If you use the usual cubic
anchors then a cube will attach on a face as shown here:

```openscad-3D
include<BOSL2/std.scad>
cyl(h=20,d=10,$fn=128)
align(RIGHT,TOP)
color("lightblue")cuboid(5);
```

But with a cylinder you can choose an arbitrary horizontal angle for
the anchor. If you do this, similar to the case of arbitrary spin,
the cube will attach on the nearest corner.

```openscad-3D
include<BOSL2/std.scad>
cyl(h=20,d=10,$fn=128)
align([1,.3],TOP)
color("lightblue")cuboid(5);
```
Loading