omdl  v1.0
OpenSCAD Mechanical Design Library
common_2d.scad
Go to the documentation of this file.
1 //! Common 2D shapes.
2 /***************************************************************************//**
3  \file
4  \author Roy Allen Sutton
5  \date 2015-2023,2026
6 
7  \copyright
8 
9  This file is part of [omdl] (https://github.com/royasutton/omdl),
10  an OpenSCAD mechanical design library.
11 
12  The \em omdl is free software; you can redistribute it and/or modify
13  it under the terms of the [GNU Lesser General Public License]
14  (http://www.gnu.org/licenses/lgpl.html) as published by the Free
15  Software Foundation; either version 2.1 of the License, or (at
16  your option) any later version.
17 
18  The \em omdl is distributed in the hope that it will be useful,
19  but WITHOUT ANY WARRANTY; without even the implied warranty of
20  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21  Lesser General Public License for more details.
22 
23  You should have received a copy of the GNU Lesser General Public
24  License along with the \em omdl; if not, write to the Free Software
25  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
26  02110-1301, USA; or see <http://www.gnu.org/licenses/>.
27 
28  \details
29 
30  \amu_define group_name (Common 2d)
31  \amu_define group_brief (Common 2D shape.)
32 
33  \amu_include (include/amu/doxyg_init_pd_gds_ipg.amu)
34 *******************************************************************************/
35 
36 //----------------------------------------------------------------------------//
37 // group and macros.
38 //----------------------------------------------------------------------------//
39 
40 /***************************************************************************//**
41  \amu_include (include/amu/doxyg_define_in_parent_open.amu)
42  \amu_include (include/amu/includes_required.amu)
43 
44  \amu_define image_view (top)
45 
46  \amu_define group_id (${parent})
47  \amu_include (include/amu/scope_diagrams_3d_in_group.amu)
48 
49  \amu_define group_id (${group})
50  \amu_include (include/amu/scope_diagrams_3d_in_group.amu)
51 
52  \amu_include (include/amu/scope_diagram_3d_object.amu)
53 *******************************************************************************/
54 
55 //----------------------------------------------------------------------------//
56 
57 //! A rectangle with corner rounds or chamfers.
58 /***************************************************************************//**
59  \param size <decimal-list-2 | decimal> A list [x, y] of decimals
60  or a single decimal for (x=y).
61 
62  \param vr <decimal-list-4 | decimal> The corner rounding radius.
63  A list [v1r, v2r, v3r, v4r] of decimals or a single decimal
64  for (v1r=v2r=v3r=v4r). Unspecified corners are not rounded.
65 
66  \param vrm <integer> The corner radius mode.
67  A 4-bit encoded integer that indicates each corner finish.
68  Use bit value \b 0 for \em round and \b 1 for \em chamfer.
69 
70  \param center <boolean> Center about origin.
71 
72  \details
73 
74  \amu_eval ( object=rectangle ${object_ex_diagram_3d} )
75 
76  Corner \em round is of constant radius \p vr. A corner \em chamfer
77  replaces the last \p vr length of the corners edge with an
78  isosceles right triangle with a chamfer length of (vr * sqrt(2))
79  cut at 45 degrees.
80 *******************************************************************************/
81 module rectangle
82 (
83  size = 1,
84  vr,
85  vrm = 0,
86  center = false
87 )
88 {
89  rx = defined_e_or(size, 0, size);
90  ry = defined_e_or(size, 1, rx);
91 
92  translate(center==true ? [-rx/2, -ry/2] : origin2d)
93  {
94  if ( is_undef(vr) ) // no rounding
95  {
96  square([rx, ry]);
97  }
98  else if ( is_scalar(vr) ) // equal rounding
99  {
100  for ( i = [ [0, 0, 1, 0, 1, 0],
101  [1, 1, -1, 0, 1, 90],
102  [2, 1, -1, 1, -1, 180],
103  [3, 0, 1, 1, -1, 270] ] )
104  {
105  translate([rx*i[1] + vr * i[2], ry*i[3] + vr * i[4]])
106  if ( binary_bit_is(vrm, i[0], 0) )
107  {
108  circle(r=vr);
109  }
110  else
111  {
112  rotate([0, 0, i[5]])
113  polygon(points=[[eps,-vr], [eps,eps], [-vr,eps]], paths=[[0,1,2]]);
114  }
115  }
116 
117  translate([0, vr])
118  square([rx, ry] - [0, vr*2]);
119 
120  translate([vr, 0])
121  square([rx, ry] - [vr*2, 0]);
122  }
123  else // individual rounding
124  {
125  crv = [ defined_e_or(vr, 0, 0),
126  defined_e_or(vr, 1, 0),
127  defined_e_or(vr, 2, 0),
128  defined_e_or(vr, 3, 0) ];
129 
130  for ( i = [ [0, 0, 1, 0, 1],
131  [1, 1, -1, 0, 1],
132  [2, 1, -1, 1, -1],
133  [3, 0, 1, 1, -1] ] )
134  {
135  if ( (crv[i[0]] > 0) && binary_bit_is(vrm, i[0], 0) )
136  {
137  translate([rx*i[1] + crv[i[0]] * i[2], ry*i[3] + crv[i[0]] * i[4]])
138  circle(r=crv[i[0]]);
139  }
140  }
141 
142  ppv =
143  [
144  for
145  (
146  i = [
147  [0, 0, 0, 0, 1],
148  [0, 0, 1, 0, 0],
149  [1, 1, -1, 0, 0],
150  [1, 1, 0, 0, 1],
151  [2, 1, 0, 1, -1],
152  [2, 1, -1, 1, 0],
153  [3, 0, 1, 1, 0],
154  [3, 0, 0, 1, -1]
155  ]
156  )
157  [rx*i[1] + crv[i[0]] * i[2], ry*i[3] + crv[i[0]] * i[4]]
158  ];
159 
160  polygon( points=ppv, paths=[ [0,1,2,3,4,5,6,7] ] );
161  }
162  }
163 }
164 
165 //! A rectangle with a removed rectangular core.
166 /***************************************************************************//**
167  \param size <decimal-list-2 | decimal> A list [x, y] of decimals
168  or a single decimal for (x=y).
169  \param core <decimal-list-2 | decimal> A list [x, y] of decimals
170  or a single decimal for (x=y).
171 
172  \param t <decimal-list-2 | decimal> A list [x, y] of decimals
173  or a single decimal for (x=y).
174 
175  \param co <decimal-list-2> Core offset. A list [x, y] of decimals.
176  \param cr <decimal> Core z-rotation.
177 
178  \param vr <decimal-list-4 | decimal> The default corner rounding radius.
179  A list [v1r, v2r, v3r, v4r] of decimals or a single decimal
180  for (v1r=v2r=v3r=v4r). Unspecified corners are not rounded.
181  \param vr1 <decimal-list-4 | decimal> The outer corner rounding radius.
182  \param vr2 <decimal-list-4 | decimal> The core corner rounding radius.
183 
184  \param vrm <integer> The default corner radius mode.
185  A 4-bit encoded integer that indicates each corner finish.
186  Use bit value \b 0 for \em round and \b 1 for \em chamfer.
187  \param vrm1 <integer> The outer corner radius mode.
188  \param vrm2 <integer> The core corner radius mode.
189 
190  \param center <boolean> Center about origin.
191 
192  \details
193 
194  Thickness \p t
195  \li `core = size - t`; when \p t and \p size are given.
196  \li `size = core + t`; when \p t and \p core are given.
197 
198  \amu_eval ( object=rectangle_c ${object_ex_diagram_3d} )
199 *******************************************************************************/
200 module rectangle_c
201 (
202  size = 1,
203  core,
204  t,
205  co,
206  cr = 0,
207  vr,
208  vr1,
209  vr2,
210  vrm = 0,
211  vrm1,
212  vrm2,
213  center = false
214 )
215 {
216  od = all_defined([t, core]) ? (core + t*2) : size;
217  id = all_defined([t, size]) ? (size - t*2) : core;
218 
219  rx = defined_e_or(od, 0, od);
220  ry = defined_e_or(od, 1, od);
221 
222  or = defined_or(vr1, vr);
223  ir = defined_or(vr2, vr);
224 
225  om = defined_or(vrm1, vrm);
226  im = defined_or(vrm2, vrm);
227 
228  if ( is_defined(id) )
229  {
230  translate(center==true ? origin2d : [rx/2, ry/2])
231  difference()
232  {
233  rectangle(size=od, vr=or, vrm=om, center=true);
234 
235  translate(is_defined(co) ? co : origin2d)
236  rotate([0, 0, cr])
237  rectangle(size=id, vr=ir, vrm=im, center=true);
238  }
239  }
240  else
241  {
242  rectangle(size=od, vr=or, vrm=om, center=center);
243  }
244 }
245 
246 //! A rhombus.
247 /***************************************************************************//**
248  \param size <decimal-list-2 | decimal> A list [w, h] of decimals
249  or a single decimal for (w=h).
250 
251  \param vr <decimal-list-4 | decimal> The corner rounding radius.
252  A list [v1r, v2r, v3r, v4r] of decimals or a single decimal
253  for (v1r=v2r=v3r=v4r). Unspecified corners are not rounded.
254 
255  \param center <boolean> Center about origin.
256 
257  \details
258 
259  \amu_eval ( object=rhombus ${object_ex_diagram_3d} )
260 
261  See [Wikipedia] for more information.
262 
263  [Wikipedia]: https://en.wikipedia.org/wiki/Rhombus
264 *******************************************************************************/
265 module rhombus
266 (
267  size = 1,
268  vr,
269  center = false
270 )
271 {
272  rx = defined_e_or(size, 0, size) / 2;
273  ry = defined_e_or(size, 1, rx*2) / 2;
274 
275  translate(center==true ? origin2d : [rx, ry])
276  {
277  if ( is_undef(vr) ) // no rounding
278  {
279  polygon
280  (
281  points=[ [rx,0], [0,ry], [-rx,0], [0,-ry] ],
282  paths=[ [0,1,2,3] ]
283  );
284  }
285  else // individual rounding
286  {
287  erc = is_scalar(vr) ? vr : 0; // equal rounding
288 
289  crv = [ defined_e_or(vr, 0, erc),
290  defined_e_or(vr, 1, erc),
291  defined_e_or(vr, 2, erc),
292  defined_e_or(vr, 3, erc) ];
293 
294  a1 = angle_ll([[rx,0], [0,ry]], [[rx,0], [0,-ry]]) / 2;
295  a2 = 90 - a1;
296 
297  for ( i = [ [0, 1, -1, 0, 0],
298  [1, 0, 0, 1, -1],
299  [2, -1, 1, 0, 0],
300  [3, 0, 0, -1, 1] ] )
301  {
302  translate
303  (
304  [ rx*i[1] + crv[i[0]]/sin(a1) * i[2], ry*i[3] + crv[i[0]]/sin(a2) * i[4] ]
305  )
306  circle (r=crv[i[0]]);
307  }
308 
309  ppv =
310  [
311  for
312  (
313  i = [
314  [0, 0, 1, -1, 0, -1],
315  [0, 0, 1, -1, 0, 1],
316  [1, 1, 0, 1, 1, -1],
317  [1, 1, 0, -1, 1, -1],
318  [2, 0, -1, 1, 0, 1],
319  [2, 0, -1, 1, 0, -1],
320  [3, 1, 0, -1, -1, 1],
321  [3, 1, 0, +1, -1, +1]
322  ]
323  )
324  ( i[1] == 0 )
325  ? [
326  rx*i[2] + crv[i[0]] * (1/sin(a1)-sin(a1)) * i[3],
327  ry*i[4] + crv[i[0]] * cos(a1) * i[5]
328  ]
329  : [
330  rx*i[2] + crv[i[0]] * cos(a2) * i[3],
331  ry*i[4] + crv[i[0]] * (1/sin(a2)-sin(a2)) * i[5]
332  ]
333  ];
334 
335  polygon( points=ppv, paths=[ [0,1,2,3,4,5,6,7] ] );
336  }
337  }
338 }
339 
340 //! An n-sided equiangular/equilateral regular polygon.
341 /***************************************************************************//**
342  \param size <decimal-list-2 | decimal> A list [r, n] of decimals
343  or a single decimal to specified \p r (default for \p n=5).
344 
345  \param vr <decimal> The vertex rounding radius.
346 
347  \details
348 
349  \amu_eval ( object=ngon ${object_ex_diagram_3d} )
350 
351  See [Wikipedia] for more information.
352 
353  [Wikipedia]: https://en.wikipedia.org/wiki/Regular_polygon
354 *******************************************************************************/
355 module ngon
356 (
357  size = 1,
358  vr
359 )
360 {
361  r = defined_e_or(size, 0, size);
362  n = defined_e_or(size, 1, 5);
363 
364  if ( is_undef(vr) )
365  {
366  circle(r=r, $fn=n);
367  }
368  else
369  {
370  hull()
371  {
372  for ( c = polygon_regular_p( r=r, n=n, vr=vr ) )
373  {
374  translate( c )
375  circle( r=vr );
376  }
377  }
378  }
379 }
380 
381 //! An ellipse.
382 /***************************************************************************//**
383  \param size <decimal-list-2 | decimal> A list [rx, ry] of decimals
384  or a single decimal for (rx=ry).
385 
386  \details
387 
388  \amu_eval ( object=ellipse ${object_ex_diagram_3d} )
389 *******************************************************************************/
390 module ellipse
391 (
392  size = 1
393 )
394 {
395  rx = defined_e_or(size, 0, size);
396  ry = defined_e_or(size, 1, rx);
397 
398  if ( rx == ry )
399  {
400  circle(r=rx);
401  }
402  else
403  {
404  scale([1, ry/rx])
405  circle(r=rx);
406  }
407 }
408 
409 //! An ellipse with a removed elliptical core.
410 /***************************************************************************//**
411  \param size <decimal-list-2 | decimal> A list [rx, ry] of decimals
412  or a single decimal for (rx=ry).
413  \param core <decimal-list-2 | decimal> A list [rx, ry] of decimals
414  or a single decimal for (rx=ry).
415 
416  \param t <decimal-list-2 | decimal> A list [x, y] of decimals
417  or a single decimal for (x=y).
418 
419  \param co <decimal-list-2> Core offset. A list [x, y] of decimals.
420  \param cr <decimal> Core z-rotation.
421 
422  \details
423 
424  Thickness \p t
425  \li `core = size - t`; when \p t and \p size are given.
426  \li `size = core + t`; when \p t and \p core are given.
427 
428  \amu_eval ( object=ellipse_c ${object_ex_diagram_3d} )
429 *******************************************************************************/
430 module ellipse_c
431 (
432  size = 1,
433  core,
434  t,
435  co,
436  cr = 0
437 )
438 {
439  od = all_defined([t, core]) ? (core + t) : size;
440  id = all_defined([t, size]) ? (size - t) : core;
441 
442  if ( is_defined(id) )
443  {
444  difference()
445  {
446  ellipse(size=od);
447 
448  translate(is_defined(co) ? co : origin2d)
449  rotate([0, 0, cr])
450  ellipse(size=id);
451  }
452  }
453  else
454  {
455  ellipse(size=od);
456  }
457 }
458 
459 //! An ellipse sector.
460 /***************************************************************************//**
461  \param size <decimal-list-2 | decimal> A list [rx, ry] of decimals
462  or a single decimal for (rx=ry).
463 
464  \param a1 <decimal> The start angle in degrees.
465  \param a2 <decimal> The stop angle in degrees.
466 
467  \details
468 
469  \amu_eval ( object=ellipse_s ${object_ex_diagram_3d} )
470 *******************************************************************************/
471 module ellipse_s
472 (
473  size = 1,
474  a1 = 0,
475  a2 = 0
476 )
477 {
478  rx = defined_e_or(size, 0, size);
479  ry = defined_e_or(size, 1, rx);
480 
481  trx = rx * sqrt(2) + 1;
482  try = ry * sqrt(2) + 1;
483 
484  pa0 = (4 * a1 + 0 * a2) / 4;
485  pa1 = (3 * a1 + 1 * a2) / 4;
486  pa2 = (2 * a1 + 2 * a2) / 4;
487  pa3 = (1 * a1 + 3 * a2) / 4;
488  pa4 = (0 * a1 + 4 * a2) / 4;
489 
490  if (a2 > a1)
491  {
492  intersection()
493  {
494  ellipse(size);
495 
496  polygon
497  ([
498  origin2d,
499  [trx * cos(pa0), try * sin(pa0)],
500  [trx * cos(pa1), try * sin(pa1)],
501  [trx * cos(pa2), try * sin(pa2)],
502  [trx * cos(pa3), try * sin(pa3)],
503  [trx * cos(pa4), try * sin(pa4)],
504  origin2d
505  ]);
506  }
507  }
508  else
509  {
510  ellipse(size);
511  }
512 }
513 
514 //! A sector of an ellipse with a removed elliptical core.
515 /***************************************************************************//**
516  \param size <decimal-list-2 | decimal> A list [rx, ry] of decimals
517  or a single decimal for (rx=ry).
518  \param core <decimal-list-2 | decimal> A list [rx, ry] of decimals
519  or a single decimal for (rx=ry).
520 
521  \param t <decimal-list-2 | decimal> A list [x, y] of decimals
522  or a single decimal for (x=y).
523 
524  \param a1 <decimal> The start angle in degrees.
525  \param a2 <decimal> The stop angle in degrees.
526 
527  \param co <decimal-list-2> Core offset. A list [x, y] of decimals.
528  \param cr <decimal> Core z-rotation.
529 
530  \details
531 
532  Thickness \p t
533  \li `core = size - t`; when \p t and \p size are given.
534  \li `size = core + t`; when \p t and \p core are given.
535 
536  \amu_eval ( object=ellipse_cs ${object_ex_diagram_3d} )
537 *******************************************************************************/
538 module ellipse_cs
539 (
540  size = 1,
541  core,
542  t,
543  a1 = 0,
544  a2 = 0,
545  co,
546  cr = 0
547 )
548 {
549  od = all_defined([t, core]) ? (core + t) : size;
550  id = all_defined([t, size]) ? (size - t) : core;
551 
552  if ( is_defined(id) )
553  {
554  difference()
555  {
556  ellipse_s(a1=a1, a2=a2, size=od);
557 
558  translate(is_defined(co) ? co : origin2d)
559  rotate([0, 0, cr])
560  ellipse(size=id);
561  }
562  }
563  else
564  {
565  ellipse_s(a1=a1, a2=a2, size=od);
566  }
567 }
568 
569 //! A two-dimensional star.
570 /***************************************************************************//**
571  \param size <decimal-list-2 | decimal> A list [l, w] of decimals
572  or a single decimal for (size=l=2*w).
573 
574  \param n <decimal> The number of points.
575 
576  \param vr <decimal-list-3 | decimal> The vertex rounding radius.
577  A list [v1r, v2r, v3r] of decimals or a single decimal for
578  (v1r=v2r=v3r).
579 
580  \details
581 
582  \amu_eval ( object=star2d ${object_ex_diagram_3d} )
583 *******************************************************************************/
584 module star2d
585 (
586  size = 1,
587  n = 5,
588  vr
589 )
590 {
591  l = defined_e_or(size, 0, size);
592  w = defined_e_or(size, 1, l/2);
593 
594  t = triangle2d_sss2ppp([l, w, l]);
595  p = is_undef(vr) ? t : polygon_round_eve_all_p(c=t, vr=vr);
596 
597  repeat_radial(n=n, angle=true, move=false)
598  rotate([0, 0, -90])
599  translate([-w/2, 0])
600  polygon(p);
601 }
602 
603 //! @}
604 //! @}
605 
606 //----------------------------------------------------------------------------//
607 // openscad-amu auxiliary scripts
608 //----------------------------------------------------------------------------//
609 
610 /*
611 BEGIN_SCOPE diagram;
612  BEGIN_OPENSCAD;
613  include <omdl-base.scad>;
614 
615  shape = "ellipse_cs";
616  $fn = 36;
617 
618  if (shape == "rectangle")
619  rectangle( size=[25,40], vr=[0,10,10,5], vrm=4, center=true );
620  else if (shape == "rectangle_c")
621  rectangle_c( size=[40,25], t=[15,5], vr1=[0,0,10,10], vr2=2.5, vrm2=3, co=[0,5], center=true );
622  else if (shape == "rhombus")
623  rhombus( size=[40,25], vr=[2,4,2,4], center=true );
624  else if (shape == "ngon")
625  ngon( [25, 6], vr=6 );
626  else if (shape == "ellipse")
627  ellipse( size=[25, 40] );
628  else if (shape == "ellipse_c")
629  ellipse_c( size=[25,40], core=[16,10], co=[0,10], cr=45 );
630  else if (shape == "ellipse_s")
631  ellipse_s( size=[25,40], a1=90, a2=180 );
632  else if (shape == "ellipse_cs")
633  ellipse_cs( size=[25,40], t=[10,5], a1=90, a2=180, co=[10,0], cr=45);
634  else if (shape == "star2d")
635  star2d( size=[40, 15], n=5, vr=2 );
636  END_OPENSCAD;
637 
638  BEGIN_MFSCRIPT;
639  include --path "${INCLUDE_PATH}" {var_init,var_gen_png2eps}.mfs;
640 
641  views name "views" views "top";
642  defines name "shapes" define "shape"
643  strings "
644  rectangle
645  rectangle_c
646  rhombus
647  ngon
648  ellipse
649  ellipse_c
650  ellipse_s
651  ellipse_cs
652  star2d
653  ";
654  variables add_opts_combine "views shapes";
655  variables add_opts "--viewall --autocenter --view=axes";
656 
657  include --path "${INCLUDE_PATH}" scr_make_mf.mfs;
658  END_MFSCRIPT;
659 END_SCOPE;
660 */
661 
662 //----------------------------------------------------------------------------//
663 // end of file
664 //----------------------------------------------------------------------------//
origin2d
<point-2d> The origin point coordinate in 2d Euclidean space.
Definition: constants.scad:407
eps
<decimal> Epsilon, small distance to deal with overlapping shapes.
Definition: constants.scad:195
function binary_bit_is(v, b, t=1)
Test if a binary bit position of an integer value equals a test bit.
function angle_ll(l1, l2, s=true)
Compute the angle between two lines or vectors in a 3d or 2d-space.
function defined_e_or(v, i, d)
Returns an element from an iterable if it exists, or a default value if not.
function all_defined(v)
Test if no element of an iterable value has an undefined value.
function defined_or(v, d)
Return given value, if defined, or a secondary value, if primary is not defined.
function is_scalar(v)
Test if a value is a single non-iterable value.
function is_defined(v)
Test if a value is defined.
function polygon_round_eve_all_p(c, vr=0, vrm=1, vfn, w=true, cw=true)
Compute coordinates that round all of the vertices between each adjacent edges in 2D.
function polygon_regular_p(n, r, a, o=origin2d, ao=0, vr, cw=true)
Compute coordinates for an n-sided regular polygon in 2D.
function triangle2d_sss2ppp(v, a=x_axis_ci, cw=true)
Compute a set of vertex coordinates for a triangle given its side lengths in 2D.
module star2d(size=1, n=5, vr)
A two-dimensional star.
module ellipse_s(size=1, a1=0, a2=0)
An ellipse sector.
Definition: common_2d.scad:891
module rhombus(size=1, vr, center=false)
A rhombus.
Definition: common_2d.scad:665
module ellipse_c(size=1, core, t, co, cr=0)
An ellipse with a removed elliptical core.
Definition: common_2d.scad:845
module rectangle(size=1, vr, vrm=0, center=false)
A rectangle with corner rounds or chamfers.
Definition: common_2d.scad:471
module ellipse(size=1)
An ellipse.
Definition: common_2d.scad:800
module ngon(size=1, vr)
An n-sided equiangular/equilateral regular polygon.
Definition: common_2d.scad:760
module ellipse_cs(size=1, core, t, a1=0, a2=0, co, cr=0)
A sector of an ellipse with a removed elliptical core.
Definition: common_2d.scad:963
module rectangle_c(size=1, core, t, co, cr=0, vr, vr1, vr2, vrm=0, vrm1, vrm2, center=false)
A rectangle with a removed rectangular core.
Definition: common_2d.scad:595
module repeat_radial(n, r=1, ao=0, angle=true, move=false)
Radially repeat copies of child objects about a z-axis radius.
Definition: repeat.scad:462
function angle(a, from=angle_unit_default, to=angle_unit_base)
Convert an angle value from one unit to another.