omdl  v0.9.5
OpenSCAD Mechanical Design Library
basic_2d.scad
Go to the documentation of this file.
1 //! Basic 2D shapes.
2 /***************************************************************************//**
3  \file
4  \author Roy Allen Sutton
5  \date 2015-2023
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 (Basic 2d)
31  \amu_define group_brief (Basic 2D shape.)
32 
33  \amu_include (include/amu/pgid_path_pstem_pg.amu)
34 *******************************************************************************/
35 
36 //----------------------------------------------------------------------------//
37 // group and macros.
38 //----------------------------------------------------------------------------//
39 
40 /***************************************************************************//**
41  \amu_include (include/amu/group_in_parent_start.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,
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 <tt>core = size - t</tt>; when \p t and \p size are given.
196  \li <tt>size = core + t</tt>; 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,
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,
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 n <integer> The number of sides.
343  \param r <decimal> The ngon vertex radius.
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  n,
358  r,
359  vr
360 )
361 {
362  if ( is_undef(vr) )
363  {
364  circle(r=r, $fn=n);
365  }
366  else
367  {
368  hull()
369  {
370  for ( c = polygon_regular_p( r=r, n=n, vr=vr ) )
371  {
372  translate( c )
373  circle( r=vr );
374  }
375  }
376  }
377 }
378 
379 //! An ellipse.
380 /***************************************************************************//**
381  \param size <decimal-list-2 | decimal> A list [rx, ry] of decimals
382  or a single decimal for (rx=ry).
383 
384  \details
385 
386  \amu_eval ( object=ellipse ${object_ex_diagram_3d} )
387 *******************************************************************************/
388 module ellipse
389 (
390  size
391 )
392 {
393  rx = defined_e_or(size, 0, size);
394  ry = defined_e_or(size, 1, rx);
395 
396  if ( rx == ry )
397  {
398  circle(r=rx);
399  }
400  else
401  {
402  scale([1, ry/rx])
403  circle(r=rx);
404  }
405 }
406 
407 //! An ellipse with a removed elliptical core.
408 /***************************************************************************//**
409  \param size <decimal-list-2 | decimal> A list [rx, ry] of decimals
410  or a single decimal for (rx=ry).
411  \param core <decimal-list-2 | decimal> A list [rx, ry] of decimals
412  or a single decimal for (rx=ry).
413 
414  \param t <decimal-list-2 | decimal> A list [x, y] of decimals
415  or a single decimal for (x=y).
416 
417  \param co <decimal-list-2> Core offset. A list [x, y] of decimals.
418  \param cr <decimal> Core z-rotation.
419 
420  \details
421 
422  Thickness \p t
423  \li <tt>core = size - t</tt>; when \p t and \p size are given.
424  \li <tt>size = core + t</tt>; when \p t and \p core are given.
425 
426  \amu_eval ( object=ellipse_c ${object_ex_diagram_3d} )
427 *******************************************************************************/
428 module ellipse_c
429 (
430  size,
431  core,
432  t,
433  co,
434  cr = 0
435 )
436 {
437  od = all_defined([t, core]) ? (core + t) : size;
438  id = all_defined([t, size]) ? (size - t) : core;
439 
440  if ( is_defined(id) )
441  {
442  difference()
443  {
444  ellipse(size=od);
445 
446  translate(is_defined(co) ? co : origin2d)
447  rotate([0, 0, cr])
448  ellipse(size=id);
449  }
450  }
451  else
452  {
453  ellipse(size=od);
454  }
455 }
456 
457 //! An ellipse sector.
458 /***************************************************************************//**
459  \param size <decimal-list-2 | decimal> A list [rx, ry] of decimals
460  or a single decimal for (rx=ry).
461 
462  \param a1 <decimal> The start angle in degrees.
463  \param a2 <decimal> The stop angle in degrees.
464 
465  \details
466 
467  \amu_eval ( object=ellipse_s ${object_ex_diagram_3d} )
468 *******************************************************************************/
469 module ellipse_s
470 (
471  size,
472  a1 = 0,
473  a2 = 0
474 )
475 {
476  rx = defined_e_or(size, 0, size);
477  ry = defined_e_or(size, 1, rx);
478 
479  trx = rx * sqrt(2) + 1;
480  try = ry * sqrt(2) + 1;
481 
482  pa0 = (4 * a1 + 0 * a2) / 4;
483  pa1 = (3 * a1 + 1 * a2) / 4;
484  pa2 = (2 * a1 + 2 * a2) / 4;
485  pa3 = (1 * a1 + 3 * a2) / 4;
486  pa4 = (0 * a1 + 4 * a2) / 4;
487 
488  if (a2 > a1)
489  {
490  intersection()
491  {
492  ellipse(size);
493 
494  polygon
495  ([
496  origin2d,
497  [trx * cos(pa0), try * sin(pa0)],
498  [trx * cos(pa1), try * sin(pa1)],
499  [trx * cos(pa2), try * sin(pa2)],
500  [trx * cos(pa3), try * sin(pa3)],
501  [trx * cos(pa4), try * sin(pa4)],
502  origin2d
503  ]);
504  }
505  }
506  else
507  {
508  ellipse(size);
509  }
510 }
511 
512 //! A sector of an ellipse with a removed elliptical core.
513 /***************************************************************************//**
514  \param size <decimal-list-2 | decimal> A list [rx, ry] of decimals
515  or a single decimal for (rx=ry).
516  \param core <decimal-list-2 | decimal> A list [rx, ry] of decimals
517  or a single decimal for (rx=ry).
518 
519  \param t <decimal-list-2 | decimal> A list [x, y] of decimals
520  or a single decimal for (x=y).
521 
522  \param a1 <decimal> The start angle in degrees.
523  \param a2 <decimal> The stop angle in degrees.
524 
525  \param co <decimal-list-2> Core offset. A list [x, y] of decimals.
526  \param cr <decimal> Core z-rotation.
527 
528  \details
529 
530  Thickness \p t
531  \li <tt>core = size - t</tt>; when \p t and \p size are given.
532  \li <tt>size = core + t</tt>; when \p t and \p core are given.
533 
534  \amu_eval ( object=ellipse_cs ${object_ex_diagram_3d} )
535 *******************************************************************************/
536 module ellipse_cs
537 (
538  size,
539  core,
540  t,
541  a1 = 0,
542  a2 = 0,
543  co,
544  cr = 0
545 )
546 {
547  od = all_defined([t, core]) ? (core + t) : size;
548  id = all_defined([t, size]) ? (size - t) : core;
549 
550  if ( is_defined(id) )
551  {
552  difference()
553  {
554  ellipse_s(a1=a1, a2=a2, size=od);
555 
556  translate(is_defined(co) ? co : origin2d)
557  rotate([0, 0, cr])
558  ellipse(size=id);
559  }
560  }
561  else
562  {
563  ellipse_s(a1=a1, a2=a2, size=od);
564  }
565 }
566 
567 //! A two-dimensional star.
568 /***************************************************************************//**
569  \param size <decimal-list-2 | decimal> A list [l, w] of decimals
570  or a single decimal for (size=l=2*w).
571 
572  \param n <decimal> The number of points.
573 
574  \param vr <decimal-list-3 | decimal> The vertex rounding radius.
575  A list [v1r, v2r, v3r] of decimals or a single decimal for
576  (v1r=v2r=v3r).
577 
578  \details
579 
580  \amu_eval ( object=star2d ${object_ex_diagram_3d} )
581 *******************************************************************************/
582 module star2d
583 (
584  size,
585  n = 5,
586  vr
587 )
588 {
589  l = defined_e_or(size, 0, size);
590  w = defined_e_or(size, 1, l/2);
591 
592  t = triangle2d_sss2ppp([l, w, l]);
593  p = is_undef(vr) ? t : polygon_round_eve_all_p(c=t, vr=vr);
594 
595  repeat_radial(n=n, angle=true, move=false)
596  rotate([0, 0, -90])
597  translate([-w/2, 0])
598  polygon(p);
599 }
600 
601 //! @}
602 //! @}
603 
604 //----------------------------------------------------------------------------//
605 // openscad-amu auxiliary scripts
606 //----------------------------------------------------------------------------//
607 
608 /*
609 BEGIN_SCOPE diagram;
610  BEGIN_OPENSCAD;
611  include <omdl-base.scad>;
612 
613  shape = "ellipse_cs";
614  $fn = 36;
615 
616  if (shape == "rectangle")
617  rectangle( size=[25,40], vr=[0,10,10,5], vrm=4, center=true );
618  else if (shape == "rectangle_c")
619  rectangle_c( size=[40,25], t=[15,5], vr1=[0,0,10,10], vr2=2.5, vrm2=3, co=[0,5], center=true );
620  else if (shape == "rhombus")
621  rhombus( size=[40,25], vr=[2,4,2,4], center=true );
622  else if (shape == "ngon")
623  ngon( n=6, r=25, vr=6 );
624  else if (shape == "ellipse")
625  ellipse( size=[25, 40] );
626  else if (shape == "ellipse_c")
627  ellipse_c( size=[25,40], core=[16,10], co=[0,10], cr=45 );
628  else if (shape == "ellipse_s")
629  ellipse_s( size=[25,40], a1=90, a2=180 );
630  else if (shape == "ellipse_cs")
631  ellipse_cs( size=[25,40], t=[10,5], a1=90, a2=180, co=[10,0], cr=45);
632  else if (shape == "star2d")
633  star2d( size=[40, 15], n=5, vr=2 );
634  END_OPENSCAD;
635 
636  BEGIN_MFSCRIPT;
637  include --path "${INCLUDE_PATH}" {var_init,var_gen_png2eps}.mfs;
638 
639  views name "views" views "top";
640  defines name "shapes" define "shape"
641  strings "
642  rectangle
643  rectangle_c
644  rhombus
645  ngon
646  ellipse
647  ellipse_c
648  ellipse_s
649  ellipse_cs
650  star2d
651  ";
652  variables add_opts_combine "views shapes";
653  variables add_opts "--viewall --autocenter --view=axes";
654 
655  include --path "${INCLUDE_PATH}" scr_make_mf.mfs;
656  END_MFSCRIPT;
657 END_SCOPE;
658 */
659 
660 //----------------------------------------------------------------------------//
661 // end of file
662 //----------------------------------------------------------------------------//
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)
Return an element of an iterable when it exists or a default value otherwise.
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_regular_p(n, r, a, c=origin2d, o=0, vr, cw=true)
Compute coordinates for an n-sided regular polygon in 2D.
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 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 ellipse_cs(size, core, t, a1=0, a2=0, co, cr=0)
A sector of an ellipse with a removed elliptical core.
Definition: basic_2d.scad:961
module ngon(n, r, vr)
An n-sided equiangular/equilateral regular polygon.
Definition: basic_2d.scad:760
module star2d(size, n=5, vr)
A two-dimensional star.
Definition: basic_2d.scad:1012
module ellipse(size)
An ellipse.
Definition: basic_2d.scad:798
module rectangle_c(size, core, t, co, cr=0, vr, vr1, vr2, vrm=0, vrm1, vrm2, center=false)
A rectangle with a removed rectangular core.
Definition: basic_2d.scad:595
module ellipse_s(size, a1=0, a2=0)
An ellipse sector.
Definition: basic_2d.scad:889
module rhombus(size, vr, center=false)
A rhombus.
Definition: basic_2d.scad:665
module ellipse_c(size, core, t, co, cr=0)
An ellipse with a removed elliptical core.
Definition: basic_2d.scad:843
module rectangle(size, vr, vrm=0, center=false)
A rectangle with corner rounds or chamfers.
Definition: basic_2d.scad:471
module repeat_radial(n, r=1, o=0, angle=true, move=false)
Distribute copies of a 2d or 3d shape equally about a z-axis radius.
Definition: repeat.scad:459
function angle(a, from=angle_unit_default, to=angle_unit_base)
Convert an angle from some units to another.