omdl  v0.9.6
OpenSCAD Mechanical Design Library
catch_latch.scad
Go to the documentation of this file.
1 //! A catch latch generator.
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 (Catch latch)
31  \amu_define group_brief (Catch latch generator.)
32 
33  \amu_include (include/amu/pgid_path_pstem_pg.amu)
34 *******************************************************************************/
35 
36 //----------------------------------------------------------------------------//
37 // group and macros.
38 //----------------------------------------------------------------------------//
39 
40 /***************************************************************************//**
41  \amu_include (include/amu/group_in_parent_start.amu)
42  \amu_define includes_required_add
43  (
44  models/3d/fastener/screws.scad
45  )
46  \amu_include (include/amu/includes_required.amu)
47 *******************************************************************************/
48 
49 //----------------------------------------------------------------------------//
50 
51 //! A catch latch generator.
52 /***************************************************************************//**
53  \param size <decimal-list-6 | decimal> latch size;
54  a list [px, py, pz, bx, by, bz], the latch profile and
55  base-mount dimensions, or a single decimal px and the
56  remainder using predefined scaling of px.
57 
58  \param screw <decimal-list-5 | decimal> mount screw hole specifications;
59  a list [d, t, h, r, b], the hole-diameter, tolerance,
60  head-diameter, recess-height, bevel-height, or a single
61  decimal for the hole diameter.
62 
63  \param latch <integer-list-1 | integer> latch; the latch type;
64  {1=no mount, 2=vertical mount, 3=horizontal mount}.
65 
66  \param catch <<integer, decimal, decimal> | integer> catch; a list
67  [t, h, g], the catch type, thickness, and gap, or a
68  single decimal t for the catch type; {1=no mount,
69  2=vertical mount, 3=horizontal mount}.
70 
71  \param p_bevel <decimal-list-3> profile beveling; a list [f, v, h],
72  the flat-height, bevel-height, bevel-width, specified
73  as a percentage of the latch size.
74 
75  \param p_width <decimal-list-3> profile width shaping; a list [t, c, h],
76  the width of the throat, catch, head, specified as a
77  percentage of the latch size.
78 
79  \param p_height <decimal-list-3> profile height shaping; a list [t, s, e],
80  the height of the throat-end, catch-start, catch-end,
81  specified as a percentage of the latch size.
82 
83  \param align <integer-list-3> object alignment; a list [x, y, z], the
84  latch or catch alignment. Available alignment options
85  depends on the object and its mount-type.
86 
87  \param verb <integer> console output verbosity {0=quiet, 1=info}.
88 
89  \details
90 
91  Construct a catch and latch.
92 
93  \amu_define scope_id (example)
94  \amu_define title (Catch latch example)
95  \amu_define image_views (top bottom diag)
96  \amu_define image_size (sxga)
97 
98  \amu_include (include/amu/scope_diagrams_3d.amu)
99 *******************************************************************************/
100 
101 module catch_latch
102 (
103  size = 5,
104 
105  screw,
106 
107  latch,
108  catch,
109 
110  p_bevel,
111  p_width,
112  p_height,
113 
114  align,
115  verb = 0
116 )
117 {
118  // construct latch
119  module construct_latch()
120  {
121  extrude_linear_mss( h=bevel_mss_h )
122  polygon(latch_p);
123  }
124 
125  // construct catch
126  module construct_catch()
127  {
128  extrude_linear_mss( h=bevel_mss_h )
129  difference()
130  {
131  offset(r=catch_g+catch_h) polygon(latch_p);
132  offset(r=catch_g) polygon(catch_p);
133 
134  // open mouth
135  throat_w = hprofile_p[1].x*2;
136 
137  translate([0, -catch_h/2])
138  square([ throat_w + catch_g*2 + catch_h*2, catch_h + catch_g*2], center = true);
139  }
140  }
141 
142  // construct mount
143  module construct_mount(n, t)
144  {
145  difference()
146  {
147  union()
148  {
149  // mount
150  rotate([0, 90, 0])
151  extrude_linear_mss( h=mnt_dx, center=true )
152  pg_rectangle(size=[size_my, size_mz], vr=pad_vr, center=true);
153 
154  // pad
155  for( p=[-1, 1] )
156  translate([p*mnt_dx/2, pad_dy/2 - size_mz/2, 0])
157  extrude_linear_mss( h=size_my, center=true )
158  pg_rectangle(size=[pad_dx, pad_dy], vr=mnt_vr, center=true);
159  }
160 
161  // screw holes on both sizes of mount
162  for( s=[-1, 1] )
163  translate([s*mnt_dx/2, pad_dy/2 - size_mz/2, 0])
164  screw_bore(d=screw_d, l=size_my+eps*8, h=[screw_h, screw_r, screw_b], t=[screw_t]);
165  }
166 
167  if (verb > 0)
168  {
169  echo(strl
170  ([ n, " mount, type ", t, ": screw hole diameter = ",
171  screw_d, ", offset = ", mnt_dx
172  ]));
173  }
174  }
175 
176  // assemble
177  module assemble()
178  {
179  //
180  // latch
181  //
182 
183  if ( is_defined( latch ) )
184  {
185  if ( latch_t == 1 )
186  {
187  construct_latch();
188  }
189 
190  if ( latch_t == 2 )
191  {
192  construct_latch();
193 
194  translate([0, -size_my/2, size_mz/2])
195  mirror([0, 1, 0])
196  rotate([90, 0, 0])
197  construct_mount("latch", latch_t);
198 
199  // connect latch to mount
200  translate([0, -size_my/4+eps*2, size_mz/2])
201  extrude_linear_mss( h=size_mz, center=true )
202  pg_rectangle(size=[width_t*2, size_my/2], vr=2, vrm=[0, 0, 4, 3], center=true);
203  }
204 
205  if ( latch_t == 3 )
206  {
207  construct_latch();
208 
209  translate([0, -size_mz/2, size_my/2])
210  mirror([0, 0, 1])
211  rotate([180, 0, 0])
212  construct_mount("latch", latch_t);
213 
214  // connect latch to mount
215  rotate([270, 270, 270])
217  rotate([0, 0, 90])
218  projection(cut=true)
219  rotate([90, 0, 0])
220  construct_latch();
221  }
222  }
223 
224  //
225  // catch
226  //
227 
228  if ( is_defined( catch ) )
229  {
230  if ( catch_t == 1 )
231  {
232  construct_catch();
233  }
234 
235  if ( catch_t == 2 )
236  {
237  construct_catch();
238 
239  translate([0, size_my/2 + size_py + catch_g + catch_h*0, size_mz/2])
240  rotate([90, 0, 0])
241  construct_mount("catch", catch_t);
242  }
243 
244  if ( catch_t == 3 )
245  {
246  construct_catch();
247 
248  difference()
249  {
250  translate([0, -size_mz/8 + size_py + catch_g + catch_h, size_my/2])
251  construct_mount("catch", catch_t);
252 
253  resize([size_px+catch_g*4, size_py+catch_g*4, size_pz])
254  construct_latch();
255  }
256  }
257  }
258  }
259 
260  //
261  // global parameters
262  //
263 
264  // latch/catch profile size: x, y, z
265  size_px = defined_e_or(size, 0, size);
266  size_py = defined_e_or(size, 1, size_px*5/2);
267  size_pz = defined_e_or(size, 2, size_px*5/4);
268 
269  // latch/catch mount size: x, y, z
270  size_mx = defined_e_or(size, 3, size_py*5/3);
271  size_my = defined_e_or(size, 4, size_px/2);
272  size_mz = defined_e_or(size, 5, size_pz);
273 
274  // mount screw: hole-diameter, tolerance, head-diameter, recess-height, bevel-height
275  screw_d = defined_e_or(screw, 0, defined_or(screw, size_mz/3));
276  screw_t = defined_e_or(screw, 1, 0);
277  screw_h = defined_e_or(screw, 2, 0);
278  screw_r = defined_e_or(screw, 3, 0);
279  screw_b = defined_e_or(screw, 4, 0);
280 
281  // latch: mount-type
282  latch_t = defined_e_or(latch, 0, latch);
283 
284  // catch: mount-type, thickness, gap
285  catch_t = defined_e_or(catch, 0, catch);
286  catch_h = defined_e_or(catch, 1, size_px/5);
287  catch_g = defined_e_or(catch, 2, size_px/20);
288 
289  // latch/catch edge bevel (percentages): v-flat, v-bevel, h-bevel
290  bevel_f = defined_e_or(p_bevel, 0, 0) / 100 * size_pz;
291  bevel_v = defined_e_or(p_bevel, 1, 0) / 100 * size_pz;
292  bevel_h = defined_e_or(p_bevel, 2, 0) / 100;
293 
294  // latch/catch profile width percentages): throat, catch, head
295  width_t = defined_e_or(p_width, 0, 60) / 100 * size_px/2;
296  width_c = defined_e_or(p_width, 1, 100) / 100 * size_px/2;
297  width_h = defined_e_or(p_width, 2, 10) / 100 * size_px/2;
298 
299  // latch/catch profile height (percentages): throat-end, catch-start, catch-end
300  height_t = defined_e_or(p_height, 0, 20) / 100 * size_py;
301  height_s = defined_e_or(p_height, 1, 40) / 100 * size_py;
302  height_e = defined_e_or(p_height, 2, 60) / 100 * size_py;
303 
304  //
305  // global variables
306  //
307 
308  // mount pad: separation, size-y, size-x, rounding(s)
309  mnt_dx = size_mx - size_mz;
310 
311  pad_dy = max(screw_d*3, size_mz);
312  pad_dx = pad_dy + screw_t;
313 
314  mnt_vr = pad_dy*2/5;
315  pad_vr = size_my/2;
316 
317  // half-profile polygon points, rounding, and rounding-mode
318  hprofile_p =
319  [
320  origin2d, // base
321  [width_t, 0], [width_t, height_t], // throat; start, end
322  [width_c, height_s], [width_c, height_e], // catch; start, end
323  [width_h, size_py] // head
324  ];
325 
326  hprofile_vr = [1/3, 1/2, 1, 1, 1/10] * size_px/2;
327  hprofile_vrm = [0, 1, 1, 1, 1];
328 
329  // assemble full profile polygon points, rounding, and rounding-modes
330  profile_p = concat( [for (i=hprofile_p) i], [for (i=reverse(hprofile_p)) [-i.x, i.y]] );
331  profile_vr = concat( [for (i=hprofile_vr) i], [for (i=reverse(hprofile_vr)) i] );
332  latch_vrm = concat( [for (i=hprofile_vrm) i], [for (i=reverse(hprofile_vrm)) i] );
333 
334  // flare-out catch mouth; replace first and last rounding elements of latch
335  catch_vrm = concat( headn(concat( [3], tailn(latch_vrm))), [4] );
336 
337  // rounded polygon points for latch and catch
338  latch_p = polygon_round_eve_all_p(c=profile_p, vr=profile_vr, vrm=latch_vrm);
339  catch_p = polygon_round_eve_all_p(c=profile_p, vr=profile_vr, vrm=catch_vrm);
340 
341  // mss extrusion for bevels
342  bevel_mss_h =
343  let( h1 = bevel_f, h2 = bevel_v, s = 1 - bevel_h )
344  [ [h1, [s, s]], [h2, [s, 1]], size_pz - (h1 + h2)*2, [h2, [1, s]], [h1, [s, s]] ];
345 
346  //
347  // orientation and alignment configuration
348  //
349  oaa = let
350  (
351  idl = is_defined(latch), idc = is_defined(catch),
352  tl = latch_t, tc = catch_t,
353 
354  // repeating values and configurations
355  v01 = catch_g+catch_h,
356  v02 = +size_mz/8-size_py-v01,
357 
358  c01 = [ [0,0,0], [0,0,0], [ [0],[0],[0] ] ],
359  c02 = [0, +mnt_dx/2+pad_dx/2, +mnt_dx/2, -mnt_dx/2, -mnt_dx/2-pad_dx/2],
360  c03 = [0, -size_pz/2, -size_pz, -pad_dy/2, -pad_dy],
361  c04 = [0, -size_my/2, -size_my, -size_pz/2, -size_pz]
362  )
363  !idc && idl ? // latch only
364  (
365  (tl == 1) ? [ [0, 0, 0], [0, 0, 0],
366  [ [0, -width_t, +width_t],
367  [0, -size_py/2, -size_py],
368  [0, -size_pz/2, -size_pz] ] ]
369  : (tl == 2) ? [ [0, 0, 0], [0, +size_my, 0],
370  [ c02,
371  [0, -size_my, -size_py/2-size_my, -size_py-size_my],
372  c03 ] ]
373  : (tl == 3) ? [ [0, 0, 0], [0, +pad_dy, 0],
374  [ c02,
375  [0, -pad_dy/2, -pad_dy, -size_py/2-pad_dy, -size_py-pad_dy],
376  c04 ] ]
377  : c01
378  )
379  : idc && !idl ? // catch only
380  (
381  (tc == 1) ? [ [0, 0, 180], [0, +size_py+v01, 0],
382  [ [0, +size_px/2+v01, -size_px/2-v01],
383  [0, -catch_h, -size_py/2-catch_h, -size_py-catch_h],
384  [0, -size_pz/2, -size_pz] ] ]
385  : (tc == 2) ? [ [0, 0, 180], [0, +size_py+catch_g+size_my, 0],
386  [ c02,
387  [0, -size_my, -size_py/2-size_my-catch_g, -size_py-size_my],
388  c03 ] ]
389  : (tc == 3) ? [ [0, 0, 180], [0, pad_dy/2-v02, 0],
390  [ c02,
391  [0, -pad_dy/2, -pad_dy, v02-pad_dy/2+size_py/2, v02-pad_dy/2],
392  c04 ] ]
393  : c01
394  )
395  : idc && idl ? // both latch and catch
396  (
397  [ [0, 0, 0], [0, 0, 0],
398  [ c02,
399  [ 0,
400  -size_py/2, +v02/2+pad_dy/4,
401  -size_py-catch_g, +size_my, -size_py-catch_g-size_my,
402  +pad_dy, +pad_dy/2, +v02+pad_dy/2, +v02, +v02-pad_dy/2
403  ],
404  concat(c03, [-size_my]) ]
405  ]
406  )
407  : c01; // neither
408 
409  align_x = select_ci ( third(oaa).x, defined_e_or(align, 0, 0), false );
410  align_y = select_ci ( third(oaa).y, defined_e_or(align, 1, 0), false );
411  align_z = select_ci ( third(oaa).z, defined_e_or(align, 2, 0), false );
412 
413  //
414  // object assembly
415  //
416 
417  translate(second(oaa) + [align_x, align_y, align_z])
418  rotate(first(oaa))
419  assemble();
420 }
421 
422 //! @}
423 //! @}
424 
425 
426 //----------------------------------------------------------------------------//
427 // openscad-amu auxiliary scripts
428 //----------------------------------------------------------------------------//
429 
430 /*
431 BEGIN_SCOPE example;
432  BEGIN_OPENSCAD;
433  include <omdl-base.scad>;
434  include <models/3d/fastener/screws.scad>;
435  include <parts/3d/fastener/catch_latch.scad>;
436 
437  s = 10;
438  p = [10, 25, 10];
439  c = [5, 4, 10, 2, 1] * s/10;
440 
441  catch_latch(latch=2, size=s, p_bevel=p, screw=c);
442 
443  translate([0, s*7, 0]) rotate([0, 0, 180])
444  catch_latch(catch=3, size=s, p_bevel=p, screw=c);
445 
446  // end_include
447  END_OPENSCAD;
448 
449  BEGIN_MFSCRIPT;
450  include --path "${INCLUDE_PATH}" {var_init,var_gen_png2eps}.mfs;
451  table_unset_all sizes;
452 
453  images name "sizes" types "sxga";
454  views name "views" views "top bottom diag";
455 
456  variables set_opts_combine "sizes views";
457  variables add_opts "--viewall --autocenter --view=axes";
458 
459  include --path "${INCLUDE_PATH}" scr_make_mf.mfs;
460  END_MFSCRIPT;
461 END_SCOPE;
462 */
463 
464 //----------------------------------------------------------------------------//
465 // end of file
466 //----------------------------------------------------------------------------//
467 
origin2d
<point-2d> The origin point coordinate in 2d Euclidean space.
Definition: constants.scad:407
eps
<decimal> Epsilon, small distance to deal with overlapping shapes.
Definition: constants.scad:195
grid_coarse
OpenSCAD coarse grid limit.
Definition: constants.scad:307
function headn(v, n=1)
Return a list containing all but the last n elements of an iterable value.
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 tailn(v, n=1)
Return a list containing all but the first n elements of an iterable value.
function reverse(v)
Reverse the elements of an iterable value.
function select_ci(v, i, l=true)
Select specified element from list or return a default.
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 is_defined(v)
Test if a value is 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 screw_bore(d=1, l=1, h, n, t, s, f=1, a=0)
Flat and beveled-head screw bore with nut, nut slot, and bore tolerance.
Definition: screws.scad:359
module catch_latch(size=5, screw, latch, catch, p_bevel, p_width, p_height, align, verb=0)
A catch latch generator.
module pg_rectangle(size=1, o, vr, vrm=1, vfn, center=false)
A polygon rectangle with vertex rounding.
Definition: polygon.scad:765
module extrude_rotate_tr(r, pa=0, ra=360)
Translate, rotate, and revolve a 2d shape about the z-axis.
Definition: extrude.scad:457
module extrude_linear_mss(h, center=false, c=true)
Linearly extrude a 2d shape with multi-segment uniformly-spaced profile scaling.
Definition: extrude.scad:748