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