1//////////////////////////////////////////////////////////////////////////
  2// LibFile: cubetruss.scad
  3//   Parts for making modular open-frame cross-braced trusses and connectors.
  4// Includes:
  5//   include <BOSL2/std.scad>
  6//   include <BOSL2/cubetruss.scad>
  7// FileGroup: Parts
  8// FileSummary: Modular open-framed trusses and joiners.
  9//////////////////////////////////////////////////////////////////////////
 10
 11$cubetruss_size = 30;
 12$cubetruss_strut_size = 3;
 13$cubetruss_bracing = true;
 14$cubetruss_clip_thickness = 1.6;
 15
 16
 17// Section: Cube Trusses
 18
 19// Function: cubetruss_dist()
 20// Usage:
 21//   cubetruss_dist(cubes, gaps, [size], [strut]);
 22// Description:
 23//   Function to calculate the length of a cubetruss truss.
 24// Arguments:
 25//   cubes = The number of cubes along the truss's length.
 26//   gaps = The number of extra strut widths to add in, corresponding to each time a truss butts up against another.
 27//   size = The length of each side of the cubetruss cubes.  Default: `$cubetruss_size` (usually 30)
 28//   strut = The width of the struts on the cubetruss cubes.  Default: `$cubetruss_strut_size` (usually 3)
 29// Topics: Trusses
 30function cubetruss_dist(cubes=0, gaps=0, size, strut) =
 31    let(
 32        size = is_undef(size)? $cubetruss_size : size,
 33        strut = is_undef(strut)? $cubetruss_strut_size : strut
 34    ) cubes*(size-strut)+gaps*strut;
 35
 36
 37// Module: cubetruss_segment()
 38// Usage:
 39//   cubetruss_segment([size], [strut], [bracing]);
 40// Description:
 41//   Creates a single cubetruss cube segment.
 42// Arguments:
 43//   size = The length of each side of the cubetruss cubes.  Default: `$cubetruss_size` (usually 30)
 44//   strut = The width of the struts on the cubetruss cubes.  Default: `$cubetruss_strut_size` (usually 3)
 45//   bracing = If true, adds internal cross-braces.  Default: `$cubetruss_bracing` (usually true)
 46//   ---
 47//   anchor = Translate so anchor point is at origin (0,0,0).  See [anchor](attachments.scad#subsection-anchor).  Default: `CENTER`
 48//   spin = Rotate this many degrees around the Z axis.  See [spin](attachments.scad#subsection-spin).  Default: `0`
 49//   orient = Vector to rotate top towards.  See [orient](attachments.scad#subsection-orient).  Default: `UP`
 50// Topics: Attachable, Trusses
 51// Examples:
 52//   cubetruss_segment(bracing=false);
 53//   cubetruss_segment(bracing=true);
 54//   cubetruss_segment(strut=4);
 55//   cubetruss_segment(size=40);
 56module cubetruss_segment(size, strut, bracing, anchor=CENTER, spin=0, orient=UP) {
 57    size = is_undef(size)? $cubetruss_size : size;
 58    strut = is_undef(strut)? $cubetruss_strut_size : strut;
 59    bracing = is_undef(bracing)? $cubetruss_bracing : bracing;
 60    h = size;
 61    crossthick = strut/sqrt(2);
 62    voffset = 0.333;
 63    attachable(anchor,spin,orient, size=[size,size,size]) {
 64        render(convexity=10)
 65        union() {
 66            difference() {
 67                // Start with a cube.
 68                cube([size, size, h], center=true);
 69
 70                cube([size-strut*2, size-strut*2, h-strut*2], center=true);
 71
 72                // Hollow out octogons in X and Y axes.
 73                zrot_copies([0,90]) {
 74                    xrot(90) zrot(180/8) cylinder(h=max(h,size)+1, d=(min(h,size)-2*strut)/cos(180/8), center=true, $fn=8);
 75                }
 76
 77                // Hollow out octogon vertically.
 78                zrot(180/8) cylinder(h=max(h,size)+1, d=(min(h,size)-2*strut)/cos(180/8), center=true, $fn=8);
 79            }
 80
 81            // Interior cross-supports
 82            if (bracing) {
 83                for (i = [-1,1]) {
 84                    zrot(i*45) {
 85                        difference() {
 86                            cube([crossthick, (size-strut)*sqrt(2), h], center=true);
 87                            up(i*voffset) {
 88                                yscale(1.3) {
 89                                    yrot(90) {
 90                                        zrot(180/6) {
 91                                            cylinder(h=crossthick+1, d=(min(h,size)-2*strut)/cos(180/6)-2*voffset, center=true, $fn=6);
 92                                        }
 93                                    }
 94                                }
 95                            }
 96                        }
 97                    }
 98                }
 99            }
100        }
101        children();
102    }
103}
104
105
106// Module: cubetruss_support()
107// Usage:
108//   cubetruss_support([size], [strut], [extents], [anchor], [spin], [orient]) [ATTACHMENTS];
109// Description:
110//   Creates a single cubetruss support.
111// Arguments:
112//   size = The length of each side of the cubetruss cubes.  Default: `$cubetruss_size` (usually 30)
113//   strut = The width of the struts on the cubetruss cubes.  Default: `$cubetruss_strut_size` (usually 3)
114//   extents = If given as an integer, specifies the number of vertical segments for the support.  If given as a list of 3 integers, specifies the number of segments in the X, Y, and Z directions.  Default: 1.
115//   ---
116//   anchor = Translate so anchor point is at origin (0,0,0).  See [anchor](attachments.scad#subsection-anchor).  Default: `CENTER`
117//   spin = Rotate this many degrees around the Z axis.  See [spin](attachments.scad#subsection-spin).  Default: `0`
118//   orient = Vector to rotate top towards.  See [orient](attachments.scad#subsection-orient).  Default: `UP`
119// Topics: Attachable, Trusses
120// Example(VPT=[0,0,0],VPD=150):
121//   cubetruss_support();
122// Example(VPT=[0,0,0],VPD=200):
123//   cubetruss_support(extents=2);
124// Example(VPT=[0,0,0],VPD=250):
125//   cubetruss_support(extents=3);
126// Example(VPT=[0,0,0],VPD=350):
127//   cubetruss_support(extents=[2,2,3]);
128// Example(VPT=[0,0,0],VPD=150):
129//   cubetruss_support(strut=4);
130// Example(VPT=[0,0,0],VPD=260):
131//   cubetruss_support(extents=2) show_anchors();
132module cubetruss_support(size, strut, extents=1, anchor=CENTER, spin=0, orient=UP) {
133    extents = is_num(extents)? [1,1,extents] : extents;
134    size = is_undef(size)? $cubetruss_size : size;
135    strut = is_undef(strut)? $cubetruss_strut_size : strut;
136    check =
137      assert(is_int(extents.x) && extents.x > 0)
138      assert(is_int(extents.y) && extents.y > 0)
139      assert(is_int(extents.z) && extents.z > 0);
140    w = (size-strut) * extents.x + strut;
141    l = (size-strut) * extents.y + strut;
142    h = (size-strut) * extents.z + strut;
143    attachable(anchor,spin,orient, size=[w,l,h], size2=[l,0], shift=[0,l/2], axis=DOWN) {
144        xcopies(size-strut, n=extents.x) {
145            difference() {
146                half_of(BACK/extents.y + UP/extents.z, s=size*(max(extents)+1))
147                    cube([size,l,h], center=true);
148                half_of(BACK/extents.y + UP/extents.z, cp=strut, s=size*(max(extents)+1)) {
149                    ycopies(size-strut, n=extents.y) {
150                        zcopies(size-strut, n=extents.z) {
151                            cyl(h=size+1, d=size-2*strut, circum=true, realign=true, orient=RIGHT, $fn=8);
152                            cyl(h=size+1, d=size-2*strut, circum=true, realign=true, $fn=8);
153                            cube(size-2*strut, center=true);
154                        }
155                    }
156                }
157                zcopies(size-strut, n=extents.z) {
158                    cyl(h=extents.y*size+1, d=size-2*strut, circum=true, realign=true, orient=BACK, $fn=8);
159                }
160            }
161        }
162        children();
163    }
164}
165
166
167// Module: cubetruss_clip()
168// Usage:
169//   cubetruss_clip(extents, [size], [strut], [clipthick], [$slop=], [anchor=], [spin=], [orient=]) [ATTACHMENTS];
170// Description:
171//   Creates a pair of clips to add onto the end of a truss.
172// Arguments:
173//   extents = How many cubes to separate the clips by.
174//   size = The length of each side of the cubetruss cubes.  Default: `$cubetruss_size` (usually 30)
175//   strut = The width of the struts on the cubetruss cubes.  Default: `$cubetruss_strut_size` (usually 3)
176//   clipthick = The thickness of the clip.  Default: `$cubetruss_clip_thickness` (usually 1.6)
177//   ---
178//   $slop = allowance for printer overextrusion
179//   anchor = Translate so anchor point is at origin (0,0,0).  See [anchor](attachments.scad#subsection-anchor).  Default: `CENTER`
180//   spin = Rotate this many degrees around the Z axis.  See [spin](attachments.scad#subsection-spin).  Default: `0`
181//   orient = Vector to rotate top towards.  See [orient](attachments.scad#subsection-orient).  Default: `UP`
182// Topics: Attachable, Trusses
183// Examples:
184//   cubetruss_clip(extents=2);
185//   cubetruss_clip(extents=1);
186//   cubetruss_clip(clipthick=2.5);
187module cubetruss_clip(extents=1, size, strut, clipthick, anchor=CENTER, spin=0, orient=UP) {
188    size = is_undef(size)? $cubetruss_size : size;
189    strut = is_undef(strut)? $cubetruss_strut_size : strut;
190    clipthick = is_undef(clipthick)? $cubetruss_clip_thickness : clipthick;
191    cliplen = strut * 2.6;
192    clipheight = min(size+strut, size/3+2*strut*2.6);
193    clipsize = 0.5;
194    s = [extents*(size-strut)+strut+2*clipthick, strut*2, clipheight-2*strut];
195    attachable(anchor,spin,orient, size=s) {
196        xflip_copy(offset=(extents*(size-strut)+strut)/2) {
197            difference() {
198                union() {
199                    difference() {
200                        right(clipthick/2-0.01) {
201                            back(strut) {
202                                difference() {
203                                    xrot(90) prismoid([clipthick, clipheight], [clipthick, clipheight-cliplen*2], h=cliplen);
204                                    right(clipthick/2) chamfer_edge_mask(l=clipheight+0.1, chamfer=clipthick);
205                                }
206                            }
207                        }
208                        fwd(strut*3/2) {
209                            cube([get_slop(), strut*3, size], center=true);
210                        }
211                    }
212                    right(get_slop()/2+0.01) {
213                        fwd(strut*1.25+get_slop()) {
214                            yrot(-90) prismoid([clipheight-cliplen*2, strut/2], [clipheight-cliplen*2-2*clipsize, strut/2], h=clipsize+0.01);
215                        }
216                    }
217                }
218                fwd(strut*1.6) {
219                    left(clipsize) {
220                        yscale(1.5) chamfer_edge_mask(l=size+1, chamfer=clipsize+clipthick/3);
221                    }
222                }
223                zcopies(clipheight-strut) cube([clipthick*3, cliplen*2, strut], center=true);
224                zcopies(clipheight-2*strut) right(clipthick) chamfer_edge_mask(l=cliplen*2, chamfer=clipthick, orient=BACK);
225            }
226        }
227        children();
228    }
229}
230
231
232// Module: cubetruss_foot()
233// Usage:
234//   cubetruss_foot(w, [size], [strut], [clipthick], [$slop=], [anchor=], [spin=], [orient=]) [ATTACHMENTS];
235// Description:
236//   Creates a foot that can be clipped onto the bottom of a truss for support.
237// Arguments:
238//   w = The number of cube segments to span between the clips.  Default: 1
239//   size = The length of each side of the cubetruss cubes.  Default: `$cubetruss_size` (usually 30)
240//   strut = The width of the struts on the cubetruss cubes.  Default: `$cubetruss_strut_size` (usually 3)
241//   clipthick = The thickness of the clips.  Default: `$cubetruss_clip_thickness` (usually 1.6)
242//   ---
243//   $slop = make fit looser to allow for printer overextrusion
244//   anchor = Translate so anchor point is at origin (0,0,0).  See [anchor](attachments.scad#subsection-anchor).  Default: `CENTER`
245//   spin = Rotate this many degrees around the Z axis.  See [spin](attachments.scad#subsection-spin).  Default: `0`
246//   orient = Vector to rotate top towards.  See [orient](attachments.scad#subsection-orient).  Default: `UP`
247// Topics: Attachable, Trusses
248// Examples:
249//   cubetruss_foot(w=1);
250//   cubetruss_foot(w=3);
251module cubetruss_foot(w=1, size, strut, clipthick, anchor=CENTER, spin=0, orient=UP) {
252    size = is_undef(size)? $cubetruss_size : size;
253    strut = is_undef(strut)? $cubetruss_strut_size : strut;
254    clipthick = is_undef(clipthick)? $cubetruss_clip_thickness : clipthick;
255    clipsize = 0.5;
256    wall_h = strut+clipthick*1.5;
257    cyld = (size-2*strut)/cos(180/8);
258    s = [w*(size-strut)+strut+2*clipthick, size-2*strut, strut+clipthick];
259    attachable(anchor,spin,orient, size=s, offset=[0,0,(strut-clipthick)/2]) {
260        down(clipthick) {
261            // Base
262            up(clipthick/2) {
263                cuboid([w*(size-strut)+strut+2*clipthick, size-2*strut, clipthick], chamfer=strut, edges="Z");
264            }
265
266            // Walls
267            xcopies(w*(size-strut)+strut+clipthick) {
268                up(clipthick-0.01) {
269                    prismoid([clipthick, (size-4*strut)], [clipthick, size/3.5], h=wall_h, anchor=BOT);
270                }
271            }
272
273            // Horiz Wall Clips
274            up(clipthick+strut+get_slop()*2) {
275                xcopies(w*(size-strut)+strut) {
276                    prismoid([clipsize*2, size/3.5], [0.1, size/3.5], h=clipsize*3, anchor=BOT);
277                }
278            }
279
280            // Middle plugs
281            for (xcol = [0:w-1]) {
282                right((xcol-(w-1)/2)*(size-strut)) {
283                    difference() {
284                        // Start with octagon to fit sides.
285                        up(clipthick-0.01) {
286                            zrot(180/8) cylinder(h=strut, d1=cyld-4*get_slop(), d2=cyld-4*get_slop()-1, center=false, $fn=8);
287                        }
288
289                        // Bevel to fit.
290                        up(clipthick+strut) {
291                            ycopies(size-2*strut-4*get_slop()) {
292                                chamfer_edge_mask(l=size-strut, chamfer=strut*2/3, orient=RIGHT);
293                            }
294                        }
295
296                        // Cut out X for possible top mount.
297                        zrot_copies([-45, 45]) {
298                            cube([size*3, strut/sqrt(2)+2*get_slop(), size*3], center=true);
299                        }
300                    }
301                }
302            }
303        }
304        children();
305    }
306}
307
308
309// Module: cubetruss_joiner()
310// Usage:
311//   cubetruss_joiner([w], [vert], [size], [strut], [clipthick], [$slop=], [anchor=], [spin=], [orient=]) [ATTACHMENTS];
312// Description:
313//   Creates a part to join two cubetruss trusses end-to-end.
314// Arguments:
315//   w = The number of cube segments to span between the clips.  Default: 1
316//   vert = If true, add vertical risers to clip to the ends of the cubetruss trusses.  Default: true
317//   size = The length of each side of the cubetruss cubes.  Default: `$cubetruss_size` (usually 30)
318//   strut = The width of the struts on the cubetruss cubes.  Default: `$cubetruss_strut_size` (usually 3)
319//   clipthick = The thickness of the clips.  Default: `$cubetruss_clip_thickness` (usually 1.6)
320//   ---
321//   $slop = Make fit looser by this amount to allow for printer overextrusion
322//   anchor = Translate so anchor point is at origin (0,0,0).  See [anchor](attachments.scad#subsection-anchor).  Default: `CENTER`
323//   spin = Rotate this many degrees around the Z axis.  See [spin](attachments.scad#subsection-spin).  Default: `0`
324//   orient = Vector to rotate top towards.  See [orient](attachments.scad#subsection-orient).  Default: `UP`
325// Topics: Attachable, Trusses
326// Examples:
327//   cubetruss_joiner(w=1, vert=false);
328//   cubetruss_joiner(w=1, vert=true);
329//   cubetruss_joiner(w=2, vert=true, anchor=BOT);
330module cubetruss_joiner(w=1, vert=true, size, strut, clipthick, anchor=CENTER, spin=0, orient=UP) {
331    size = is_undef(size)? $cubetruss_size : size;
332    strut = is_undef(strut)? $cubetruss_strut_size : strut;
333    clipthick = is_undef(clipthick)? $cubetruss_clip_thickness : clipthick;
334    clipsize = 0.5;
335    s = [cubetruss_dist(w,1)+2*clipthick, cubetruss_dist(2,0)-0.1, strut+clipthick];
336    attachable(anchor,spin,orient, size=s, offset=[0,0,-(clipthick-strut)/2]) {
337        down(clipthick) {
338            // Base
339            cube([w*(size-strut)+strut+2*clipthick, size, clipthick], anchor=BOT);
340
341            xcopies(w*(size-strut)+strut+clipthick) {
342                cube([clipthick, size, clipthick+strut*3/4], anchor=BOT);
343            }
344
345            // Use feet
346            ycopies(size) {
347                cubetruss_foot(w=w, size=size, strut=strut, clipthick=clipthick, anchor=BOT);
348            }
349
350            if (vert) {
351                // Vert Walls
352                xcopies(w*(size-strut)+strut+clipthick) {
353                    up(clipthick-0.01) {
354                        prismoid([clipthick, size], [clipthick, 2*strut+2*clipthick], h=size*0.6, anchor=BOT);
355                    }
356                }
357
358                // Vert Wall Clips
359                up(size/2) {
360                    xflip_copy(offset=(w*(size-strut)+strut+0.02)/2) {
361                        yflip_copy(offset=strut+get_slop()/2) {
362                            yrot(-90) {
363                                back_half() {
364                                    prismoid([size/3.5, clipthick*2], [size/3.5-4*2*clipsize, 0.1], h=2*clipsize, anchor=BOT);
365                                }
366                            }
367                        }
368                    }
369                }
370            }
371        }
372        children();
373    }
374}
375
376
377// Module: cubetruss_uclip()
378// Usage:
379//   cubetruss_uclip(dual, [size], [strut], [clipthick], [$slop=], [anchor=], [spin=], [orient=]) [ATTACHMENTS];
380// Description:
381//   Creates a small clip that can snap around one or two adjacent struts.
382// Arguments:
383//   dual = If true, create a clip to clip around two adjacent struts.  If false, just fit around one strut.  Default: true
384//   size = The length of each side of the cubetruss cubes.  Default: `$cubetruss_size` (usually 30)
385//   strut = The width of the struts on the cubetruss cubes.  Default: `$cubetruss_strut_size` (usually 3)
386//   clipthick = The thickness of the clips.  Default: `$cubetruss_clip_thickness` (usually 1.6)
387//   ---
388//   $slop = Make fit looser by this amount
389//   anchor = Translate so anchor point is at origin (0,0,0).  See [anchor](attachments.scad#subsection-anchor).  Default: `CENTER`
390//   spin = Rotate this many degrees around the Z axis.  See [spin](attachments.scad#subsection-spin).  Default: `0`
391//   orient = Vector to rotate top towards.  See [orient](attachments.scad#subsection-orient).  Default: `UP`
392// Topics: Attachable, Trusses
393// Examples:
394//   cubetruss_uclip(dual=false);
395//   cubetruss_uclip(dual=true);
396module cubetruss_uclip(dual=true, size, strut, clipthick, anchor=CENTER, spin=0, orient=UP) {
397    size = is_undef(size)? $cubetruss_size : size;
398    strut = is_undef(strut)? $cubetruss_strut_size : strut;
399    clipthick = is_undef(clipthick)? $cubetruss_clip_thickness : clipthick;
400    clipsize = 0.5;
401    s = [(dual?2:1)*strut+2*clipthick+get_slop(), strut+2*clipthick, size/3.5];
402    attachable(anchor,spin,orient, size=s) {
403        union() {
404            difference() {
405                cube(s, center=true);
406                back(clipthick) cube([(dual?2:1)*strut+get_slop(), strut+2*clipthick, size+1], center=true);
407            }
408            back((strut+get_slop())/2) {
409                xflip_copy(offset=(dual?1:0.5)*strut+get_slop()/2) {
410                    yrot(-90) {
411                        back_half() {
412                            prismoid([size/3.5, clipthick*1.87], [size/3.5, 0.1], h=clipsize, anchor=BOT);
413                        }
414                    }
415                }
416            }
417        }
418        children();
419    }
420}
421
422
423// Module: cubetruss()
424// Usage:
425//   cubetruss(extents, [clips], [bracing], [size], [strut], [clipthick]);
426// Description:
427//   Creates a cubetruss truss, assembled out of one or more cubical segments.
428// Arguments:
429//   extents = The number of cubes in length to make the truss.  If given as a [X,Y,Z] vector, specifies the number of cubes in each dimension.
430//   clips = List of vectors pointing towards the sides to add clips to.
431//   size = The length of each side of the cubetruss cubes.  Default: `$cubetruss_size` (usually 30)
432//   strut = The width of the struts on the cubetruss cubes.  Default: `$cubetruss_strut_size` (usually 3)
433//   bracing = If true, adds internal cross-braces.  Default: `$cubetruss_bracing` (usually true)
434//   clipthick = The thickness of the clips.  Default: `$cubetruss_clip_thickness` (usually 1.6)
435//   ---
436//   anchor = Translate so anchor point is at origin (0,0,0).  See [anchor](attachments.scad#subsection-anchor).  Default: `CENTER`
437//   spin = Rotate this many degrees around the Z axis.  See [spin](attachments.scad#subsection-spin).  Default: `0`
438//   orient = Vector to rotate top towards.  See [orient](attachments.scad#subsection-orient).  Default: `UP`
439// Topics: Attachable, Trusses
440// Examples:
441//   cubetruss(extents=3);
442//   cubetruss(extents=3, clips=FRONT);
443//   cubetruss(extents=3, clips=[FRONT,BACK]);
444//   cubetruss(extents=[2,3]);
445//   cubetruss(extents=[1,4,2]);
446//   cubetruss(extents=[1,4,2], bracing=false);
447module cubetruss(extents=6, clips=[], bracing, size, strut, clipthick, anchor=CENTER, spin=0, orient=UP) {
448    clips = is_vector(clips)? [clips] : clips;
449    size = is_undef(size)? $cubetruss_size : size;
450    strut = is_undef(strut)? $cubetruss_strut_size : strut;
451    bracing = is_undef(bracing)? $cubetruss_bracing : bracing;
452    clipthick = is_undef(clipthick)? $cubetruss_clip_thickness : clipthick;
453    extents = is_vector(extents)? point3d(extents,fill=1) : [1,extents,1];
454    w = extents[0];
455    l = extents[1];
456    h = extents[2];
457    s = [cubetruss_dist(w,1), cubetruss_dist(l,1), cubetruss_dist(h,1)];
458    attachable(anchor,spin,orient, size=s) {
459        union() {
460            for (zrow = [0:h-1]) {
461                up((zrow-(h-1)/2)*(size-strut)) {
462                    for (xcol = [0:w-1]) {
463                        right((xcol-(w-1)/2)*(size-strut)) {
464                            for (ycol = [0:l-1]) {
465                                back((ycol-(l-1)/2)*(size-strut)) {
466                                    cubetruss_segment(size=size, strut=strut, bracing=bracing);
467                                }
468                            }
469                        }
470                    }
471                }
472            }
473            if (clipthick > 0) {
474                for (vec = clips) {
475                    exts = v_abs(rot(from=FWD, to=vec, p=extents));
476                    rot(from=FWD,to=vec) {
477                        for (zrow = [0:1:exts.z-1]) {
478                            up((zrow-(exts.z-1)/2)*(size-strut)) {
479                                fwd((exts.y*(size-strut)+strut)/2) {
480                                    cubetruss_clip(size=size, strut=strut, extents=exts.x, clipthick=clipthick);
481                                }
482                            }
483                        }
484                    }
485                }
486            }
487        }
488        children();
489    }
490}
491
492
493// Module: cubetruss_corner()
494// Usage:
495//   cubetruss_corner(h, extents, [bracing], [size], [strut], [clipthick]);
496// Description:
497//   Creates a corner cubetruss with extents jutting out in one or more directions.
498// Arguments:
499//   h = The number of cubes high to make the base and horizontal extents.
500//   extents = The number of cubes to extend beyond the corner.  If given as a vector of cube counts, gives the number of cubes to extend right, back, left, front, and up in order.  If the vector is shorter than length 5 the extra cube counts are taken to be zero.  
501//   size = The length of each side of the cubetruss cubes.  Default: `$cubetruss_size` (usually 30)
502//   strut = The width of the struts on the cubetruss cubes.  Default: `$cubetruss_strut_size` (usually 3)
503//   bracing = If true, adds internal cross-braces.  Default: `$cubetruss_bracing` (usually true)
504//   clipthick = The thickness of the clips.  Default: `$cubetruss_clip_thickness` (usually 1.6)
505//   ---
506//   anchor = Translate so anchor point is at origin (0,0,0).  See [anchor](attachments.scad#subsection-anchor).  Default: `CENTER`
507//   spin = Rotate this many degrees around the Z axis.  See [spin](attachments.scad#subsection-spin).  Default: `0`
508//   orient = Vector to rotate top towards.  See [orient](attachments.scad#subsection-orient).  Default: `UP`
509// Topics: Attachable, Trusses
510// Examples:
511//   cubetruss_corner(extents=2);
512//   cubetruss_corner(extents=2, h=2);
513//   cubetruss_corner(extents=[3,3,0,0,2]);
514//   cubetruss_corner(extents=[3,0,3,0,2]);
515//   cubetruss_corner(extents=[3,3,3,3,2]);
516module cubetruss_corner(h=1, extents=[1,1,0,0,1], bracing, size, strut, clipthick, anchor=CENTER, spin=0, orient=UP) {
517    size = is_undef(size)? $cubetruss_size : size;
518    strut = is_undef(strut)? $cubetruss_strut_size : strut;
519    bracing = is_undef(bracing)? $cubetruss_bracing : bracing;
520    clipthick = is_undef(clipthick)? $cubetruss_clip_thickness : clipthick;
521    exts = is_vector(extents)? list_pad(extents,5,fill=0) : [extents, extents, 0, 0, extents];
522    dummy = assert(len(exts)==5, "Input extents must be a scalar or vector with length 5 or less.");
523    s = [cubetruss_dist(exts[0]+1+exts[2],1), cubetruss_dist(exts[1]+1+exts[3],1), cubetruss_dist(h+exts[4],1)];
524    offset = [cubetruss_dist(exts[0]-exts[2],0), cubetruss_dist(exts[1]-exts[3],0), cubetruss_dist(h+exts[4]-1,0)]/2;
525    attachable(anchor,spin,orient, size=s, offset=offset) {
526        union() {
527            for (zcol = [0:h-1]) {
528                up((size-strut)*zcol) {
529                    cubetruss_segment(size=size, strut=strut, bracing=bracing);
530                }
531            }
532            for (dir = [0:3]) {
533                if (exts[dir] != undef && exts[dir] > 0) {
534                    zrot(dir*90) {
535                        for (zcol = [0:h-1]) {
536                            up((size-strut+0.01)*zcol) {
537                                for (i = [1:exts[dir]]) {
538                                    right((size-strut+0.01)*i) cubetruss_segment(size=size, strut=strut, bracing=bracing);
539                                }
540                                if (clipthick > 0) {
541                                    right(exts[dir]*(size-strut)+size/2) {
542                                        zrot(90) cubetruss_clip(size=size, strut=strut, clipthick=clipthick);
543                                    }
544                                }
545                            }
546                        }
547                    }
548                }
549            }
550            if (exts[4] != undef && exts[4] > 0) {
551                for (i = [1:exts[4]]) {
552                    up((size-strut+0.01)*(i+h-1)) cubetruss_segment(size=size, strut=strut, bracing=bracing);
553                }
554                if (clipthick > 0) {
555                    up((exts[4]+h-1)*(size-strut)+size/2) {
556                        xrot(-90) cubetruss_clip(size=size, strut=strut, clipthick=clipthick);
557                    }
558                }
559            }
560        }
561        children();
562    }
563}
564
565
566
567// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap