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