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