omdl  v0.6.1
OpenSCAD Mechanical Design Library
tools_utility.scad
Go to the documentation of this file.
1 //! Shape transformation utility tools.
2 /***************************************************************************//**
3  \file tools_utility.scad
4  \author Roy Allen Sutton
5  \date 2015-2017
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  \ingroup tools tools_extrude tools_repeat
31 *******************************************************************************/
32 
33 include <../console.scad>;
34 include <../math/math-base.scad>;
35 include <../math/math_oshapes.scad>;
36 include <../math/math_bitwise.scad>;
37 
38 //----------------------------------------------------------------------------//
39 /***************************************************************************//**
40  \addtogroup tools
41 
42  \amu_define caption (Transformation Utilities)
43 
44  \amu_make png_files (append=dim extension=png)
45  \amu_make eps_files (append=dim extension=png2eps)
46  \amu_shell file_cnt ("echo ${png_files} | wc -w")
47  \amu_shell cell_num ("seq -f '(%g)' -s '^' ${file_cnt}")
48 
49  \htmlonly
50  \amu_image_table
51  (
52  type=html columns=4 image_width="200" cell_files="${png_files}"
53  table_caption="${caption}" cell_captions="${cell_num}"
54  )
55  \endhtmlonly
56  \latexonly
57  \amu_image_table
58  (
59  type=latex columns=4 image_width="1.25in" cell_files="${eps_files}"
60  table_caption="${caption}" cell_captions="${cell_num}"
61  )
62  \endlatexonly
63 *******************************************************************************/
64 
65 /***************************************************************************//**
66  \addtogroup tools
67  @{
68 
69  \defgroup tools_extrude Extrude
70  \brief Shape extrusion tools.
71  @{
72 *******************************************************************************/
73 //----------------------------------------------------------------------------//
74 
75 //----------------------------------------------------------------------------//
76 // openscad-amu macros
77 //----------------------------------------------------------------------------//
78 /***************************************************************************//**
79  \amu_define scope (tools_utility_dim)
80  \amu_define tuple (qvga_diag)
81 
82  \amu_define example_dim
83  (
84  \image html ${scope}_${tuple}_${function}.png "${function}"
85  \image latex ${scope}_${tuple}_${function}.eps "${function}" width=2.5in
86  \dontinclude ${scope}.scad \skipline ${function}(
87  )
88 *******************************************************************************/
89 //----------------------------------------------------------------------------//
90 
91 //! Translate, rotate, and revolve the 2d shape about the z-axis.
92 /***************************************************************************//**
93  \param r <decimal> The rotation radius.
94  \param pa <decimal> The profile pitch angle in degrees.
95  \param ra <decimal> The rotation sweep angle in degrees.
96  \param profile <boolean> Show profile only (do not extrude).
97 
98  \details
99 
100  \b Example
101  \amu_eval ( function=rotate_extrude_tr ${example_dim} )
102 *******************************************************************************/
103 module rotate_extrude_tr
104 (
105  r,
106  pa = 0,
107  ra = 360,
108  profile = false
109 )
110 {
111  rotate_extrude(angle = (profile==true ? 1 : ra) )
112  translate([r, 0])
113  rotate([0, 0, pa])
114  children();
115 }
116 
117 //! Translate, rotate, and revolve the 2d shape about the z-axis with linear elongation.
118 /***************************************************************************//**
119  \param r <decimal> The rotation radius.
120  \param l <decimal-list-2|decimal> The elongation length.
121  A list [x, y] of decimals or a single decimal for (x=y)
122  \param pa <decimal> The profile pitch angle in degrees.
123  \param ra <decimal> The rotation sweep angle in degrees.
124  \param m <integer> The section render mode. An 8-bit encoded integer
125  that indicates the revolution sections to render.
126  Bit values \b 1 enables the corresponding section and bit values
127  \b 0 are disabled. Sections are assigned to the bit position in
128  counter-clockwise order.
129  \param profile <boolean> Show profile only (do not extrude).
130 
131  \details
132 
133  \b Example
134  \amu_eval ( function=rotate_extrude_tre ${example_dim} )
135 
136  \note When elongating <tt>(l > 0)</tt>, \p ra is ignored. However, \p m
137  may be used to control which complete revolution section to render.
138 *******************************************************************************/
139 module rotate_extrude_tre
140 (
141  r,
142  l,
143  pa = 0,
144  ra = 360,
145  m = 255,
146  profile = false
147 )
148 {
149  if ( not_defined(l) || (profile==true) )
150  {
151  rotate_extrude_tr(r=r, pa=pa, ra=ra, profile=profile)
152  children();
153  }
154  else
155  {
156  ld = is_scalar(l) ? l : 0;
157  lx = edefined_or(l, 0, ld);
158  ly = edefined_or(l, 1, ld);
159 
160  for
161  (
162  i = [
163  [+lx/2, +ly/2, 0, 1],
164  [-lx/2, +ly/2, 90, 3],
165  [-lx/2, -ly/2, 180, 5],
166  [+lx/2, -ly/2, 270, 7]
167  ]
168  )
169  if ( bitwise_is_equal(m, i[3], 1) )
170  {
171  translate([i[0], i[1], 0])
172  rotate([0, 0, i[2]])
173  rotate_extrude_tr(r=r, pa=pa, ra=90, profile=profile)
174  children();
175  }
176 
177  for
178  (
179  i = [
180  [ +r +lx/2, +ly/2, 0, ly, 0],
181  [ -lx/2, +r +ly/2, 90, lx, 2],
182  [ -r -lx/2, -ly/2, 180, ly, 4],
183  [ lx/2, -r -ly/2, 270, lx, 6]
184  ]
185  )
186  if ( bitwise_is_equal(m, i[4], 1) )
187  {
188  translate([i[0], i[1], 0])
189  rotate([90, 0, i[2]])
190  linear_extrude(height=i[3])
191  rotate([0, 0, pa])
192  children();
193  }
194  }
195 }
196 
197 //! Linearly extrude 2d shape with extrusion upper and lower scaling.
198 /***************************************************************************//**
199  \param h <decimal-list-3:9|decimal> A list of decimals or a single
200  decimal to specify simple extrusion height.
201  \param center <boolean> Center extrusion about origin.
202 
203  \details
204 
205  When \p h is a decimal, the shape is extruded linearly as normal.
206  To scale the upper and lower slices of the extrusion, \p h must be
207  assigned a list with a minimum of three decimal values as described
208  in the following table.
209 
210  sym | h[n] | default | description
211  :----:|:----:|:-------:|:---------------------------------------
212  h | 0 | | total extrusion height
213  n1 | 1 | | (+z) number of scaled extrusion slices
214  h1 | 2 | | (+z) extrusion scale percentage
215  x1 | 3 | -h1 | (+z) x-dimension scale percentage
216  y1 | 4 | x1 | (+z) y-dimension scale percentage
217  n2 | 5 | n1 | (-z) number of scaled extrusion slices
218  h2 | 6 | h1 | (-z) extrusion scale percentage
219  x2 | 7 | x1 | (-z) x-dimension scale percentage
220  y2 | 8 | y1 | (-z) y-dimension scale percentage
221 
222  \details
223 
224  \b Example
225  \amu_eval ( function=linear_extrude_uls ${example_dim} )
226 
227  \note When symmetrical scaling is desired, shape must be centered about
228  origin.
229 
230  \todo This function should be rewritten to use the built-in scaling
231  provided by linear_extrude() in the upper and lower scaling zones.
232 *******************************************************************************/
233 module linear_extrude_uls
234 (
235  h,
236  center = false
237 )
238 {
239  if ( not_defined(h) )
240  {
241  children();
242  }
243  else if ( is_scalar(h) )
244  {
245  translate(center==true ? [0, 0, -h/2] : origin3d)
246  linear_extrude(height=h)
247  children();
248  }
249  else
250  {
251  z = h[0]; // total height
252 
253  n1 = (len(h) >= 3) ? max(h[1], 0) : undef; // number of scaled-slices
254  z1 = (len(h) >= 3) ? abs(h[2])/100 : undef; // z scale fraction
255  x1 = (len(h) >= 4) ? h[3] /100 : -z1; // x scale fraction
256  y1 = (len(h) >= 5) ? h[4] /100 : x1; // y scale fraction
257 
258  n2 = (len(h) >= 6) ? max(h[5], 0) : n1;
259  z2 = (len(h) >= 7) ? abs(h[6])/100 : z1;
260  x2 = (len(h) >= 8) ? h[7] /100 : x1;
261  y2 = (len(h) >= 9) ? h[8] /100 : y1;
262 
263  h1 = (n1>0) ? z1 * z : 0;
264  h2 = (n2>0) ? z2 * z : 0;
265  h0 = z - h1 - h2;
266 
267  translate(center==true ? [0, 0, -z/2] : origin3d)
268  {
269  if (h1 > 0)
270  {
271  translate([0, 0, h0+h2])
272  for( s = [0 : n1-1] )
273  {
274  translate([0, 0, h1/n1*s])
275  scale([1+x1/n1*(s+1), 1+y1/n1*(s+1), 1])
276  linear_extrude(height=h1/n1)
277  children();
278  }
279  }
280 
281  translate([0, 0, h2])
282  linear_extrude(height=h0)
283  children();
284 
285  if (h2 > 0)
286  {
287  for( s = [0 : n2-1] )
288  {
289  translate([0, 0, h2/n2*s])
290  scale([1+x2/n2*(n2-s), 1+y2/n2*(n2-s), 1])
291  linear_extrude(height=h2/n2)
292  children();
293  }
294  }
295  }
296  }
297 }
298 
299 //! @}
300 //! @}
301 
302 //----------------------------------------------------------------------------//
303 /***************************************************************************//**
304  \addtogroup tools
305  @{
306 
307  \defgroup tools_repeat Repeat
308  \brief Shape repetition and distribution tools.
309  @{
310 *******************************************************************************/
311 //----------------------------------------------------------------------------//
312 
313 //! Distribute copies of a 2d or 3d shape equally about a z-axis radius.
314 /***************************************************************************//**
315  \param n <integer> The number of equally spaced radii.
316  \param r <decimal> The shape move radius.
317  \param angle <boolean> Rotate each copy about z-axis.
318  \param move <boolean> Move each shape copy to radii coordinate.
319 
320  \details
321 
322  \b Example
323  \amu_eval ( function=radial_repeat ${example_dim} )
324 *******************************************************************************/
325 module radial_repeat
326 (
327  n,
328  r = 1,
329  angle = true,
330  move = false
331 )
332 {
333  for ( p = rpolygon_lp( r=r, n=n ) )
334  {
335  translate(move==true ? p : origin2d)
336  rotate(angle==true ? [0, 0, angle_ll(x_axis2d_uv, p)] : origin3d)
337  children();
338  }
339 }
340 
341 //! Distribute copies of 2d or 3d shapes about Cartesian grid.
342 /***************************************************************************//**
343  \param g <integer-list-3|integer> The grid division count. A list
344  [x, y, z] of integers or a single integer for (x=y=z).
345  \param i <decimal-list-3|decimal> The grid increment size. A list
346  [x, y, z] of decimals or a single decimal for (x=y=z).
347  \param c <integer> The number of copies. Number of times to iterate
348  over children.
349  \param center <boolean> Center distribution about origin.
350 
351  \details
352 
353  \b Example
354  \amu_eval ( function=grid_repeat ${example_dim} )
355 *******************************************************************************/
356 module grid_repeat
357 (
358  g,
359  i,
360  c = 1,
361  center = false
362 )
363 {
364  gridd = is_scalar(g) ? g : 1;
365 
366  gridx = edefined_or(g, 0, gridd);
367  gridy = edefined_or(g, 1, gridd);
368  gridz = edefined_or(g, 2, gridd);
369 
370  incrd = is_scalar(i) ? i : 0;
371 
372  incrx = edefined_or(i, 0, incrd);
373  incry = edefined_or(i, 1, incrd);
374  incrz = edefined_or(i, 2, incrd);
375 
376  if ( ( $children * c ) > ( gridx * gridy * gridz ) )
377  {
378  log_warn("more objects than grid capacity, shapes will overlap.");
379  log_info
380  (
381  str
382  (
383  "children=", $children,
384  ", copies=", c,
385  ", objects=", $children * c
386  )
387  );
388  log_info
389  (
390  str
391  (
392  "grid[x,y,z]=[", gridx, ", ", gridy, ", ", gridz, "]",
393  ", capacity=", gridx * gridy * gridz
394  )
395  );
396  }
397 
398  translate
399  (
400  center==true
401  ? [
402  -( min($children * c, gridx) -1 ) * incrx / 2,
403  -( min(ceil($children * c/gridx), gridy) -1 ) * incry / 2,
404  -( min(ceil($children * c/gridx/gridy), gridz) -1 ) * incrz / 2
405  ]
406  : origin3d
407  )
408  if ( c > 0 )
409  {
410  for
411  (
412  y = [0 : (c-1)],
413  x = [0 : ($children-1)]
414  )
415  {
416  j = y * $children + x;
417 
418  translate
419  (
420  [
421  incrx * (j%gridx),
422  incry * (floor(j/gridx)%gridy),
423  incrz * (floor(floor(j/gridx)/gridy)%gridz)
424  ]
425  )
426  children([x]);
427  }
428  }
429 }
430 
431 //! @}
432 //! @}
433 
434 //----------------------------------------------------------------------------//
435 // openscad-amu auxiliary scripts
436 //----------------------------------------------------------------------------//
437 
438 /*
439 BEGIN_SCOPE dim;
440  BEGIN_OPENSCAD;
441  include <tools/tools_utility.scad>;
442 
443  shape = "rotate_extrude_tr";
444  $fn = 72;
445 
446  if (shape == "rotate_extrude_tr")
447  rotate_extrude_tr( r=50, pa=45, ra=270 ) square( [10,5], center=true );
448  else if (shape == "rotate_extrude_tre")
449  rotate_extrude_tre( r=25, l=[5, 50], pa=45, m=31 ) square( [10,5], center=true );
450  else if (shape == "linear_extrude_uls")
451  linear_extrude_uls( [5,10,15,-5], center=true ) square( [20,15], center=true );
452  else if (shape == "radial_repeat")
453  radial_repeat( n=7, r=6, move=true ) square( [20,1], center=true );
454  else if (shape == "grid_repeat")
455  grid_repeat( g=[5,5,4], i=10, c=50, center=true ) {cube(10, center=true); sphere(10);}
456  END_OPENSCAD;
457 
458  BEGIN_MFSCRIPT;
459  include --path "${INCLUDE_PATH}" {config_base,config_png}.mfs;
460 
461  views name "views" views "diag";
462  defines name "shapes" define "shape"
463  strings "
464  rotate_extrude_tr
465  rotate_extrude_tre
466  linear_extrude_uls
467  radial_repeat
468  grid_repeat
469  ";
470  variables add_opts_combine "views shapes";
471  variables add_opts "--viewall --autocenter";
472 
473  include --path "${INCLUDE_PATH}" script_std.mfs;
474  END_MFSCRIPT;
475 END_SCOPE;
476 */
477 
478 //----------------------------------------------------------------------------//
479 // end of file
480 //----------------------------------------------------------------------------//
module radial_repeat(n, r=1, angle=true, move=false)
Distribute copies of a 2d or 3d shape equally about a z-axis radius.
module grid_repeat(g, i, c=1, center=false)
Distribute copies of 2d or 3d shapes about Cartesian grid.
function rpolygon_lp(n, r, a, vr, cw=true)
Compute the coordinates for an n-sided regular polygon.
function is_scalar(v)
Test if a value is a single non-iterable value.
function edefined_or(v, i, d)
Return an iterable element when it exists or a default value when it does not.
module log_warn(m)
Output warning message to console.
Definition: console.scad:137
module log_info(m)
Output information message to console.
Definition: console.scad:122
function not_defined(v)
Test if a value is not defined.
origin3d
The origin point coordinate in 3-dimensional Euclidean space.
Definition: constants.scad:127
function angle_ll(l1, l2)
Compute the angle between two lines (or vectors) in a Euclidean 3d or 2d-space.
function bitwise_is_equal(v, b, t=1)
Test if a base-two bit position of an integer value equals a test bit.
module rotate_extrude_tre(r, l, pa=0, ra=360, m=255, profile=false)
Translate, rotate, and revolve the 2d shape about the z-axis with linear elongation.
origin2d
The origin point coordinate in 2d Euclidean space.
Definition: constants.scad:109
module linear_extrude_uls(h, center=false)
Linearly extrude 2d shape with extrusion upper and lower scaling.
module rotate_extrude_tr(r, pa=0, ra=360, profile=false)
Translate, rotate, and revolve the 2d shape about the z-axis.
x_axis2d_uv
The unit vector of the positive x-axis in 2d Euclidean space.
Definition: constants.scad:112