omdl  v1.0
OpenSCAD Mechanical Design Library
layout.scad
Go to the documentation of this file.
1 //! Ordered sequences of geometric transforms as a single composite operation.
2 /***************************************************************************//**
3  \file
4  \author Roy Allen Sutton
5  \date 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 (Layout)
31  \amu_define group_brief (Ordered sequences of geometric transforms as a single composite operation.)
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 
45 //----------------------------------------------------------------------------//
46 
47 //! A transform sequence to place a child shape.
48 /***************************************************************************//**
49  \param t <datastuct> The transform sequence configuration
50  (see below).
51 
52  \param s <integer | integer-list | range> The optional child
53  object selection(s).
54 
55  \param b <decimal-list-2:3> The placement reference region
56  (bounding box).
57 
58  \param mode <integer> Modifier mode.
59 
60  \param verb <integer> Console output verbosity.
61 
62  \details
63 
64  This module performs an ordered sequence of geometric transforms as a
65  single composite operation. Using a transformation configuration
66  list, child objects may be translated, rotated, mirrored, and placed
67  as specified in the table below.
68 
69  This function is a simplified version of layout_grid_rp() that omits
70  child replication functionality.
71 
72  An optional bounding box region may be defined to provide a reference
73  frame for layout placement. The layout—also referred to as the
74  bounding box—serves as a positional guide only; placements may extend
75  beyond this region if desired.
76 
77  ## Multi-value and structured parameters
78 
79  ### t
80 
81  The transform sequence is specified as a configuration list with the
82  elements described below. The operation supports both 2D and 3D
83  modes. The configuration list does not need to be fully specified;
84  any unspecified elements are automatically assigned the default
85  values shown in the table.
86 
87  e | data type | 3D default | 2D default | scalar updates | parameter description
88  ---:|:-----------------:|:----------:|:----------:|:-----------:|:------------------------------------
89  0 | integer | \p mode | \p mode | - | layout modifier mode
90  1 | decimal-list-2:3 \| decimal | [0,0,0] | [0,0] | x | layout placement
91  2 | integer-list-2:3 \| integer | [0,0,0] | [0,0] | x | child mirror
92  3 | decimal-list-2:3 \| decimal | 0 | 0 | z | child rotate
93  4 | decimal-list-2:3 \| decimal | [0,0,0] | [0,0] | x | layout translate
94 
95  #### t[0]: layout modifier mode
96 
97  v | description
98  ---:|:------------------------------------
99  0 | none
100  1 | disable
101  2 | show only
102  3 | highlight / debug
103  4 | transparent / background
104 *******************************************************************************/
105 module layout_grid_p
106 (
107  t,
108  s,
109  b = zero3d,
110  mode = 0,
111  verb = 0
112 )
113 {
114  // apply transform on all children
115  module transform_all()
116  {
117  // group translate
118  gt = [ for (i = [0:ac-1]) b[i] * lp[i] ];
119 
120  translate( gt + lt )
121  rotate( cr )
122  mirror( cm )
123 
124  children();
125  }
126 
127  cs = defined_or(s, [0:$children-1]);
128 
129  ac = is_list(b) ? len(b) : undef;
130 
131  assert
132  (
133  ac == 2 || ac == 3,
134  "Bounds must have two or three dimensions."
135  );
136 
137  c0 = [for (i = [0:ac-1]) 0];
138 
139  //
140  // decode layout list
141  //
142 
143  // mm: modifier mode
144  mm = defined_e_or (t, 0, mode);
145 
146  // lP; layout placement
147  lp = list_get_value(t, 1, c0, ac, 0);
148 
149  // cm: child mirror; cr: child rotate
150  cm = list_get_value(t, 2, c0, ac, 0);
151  cr = defined_e_or (t, 3, 0);
152 
153  // lt: layout translate
154  lt = list_get_value(t, 4, c0, ac, 0);
155 
156  //
157  // apply transform sequence with modifier
158  //
159 
160  if ( mm == 0 )
161  transform_all() children(cs);
162  else if ( mm == 2 )
163  !transform_all() children(cs);
164  else if ( mm == 3 )
165  #transform_all() children(cs);
166  else if ( mm == 4 )
167  %transform_all() children(cs);
168 
169  if (verb > 0)
170  {
171  log_info(strl(["t = ", t, ", s = ", cs, ", b = ", b, ", mode = ", mode]));
172 
173  if (verb >1)
174  echo(mm=mm, lp=lp, cm=cm, cr=cr, lt=lt);
175  }
176 }
177 
178 //! A transform sequence to replicate and place a child shape.
179 /***************************************************************************//**
180  \param t <datastuct> The transform sequence configuration
181  (see below).
182 
183  \param s <integer | integer-list | range> The optional child
184  object selection(s).
185 
186  \param b <decimal-list-2:3> The placement reference region
187  (bounding box).
188 
189  \param center <boolean-list-2:3 | boolean> Center the replication
190  group about the child objects' local origin.
191 
192  \param mode <integer> Modifier mode.
193 
194  \param verb <integer> Console output verbosity.
195 
196  \details
197 
198  This module performs an ordered sequence of geometric transforms as a
199  single composite operation. Using a transformation configuration
200  list, child objects may be translated, rotated, mirrored, placed, and
201  replicated as specified in the table below.
202 
203  An optional bounding box region may be defined to provide a reference
204  frame for layout placement. The layout—also referred to as the
205  bounding box—serves as a positional guide only; placements may extend
206  beyond this region if desired.
207 
208  ## Multi-value and structured parameters
209 
210  ### t
211 
212  The transform sequence is specified as a configuration list with the
213  elements described below. The operation supports both 2D and 3D
214  modes. The configuration list does not need to be fully specified;
215  any unspecified elements are automatically assigned the default
216  values shown in the table.
217 
218  e | data type | 3D default | 2D default | scalar updates | parameter description
219  ---:|:-----------------:|:----------:|:----------:|:-----------:|:------------------------------------
220  0 | integer | \p mode | \p mode | - | layout modifier mode
221  1 | decimal-list-2:3 \| decimal | [0,0,0] | [0,0] | x | layout placement
222  2 | decimal-list-2:3 \| decimal | 0 | 0 | z | layout rotate
223  3 | integer-list-2:3 \| integer | [0,0,0] | [0,0] | x | child mirror
224  4 | decimal-list-2:3 \| decimal | 0 | 0 | z | child rotate
225  5 | decimal-list-2:3 \| decimal | [0,0,0] | [0,0] | x | layout translate
226  6 | integer-list-2:3 \| integer | [1,1,1] | [1,1] | x | child replication
227  7 | integer-list-2:3 \| integer | [1,1,1] | [1,1] | x | replication layout grid
228  8 | boolean-list-2:3 \| boolean | \p center | \p center | [x, y, z] | center replication
229 
230  #### t[0]: layout modifier mode
231 
232  v | description
233  ---:|:------------------------------------
234  0 | none
235  1 | disable
236  2 | show only
237  3 | highlight / debug
238  4 | transparent / background
239 
240  \amu_define scope_id (example)
241  \amu_define title (Transform example)
242  \amu_define image_views (top front diag)
243  \amu_define image_size (sxga)
244 
245  \amu_include (include/amu/scope_diagrams_3d.amu)
246 *******************************************************************************/
247 module layout_grid_rp
248 (
249  t,
250  s,
251  b = zero3d,
252  center = false,
253  mode = 0,
254  verb = 0
255 )
256 {
257  // apply transform on all children
258  module transform_all()
259  {
260  // z-axis object instances and grid spacing (2d and 3d)
261  rc_z = (ac == 2) ? 0 : [0:rc.z-1];
262  rg_z = (ac == 2) ? 0 : rg.z;
263 
264  // group translate
265  gt = [ for (i = [0:ac-1]) b[i] * lp[i] ];
266 
267  // re-center object group offset
268  co = [ for (i = [0:ac-1]) (rg[i] * (rc[i]-1))/2 * (lc[i] == true ? 1 : 0) ];
269 
270  // group placement
271  translate( gt )
272  rotate( lr )
273 
274  // center group + offsets
275  translate( lt - co )
276 
277  // group instances
278  for (i = [0:rc.x-1], j = [0:rc.y-1], k = rc_z)
279  translate( [rg.x * i, rg.y * j, rg_z * k] )
280 
281  // object placement
282  rotate( cr )
283  mirror( cm )
284 
285  children();
286  }
287 
288  cs = defined_or(s, [0:$children-1]);
289 
290  ac = is_list(b) ? len(b) : undef;
291 
292  assert
293  (
294  ac == 2 || ac == 3,
295  "Bounds must have two or three dimensions."
296  );
297 
298  c0 = [for (i = [0:ac-1]) 0];
299  c1 = [for (i = [0:ac-1]) 1];
300  cf = is_list( center ) ? center
301  : [for (i = [0:ac-1]) center];
302 
303  //
304  // decode layout list
305  //
306 
307  // mm: modifier mode
308  mm = defined_e_or (t, 0, mode);
309 
310  // lP; layout placement; lr: layout rotate
311  lp = list_get_value(t, 1, c0, ac, 0);
312  lr = defined_e_or (t, 2, 0);
313 
314  // cm: child mirror; cr: child rotate
315  cm = list_get_value(t, 3, c0, ac, 0);
316  cr = defined_e_or (t, 4, 0);
317 
318  // lt: layout translate
319  lt = list_get_value(t, 5, c0, ac, 0);
320 
321  // rc: child replication; rg: replication layout grid
322  rc = list_get_value(t, 6, c1, ac, 1);
323  rg = list_get_value(t, 7, c0, ac, 0);
324 
325  // lc: center replication
326  lc = list_get_value(t, 8, cf, ac, center, -1);
327 
328  //
329  // apply transform sequence with modifier
330  //
331 
332  if ( mm == 0 )
333  transform_all() children(cs);
334  else if ( mm == 2 )
335  !transform_all() children(cs);
336  else if ( mm == 3 )
337  #transform_all() children(cs);
338  else if ( mm == 4 )
339  %transform_all() children(cs);
340 
341  if (verb > 0)
342  {
343  log_info(strl(["t = ", t, ", s = ", cs, ", b = ", b, ", center = ", center, ", mode = ", mode]));
344 
345  if (verb >1)
346  echo(mm=mm, lp=lp, lr=lr, cm=cm, cr=cr, lt=lt, rc=rc, rg=rg, lc=lc);
347  }
348 }
349 
350 //! @}
351 //! @}
352 
353 //----------------------------------------------------------------------------//
354 // openscad-amu auxiliary scripts
355 //----------------------------------------------------------------------------//
356 
357 /*
358 BEGIN_SCOPE example;
359  BEGIN_OPENSCAD;
360  include <omdl-base.scad>;
361  include <transforms/layout.scad>;
362 
363  $fn = 36;
364 
365  b = [20, 5, 20];
366 
367  v =
368  [
369  3,
370  0,
371  [90,0,0],
372  0,
373  0,
374  0,
375  [6,6,1],
376  [3,3,6]
377  ];
378 
379  %cube(b, center=true);
380  layout_grid_rp( t=v, b=b, center=true, mode=3 )
381  cylinder( r=1, h=6, center=true );
382 
383  // end_include
384  END_OPENSCAD;
385 
386  BEGIN_MFSCRIPT;
387  include --path "${INCLUDE_PATH}" {var_init,var_gen_png2eps}.mfs;
388  table_unset_all sizes;
389 
390  images name "sizes" types "sxga";
391  views name "views" views "top front diag";
392 
393  variables set_opts_combine "sizes views";
394  variables add_opts "--viewall --autocenter --view=axes";
395 
396  include --path "${INCLUDE_PATH}" scr_make_mf.mfs;
397  END_MFSCRIPT;
398 END_SCOPE;
399 */
400 
401 //----------------------------------------------------------------------------//
402 // end of file
403 //----------------------------------------------------------------------------//
404 
module log_info(m)
Output information message to console.
Definition: console.scad:318
zero3d
<decimal-list-2> A 3d zero vector (a list with three zeros).
Definition: constants.scad:422
function defined_e_or(v, i, d)
Returns an element from an iterable if it exists, or a default value if not.
function list_get_value(l, i, dv, s, de, di=0)
Return the value of an indexed list element with output defaults and list composition.
function strl(v)
Convert a list of values to a concatenated string.
function defined_or(v, d)
Return given value, if defined, or a secondary value, if primary is not defined.
module layout_grid_rp(t, s, b=zero3d, center=false, mode=0, verb=0)
A transform sequence to replicate and place a child shape.
Definition: layout.scad:507
module layout_grid_p(t, s, b=zero3d, mode=0, verb=0)
A transform sequence to place a child shape.
Definition: layout.scad:211