omdl  v0.9.5
OpenSCAD Mechanical Design Library
project_box_rectangle.scad
Go to the documentation of this file.
1 //! A rectangular box maker for project boxes, enclosures and housings.
2 /***************************************************************************//**
3  \file
4  \author Roy Allen Sutton
5  \date 2024
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 (Rectangular project box)
31  \amu_define group_brief (Rectangular prism project box generator.)
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_define includes_required_add
43  (
44  tools/operation_cs.scad
45  )
46  \amu_include (include/amu/includes_required.amu)
47 *******************************************************************************/
48 
49 //----------------------------------------------------------------------------//
50 
51 //! A rectangular box maker for project boxes, enclosures and housings.
52 /***************************************************************************//**
53  \param wth <decimal> wall thickness.
54 
55  \param h <datastruct | decimal> box extrusion height;
56  structured data or a single decimal to set the box
57  height.
58 
59  \param size <decimal-list-2 | decimal> box base size; a list [x, y]
60  or a single decimal for (x=y).
61 
62  \param vr <decimal-list-4 | decimal> wall corner rounding radius;
63  a list [v1r, v2r, v3r, v4r] or a single decimal for
64  (v1r=v2r=v3r=v4r).
65 
66  \param vrm <integer-list-4 | integer> wall corner rounding mode =
67  {0:none, 1:bevel, 2:round}; a list [v1rm, v2rm, v3rm,
68  v4rm] or a single decimal for (v1rm=v2rm=v3rm=v4rm).
69 
70  \param inset <decimal-list-2 | decimal> wall-to-lid negative offset;
71  a list [x, y] or a single decimal for (x=y).
72 
73  \param lid <datastruct | decimal> lid extrusion height;
74  structured data or a single decimal to set the lid
75  height.
76 
77  \param lip <datastruct | integer> wall lip; structured data or a
78  single integer to set the lip mode.
79 
80  \param rib <datastruct | integer> wall ribs; structured data or a
81  single integer to set the rib mode.
82 
83  \param wall <datastruct> interior walls; structured data.
84 
85  \param post <datastruct> posts; structured data.
86 
87  \param align <integer-list-3> box alignment; a list [x, y, z].
88 
89  \param mode <integer> module mode of operation.
90 
91  \param verb <integer> console output verbosity
92  {0=quiet, 1=info, 2=details}.
93 
94  \details
95 
96  Construct a rectangular enclosure for electronic and or other
97  project boxes of the like. This module is designed to construct no
98  more than one attached exterior cover and four exterior walls for
99  each invocation. Therefore, a minimum of two invocations are
100  required to construct a complete enclosure with six sides (top,
101  walls, and bottom). Only the parameters \p wth and \p size are
102  require; all others are optional.
103 
104  In a simple case, a box would consist of a (1) cover with attached
105  walls and (2) a separate opposite cover, without walls, to close
106  the box. This would require exactly two invocations. More than two
107  invocations can be used to construct boxes with multiple
108  mid-sections and/or removable covers on one or both sides as shown
109  in the following example.
110 
111  \amu_define scope_id (example_multiple)
112  \amu_define title (Muilti-section project box example)
113  \amu_define image_views (front diag)
114  \amu_define image_size (sxga)
115 
116  \amu_include (include/amu/scope_diagrams_3d.amu)
117 
118  Notice that the middle sections omit the \p lid parameter to skip
119  cover construction in this example.
120 
121  ## Parameter defaults
122 
123  Default values are calculated for all parameters. In some cases,
124  the defaults are calculated based on prior user supplied values.
125  For example, post diameters are calculated based on the supplied
126  screw size for a post instance. Whenever a configuration consists
127  of a list of values, there is no requirement to supply values for
128  all elements of the list. Generally speaking, the list may be
129  terminated at the parameter of interest. The caveat is for
130  parameters of interest that comes after those which are not of
131  interest. In this case, the prior values may be assigned a suitable
132  value or may be assigned the value \b undef to use the calculated
133  default as demonstrated below.
134 
135  \code
136  partial_config = [ 12.42, [1,2], [2,1], 0, [1,2], 31, [1,2,3], 0 ];
137  full_config = [ undef, undef, undef, 2, undef, 31 ];
138  \endcode
139 
140  ## Rounding and extrusions
141 
142  The edge rounding during shape construction is performed using the
143  function polygon_round_eve_all_p(). Refer to its documentation for
144  more information on the rounding modes and their descriptions.
145 
146  All height extrusions for walls, ribs, posts, etc, are performed by
147  the function extrude_linear_mss(). This facilitates flexible
148  scaling along the extrusion height as described in that functions
149  documentation. The <em>box bottom section example</em> at the end
150  of this page shows how this scaling can be used to create features,
151  such as corner rounding and face protrusion, along the lid and box
152  height.
153 
154  ## Multi-value and structured parameters
155 
156  ### h, lid
157 
158  The height of the exterior walls and the box lid are the result of
159  extrusions produced using the function extrude_linear_mss(). The
160  height can be specified as a single decimal value or may be
161  specified as list of scaled sections along the height. For a
162  description on specifying scaled extrusions see the documentation
163  for this extrusion function.
164 
165  ### lip
166 
167  By way of the parameter \p lip, the box walls can have an overhang
168  that interfaces with adjacent wall or lid sections. The adjacent
169  section should be constructed with an opposite lip orientation
170  using the mode configuration.
171 
172  #### Data structure schema:
173 
174  name | schema
175  ---------------:|:----------------------------------------------
176  lip | [ mode, height, width, taper, alignment ]
177 
178  #### Data structure fields: lip
179 
180  e | data type | default value | parameter description
181  ---:|:-----------------:|:-----------------:|:------------------------------------
182  0 | integer | required | mode
183  1 | decimal | wth | height
184  2 | decimal | 45 | base width percentage of wall
185  3 | decimal | 10 | top taper width percentage of wall
186  4 | integer | 0 | alignment
187 
188  #### lip[0]: mode
189 
190  Integer value is binary encoded.
191 
192  b | description
193  ---:|:---------------------------------------
194  0 | upper and inside edge of wall
195  1 | upper and outer edge of wall
196  2 | lower and inside edge of wall
197  3 | lower and outer edge of wall
198 
199  A lip pocket can be generated by using an appropriately sized
200  inside and outer lip together. A corresponding lip pocket-insert
201  can be approximated by using an inside lip with an alignment in the
202  wall center (minimum lip gap).
203 
204  #### lip[4]: alignment
205 
206  v | description
207  ---:|:---------------------------------------
208  0 | maximum lips gap
209  1 | minimum lips gap with backfield
210  2 | minimum lips gap
211 
212  Only inside edge lips may be aligned. Outer edge lips are always
213  aligned with the outer edge of the box wall exterior.
214 
215  ### rib
216 
217  The exterior box walls and lid rigidity can be reinforced using a
218  this options to configure and construct a grid of rib-like
219  structures which are embed on the interior surface of the walls and
220  lid.
221 
222  #### Data structure schema:
223 
224  name | schema
225  ---------------:|:----------------------------------------------
226  rib | [ mode, extrusions, coverage, counts ]
227  extrusions | [ base, x-extrusion, y-extrusion ]
228 
229  #### Data structure fields: rib
230 
231  e | data type | default value | parameter description
232  ---:|:-----------------:|:-----------------:|:------------------------------------
233  0 | integer | required | mode
234  1 | datastruct | (see below) | base and height extrusions
235  2 | decimal-list-3:1 \| decimal | 10 | [x, y, h] coverage percentage
236  3 | integer-list-3:1 \| integer | (calculated) | [x, y, h] count override
237 
238  #### rib[0]: mode
239 
240  Integer value is binary encoded.
241 
242  b | description
243  ---:|:---------------------------------------
244  0 | no ribs on the lid
245  1 | no ribs on the x-positive wall
246  2 | no ribs on the y-positive wall
247  3 | no ribs on the x-negative wall
248  4 | no ribs on the y-negative wall
249  5-6 | lip coverage count (2-bit encoded integer)
250  7 | offset all ribs to bottom of lower lip
251 
252  #### rib[1]: base and height extrusion
253 
254  e | data type | default value | parameter description
255  ---:|:-----------------:|:-----------------:|:------------------------------------
256  0 | decimal | wth | rib base width
257  1 | decimal-list-2 |[[wth, \em rib_edx]]| x-axis oriented rib height extrusion
258  2 | decimal-list-2 |[[wth, \em rib_edy]]| y-axis oriented rib height extrusion
259 
260  The constants \em rib_edx and \em rib_edy are defaults that
261  approximates a half-ellipse rib-like shape. To specify alternative
262  custom extrusions, see the documentation for the extrusion function
263  extrude_linear_mss().
264 
265  ### wall
266 
267  The parameter \p wall may be used to define one or more interior
268  walls to be constructed. There are two types which correspond to
269  walls parallel to the x-axis (type 0) or y-axis (type 1). Each wall
270  instance may be moved, scaled, or rotated.
271 
272  #### Data structure schema:
273 
274  name | schema
275  ---------------:|:----------------------------------------------
276  wall | [ configuration, instances ]
277  configuration | [ mode, defaults ]
278  defaults | [ w, h, vr, vrm ]
279  instances | [ instance, instance, ..., instance ]
280  instance | [ type, move, scale, rotate, size, h, vr, vrm ]
281 
282  #### Data structure fields: wall
283 
284  e | data type | default value | parameter description
285  ---:|:-----------------:|:-----------------:|:------------------------------------
286  0 | datastruct | required | configuration
287  1 | datastruct | required | instances
288 
289  #### wall[0]: configuration
290 
291  e | data type | default value | parameter description
292  ---:|:-----------------:|:-----------------:|:------------------------------------
293  0 | integer | required | mode
294  1 | datastruct | (see below) | defaults
295 
296  ##### wall[0]: configuration[0]: mode
297 
298  Integer value is binary encoded.
299 
300  b | description
301  ---:|:---------------------------------------
302  0-1 | wall end rounding {0:none, 1:bevel, 2:fillet, 3:round-out}
303  2-4 | wall top rounding (1)
304  5-7 | wall base rounding (1)
305  8-9 | wall on lips {0:none, 1:one, 2:both}
306  10 | offset all walls to bottom of lower lip
307 
308  (1) The bits 2-4 and bits 5-7, configure the rounding mode for the
309  wall top and wall base, respectively. The 3-bits integer values are
310  indexed to the rounding options as summarized in the following
311  table:
312 
313  Integer value is binary encoded.
314 
315  v | wall top rounding | wall base rounding
316  ---:|:-----------------:|:-----------------:
317  0 | none | none
318  1 | bevel-in | bevel-in
319  2 | round-in | round-in
320  3 | fillet-in | fillet-in
321  4 | bevel-out | bevel-out
322  5 | fillet-out | fillet-out
323  6 | round-out | round-out
324 
325  ##### wall[0]: configuration[1]: defaults
326 
327  e | data type | default value | parameter description
328  ---:|:-----------------:|:-----------------:|:------------------------------------
329  0 | decimal | wth | width
330  1 | datastruct | \em cfg_he | extrusion
331  2 | decimal-list-4 \| decimal | wth | rounding radius
332  3 | integer-list-4 \| integer |\em cfg_vrm| rounding mode
333 
334  The constants \em cfg_he and \em cfg_vrm define defaults that may
335  be used to round the top, base, and edges of a wall.
336 
337  #### wall[1]: instances
338 
339  e | data type | default value | parameter description
340  ---:|:-----------------:|:-----------------:|:------------------------------------
341  0 | integer | required | type {0: x-axis, 1:y-axis}
342  1 | decimal-list-3:2 \| decimal | [0, 0, 0] | move
343  2 | decimal-list-3:2 \| decimal | [1, 1, 1] | scale
344  3 | decimal-list-3:1 \| decimal | [0, 0, 0] | rotate
345  4 | decimal-list-2 | \em tdef_s | size
346  5 | decimal-list-2 | \em tdef_he | extrusion
347  6 | decimal-list-4 \| decimal | \em tdef_vr | rounding radius
348  7 | integer-list-4 \| integer | \em tdef_vrm | rounding mode
349 
350  The constants \em tdef_s, \em tdef_he, \em tdef_vr, and \em
351  tdef_vrm are default values that depend on the wall type being
352  constructed. For example, \em tdef_s = [max_x, wth] for wall type 0
353  and \em tdef_s = [wth, max_y] for wall type 1. These default may be
354  overridden to provide custom wall sizes, wall rounding and/or
355  height extrusions for each wall instance.
356 
357  ### post
358 
359  This parameter may be used to define one or more screw posts for
360  securing covers, circuit boards, mounts, and the like. There are
361  two types of predefined posts; normal posts and recessed access
362  posts. Recessed posts have a widened access tunnel where screws can
363  be inserted through and below the surface where the post is
364  attached. All posts (and holes) may be rounded at the bottom, to
365  widen the contact with the the adjacent surface, or at the top, to
366  enhance contact or smooth its edges. Each post instance consists of
367  two holes, a post with optional fins, and can be aligned, moved,
368  and rotated. The optional post fins can be either triangular or
369  rectangular in shape.
370 
371  #### Data structure schema:
372 
373  name | schema
374  ---------------:|:----------------------------------------------
375  post | [ configuration, instances ]
376  configuration | [ mode, defaults ]
377  defaults | [ hole0, hole1, post1, hole2, post2, fins0, fins1, calculation ]
378  hole, post (1) | [ d, h, ho, da, ha, vr, vrm ]
379  fins (2) | [ c, sweep-angle, w, d-scale, h-scale, vr, vrm ]
380  calculation | [ hole1-mul, hole1-add, post1-mul, post1-add, hole2-mul, hole2-add, post2-mul, post2-add ]
381  instances | [ instance, instance, ..., instance ]
382  instance | [ type, align. move, rotate, hole0, hole1, post, fins ]
383 
384  (1) All numbered and unnumbered holes and posts utilize this form.
385  (2) All fins defaults and instances are of this form.
386 
387  #### Data structure fields: post
388 
389  e | data type | default value | parameter description
390  ---:|:-----------------:|:-----------------:|:------------------------------------
391  0 | datastruct | required | configuration
392  1 | datastruct | required | instances
393 
394  #### post[0]: configuration
395 
396  e | data type | default value | parameter description
397  ---:|:-----------------:|:-----------------:|:------------------------------------
398  0 | integer | required | mode
399  1 | datastruct | (see below) | defaults
400 
401  ##### post[0]: configuration[0]: mode
402 
403  Integer value is binary encoded.
404 
405  b | description
406  ---:|:---------------------------------------
407  0-1 | post rounding {0:none, 1:bevel, 2:filet}
408  2-3 | fin rounding {0:none, 1:bevel, 2:filet}
409  4 | post base rounded same as top {0:opposite, 1:same}
410  5 | set auxiliary screw hole on opposite side of lid
411  6 | re-calculate defaults with each instance (1)
412  7 | post type that extends into lip height {0:normal, 1:recessed}
413  8 | lip height extension count {0:one, 1:both}
414  9 | offset all posts to bottom of lower lip
415 
416 
417  (1) The post and secondary hole diameter defaults are calculated as
418  shown under calculation described below. This mode bit controls
419  when the calculation is performed; either when defaults are
420  configured (b=0), or when a post instance is created (b=1).
421 
422  ##### post[0]: configuration[1]: defaults
423 
424  e | data type | default value | parameter description
425  ---:|:-----------------:|:-----------------:|:------------------------------------
426  0 | datastruct | (see below) | hole0; the screw hole
427  1 | datastruct | (see below) | hole1; post 1 aux hole
428  2 | datastruct | (see below) | post1; normal-post
429  3 | datastruct | (see below) | hole2; post 2 access hole
430  4 | datastruct | (see below) | post2; recessed-post
431  5 | datastruct | (see below) | fins0: triangular-fins
432  6 | datastruct | (see below) | fins1: rectangular-fins
433  7 | datastruct | (see below) | calculation
434 
435  ##### post[0]: configuration[1]: defaults[0]: hole0
436 
437  e | data type | default value | parameter description
438  ---:|:-----------------:|:-----------------:|:------------------------------------
439  0 | decimal | 3.25 | diameter
440  1 | decimal | (maximum) | height
441  2 | decimal | 0 | height offset
442  3 | decimal | 0 | diameter adjust (1)
443  4 | decimal | 0 | height adjust (1)
444  5 | decimal-list-4 \| decimal| 0 | rounding radius
445  6 | integer-list-4 \| integer| 0 | rounding mode
446 
447  (1) The elements 3 and 4 are used for \em late adjustments to
448  diameters and heights for posts and holes. By \em late, it is meant
449  that they allow for dimension changes without affecting dependent
450  value calculations. This is useful to construct screw holes gaps or
451  for a diameter increase required for brass metal screw inserts, for
452  example. Another example is for use in post height adjustment that
453  allow clearance for circuit board mounting.
454 
455  ##### post[0]: configuration[1]: defaults[1-4]: hole1-2, post1-2
456 
457  The default values for hole1, hole2, post1, and post2 are computed
458  according to that outlined in the defaults calculation section
459  below. The height and offsets are set based on the post height and
460  other configured requirements.
461 
462  ##### post[0]: configuration[1]: defaults[5]: fins0: triangular-fins
463 
464  e | data type | default value | parameter description
465  ---:|:-----------------:|:-----------------:|:------------------------------------
466  0 | integer | 4 | count
467  1 | decimal | 360 | distribution angle
468  2 | decimal | wth | width
469  3 | decimal | 1/5 | post diameter fraction
470  4 | decimal | 5/8 | post height fraction
471  5 | decimal-list-3 \| decimal | \em def_f0_vr | rounding radius
472  6 | integer-list-3 \| integer | \em def_f0_vrm | rounding mode
473 
474  The constants \em def_f0_vr and \em def_f0_vrm define defaults for
475  fin rounding and may be overridden if needed. See the source code
476  for more details.
477 
478  ##### post[0]: configuration[1]: defaults[6]: fins1: rectangular-fins
479 
480  e | data type | default value | parameter description
481  ---:|:-----------------:|:-----------------:|:------------------------------------
482  0 | integer | 4 | count
483  1 | decimal | 360 | distribution angle
484  2 | decimal | wth | width
485  3 | decimal | 1/2 | post diameter fraction
486  4 | decimal | 1 | post height fraction
487  5 | decimal-list-4 \| decimal | \em def_f1_vr | rounding radius
488  6 | integer-list-4 \| integer | \em def_f1_vrm | rounding mode
489 
490  The constants \em def_f1_vr and \em def_f1_vrm define defaults for
491  fin rounding and may be overridden if needed. See the source code
492  for more details.
493 
494  ##### post[0]: configuration[1]: defaults[7]: calculation
495 
496  e | data type | default value | parameter description
497  ---:|:-----------------:|:-----------------:|:------------------------------------
498  0 | decimal | 0 | hole1 multiplier
499  1 | decimal | 0 | hole1 addition
500  2 | decimal | 3.0 | post1 multiplier
501  3 | decimal | wth/2 | post1 addition
502  4 | decimal | 2.0 | hole2 multiplier
503  5 | decimal | wth/2 | hole2 addition
504  6 | decimal | 4.0 | post2 multiplier
505  7 | decimal | wth/2 | post2 addition
506 
507  For hole1, hole2, post1, and post2, the diameters are calculated
508  based on the following model:
509 
510  \code
511  diameter = hole0 + wth * multiplier + addition
512  \endcode
513 
514  where \c hole0 is the screw-hole diameter and \c wth is the
515  configured wall thickness parameter value. This allow for a simple
516  way to generate posts and holes that are dependent on the screw
517  hole diameter. The multiplier and fixed additions for each hole and
518  post may be configured to replace the values shown in the above
519  table.
520 
521  #### post[1]: instances
522 
523  e | data type | default value | parameter description
524  ---:|:-----------------:|:-----------------:|:------------------------------------
525  0 | integer | required | type
526  1 | integer-list-3:1 | undef | align
527  2 | decimal-list-3:2 | [0, 0, 0] | move
528  3 | decimal-list-3:1 \| decimal | [0, 0, 0] | rotate
529  4 | datastruct | (see note) | hole0; screw hole
530  5 | datastruct | (see note) | hole1; aux hole
531  6 | datastruct | (see note) | post
532  7 | datastruct | (see note) | fins
533 
534  \note The default values for the holes, post, and fins are set
535  based on the type and, when not specified with an instances, are
536  obtained from the configured default values as described above.
537 
538  ##### post[1]: instances[0]: type
539 
540  Integer value is binary encoded.
541 
542  b | description
543  ---:|:---------------------------------------
544  0 | post type {0:normal, 1:recessed}
545  1 | fin type {0:triangular, 1:rectangular}
546 
547  ### align
548 
549  The x, y, and z axis of the box can be aligned independently using
550  this parameter.
551 
552  e | data type | default value | parameter description
553  ---:|:-----------------:|:-----------------:|:------------------------------------
554  0 | integer | 0 | x-axis alignment
555  1 | integer | 0 | y-axis alignment
556  2 | integer | 0 | z-axis alignment
557 
558  #### align[0-1]: x or y axis alignment
559 
560  v | description
561  ---:|:---------------------------------------
562  0 | center of enclosure
563  1 | positive exterior edge of lid
564  2 | positive exterior edge of wall
565  3 | positive interior edge of wall
566  4 | negative interior edge of wall
567  5 | negative exterior edge of wall
568  6 | negative exterior edge of lid
569 
570  #### align[2]: z-axis alignment
571 
572  v | description
573  ---:|:---------------------------------------
574  0 | bottom edge of lid
575  1 | bottom edge of wall
576  2 | middle of enclosure
577  3 | middle of wall
578  4 | top edge of wall
579  5 | top edge of lip
580 
581  ### mode
582 
583  Integer value is binary encoded.
584 
585  b | description
586  ---:|:---------------------------------------
587  0 | size is specified for enclosure interior
588  1 | remove features outside of enclosure envelope
589  2 | scale interior with exterior wall during extrusion
590  3 | do not limit wall rounding modes to bevel and rounded (1)
591 
592  (1) When rounding mode limiting is disabled, the rounding mode
593  value, \p vrm, is no longer mapped to \em bevel or \em rounded and
594  any mode of the function polygon_round_eve_all_p() may be used to
595  round the box exterior walls and lid.
596 
597  \amu_define scope_id (example_bottom)
598  \amu_define title (Project box bottom section example)
599  \amu_define image_views (top front right diag)
600  \amu_define image_size (sxga)
601  \amu_define image_columns (4)
602 
603  \amu_include (include/amu/scope_diagrams_3d.amu)
604 *******************************************************************************/
606 (
607  wth,
608  h,
609  size,
610 
611  vr,
612  vrm,
613 
614  inset,
615 
616  lid,
617  lip,
618  rib,
619  wall,
620  post,
621 
622  align,
623  mode = 0,
624  verb = 0
625 )
626 {
627  //
628  //
629  // helper modules and functions
630  //
631  //
632 
633  // exterior walls
634  module construct_exterior_walls( envelop=false )
635  {
636  // re-scale total extrusion height of 'h' equally to 'wall_h'
637  // and extrude scaled version 'hs' to maintain proper wall height
638  hs = !is_list(h) ?
639  wall_h
640  : let( sf=wall_h/h_h )
641  [ for (e=h) !is_list(e) ? e * sf : [ first(e) * sf, second(e) ] ];
642 
643  if ( mode_scale_io == true )
644  { // scale inner and outer wall together
646  difference_cs( envelop == false )
647  {
648  pg_rectangle(wall_xy + 0*[wth, wth], vr=vr, vrm=vrm_ci, center=true);
649  pg_rectangle(wall_xy - 2*[wth, wth], vr=vr, vrm=vrm_ci, center=true);
650  }
651  }
652  else
653  { // scale outer wall only
654  difference_cs( envelop == false )
655  {
657  pg_rectangle(wall_xy + 0*[wth, wth], vr=vr, vrm=vrm_ci, center=true);
658 
659  translate([0, 0, -10*eps/2])
660  extrude_linear_mss(wall_h + 10*eps)
661  pg_rectangle(wall_xy - 2*[wth, wth], vr=vr, vrm=vrm_ci, center=true);
662  }
663  }
664 
665  if (verb > 0)
666  {
667  // generate list of all scale factors in extrusion [x, y]
668  sf_x = !is_list(h) ?
669  1
670  : let( sf = [ for (e=h) !is_list(e) ? 1 : [ for (f=second(e)) !is_list(f) ? f : first(f) ] ] )
671  merge_s( sf );
672 
673  sf_y = !is_list(h) ?
674  1
675  : let( sf = [ for (e=h) !is_list(e) ? 1 : [ for (f=second(e)) !is_list(f) ? f : second(f) ] ] )
676  merge_s( sf );
677 
678  echo(strl(["wall: extrusion scale factors [x-min, x-max] = ", [min(sf_x), max(sf_x)]]));
679  echo(strl(["wall: extrusion scale factors [y-min,y- max] = ", [min(sf_y), max(sf_y)]]));
680  echo(strl(["wall: height (ignoring ribs) = ", wall_h]));
681  echo(strl(["wall: total interior height (ignoring ribs) = ", wall_h + lip_h]));
682  }
683  }
684 
685  // wall lips
686  module construct_lips( envelop=false )
687  {
688  // 'lip_h', bit '1', is set globally (ensure coherency with bits of 'lip')
689  // wall lip: mode, height, base pct, taper pct, alignment
690  lip_m = defined_e_or(lip, 0, lip);
691  lip_bw = defined_e_or(lip, 2, 45);
692  lip_tw = defined_e_or(lip, 3, 10);
693  lip_a = defined_e_or(lip, 4, 0);
694 
695  // calculate lip bevel scaling factor
696  // scale control parameter is percentage of wall thickness
697  sf = 2*wth / max(wall_xy) * lip_tw/100;
698 
699  // inner lip alignment method selection
700  lip_ro = select_ci( [1,2,3], lip_a );
701 
702  translate( [0, 0, wall_h/2] )
703  for
704  (
705  z =
706  [ // [mode, r-offset, z-offset, hc]
707  [3, 0, -1, [1 + sf, 1]], // outer, lower
708  [2, lip_ro, -1, [1 - sf, 1]], // inner, lower
709  [1, 0, +1, [1, 1 + sf]], // outer, upper
710  [0, lip_ro, +1, [1, 1 - sf]] // inner, upper
711  ]
712  )
713  {
714  if ( binary_bit_is(lip_m, first(z), 1) == true )
715  {
716  hc = z[3];
717  ro = second(z);
718 
719  // addition
720  h1 = (ro == 0) ? [lip_h + 0 * eps]
721  : [lip_h + 0 * eps, hc];
722 
723  s1 = (ro == 0) ? wall_xy - 0 * [wth, wth] * lip_bw/100
724  : (ro == 1) ? wall_xy - 2 * [wth, wth] * (1-lip_bw/100)
725  : (ro == 2) ? wall_xy - 2 * [wth, wth] * lip_bw/100
726  : wall_xy - 2 * [wth, wth] * lip_bw/100;
727 
728  // removal
729  h2 = (ro == 0) ? [lip_h + 10 * eps, hc]
730  : [lip_h + 10 * eps];
731 
732  s2 = (ro == 0) ? wall_xy - 2 * [wth, wth] * lip_bw/100
733  : (ro == 1) ? wall_xy - 2 * [wth, wth]
734  : (ro == 2) ? wall_xy - 2 * [wth, wth]
735  : wall_xy - 4 * [wth, wth] * lip_bw/100;
736 
737  translate([0, 0, (wall_h + lip_h - eps)/2 * third(z)])
738  difference_cs( envelop == false )
739  {
740  extrude_linear_uss(h1, center=true)
741  pg_rectangle(s1, vr=vr, vrm=vrm_ci, center=true);
742 
743  extrude_linear_uss(h2, center=true)
744  pg_rectangle(s2, vr=vr, vrm=vrm_ci, center=true);
745  }
746  }
747  }
748 
749  if (verb > 0)
750  {
751  echo(strl(["lip: mode = ", lip_m]));
752  echo(strl(["lip: height = ", lip_h]));
753  echo(strl(["lip: base width percentage = ", lip_bw]));
754  echo(strl(["lip: top reduction percentage = ", lip_tw]));
755  echo(strl(["lip: inner lip alignment index = ", lip_a]));
756  }
757  }
758 
759  // lid extrusion
760  module construct_lid()
761  {
762  mirror([0, 0, 1])
763  translate([0, 0, -eps])
764  extrude_linear_mss(lid)
765  pg_rectangle([encl_x, encl_y] + 0*[wth, wth], vr=vr, vrm=vrm_ci, center=true);
766 
767  if (verb > 0)
768  {
769  echo(strl(["lid: extrusion = ", lid]));
770  echo(strl(["lid: height = ", lid_h]));
771  }
772  }
773 
774  // ribs
775  module construct_ribs()
776  {
777  // mode
778  rib_m = defined_e_or(rib, 0, rib);
779 
780  // B5-6: wall limits (mode dependent)
781  max_x = first( wall_xy) - 2*(wth - eps);
782  max_y = second(wall_xy) - 2*(wth - eps);
783 
784  // 'max_h' may include 0 to 2 'lip_h' (ie: one at top and bottom)
785  max_h = wall_h + min(2, binary_iw2i(rib_m, 5, 2)) * lip_h;
786 
787  // B7: configurable global offset (to align with lower lip)
788  rib_lo = binary_bit_is(rib_m, 7, 1) ? [0, 0, -lip_h] : zero3d;
789 
790  // rib width and extrusion configuration (semicircle)
791  rib_edx = [for (x=[0:1/get_fn(1)/2:1]) [2*sqrt(1-pow(x,2)), 1]];
792 
793  rib_edy = [for (e=rib_edx) reverse(e)];
794 
795  rib_sd = defined_e_or(rib, 1, [ wth, [[wth, rib_edx]], [[wth, rib_edy]] ] );
796 
797  rib_w = defined_e_or(rib_sd, 0, rib_sd);
798  rib_hx = defined_e_or(rib_sd, 1, [[rib_w, rib_edx]]);
799  rib_hy = defined_e_or(rib_sd, 2, [[rib_w, rib_edy]]);
800 
801  // rib coverage percentages
802  rcp_d = defined_e_or(rib, 2, 10);
803 
804  rcp_x = defined_e_or(rcp_d, 0, rcp_d);
805  rcp_y = defined_e_or(rcp_d, 1, rcp_x);
806  rcp_z = defined_e_or(rcp_d, 2, rcp_y);
807 
808  // calculated rib counts based on coverage percentage
809  crc_x = max([0, floor(max_x/rib_w * rcp_x / 100)]);
810  crc_y = max([0, floor(max_y/rib_w * rcp_y / 100)]);
811  crc_z = max([0, floor(max_h/rib_w * rcp_z / 100)]);
812 
813  // rib count assignment
814  cnt_d = defined_e_or(rib, 3, [crc_x, crc_y, crc_z]);
815 
816  cnt_x = defined_e_or(cnt_d, 0, cnt_d);
817  cnt_y = defined_e_or(cnt_d, 1, cnt_x);
818  cnt_z = defined_e_or(cnt_d, 2, cnt_y);
819 
820  //
821  //
822  // construct ribs
823  //
824  //
825 
826  translate(rib_lo)
827  for
828  (
829  i =
830  [ // [ B0-4: mode-bit, size:[x, y], count:[x, y], xform:[r, t] ]
831  [ 0, [max_x, max_y], [cnt_x, cnt_y], [[0, 0, 0], [0, 0, 0]] ],
832  [ 1, [max_y, max_h], [cnt_y, cnt_z], [[90, 0, -90], [max_x/2, 0, max_h/2]] ],
833  [ 2, [max_x, max_h], [cnt_x, cnt_z], [[90, 0, 0], [0, max_y/2, max_h/2]] ],
834  [ 3, [max_y, max_h], [cnt_y, cnt_z], [[90, 0, 90], [-max_x/2, 0, max_h/2]] ],
835  [ 4, [max_x, max_h], [cnt_x, cnt_z], [[-90, 0, 0], [0, -max_y/2, max_h/2]] ],
836  ]
837  )
838  {
839  if ( binary_bit_is(rib_m, first(i), 0) == true )
840  {
841  si = second(i); // size [x, y]
842  ni = third(i); // number [x, y]
843  xi = i[3]; // transform [r, t]
844 
845  sx = first(si);
846  sy = second(si);
847 
848  nx = first(ni);
849  ny = second(ni);
850 
851  translate(second(xi))
852  rotate(first(xi))
853  union()
854  {
855  // ribs-x
856  if (nx > 0)
857  for (i = [0: nx-1])
858  translate([(sx/nx*(1-nx)/2) + (sx/nx * i), 0, 0])
859  extrude_linear_mss(rib_hx)
860  square([rib_w, sy], center=true);
861 
862  // ribs-y
863  if (ny > 0)
864  for (i = [0: ny-1])
865  translate([0, (sy/ny*(1-ny)/2) + (sy/ny * i), 0])
866  extrude_linear_mss(rib_hy)
867  square([sx, rib_w], center=true);
868  }
869  }
870  }
871 
872  if (verb > 0)
873  {
874  // calculate rib heights
875  rib_hxd = sum( [for (e=rib_hx) is_list(e) ? first(e) : e] );
876  rib_hyd = sum( [for (e=rib_hy) is_list(e) ? first(e) : e] );
877 
878  // only when there are ribs on the lid (mode-bit '0' is for the lid)
879  // can not be greater than max xy height less negative lower offset
880  rib_rwh = wall_h + lip_h
881  - max( 0, max([rib_hxd, rib_hyd]) + third(rib_lo) )
882  * ( (binary_bit_is(rib_m, 0, 0) == true) ? 1 : 0 );
883 
884  echo(strl(["rib: mode = ", rib_m]));
885  echo(strl(["rib: width = ", rib_w]));
886  echo(strl(["rib: extrusion x = ", rib_hx]));
887  echo(strl(["rib: height x = ", rib_hxd]));
888  echo(strl(["rib: extrusion y = ", rib_hy]));
889  echo(strl(["rib: height y = ", rib_hyd]));
890  echo(strl(["rib: coverage [x, y, z] = ", [rcp_x, rcp_y, rcp_z]]));
891  echo(strl(["rib: count [x, y, z] = ", [cnt_x, cnt_y, cnt_z]]));
892 
893  echo(strl(["rib: global offset = ", rib_lo]));
894  echo(strl(["rib: remaining wall height = ", rib_rwh]));
895  }
896  }
897 
898  // interior walls
899  module construct_interior_walls()
900  {
901  // wall
902  config = defined_e_or(wall, 0, wall);
903  inst_l = defined_e_or(wall, 1, empty_lst);
904 
905  // configuration
906  wall_m = defined_e_or(config, 0, config);
907  defs_l = defined_e_or(config, 1, empty_lst);
908 
909  // set a few values early for dependent defaults
910  def_dw = defined_e_or(defs_l, 0, wth);
911 
912  // wall limits (mx, my, mz)
913  max_x = first( wall_xy) - 2*(wth - eps);
914  max_y = second(wall_xy) - 2*(wth - eps);
915 
916  // B8-9: 'max_h' may include 0 to 2 'lip_h' (ie: one at top and bottom)
917  max_h = wall_h + min(2, binary_iw2i(wall_m, 8, 2)) * lip_h;
918 
919  // B10: global lower-lip offset
920  wall_lo = binary_bit_is(wall_m, 10, 1) ? [0, 0, -lip_h] : zero3d;
921 
922  // B0-1: default wall end rounding
923  cfg_vrm = let( i = binary_iw2i(wall_m, 0, 2) )
924  (i == 1) ? [ 9, 10, 9, 10] // bevel
925  : (i == 2) ? [ 3, 4, 3, 4] // fillet
926  : (i == 3) ? [ 7, 8, 7, 8] // round-out
927  : 0; // none
928 
929  // configurations for top wall extrusion rounding factors for horizontal
930  // wall using approximated semicircles with $fn segments for rounding
931  // (must reverse for bottom and reorder x/y for vertical wall).
932  cfg_wt_rm =
933  [
934  0, // none
935  [[1,1],[1,1/2]], // bevel-in
936  [for (x=[0:1/get_fn(1)/2:1]) [1,sqrt(1+eps-pow(x,2))]], // round-in
937  [for (x=[1:-1/get_fn(1)/2:1/2]) [1,1-sqrt(1-pow(x,2))]], // fillet-in
938  [[1,1],[1,1+1/2]], // bevel-out
939  [for (x=[0:1/get_fn(1)/2:1]) [1,sqrt(1+eps+pow(x,2))]], // fillet-out
940  [for (x=[1:-1/get_fn(1)/2:1/2]) [1,1+sqrt(1-pow(x,2))]], // round-out
941  ];
942 
943  // B2-4: wall top rounding
944  wt_rm_i = binary_iw2i(wall_m, 2, 3);
945  s_wt_rm = select_ci( cfg_wt_rm, wt_rm_i, true );
946  cfg_rt = [def_dw/2, s_wt_rm];
947 
948  // B5-7: wall base rounding
949  wb_rm_i = binary_iw2i(wall_m, 5, 3);
950  s_wb_rm = select_ci( cfg_wt_rm, wb_rm_i, true );
951  cfg_rb = [def_dw/2, reverse(s_wb_rm)];
952 
953  // default height extrusion configuration
954  cfg_he =
955  (wt_rm_i > 0 && wb_rm_i == 0) ? [max_h - def_dw/2, cfg_rt] // top only
956  : (wt_rm_i == 0 && wb_rm_i > 0) ? [cfg_rb, max_h - def_dw/2] // base only
957  : (wt_rm_i > 0 && wb_rm_i > 0) ? [cfg_rb, max_h - def_dw, cfg_rt] // both
958  : max_h; // neither
959 
960  // configured configuration defaults
961  def_he = defined_e_or(defs_l, 1, cfg_he);
962  def_vr = defined_e_or(defs_l, 2, def_dw);
963  def_vrm = defined_e_or(defs_l, 3, cfg_vrm);
964 
965  //
966  //
967  // construct walls
968  //
969  //
970 
971  // process wall instance list
972  translate(wall_lo)
973  for (inst=inst_l)
974  {
975  inst_t = defined_e_or(inst, 0, inst); // type
976 
977  inst_m = defined_e_or(inst, 1, zero3d); // *move
978  inst_f = defined_e_or(inst, 2, [1, 1, 1]); // scale
979  inst_r = defined_e_or(inst, 3, zero3d); // rotate
980 
981  inst_s = defined_e_or(inst, 4, undef); // *size
982  inst_he = defined_e_or(inst, 5, undef); // *he
983  inst_vr = defined_e_or(inst, 6, undef); // *vr
984  inst_vrm = defined_e_or(inst, 7, undef); // *vrm
985 
986  //
987  // default value updates based on wall type: (0=horizontal, 1=vertical)
988  //
989 
990  // move vector
991  type_m = is_list(inst_m) ?
992  inst_m
993  : (inst_t == 0) ?
994  [0, inst_m]
995  : [inst_m, 0];
996 
997  // max length horizontal or vertical base shape
998  tdef_s = (inst_t == 0) ?
999  [max_x, def_dw]
1000  : [def_dw, max_y];
1001 
1002  // wall base extrusion (adjusted for vertical walls)
1003  tdef_he = !is_list(def_he) ?
1004  def_he // use specified scalar value
1005  : (inst_t == 0) ?
1006  def_he // horizontal: use list as defined
1007  : [ for (he=def_he) // vertical: reverse [x, y] scale factors
1008  !is_list(he) ?
1009  he
1010  : [ first(he), [ for (s=second(he)) reverse(s) ] ]
1011  ];
1012 
1013  // wall-end rounding radii (adjusted for vertical walls)
1014  tdef_vr = !is_list(def_vr) ?
1015  def_vr
1016  : (inst_t == 0) ?
1017  def_vr
1018  : shift(def_vr, n=-1, r=false, c=true);
1020  // wall-end rounding modes (adjusted for vertical walls)
1021  tdef_vrm = !is_list(def_vrm) ?
1022  def_vrm
1023  : (inst_t == 0) ?
1024  def_vrm
1025  : shift(def_vrm, n=+1, r=false, c=true);
1026 
1027  //
1028  // assign defaults when not specified with wall instance
1029  //
1030 
1031  s = defined_or(inst_s, tdef_s);
1032  he = defined_or(inst_he, tdef_he);
1033  vr = defined_or(inst_vr, tdef_vr);
1034  vrm = defined_or(inst_vrm, tdef_vrm);
1035 
1036  //
1037  // construct wall instance
1038  //
1039 
1040  translate(type_m)
1041  scale(inst_f)
1042  rotate(inst_r)
1043  extrude_linear_mss(he)
1044  pg_rectangle(s, vr=vr, vrm=vrm, center=true);
1045 
1046  if (verb > 1)
1047  echo(strl(["wall-inst: [type, move, scale, rotation, size, he, vr, vrm] = ",
1048  [inst_t, inst_m, inst_f, inst_r, s, he, vr, vrm]]));
1049  }
1050 
1051  if (verb > 0)
1052  {
1053  // handle special case: a single horizontal or vertical wall
1054  wall_cnt = is_list(inst_l) ? len(inst_l) : 1;
1055 
1056  echo(strl(["wall: configuration = ", config]));
1057  echo(strl(["wall: mode = ", wall_m]));
1058 
1059  echo(strl(["wall: max [x, y, h] = ", [max_x, max_y, max_h]]));
1060 
1061  echo(strl(["wall: default width = ", def_dw]));
1062  echo(strl(["wall: default extrusion = ", def_he]));
1063  echo(strl(["wall: default edge rounding = ", def_vr]));
1064  echo(strl(["wall: default edge rounding mode = ", def_vrm]));
1065 
1066  echo(strl(["wall: count = ", wall_cnt]));
1067 
1068  echo(strl(["wall: global offset = ", wall_lo]));
1069  }
1070  }
1071 
1072  // posts and screw holes
1073  module construct_posts( add=false, remove=false )
1074  {
1075  // post
1076  config = defined_e_or(post, 0, post);
1077  inst_l = defined_e_or(post, 1, empty_lst);
1078 
1079  // configuration
1080  post_m = defined_e_or(config, 0, config);
1081  defs_l = defined_e_or(config, 1, empty_lst);
1082 
1083  // B4: post base rounded same as post top
1084  cfg_rbst = binary_bit_is(post_m, 4, 1);
1085 
1086  // rounding constant configurations
1087  cfg_p_vr_sf = (cfg_rbst == true) ? [0, 1/2, 1/2, 0] : [0, 1/2, 3/2, 0];
1088  cfg_p_vrm_filet = (cfg_rbst == true) ? [0, 1, 1, 0] : [0, 1, 4, 0];
1089  cfg_p_vrm_bevel = (cfg_rbst == true) ? [0, 5, 5, 0] : [0, 5, 10, 0];
1090 
1091  cfg_f0_vr_sf = [2, 0, 1];
1092  cfg_f0_vrm_filet = [4, 0, 3];
1093  cfg_f0_vrm_bevel = [10, 0, 9];
1094 
1095  cfg_f1_vr_sf = [0, 1, 1, 0];
1096  cfg_f1_vrm_filet = [0, 4, 3, 0];
1097  cfg_f1_vrm_bevel = [0, 10, 9, 0];
1098 
1099  // mode dependent configuration
1100  // B0-1: post rounding mode
1101  cfg_p_vrm = let( i = binary_iw2i(post_m, 0, 2) )
1102  (i == 1) ? cfg_p_vrm_bevel
1103  : (i == 2) ? cfg_p_vrm_filet
1104  : 0;
1105 
1106  // B2-3: fin rounding mode
1107  cfg_f0_vrm = let( i = binary_iw2i(post_m, 2, 2) )
1108  (i == 1) ? cfg_f0_vrm_bevel
1109  : (i == 2) ? cfg_f0_vrm_filet
1110  : 0;
1111 
1112  cfg_f1_vrm = let( i = binary_iw2i(post_m, 2, 2) )
1113  (i == 1) ? cfg_f1_vrm_bevel
1114  : (i == 2) ? cfg_f1_vrm_filet
1115  : 0;
1116 
1117  // B5: auxiliary screw hole height (through lid)
1118  cfg_h1_h = binary_bit_is(post_m, 5, 1) ? lid_h : 0;
1119 
1120  // B6: re-calculate defaults with each instance.
1121  cfg_hp_idr = binary_bit_is(post_m, 6, 1);
1122 
1123  // B8: total lip_h extension height (0: one, 1: both)
1124  lip_h_t = ((binary_bit_is(post_m, 8, 1) ? 1 : 0) + 1) * lip_h;
1125 
1126  // B7: post1 and post2 heights (only one extends by lip height)
1127  cfg_p1_h = (binary_bit_is(post_m, 7, 1) ? lip_h_t : 0) + wall_h;
1128  cfg_p2_h = (binary_bit_is(post_m, 7, 0) ? lip_h_t : 0) + wall_h;
1129 
1130  // B9: global lower-lip offset
1131  post_lo = binary_bit_is(post_m, 9, 1) ? [0, 0, -lip_h] : zero3d;
1132 
1133  max_x = first( wall_xy) - 2*(wth - eps);
1134  max_y = second(wall_xy) - 2*(wth - eps);
1135  max_h = wall_h + lip_h_t;
1136 
1137  //
1138  // configured configuration defaults
1139  //
1140 
1141  def_h0 = defined_e_or(defs_l, 0, empty_lst);
1142  def_h1 = defined_e_or(defs_l, 1, empty_lst);
1143  def_p1 = defined_e_or(defs_l, 2, empty_lst);
1144  def_h2 = defined_e_or(defs_l, 3, empty_lst);
1145  def_p2 = defined_e_or(defs_l, 4, empty_lst);
1146  def_f0 = defined_e_or(defs_l, 5, empty_lst);
1147  def_f1 = defined_e_or(defs_l, 6, empty_lst);
1148  def_dc = defined_e_or(defs_l, 7, empty_lst);
1149 
1150  // hole0: normal & recessed screw common hole
1151  def_h0_d = defined_e_or(def_h0, 0, 3.25);
1152  def_h0_h = defined_e_or(def_h0, 1, max_h);
1153  def_h0_ho = defined_e_or(def_h0, 2, 0);
1154  def_h0_da = defined_e_or(def_h0, 3, 0);
1155  def_h0_ha = defined_e_or(def_h0, 4, 0);
1156  def_h0_vr = defined_e_or(def_h0, 5, 0);
1157  def_h0_vrm = defined_e_or(def_h0, 6, 0);
1158 
1159  //
1160  // default diameter calculations based on hole0
1161  //
1162  def_h1_d_c = def_h0_d
1163  + defined_e_or(def_dc, 0, 0.0) * wth
1164  + defined_e_or(def_dc, 1, 0);
1165 
1166  def_p1_d_c = def_h0_d
1167  + defined_e_or(def_dc, 2, 3.0) * wth
1168  + defined_e_or(def_dc, 3, wth/2);
1169 
1170  def_h2_d_c = def_h0_d
1171  + defined_e_or(def_dc, 4, 2.0) * wth
1172  + defined_e_or(def_dc, 5, wth/2);
1173 
1174  def_p2_d_c = def_h0_d
1175  + defined_e_or(def_dc, 6, 4.0) * wth
1176  + defined_e_or(def_dc, 7, wth/2);
1177 
1178  // hole1: normal thru lid hole
1179  def_h1_d = defined_e_or(def_h1, 0, def_h1_d_c);
1180  def_h1_h = defined_e_or(def_h1, 1, cfg_h1_h);
1181  def_h1_ho = defined_e_or(def_h1, 2, -cfg_h1_h);
1182  def_h1_da = defined_e_or(def_h1, 3, 0);
1183  def_h1_ha = defined_e_or(def_h1, 4, 0);
1184  def_h1_vr = defined_e_or(def_h1, 5, 0);
1185  def_h1_vrm = defined_e_or(def_h1, 6, 0);
1186 
1187  // post1: normal mount post
1188  def_p1_d = defined_e_or(def_p1, 0, def_p1_d_c);
1189  def_p1_h = defined_e_or(def_p1, 1, cfg_p1_h);
1190  def_p1_ho = defined_e_or(def_p1, 2, 0);
1191  def_p1_da = defined_e_or(def_p1, 3, 0);
1192  def_p1_ha = defined_e_or(def_p1, 4, 0);
1193  def_p1_vr = defined_e_or(def_p1, 5, cfg_p_vr_sf * wth);
1194  def_p1_vrm = defined_e_or(def_p1, 6, cfg_p_vrm);
1195 
1196  // hole2: recessed access hole thru lid
1197  def_h2_d = defined_e_or(def_h2, 0, def_h2_d_c);
1198  def_h2_h = defined_e_or(def_h2, 1, cfg_p2_h);
1199  def_h2_ho = defined_e_or(def_h2, 2, -lid_h);
1200  def_h2_da = defined_e_or(def_h2, 3, 0);
1201  def_h2_ha = defined_e_or(def_h2, 4, 0);
1202  def_h2_vr = defined_e_or(def_h2, 5, cfg_p_vr_sf * wth/2);
1203  def_h2_vrm = defined_e_or(def_h2, 6, cfg_p_vrm);
1204 
1205  // post2: recessed access post
1206  def_p2_d = defined_e_or(def_p2, 0, def_p2_d_c);
1207  def_p2_h = defined_e_or(def_p2, 1, cfg_p2_h);
1208  def_p2_ho = defined_e_or(def_p2, 2, 0);
1209  def_p2_da = defined_e_or(def_p2, 3, 0);
1210  def_p2_ha = defined_e_or(def_p2, 4, 0);
1211  def_p2_vr = defined_e_or(def_p2, 5, cfg_p_vr_sf * wth);
1212  def_p2_vrm = defined_e_or(def_p2, 6, cfg_p_vrm);
1213 
1214  // fins0: triangular fins
1215  def_f0_c = defined_e_or(def_f0, 0, 4);
1216  def_f0_da = defined_e_or(def_f0, 1, 360);
1217  def_f0_w = defined_e_or(def_f0, 2, wth);
1218  def_f0_d_sf = defined_e_or(def_f0, 3, 1/5);
1219  def_f0_h_sf = defined_e_or(def_f0, 4, 5/8);
1220  def_f0_vr = defined_e_or(def_f0, 5, cfg_f0_vr_sf * wth);
1221  def_f0_vrm = defined_e_or(def_f0, 6, cfg_f0_vrm);
1222 
1223  // fins1: rectangular fins
1224  def_f1_c = defined_e_or(def_f1, 0, 4);
1225  def_f1_da = defined_e_or(def_f1, 1, 360);
1226  def_f1_w = defined_e_or(def_f1, 2, wth);
1227  def_f1_d_sf = defined_e_or(def_f1, 3, 1/2);
1228  def_f1_h_sf = defined_e_or(def_f1, 4, 1);
1229  def_f1_vr = defined_e_or(def_f1, 5, cfg_f1_vr_sf * wth);
1230  def_f1_vrm = defined_e_or(def_f1, 6, cfg_f1_vrm);
1231 
1232  //
1233  //
1234  // construct posts
1235  //
1236  //
1237 
1238  // construct fins around a cylinder
1239  module construct_fins(d, h, t, f)
1240  {
1241  c = defined_e_or(f, 0, 0);
1242 
1243  // move distance for fin to always contact polygon cylinder
1244  function fin_embed(r, w) =
1245  let
1246  (
1247  n = get_fn(r),
1248  d = polygon_regular_perimeter(n, r) / n
1249  )
1250  r - sqrt( pow(r,2) - pow(w/2, 2) - pow(d/2, 2) );
1251 
1252  if ( c > 0 )
1253  {
1254  da = f[1];
1255  w = f[2];
1256  df = f[3];
1257  hf = f[4];
1258  vr = f[5];
1259  vrm = f[6];
1260 
1261  b = d * df;
1262  l = h * hf;
1263 
1264  if (verb > 2)
1265  echo(strl(["post-inst-fins: [d, h, t, f] = ", [d, h, t, f]]));
1266 
1267  f_in = fin_embed(d/2, w);
1268 
1269  // triangular fins
1270  if ( t == 0 )
1271  {
1272  for (i = [0:c-1])
1273  {
1274  rotate([90, 0, da/c * i + 180])
1275  translate([-d/2 - b + f_in, 0, 0])
1276  extrude_linear_mss(w, center=true)
1277  pg_triangle_sas([l, 90, b], vr=vr, vrm=vrm);
1278  }
1279  }
1280 
1281  // rectangular fins
1282  if ( t == 1 )
1283  {
1284  for (i = [0:c-1])
1285  {
1286  rotate([0, 0, da/c * i + 180])
1287  translate([b/2 + d/2 - f_in, 0, 0])
1289  pg_rectangle( [b, w], vr=vr, vrm=vrm, center=true);
1290  }
1291  }
1292 
1293  }
1294  }
1295 
1296  // construct a cylinder with optional fins
1297  module construct_cylinder ( en, c, ft, f, eps=0 )
1298  {
1299  if (en == true)
1300  {
1301  d = c[0];
1302  h = c[1];
1303  ho = c[2];
1304  da = c[3];
1305  ha = c[4];
1306  vr = c[5];
1307  vrm = c[6];
1308 
1309  if (verb > 2)
1310  echo(strl(["post-inst-cylinder: [c, eps] = ", [c, eps]]));
1311 
1312  translate([0, 0, ho - eps/2])
1313  {
1314  // late adjustments
1315  d_adj = d + da;
1316  h_adj = h + ha;
1317 
1318  rotate_extrude()
1319  pg_rectangle([d_adj/2, h_adj + eps], vr=vr, vrm=vrm);
1320 
1321  construct_fins(d_adj, h_adj, ft, f);
1322  }
1323  }
1324  }
1325 
1326  // pre-processing message
1327  if (verb > 0)
1328  {
1329  post_cfm = ( add == true && remove == false ) ? "add"
1330  : ( add == false && remove == true ) ? "remove"
1331  : ( add == true && remove == true ) ? "add & remove"
1332  : "do nothing";
1333 
1334  echo(strl(["post: construction phase = ", post_cfm]));
1335  }
1336 
1337  // process 'post' instance list
1338  translate(post_lo)
1339  for (inst=inst_l)
1340  {
1341  inst_t = defined_e_or(inst, 0, inst); // type
1342 
1343  inst_a = defined_e_or(inst, 1, undef); // align [x, y, z]
1344  inst_m = defined_e_or(inst, 2, zero3d); // move [x, y, z]
1345  inst_r = defined_e_or(inst, 3, zero3d); // rotate [x, y, z]
1346 
1347  inst_h0 = defined_e_or(inst, 4, undef); // hole0
1348  inst_h1 = defined_e_or(inst, 5, undef); // hole1
1349  inst_p = defined_e_or(inst, 6, undef); // post
1350 
1351  inst_f = defined_e_or(inst, 7, undef); // fins
1352 
1353  // alignment
1354  inst_ax = defined_e_or(inst_a, 0, undef);
1355  inst_ay = defined_e_or(inst_a, 1, undef);
1356  inst_az = defined_e_or(inst_a, 2, 0);
1357 
1358  inst_zx = is_undef( inst_ax ) ? 0
1359  : ( binary_bit_is(inst_ax, 0, 0) ? -1 : +1 ) * (max_x + wth)/2;
1360 
1361  inst_zy = is_undef( inst_ay ) ? 0
1362  : ( binary_bit_is(inst_ay, 0, 0) ? -1 : +1 ) * (max_y + wth)/2;
1363 
1364  inst_zz = ( binary_bit_is(inst_az, 0, 0) ? 0 : -lid_h );
1365 
1366  //
1367  // default value updates based on types
1368  //
1369 
1370  // B0: post-type
1371  inst_pt = binary_iw2i(inst_t, 0, 1);
1372 
1373  // hole0:
1374 
1375  // hole1:
1376  tdef_h1_d_c = (inst_pt == 0) ? def_h1_d_c : def_h2_d_c;
1377  tdef_h1_d = (inst_pt == 0) ? def_h1_d : def_h2_d;
1378  tdef_h1_h = (inst_pt == 0) ? def_h1_h : def_h2_h;
1379  tdef_h1_ho = (inst_pt == 0) ? def_h1_ho : def_h2_ho;
1380  tdef_h1_da = (inst_pt == 0) ? def_h1_da : def_h2_da;
1381  tdef_h1_ha = (inst_pt == 0) ? def_h1_ha : def_h2_ha;
1382  tdef_h1_vr = (inst_pt == 0) ? def_h1_vr : def_h2_vr;
1383  tdef_h1_vrm = (inst_pt == 0) ? def_h1_vrm : def_h2_vrm;
1384 
1385  // post:
1386  tdef_p_d_c = (inst_pt == 0) ? def_p1_d_c : def_p2_d_c;
1387  tdef_p_d = (inst_pt == 0) ? def_p1_d : def_p2_d;
1388  tdef_p_h = (inst_pt == 0) ? def_p1_h : def_p2_h;
1389  tdef_p_ho = (inst_pt == 0) ? def_p1_ho : def_p2_ho;
1390  tdef_p_da = (inst_pt == 0) ? def_p1_da : def_p2_da;
1391  tdef_p_ha = (inst_pt == 0) ? def_p1_ha : def_p2_ha;
1392  tdef_p_vr = (inst_pt == 0) ? def_p1_vr : def_p2_vr;
1393  tdef_p_vrm = (inst_pt == 0) ? def_p1_vrm : def_p2_vrm;
1394 
1395  // B1: fins-type
1396  inst_ft = binary_iw2i(inst_t, 1, 1);
1397 
1398  // fins:
1399  tdef_f_c = (inst_ft == 0) ? def_f0_c : def_f1_c;
1400  tdef_f_da = (inst_ft == 0) ? def_f0_da : def_f1_da;
1401  tdef_f_w = (inst_ft == 0) ? def_f0_w : def_f1_w;
1402  tdef_f_d_sf = (inst_ft == 0) ? def_f0_d_sf : def_f1_d_sf;
1403  tdef_f_h_sf = (inst_ft == 0) ? def_f0_h_sf : def_f1_h_sf;
1404  tdef_f_vr = (inst_ft == 0) ? def_f0_vr : def_f1_vr;
1405  tdef_f_vrm = (inst_ft == 0) ? def_f0_vrm : def_f1_vrm;
1406 
1407  //
1408  // assign defaults when not specified with post instance
1409  //
1410 
1411  // hole0: screw hole
1412  h0_en = (remove == true);
1413 
1414  h0_d = defined_e_or(inst_h0, 0, def_h0_d);
1415  h0_h = defined_e_or(inst_h0, 1, def_h0_h);
1416  h0_ho = defined_e_or(inst_h0, 2, def_h0_ho);
1417  h0_da = defined_e_or(inst_h0, 3, def_h0_da);
1418  h0_ha = defined_e_or(inst_h0, 4, def_h0_ha);
1419  h0_vr = defined_e_or(inst_h0, 5, def_h0_vr);
1420  h0_vrm = defined_e_or(inst_h0, 6, def_h0_vrm);
1421 
1422  h0 = [h0_d, h0_h, h0_ho, h0_da, h0_ha, h0_vr, h0_vrm];
1423 
1424  //
1425  // assign hole and post defaults based on selected mode 'cfg_hp_idr'
1426  //
1427  tdef_h1_ims = (cfg_hp_idr == true) ? h0_d + tdef_h1_d_c : tdef_h1_d;
1428  tdef_p_ims = (cfg_hp_idr == true) ? h0_d + tdef_p_d_c : tdef_p_d;
1429 
1430  // hole1: aux screw hole or thru lid access hole
1431  h1_en = (remove == true);
1432 
1433  h1_d = defined_e_or(inst_h1, 0, tdef_h1_ims);
1434  h1_h = defined_e_or(inst_h1, 1, tdef_h1_h);
1435  h1_ho = defined_e_or(inst_h1, 2, tdef_h1_ho);
1436  h1_da = defined_e_or(inst_h1, 3, tdef_h1_da);
1437  h1_ha = defined_e_or(inst_h1, 4, tdef_h1_ha);
1438  h1_vr = defined_e_or(inst_h1, 5, tdef_h1_vr);
1439  h1_vrm = defined_e_or(inst_h1, 6, tdef_h1_vrm);
1440 
1441  h1 = [h1_d, h1_h, h1_ho, h1_da, h1_ha, h1_vr, h1_vrm];
1442 
1443  // post: post and fins
1444  p_en = (add == true);
1445 
1446  p_d = defined_e_or(inst_p, 0, tdef_p_ims);
1447  p_h = defined_e_or(inst_p, 1, tdef_p_h);
1448  p_ho = defined_e_or(inst_p, 2, tdef_p_ho);
1449  p_da = defined_e_or(inst_p, 3, tdef_p_da);
1450  p_ha = defined_e_or(inst_p, 4, tdef_p_ha);
1451  p_vr = defined_e_or(inst_p, 5, tdef_p_vr);
1452  p_vrm = defined_e_or(inst_p, 6, tdef_p_vrm);
1453 
1454  p = [p_d, p_h, p_ho, p_da, p_ha, p_vr, p_vrm];
1455 
1456  f_c = defined_e_or(inst_f, 0, tdef_f_c);
1457  f_da = defined_e_or(inst_f, 1, tdef_f_da);
1458  f_w = defined_e_or(inst_f, 2, tdef_f_w);
1459  f_d_sf = defined_e_or(inst_f, 3, tdef_f_d_sf);
1460  f_h_sf = defined_e_or(inst_f, 4, tdef_f_h_sf);
1461  f_vr = defined_e_or(inst_f, 5, tdef_f_vr);
1462  f_vrm = defined_e_or(inst_f, 6, tdef_f_vrm);
1463 
1464  f = [f_c, f_da, f_w, f_d_sf, f_h_sf, f_vr, f_vrm];
1465 
1466  //
1467  // construct post instance
1468  //
1469 
1470  translate(inst_m) // do separately to allow for 2d
1471  translate([inst_zx, inst_zy, inst_zz]) // moves in 'inst_m' of form [x, y]
1472  rotate(inst_r)
1473  union()
1474  {
1475  construct_cylinder(p_en, p, inst_ft, f);
1476 
1477  construct_cylinder(h0_en, h0, eps=10*eps);
1478  construct_cylinder(h1_en, h1, eps=10*eps);
1479  }
1480 
1481  if (verb > 1)
1482  echo(strl(["post-inst: [type, align, move, rotation, hole0, hole1, post, fins] = ",
1483  [inst_t, inst_a, inst_m, inst_r, inst_h0, inst_h1, inst_p, inst_f]]));
1484  }
1485 
1486  // post-processing message
1487  if (verb > 0)
1488  {
1489  // handle special case: a single post
1490  post_cnt = is_list(inst_l) ? len(inst_l) : 1;
1491 
1492  echo(strl(["post: configuration = ", config]));
1493  echo(strl(["post: mode = ", post_m]));
1494 
1495  echo(strl(["post: count = ", post_cnt]));
1496  }
1497  }
1498 
1499  // limit child to wall interior volume
1500  module envelop_assembly( envelop=false )
1501  {
1502  if ( envelop == true )
1503  {
1504  intersection()
1505  {
1506  union()
1507  {
1508  construct_exterior_walls( true );
1509  construct_lips( true );
1510  }
1511 
1512  children();
1513  }
1514  }
1515  else
1516  {
1517  children();
1518  }
1519  }
1520 
1521  // assembly feature additions
1522  module assembly_add()
1523  {
1524  if ( wall_h > 0 )
1525  {
1526  construct_exterior_walls();
1527  }
1528 
1529  if ( is_defined( lip ) )
1530  {
1531  construct_lips();
1532  }
1533 
1534  if ( lid_h > 0 )
1535  {
1536  construct_lid();
1537  }
1538 
1539  //
1540  // better to apply envelop_assembly() to union of all?
1541  //
1542 
1543  if ( is_defined( rib ) )
1544  {
1545  envelop_assembly( mode_int_mask == true )
1546  construct_ribs();
1547  }
1548 
1549  if ( is_defined( wall ) )
1550  {
1551  envelop_assembly( mode_int_mask == true )
1552  construct_interior_walls();
1553  }
1554 
1555  if ( is_defined( post ) )
1556  {
1557  envelop_assembly( mode_int_mask == true )
1558  construct_posts( add=true);
1559  }
1560  }
1561 
1562  // assembly feature removals
1563  module assembly_remove()
1564  {
1565  if ( is_defined( post ) )
1566  {
1567  construct_posts( remove=true);
1568  }
1569  }
1570 
1571  //
1572  //
1573  // global parameter calculation
1574  //
1575  //
1576 
1577  // decode mode configurations
1578  mode_size_in = binary_bit_is(mode, 0, 1);
1579  mode_int_mask = binary_bit_is(mode, 1, 1);
1580  mode_scale_io = binary_bit_is(mode, 2, 1);
1581  mode_lmt_vrm = binary_bit_is(mode, 3, 0);
1582 
1583  // specified wall extrusion height
1584  // calculate total extrusion 'h_h' height of all sections
1585  hv = is_defined(h) ? [for (e=h) is_list(e) ? first(e) : e] : [0];
1586  h_h = sum(hv);
1587 
1588  // specified base size
1589  size_x = defined_e_or(size, 0, size);
1590  size_y = defined_e_or(size, 1, size_x);
1591 
1592  // limit rounding mode to those options that make sense; set={0, 5, 1}
1593  // limit each element when 'vrm' is a list
1594  vrm_ci = (mode_lmt_vrm == false) ? vrm
1595  : is_list(vrm) ?
1596  [for (e=vrm) select_ci(v=[0, 5, 1], i=e, l=false)]
1597  : select_ci(v=[0, 5, 1], i=vrm, l=false);
1598 
1599  // wall lip default height (set to zero when there is no lip)
1600  // 'lip_h', bit '1', is set globally (ensure coherency with bits of 'lip')
1601  lip_hd = is_defined(lip) ? wth : 0;
1602  lip_h = defined_e_or(lip, 1, lip_hd);
1603 
1604  // lid extrusion height (calculate total height of all sections)
1605  lid_hv = is_defined(lid) ? [for (e=lid) is_list(e) ? first(e) : e] : [0];
1606  lid_h = sum(lid_hv);
1607 
1608  // wall height
1609  wall_h = (mode_size_in == true) ? h_h - lip_h : h_h - lip_h - lid_h;
1610 
1611  // wall x and y insets (usually negative, but allow positive)
1612  wall_od = ( is_defined(inset) && is_scalar(inset) ) ? inset : 0;
1613  wall_ox = defined_e_or(inset, 0, wall_od) * -1;
1614  wall_oy = defined_e_or(inset, 1, wall_od) * -1;
1615 
1616  // exterior envelope of enclosure [encl_x, encl_y, encl_z]
1617  encl_x = (mode_size_in == true) ? size_x + 2*wth - wall_ox : size_x;
1618  encl_y = (mode_size_in == true) ? size_y + 2*wth - wall_oy : size_y;
1619  encl_z = (mode_size_in == true) ? wall_h + lip_h + lid_h : h_h;
1620 
1621  // exterior size of wall x and y
1622  wall_xy = [encl_x + wall_ox, encl_y + wall_oy];
1623 
1624  // interior size of enclosure
1625  szint_x = first (wall_xy) - 2*wth;
1626  szint_y = second(wall_xy) - 2*wth;
1627  szint_z = wall_h + lip_h;
1628 
1629  if (verb > 0)
1630  {
1631  echo(strl(["box: construction begin"]));
1632 
1633  echo(strl(["box: exterior dimensions [x, y, z] = ", [encl_x, encl_y, encl_z]]));
1634  echo(strl(["box: interior dimensions [x, y, z] = ", [szint_x, szint_y, szint_z]]));
1635  }
1636 
1637  //
1638  //
1639  // box and feature construction
1640  //
1641  //
1642 
1643  alignments =
1644  [
1645  [0, -encl_x, -szint_x -wth*2, -szint_x, +szint_x, +szint_x +wth*2, +encl_x ]/2,
1646  [0, -encl_y, -szint_y -wth*2, -szint_y, +szint_y, +szint_y +wth*2, +encl_y ]/2,
1647  [lid_h, 0, lid_h -encl_z/2, -wall_h/2, -wall_h, -wall_h -lip_h]
1648  ];
1649 
1650  align_x = select_ci ( alignments.x, defined_e_or(align, 0, 0), false );
1651  align_y = select_ci ( alignments.y, defined_e_or(align, 1, 0), false );
1652  align_z = select_ci ( alignments.z, defined_e_or(align, 2, 0), false );
1653 
1654  translate([align_x, align_y, align_z])
1655  difference()
1656  {
1657  assembly_add();
1658  assembly_remove();
1659  }
1660 
1661  if (verb > 0)
1662  {
1663  echo(strl(["box: alignment [x, y, z] = ", [align_x, align_y, align_z]]));
1664 
1665  echo(strl(["box: construction end"]));
1666  }
1667 }
1668 
1669 //! @}
1670 //! @}
1671 
1672 
1673 //----------------------------------------------------------------------------//
1674 // openscad-amu auxiliary scripts
1675 //----------------------------------------------------------------------------//
1676 
1677 /*
1678 BEGIN_SCOPE example_multiple;
1679  BEGIN_OPENSCAD;
1680  include <omdl-base.scad>;
1681  include <tools/operation_cs.scad>;
1682  include <parts/3d/enclosure/project_box_rectangle.scad>;
1683 
1684  wth = 2; h = 8; sx = 75; sy = 50; vr = 5; vrm = 2;
1685 
1686  translate([0,0,0]) // bottom
1687  project_box_rectangle( wth=wth, h=h, size=[sx,sy], vr=vr, vrm=vrm, lip=1, lid=wth );
1688 
1689  for (z = [1,3]) translate([0,0, (h+4)*z]) // mid-sections
1690  project_box_rectangle( wth=wth, h=h, size=[sx,sy], vr=vr, vrm=vrm, lip=9 );
1691 
1692  translate([0,0,(h+4)*4 + h]) mirror([0,0,1]) // top
1693  project_box_rectangle( wth=wth, h=h, size=[sx,sy], vr=vr, vrm=vrm, lip=2, lid=wth );
1694 
1695  // end_include
1696  END_OPENSCAD;
1697 
1698  BEGIN_MFSCRIPT;
1699  include --path "${INCLUDE_PATH}" {var_init,var_gen_png2eps}.mfs;
1700  table_unset_all sizes;
1701 
1702  images name "sizes" types "sxga";
1703  views name "views" views "front diag";
1704 
1705  variables set_opts_combine "sizes views";
1706  variables add_opts "--viewall --autocenter --view=axes";
1707 
1708  include --path "${INCLUDE_PATH}" scr_make_mf.mfs;
1709  END_MFSCRIPT;
1710 END_SCOPE;
1711 
1712 BEGIN_SCOPE example_bottom;
1713  BEGIN_OPENSCAD;
1714  include <omdl-base.scad>;
1715  include <tools/operation_cs.scad>;
1716  include <parts/3d/enclosure/project_box_rectangle.scad>;
1717 
1718  $fn = 18;
1719 
1720  wth = 1;
1721 
1722  lid_rounding = [for (s=[0:1/32:1/8]) 1-pow(s,2)/2];
1723  lid_profile = [[wth/3, reverse(lid_rounding)], wth/3, [wth/3, lid_rounding]];
1724 
1725  // set default post support fin count to '0' and assign 'undef'
1726  // to other parameters to use their default values.
1727  function post(x, o) =
1728  [
1729  [0, [undef, undef, undef, undef, undef, [0]]],
1730  [
1731  [x, [0,0], [+1,+1]*o], [x, [0,1], [+1,-1]*o],
1732  [x, [1,0], [-1,+1]*o], [x, [1,1], [-1,-1]*o],
1733  ]
1734  ];
1735 
1736  project_box_rectangle
1737  (
1738  wth = wth,
1739  size = [100, 60],
1740  h = [[1, [1.05,1]], 7, [5, [1,.99,1]], 6, [6, [1,1.05,1]]],
1741  vr = 2,
1742  vrm = 1,
1743 
1744  inset = 5,
1745 
1746  lip = 1,
1747  lid = lid_profile,
1748  rib = 0,
1749  wall = [13, [[1, -11.5], [1, +11.5] ]],
1750  post = post(0, wth*3.25),
1751 
1752  mode = 1
1753  );
1754 
1755  // end_include
1756  END_OPENSCAD;
1757 
1758  BEGIN_MFSCRIPT;
1759  include --path "${INCLUDE_PATH}" {var_init,var_gen_png2eps}.mfs;
1760  table_unset_all sizes;
1761 
1762  images name "sizes" types "sxga";
1763  views name "views" views "top front right diag";
1764 
1765  variables set_opts_combine "sizes views";
1766  variables add_opts "--viewall --autocenter --view=axes";
1767 
1768  include --path "${INCLUDE_PATH}" scr_make_mf.mfs;
1769  END_MFSCRIPT;
1770 END_SCOPE;
1771 */
1772 
1773 //----------------------------------------------------------------------------//
1774 // end of file
1775 //----------------------------------------------------------------------------//
1776 
zero3d
<decimal-list-2> A 3d zero vector (a list with three zeros).
Definition: constants.scad:422
eps
<decimal> Epsilon, small distance to deal with overlapping shapes.
Definition: constants.scad:195
empty_lst
<list> A list with no values (the empty list).
Definition: constants.scad:304
function binary_iw2i(v, s, w)
Decode the binary bits of a bit window to an integer value.
function binary_bit_is(v, b, t=1)
Test if a binary bit position of an integer value equals a test bit.
function defined_e_or(v, i, d)
Return an element of an iterable when it exists or a default value otherwise.
function third(v)
Return the third element of an iterable value.
function shift(v, n=0, r=true, c=true)
Shift the elements of an iterable value.
function second(v)
Return the second element of an iterable value.
function first(v)
Return the first element of an iterable value.
function reverse(v)
Reverse the elements of an iterable value.
function select_ci(v, i, l=true)
Select specified element from list or return a default.
function strl(v)
Convert a list of values to a concatenated string.
function merge_s(v, r=false)
Serially merge the elements of a list.
function sum(v, i1, i2)
Compute the sum of a list of numbers.
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_perimeter(n, r, a)
Compute the perimeter of an n-sided regular polygon in 2D.
function get_fn(r)
Return facets number for the given arc radius.
module project_box_rectangle(wth, h, size, vr, vrm, inset, lid, lip, rib, wall, post, align, mode=0, verb=0)
A rectangular box maker for project boxes, enclosures and housings.
module pg_triangle_sas(v, a=x_axis_ci, o, vr, vrm=1, vfn, cm=0)
A polygon triangle specified by size-angle-size with vertex rounding.
Definition: polygon.scad:1098
module pg_rectangle(size=1, o, vr, vrm=1, vfn, center=false)
A polygon rectangle with vertex rounding.
Definition: polygon.scad:759
module extrude_linear_mss(h, center=false, c=true)
Linearly extrude a 2d shape with multi-segment uniformly-spaced profile scaling.
Definition: extrude.scad:748
module extrude_linear_uss(h, center=false, c=true, ha=0)
Linearly extrude a 2d shape with uniformly-spaced profile scaling.
Definition: extrude.scad:666
module difference_cs(c=true, s)
Conditionally apply the difference boolean operation.