omdl  v0.9.6
OpenSCAD Mechanical Design Library
power_strip.scad
Go to the documentation of this file.
1 //! A power strip maker for electrical receptacles and/or devices.
2 /***************************************************************************//**
3  \file
4  \author Roy Allen Sutton
5  \date 2025
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 (Power Strip Maker)
31  \amu_define group_brief (Electrical receptacle power strip generator.)
32 
33  \amu_include (include/amu/pgid_path_pstem_pg.amu)
34 *******************************************************************************/
35 
36 //----------------------------------------------------------------------------//
37 
38 /***************************************************************************//**
39  \amu_include (include/amu/group_in_parent_start.amu)
40  \amu_define includes_required_add
41  (
42  tools/operation_cs.scad
43  models/3d/misc/omdl_logo.scad
44  models/3d/fastener/screws.scad
45  parts/3d/enclosure/clamps.scad
46  parts/3d/enclosure/mounts.scad
47  parts/3d/enclosure/project_box_rectangle.scad
48  )
49  \amu_include (include/amu/includes_required.amu)
50 *******************************************************************************/
51 
52 //----------------------------------------------------------------------------//
53 // global configuration variables
54 //----------------------------------------------------------------------------//
55 
56 //! \name Maps
57 //! @{
58 
59 //! <map> A single gang electrical device box configuration.
60 /***************************************************************************//**
61  \details
62 
63  The default electrical device box configuration map.
64 
65  \amu_define title (Default device box configuration map)
66  \amu_define scope_id (default_box)
67  \amu_define output_scad (false)
68  \amu_define output_console (false)
69  \amu_define notes_table (Map key description is available in source. See the map)
70 
71  \amu_include (include/amu/scope_table.amu)
72 
73  \hideinitializer
74 *******************************************************************************/
76 [
77  ["wth", 2.0], // box wall thickness
78  ["roww", 50.0], // receptacle row width
79  ["dlts", 108.00], // device length tab-to-tab space
80  ["boxd", 25.0], // box internal depth
81 
82  ["evrm", 2], // box & cover rounding mode: {0|1|2}
83  ["evr", 4.0], // box & cover rounding radius
84 
85  ["cdms", false], // cover uses device mount screws: {true|false}
86 
87  ["lefb", 2], // box lid edge finish: {0|1|2|3|4}
88  ["lefc", 2], // cover lid edge finish: {0|1|2|3|4}
89 
90  ["dlogo", true], // detail logo on box rear: {true|false}
91  ["drimb", true], // detail rim on box rear: {true|false}
92  ["drimc", true], // detail rim on cover top: {true|false}
93 
94  ["fins", [3, 270, 3, 3/4]], // post fins: [number, angle, width, length]
95 
96  ["ribs", [0, 1.75] ], // (1) box ribs configuration
97  ["wmode", 426], // (1) box wall mode
98  ["wiab", undef], // (1) box wall instance additions
99  ["pmode", 138], // (1) box post mode (b7=1 required)
100  ["piab", undef], // (1) box post instance additions
101  ["piac", undef], // (1) cover post instance additions
102 
103  ["mpc2b", true], // mirror cover post additions in box: {true|false}
104  ["mphda", 0], // mirrored post hole diameter adjustment
105 
106  ["iscl", 15.0], // input space: cord, switch, surge, etc
107  ["oscl", 0], // output space: wire-nuts, led, aux board, etc
108  ["lscl", 0], // left-side extra space
109  ["rscl", 0], // right-side extra space
110 
111  ["iwdo", true], // internal wall divisions on: {true|false}
112  ["iwpd", 10.0], // internal wall wire pass diameter
113  ["iwps", +1], // internal wall wire pass side: {+1|-1}
114 
115  ["pwco", [0, 0]], // power cord connections offset: [x, z]
116  ["pwcd", 7], // power cord dimensions: {d|[w,h]}
117  ["pwcs", 0], // power cord clamp side: {0|1}
118  ["pwct", 10.5], // power cord clamp tab width
119  ["pwcp", undef], // power cord clamp pinch bar percentage: [h, w]
120 
121  ["pwsd", 3.5], // power cord clamp screw diameter
122  ["pwsh", [6, 3.5]], // (2) power cord clamp screw head spec
123  ["pwsn", [5.75, 2.5]], // (2) power cord clamp screw nut spec
124 
125  ["mtab", [4, 25, 4]], // (3) mount tab: [screw, brace, vrm, vr, wth, size]
126  ["mtabs", undef] // mount tab instances: [[edge, zero, move], ...]
127 ];
128  /*
129  (1): see project_box_rectangle() in omdl for descriptions
130  (2): see screw_bore() in omdl for descriptions
131  (3): see screw_mount_tab() in omdl for descriptions
132  */
133 
134 //! <map> A single gang electrical device mount configuration.
135 /***************************************************************************//**
136  \details
137 
138  The default electrical device mount configuration map.
139 
140  \amu_define title (Default device mount configuration map)
141  \amu_define scope_id (default_mount)
142  \amu_define output_scad (false)
143  \amu_define output_console (false)
144  \amu_define notes_table (Map key description is available in source. See the map)
145 
146  \amu_include (include/amu/scope_table.amu)
147 
148  \hideinitializer
149 *******************************************************************************/
151 [
152  ["mss", length(3+9/32, "in")], // device mount screw separation
153  ["rmsd", length( 1/8, "in")], // mount screw hole diameter
154  ["rmsh", length( 3/32, "in")], // mount screw head height
155  ["rshc", length( 5/16, "in")], // mount screw head clearance
156  ["rmth", length( 1/16, "in")] // mount tab height
157 ];
158 
159 //! <map> A single gang duplex receptacle cover configuration.
160 /***************************************************************************//**
161  \details
162 
163  The default electrical device cover configuration map.
164 
165  \amu_define title (Default device cover configuration map)
166  \amu_define scope_id (default_cover)
167  \amu_define output_scad (false)
168  \amu_define output_console (false)
169  \amu_define notes_table (Map key description is available in source. See the map)
170 
171  \amu_include (include/amu/scope_table.amu)
172 
173  \hideinitializer
174 *******************************************************************************/
176 [
177  ["drpo", length(1+1/2, "in")], // receptacle offset
178  ["rpd", length(1+3/8, "in")], // receptacle diameter
179  ["rpfl", length(1+5/32, "in")], // receptacle flat-to-flat height (1/32" added)
180  ["rcsd", // cover center hole screw:
181  [3.51, 6.50, 1.5, 1/2]] // [diameter, head-diameter, head-height, tolerance]
182 ];
183 
184 //! \cond DOXYGEN_SHOULD_SKIP_THIS
188 //! \endcond
189 
190 //! @}
191 
192 //----------------------------------------------------------------------------//
193 // modules
194 //----------------------------------------------------------------------------//
195 
196 //! A power strip generator for single gang electrical receptacles.
197 /***************************************************************************//**
198  \param cols <integer> device column count.
199 
200  \param rows <integer> device row count.
201 
202  \param mode <integer> part mode.
203 
204  \param verb <integer> console output verbosity {0|1|2}.
205 
206  \details
207 
208  This module constructs a power strip grid of standard [NEMA]
209  electrical power receptacles. The number of columns and rows in the
210  power strip are configurable as well as most aspects of the power
211  strip enclosure box, receptacle device mounts, and device cover.
212  The default configuration of the enclosure box, device mount, and
213  device cover are specified in global variable maps.
214 
215  ### part mode
216 
217  Integer value is binary encoded.
218 
219  b | description
220  ---:|:---------------------------------------
221  0 | generate enclosure box
222  1 | generate clamp top
223  2 | generate enclosure cover
224 
225  The default configuration maps can be completely replaced with a
226  user supplied maps or may be partially updated as shown in the
227  following example.
228 
229  \amu_define scope_id (example)
230  \amu_define title (Custom power strip example)
231  \amu_define image_views (bottom front diag)
232  \amu_define image_size (sxga)
233  \amu_define output_scad (true)
234 
235  \amu_include (include/amu/scope_diagrams_3d.amu)
236 
237  \todo Support enclosure box screw-hole slot mounts.
238 
239  [NEMA]: https://en.wikipedia.org/wiki/NEMA_connector
240 *******************************************************************************/
241 module power_strip_sg
242 (
243  cols = 1,
244  rows = 1,
245 
246  mode = 7,
247  verb = 1,
248 
250  cm_mount = power_strip_sg_default_mount,
252 )
253 {
254  //
255  // local modules and functions
256  //
257 
258  // lid edge finish; s:{0|1|2|3|4}
259  function e ( s = 0 )
260  = let
261  (
262  bs = 2/100
263  )
264  (s == 1) ? [wth*1/3, [wth*2/3, [1, 1-bs]]]
265  : (s == 2) ? [wth*1/3, [wth*2/3, [for (s=[0:1/32:1/8]) 1-pow(s,2)]]]
266  : (s == 3) ? [[wth*4/5, [1, 1+bs]], [wth*1/5, 1+bs]]
267  : (s == 4) ? [[wth*4/5, [for (s=[0:1/32:1/8]) 1+pow(s,2)]], [wth*1/5, 1+pow(1/8,2)]]
268  : wth;
269 
270  // enclosure lips; m:{1=box, 2=cover}
271  function l ( m = 0 )
272  = let
273  (
274  rmsh = map_get_value(cm_mount, "rmsh")
275  )
276  [
277  m, // lip mode
278  rmsh*2 // lip height
279  ];
280 
281  // power cord connection z-offset
282  function pczo ( d = 0 )
283  = let
284  (
285  zo = defined_e_or(map_get_value(cm_box, "pwco"), 1, 0)
286  )
287  wth + (is_list(d) ? second(d) : d) * 5/4 + zo;
288 
289  // power connection clamp strap
290  module clamp_strap()
291  {
292  // box power cord connection
293  pwcd = map_get_value(cm_box, "pwcd");
294  pwsd = map_get_value(cm_box, "pwsd");
295  pwsh = map_get_value(cm_box, "pwsh");
296  pwsn = map_get_value(cm_box, "pwsn");
297  pwct = map_get_value(cm_box, "pwct");
298  pwcp = map_get_value(cm_box, "pwcp");
299 
300  pwzo = pczo( pwcd );
301 
302  translate([0, 0, pwct - eps*2])
303  clamp_cg(size=pwcd, clamp=[1, pwzo, [pwsd,undef,pwsh,pwsn], pwct, pwcp], wth=0, mode=2);
304  }
305 
306  // power strip base
307  module enclosure_box()
308  {
309  //
310  // local modules
311  //
312 
313  // convert cover post instance additions for box (x and y dimensions only)
314  // mirror: type, x-align, x-move, and xy-rotate, add diameter adjustment
315  function piac_to_piab(pia)
316  = [
317  for (i=pia)
318  let
319  (
320  mphda = map_get_value(cm_box, "mphda"),
321 
322  t = i[0],
323  a = i[1], ax = a[0], ay = a[1],
324  m = i[2], mx = m[0], my = m[1],
325  r = i[3],
326  h0 = i[4],
327  h1 = i[5],
328  p = i[6],
329  f = i[7]
330  )
331  [
332  t == 0 ? 1 : 0,
333  [is_undef(ax) ? undef : -ax, ay],
334  [is_undef(m) ? undef : -mx, my],
335  is_undef(r) ? undef : -r,
336  [h0[0], h0[1], h0[2], mphda, h0[4], h0[5], h0[6]],
337  h1, p, f
338  ]
339  ];
340 
341  // screw mount tabs
342  module mount_tabs()
343  {
344  mtab = map_get_value(cm_box, "mtab");
345 
346  // configuration and defaults
347  s = defined_e_or(mtab, 0, undef);
348  b = defined_e_or(mtab, 1, undef);
349  vrm = defined_e_or(mtab, 2, undef);
350  vr = defined_e_or(mtab, 3, undef);
351  w = defined_e_or(mtab, 4, wth*2);
352  sz = defined_e_or(mtab, 5, undef);
353 
354  //
355  // instantiate
356  //
357 
358  mtabs = map_get_value(cm_box, "mtabs");
359 
360  if ( is_defined( mtabs ) )
361  for ( i = mtabs )
362  {
363  e = defined_e_or(i, 0, 0); // edge: {0|1|2|3}
364  z = defined_e_or(i, 1, 0); // zero
365  m = defined_e_or(i, 2, 0); // move
366 
367  if ( e == 0 )
368  { // top edge
369  translate([limit(z,-1,+1)*iw/2 + m, il/2 + wth - eps*2, 0])
370  rotate([0, 0, 0])
371  screw_mount_tab(wth=w, screw=s, brace=b, size=sz, vr=vr, vrm=vrm);
372  } else
373  if ( e == 1 )
374  { // right edge
375  translate([iw/2 + wth - eps*2, limit(z,-1,+1)*il/2 + m, 0])
376  rotate([0, 0, -90])
377  screw_mount_tab(wth=w, screw=s, brace=b, size=sz, vr=vr, vrm=vrm);
378  } else
379  if ( e == 2 )
380  { // bottom edge
381  translate([limit(z,-1,+1)*iw/2 + m, -(il/2 + wth - eps*2), 0])
382  rotate([0, 0, 180])
383  screw_mount_tab(wth=w, screw=s, brace=b, size=sz, vr=vr, vrm=vrm);
384  } else
385  if ( e == 3 )
386  { // left edge
387  translate([-(iw/2 + wth - eps*2), limit(z,-1,+1)*il/2 + m, 0])
388  rotate([0, 0, +90])
389  screw_mount_tab(wth=w, screw=s, brace=b, size=sz, vr=vr, vrm=vrm);
390  }
391  }
392  }
393 
394  // screw mount slots
395  module mount_slots()
396  {
397  }
398 
399  // base internal wall wire holes
400  module internal_wire_passage()
401  {
402  dlts = map_get_value(cm_box, "dlts");
403  roww = map_get_value(cm_box, "roww");
404  iscl = map_get_value(cm_box, "iscl");
405  oscl = map_get_value(cm_box, "oscl");
406  lscl = map_get_value(cm_box, "lscl");
407  rscl = map_get_value(cm_box, "rscl");
408  iwpd = map_get_value(cm_box, "iwpd");
409  iwps = map_get_value(cm_box, "iwps");
410 
411  // offset from wall by "wth"
412  zr = let
413  (
414  z = iw/2 - iwpd/2 - wth,
415  s = (iwps>0) ? 1 : -1,
416  o = (iwps>0) ? rscl : -lscl
417  )
418  z * s - o;
419  sr = roww;
420 
421  nc = (oscl>0) ? cols : cols-1;
422  zc = -il/2 - wth + iscl;
423  sc = dlts + wth;
424 
425  // offset from bottom by 'wth"
426  zo = wth*2 + iwpd/2;
427 
428  // for echo row and wall instance
429  for (i=[0:rows-1], j=[0 : nc])
430  translate([zr - i*sr * iwps, zc + j*sc, zo])
431  rotate([90, 0, 0])
432  cylinder(d=iwpd, h = wth+eps*8, center=true);
433  }
434 
435  //
436  // local variables
437  //
438 
439  cdms = map_get_value(cm_box, "cdms");
440 
441  // box power cord connection
442  pwcd = map_get_value(cm_box, "pwcd");
443  pwcs = map_get_value(cm_box, "pwcs");
444  pwsd = map_get_value(cm_box, "pwsd");
445  pwsh = map_get_value(cm_box, "pwsh");
446  pwsn = map_get_value(cm_box, "pwsn");
447  pwct = map_get_value(cm_box, "pwct");
448  pwcp = map_get_value(cm_box, "pwcp");
449 
450  pwzo = pczo( pwcd );
451  pwxo = defined_e_or(map_get_value(cm_box, "pwco"), 0, 0);
452 
453  ih = map_get_value(cm_box, "boxd");
454 
455  // base ribs
456  r = map_get_value(cm_box, "ribs");
457 
458  // base walls
459  w = let
460  (
461  dlts = map_get_value(cm_box, "dlts"),
462  iscl = map_get_value(cm_box, "iscl"),
463  oscl = map_get_value(cm_box, "oscl"),
464  wmode = map_get_value(cm_box, "wmode"),
465  wiab = map_get_value(cm_box, "wiab"),
466  iwdo = map_get_value(cm_box, "iwdo"),
467 
468  nc = (oscl>0) ? cols : cols-1,
469  zc = -il/2 - wth + iscl,
470  sc = dlts + wth
471  )
472  ( !iwdo ) ? undef
473  : [ // wall configuration:mode
474  wmode,
475 
476  // wall instances
477  [
478  for (j=[0 : nc]) [0, zc + j*sc],
479 
480  // add custom instances
481  if ( is_defined(wiab) ) for (i=wiab) i
482  ]
483  ];
484 
485  // base screw posts
486  p = let
487  (
488  dlts = map_get_value(cm_box, "dlts"),
489  roww = map_get_value(cm_box, "roww"),
490  iscl = map_get_value(cm_box, "iscl"),
491  lscl = map_get_value(cm_box, "lscl"),
492  fins = map_get_value(cm_box, "fins"),
493  pmode = map_get_value(cm_box, "pmode"),
494  piab = map_get_value(cm_box, "piab"),
495  piac = map_get_value(cm_box, "piac"),
496  mpc2b = map_get_value(cm_box, "mpc2b"),
497 
498  mss = map_get_value(cm_mount, "mss"),
499  rmsd = map_get_value(cm_mount, "rmsd"),
500  rmsh = map_get_value(cm_mount, "rmsh"),
501  rmth = map_get_value(cm_mount, "rmth"),
502 
503  u = undef,
504 
505  zr = -iw/2 + roww/2 + lscl,
506  sr = roww,
507 
508  zc = iscl + (dlts - mss)/2,
509  sc = dlts + wth,
510  dc = mss,
511 
512  h0 = [rmsd],
513  p1 = [u, u, u, u, -rmth -(cdms?0:rmsh)],
514  f = fins
515  )
516  [ // post configuration:mode
517  pmode,
518 
519  // post instances
520  [
521  for (i=[0:rows-1], j=[0:cols-1])
522  [2, [0, -1], [zr + i*sr, zc + j*sc, 0], 180, h0, u, p1, f ],
523  for (i=[0:rows-1], j=[0:cols-1])
524  [2, [0, -1], [zr + i*sr, zc + j*sc + dc, 0], 000, h0, u, p1, f ],
525 
526  // add custom instances
527  if ( is_defined(piab) ) for (i=piab) i,
528 
529  // mirror custom cover instances
530  if ( is_defined(piac) && mpc2b ) for (i=piac_to_piab(piac)) i
531  ]
532  ];
533 
534  // lid edge finish
535  lf = e( map_get_value(cm_box, "lefb") );
536 
537  //
538  // instances
539  //
540 
541  difference()
542  {
543  // base enclosure
545  (
546  wth = wth,
547  lid = lf,
548  h = ih, size = [iw, il],
549  vrm = evrm, vr = evr,
550 
551  lip = l(1),
552  rib = r,
553 
554  wall = w,
555  post = p,
556 
557  mode = 1,
558 
559  verb = verb
560  );
561 
562  // internal wall wire passage holes
563  internal_wire_passage();
564 
565  // power cord hole (wth*4 to remove obstructing ribs)
566  translate([pwxo, -il/2-wth/2, pwzo]) rotate([90, 0, 0])
567  clamp_cg(size=pwcd, wth=wth*4, mode=0);
568 
569  // screw mount slot holes
570  mount_slots();
571 
572  // detail: logo
573  if ( map_get_value(cm_box, "dlogo") )
574  {
575  logod = map_get_value(cm_box, "roww")/2;
576 
577  translate([0, logod - il/2, 0])
578  mirror([0, 1, 0]) rotate([0, 0, 180])
579  omdl_logo(d=logod, b=true, t=true, a=1, $fn=36);
580  }
581 
582  // detail: enclosure rim grove trim
583  if ( map_get_value(cm_box, "drimb") )
584  extrude_rotate_trl(r=evr, l=[iw-evr*2, il-evr*2])
585  circle(d=wth/2);
586  }
587 
588  // add power cord clamp bottom
589  translate([pwxo, -il/2-wth/2, pwzo]) rotate([90, 0, 0])
590  clamp_cg(size=pwcd, clamp=[pwcs, pwzo, [pwsd,undef,pwsh,pwsn], pwct, pwcp], cone=pwcs+1, wth=wth, mode=1);
591 
592  // add mount tabs
593  mount_tabs();
594 
595  // add screw mount slots
596  mount_slots();
597 
598  // report power cord hole size
599  if ( verb > 0 )
600  {
601  echo(str( parent_module(0), "(): power cord hole size = ", pwcd ));
602  }
603  }
604 
605  // power strip cover
606  module enclosure_cover()
607  {
608  //
609  // local modules
610  //
611 
612  module cover_round_cut_duplex()
613  {
614  // for echo row and wall instance
615  for (i=[0:rows-1], j=[0 : cols-1])
616  translate([zr - i*sr, zc + j*sc, zo])
617  union()
618  {
619  if ( cdms )
620  { // device mount screw holes
621  mss = map_get_value(cm_mount, "mss");
622  rmsd = map_get_value(cm_mount, "rmsd");
623 
624  for (i=[-1, 1])
625  translate([0, i*mss/2, 0])
626  screw_bore
627  (
628  d = rmsd,
629  l = zh,
630  f = 1+25/100,
631  a = 0
632  );
633  }
634  else
635  { // cover center screw hole
636  rcsd = map_get_value(cm_cover, "rcsd");
637  rmsh = map_get_value(cm_mount, "rmsh");
638 
639  translate([0, 0, rmsh/2])
640  mirror([0, 0, 1])
641  screw_bore
642  (
643  d = first(rcsd),
644  l = zh + rmsh + eps*4,
645  h = [second(rcsd), 0, third(rcsd)],
646  t = [rcsd[3]],
647  a = 0
648  );
649  }
650 
651  // duplex receptacle thru-holes
652  drpo = map_get_value(cm_cover, "drpo");
653  rpd = map_get_value(cm_cover, "rpd");
654  rpfl = map_get_value(cm_cover, "rpfl");
655 
656  extrude_linear_uss(zh, center=true)
657  for (i=[-1, 1])
658  translate([0, i * drpo/2])
659  difference()
660  {
661  circle(d=rpd);
662 
663  for (j=[-1, 1])
664  translate([0, j * (rpd/2 + rpfl)/2])
665  square([rpd, rpd/2], center=true);
666  }
667  }
668  }
669 
670  // add stabilizer pads when using cover center screw
671  // (mount screws will be hidden under cover)
672  module cover_stabilizers()
673  {
674  if ( !cdms )
675  {
676  // for echo row and wall instance
677  for (i=[0:rows-1], j=[0 : cols-1])
678  translate([zr - i*sr, zc + j*sc, zo])
679  union()
680  {
681  mss = map_get_value(cm_mount, "mss");
682  rmsh = map_get_value(cm_mount, "rmsh");
683  rshc = map_get_value(cm_mount, "rshc");
684 
685  translate([0, 0, zo])
686  extrude_linear_uss(rmsh, center=false)
687  union()
688  {
689  rectangle([4, 1]*rshc, vr=rshc/4, vrm=0, center=true);
690 
691  for (i=[-1, 1])
692  translate([0, i * (mss+rshc)/2])
694  (
695  size = [4,1]*rshc,
696  core = [5/4,1]*rshc,
697  co = [0,1/3]*rshc * -i,
698  vr = rshc/4,
699  vrm = 0,
700  center = true
701  );
702  }
703  }
704  }
705  }
706 
707  //
708  // local variables
709  //
710 
711  // wall height must be >= lip height, with min of wth
712  ih = max([ wth, second(l()) ]);
713 
714  // cover screw posts (add custom instances)
715  p = let
716  (
717  pmode = map_get_value(cm_box, "pmode"),
718  piac = map_get_value(cm_box, "piac")
719  )
720  is_undef(piac) ? undef
721  : [pmode, [for (i=piac) i]];
722 
723  // lid edge finish
724  lf = e( map_get_value(cm_box, "lefc") );
725 
726  dlts = map_get_value(cm_box, "dlts");
727  roww = map_get_value(cm_box, "roww");
728  iscl = map_get_value(cm_box, "iscl");
729  lscl = map_get_value(cm_box, "lscl");
730  cdms = map_get_value(cm_box, "cdms");
731 
732  zr = iw/2 - roww/2 - lscl;
733  sr = roww;
734 
735  zc = -il/2 - wth + iscl + dlts/2;
736  sc = dlts + wth;
737 
738  // calculate the total lid extrusion height
739  zh = extrude_linear_mss_eht(lf) + eps*8;
740  zo = zh/2 - eps*4;
741 
742  //
743  // instances
744  //
745 
746  difference()
747  {
748  // cover enclosure
749  union()
750  {
752  (
753  wth = wth,
754  lid = lf,
755  h = ih, size = [iw, il],
756  vrm = evrm, vr = evr,
757 
758  lip = l(2),
759 
760  post = p,
761 
762  mode = 1,
763 
764  verb = verb
765  );
766 
767  // add cover stabilizers
768  cover_stabilizers();
769  }
770 
771  // duplex receptacle holes
772  cover_round_cut_duplex();
773 
774  // detail: enclosure rim grove trim
775  if ( map_get_value(cm_box, "drimc") )
776  extrude_rotate_trl(r=evr, l=[iw-evr*2, il-evr*2])
777  circle(d=wth/2);
778  }
779  }
780 
781  // check configuration map
782  module check_cm(name, mc, md)
783  {
784  for ( k = map_get_keys(mc) )
785  if( !map_exists(md, k) )
786  {
787  log_warn
788  (
789  strl
790  ([
791  "bad entry in map [", name, "] = [", k, ",", map_get_value(mc, k), "]"
792  ])
793  );
794  }
795  }
796 
797  //
798  // local variables
799  //
800 
801  wth = map_get_value(cm_box, "wth");
802 
803  iw = let
804  (
805  roww = map_get_value(cm_box, "roww"),
806  lscl = map_get_value(cm_box, "lscl"),
807  rscl = map_get_value(cm_box, "rscl")
808  )
809  lscl + roww * rows + rscl;
810 
811  il = let
812  (
813  dlts = map_get_value(cm_box, "dlts"),
814  iscl = map_get_value(cm_box, "iscl"),
815  oscl = map_get_value(cm_box, "oscl")
816  )
817  iscl - wth * 3/2 + cols * (dlts + wth) + oscl;
818 
819  evrm = map_get_value(cm_box, "evrm");
820  evr = map_get_value(cm_box, "evr");
821 
822  //
823  // report errors in configuration maps
824  //
825 
826  if ( verb > 0 )
827  {
828  check_cm("cm_box", cm_box, power_strip_sg_default_box);
829  check_cm("cm_mount", cm_mount, power_strip_sg_default_mount);
830  check_cm("cm_cover", cm_cover, power_strip_sg_default_cover);
831  }
832 
833  //
834  // instances
835  //
836 
837  ps = wth*10;
838 
839  if ( binary_bit_is(mode, 0, 1) )
840  translate([-(iw/2 + ps), 0, 0])
841  enclosure_box();
842 
843  if ( binary_bit_is(mode, 1, 1) )
844  translate([+(iw/2 + ps), -(il/2 + ps), 0])
845  clamp_strap();
846 
847  if ( binary_bit_is(mode, 2, 1) )
848  translate([+(iw/2 + ps), 0, 0])
849  enclosure_cover();
850 }
851 
852 //! @}
853 //! @}
854 
855 
856 //----------------------------------------------------------------------------//
857 // openscad-amu auxiliary scripts
858 //----------------------------------------------------------------------------//
859 
860 /*
861 BEGIN_SCOPE example;
862  BEGIN_OPENSCAD;
863  include <omdl-base.scad>;
864  include <tools/operation_cs.scad>;
865  include <models/3d/misc/omdl_logo.scad>;
866  include <models/3d/fastener/screws.scad>;
867  include <parts/3d/enclosure/clamps.scad>;
868  include <parts/3d/enclosure/mounts.scad>;
869  include <parts/3d/enclosure/project_box_rectangle.scad>;
870  include <parts/3d/enclosure/power_strip.scad>;
871 
872  box_conf =
873  [
874  ["iscl", 15.0],
875  ["oscl", 15.0],
876 
877  ["pwcd", [8.6, 3.6]],
878  ["pwsh", [6]],
879  ["pwco", [0, 2]],
880  ["pwcp", 20],
881 
882  ["mtabs", [[0]]]
883  ];
884 
885  custom_box = map_merge(box_conf, power_strip_sg_default_box);
886  map_check(custom_box);
887 
888  power_strip_sg(cm_box=custom_box);
889 
890  // end_include
891  END_OPENSCAD;
892 
893  BEGIN_MFSCRIPT;
894  include --path "${INCLUDE_PATH}" {var_init,var_gen_png2eps}.mfs;
895  table_unset_all sizes;
896 
897  images name "sizes" types "sxga";
898  views name "views" views "bottom front diag";
899 
900  variables set_opts_combine "sizes views";
901  variables add_opts "--viewall --autocenter --view=axes";
902 
903  include --path "${INCLUDE_PATH}" scr_make_mf.mfs;
904  END_MFSCRIPT;
905 END_SCOPE;
906 */
907 
908 /*
909 BEGIN_SCOPE default_box;
910  BEGIN_OPENSCAD;
911  include <omdl-base.scad>;
912  include <tools/operation_cs.scad>;
913  include <models/3d/misc/omdl_logo.scad>;
914  include <models/3d/fastener/screws.scad>;
915  include <parts/3d/enclosure/clamps.scad>;
916  include <parts/3d/enclosure/project_box_rectangle.scad>;
917  include <parts/3d/enclosure/power_strip.scad>;
918 
919  map_write( power_strip_sg_default_box );
920  END_OPENSCAD;
921 
922  BEGIN_MFSCRIPT;
923  include --path "${INCLUDE_PATH}" {var_init,var_gen_term}.mfs;
924  include --path "${INCLUDE_PATH}" scr_make_mf.mfs;
925  END_MFSCRIPT;
926 END_SCOPE;
927 
928 BEGIN_SCOPE default_mount;
929  BEGIN_OPENSCAD;
930  include <omdl-base.scad>;
931  include <tools/operation_cs.scad>;
932  include <models/3d/misc/omdl_logo.scad>;
933  include <models/3d/fastener/screws.scad>;
934  include <parts/3d/enclosure/clamps.scad>;
935  include <parts/3d/enclosure/project_box_rectangle.scad>;
936  include <parts/3d/enclosure/power_strip.scad>;
937 
938  map_write( power_strip_sg_default_mount );
939  END_OPENSCAD;
940 
941  BEGIN_MFSCRIPT;
942  include --path "${INCLUDE_PATH}" {var_init,var_gen_term}.mfs;
943  include --path "${INCLUDE_PATH}" scr_make_mf.mfs;
944  END_MFSCRIPT;
945 END_SCOPE;
946 
947 BEGIN_SCOPE default_cover;
948  BEGIN_OPENSCAD;
949  include <omdl-base.scad>;
950  include <tools/operation_cs.scad>;
951  include <models/3d/misc/omdl_logo.scad>;
952  include <models/3d/fastener/screws.scad>;
953  include <parts/3d/enclosure/clamps.scad>;
954  include <parts/3d/enclosure/project_box_rectangle.scad>;
955  include <parts/3d/enclosure/power_strip.scad>;
956 
957  map_write( power_strip_sg_default_cover );
958  END_OPENSCAD;
959 
960  BEGIN_MFSCRIPT;
961  include --path "${INCLUDE_PATH}" {var_init,var_gen_term}.mfs;
962  include --path "${INCLUDE_PATH}" scr_make_mf.mfs;
963  END_MFSCRIPT;
964 END_SCOPE;
965 */
966 
967 //----------------------------------------------------------------------------//
968 // end of file
969 //----------------------------------------------------------------------------//
module log_warn(m)
Output warning message to console.
Definition: console.scad:333
eps
<decimal> Epsilon, small distance to deal with overlapping shapes.
Definition: constants.scad:195
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 second(v)
Return the second element of an iterable value.
function first(v)
Return the first element of an iterable value.
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 map_get_value(m, k)
Get the map value associated with a key.
function map_get_keys(m)
Get a list of all map keys.
module map_check(m, verbose=false)
Perform basic format checks on a map and output errors to console.
Definition: map.scad:431
function map_exists(m, k)
Test if a key exists.
function is_defined(v)
Test if a value is defined.
module screw_bore(d=1, l=1, h, n, t, s, f=1, a=0)
Flat and beveled-head screw bore with nut, nut slot, and bore tolerance.
Definition: screws.scad:359
module omdl_logo(r=5, c=false, b=false, t=false, td="ltr", a=0, d)
Standard omdl logo.
Definition: omdl_logo.scad:328
module clamp_cg(size, clamp, cone, grip, wth=0, gap=10, mode)
A clamp, bushing, and/or grip for wire/hose wall penetrations.
Definition: clamps.scad:743
module screw_mount_tab(wth, screw, brace, size, vr, vrm)
A mount tab with screw hole and support brace.
Definition: mounts.scad:362
power_strip_sg_default_box
<map> A single gang electrical device box configuration.
module power_strip_sg(cols=1, rows=1, mode=7, verb=1, cm_box=power_strip_sg_default_box, cm_mount=power_strip_sg_default_mount, cm_cover=power_strip_sg_default_cover)
A power strip generator for single gang electrical receptacles.
power_strip_sg_default_mount
<map> A single gang electrical device mount configuration.
power_strip_sg_default_cover
<map> A single gang duplex receptacle cover configuration.
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 rectangle_c(size, core, t, co, cr=0, vr, vr1, vr2, vrm=0, vrm1, vrm2, center=false)
A rectangle with a removed rectangular core.
Definition: basic_2d.scad:595
module rectangle(size, vr, vrm=0, center=false)
A rectangle with corner rounds or chamfers.
Definition: basic_2d.scad:471
module cone(r=1, h, d, vr)
A cone.
Definition: basic_3d.scad:461
module extrude_rotate_trl(r, pa=0, ra=360, l, m=255)
Translate, rotate, and revolve a 2d shape about the z-axis with linear elongation.
Definition: extrude.scad:562
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().
function length(v, from=length_unit_default, to=length_unit_base, d=1)
Convert a value from from one units to another with dimensions.