1# 2D Shapes Tutorial
2
3<!-- TOC -->
4
5## Primitives
6There are two built-in 2D primitive shapes that OpenSCAD provides: `square()`, and `circle()`.
7You can still use them in the familiar ways that OpenSCAD provides:
8
9```openscad-2D
10include <BOSL2/std.scad>
11square([60,40], center=true);
12```
13
14```openscad-2D
15include <BOSL2/std.scad>
16circle(r=50);
17```
18
19```openscad-2D
20include <BOSL2/std.scad>
21circle(d=100, $fn=8);
22```
23
24These modules have also been enhanced in the BOSL2 library in three ways: Anchoring, spin, and
25attachability.
26
27#### Anchoring:
28When you create a `square()`, you can specify what corner or side will be anchored at the
29origin. This is used in place of the `center=` argument, and is more flexible. The `anchor=`
30argument takes a vector as a value, pointing roughly towards the side or corner you
31want to align to the origin. For example, to align the center of the back edge to the
32origin, set the anchor to `[0,1]`:
33
34```openscad-2D
35include <BOSL2/std.scad>
36square([60,40], anchor=[0,1]);
37```
38
39To align the front right corner to the origin:
40
41```openscad-2D
42include <BOSL2/std.scad>
43square([60,40], anchor=[1,-1]);
44```
45
46To center:
47
48```openscad-2D
49include <BOSL2/std.scad>
50square([60,40], anchor=[0,0]);
51```
52
53To make it clearer when giving vectors, there are several standard vector constants defined:
54
55Constant | Direction | Value
56-------- | --------- | -----------
57`LEFT` | X- | `[-1, 0, 0]`
58`RIGHT` | X+ | `[ 1, 0, 0]`
59`FRONT`/`FORWARD`/`FWD` | Y- | `[ 0,-1, 0]`
60`BACK` | Y+ | `[ 0, 1, 0]`
61`BOTTOM`/`BOT`/`BTM`/`DOWN` | Z- | `[ 0, 0,-1]` (3D only.)
62`TOP`/`UP` | Z+ | `[ 0, 0, 1]` (3D only.)
63`CENTER`/`CTR` | Centered | `[ 0, 0, 0]`
64
65Note that even though these are 3D vectors, you can use most of them,
66(except `UP`/`DOWN`, of course) for anchors in 2D shapes:
67
68```openscad-2D
69include <BOSL2/std.scad>
70square([60,40], anchor=BACK);
71```
72
73```openscad-2D
74include <BOSL2/std.scad>
75square([60,40], anchor=CENTER);
76```
77
78You can add vectors together to point to corners:
79
80```openscad-2D
81include <BOSL2/std.scad>
82square([60,40], anchor=FRONT+RIGHT);
83```
84
85For `circle()`, the anchor vector can point at any part of the circle perimeter:
86
87```openscad-2D
88include <BOSL2/std.scad>
89circle(d=50, anchor=polar_to_xy(1,150));
90```
91
92Note that the radius does not matter for the anchor because only the
93anchor's direction affects the result. You can see the typical anchor
94points by giving `show_anchors()` as a child of the shape:
95
96```openscad-2D
97include <BOSL2/std.scad>
98square([60,40], center=true)
99 show_anchors();
100```
101
102```openscad-2D
103include <BOSL2/std.scad>
104circle(d=50)
105 show_anchors();
106```
107
108#### Spin:
109The second way that `square()` and `circle()` have been enhanced is with spin. When you create
110the shape, you can spin it in place with the `spin=` argument. You just pass it a number of
111degrees to rotate clockwise:
112
113```openscad-2D
114include <BOSL2/std.scad>
115square([60,40], anchor=CENTER, spin=30);
116```
117
118Anchoring or centering is performed before the spin:
119
120```openscad-2D
121include <BOSL2/std.scad>
122square([60,40], anchor=BACK, spin=30);
123```
124
125For circles, spin can be useful when `$fn=` is also given:
126
127```openscad-2D
128include <BOSL2/std.scad>
129circle(d=50, $fn=6, spin=15);
130```
131
132Since anchoring is performed before spin, you can use them together to spin around the anchor:
133
134```openscad-2D
135include <BOSL2/std.scad>
136circle(d=50, $fn=6, anchor=LEFT, spin=15);
137```
138
139
140#### Attachability:
141
142The third way `square()` and `circle()` have been enhanced is that you can attach them together
143at anchoring points in various ways. This is done by making one shape a child of the shape
144you want to attach to. By default, just making one shape a child of the other will position
145the child shape at the center of the parent shape.
146
147```openscad-2D
148include <BOSL2/std.scad>
149square(50, center=true)
150 #square(50, spin=45, center=true);
151```
152
153```openscad-2D
154include <BOSL2/std.scad>
155square(50, center=true)
156 #square([20,40], anchor=FWD);
157```
158
159By adding the `position()` module, you can position the child at any anchorpoint on the parent:
160
161```openscad-2D
162include <BOSL2/std.scad>
163square(50, center=true)
164 position(BACK)
165 #square(25, spin=45, center=true);
166```
167
168```openscad-2D
169include <BOSL2/std.scad>
170square(50, center=true)
171 position(FWD+RIGHT)
172 #square(25, spin=45, center=true);
173```
174
175```openscad-2D
176include <BOSL2/std.scad>
177circle(d=50)
178 position(polar_to_xy(1,60))
179 #circle(d=10);
180```
181
182
183Anchorpoints aren't just positions on the parent, though. They also have an orientation. In most
184cases, the orientation of an anchorpoint is outward away from the face of the wall, generally away
185from the center of the shape. You can see this with the `show_anchors()` module:
186
187```openscad-2D
188include <BOSL2/std.scad>
189square(50, center=true)
190 show_anchors();
191```
192
193```openscad-2D
194include <BOSL2/std.scad>
195circle(d=50)
196 show_anchors();
197```
198
199If you want to orient the child to match the orientation of an anchorpoint, you can use the `orient()`
200module. It does not position the child. It only rotates it:
201
202```openscad-2D
203include <BOSL2/std.scad>
204square(50, center=true)
205 orient(anchor=LEFT)
206 #square([10,40], anchor=FWD);
207```
208
209```openscad-2D
210include <BOSL2/std.scad>
211square(50, center=true)
212 orient(anchor=FWD)
213 #square([10,40], anchor=FWD);
214```
215
216```openscad-2D
217include <BOSL2/std.scad>
218square(50, center=true)
219 orient(anchor=RIGHT)
220 #square([10,40], anchor=FWD);
221```
222
223```openscad-2D
224include <BOSL2/std.scad>
225circle(d=50)
226 orient(polar_to_xy(1,30))
227 #square([10,40], anchor=FWD);
228```
229
230You can use `position()` and `orient()` together to both position and orient to an anchorpoint:
231
232```openscad-2D
233include <BOSL2/std.scad>
234square(50, center=true)
235 position(RIGHT+BACK)
236 orient(anchor=RIGHT+BACK)
237 #square([10,40], anchor=FWD);
238```
239
240```openscad-2D
241include <BOSL2/std.scad>
242circle(d=50)
243 position(polar_to_xy(1,30))
244 orient(polar_to_xy(1,30))
245 #square([10,40], anchor=FWD);
246```
247
248But it's simpler to just use the `attach()` module to do both at once:
249
250```openscad-2D
251include <BOSL2/std.scad>
252square(50, center=true)
253 attach(LEFT+BACK)
254 #square([10,40], anchor=FWD);
255```
256
257```openscad-2D
258include <BOSL2/std.scad>
259circle(d=50)
260 attach(polar_to_xy(1,30))
261 #square([10,40], center=true);
262```
263
264Instead of specifying the `anchor=` in the child, you can pass a second argument to `attach()`
265that tells it which side of the child to attach to the parent:
266
267```openscad-2D
268include <BOSL2/std.scad>
269square([10,50], center=true)
270 attach(BACK, LEFT)
271 #square([10,40], center=true);
272```
273
274```openscad-2D
275include <BOSL2/std.scad>
276circle(d=50)
277 attach(polar_to_xy(1,30), LEFT)
278 #square([10,40], center=true);
279```
280
281
282
283#### Rectangles
284
285The BOSL2 library provides an alternative to `square()`, that support more features. It is
286called `rect()`. You can use it in the same way you use `square()`, but it also provides
287extended functionality. For example, it allows you to round the corners:
288
289```openscad-2D
290include <BOSL2/std.scad>
291rect([60,40], rounding=10);
292```
293
294Or chamfer them:
295
296```openscad-2D
297include <BOSL2/std.scad>
298rect([60,40], chamfer=10);
299```
300
301You can even specify *which* corners get rounded or chamfered. If you pass a
302list of four size numbers to the `rounding=` or `chamfer=` arguments, it will
303give each corner its own size. In order, it goes from the back-right (quadrant I)
304corner, counter-clockwise around to the back-left (quadrant II) corner, to the
305forward-left (quadrant III) corner, to the forward-right (quadrant IV) corner:
306
307```openscad-2DImgOnly
308include <BOSL2/std.scad>
309module text3d(text) color("black") text(
310 text=text, font="Times", size=10,
311 halign="center", valign="center"
312);
313translate([ 50, 50]) text3d("I");
314translate([-50, 50]) text3d("II");
315translate([-50,-50]) text3d("III");
316translate([ 50,-50]) text3d("IV");
317rect([90,80]);
318```
319
320If a size is given as `0`, then there is no rounding and/or chamfering for
321that quadrant's corner:
322
323```openscad-2D
324include <BOSL2/std.scad>
325rect([60,40], rounding=[0,5,10,15]);
326```
327
328```openscad-2D
329include <BOSL2/std.scad>
330rect([60,40], chamfer=[0,5,10,15]);
331```
332
333You can give both `rounding=` and `chamfer=` arguments to mix rounding and
334chamfering, but only if you specify per corner. If you want a rounding in
335a corner, specify a 0 chamfer for that corner, and vice versa:
336
337```openscad-2D
338include <BOSL2/std.scad>
339rect([60,40], rounding=[5,0,10,0], chamfer=[0,5,0,15]);
340```
341
342#### Ellipses
343
344The BOSL2 library also provides an enhanced equivalent of `circle()` called `ellipse()`.
345You can use it in the same way you use `circle()`, but it also provides extended
346functionality. For example, it allows more control over its size.
347
348Since a circle in OpenSCAD can only be approximated by a regular polygon with a number
349of straight sides, this can lead to size and shape inaccuracies. To counter this, the
350`realign=` and `circum=` arguments are also provided.
351
352The `realign=` argument, if set `true`, rotates the `ellipse()` by half the angle
353between the polygon sides:
354
355```openscad-2D
356include <BOSL2/std.scad>
357ellipse(d=100, $fn=8);
358#ellipse(d=100, $fn=8, realign=true);
359```
360
361The `circum=` argument, if true, makes it so that the polygon forming the
362`ellipse()` circumscribes the ideal circle instead of inscribing it.
363
364Inscribing the ideal circle:
365
366```openscad-2D
367include <BOSL2/std.scad>
368color("green") ellipse(d=100, $fn=360);
369ellipse(d=100, $fn=6);
370```
371
372Circumscribing the ideal circle:
373
374```openscad-2D
375include <BOSL2/std.scad>
376ellipse(d=100, $fn=6, circum=true);
377color("green") ellipse(d=100, $fn=360);
378```
379
380The `ellipse()` module, as its name suggests, can be given separate X and Y radii
381or diameters. To do this, just give `r=` or `d=` with a list of two radii or
382diameters:
383
384```openscad-2D
385include <BOSL2/std.scad>
386ellipse(r=[30,20]);
387```
388
389```openscad-2D
390include <BOSL2/std.scad>
391ellipse(d=[60,40]);
392```
393
394Like `circle()`, you can anchor, spin and attach `ellipse()` shapes:
395
396```openscad-2D
397include <BOSL2/std.scad>
398ellipse(d=50, anchor=BACK);
399```
400
401```openscad-2D
402include <BOSL2/std.scad>
403ellipse(d=50, anchor=FRONT+RIGHT);
404```
405
406```openscad-2D
407include <BOSL2/std.scad>
408ellipse(d=50)
409 attach(BACK+RIGHT, FRONT+LEFT)
410 ellipse(d=30);
411```
412
413
414#### Right Triangles
415The BOSL2 library provides a simple way to make a 2D right triangle by using the `right_triangle()` module:
416
417```openscad-2D
418include <BOSL2/std.scad>
419right_triangle([40,30]);
420```
421
422You can use `xflip()` and `yflip()` to change which quadrant the triangle is formed in:
423
424```openscad-2D
425include <BOSL2/std.scad>
426xflip() right_triangle([40,30]);
427```
428
429```openscad-2D
430include <BOSL2/std.scad>
431yflip() right_triangle([40,30]);
432```
433
434```openscad-2D
435include <BOSL2/std.scad>
436xflip() yflip() right_triangle([40,30]);
437```
438
439Or, alternatively, just rotate it into the correct quadrant with `spin=`:
440
441```openscad-2D
442include <BOSL2/std.scad>
443right_triangle([40,30], spin=90);
444```
445
446```openscad-2D
447include <BOSL2/std.scad>
448right_triangle([40,30], spin=-90);
449```
450
451You can also use anchoring with right triangles:
452
453```openscad-2D
454include <BOSL2/std.scad>
455right_triangle([40,30], anchor=FWD+RIGHT);
456```
457
458
459#### Trapezoids
460
461OpenSCAD doesn't provide a simple way to make general 2D triangles, trapezoids, or parallelograms.
462The BOSL2 library can provide all of these shapes with the `trapezoid()` module.
463
464To make a simple triangle, just make one of the widths zero:
465
466```openscad-2D
467include <BOSL2/std.scad>
468trapezoid(w1=50, w2=0, h=40);
469```
470
471To make a right triangle, you need to use the `shift=` argument, to shift the back of the trapezoid along the X axis:
472
473```openscad-2D
474include <BOSL2/std.scad>
475trapezoid(w1=50, w2=0, h=50, shift=-25);
476```
477
478```openscad-2D
479include <BOSL2/std.scad>
480trapezoid(w1=50, w2=0, h=50, shift=25);
481```
482
483```openscad-2D
484include <BOSL2/std.scad>
485trapezoid(w1=0, w2=50, h=50, shift=-25);
486```
487
488```openscad-2D
489include <BOSL2/std.scad>
490trapezoid(w1=0, w2=50, h=50, shift=25);
491```
492
493You can make a trapezoid by specifying non-zero widths for both the front (`w1=`) and back (`w2=`):
494
495```openscad-2D
496include <BOSL2/std.scad>
497trapezoid(w1=30, w2=50, h=50);
498```
499
500A parallelogram is just a matter of using the same width for front and back, with a shift along the X axis:
501
502```openscad-2D
503include <BOSL2/std.scad>
504trapezoid(w1=50, w2=50, shift=20, h=50);
505```
506
507A quadrilateral can be made by having unequal, non-zero front (`w1=`) and back (`w2=`) widths, with the back shifted along the X axis:
508
509```openscad-2D
510include <BOSL2/std.scad>
511trapezoid(w1=50, w2=30, shift=20, h=50);
512```
513
514You can use `anchor=` and `spin=`, just like with other attachable shapes. However, the anchor
515point orientations are based on the side angles of the faces, and may not be what you expect:
516
517```openscad-2D
518include <BOSL2/std.scad>
519trapezoid(w1=30, w2=50, h=50)
520 show_anchors();
521```
522
523#### Regular N-Gons
524
525OpenSCAD lets you make regular N-gons (pentagon, hexagon, etc) by using `circle()` with `$fn`.
526While this is concise, it may be less than obvious at first glance:
527
528```openscad-2D
529include <BOSL2/std.scad>
530circle(d=50, $fn=5);
531```
532
533The BOSL2 library has modules that are named more clearly, for common N-gons:
534
535```openscad-2D
536include <BOSL2/std.scad>
537pentagon(d=50);
538```
539
540```openscad-2D
541include <BOSL2/std.scad>
542hexagon(d=50);
543```
544
545```openscad-2D
546include <BOSL2/std.scad>
547octagon(d=50);
548```
549
550```openscad-2D
551include <BOSL2/std.scad>
552regular_ngon(n=7, d=50);
553```
554
555These modules also provide you with extra functionality. They can be sized by side length:
556
557```openscad-2D
558include <BOSL2/std.scad>
559pentagon(side=20);
560```
561
562They can be sized by circumscribed circle radius/diameter:
563
564```openscad-2D
565include <BOSL2/std.scad>
566pentagon(ir=25);
567pentagon(id=50);
568```
569
570They can be rotated by half a side:
571
572```openscad-2D
573include <BOSL2/std.scad>
574left(30) pentagon(d=50, realign=true);
575right(30) pentagon(d=50, realign=false);
576```
577
578They can be rounded:
579
580```openscad-2D
581include <BOSL2/std.scad>
582pentagon(d=50, rounding=10);
583```
584
585```openscad-2D
586include <BOSL2/std.scad>
587hexagon(d=50, rounding=10);
588```
589
590They also have somewhat different attachment behavior. A circle with a small `$fn=` will
591attach things at the ideal circle, not along the created polygon:
592
593```openscad-2D
594include <BOSL2/std.scad>
595color("green") stroke(circle(d=50), closed=true);
596circle(d=50,$fn=6)
597 show_anchors();
598```
599
600While an N-gon will attach along the polygon itself:
601
602```openscad-2D
603include <BOSL2/std.scad>
604hexagon(d=50)
605 show_anchors(custom=false);
606```
607
608You can use `anchor=` and `spin=`, just like with other attachable shapes. However, the anchor
609points are based on where the anchor vector would intersect the side of the N-gon, and may not
610be where you expect them:
611
612```openscad-2D
613include <BOSL2/std.scad>
614pentagon(d=50)
615 show_anchors(custom=false);
616```
617
618N-gons also have named anchor points for their sides and tips:
619
620```openscad-2D,Med
621include <BOSL2/std.scad>
622pentagon(d=30)
623 show_anchors(std=false);
624```
625
626
627#### Stars
628
629The BOSL2 library has stars as a basic supported shape. They can have any number of points.
630You can specify a star's shape by point count, inner and outer vertex radius/diameters:
631
632```openscad-2D
633include <BOSL2/std.scad>
634star(n=3, id=10, d=50);
635```
636
637```openscad-2D
638include <BOSL2/std.scad>
639star(n=5, id=15, r=25);
640```
641
642```openscad-2D
643include <BOSL2/std.scad>
644star(n=10, id=30, d=50);
645```
646
647Or you can specify the star shape by point count and number of points to step:
648
649```openscad-2D
650include <BOSL2/std.scad>
651star(n=7, step=2, d=50);
652```
653
654```openscad-2D
655include <BOSL2/std.scad>
656star(n=7, step=3, d=50);
657```
658
659If the `realign=` argument is given a true value, then the star will be rotated by half a point angle:
660
661```openscad-2D
662include <BOSL2/std.scad>
663left(30) star(n=5, step=2, d=50);
664right(30) star(n=5, step=2, d=50, realign=true);
665```
666
667The `align_tip=` argument can be given a vector so that you can align the first point in a specific direction:
668
669```openscad-2D
670include <BOSL2/std.scad>
671star(n=5, ir=15, or=30, align_tip=BACK)
672 attach("tip0") color("blue") anchor_arrow2d();
673```
674
675```openscad-2D
676include <BOSL2/std.scad>
677star(n=5, ir=15, or=30, align_tip=BACK+RIGHT)
678 attach("tip0") color("blue") anchor_arrow2d();
679```
680
681Similarly, the first indentation or pit can be oriented towards a specific vector with `align_pit=`:
682
683
684```openscad-2D
685include <BOSL2/std.scad>
686star(n=5, ir=15, or=30, align_pit=BACK)
687 attach("pit0") color("blue") anchor_arrow2d();
688```
689
690```openscad-2D
691include <BOSL2/std.scad>
692star(n=5, ir=15, or=30, align_pit=BACK+RIGHT)
693 attach("pit0") color("blue") anchor_arrow2d();
694```
695
696You can use `anchor=` and `spin=`, just like with other attachable shapes. However, the anchor
697points are based on the furthest extents of the shape, and may not be where you expect them:
698
699```openscad-2D
700include <BOSL2/std.scad>
701star(n=5, step=2, d=50)
702 show_anchors(custom=false);
703```
704
705Stars also have named anchor points for their pits, tips, and midpoints between tips:
706
707```openscad-2D,Med
708include <BOSL2/std.scad>
709star(n=5, step=2, d=40)
710 show_anchors(std=false);
711```
712
713
714
715#### Teardrop2D
716
717Often when 3D printing, you may want to make a circular hole in a vertical wall. If the hole is
718too big, however, the overhang at the top of the hole can cause problems with printing on an
719FDM/FFF printer. If you don't want to use support material, you can just use the teardrop shape.
720The `teardrop2d()` module will let you make a 2D version of the teardrop shape, so that you can
721extrude it later:
722
723```openscad-2D
724include <BOSL2/std.scad>
725teardrop2d(r=20);
726```
727
728```openscad-2D
729include <BOSL2/std.scad>
730teardrop2d(d=50);
731```
732
733The default overhang angle is 45 degrees, but you can adjust that with the `ang=` argument:
734
735```openscad-2D
736include <BOSL2/std.scad>
737teardrop2d(d=50, ang=30);
738```
739
740If you prefer to flatten the top of the teardrop, to encourage bridging, you can use the `cap_h=`
741argument:
742
743```openscad-2D
744include <BOSL2/std.scad>
745teardrop2d(d=50, cap_h=25);
746```
747
748```openscad-2D
749include <BOSL2/std.scad>
750teardrop2d(d=50, ang=30, cap_h=30);
751```
752
753You can use `anchor=` and `spin=`, just like with other attachable shapes. However, the anchor
754points are based on the furthest extents of the shape, and may not be where you expect them:
755
756```openscad-2D
757include <BOSL2/std.scad>
758teardrop2d(d=50, ang=30, cap_h=30)
759 show_anchors();
760```
761
762
763#### Glued Circles
764
765A more unusal shape that BOSL2 provides is Glued Circles. It's basically a pair of circles,
766connected by what looks like a gloopy glued miniscus:
767
768```openscad-2D
769include <BOSL2/std.scad>
770glued_circles(d=30, spread=40);
771```
772
773The `r=`/`d=` arguments can specify the radius or diameter of the two circles:
774
775```openscad-2D
776include <BOSL2/std.scad>
777glued_circles(r=20, spread=45);
778```
779
780```openscad-2D
781include <BOSL2/std.scad>
782glued_circles(d=40, spread=45);
783```
784
785The `spread=` argument specifies the distance between the centers of the two circles:
786
787```openscad-2D
788include <BOSL2/std.scad>
789glued_circles(d=30, spread=30);
790```
791
792```openscad-2D
793include <BOSL2/std.scad>
794glued_circles(d=30, spread=40);
795```
796
797The `tangent=` argument gives the angle of the tangent of the meniscus on the two circles:
798
799```openscad-2D
800include <BOSL2/std.scad>
801glued_circles(d=30, spread=30, tangent=45);
802```
803
804```openscad-2D
805include <BOSL2/std.scad>
806glued_circles(d=30, spread=30, tangent=20);
807```
808
809```openscad-2D
810include <BOSL2/std.scad>
811glued_circles(d=30, spread=30, tangent=-20);
812```
813
814One useful thing you can do is to string a few `glued_circle()`s in a line then extrude them to make a ribbed wall:
815
816```openscad-3D
817include <BOSL2/std.scad>
818$fn=36; s=10;
819linear_extrude(height=50,convexity=16,center=true)
820 xcopies(s*sqrt(2),n=3)
821 glued_circles(d=s, spread=s*sqrt(2), tangent=45);
822```
823
824You can use `anchor=` and `spin=`, just like with other attachable shapes. However, the anchor
825points are based on the furthest extents of the shape, and may not be where you expect them:
826
827```openscad-2D
828include <BOSL2/std.scad>
829glued_circles(d=40, spread=40, tangent=45)
830 show_anchors();
831```
832