Merge pull request #348 from revarbat/revarbat_dev

Tutorial work
This commit is contained in:
Revar Desmera 2020-12-28 03:11:14 -08:00 committed by GitHub
commit 59c22a2670
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 1153 additions and 294 deletions

View file

@ -91,7 +91,7 @@ $tags_hidden = [];
// Function: anchorpt()
// Usage:
// anchor(name, pos, [dir], [rot])
// anchor(name, pos, <dir>, <rot>)
// Description:
// Creates a anchor data structure.
// Arguments:
@ -105,21 +105,21 @@ function anchorpt(name, pos=[0,0,0], orient=UP, spin=0) = [name, pos, orient, sp
// Function: attach_geom()
//
// Usage: Square/Trapezoid Geometry
// geom = attach_geom(anchor, spin, [orient], two_d, size, [size2], [shift], [cp], [offset], [anchors]);
// geom = attach_geom(anchor, spin, two_d, size, <size2>, <shift>, <cp>, <offset>, <anchors>);
// Usage: Circle/Oval Geometry
// geom = attach_geom(anchor, spin, [orient], two_d, r|d, [cp], [offset], [anchors]);
// geom = attach_geom(anchor, spin, two_d, r|d, <cp>, <offset>, <anchors>);
// Usage: 2D Path/Polygon Geometry
// geom = attach_geom(anchor, spin, [orient], two_d, path, [extent], [cp], [offset], [anchors]);
// geom = attach_geom(anchor, spin, two_d, path, <extent>, <cp>, <offset>, <anchors>);
// Usage: Cubical/Prismoidal Geometry
// geom = attach_geom(anchor, spin, [orient], size, [size2], [shift], [cp], [offset], [anchors]);
// geom = attach_geom(anchor, spin, <orient>, size, <size2>, <shift>, <cp>, <offset>, <anchors>);
// Usage: Cylindrical Geometry
// geom = attach_geom(anchor, spin, [orient], r|d, l, [cp], [axis], [offset], [anchors]);
// geom = attach_geom(anchor, spin, <orient>, r|d, l, <cp>, <axis>, <offset>, <anchors>);
// Usage: Conical Geometry
// geom = attach_geom(anchor, spin, [orient], r1|d1, r2|d2, l, [cp], [axis], [offset], [anchors]);
// geom = attach_geom(anchor, spin, <orient>, r1|d1, r2|d2, l, <cp>, <axis>, <offset>, <anchors>);
// Usage: Spheroid/Ovoid Geometry
// geom = attach_geom(anchor, spin, [orient], r|d, [cp], [offset], [anchors]);
// geom = attach_geom(anchor, spin, <orient>, r|d, <cp>, <offset>, <anchors>);
// Usage: VNF Geometry
// geom = attach_geom(anchor, spin, [orient], vnf, [extent], [cp], [offset], [anchors]);
// geom = attach_geom(anchor, spin, <orient>, vnf, <extent>, <cp>, <offset>, <anchors>);
//
// Description:
// Given arguments that describe the geometry of an attachable object, returns the internal geometry description.
@ -332,8 +332,8 @@ function attach_geom_size(geom) =
) delt
) : type == "rect"? ( //size, size2
let(
size=geom[1], size2=geom[2],
maxx = max(size.x,size2)
size=geom[1], size2=geom[2], shift=geom[3],
maxx = max(size.x,size2+abs(shift))
) [maxx, size.y]
) : type == "circle"? ( //r
let( r=geom[1] )
@ -349,7 +349,7 @@ function attach_geom_size(geom) =
// Function: attach_transform()
// Usage:
// mat = attach_transform(anchor=CENTER, spin=0, orient=UP, geom);
// mat = attach_transform(anchor, spin, orient, geom);
// Description:
// Returns the affine3d transformation matrix needed to `anchor`, `spin`, and `orient`
// the given geometry `geom` shape into position.
@ -557,12 +557,12 @@ function find_anchor(anchor, geom) =
mpt = approx(point2d(anchor),[0,0])? [maxx,0,0] : [maxx, avgy, avgz],
pos = point3d(cp) + rot(from=RIGHT, to=anchor, p=mpt)
) [anchor, pos, anchor, oang]
) : type == "rect"? ( //size, size2
) : type == "rect"? ( //size, size2, shift
let(
size=geom[1], size2=geom[2],
size=geom[1], size2=geom[2], shift=geom[3],
u = (anchor.y+1)/2,
frpt = [size.x/2*anchor.x, -size.y/2],
bkpt = [size2/2*anchor.x, size.y/2],
bkpt = [size2/2*anchor.x+shift, size.y/2],
pos = point2d(cp) + lerp(frpt, bkpt, u) + offset,
vec = unit(rot(from=BACK, to=bkpt-frpt, p=anchor),[0,1])
) [anchor, pos, vec, 0]
@ -629,21 +629,21 @@ function attachment_is_shown(tags) =
// Function: reorient()
//
// Usage: Square/Trapezoid Geometry
// reorient(anchor, spin, [orient], two_d, size, [size2], [shift], [cp], [offset], [anchors], [p]);
// reorient(anchor, spin, <orient>, two_d, size, <size2>, <shift>, <cp>, <offset>, <anchors>, <p>);
// Usage: Circle/Oval Geometry
// reorient(anchor, spin, [orient], two_d, r|d, [cp], [offset], [anchors], [p]);
// reorient(anchor, spin, <orient>, two_d, r|d, <cp>, <offset>, <anchors>, <p>);
// Usage: 2D Path/Polygon Geometry
// reorient(anchor, spin, [orient], two_d, path, [extent], [cp], [offset], [anchors], [p]);
// reorient(anchor, spin, <orient>, two_d, path, <extent>, <cp>, <offset>, <anchors>, <p>);
// Usage: Cubical/Prismoidal Geometry
// reorient(anchor, spin, [orient], size, [size2], [shift], [cp], [offset], [anchors], [p]);
// reorient(anchor, spin, <orient>, size, <size2>, <shift>, <cp>, <offset>, <anchors>, <p>);
// Usage: Cylindrical Geometry
// reorient(anchor, spin, [orient], r|d, l, [offset], [axis], [cp], [anchors], [p]);
// reorient(anchor, spin, <orient>, r|d, l, <offset>, <axis>, <cp>, <anchors>, <p>);
// Usage: Conical Geometry
// reorient(anchor, spin, [orient], r1|d1, r2|d2, l, [axis], [cp], [offset], [anchors], [p]);
// reorient(anchor, spin, <orient>, r1|d1, r2|d2, l, <axis>, <cp>, <offset>, <anchors>, <p>);
// Usage: Spheroid/Ovoid Geometry
// reorient(anchor, spin, [orient], r|d, [cp], [offset], [anchors], [p]);
// reorient(anchor, spin, <orient>, r|d, <cp>, <offset>, <anchors>, <p>);
// Usage: VNF Geometry
// reorient(anchor, spin, [orient], vnf, [extent], [cp], [offset], [anchors], [p]);
// reorient(anchor, spin, <orient>, vnf, <extent>, <cp>, <offset>, <anchors>, <p>);
//
// Description:
// Given anchor, spin, orient, and general geometry info for a managed volume, this calculates
@ -723,21 +723,21 @@ function reorient(
// Module: attachable()
//
// Usage: Square/Trapezoid Geometry
// attachable(anchor, spin, [orient], two_d, size, [size2], [shift], [cp], [offset], [anchors] ...
// attachable(anchor, spin, two_d, size, <size2>, <shift>, <cp>, <offset>, <anchors> ...
// Usage: Circle/Oval Geometry
// attachable(anchor, spin, [orient], two_d, r|d, [cp], [offset], [anchors]) ...
// attachable(anchor, spin, two_d, r|d, <cp>, <offset>, <anchors>) ...
// Usage: 2D Path/Polygon Geometry
// attachable(anchor, spin, [orient], two_d, path, [extent], [cp], [offset], [anchors] ...
// attachable(anchor, spin, two_d, path, <extent>, <cp>, <offset>, <anchors> ...
// Usage: Cubical/Prismoidal Geometry
// attachable(anchor, spin, [orient], size, [size2], [shift], [cp], [offset], [anchors] ...
// attachable(anchor, spin, <orient>, size, <size2>, <shift>, <cp>, <offset>, <anchors> ...
// Usage: Cylindrical Geometry
// attachable(anchor, spin, [orient], r|d, l, [axis], [cp], [offset], [anchors]) ...
// attachable(anchor, spin, <orient>, r|d, l, <axis>, <cp>, <offset>, <anchors>) ...
// Usage: Conical Geometry
// attachable(anchor, spin, [orient], r1|d1, r2|d2, l, [axis], [cp], [offset], [anchors]) ...
// attachable(anchor, spin, <orient>, r1|d1, r2|d2, l, <axis>, <cp>, <offset>, <anchors>) ...
// Usage: Spheroid/Ovoid Geometry
// attachable(anchor, spin, [orient], r|d, [cp], [offset], [anchors]) ...
// attachable(anchor, spin, <orient>, r|d, <cp>, <offset>, <anchors>) ...
// Usage: VNF Geometry
// attachable(anchor, spin, [orient], vnf, [extent], [cp], [offset], [anchors]) ...
// attachable(anchor, spin, <orient>, vnf, <extent>, <cp>, <offset>, <anchors>) ...
//
// Description:
// Manages the anchoring, spin, orientation, and attachments for a 3D volume or 2D area.
@ -969,8 +969,8 @@ module position(from)
// Module: attach()
// Usage:
// attach(from, [overlap]) ...
// attach(from, to, [overlap]) ...
// attach(from, <overlap>) ...
// attach(from, to, <overlap>) ...
// Description:
// Attaches children to a parent object at an anchor point and orientation.
// Attached objects will be overlapped into the parent object by a little bit,
@ -1012,7 +1012,7 @@ module attach(from, to=undef, overlap=undef, norot=false)
// Module: face_profile()
// Usage:
// face_profile(faces=[], convexity=10, r, d) ...
// face_profile(faces, r, d, <convexity>) ...
// Description:
// Given a 2D edge profile, extrudes it into a mask for all edges and corners bounding each given face.
// Arguments:
@ -1032,7 +1032,7 @@ module face_profile(faces=[], r, d, convexity=10) {
// Module: edge_profile()
// Usage:
// edge_profile([edges], [except], [convexity]) ...
// edge_profile(<edges>, <except>, <convexity>) ...
// Description:
// Takes a 2D mask shape and attaches it to the selected edges, with the appropriate orientation
// and extruded length to be `diff()`ed away, to give the edge a matching profile.
@ -1082,7 +1082,7 @@ module edge_profile(edges=EDGES_ALL, except=[], convexity=10) {
// Module: corner_profile()
// Usage:
// corner_profile([corners], [except], [convexity]) ...
// corner_profile(<corners>, <except>, <convexity>) ...
// Description:
// Takes a 2D mask shape, rotationally extrudes and converts it into a corner mask, and attaches it
// to the selected corners with the appropriate orientation. Tags it as a "mask" to allow it to be
@ -1144,7 +1144,7 @@ module corner_profile(corners=CORNERS_ALL, except=[], r, d, convexity=10) {
// Module: edge_mask()
// Usage:
// edge_mask([edges], [except]) ...
// edge_mask(<edges>, <except>) ...
// Description:
// Takes a 3D mask shape, and attaches it to the given edges, with the
// appropriate orientation to be `diff()`ed away.
@ -1186,7 +1186,7 @@ module edge_mask(edges=EDGES_ALL, except=[]) {
// Module: corner_mask()
// Usage:
// corner_mask([corners], [except]) ...
// corner_mask(<corners>, <except>) ...
// Description:
// Takes a 3D mask shape, and attaches it to the given corners, with the appropriate
// orientation to be `diff()`ed away. The 3D corner mask shape should be designed to
@ -1305,8 +1305,8 @@ module show(tags="")
// Module: diff()
// Usage:
// diff(neg, [keep]) ...
// diff(neg, pos, [keep]) ...
// diff(neg, <keep>) ...
// diff(neg, pos, <keep>) ...
// Description:
// If `neg` is given, takes the union of all children with tags that are in `neg`, and differences
// them from the union of all children with tags in `pos`. If `pos` is not given, then all items in
@ -1363,8 +1363,8 @@ module diff(neg, pos=undef, keep=undef)
// Module: intersect()
// Usage:
// intersect(a, [keep]) ...
// intersect(a, b, [keep]) ...
// intersect(a, <keep>) ...
// intersect(a, b, <keep>) ...
// Description:
// If `a` is given, takes the union of all children with tags that are in `a`, and `intersection()`s
// them with the union of all children with tags in `b`. If `b` is not given, then the union of all

View file

@ -274,7 +274,7 @@ function standard_anchors(two_d=false) = [
// Module: anchor_arrow()
// Usage:
// anchor_arrow([s], [color], [flag]);
// anchor_arrow(<s>, <color>, <flag>);
// Description:
// Show an anchor orientation arrow.
// Arguments:
@ -303,7 +303,7 @@ module anchor_arrow(s=10, color=[0.333,0.333,1], flag=true, $tags="anchor-arrow"
// Module: anchor_arrow2d()
// Usage:
// anchor_arrow2d([s], [color], [flag]);
// anchor_arrow2d(<s>, <color>, <flag>);
// Description:
// Show an anchor orientation arrow.
// Arguments:
@ -312,7 +312,7 @@ module anchor_arrow(s=10, color=[0.333,0.333,1], flag=true, $tags="anchor-arrow"
// Example:
// anchor_arrow2d(s=20);
module anchor_arrow2d(s=15, color=[0.333,0.333,1], $tags="anchor-arrow") {
noop() stroke([[0,0],[0,s]], width=s/10, endcap1="butt", endcap2="arrow2");
noop() color(color) stroke([[0,0],[0,s]], width=s/10, endcap1="butt", endcap2="arrow2");
}
@ -341,18 +341,28 @@ module show_internal_anchors(opacity=0.2) {
// Example(FlatSpin):
// cube(50, center=true) show_anchors();
module show_anchors(s=10, std=true, custom=true) {
check = assert($parent_geom != undef) 1;
two_d = attach_geom_2d($parent_geom);
if (std) {
for (anchor=standard_anchors()) {
attach(anchor) anchor_arrow(s);
for (anchor=standard_anchors(two_d=two_d)) {
if(two_d) {
attach(anchor) anchor_arrow2d(s);
} else {
attach(anchor) anchor_arrow(s);
}
}
}
if (custom) {
for (anchor=select($parent_geom,-1)) {
attach(anchor[0]) {
anchor_arrow(s, color="cyan");
recolor("black")
if(two_d) {
anchor_arrow2d(s, color="cyan");
} else {
anchor_arrow(s, color="cyan");
}
color("black")
noop($tags="anchor-arrow") {
xrot(90) {
xrot(two_d? 0 : 90) {
up(s/10) {
linear_extrude(height=0.01, convexity=12, center=true) {
text(text=anchor[0], size=s/4, halign="center", valign="center");

View file

@ -15,7 +15,7 @@ done
if [[ "$FILES" != "" ]]; then
PREVIEW_LIBS="$FILES"
else
PREVIEW_LIBS="Transforms Distributors Basic_Shapes FractalTree"
PREVIEW_LIBS="Transforms Distributors Shapes2d Shapes3d Paths FractalTree"
fi
dir="$(basename $PWD)"

View file

@ -1159,6 +1159,14 @@ module torus(
// Creates a spheroid object, with support for anchoring and attachments.
// This is a drop-in replacement for the built-in `sphere()` module.
// When called as a function, returns a [VNF](vnf.scad) for a spheroid.
// The exact triangulation of this spheroid can be controlled via the `style=`
// argument, where the value can be one of `"orig"`, `"aligned"`, `"stagger"`,
// `"octa"`, or `"icosa"`:
// - `style="orig"` constructs a sphere the same way that the OpenSCAD `sphere()` built-in does.
// - `style="aligned"` constructs a sphere where, if `$fn` is a multiple of 4, it has vertices at all axis maxima and minima. ie: its bounding box is exactly the sphere diameter in length on all three axes. This is the default.
// - `style="stagger"` forms a sphere where all faces are triangular, but the top and bottom poles have thinner triangles.
// - `style="octa"` forms a sphere by subdividing an octahedron (8-sided platonic solid). This makes more uniform faces over the entirety of the sphere, and guarantees the bounding box is the sphere diameter in size on all axes. The effective `$fn` value is quantized to a multiple of 4, though. This is used in constructing rounded corners for various other shapes.
// - `style="icosa"` forms a sphere by subdividing an icosahedron (20-sided platonic solid). This makes even more uniform faces over the entirety of the sphere. The effective `$fn` value is quantized to a multiple of 5, though.
// Arguments:
// r = Radius of the spheroid.
// d = Diameter of the spheroid.
@ -1200,21 +1208,16 @@ module spheroid(r, d, circum=false, style="aligned", anchor=CENTER, spin=0, orie
{
r = get_radius(r=r, d=d, dflt=1);
sides = segs(r);
vsides = ceil(sides/2);
attachable(anchor,spin,orient, r=r) {
if (style=="orig") {
rotate_extrude(convexity=2,$fn=sides) {
difference() {
oval(r=r, circum=circum, realign=true, $fn=sides);
left(r) square(2*r,center=true);
}
}
} else if (style=="aligned") {
rotate_extrude(convexity=2,$fn=sides) {
difference() {
oval(r=r, circum=circum, $fn=sides);
left(r) square(2*r,center=true);
}
}
merids = [ for (i=[0:1:vsides]) 90-(i+0.5)*180/(vsides+1) ];
path = [
let(a = merids[0]) [0, r*sin(a)],
for (a=merids) r * [cos(a), sin(a)],
let(a = select(merids,-1)) [0, r*sin(a)]
];
rotate_extrude(convexity=2,$fn=sides) polygon(path);
} else {
vnf = spheroid(r=r, circum=circum, style=style);
vnf_polyhedron(vnf, convexity=2);

View file

@ -1250,7 +1250,7 @@ module trapezoid(h, w1, w2, angle, shift=0, anchor=CENTER, spin=0) {
w2 = !is_undef(w2)? w2 : w1 - 2*(adj_ang_to_opp(h, angle) + shift);
assert(w1>=0 && w2>=0 && h>0, "Degenerate trapezoid geometry.");
path = [[w1/2,-h/2], [-w1/2,-h/2], [-w2/2+shift,h/2], [w2/2+shift,h/2]];
attachable(anchor,spin, two_d=true, size=[w1,h], size2=w2) {
attachable(anchor,spin, two_d=true, size=[w1,h], size2=w2, shift=shift) {
polygon(path);
children();
}
@ -1325,8 +1325,8 @@ function teardrop2d(r, d, ang=45, cap_h, anchor=CENTER, spin=0) =
// Arguments:
// r = The radius of the end circles.
// d = The diameter of the end circles.
// spread = The distance between the centers of the end circles.
// tangent = The angle in degrees of the tangent point for the joining arcs, measured away from the Y axis.
// spread = The distance between the centers of the end circles. Default: 10
// tangent = The angle in degrees of the tangent point for the joining arcs, measured away from the Y axis. Default: 30
// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#anchor). Default: `CENTER`
// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#spin). Default: `0`
// Examples(2D):

504
tutorials/Paths.md Normal file
View file

@ -0,0 +1,504 @@
# Paths, Polygons and Regions Tutorial
## Paths
A number of advanced features in BOSL2 rely on paths, which are just ordered lists of points.
First-off, some terminology:
- A 2D point is a vectors of X and Y axis position values. ie: `[3,4]` or `[7,-3]`.
- A 3D point is a vectors of X, Y and Z axis position values. ie: `[3,4,2]` or `[-7,5,3]`.
- A 2D path is simply a list of two or more 2D points. ie: `[[5,7], [1,-5], [-5,6]]`
- A 3D path is simply a list of two or more 3D points. ie: `[[5,7,-1], [1,-5,3], [-5,6,1]]`
- A polygon is a 2D (or planar 3D) path where the last point is assumed to connect to the first point.
- A region is a list of 2D polygons, where each polygon is XORed against all the others. ie: if one polygon is inside another, it makes a hole in the first polygon.
### Stroke
A path can be hard to visualize, since it's just a bunch of numbers in the source code.
One way to see the path is to pass it to `polygon()`:
```openscad-2D
path = [[0,0], [-10,10], [0,20], [10,20], [10,10]];
polygon(path);
```
Sometimes, however, it's easier to see just the path itself. For this, you can use the `stroke()` module.
At its most basic, `stroke()` just shows the path's line segments:
```openscad-2D
path = [[0,0], [-10,10], [0,20], [10,20], [10,10]];
stroke(path);
```
You can vary the width of the drawn path with the `width=` argument:
```openscad-2D
path = [[0,0], [-10,10], [0,20], [10,20], [10,10]];
stroke(path, width=3);
```
You can vary the line length along the path by giving a list of widths, one per point:
```openscad-2D
path = [[0,0], [-10,10], [0,20], [10,20], [10,10]];
stroke(path, width=[3,2,1,2,3]);
```
If a path is meant to represent a closed polygon, you can use `closed=true` to show it that way:
```openscad-2D
path = [[0,0], [-10,10], [0,20], [10,20], [10,10]];
stroke(path, closed=true);
```
The ends of the drawn path are normally capped with a "round" endcap, but there are other options:
```openscad-2D
path = [[0,0], [-10,10], [0,20], [10,20], [10,10]];
stroke(path, endcaps="round");
```
```openscad-2D
path = [[0,0], [-10,10], [0,20], [10,20], [10,10]];
stroke(path, endcaps="butt");
```
```openscad-2D
path = [[0,0], [-10,10], [0,20], [10,20], [10,10]];
stroke(path, endcaps="line");
```
```openscad-2D
path = [[0,0], [-10,10], [0,20], [10,20], [10,10]];
stroke(path, endcaps="tail");
```
```openscad-2D
path = [[0,0], [-10,10], [0,20], [10,20], [10,10]];
stroke(path, endcaps="arrow2");
```
For more standard supported endcap options, see the docs for [`stroke()`](shapes2d.scad#stroke).
The start and ending endcaps can be specified individually or separately, using `endcap1=` and `endcap2=`:
```openscad-2D
path = [[0,0], [-10,10], [0,20], [10,20], [10,10]];
stroke(path, endcap2="arrow2");
```
```openscad-2D
path = [[0,0], [-10,10], [0,20], [10,20], [10,10]];
stroke(path, endcap1="butt", endcap2="arrow2");
```
```openscad-2D
path = [[0,0], [-10,10], [0,20], [10,20], [10,10]];
stroke(path, endcap1="tail", endcap2="arrow");
```
The size of the endcaps will be relative to the width of the line where the endcap is to be placed:
```openscad-2D
path = [[0,0], [-10,10], [0,20], [10,20], [10,10]];
widths = [1, 1.25, 1.5, 1.75, 2];
stroke(path, width=widths, endcaps="arrow2");
```
If none of the standard endcaps are useful to you, it is possible to design your own, simply by
passing a path to the `endcaps=`, `endcap1=`, or `endcap2=` arguments. You may also need to give
`trim=` to tell it how far back to trim the main line, so it renders nicely. The values in the
endcap polygon, and in the `trim=` argument are relative to the line width. A value of 1 is one
line width size.
Untrimmed:
```openscad-2D
path = [[0,0], [-10,10], [0,20], [10,20], [10,10]];
dblarrow = [[0,0], [2,-3], [0.5,-2.3], [2,-4], [0.5,-3.5], [-0.5,-3.5], [-2,-4], [-0.5,-2.3], [-2,-3]];
stroke(path, endcaps=dblarrow);
```
Trimmed:
```openscad-2D
path = [[0,0], [-10,10], [0,20], [10,20], [10,10]];
dblarrow = [[0,0], [2,-3], [0.5,-2.3], [2,-4], [0.5,-3.5], [-0.5,-3.5], [-2,-4], [-0.5,-2.3], [-2,-3]];
stroke(path, trim=3.5, endcaps=dblarrow);
```
### Standard 2D Shape Polygons
BOSL2 will let you get the perimeter polygon for almost all of the standard 2D shapes simply by calling them like a function:
```openscad-2D
path = square(40, center=true);
stroke(path, closed=true, endcap2="arrow2");
```
```openscad-2D
path = rect([40,30], rounding=5, center=true);
stroke(path, closed=true, endcap2="arrow2");
```
```openscad-2D
path = trapezoid(w1=40, w2=20, h=30);
stroke(path, closed=true, endcap2="arrow2");
```
```openscad-2D
path = circle(d=50);
stroke(path, closed=true, endcap2="arrow2");
```
```openscad-2D
path = oval(d=[50,30]);
stroke(path, closed=true, endcap2="arrow2");
```
```openscad-2D
path = pentagon(d=50);
stroke(path, closed=true, endcap2="arrow2");
```
```openscad-2D
path = star(n=5, step=2, d=50);
stroke(path, closed=true, endcap2="arrow2");
```
### Arcs
Often, when you are constructing a path, you will want to add an arc. The `arc()` command lets you do that:
```openscad-2D
path = arc(r=30, angle=120);
stroke(path, endcap2="arrow2");
```
```openscad-2D
path = arc(d=60, angle=120);
stroke(path, endcap2="arrow2");
```
If you give the `N=` argument, you can control exactly how many points the arc is divided into:
```openscad-2D
path = arc(N=5, r=30, angle=120);
stroke(path, endcap2="arrow2");
```
With the `start=` argument, you can start the arc somewhere other than the X+ axis:
```openscad-2D
path = arc(start=45, r=30, angle=120);
stroke(path, endcap2="arrow2");
```
Alternatively, you can give starting and ending angles in a list in the `angle=` argument:
```openscad-2D
path = arc(angle=[120,45], r=30);
stroke(path, endcap2="arrow2");
```
The `cp=` argument lets you center the arc somewhere other than the origin:
```openscad-2D
path = arc(cp=[10,0], r=30, angle=120);
stroke(path, endcap2="arrow2");
```
The arc can also be given by three points on the arc:
```openscad-2D
pts = [[-15,10],[0,20],[35,-5]];
path = arc(points=pts);
stroke(path, endcap2="arrow2");
```
### Turtle Graphics
Another way you can create a path is using the `turtle()` command. It implements a simple path
description language that is similar to LOGO Turtle Graphics. The concept is that you have a virtial
turtle or cursor walking a path. It can "move" forward or backward, or turn "left" or "right" in
place:
```openscad-2D
path = turtle([
"move", 10,
"left", 90,
"move", 20,
"left", 135,
"move", 10*sqrt(2),
"right", 90,
"move", 10*sqrt(2),
"left", 135,
"move", 20
]);
stroke(path, endcap2="arrow2");
```
The position and the facing of the turtle/cursor updates after each command. The motion and turning
commands can also have default distances or angles given:
```openscad-2D
path = turtle([
"angle",360/6,
"length",10,
"move","turn",
"move","turn",
"move","turn",
"move","turn",
"move"
]);
stroke(path, endcap2="arrow2");
```
You can use "scale" to relatively scale up the default motion length:
```openscad-2D
path = turtle([
"angle",360/6,
"length",10,
"move","turn",
"move","turn",
"scale",2,
"move","turn",
"move","turn",
"scale",0.5,
"move"
]);
stroke(path, endcap2="arrow2");
```
Sequences of commands can be repeated using the "repeat" command:
```openscad-2D
path=turtle([
"angle",360/5,
"length",10,
"repeat",5,["move","turn"]
]);
stroke(path, endcap2="arrow2");
```
More complicated commands also exist, including those that form arcs:
```openscad-2D
path = turtle([
"move", 10,
"left", 90,
"move", 20,
"arcleft", 10, 180,
"move", 20
]);
stroke(path, endcap2="arrow2");
```
A comprehensive list of supported turtle commands can be found in the docs for [`turtle()`](shapes2d.scad#turtle).
### Transforming Paths and Polygons
To translate a path, you can just pass it to the `move()` (or up/down/left/right/fwd/back) function in the `p=` argument:
```openscad-2D
path = move([-15,-30], p=square(50,center=true));
stroke(path, closed=true, endcap2="arrow2");
```
```openscad-2D
path = fwd(30, p=square(50,center=true));
stroke(path, closed=true, endcap2="arrow2");
```
```openscad-2D
path = left(30, p=square(50,center=true));
stroke(path, closed=true, endcap2="arrow2");
```
To scale a path, you can just pass it to the `scale()` (or [xyz]scale) function in the `p=` argument:
```openscad-2D
path = scale([1.5,0.75], p=square(50,center=true));
stroke(path, closed=true, endcap2="arrow2");
```
```openscad-2D
path = xscale(1.5, p=square(50,center=true));
stroke(path, closed=true, endcap2="arrow2");
```
```openscad-2D
path = yscale(1.5, p=square(50,center=true));
stroke(path, closed=true, endcap2="arrow2");
```
To rotate a path, just can pass it to the `rot()` (or [xyz]rot) function in the `p=` argument:
```openscad-2D
path = rot(30, p=square(50,center=true));
stroke(path, closed=true, endcap2="arrow2");
```
```openscad-2D
path = zrot(30, p=square(50,center=true));
stroke(path, closed=true, endcap2="arrow2");
```
To mirror a path, just can pass it to the `mirror()` (or [xyz]flip) function in the `p=` argument:
```openscad-2D
path = mirror([1,1], p=trapezoid(w1=40, w2=10, h=25));
stroke(path, closed=true, endcap2="arrow2");
```
```openscad-2D
path = xflip(p=trapezoid(w1=40, w2=10, h=25));
stroke(path, closed=true, endcap2="arrow2");
```
```openscad-2D
path = yflip(p=trapezoid(w1=40, w2=10, h=25));
stroke(path, closed=true, endcap2="arrow2");
```
You can get raw transformation matrices for various transformations by calling them like a function without a `p=` argument:
```openscad-2D
mat = move([5,10,0]);
multmatrix(mat) square(50,center=true);
```
```openscad-2D
mat = scale([1.5,0.75,1]);
multmatrix(mat) square(50,center=true);
```
```openscad-2D
mat = rot(30);
multmatrix(mat) square(50,center=true);
```
Raw transformation matrices can be multiplied together to precalculate a compound transformation. For example, to scale a shape, then rotate it, then translate the result, you can do something like:
```openscad-2D
mat = move([5,10,0]) * rot(30) * scale([1.5,0.75,1]);
multmatrix(mat) square(50,center=true);
```
To apply a compound transformation matrix to a path, you can use the `apply()` function:
```openscad-2D
mat = move([5,10]) * rot(30, planar=true) * scale([1.5,0.75]);
path = square(50,center=true);
tpath = apply(mat, path);
stroke(tpath, endcap2="arrow2");
```
### Regions
A polygon is good to denote a single closed 2D shape with no holes in it. For more complex 2D
shapes, you will need to use regions. A region is a list of 2D polygons, where each polygon is
XORed against all the others. You can display a region using the `region()` module.
If you have a region with one polygon fully inside another, it makes a hole:
```openscad-2D
rgn = [square(50,center=true), circle(d=30)];
region(rgn);
```
If you have a region with multiple polygons that are not contained by any others, they make multiple discontiguous shapes:
```openscad-2D
rgn = [
move([-30, 20], p=square(20,center=true)),
move([ 0,-20], p=trapezoid(w1=20, w2=10, h=20)),
move([ 30, 20], p=square(20,center=true)),
];
region(rgn);
```
Region polygons can be nested abitrarily deep, in multiple discontiguous shapes:
```openscad-2D
rgn = [
for (d=[50:-10:10]) left(30, p=circle(d=d)),
for (d=[50:-10:10]) right(30, p=circle(d=d))
];
region(rgn);
```
A region with crossing polygons is somewhat poorly formed, but the intersection(s) of the polygons become holes:
```openscad-2D
rgn = [
left(15, p=circle(d=50)),
right(15, p=circle(d=50))
];
region(rgn);
```
### Boolean Region Geometry
Similarly to how OpenSCAD can perform operations like union/difference/intersection/offset on shape geometry,
the BOSL2 library lets you perform those same operations on regions:
```openscad-2D
rgn1 = [for (d=[40:-10:10]) circle(d=d)];
rgn2 = [square([60,12], center=true)];
rgn = union(rgn1, rgn2);
region(rgn);
```
```openscad-2D
rgn1 = [for (d=[40:-10:10]) circle(d=d)];
rgn2 = [square([60,12], center=true)];
rgn = difference(rgn1, rgn2);
region(rgn);
```
```openscad-2D
rgn1 = [for (d=[40:-10:10]) circle(d=d)];
rgn2 = [square([60,12], center=true)];
rgn = intersection(rgn1, rgn2);
region(rgn);
```
```openscad-2D
rgn1 = [for (d=[40:-10:10]) circle(d=d)];
rgn2 = [square([60,12], center=true)];
rgn = exclusive_or(rgn1, rgn2);
region(rgn);
```
```openscad-2D
orig_rgn = [star(n=5, step=2, d=50)];
rgn = offset(orig_rgn, r=-3, closed=true);
color("blue") region(orig_rgn);
region(rgn);
```
You can use regions for several useful things. If you wanted a grid of holes in your object that
form the shape given by a region, you can do that with `grid2d()`:
```openscad-3D
rgn = [
circle(d=100),
star(n=5,step=2,d=100,spin=90)
];
difference() {
cyl(h=5, d=120);
grid2d(size=[120,120], spacing=[4,4], inside=rgn) cyl(h=10,d=2);
}
```
You can also sweep a region through 3-space to make a solid:
```openscad-3D
$fa=1; $fs=1;
rgn = [ for (d=[50:-10:10]) circle(d=d) ];
tforms = [
for (a=[90:-5:0]) xrot(a, cp=[0,-70]),
for (a=[0:5:90]) xrot(a, cp=[0,70]),
move([0,150,-70]) * xrot(90),
];
sweep(rgn, tforms, closed=false, caps=true);
```

553
tutorials/Shapes2d.md Normal file
View file

@ -0,0 +1,553 @@
# 2D Shapes Tutorial
## Primitives
There are two built-in 2D primitive shapes that OpenSCAD provides: `square()`, and `circle()`.
The BOSL2 library provides alternative to these shapes so that they support more features,
and more ways to simply reorient them.
### 2D Squares
You can still use the built-in `square()` in the familiar ways that OpenSCAD provides:
```openscad-2D
square(100, center=false);
```
```openscad-2D
square(100, center=true);
```
```openscad-2D
square([60,40], center=true);
```
The BOSL2 library provides an enhanced equivalent to `square()` called `rect()`.
You can use it in the same way you use `square()`, but it also provides
extended functionality. For example, it allows you to round the corners:
```openscad-2D
rect([60,40], center=true, rounding=10);
```
Or chamfer them:
```openscad-2D
rect([60,40], center=true, chamfer=10);
```
You can even specify *which* corners get rounded or chamfered. If you pass a
list of four size numbers to the `rounding=` or `chamfer=` arguments, it will
give each corner its own size. In order, it goes from the back-right (quadrant I)
corner, counter-clockwise around to the back-left (quadrant II) corner, to the
forward-left (quadrant III) corner, to the forward-right (quadrant IV) corner:
```openscad-2DImgOnly
module text3d(text) color("black") text(
text=text, font="Times", size=10,
halign="center", valign="center"
);
translate([ 50, 50]) text3d("I");
translate([-50, 50]) text3d("II");
translate([-50,-50]) text3d("III");
translate([ 50,-50]) text3d("IV");
rect([90,80], center=true);
```
If a size is given as `0`, then there is no rounding and/or chamfering for
that quadrant's corner:
```openscad-2D
rect([60,40], center=true, rounding=[0,5,10,15]);
```
```openscad-2D
rect([60,40], center=true, chamfer=[0,5,10,15]);
```
You can give both `rounding=` and `chamfer=` arguments to mix rounding and
chamfering, but only if you specify per corner. If you want a rounding in
a corner, specify a 0 chamfer for that corner, and vice versa:
```openscad-2D
rect([60,40], center=true, rounding=[5,0,10,0], chamfer=[0,5,0,15]);
```
#### Anchors and Spin
Another way that `rect()` is enhanced over `square()`, is that you can anchor,
spin and attach it.
The `anchor=` argument is an alternative to `center=`, which allows more
alignment options. It takes a vector as a value, pointing roughly towards
the side or corner you want to align to the origin. For example, to align
the center of the back edge to the origin, set the anchor to `[0,1]`:
```openscad-2D
rect([60,40], anchor=[0,1]);
```
To align the front right corner to the origin:
```openscad-2D
rect([60,40], anchor=[1,-1]);
```
To center:
```openscad-2D
rect([60,40], anchor=[0,0]);
```
To make it clearer when giving vectors, there are several standard vector
constants defined:
Constant | Direction | Value
-------- | --------- | -----------
`LEFT` | X- | `[-1, 0, 0]`
`RIGHT` | X+ | `[ 1, 0, 0]`
`FRONT`/`FORWARD`/`FWD` | Y- | `[ 0,-1, 0]`
`BACK` | Y+ | `[ 0, 1, 0]`
`BOTTOM`/`BOT`/`BTM`/`DOWN` | Z- | `[ 0, 0,-1]` (3D only.)
`TOP`/`UP` | Z+ | `[ 0, 0, 1]` (3D only.)
`CENTER`/`CTR` | Centered | `[ 0, 0, 0]`
Note that even though these are 3D vectors, you can use most of them,
(except `UP`/`DOWN`, of course) for anchors in 2D shapes:
```openscad-2D
rect([60,40], anchor=BACK);
```
```openscad-2D
rect([60,40], anchor=CENTER);
```
You can add vectors together to point to corners:
```openscad-2D
rect([60,40], anchor=FRONT+RIGHT);
```
Finally, the `spin` argument can rotate the shape by a given number of degrees
clockwise:
```openscad-2D
rect([60,40], anchor=CENTER, spin=30);
```
Anchoring or centering is performed before the spin:
```openscad-2D
rect([60,40], anchor=BACK, spin=30);
```
Anchor points double as attachment points, so that you can attach other shapes:
```openscad-2D
rect([60,40],center=true)
show_anchors();
```
### 2D Circles and Ovals
The built-in `circle()` primitive can be used as expected:
```openscad-2D
circle(r=50);
```
```openscad-2D
circle(d=100);
```
```openscad-2D
circle(d=100, $fn=8);
```
The BOSL2 library also provides an enhanced equivalent of `circle()` called `oval()`.
You can use it in the same way you use `circle()`, but it also provides extended
functionality. For example, it allows more control over its size and orientation.
Since a circle in OpenSCAD can only be approximated by a regular polygon with
a number of straight sides, this can lead to size and shape inaccuracies.
To counter this, the `realign=` and `circum=` arguments are also provided.
The `realign=` argument, if set `true`, rotates the `oval()` by half the angle
between the sides:
```openscad-2D
oval(d=100, $fn=8, realign=true);
```
The `circum=` argument, if true, makes it so that the polygon forming the
`oval()` circumscribes the ideal circle instead of inscribing it.
Inscribing the ideal circle:
```openscad-2D
difference() {
circle(d=100, $fn=360);
oval(d=100, $fn=8);
}
```
Circumscribing the ideal circle:
```openscad-2D
difference() {
oval(d=100, $fn=8, circum=true);
circle(d=100, $fn=360);
}
```
The `oval()` module, as its name suggests, can be given separate X and Y radii
or diameters. To do this, just give `r=` or `d=` with a list of two radii or
diameters:
```openscad-2D
oval(r=[30,20]);
```
```openscad-2D
oval(d=[60,40]);
```
Another way that `oval()` is enhanced over `circle()`, is that you can anchor,
spin and attach it.
```openscad-2D
oval(r=50, anchor=BACK);
```
```openscad-2D
oval(r=50, anchor=FRONT+RIGHT);
```
Using spin on a circle may not make initial sense, until you remember that
anchoring is performed before spin:
```openscad-2D
oval(r=50, anchor=FRONT, spin=-30);
```
### Trapezoids
OpenSCAD doesn't provide a simple way to make 2D triangles, trapezoids, or parallelograms.
The BOSL2 library can provide all of these shapes with the `trapezoid()` module.
To make a simple triangle, just make one of the widths zero:
```openscad-2D
trapezoid(w1=50, w2=0, h=50);
```
To make a right triangle, you need to use the `shift=` argument, to shift the back of the trapezoid along the X axis:
```openscad-2D
trapezoid(w1=50, w2=0, h=50, shift=-25);
```
```openscad-2D
trapezoid(w1=50, w2=0, h=50, shift=25);
```
```openscad-2D
trapezoid(w1=0, w2=50, h=50, shift=-25);
```
```openscad-2D
trapezoid(w1=0, w2=50, h=50, shift=25);
```
You can make a trapezoid by specifying non-zero widths for both the front (`w1=`) and back (`w2=`):
```openscad-2D
trapezoid(w1=30, w2=50, h=50);
```
A parallelogram is just a matter of using the same width for front and back, with a shift along the X axis:
```openscad-2D
trapezoid(w1=50, w2=50, shift=20, h=50);
```
A quadrilateral can be made by having unequal, non-zero front (`w1=`) and back (`w2=`) widths, with the back shifted along the X axis:
```openscad-2D
trapezoid(w1=50, w2=30, shift=20, h=50);
```
You can use `anchor=` and `spin=`, just like with other attachable shapes. However, the anchor
points are based on the side angles of the faces, and may not be where you expect them:
```openscad-2D
trapezoid(w1=30, w2=50, h=50)
show_anchors();
```
### Regular N-Gons
OpenSCAD lets you make regular N-gons (pentagon, hexagon, etc) by using `circle()` with `$fn`.
While this is concise, it may be less than obvious at first glance:
```openscad-2D
circle(d=50, $fn=5);
```
The BOSL2 library has modules that are named more clearly:
```openscad-2D
pentagon(d=50);
```
```openscad-2D
hexagon(d=50);
```
```openscad-2D
octagon(d=50);
```
```openscad-2D
regular_ngon(n=7, d=50);
```
These modules also provide you with extra functionality.
They can be sized by side length:
```openscad-2D
pentagon(side=20);
```
They can be sized by circumscribed circle radius/diameter:
```openscad-2D
pentagon(ir=25);
pentagon(id=50);
```
They can be realigned by half a side's angle:
```openscad-2D
left(30) pentagon(d=50, realign=true);
right(30) pentagon(d=50, realign=false);
```
They can be rounded:
```openscad-2D
pentagon(d=50, rounding=10);
```
```openscad-2D
hexagon(d=50, rounding=10);
```
They also have somewhat different attachment behavior:
```openscad-2D
color("green") stroke(circle(d=50), closed=true);
oval(d=50,$fn=5)
attach(LEFT) color("blue") anchor_arrow2d();
```
```openscad-2D
pentagon(d=50)
attach(LEFT) color("blue") anchor_arrow2d();
```
You can use `anchor=` and `spin=`, just like with other attachable shapes. However, the anchor
points are based on where the anchor vector would intersect the side of the N-gon, and may not
be where you expect them:
```openscad-2D
pentagon(d=50)
show_anchors(custom=false);
```
N-gons also have named anchor points for their sides and tips:
```openscad-2D
pentagon(d=30)
show_anchors(std=false);
```
### Stars
The BOSL2 library has stars as a basic supported shape. They can have any number of points.
You can specify a star's shape by point count, inner and outer vertex radius/diameters:
```openscad-2D
star(n=3, id=10, d=50);
```
```openscad-2D
star(n=5, id=15, r=25);
```
```openscad-2D
star(n=10, id=30, d=50);
```
Or you can specify the star shape by point count and number of points to step:
```openscad-2D
star(n=7, step=2, d=50);
```
```openscad-2D
star(n=7, step=3, d=50);
```
If the `realign=` argument is given a true value, then the star will be rotated by half a point angle:
```openscad-2D
left(30) star(n=5, step=2, d=50);
right(30) star(n=5, step=2, d=50, realign=true);
```
The `align_tip=` argument can be given a vector so that you can align the first point in a specific direction:
```openscad-2D
star(n=5, ir=15, or=30, align_tip=BACK+LEFT)
attach("tip0") color("blue") anchor_arrow2d();
```
```openscad-2D
star(n=5, ir=15, or=30, align_tip=BACK+RIGHT)
attach("tip0") color("blue") anchor_arrow2d();
```
Similarly, the first indentation or pit can be oriented towards a specific vector with `align_pit=`:
```openscad-2D
star(n=5, ir=15, or=30, align_pit=BACK+LEFT)
attach("pit0") color("blue") anchor_arrow2d();
```
```openscad-2D
star(n=5, ir=15, or=30, align_pit=BACK+RIGHT)
attach("pit0") color("blue") anchor_arrow2d();
```
You can use `anchor=` and `spin=`, just like with other attachable shapes. However, the anchor
points are based on the furthest extents of the shape, and may not be where you expect them:
```openscad-2D
star(n=5, step=2, d=50)
show_anchors(custom=false);
```
Stars also have named anchor points for their pits, tips, and midpoints between tips:
```openscad-2D
star(n=5, step=2, d=40)
show_anchors(std=false);
```
### Teardrop2D
Often when 3D printing, you may want to make a circular hole in a vertical wall. If the hole is
too big, however, the overhang at the top of the hole can cause problems with printing on an
FDM/FFF printer. If you don't want to use support material, you can just use the teardrop shape.
The `teardrop2d()` module will let you make a 2D version of the teardrop shape, so that you can
extrude it later:
```openscad-2D
teardrop2d(r=20);
```
```openscad-2D
teardrop2d(d=50);
```
The default overhang angle is 45 degrees, but you can adjust that with the `ang=` argument:
```openscad-2D
teardrop2d(d=50, ang=30);
```
If you prefer to flatten the top of the teardrop, to encourage bridging, you can use the `cap_h=`
argument:
```openscad-2D
teardrop2d(d=50, cap_h=25);
```
```openscad-2D
teardrop2d(d=50, ang=30, cap_h=30);
```
You can use `anchor=` and `spin=`, just like with other attachable shapes. However, the anchor
points are based on the furthest extents of the shape, and may not be where you expect them:
```openscad-2D
teardrop2d(d=50, ang=30, cap_h=30)
show_anchors();
```
### Glued Circles
A more unusal shape that BOSL2 provides is Glued Circles. It's basically a pair of circles,
connected by what looks like a gloopy glued miniscus:
```openscad-2D
glued_circles(d=30, spread=40);
```
The `r=`/`d=` arguments can specify the radius or diameter of the two circles:
```openscad-2D
glued_circles(r=20, spread=45);
```
```openscad-2D
glued_circles(d=40, spread=45);
```
The `spread=` argument specifies the distance between the centers of the two circles:
```openscad-2D
glued_circles(d=30, spread=30);
```
```openscad-2D
glued_circles(d=30, spread=40);
```
The `tangent=` argument gives the angle of the tangent of the meniscus on the two circles:
```openscad-2D
glued_circles(d=30, spread=30, tangent=45);
```
```openscad-2D
glued_circles(d=30, spread=30, tangent=20);
```
```openscad-2D
glued_circles(d=30, spread=30, tangent=-20);
```
One useful thing you can do is to string a few `glued_circle()`s in a line then extrude them to make a ribbed wall:
```openscad-3D
$fn=36; s=10;
linear_extrude(height=50,convexity=16,center=true)
xcopies(s*sqrt(2),n=3)
glued_circles(d=s, spread=s*sqrt(2), tangent=45);
```
You can use `anchor=` and `spin=`, just like with other attachable shapes. However, the anchor
points are based on the furthest extents of the shape, and may not be where you expect them:
```openscad-2D
glued_circles(d=40, spread=40, tangent=45)
show_anchors();
```

View file

@ -1,233 +1,13 @@
# Basic Shapes Tutorial
## Primitives
There are 5 built-in primitive shapes that OpenSCAD provides.
`square()`, `circle()`, `cube()`, `cylinder()`, and `sphere()`.
The BOSL2 library extends or provides alternative to these shapes so
There are 3 built-in 3D primitive shapes that OpenSCAD provides: `cube()`, `cylinder()`,
and `sphere()`. The BOSL2 library extends and provides alternative to these shapes so
that they support more features, and more ways to simply reorient them.
### 2D Squares
You can still use the built-in `square()` in the familiar ways that OpenSCAD provides:
```openscad-2D
square(100, center=false);
```
```openscad-2D
square(100, center=true);
```
```openscad-2D
square([60,40], center=true);
```
The BOSL2 library provides an enhanced equivalent to `square()` called `rect()`.
You can use it in the same way you use `square()`, but it also provides
extended functionality. For example, it allows you to round the corners:
```openscad-2D
rect([60,40], center=true, rounding=10);
```
Or chamfer them:
```openscad-2D
rect([60,40], center=true, chamfer=10);
```
You can even specify *which* corners get rounded or chamfered. If you pass a
list of four size numbers to the `rounding=` or `chamfer=` arguments, it will
give each corner its own size. In order, it goes from the back-right (quadrant I)
corner, counter-clockwise around to the back-left (quadrant II) corner, to the
forward-left (quadrant III) corner, to the forward-right (quadrant IV) corner:
```openscad-2DImgOnly
module text3d(text) color("black") text(
text=text, font="Times", size=10,
halign="center", valign="center"
);
translate([ 50, 50]) text3d("I");
translate([-50, 50]) text3d("II");
translate([-50,-50]) text3d("III");
translate([ 50,-50]) text3d("IV");
rect([90,80], center=true);
```
If a size is given as `0`, then there is no rounding and/or chamfering for
that quadrant's corner:
```openscad-2D
rect([60,40], center=true, rounding=[0,5,10,15]);
```
```openscad-2D
rect([60,40], center=true, chamfer=[0,5,10,15]);
```
You can give both `rounding=` and `chamfer=` arguments to mix rounding and
chamfering, but only if you specify per corner. If you want a rounding in
a corner, specify a 0 chamfer for that corner, and vice versa:
```openscad-2D
rect([60,40], center=true, rounding=[5,0,10,0], chamfer=[0,5,0,15]);
```
#### Anchors and Spin
Another way that `rect()` is enhanced over `square()`, is that you can anchor,
spin and attach it.
The `anchor=` argument is an alternative to `center=`, which allows more
alignment options. It takes a vector as a value, pointing roughly towards
the side or corner you want to align to the origin. For example, to align
the center of the back edge to the origin, set the anchor to `[0,1]`:
```openscad-2D
rect([60,40], anchor=[0,1]);
```
To align the front right corner to the origin:
```openscad-2D
rect([60,40], anchor=[1,-1]);
```
To center:
```openscad-2D
rect([60,40], anchor=[0,0]);
```
To make it clearer when giving vectors, there are several standard vector
constants defined:
Constant | Direction | Value
-------- | --------- | -----------
`LEFT` | X- | `[-1, 0, 0]`
`RIGHT` | X+ | `[ 1, 0, 0]`
`FRONT`/`FORWARD`/`FWD` | Y- | `[ 0,-1, 0]`
`BACK` | Y+ | `[ 0, 1, 0]`
`BOTTOM`/`BOT`/`BTM`/`DOWN` | Z- | `[ 0, 0,-1]` (3D only.)
`TOP`/`UP` | Z+ | `[ 0, 0, 1]` (3D only.)
`CENTER`/`CTR` | Centered | `[ 0, 0, 0]`
Note that even though these are 3D vectors, you can use most of them,
(except `UP`/`DOWN`, of course) for anchors in 2D shapes:
```openscad-2D
rect([60,40], anchor=BACK);
```
```openscad-2D
rect([60,40], anchor=CENTER);
```
You can add vectors together to point to corners:
```openscad-2D
rect([60,40], anchor=FRONT+RIGHT);
```
Finally, the `spin` argument can rotate the shape by a given number of degrees
clockwise:
```openscad-2D
rect([60,40], anchor=CENTER, spin=30);
```
Anchoring or centering is performed before the spin:
```openscad-2D
rect([60,40], anchor=BACK, spin=30);
```
### 2D Circles
The built-in `circle()` primitive can be used as expected:
```openscad-2D
circle(r=50);
```
```openscad-2D
circle(d=100);
```
```openscad-2D
circle(d=100, $fn=8);
```
The BOSL2 library provides an enhanced equivalent of `circle()` called `oval()`.
You can use it in the same way you use `circle()`, but it also provides
extended functionality. For example, it allows more control over its size and
orientation.
Since a circle in OpenSCAD can only be approximated by a regular polygon with
a number of straight sides, this can lead to size and shape inaccuracies.
To counter this, the `realign=` and `circum=` arguments are also provided.
The `realign=` argument, if set `true`, rotates the `oval()` by half the angle
between the sides:
```openscad-2D
oval(d=100, $fn=8, realign=true);
```
The `circum=` argument, if true, makes it so that the polygon forming the
`oval()` circumscribes the ideal circle instead of inscribing it.
Inscribing the ideal circle:
```openscad-2D
difference() {
circle(d=100, $fn=360);
oval(d=100, $fn=8);
}
```
Circumscribing the ideal circle:
```openscad-2D
difference() {
oval(d=100, $fn=8, circum=true);
circle(d=100, $fn=360);
}
```
The `oval()` module, as its name suggests, can be given separate X and Y radii
or diameters. To do this, just give `r=` or `d=` with a list of two radii or
diameters:
```openscad-2D
oval(r=[30,20]);
```
```openscad-2D
oval(d=[60,40]);
```
Another way that `oval()` is enhanced over `circle()`, is that you can anchor,
spin and attach it.
```openscad-2D
oval(r=50, anchor=BACK);
```
```openscad-2D
oval(r=50, anchor=FRONT+RIGHT);
```
Using spin on a circle may not make initial sense, until you remember that
anchoring is performed before spin:
```openscad-2D
oval(r=50, anchor=FRONT, spin=-30);
```
### 3D Cubes
BOSL2 overrides the built-in `cube()` module. It still can be used as you
expect from the built-in:
BOSL2 overrides the built-in `cube()` module. It still can be used as you expect from the built-in:
```openscad-3D
cube(100);
@ -243,7 +23,7 @@ expect from the built-in:
It is also enhanced to allow you to anchor, spin, orient, and attach it.
You can use `anchor=` similarly to how you use it with `square()` or `rect()`,
You can use `anchor=` similarly to how you use it with `rect()` or `oval()`,
except you can also anchor vertically in 3D, allowing anchoring to faces, edges,
and corners:
@ -546,11 +326,20 @@ The "stagger" style will stagger the triangulation of the vertical rows:
spheroid(d=100, style="stagger", $fn=20);
```
The "icosa"` style will make for roughly equal-sized triangles for the entire
sphere surface:
The "icosa" style will make for roughly equal-sized triangles for the entire
sphere surface, based on subdividing an icosahedron. This style will round the
effective `$fn` to a multiple of 5 when constructing the spheroid:
```openscad-3D
spheroid(d=100, style="icosa", $fn=20);
```
The "octa" style will also make for roughly equal-sized triangles for the entire
sphere surface, but based on subdividing an octahedron. This is useful in that it
guarantees vertices at the axis extrema. This style will round the effective `$fn`
to a multiple of 4 when constructing the spheroid:
```openscad-3D
spheroid(d=100, style="octa", $fn=20);
```

View file

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