omdl  v1.0
OpenSCAD Mechanical Design Library
dovetail.scad
Go to the documentation of this file.
1 //! Models for generating dovetailed joints in 2d.
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 (Dovetails)
31  \amu_define group_brief (Models for generating dovetailed joints in 2d.)
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  transforms/base_cs.scad
45  )
46  \amu_include (include/amu/includes_required.amu)
47 *******************************************************************************/
48 
49 //----------------------------------------------------------------------------//
50 
51 //! Create 2D edge profiles for dovetail joint construction.
52 /***************************************************************************//**
53  \param t <decimal-list-6 | decimal> tail configuration; a list
54  [m, s, f, g, er, ir] or a single decimal to set m
55  (see below).
56 
57  \param d <decimal> joint depth (tail length).
58 
59  \param w <decimal> joint total width.
60 
61  \param o <decimal> tail initial width offset.
62 
63  \param type <integer> construction type {0=male additions,
64  1=male removals, 2=female removals}.
65 
66  \param trim <boolean> limit construction to within the total
67  joint width.
68 
69  \param center <boolean> center tails over total joint width.
70 
71  \param align <integer-list-2> joint alignment; edge-1, center, and
72  edge-2 for both [x, y].
73 
74  \details
75 
76  Use this module to generate a 2D profile for constructing dovetail
77  joints. Set \p type = 0 to create the male dovetail fingers, and
78  set \p type = 2 to create the corresponding female slots. Ensure
79  that the same profile parameters are used for both components to
80  achieve proper alignment and fit.
81 
82  When creating dovetail joints using 3D-printed plastics, it’s
83  important to carefully manage the joint gap due to the rigidity of
84  most plastics. It’s a good idea to test with small sample joints
85  before proceeding with larger parts. Additionally, applying gentle
86  heat to the joint during assembly using a hot air gun (or hair
87  dryer) can help soften the male and female components slightly,
88  improving the fit and ease of assembly.
89 
90  ## Multi-value and structured parameters
91 
92  ### tail
93 
94  #### Data structure fields: t (tail configuration)
95 
96  e | data type | default value | parameter description
97  ---:|:-----------------:|:-----------------:|:------------------------------------
98  0 | decimal | required | \p m : male tail width
99  1 | decimal | m | \p s : female slot width
100  2 | decimal | m/5 | \p f : tail fin width expansion
101  3 | decimal | m/25 | \p g : joint gap (male and female)
102  4 | decimal | m/20 | \p er : external edge rounding
103  5 | decimal | m/20 | \p ir : internal edge rounding (minimum cut radius)
104 
105  The parameter \p ir can be used to define an internal corner edge
106  overcut, which helps accommodate the minimum cut radius required
107  for subtractive manufacturing. This overcut is based on the minimum
108  diameter of the cut tool. By clearing the rounded section, it
109  ensures proper clearance for mating joint members during assembly.
110 
111  \amu_define scope_id (example)
112  \amu_define title (Dovetail profile example)
113  \amu_define image_views (top)
114  \amu_define image_size (sxga)
115 
116  \amu_include (include/amu/scope_diagrams_3d.amu)
117 *******************************************************************************/
118 
119 module joint2d_dovetail
120 (
121  t = 1,
122  d = 1,
123 
124  w = 10,
125  o = 0,
126 
127  type = 0,
128 
129  trim = false,
130  center = false,
131 
132  align
133 )
134 {
135  t1 = defined_e_or(t, 0, t); // male (tail) width
136  t2 = defined_e_or(t, 1, t1); // female width
137  te = defined_e_or(t, 2, t1/5); // "engagement" width
138  tg = defined_e_or(t, 3, t1/25); // finger gap width
139  er = defined_e_or(t, 4, t1/20); // finger exterior edge rounding
140  ir = defined_e_or(t, 5, t1/20); // finger interior edge rounding
141 
142  tc = ceil(w / (t1 + t2)); // finger count
143 
144  mr = (type == 2) ? 0 : er; // male exterior rounding
145  fr = (type == 2) ? er : 0; // female exterior rounding
146  sg = (type == 2) ? 1 : -1; // gap adjustment
147 
148  s1 = t1 + sg * tg/2; // finger sized for gap
149 
150  // joint initial offset
151  io = o - sg * tg/4 + (center ? w/2 - (t1*tc + t2*(tc-1))/2 : 0);
152 
153  // align construction
154  translate
155  (
156  [
157  select_ci( [ 0, -w/2, -w ], defined_e_or(align, 0, 0), false ),
158  select_ci( [ 0, -d/2, -d ], defined_e_or(align, 1, 0), false ),
159  ]
160  )
161  {
162  // male and female joint construction; male additions or female removals
163  if (type == 0 || type == 2)
164  intersection_cs(trim, trim ? undef : 1)
165  {
166  // child-0: joint trim area = length x depth
167  square([w, d]);
168 
169  // child-1: dovetails; male additions or female removals
170  for ( i = [0 : tc-1] )
171  translate ([io + (t1 + t2)*i, 0])
172  {
173  // male and female finger construction
174  if (te > 0)
175  { // finger tail with engagement
176  pg_te = let
177  (
178  sss = triangle_sas2sss( [d, 90, te/2] ),
179  ppp = triangle2d_sss2ppp( sss ),
180 
181  vrm = [0,0,1]
182  )
183  polygon_round_eve_all_p(ppp, vr=mr, vrm=vrm);
184 
185  // straight section round out at base (female removal)
186  pg_rectangle([s1, d], vr=fr, vrm=[0,0,4,3]);
187 
188  translate([-te/2,d])
189  rotate([180,0])
190  polygon(pg_te);
191 
192  translate([s1 + te/2, d])
193  rotate([180,180])
194  polygon(pg_te);
195  }
196  else
197  { // straight finger / pin
198  pg_rectangle([s1, d], vr=er, vrm=(type == 2) ? [0,0,4,3] : [1,1,0,0]);
199  }
200  }
201  }
202 
203  // interior corner minimum cut radius; removal modes only
204  if ( ir > 0 && (type == 1 || type == 2))
205  for
206  (
207  i = [0 : tc-1],
208 
209  mcr_o =
210  let ( pe = max(te, 0) )
211  [
212  [ - pe/2, 0] + ((type == 2) ? [+ir/2, d] : [+(pe-ir)/2, 0]),
213  [s1 + pe/2, 0] + ((type == 2) ? [-ir/2, d] : [-(pe-ir)/2, 0])
214  ]
215  )
216  translate([io + (t1 + t2)*i, 0] + mcr_o)
217  circle(d=ir);
218  }
219 }
220 
221 
222 //! @}
223 //! @}
224 
225 
226 //----------------------------------------------------------------------------//
227 // openscad-amu auxiliary scripts
228 //----------------------------------------------------------------------------//
229 
230 /*
231 BEGIN_SCOPE example;
232  BEGIN_OPENSCAD;
233  include <omdl-base.scad>;
234  include <transforms/base_cs.scad>;
235  include <models/2d/joint/dovetail.scad>;
236 
237  w = 20;
238  t = [2, 3.25, 1, 1/20, 1/8, 1/4];
239  d = 2.75;
240  c = true;
241 
242  // male section (lower)
243  joint2d_dovetail (w=w, t=t, d=d, type=0, center=c );
244  difference() { translate([0, -d/2]) square([w, d/2]); joint2d_dovetail (w=w, t=t, d=d, type=1, center=c ); }
245 
246  // female section (upper)
247  translate([0, d*1.25])
248  difference() { square([w, d+d/2]); joint2d_dovetail (w=w, t=t, d=d, type=2, center=c ); }
249 
250  // end_include
251  END_OPENSCAD;
252 
253  BEGIN_MFSCRIPT;
254  include --path "${INCLUDE_PATH}" {var_init,var_gen_png2eps}.mfs;
255  table_unset_all sizes;
256 
257  images name "sizes" types "sxga";
258  views name "views" views "top";
259 
260  variables set_opts_combine "sizes views";
261  variables add_opts "--viewall --autocenter --view=axes";
262 
263  include --path "${INCLUDE_PATH}" scr_make_mf.mfs;
264  END_MFSCRIPT;
265 END_SCOPE;
266 */
267 
268 //----------------------------------------------------------------------------//
269 // end of file
270 //----------------------------------------------------------------------------//
271 
function defined_e_or(v, i, d)
Returns an element from an iterable if it exists, or a default value if not.
function select_ci(v, i, l=true)
Select specified element from list or return a default.
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.
function triangle_sas2sss(v)
Compute the side lengths of a triangle given two sides and the included angle.
function triangle2d_sss2ppp(v, a=x_axis_ci, cw=true)
Compute a set of vertex coordinates for a triangle given its side lengths in 2D.
module joint2d_dovetail(t=1, d=1, w=10, o=0, type=0, trim=false, center=false, align)
Create 2D edge profiles for dovetail joint construction.
Definition: dovetail.scad:380
module pg_rectangle(size=1, o, vr, vrm=1, vfn, center=false)
A polygon rectangle with vertex rounding.
Definition: polygon.scad:773
module intersection_cs(c=true, s)
Conditionally apply the difference intersection operation.
Definition: base_cs.scad:294