1//////////////////////////////////////////////////////////////////////
  2// LibFile: metric_screws.scad
  3//   Screws, Bolts, and Nuts.
  4//   To use, include the following lines at the top of your file:
  5//   ```
  6//   include <BOSL/constants.scad>
  7//   use <BOSL/metric_screws.scad>
  8//   ```
  9//////////////////////////////////////////////////////////////////////
 10
 11/*
 12BSD 2-Clause License
 13
 14Copyright (c) 2017, Revar Desmera
 15All rights reserved.
 16
 17Redistribution and use in source and binary forms, with or without
 18modification, are permitted provided that the following conditions are met:
 19
 20* Redistributions of source code must retain the above copyright notice, this
 21  list of conditions and the following disclaimer.
 22
 23* Redistributions in binary form must reproduce the above copyright notice,
 24  this list of conditions and the following disclaimer in the documentation
 25  and/or other materials provided with the distribution.
 26
 27THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 28AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 29IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 30DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 31FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 32DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 33SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 34CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 35OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 36OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 37*/
 38
 39
 40include <constants.scad>
 41use <transforms.scad>
 42use <shapes.scad>
 43use <threading.scad>
 44use <phillips_drive.scad>
 45use <torx_drive.scad>
 46use <math.scad>
 47
 48
 49// Section: Functions
 50
 51
 52// Function: get_metric_bolt_head_size()
 53// Description: Returns the diameter of a typical metric bolt's head, based on the bolt `size`.
 54function get_metric_bolt_head_size(size) = lookup(size, [
 55		[ 3.0,  5.5],
 56		[ 4.0,  7.0],
 57		[ 5.0,  8.0],
 58		[ 6.0, 10.0],
 59		[ 7.0, 11.0],
 60		[ 8.0, 13.0],
 61		[10.0, 17.0],
 62		[12.0, 19.0],
 63		[14.0, 22.0],
 64		[16.0, 24.0],
 65		[18.0, 27.0],
 66		[20.0, 30.0],
 67		[24.0, 36.0],
 68		[30.0, 46.0],
 69		[36.0, 55.0],
 70		[42.0, 65.0],
 71		[48.0, 75.0],
 72		[56.0, 85.0],
 73		[64.0, 95.0]
 74	]);
 75
 76
 77// Function: get_metric_bolt_head_height()
 78// Description: Returns the height of a typical metric bolt's head, based on the bolt `size`.
 79function get_metric_bolt_head_height(size) = lookup(size, [
 80		[ 1.6,  1.23],
 81		[ 2.0,  1.53],
 82		[ 2.5,  1.83],
 83		[ 3.0,  2.13],
 84		[ 4.0,  2.93],
 85		[ 5.0,  3.65],
 86		[ 6.0,  4.15],
 87		[ 8.0,  5.45],
 88		[10.0,  6.58],
 89		[12.0,  7.68],
 90		[14.0,  8.98],
 91		[16.0, 10.18],
 92		[20.0, 12.72],
 93		[24.0, 15.35],
 94		[30.0, 19.12],
 95		[36.0, 22.92],
 96		[42.0, 26.42],
 97		[48.0, 30.42],
 98		[56.0, 35.50],
 99		[64.0, 40.50]
100	]);
101
102
103// Function: get_metric_socket_cap_diam()
104// Description: Returns the diameter of a typical metric socket cap bolt's head, based on the bolt `size`.
105function get_metric_socket_cap_diam(size) = lookup(size, [
106		[ 1.6,  3.0],
107		[ 2.0,  3.8],
108		[ 2.5,  4.5],
109		[ 3.0,  5.5],
110		[ 4.0,  7.0],
111		[ 5.0,  8.5],
112		[ 6.0, 10.0],
113		[ 8.0, 13.0],
114		[10.0, 16.0],
115		[12.0, 18.0],
116		[14.0, 21.0],
117		[16.0, 24.0],
118		[18.0, 27.0],
119		[20.0, 30.0],
120		[22.0, 33.0],
121		[24.0, 36.0],
122		[27.0, 40.0],
123		[30.0, 45.0],
124		[33.0, 50.0],
125		[36.0, 54.0],
126		[42.0, 63.0],
127		[48.0, 72.0],
128		[56.0, 84.0],
129		[64.0, 96.0]
130	]);
131
132
133// Function: get_metric_socket_cap_height()
134// Description: Returns the height of a typical metric socket cap bolt's head, based on the bolt `size`.
135function get_metric_socket_cap_height(size) = lookup(size, [
136		[ 1.6,  1.7],
137		[ 2.0,  2.0],
138		[ 2.5,  2.5],
139		[ 3.0,  3.0],
140		[ 4.0,  4.0],
141		[ 5.0,  5.0],
142		[ 6.0,  6.0],
143		[ 8.0,  8.0],
144		[10.0, 10.0],
145		[12.0, 12.0],
146		[14.0, 14.0],
147		[16.0, 16.0],
148		[18.0, 18.0],
149		[20.0, 20.0],
150		[22.0, 22.0],
151		[24.0, 24.0],
152		[27.0, 27.0],
153		[30.0, 30.0],
154		[33.0, 33.0],
155		[36.0, 36.0],
156		[42.0, 42.0],
157		[48.0, 48.0],
158		[56.0, 56.0],
159		[64.0, 64.0]
160	]);
161
162
163// Function: get_metric_socket_cap_socket_size()
164// Description: Returns the diameter of a typical metric socket cap bolt's hex drive socket, based on the bolt `size`.
165function get_metric_socket_cap_socket_size(size) = lookup(size, [
166		[ 1.6,  1.5],
167		[ 2.0,  1.5],
168		[ 2.5,  2.0],
169		[ 3.0,  2.5],
170		[ 4.0,  3.0],
171		[ 5.0,  4.0],
172		[ 6.0,  5.0],
173		[ 8.0,  6.0],
174		[10.0,  8.0],
175		[12.0, 10.0],
176		[14.0, 12.0],
177		[16.0, 14.0],
178		[18.0, 14.0],
179		[20.0, 17.0],
180		[22.0, 17.0],
181		[24.0, 19.0],
182		[27.0, 19.0],
183		[30.0, 22.0],
184		[33.0, 24.0],
185		[36.0, 27.0],
186		[42.0, 32.0],
187		[48.0, 36.0],
188		[56.0, 41.0],
189		[64.0, 46.0]
190	]);
191
192
193// Function: get_metric_socket_cap_socket_depth()
194// Description: Returns the depth of a typical metric socket cap bolt's hex drive socket, based on the bolt `size`.
195function get_metric_socket_cap_socket_depth(size) = lookup(size, [
196		[ 1.6,  0.7],
197		[ 2.0,  1.0],
198		[ 2.5,  1.1],
199		[ 3.0,  1.3],
200		[ 4.0,  2.0],
201		[ 5.0,  2.5],
202		[ 6.0,  3.0],
203		[ 8.0,  4.0],
204		[10.0,  5.0],
205		[12.0,  6.0],
206		[14.0,  7.0],
207		[16.0,  8.0],
208		[18.0,  9.0],
209		[20.0, 10.0],
210		[22.0, 11.0],
211		[24.0, 12.0],
212		[27.0, 13.5],
213		[30.0, 15.5],
214		[33.0, 18.0],
215		[36.0, 19.0],
216		[42.0, 24.0],
217		[48.0, 28.0],
218		[56.0, 34.0],
219		[64.0, 38.0]
220	]);
221
222
223// Function: get_metric_iso_coarse_thread_pitch()
224// Description: Returns the ISO metric standard coarse threading pitch for a given bolt `size`.
225function get_metric_iso_coarse_thread_pitch(size) = lookup(size, [
226		[ 1.6, 0.35],
227		[ 2.0, 0.40],
228		[ 2.5, 0.45],
229		[ 3.0, 0.50],
230		[ 4.0, 0.70],
231		[ 5.0, 0.80],
232		[ 6.0, 1.00],
233		[ 7.0, 1.00],
234		[ 8.0, 1.25],
235		[10.0, 1.50],
236		[12.0, 1.75],
237		[14.0, 2.00],
238		[16.0, 2.00],
239		[18.0, 2.50],
240		[20.0, 2.50],
241		[22.0, 2.50],
242		[24.0, 3.00],
243		[27.0, 3.00],
244		[30.0, 3.50],
245		[33.0, 3.50],
246		[36.0, 4.00],
247		[39.0, 4.00],
248		[42.0, 4.50],
249		[45.0, 4.50],
250		[48.0, 5.00],
251		[56.0, 5.50],
252		[64.0, 6.00]
253	]);
254
255
256// Function: get_metric_iso_fine_thread_pitch()
257// Description: Returns the ISO metric standard fine threading pitch for a given bolt `size`.
258function get_metric_iso_fine_thread_pitch(size) = lookup(size, [
259		[ 1.6, 0.35],
260		[ 2.0, 0.40],
261		[ 2.5, 0.45],
262		[ 3.0, 0.50],
263		[ 4.0, 0.70],
264		[ 5.0, 0.80],
265		[ 6.0, 1.00],
266		[ 7.0, 1.00],
267		[ 8.0, 1.00],
268		[10.0, 1.25],
269		[12.0, 1.50],
270		[14.0, 1.50],
271		[16.0, 2.00],
272		[18.0, 2.50],
273		[20.0, 2.50],
274		[22.0, 2.50],
275		[24.0, 3.00],
276		[27.0, 3.00],
277		[30.0, 3.50],
278		[33.0, 3.50],
279		[36.0, 4.00],
280		[39.0, 4.00],
281		[42.0, 4.50],
282		[45.0, 4.50],
283		[48.0, 5.00],
284		[56.0, 5.50],
285		[64.0, 6.00]
286	]);
287
288
289// Function: get_metric_iso_superfine_thread_pitch()
290// Description: Returns the ISO metric standard superfine threading pitch for a given bolt `size`.
291function get_metric_iso_superfine_thread_pitch(size) = lookup(size, [
292		[ 1.6, 0.35],
293		[ 2.0, 0.40],
294		[ 2.5, 0.45],
295		[ 3.0, 0.50],
296		[ 4.0, 0.70],
297		[ 5.0, 0.80],
298		[ 6.0, 1.00],
299		[ 7.0, 1.00],
300		[ 8.0, 1.00],
301		[10.0, 1.00],
302		[12.0, 1.25],
303		[14.0, 1.50],
304		[16.0, 2.00],
305		[18.0, 2.50],
306		[20.0, 2.50],
307		[22.0, 2.50],
308		[24.0, 3.00],
309		[27.0, 3.00],
310		[30.0, 3.50],
311		[33.0, 3.50],
312		[36.0, 4.00],
313		[39.0, 4.00],
314		[42.0, 4.50],
315		[45.0, 4.50],
316		[48.0, 5.00],
317		[56.0, 5.50],
318		[64.0, 6.00]
319	]);
320
321
322// Function: get_metric_jis_thread_pitch()
323// Description: Returns the JIS metric standard threading pitch for a given bolt `size`.
324function get_metric_jis_thread_pitch(size) = lookup(size, [
325		[ 2.0, 0.40],
326		[ 2.5, 0.45],
327		[ 3.0, 0.50],
328		[ 4.0, 0.70],
329		[ 5.0, 0.80],
330		[ 6.0, 1.00],
331		[ 7.0, 1.00],
332		[ 8.0, 1.25],
333		[10.0, 1.25],
334		[12.0, 1.25],
335		[14.0, 1.50],
336		[16.0, 1.50],
337		[18.0, 1.50],
338		[20.0, 1.50]
339	]);
340
341
342// Function: get_metric_nut_size()
343// Description: Returns the typical metric nut flat-to-flat diameter for a given bolt `size`.
344function get_metric_nut_size(size) = lookup(size, [
345		[ 2.0,  4.0],
346		[ 2.5,  5.0],
347		[ 3.0,  5.5],
348		[ 4.0,  7.0],
349		[ 5.0,  8.0],
350		[ 6.0, 10.0],
351		[ 7.0, 11.0],
352		[ 8.0, 13.0],
353		[10.0, 17.0],
354		[12.0, 19.0],
355		[14.0, 22.0],
356		[16.0, 24.0],
357		[18.0, 27.0],
358		[20.0, 30.0],
359		[22.0, 32.0],
360		[24.0, 36.0],
361		[27.0, 41.0],
362		[30.0, 46.0],
363		[33.0, 50.0],
364		[36.0, 55.0],
365		[39.0, 60.0],
366		[42.0, 65.0],
367		[45.0, 70.0],
368		[48.0, 75.0],
369		[52.0, 80.0],
370		[56.0, 85.0],
371		[60.0, 90.0],
372		[64.0, 95.0],
373		[68.0, 100.0],
374		[72.0, 105.0]
375	]);
376
377
378// Function: get_metric_nut_thickness()
379// Description: Returns the typical metric nut thickness for a given bolt `size`.
380function get_metric_nut_thickness(size) = lookup(size, [
381		[ 1.6,  1.3],
382		[ 2.0,  1.6],
383		[ 2.5,  2.0],
384		[ 3.0,  2.4],
385		[ 4.0,  3.2],
386		[ 5.0,  4.0],
387		[ 6.0,  5.0],
388		[ 7.0,  5.5],
389		[ 8.0,  6.5],
390		[10.0,  8.0],
391		[12.0, 10.0],
392		[14.0, 11.0],
393		[16.0, 13.0],
394		[18.0, 15.0],
395		[20.0, 16.0],
396		[24.0, 21.5],
397		[30.0, 25.6],
398		[36.0, 31.0],
399		[42.0, 34.0],
400		[48.0, 38.0],
401		[56.0, 45.0],
402		[64.0, 51.0]
403	]);
404
405
406
407// Section: Modules
408
409
410// Module: screw()
411// Description:
412//   Makes a very simple screw model, useful for making screwholes.
413// Usage:
414//   screw(screwsize, screwlen, headsize, headlen, [countersunk], [orient], [align])
415// Arguments:
416//   screwsize = diameter of threaded part of screw.
417//   screwlen = length of threaded part of screw.
418//   headsize = diameter of the screw head.
419//   headlen = length of the screw head.
420//   countersunk = If true, center from cap's top instead of it's bottom.
421//   orient = Orientation of the screw.  Use the `ORIENT_` constants from `constants.scad`.  Default: `ORIENT_Z`.
422//   align = Alignment of the screw.  Use the `V_` constants from `constants.scad` or `"sunken"`, or `"base"`.  Default: `"base"`.
423// Examples:
424//   screw(screwsize=3,screwlen=10,headsize=6,headlen=3,countersunk=true);
425//   screw(screwsize=3,screwlen=10,headsize=6,headlen=3, align="base");
426module screw(
427	screwsize=3,
428	screwlen=10,
429	headsize=6,
430	headlen=3,
431	pitch=undef,
432	countersunk=false,
433	orient=ORIENT_Z,
434	align="base"
435) {
436	sides = max(12, segs(screwsize/2));
437	algn = countersunk? ALIGN_NEG : align;
438	alignments = [
439		["base",   [0,0,-headlen/2+screwlen/2]],
440		["sunken", [0,0,(headlen+screwlen)/2-0.01]]
441	];
442	orient_and_align([headsize, headsize, headlen+screwlen], orient, algn, alignments=alignments) {
443		down(headlen/2-screwlen/2) {
444			down(screwlen/2) {
445				if (pitch == undef) {
446					cylinder(r=screwsize/2, h=screwlen+0.05, center=true, $fn=sides);
447				} else {
448					threaded_rod(d=screwsize, l=screwlen+0.05, pitch=pitch, $fn=sides);
449				}
450			}
451			up(headlen/2) cylinder(r=headsize/2, h=headlen, center=true, $fn=sides*2);
452		}
453	}
454}
455
456
457// Module: metric_bolt()
458// Description:
459//   Makes a standard metric screw model.
460// Arguments:
461//   size = Diameter of threaded part of screw.
462//   headtype = One of `"hex"`, `"pan"`, `"button"`, `"round"`, `"countersunk"`, `"oval"`, `"socket`".  Default: `"socket"`
463//   l = Length of screw, except for the head.
464//   shank = Length of unthreaded portion of the shaft.
465//   pitch = If given, render threads of the given pitch.  If 0, then no threads.  Overrides coarse argument.
466//   details = If true model should be rendered with extra details.  (Default: false)
467//   coarse = If true, make coarse threads instead of fine threads.  Default = true
468//   flange = Radius of flange beyond the head.  Default = 0 (no flange)
469//   phillips = If given, the size of the phillips drive hole to add.  (ie: "#1", "#2", or "#3")
470//   torx = If given, the size of the torx drive hole to add.  (ie: 10, 20, 30, etc.)
471//   orient = Orientation of the bolt.  Use the `ORIENT_` constants from `constants.scad`.  Default: `ORIENT_Z`.
472//   align = Alignment of the bolt.  Use the `V_` constants from `constants.scad` or `"sunken"`, `"base"`, or `"shank"`.  Default: `"base"`.
473// Example: Bolt Head Types
474//   ydistribute(40) {
475//       xdistribute(30) {
476//           // Front Row, Left to Right
477//           metric_bolt(headtype="pan", size=10, l=15, details=true, phillips="#2");
478//           metric_bolt(headtype="button", size=10, l=15, details=true, phillips="#2");
479//           metric_bolt(headtype="round", size=10, l=15, details=true, phillips="#2");
480//       }
481//       xdistribute(30) {
482//           // Back Row, Left to Right
483//           metric_bolt(headtype="socket", size=10, l=15, details=true);
484//           metric_bolt(headtype="hex", size=10, l=15, details=true, phillips="#2");
485//           metric_bolt(headtype="countersunk", size=10, l=15, details=true, phillips="#2");
486//           metric_bolt(headtype="oval", size=10, l=15, details=true, phillips="#2");
487//       }
488//   }
489// Example: Details
490//   metric_bolt(size=10, l=15, details=true, $fn=32);
491// Example: No Details Except Threads
492//   metric_bolt(size=10, l=15);
493// Example: No Details, No Threads
494//   metric_bolt(size=10, l=15, pitch=0);
495// Example: Fine Threads
496//   metric_bolt(size=10, l=15, coarse=false);
497// Example: Flange
498//   metric_bolt(size=10, l=15, flange=5);
499// Example: Shank
500//   metric_bolt(size=10, l=25, shank=10);
501// Example: Hex Head with Phillips
502//   metric_bolt(headtype="hex", size=10, l=15, phillips="#2");
503// Example: Hex Head with Torx
504//   metric_bolt(headtype="hex", size=10, l=15, torx=50);
505module metric_bolt(
506	headtype="socket",
507	size=3,
508	l=12,
509	shank=0,
510	pitch=undef,
511	details=false,
512	coarse=true,
513	phillips=undef,
514	torx=undef,
515	flange=0,
516	orient=ORIENT_Z,
517	align="base"
518) {
519	D = headtype != "hex"?
520		get_metric_socket_cap_diam(size) :
521		get_metric_bolt_head_size(size);
522	H = headtype == "socket"?
523		get_metric_socket_cap_height(size) :
524		get_metric_bolt_head_height(size);
525	P = coarse?
526		(pitch==undef? get_metric_iso_coarse_thread_pitch(size) : pitch) :
527		(pitch==undef? get_metric_iso_fine_thread_pitch(size) : pitch);
528	tlen = l - min(l, shank);
529	sides = max(12, segs(size/2));
530	tcirc = D/cos(30);
531	bevtop = (tcirc-D)/2;
532	bevbot = P/2;
533
534	//algn = (headtype == "countersunk" || headtype == "oval")? (D-size)/2 : 0;
535	headlen = (
536		(headtype == "pan" || headtype == "round" || headtype == "button")? H*0.75 :
537		(headtype == "countersunk")? (D-size)/2 :
538		(headtype == "oval")? ((D-size)/2 + D/2/3) :
539		H
540	);
541	base = l/2 - headlen/2;
542	sunklen = (
543		(headtype == "oval")? (D-size)/2 :
544		headlen-0.001
545	);
546
547	alignments = [
548		["sunken", [0,0,base+sunklen]],
549		["base",   [0,0,base]],
550		["shank",  [0,0,base-shank]]
551	];
552
553	color("silver")
554	orient_and_align([D+flange, D+flange, headlen+l], orient, align, alignments=alignments) {
555		up(base) {
556			difference() {
557				union() {
558					// Head
559					if (headtype == "hex") {
560						difference() {
561							cylinder(d=tcirc, h=H, center=false, $fn=6);
562
563							// Bevel hex nut top
564							if (details) {
565								up(H-bevtop) {
566									difference() {
567										upcube([tcirc+1, tcirc+1, bevtop+0.5]);
568										down(0.01) cylinder(d1=tcirc, d2=tcirc-bevtop*2, h=bevtop+0.02, center=false);
569									}
570								}
571							}
572						}
573					} else if (headtype == "socket") {
574						sockw = get_metric_socket_cap_socket_size(size);
575						sockd = get_metric_socket_cap_socket_depth(size);
576						difference() {
577							cylinder(d=D, h=H, center=false);
578							up(H-sockd) cylinder(h=sockd+0.1, d=sockw/cos(30), center=false, $fn=6);
579							if (details) {
580								kcnt = 36;
581								zring(n=kcnt, r=D/2) up(H/3) upcube([PI*D/kcnt/2, PI*D/kcnt/2, H]);
582							}
583						}
584					} else if (headtype == "pan") {
585						cyl(l=H*0.75, d=D, fillet2=H*0.75/2, align=V_UP);
586					} else if (headtype == "round") {
587						top_half() zscale(H*0.75/D*2) sphere(d=D);
588					} else if (headtype == "button") {
589						up(H*0.75/3) top_half() zscale(H*0.75*2/3/D*2) sphere(d=D);
590						cylinder(d=D, h=H*0.75/3+0.01, center=false);
591					} else if (headtype == "countersunk") {
592						cylinder(h=(D-size)/2, d1=size, d2=D, center=false);
593					} else if (headtype == "oval") {
594						up((D-size)/2) top_half() zscale(0.333) sphere(d=D);
595						cylinder(h=(D-size)/2, d1=size, d2=D, center=false);
596					}
597
598					// Flange
599					if (flange>0) {
600						up(headtype == "countersunk" || headtype == "oval"? (D-size)/2 : 0) {
601							cylinder(d=D+flange, h=H/8, center=false);
602							up(H/8) cylinder(d1=D+flange, d2=D, h=H/8, center=false);
603						}
604					}
605
606					// Unthreaded Shank
607					if (tlen < l) {
608						down(l-tlen) cylinder(d=size, h=l-tlen+0.05, center=false, $fn=sides);
609					}
610
611					// Threads
612					down(l) {
613						difference() {
614							up(tlen/2+0.05) {
615								if (tlen > 0) {
616									if (P > 0) {
617										threaded_rod(d=size, l=tlen+0.05, pitch=P, $fn=sides);
618									} else {
619										cylinder(d=size, h=tlen+0.05, $fn=sides, center=true);
620									}
621								}
622							}
623
624							// Bevel bottom end of threads
625							if (details) {
626								difference() {
627									down(0.5) upcube([size+1, size+1, bevbot+0.5]);
628									cylinder(d1=size-bevbot*2, d2=size, h=bevbot+0.01, center=false);
629								}
630							}
631						}
632					}
633				}
634
635				// Phillips drive hole
636				if (headtype != "socket" && phillips != undef) {
637					down(headtype != "hex"? H/6 : 0) {
638						phillips_drive(size=phillips, shaft=D);
639					}
640				}
641
642				// Torx drive hole
643				if (headtype != "socket" && torx != undef) {
644					up(1) torx_drive(size=torx, l=H+0.1, center=false);
645				}
646			}
647		}
648	}
649}
650
651
652// Module: metric_nut()
653// Description:
654//   Makes a model of a standard nut for a standard metric screw.
655// Arguments:
656//   size = standard metric screw size in mm. (Default: 3)
657//   hole = include the hole in the nut.  (Default: true)
658//   pitch = pitch of threads in the hole.  No threads if not given.
659//   flange = radius of flange beyond the head.  Default = 0 (no flange)
660//   details = true if model should be rendered with extra details.  (Default: false)
661//   orient = Orientation of the nut.  Use the `ORIENT_` constants from `constants.scad`.  Default: `ORIENT_Z`.
662//   align = Alignment of the nut.  Use the `V_` constants from `constants.scad`.  Default: `V_UP`.
663//   center = If true, centers the nut at the origin.  If false, sits on top of XY plane.  Overrides `align` if given.
664// Example: No details, No Hole.  Useful for a mask.
665//   metric_nut(size=10, hole=false);
666// Example:  Hole, with No Threads
667//   metric_nut(size=10, hole=true);
668// Example:  Threads
669//   metric_nut(size=10, hole=true, pitch=1.5);
670// Example:  Details
671//   metric_nut(size=10, hole=true, pitch=1.5, details=true);
672// Example:  Centered
673//   metric_nut(size=10, hole=true, pitch=1.5, details=true, center=true);
674// Example:  Flange
675//   metric_nut(size=10, hole=true, pitch=1.5, flange=3, details=true);
676module metric_nut(
677	size=3,
678	hole=true,
679	pitch=undef,
680	details=false,
681	flange=0,
682	center=undef,
683	orient=ORIENT_Z,
684	align=V_UP
685) {
686	H = get_metric_nut_thickness(size);
687	D = get_metric_nut_size(size);
688	boltfn = max(12, segs(size/2));
689	nutfn = max(12, segs(D/2));
690	dcirc = D/cos(30);
691	bevtop = (dcirc - D)/2;
692
693	color("silver")
694	orient_and_align([dcirc+flange, dcirc+flange, H], orient, align, center) {
695		difference() {
696			union() {
697				difference() {
698					cylinder(d=dcirc, h=H, center=true, $fn=6);
699					if (details) {
700						up(H/2-bevtop) {
701							difference() {
702								upcube([dcirc+1, dcirc+1, bevtop+0.5]);
703								down(0.01) cylinder(d1=dcirc, d2=dcirc-bevtop*2, h=bevtop+0.02, center=false, $fn=nutfn);
704							}
705						}
706						if (flange == 0) {
707							down(H/2) {
708								difference() {
709									down(0.5) upcube([dcirc+1, dcirc+1, bevtop+0.5]);
710									down(0.01) cylinder(d1=dcirc-bevtop*2, d2=dcirc, h=bevtop+0.02, center=false, $fn=nutfn);
711								}
712							}
713						}
714					}
715				}
716				if (flange>0) {
717					down(H/2) {
718						cylinder(d=D+flange, h=H/8, center=false);
719						up(H/8) cylinder(d1=D+flange, d2=D, h=H/8, center=false);
720					}
721				}
722			}
723			if (hole == true) {
724				if (pitch == undef) {
725					cylinder(r=size/2, h=H+0.5, center=true, $fn=boltfn);
726				} else {
727					threaded_rod(d=size, l=H+0.5, pitch=pitch, $fn=boltfn);
728				}
729			}
730		}
731	}
732}
733
734
735// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap