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