omdl  v1.0
OpenSCAD Mechanical Design Library
box_finger_joint.scad
Go to the documentation of this file.
1 //! A finger joint (box joint) box generator for CNC cut-based fabrication.
2 /***************************************************************************//**
3  \file
4  \author Roy Allen Sutton
5  \date 2026
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 (Finger Joint Box Generator)
31  \amu_define group_brief (Finger joint (box joint) box generator.)
32 
33  \amu_include (include/amu/doxyg_init_pd_gds_ipg.amu)
34 *******************************************************************************/
35 
36 //----------------------------------------------------------------------------//
37 // group and macros.
38 //----------------------------------------------------------------------------//
39 
40 /***************************************************************************//**
41  \amu_include (include/amu/doxyg_define_in_parent_open.amu)
42  \amu_define includes_required_add
43  (
44  shapes/select_common_2d.scad
45  transforms/base_cs.scad
46  transforms/layout.scad
47  models/2d/joint/box_screw.scad
48  )
49  \amu_include (include/amu/includes_required.amu)
50 *******************************************************************************/
51 
52 //----------------------------------------------------------------------------//
53 
54 //! Generate a 2D box design using screw-based finger joint (box-joint).
55 /***************************************************************************//**
56  \param mth <decimal> material thickness.
57 
58  \param size <decimal-list-3 | decimal> box size; a list
59  [x, y, z] or a single decimal for (x=y=z).
60 
61  \param joint_pin <decimal-list-5 | decimal> joint pin
62  configuration.
63 
64  \param joint_screw <decimal-list-2 | decimal> joint screw
65  configuration.
66 
67  \param joint_nut <decimal-list-4 | decimal> joint nut
68  configuration.
69 
70  \param joint_form <integer> joint form.
71 
72  \param joint_mode <integer> joint mode.
73 
74  \param joint_spacing <decimal-list-3 | decimal> minimum separation
75  between joint pins; a list [x, y, z] or a
76  single decimal for (x=y=z).
77 
78  \param joints_max <integer-list-3 | integer> maximum pin sets for
79  sides [x, y, z] or a single integer for (x=y=z).
80 
81  \param side_holes <datastruct> box side hole instances (see below).
82 
83  \param side_add <point-2d-list-4-list> coordinate points to
84  merge into the box xz and yz sides.
85 
86  \param vr <decimal-list-6-list-n | decimal> box rounding;
87  where `n = 4` for rectangular sides. (see below).
88 
89  \param vrm <integer-list-6-list-n | integer> box rounding
90  mode where `n = 4` for rectangular sides. (see
91  below).
92 
93  \param side_spacing <decimal> separation between box sides.
94 
95  \param layout <integer> layout selection {0 | 1 | 2}.
96 
97  \param mode <integer> construction mode (see below).
98 
99  \param part <integer> side output selection (see below).
100 
101  \param verb <integer> output console verbosity.
102 
103  \details
104 
105  Creates a 2D box layout with straight finger joints and optional
106  screw fasteners. The resulting geometry can be rendered to SVG or
107  DXF for CNC cutting, or extruded to a specified material thickness
108  for fabrication using a 3D printer.
109 
110  ### joint_*
111 
112  The joints are constructed using the module joint2d_box_screw().
113  For clarity, all related parameters in this context are prefixed
114  with \p joint_. The joint module supports configurable interior and
115  exterior corner rounding to compensate for cutting tool diameter, a
116  technique commonly referred to as dogbone corner relief. Refer to
117  the joint2d_box_screw() module documentation for detailed
118  information on the expected data types and configuration scheme.
119 
120  ### side_holes
121 
122  #### Data structure schema:
123 
124  name | schema
125  ---------------:|:----------------------------------------------
126  side_holes | [instances]
127  instances | [instance, instance, ..., instance]
128 
129  #### Data structure fields: instance
130 
131  e | data type | default value | parameter description
132  ---:|:-----------------:|:-----------------:|:------------------------------------
133  0 | integer-list \| integer | required | box side index or index list (see below)
134  1 | datastruct \| integer | 1 | 2d shape selections (see: select_common_2d_shape())
135  2 | datastruct | [0] | shape layout (see: layout_grid_rp()
136 
137  The box side are assigned the following indices:
138 
139  v | side | description
140  ---:|:-----------:|:--------------------
141  0 | back | side xz negative
142  1 | front | side xz positive
143  2 | left | side yz negative
144  3 | right | side yz positive
145  4 | bottom | side xy negative
146  5 | top | side xy positive
147 
148  ### side_add
149 
150  When the box is open (no top side) individual box sides can be
151  customized by merging an additional list of coordinate points into
152  the side geometry. Each side may be customized independently using
153  the scheme in the following table:
154 
155  e | data type | default value | parameter description
156  ---:|:-----------------:|:-----------------:|:------------------------------------
157  0 | point-2d-list | | \p ap_xz_1 : side xz-1
158  1 | point-2d-list | | \p ap_yz_1 : side yz-1
159  2 | point-2d-list | \p ap_xz_1 | \p ap_xz_2 : side xz-2
160  3 | point-2d-list | \p ap_yz_1 | \p ap_yz_2 : side yz-2
161 
162  The parameter \p p is ignored for closed boxes.
163 
164  ### vr and vrm
165 
166  The box sides can be rounded together or independently using the
167  parameters \p vr and \p vrm as show in the table below:
168 
169  e | data type | default value | parameter description
170  ---:|:-----------------:|:-------------------:|:------------------------------------
171  0 | decimal-list-n \| decimal | required | \p vr_xy_1 : side xy-1 rounding
172  1 | decimal-list-n \| decimal | \p vr_xy_1 | \p vr_xz_1 : side xz-1 rounding
173  2 | decimal-list-n \| decimal | \p vr_xz_1 | \p vr_yz_1 : side yz-1 rounding
174  3 | decimal-list-n \| decimal | \p vr_xy_1 | \p vr_xy_2 : side xy-2 rounding
175  4 | decimal-list-n \| decimal | \p vr_xz_1 | \p vr_xz_2 : side xz-2 rounding
176  5 | decimal-list-n \| decimal | \p vr_yz_1 | \p vr_yz_2 : side yz-2 rounding
177 
178  The vertices of each side can be rounded independently by assigning
179  values using a four-element list, or they can all be assigned the
180  same value by setting the side rounding to a single value.
181 
182  The rounding mode follows the same scheme described above. For more
183  information on rounding options, see polygon_round_eve_all_p().
184 
185  For rectangular sides `n = 4`. However, when customized side points
186  are specified using the \p side_add option, the corresponding
187  rounding lists size `n` must be extended to match the number of
188  added points for each customized side, if individual vertex
189  treatment is desired.
190 
191  ### mode
192 
193  Integer value is binary encoded.
194 
195  b | description
196  ---:|:---------------------------------------
197  0 | size is specified for box interior
198  1 | add top side to close box
199  2 | trim each joint to within its width
200  3 | extrude 2d layout for 3d printing
201 
202  ### part
203 
204  Construction of each side of the box is controlled using the
205  binary-encoded integer parameter \p part. Each side corresponds to
206  a specific bit position according to the side index described
207  above. To enable or disable a side, adjust the \p part value by
208  setting or clearing the binary value associated with that side’s
209  index.
210 
211  For example, to output only the bottom of the front and the bottom
212  of the box, set: `part = (pow(2, 1) + pow(2, 5));`
213 
214  \amu_define scope_id (example)
215  \amu_define title (2d box example)
216  \amu_define image_views (top)
217  \amu_define image_size (sxga)
218 
219  \amu_include (include/amu/scope_diagrams_3d.amu)
220 
221  \amu_define scope_id (example_assemled)
222  \amu_define title (Assembled box example)
223  \amu_define image_views (top front right diag)
224  \amu_define image_size (sxga)
225  \amu_define image_columns (4)
226  \amu_define output_scad (false)
227 
228  \amu_include (include/amu/scope_diagrams_3d.amu)
229 
230  \todo
231 
232  -# Support side-wall joint edge inset(s).
233  -# Support addition of horizontal and vertical interior walls.
234 *******************************************************************************/
235 module box2d_finger_joint
236 (
237  mth = 1,
238  size,
239 
240  joint_pin,
241  joint_screw,
242  joint_nut,
243  joint_form = 7,
244  joint_mode = 0,
245  joint_spacing,
246  joints_max,
247 
248  side_holes,
249  side_add,
250 
251  vr,
252  vrm,
253 
254  side_spacing,
255  layout = 0,
256 
257  mode = 0,
258  part = 63,
259  verb = 0
260 )
261 {
262  //
263  // construct a side
264  //
265  module construct_side( idx, size, insts, p, vr, vrm )
266  {
267  //
268  // construct a side joint
269  //
270  module construct_joint( size, length, count, offset, axis, sides, type )
271  {
272  side_offset = type == 2 ? -1 : +1;
273 
274  joint_length = first(pin_conf) * 2 + second(pin_conf) + offset;
275  joint_count = min(count, max(1, floor(length / joint_length)));
276 
277  if (joint_count > 0)
278  for (s = sides)
279  translate
280  (
281  axis == 0 ?
282  [ s * (size.x/2 + mth/2 * side_offset), 0 ]
283  : [ 0, s * (size.y/2 + mth/2 * side_offset) ]
284  )
285  rotate(axis == 0 ? -90 : 0)
286  translate([joint_length/2 - (joint_length * joint_count)/2, 0])
287  mirror(s < 0 ? [0, 1] : [0, 0])
288  mirror(type == 2 ? [0, 1] : [0, 0])
290  (
291  conf = [ length, mth, pin_conf, screw_conf, nut_conf ],
292  insts = [ for ( i = [0 : joint_count - 1] ) [0, joint_length * i, joint_form ] ],
293  mode = joint_mode,
294  type = type,
295  trim = trim,
296  align = [0, 1]
297  );
298  }
299 
300  //
301  // construct a side hole instance
302  //
303  module construct_hole_inst( inst )
304  {
305  shape = defined_e_or (inst, 1, 1);
306  layout = defined_e_or (inst, 2, [0]);
307 
308  shape_type = is_list(shape) ? first(shape) : shape;
309  shape_argv = is_list(shape) ? tailn(shape, 1) : undef;
310 
311  layout_grid_rp(t=layout, b=size, center=true, verb=verb-1)
312  select_common_2d_shape( type=shape_type, argv=shape_argv, center=true, verb=verb-1 );
313 
314  if (verb > 1)
315  {
316  log_info(strl(["holes for side index = ", idx, ", conf = ", inst]));
317  log_echo(strl(["hole conf = ", inst]));
318 
319  if (verb > 2)
320  echo(shape_type=shape_type, shape_argv=shape_argv, layout=layout);
321  }
322  }
323 
324  // assemble side with joint
325  difference()
326  {
327  // joint instance additions
328  for (i = insts)
329  {
330  length = i[0];
331  count = i[1];
332  offset = i[2];
333  axis = i[3];
334  sides = i[4];
335  type = i[5];
336 
337  // rectangular side shape
338  polygon
339  (
340  let
341  (
342  x = size.x/2, y = size.y/2,
343 
344  c = is_undef( p ) ?
345  // centered rectangular
346  [[x, -y], [x, y], [-x, y], [-x, -y]]
347  // centered rectangular with points 'p' at top
348  : concat([[x, -y], [x, y]], p ,[[-x, y], [-x, -y]]),
349 
350  // round if defined
351  p = is_undef( vr ) ? c : polygon_round_eve_all_p(c=c, vr=vr, vrm=vrm)
352  )
353  p
354  );
355 
356  // male pins additions
357  if ( type == 0 )
358  construct_joint
359  (
360  size=size, length=length, count=count,
361  offset=offset, axis=axis, sides=sides,
362  type=0
363  );
364  }
365 
366  // joint instance removals
367  for (i = insts)
368  {
369  length = i[0];
370  count = i[1];
371  offset = i[2];
372  axis = i[3];
373  sides = i[4];
374  type = i[5];
375 
376  size_ro = size + [eps, eps] * 8;
377 
378  // male pins removals
379  if ( type == 0 )
380  construct_joint
381  (
382  size=size_ro, length=length, count=count,
383  offset=offset, axis=axis, sides=sides,
384  type=1
385  );
386 
387  // female pins removals
388  if ( type == 2 )
389  construct_joint
390  (
391  size=size_ro, length=length, count=count,
392  offset=offset, axis=axis, sides=sides,
393  type=2
394  );
395  }
396 
397  // side hole instance removals
398  for (i = side_holes)
399  {
400  // get enabled side (or side list) for instance
401  e = defined_eon_or(i, 0, undef);
402 
403  if ( !is_empty( search(idx, is_list(e) ? e : [e]) ) )
404  construct_hole_inst( i );
405  }
406  }
407  }
408 
409  //
410  // layout in 2d
411  //
412  module layout_2d( gap, select )
413  {
414  if (verb > 0)
415  log_info(strl(["2d layout number ", select]));
416 
417  side_offset_x = (select == 0) ?
418  (side_xy.x + side_yz.x)/2 + gap - mth
419  : (side_xy.x + side_yz.y)/2 + gap;
420 
421  side_offset_y = (side_xy.y + side_xz.y)/2 + gap;
422 
423  for (side = close ? [0, 2] : [0])
424  let
425  (
426  i = side > 0 ? 5 : 4,
427 
428  r = side > 0 ? 0 : 180,
429  t = [0, side_offset_y * side],
430 
431  p = undef,
432  vr = side > 0 ? vr_xy_1 : vr_xy_2,
433  vrm = side > 0 ? vrm_xy_1 : vrm_xy_2
434  )
435  if (binary_bit_is(part, i, 1))
436  translate(t) rotate(r)
437  construct_side( idx=i, size=side_xy, insts=insts_xy, p=p, vr=vr, vrm=vrm );
438 
439  for (side = [-1, 1])
440  let
441  (
442  i = side > 0 ? 1 : 0,
443 
444  r = side > 0 ? 0 : 180,
445  t = [0, side_offset_y * side],
446 
447  p = side > 0 ? ap_xz_1 : ap_xz_2,
448  vr = side > 0 ? vr_xz_1 : vr_xz_2,
449  vrm = side > 0 ? vrm_xz_1 : vrm_xz_2
450  )
451  if (binary_bit_is(part, i, 1))
452  translate(t) rotate(r)
453  construct_side( idx=i, size=side_xz, insts=insts_xz, p=p, vr=vr, vrm=vrm );
454 
455  for (side = [-1, 1])
456  let
457  (
458  i = side > 0 ? 3 : 2,
459 
460  r = (select == 0) ?
461  side > 0 ? 0 : 180
462  : side > 0 ? 270 : 90,
463 
464  t = (select == 0) ?
465  [side_offset_x * side, side_offset_y * side]
466  : [side_offset_x * side, 0],
467 
468  p = side > 0 ? ap_yz_1 : ap_yz_2,
469  vr = side > 0 ? vr_yz_1 : vr_yz_2,
470  vrm = side > 0 ? vrm_yz_1 : vrm_yz_2
471  )
472  if (binary_bit_is(part, i, 1))
473  translate(t) rotate(r)
474  construct_side( idx=i, size=side_yz, insts=insts_yz, p=p, vr=vr, vrm=vrm );
475  }
476 
477  //
478  // layout in 3d
479  //
480  module layout_3d( gap )
481  {
482  if (verb > 0)
483  log_info(strl(["3d layout"]));
484 
485  color("blue")
486  for (side = close ? [-1, 1] : [-1])
487  let
488  (
489  i = side > 0 ? 5 : 4,
490 
491  r = 0,
492  t = [0, 0, (box_z/2 - mth/2 + gap) * side + (close ? 0 : -mth/2)],
493 
494  p = undef,
495  vr = side > 0 ? vr_xy_1 : vr_xy_2,
496  vrm = side > 0 ? vrm_xy_1 : vrm_xy_2
497  )
498  if (binary_bit_is(part, i, 1))
499  translate(t) rotate(r)
500  extrude_linear_uss(mth, center=true)
501  construct_side( idx=i, size=side_xy, insts=insts_xy, p=p, vr=vr, vrm=vrm );
502 
503  color("green")
504  for (side = [-1, 1])
505  let
506  (
507  i = side > 0 ? 1 : 0,
508 
509  r = side > 0 ? [90, 0, 0] : [90, 0, 180],
510  t = [0, (box_y/2 + gap) * side, 0],
511 
512  p = side > 0 ? ap_xz_1 : ap_xz_2,
513  vr = side > 0 ? vr_xz_1 : vr_xz_2,
514  vrm = side > 0 ? vrm_xz_1 : vrm_xz_2
515  )
516  if (binary_bit_is(part, i, 1))
517  translate(t) rotate(r)
518  extrude_linear_uss(mth)
519  construct_side( idx=i, size=side_xz, insts=insts_xz, p=p, vr=vr, vrm=vrm );
520 
521  color("gray")
522  for (side = [-1, 1])
523  let
524  (
525  i = side > 0 ? 3 : 2,
526 
527  r = side > 0 ? [90, 0, 90] : [90, 0, 270],
528  t = [(box_x/2 - mth + gap) * side, 0, 0],
529 
530  p = side > 0 ? ap_yz_1 : ap_yz_2,
531  vr = side > 0 ? vr_yz_1 : vr_yz_2,
532  vrm = side > 0 ? vrm_yz_1 : vrm_yz_2
533  )
534  if (binary_bit_is(part, i, 1))
535  translate(t) rotate(r)
536  extrude_linear_uss(mth)
537  construct_side( idx=i, size=side_yz, insts=insts_yz, p=p, vr=vr, vrm=vrm );
538  }
539 
540  //
541  // decode and assign defaults to undefined parameters
542  //
543 
544  // decode mode configurations
545  inside = binary_bit_is(mode, 0, 1);
546  close = binary_bit_is(mode, 1, 1);
547  trim = binary_bit_is(mode, 2, 1);
548  extrude = binary_bit_is(mode, 3, 1);
549 
550  box_p_x = defined_eon_or(size, 0, mth*10);
551  box_p_y = defined_e_or (size, 1, box_p_x);
552  box_p_z = defined_e_or (size, 2, box_p_y);
553 
554  pin_conf = defined_or(joint_pin, [mth, mth * 5/2]);
555 
556  pin_offset_x = defined_eon_or(joint_spacing, 0, second(pin_conf));
557  pin_offset_y = defined_e_or (joint_spacing, 1, pin_offset_x);
558  pin_offset_z = defined_e_or (joint_spacing, 2, pin_offset_y);
559 
560  max_sets_x = defined_eon_or(joints_max, 0, number_max);
561  max_sets_y = defined_e_or (joints_max, 1, max_sets_x);
562  max_sets_z = defined_e_or (joints_max, 2, max_sets_y);
563 
564  screw_conf = defined_or(joint_screw, mth/3);
565  nut_conf = defined_or(joint_nut, mth*2/3);
566 
567  side_offset = defined_or(side_spacing, mth);
568 
569  // side customization for open boxes only
570  ap_xz_1 = close ? undef : defined_e_or (side_add, 0, undef);
571  ap_yz_1 = close ? undef : defined_e_or (side_add, 1, undef);
572 
573  ap_xz_2 = close ? undef : defined_e_or (side_add, 2, ap_xz_1);
574  ap_yz_2 = close ? undef : defined_e_or (side_add, 3, ap_yz_1);
575 
576  // side rounding
577  vr_xy_1 = defined_eon_or(vr, 0, 0);
578  vr_xz_1 = defined_e_or (vr, 1, vr_xy_1);
579  vr_yz_1 = defined_e_or (vr, 2, vr_xz_1);
580 
581  vr_xy_2 = defined_e_or (vr, 3, vr_xy_1);
582  vr_xz_2 = defined_e_or (vr, 4, vr_xz_1);
583  vr_yz_2 = defined_e_or (vr, 5, vr_yz_1);
584 
585  // side rounding modes
586  vrm_xy_1 = defined_eon_or(vrm, 0, 1);
587  vrm_xz_1 = defined_e_or (vrm, 1, vrm_xy_1);
588  vrm_yz_1 = defined_e_or (vrm, 2, vrm_xz_1);
589 
590  vrm_xy_2 = defined_e_or (vrm, 3, vrm_xy_1);
591  vrm_xz_2 = defined_e_or (vrm, 4, vrm_xz_1);
592  vrm_yz_2 = defined_e_or (vrm, 5, vrm_yz_1);
593 
594  //
595  // Calculate sizes and configuration
596  //
597 
598  // box size
599  box_x = inside ? box_p_x + mth*2 : box_p_x;
600  box_y = inside ? box_p_y + mth*2 : box_p_y;
601  box_z = inside ? box_p_z + mth*2 : box_p_z;
602 
603  // box side dimensions
604  side_xy = [ box_x, box_y ];
605  side_xz = [ box_x - mth*2, box_z - (close ? mth*2 : mth) ];
606  side_yz = [ box_y, box_z - (close ? mth*2 : mth) ];
607 
608  // joint lengths
609  joint_x = min(side_xy.x, side_xz.x);
610  joint_y = min(side_xy.y, side_yz.y);
611  joint_z = min(side_xz.y, side_yz.y);
612 
613  //
614  // joint instances
615  //
616 
617  insts_xy =
618  [
619  [joint_y, max_sets_y, pin_offset_y, 0, [-1, +1], 2],
620  [joint_x, max_sets_x, pin_offset_x, 1, [-1, +1], 2]
621  ];
622 
623  insts_xz =
624  [
625  [joint_z, max_sets_z, pin_offset_z, 0, [-1, +1], 0],
626  [joint_x, max_sets_x, pin_offset_x, 1, close ? [-1, +1] : [-1], 0]
627  ];
628 
629  insts_yz =
630  [
631  [joint_z, max_sets_z, pin_offset_z, 0, [-1, +1], 2],
632  [joint_y, max_sets_y, pin_offset_y, 1, close ? [-1, +1] : [-1], 0]
633  ];
634 
635  //
636  // construct box layout
637  //
638 
639  if (verb > 0)
640  {
641  log_info(strl(["box exterior size = ", [box_x, box_y, box_z]]));
642 
643  log_info(strl(["side_xy = ", side_xy]));
644  log_info(strl(["side_xz = ", side_xz]));
645  log_info(strl(["side_yz = ", side_yz]));
646  }
647 
648  if ( layout > 1)
649  {
650  layout_3d( gap=side_offset );
651  }
652  else
653  {
654  if ( extrude )
655  {
656  extrude_linear_uss( mth, center=false )
657  layout_2d( gap=side_offset, select=layout );
658  }
659  else
660  {
661  layout_2d( gap=side_offset, select=layout );
662  }
663  }
664 }
665 
666 
667 //! @}
668 //! @}
669 
670 
671 //----------------------------------------------------------------------------//
672 // openscad-amu auxiliary scripts
673 //----------------------------------------------------------------------------//
674 
675 /*
676 BEGIN_SCOPE example;
677  BEGIN_OPENSCAD;
678  include <omdl-base.scad>;
679  include <shapes/select_common_2d.scad>;
680  include <transforms/base_cs.scad>;
681  include <transforms/layout.scad>;
682  include <models/2d/joint/box_screw.scad>;
683  include <parts/2d/enclosure/box_finger_joint.scad>;
684 
685  box2d_finger_joint
686  (
687  mth = 2,
688  size = [80, 40, 30],
689 
690  joint_pin = [4, 6, 1/2, 1/2, 1/2],
691  joint_screw = [3/2, 5],
692  joint_nut = [3, 3/2],
693  joint_spacing = 20,
694  joints_max = [3, 1, 1],
695 
696  side_add =
697  [
698  // lower mid-section
699  [[0, 5]],
700 
701  // raise sides for handles
702  [[+10, 20], [-10, 20]]
703  ],
704 
705  side_holes =
706  [
707  // stars
708  [ [0,1], [9, 2], [0, 0, 0, 0, 0, 0, 8, 8] ],
709 
710  // slots
711  [ [2,3], [3, [2, 10], 1, 5], [0, 0, 0, 0, 0, 0, 8, 4] ],
712 
713  // handles
714  [ [2,3], [6, [[10, 5], -x_axis2d_uv, +x_axis2d_uv]], [0, 0, 0, 0, 0, [0,12]] ],
715 
716  // bottom
717  [ 4, [2, [1, 6]], [0, 0, 0, 0, 0, 0, [9,4], [8,8]] ]
718  ],
719 
720  vr = 2,
721  layout = 1
722  );
723 
724  // end_include
725  END_OPENSCAD;
726 
727  BEGIN_MFSCRIPT;
728  include --path "${INCLUDE_PATH}" {var_init,var_gen_png2eps}.mfs;
729  table_unset_all sizes;
730 
731  images name "sizes" types "sxga";
732  views name "views" views "top";
733 
734  variables set_opts_combine "sizes views";
735  variables add_opts "--viewall --autocenter --view=axes";
736 
737  include --path "${INCLUDE_PATH}" scr_make_mf.mfs;
738  END_MFSCRIPT;
739 END_SCOPE;
740 */
741 
742 /*
743 BEGIN_SCOPE example_assemled;
744  BEGIN_OPENSCAD;
745  include <omdl-base.scad>;
746  include <shapes/select_common_2d.scad>;
747  include <transforms/base_cs.scad>;
748  include <transforms/layout.scad>;
749  include <models/2d/joint/box_screw.scad>;
750  include <parts/2d/enclosure/box_finger_joint.scad>;
751 
752  box2d_finger_joint
753  (
754  mth = 2,
755  size = [80, 40, 30],
756 
757  joint_pin = [4, 6, 1/2, 1/2, 1/2],
758  joint_screw = [3/2, 5],
759  joint_nut = [3, 3/2],
760  joint_spacing = 20,
761  joints_max = [3, 1, 1],
762 
763  side_add =
764  [
765  // lower mid-section
766  [[0, 5]],
767 
768  // raise sides for handles
769  [[+10, 20], [-10, 20]]
770  ],
771 
772  side_holes =
773  [
774  // stars
775  [ [0,1], [9, 2], [0, 0, 0, 0, 0, 0, 8, 8] ],
776 
777  // slots
778  [ [2,3], [3, [2, 10], 1, 5], [0, 0, 0, 0, 0, 0, 8, 4] ],
779 
780  // handles
781  [ [2,3], [6, [[10, 5], -x_axis2d_uv, +x_axis2d_uv]], [0, 0, 0, 0, 0, [0,12]] ],
782 
783  // bottom
784  [ 4, [2, [1, 6]], [0, 0, 0, 0, 0, 0, [9,4], [8,8]] ]
785  ],
786 
787  vr = 2,
788  layout = 2
789  );
790 
791  // end_include
792  END_OPENSCAD;
793 
794  BEGIN_MFSCRIPT;
795  include --path "${INCLUDE_PATH}" {var_init,var_gen_png2eps}.mfs;
796  table_unset_all sizes;
797 
798  images name "sizes" types "sxga";
799  views name "views" views "top front right diag";
800 
801  variables set_opts_combine "sizes views";
802  variables add_opts "--viewall --autocenter --view=axes";
803 
804  include --path "${INCLUDE_PATH}" scr_make_mf.mfs;
805  END_MFSCRIPT;
806 END_SCOPE;
807 */
808 
809 //----------------------------------------------------------------------------//
810 // end of file
811 //----------------------------------------------------------------------------//
812 
module log_echo(m)
Output message to console.
Definition: console.scad:272
module log_info(m)
Output information message to console.
Definition: console.scad:318
eps
<decimal> Epsilon, small distance to deal with overlapping shapes.
Definition: constants.scad:195
number_max
<decimal> The largest representable number in OpenSCAD scripts.
Definition: constants.scad:289
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)
Returns an element from an iterable if it exists, or a default value if not.
function count(mv, v, s=true, i)
Count all occurrences of a match value in an iterable value.
function second(v)
Return the second element of an iterable value.
function defined_eon_or(v, i, d)
Returns the list element or scalar numeric value if defined, otherwise returns the default value.
function first(v)
Return the first element of an iterable value.
function tailn(v, n=1)
Return a list containing all but the first n elements of an iterable value.
function is_empty(v)
Test if an iterable value is empty.
function strl(v)
Convert a list of values to a concatenated string.
function defined_or(v, d)
Return given value, if defined, or a secondary value, if primary is not defined.
function polygon_round_eve_all_p(c, vr=0, vrm=1, vfn, w=true, cw=true)
Compute coordinates that round all of the vertices between each adjacent edges in 2D.
module joint2d_box_screw(conf, insts, mode=0, type=0, trim=false, align)
Create 2d edge profiles for screw and nut box joint construction.
Definition: box_screw.scad:433
module box2d_finger_joint(mth=1, size, joint_pin, joint_screw, joint_nut, joint_form=7, joint_mode=0, joint_spacing, joints_max, side_holes, side_add, vr, vrm, side_spacing, layout=0, mode=0, part=63, verb=0)
Generate a 2D box design using screw-based finger joint (box-joint).
module select_common_2d_shape(type=0, argv, center=false, verb=0)
Select configure and construct one of the available 2d shapes.
module extrude_linear_uss(h, center=false, c=true, ha=0)
Linearly extrude a 2d shape with uniformly-spaced profile scaling.
Definition: extrude.scad:666
module layout_grid_rp(t, s, b=zero3d, center=false, mode=0, verb=0)
A transform sequence to replicate and place a child shape.
Definition: layout.scad:507
function length(v, from=length_unit_default, to=length_unit_base, d=1)
Convert a length value from one unit to another, with optional dimensional scaling.