@code3d/screws 0.0.1-alpha.4 → 0.0.1-alpha.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +228 -40
- package/bld/chunks/chunk-2DGVQRQ5.js +78 -0
- package/bld/chunks/chunk-2DGVQRQ5.js.map +7 -0
- package/bld/chunks/chunk-4FMUSJBB.js +27 -0
- package/bld/chunks/chunk-4FMUSJBB.js.map +7 -0
- package/bld/chunks/chunk-7UGU5EFV.js +87 -0
- package/bld/chunks/chunk-7UGU5EFV.js.map +7 -0
- package/bld/chunks/chunk-DKS4VANI.js +27 -0
- package/bld/chunks/chunk-DKS4VANI.js.map +7 -0
- package/bld/chunks/chunk-ES62SR3Q.js +21 -0
- package/bld/chunks/chunk-ES62SR3Q.js.map +7 -0
- package/bld/chunks/chunk-ESLSQKZW.js +25 -0
- package/bld/chunks/chunk-ESLSQKZW.js.map +7 -0
- package/bld/chunks/chunk-GAX6375G.js +25 -0
- package/bld/chunks/chunk-GAX6375G.js.map +7 -0
- package/bld/chunks/chunk-GIIOR3XJ.js +49 -0
- package/bld/chunks/chunk-GIIOR3XJ.js.map +7 -0
- package/bld/chunks/chunk-HPPYZYCK.js +23 -0
- package/bld/chunks/chunk-HPPYZYCK.js.map +7 -0
- package/bld/chunks/chunk-IXFHRZSY.js +121 -0
- package/bld/chunks/chunk-IXFHRZSY.js.map +7 -0
- package/bld/chunks/chunk-MEIKYZ23.js +84 -0
- package/bld/chunks/chunk-MEIKYZ23.js.map +7 -0
- package/bld/chunks/chunk-O34BMYJV.js +84 -0
- package/bld/chunks/chunk-O34BMYJV.js.map +7 -0
- package/bld/chunks/chunk-P3M5KQ5U.js +46 -0
- package/bld/chunks/chunk-P3M5KQ5U.js.map +7 -0
- package/bld/chunks/chunk-PFFNLWWR.js +25 -0
- package/bld/chunks/chunk-PFFNLWWR.js.map +7 -0
- package/bld/chunks/chunk-SDUJLXOE.js +46 -0
- package/bld/chunks/chunk-SDUJLXOE.js.map +7 -0
- package/bld/chunks/chunk-SDYJF2XK.js +25 -0
- package/bld/chunks/chunk-SDYJF2XK.js.map +7 -0
- package/bld/chunks/chunk-SGDNOA44.js +92 -0
- package/bld/chunks/chunk-SGDNOA44.js.map +7 -0
- package/bld/chunks/chunk-SPFHOFBC.js +125 -0
- package/bld/chunks/chunk-SPFHOFBC.js.map +7 -0
- package/bld/chunks/chunk-VVX3WOBG.js +160 -0
- package/bld/chunks/chunk-VVX3WOBG.js.map +7 -0
- package/bld/chunks/chunk-W62ASGIP.js +25 -0
- package/bld/chunks/chunk-W62ASGIP.js.map +7 -0
- package/bld/chunks/chunk-Z5LEGL77.js +464 -0
- package/bld/chunks/chunk-Z5LEGL77.js.map +7 -0
- package/bld/chunks/chunk-ZNWKI54A.js +25 -0
- package/bld/chunks/chunk-ZNWKI54A.js.map +7 -0
- package/bld/library/common.d.ts +104 -0
- package/bld/library/common.d.ts.map +1 -0
- package/bld/library/gb-2672.d.ts +8 -0
- package/bld/library/gb-2672.d.ts.map +1 -0
- package/bld/library/gb-2672.js +17 -0
- package/bld/library/gb-2672.js.map +7 -0
- package/bld/library/gb-5281.d.ts +8 -0
- package/bld/library/gb-5281.d.ts.map +1 -0
- package/bld/library/gb-5281.js +15 -0
- package/bld/library/gb-5281.js.map +7 -0
- package/bld/library/gb-5782.d.ts +8 -0
- package/bld/library/gb-5782.d.ts.map +1 -0
- package/bld/library/gb-5782.js +19 -0
- package/bld/library/gb-5782.js.map +7 -0
- package/bld/library/gb-5783.d.ts +8 -0
- package/bld/library/gb-5783.d.ts.map +1 -0
- package/bld/library/gb-5783.js +19 -0
- package/bld/library/gb-5783.js.map +7 -0
- package/bld/library/gb-70-1.d.ts +8 -0
- package/bld/library/gb-70-1.d.ts.map +1 -0
- package/bld/library/gb-70-1.js +17 -0
- package/bld/library/gb-70-1.js.map +7 -0
- package/bld/library/gb-70-2.d.ts +8 -0
- package/bld/library/gb-70-2.d.ts.map +1 -0
- package/bld/library/gb-70-2.js +17 -0
- package/bld/library/gb-70-2.js.map +7 -0
- package/bld/library/gb-70-3.d.ts +8 -0
- package/bld/library/gb-70-3.d.ts.map +1 -0
- package/bld/library/gb-70-3.js +17 -0
- package/bld/library/gb-70-3.js.map +7 -0
- package/bld/library/gb-70-4.d.ts +8 -0
- package/bld/library/gb-70-4.d.ts.map +1 -0
- package/bld/library/gb-70-4.js +17 -0
- package/bld/library/gb-70-4.js.map +7 -0
- package/bld/library/gb-80.d.ts +8 -0
- package/bld/library/gb-80.d.ts.map +1 -0
- package/bld/library/gb-80.js +13 -0
- package/bld/library/gb-80.js.map +7 -0
- package/bld/library/gb-818.d.ts +8 -0
- package/bld/library/gb-818.d.ts.map +1 -0
- package/bld/library/gb-818.js +17 -0
- package/bld/library/gb-818.js.map +7 -0
- package/bld/library/hex-head.d.ts +18 -0
- package/bld/library/hex-head.d.ts.map +1 -0
- package/bld/library/index.d.ts +19 -0
- package/bld/library/index.d.ts.map +1 -1
- package/bld/library/index.js +80 -455
- package/bld/library/index.js.map +3 -3
- package/bld/library/iso-10642.d.ts +51 -0
- package/bld/library/iso-10642.d.ts.map +1 -0
- package/bld/library/iso-10642.js +16 -0
- package/bld/library/iso-10642.js.map +7 -0
- package/bld/library/iso-14583.d.ts +35 -0
- package/bld/library/iso-14583.d.ts.map +1 -0
- package/bld/library/iso-14583.js +16 -0
- package/bld/library/iso-14583.js.map +7 -0
- package/bld/library/iso-4014.d.ts +20 -0
- package/bld/library/iso-4014.d.ts.map +1 -0
- package/bld/library/iso-4014.js +18 -0
- package/bld/library/iso-4014.js.map +7 -0
- package/bld/library/iso-4017.d.ts +20 -0
- package/bld/library/iso-4017.d.ts.map +1 -0
- package/bld/library/iso-4017.js +18 -0
- package/bld/library/iso-4017.js.map +7 -0
- package/bld/library/iso-4029.d.ts +32 -0
- package/bld/library/iso-4029.d.ts.map +1 -0
- package/bld/library/iso-4029.js +12 -0
- package/bld/library/iso-4029.js.map +7 -0
- package/bld/library/iso-4762.d.ts +10 -152
- package/bld/library/iso-4762.d.ts.map +1 -1
- package/bld/library/iso-4762.js +16 -0
- package/bld/library/iso-4762.js.map +7 -0
- package/bld/library/iso-7045.d.ts +33 -0
- package/bld/library/iso-7045.d.ts.map +1 -0
- package/bld/library/iso-7045.js +16 -0
- package/bld/library/iso-7045.js.map +7 -0
- package/bld/library/iso-7379.d.ts +56 -0
- package/bld/library/iso-7379.d.ts.map +1 -0
- package/bld/library/iso-7379.js +14 -0
- package/bld/library/iso-7379.js.map +7 -0
- package/bld/library/iso-7380-1.d.ts +31 -0
- package/bld/library/iso-7380-1.d.ts.map +1 -0
- package/bld/library/iso-7380-1.js +16 -0
- package/bld/library/iso-7380-1.js.map +7 -0
- package/bld/library/iso-7380-2.d.ts +33 -0
- package/bld/library/iso-7380-2.d.ts.map +1 -0
- package/bld/library/iso-7380-2.js +16 -0
- package/bld/library/iso-7380-2.js.map +7 -0
- package/package.json +82 -2
- package/src/library/common.ts +367 -0
- package/src/library/gb-2672.ts +7 -0
- package/src/library/gb-5281.ts +7 -0
- package/src/library/gb-5782.ts +7 -0
- package/src/library/gb-5783.ts +7 -0
- package/src/library/gb-70-1.ts +7 -0
- package/src/library/gb-70-2.ts +7 -0
- package/src/library/gb-70-3.ts +7 -0
- package/src/library/gb-70-4.ts +7 -0
- package/src/library/gb-80.ts +7 -0
- package/src/library/gb-818.ts +7 -0
- package/src/library/hex-head.ts +53 -0
- package/src/library/index.ts +20 -0
- package/src/library/iso-10642.ts +173 -0
- package/src/library/iso-14583.ts +181 -0
- package/src/library/iso-4014.ts +64 -0
- package/src/library/iso-4017.ts +62 -0
- package/src/library/iso-4029.ts +101 -0
- package/src/library/iso-4762.ts +70 -300
- package/src/library/iso-7045.ts +134 -0
- package/src/library/iso-7379.ts +230 -0
- package/src/library/iso-7380-1.ts +110 -0
- package/src/library/iso-7380-2.ts +135 -0
- package/src/library/thread.ts +7 -1
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GB/T 818-2016 (MOD ISO 7045:2011).
|
|
3
|
+
* Shares the corresponding ISO module's nominal geometry within our preset
|
|
4
|
+
* range. See the package README for sizes, hole allowances and modeling limits.
|
|
5
|
+
* https://std.samr.gov.cn/gb/search/gbDetailed?id=71F772D813A1D3A7E05397BE0A0AB82A
|
|
6
|
+
*/
|
|
7
|
+
export * from './iso-7045.js';
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import {frustum, intersect, regularPrism} from '@code3d/core';
|
|
2
|
+
import {
|
|
3
|
+
metric,
|
|
4
|
+
validateHead,
|
|
5
|
+
positive,
|
|
6
|
+
type HeadSpecification,
|
|
7
|
+
type MetricSize,
|
|
8
|
+
} from './common.js';
|
|
9
|
+
|
|
10
|
+
export type Specification = HeadSpecification & Readonly<{headWidth: number}>;
|
|
11
|
+
|
|
12
|
+
// Shared head dimensions of ISO 4014 and ISO 4017. ISO widths, not DIN 931/933.
|
|
13
|
+
// https://www.vipafasteners.com/files/0/801-PARTIAL_THREAD_HEXAGON_HEAD_SCREWS_ISO_4014_UNI_5737_DIN_931.pdf
|
|
14
|
+
function specification(
|
|
15
|
+
size: MetricSize,
|
|
16
|
+
headWidth: number,
|
|
17
|
+
headHeight: number,
|
|
18
|
+
underHeadRadius: number,
|
|
19
|
+
): Specification {
|
|
20
|
+
return {
|
|
21
|
+
...metric(size),
|
|
22
|
+
headWidth,
|
|
23
|
+
headHeight,
|
|
24
|
+
underHeadRadius,
|
|
25
|
+
headDiameter: (2 * headWidth) / Math.sqrt(3),
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const specifications = {
|
|
30
|
+
M3: specification('M3', 5.5, 2, 0.1),
|
|
31
|
+
M4: specification('M4', 7, 2.8, 0.2),
|
|
32
|
+
M5: specification('M5', 8, 3.5, 0.2),
|
|
33
|
+
M6: specification('M6', 10, 4, 0.25),
|
|
34
|
+
M8: specification('M8', 13, 5.3, 0.4),
|
|
35
|
+
M10: specification('M10', 16, 6.4, 0.4),
|
|
36
|
+
M12: specification('M12', 18, 7.5, 0.6),
|
|
37
|
+
} as const;
|
|
38
|
+
|
|
39
|
+
export function hexHead(spec: Specification) {
|
|
40
|
+
validateHead(spec);
|
|
41
|
+
positive('Head width', spec.headWidth);
|
|
42
|
+
if (Math.abs(spec.headDiameter - (2 * spec.headWidth) / Math.sqrt(3)) > 1e-6)
|
|
43
|
+
throw new Error('Hex head diameter must describe its corner envelope.');
|
|
44
|
+
const radius = spec.headWidth / Math.sqrt(3);
|
|
45
|
+
const blank = regularPrism(radius, spec.headHeight, 6, 30);
|
|
46
|
+
// The cone produces the circular crown and six curved chamfer boundaries.
|
|
47
|
+
const chamferEnvelope = frustum(
|
|
48
|
+
spec.headWidth / 2 + spec.headHeight * Math.sqrt(3),
|
|
49
|
+
spec.headWidth / 2,
|
|
50
|
+
spec.headHeight,
|
|
51
|
+
);
|
|
52
|
+
return intersect([blank, chamferEnvelope]);
|
|
53
|
+
}
|
package/src/library/index.ts
CHANGED
|
@@ -1 +1,21 @@
|
|
|
1
1
|
export * as ISO4762 from './iso-4762.js';
|
|
2
|
+
export * as ISO10642 from './iso-10642.js';
|
|
3
|
+
export * as ISO7380_1 from './iso-7380-1.js';
|
|
4
|
+
export * as ISO4017 from './iso-4017.js';
|
|
5
|
+
export * as ISO4014 from './iso-4014.js';
|
|
6
|
+
export * as ISO7380_2 from './iso-7380-2.js';
|
|
7
|
+
export * as ISO4029 from './iso-4029.js';
|
|
8
|
+
export * as ISO7045 from './iso-7045.js';
|
|
9
|
+
export * as ISO14583 from './iso-14583.js';
|
|
10
|
+
export * as ISO7379 from './iso-7379.js';
|
|
11
|
+
|
|
12
|
+
export * as GB70_1 from './gb-70-1.js';
|
|
13
|
+
export * as GB70_2 from './gb-70-2.js';
|
|
14
|
+
export * as GB70_3 from './gb-70-3.js';
|
|
15
|
+
export * as GB70_4 from './gb-70-4.js';
|
|
16
|
+
export * as GB5782 from './gb-5782.js';
|
|
17
|
+
export * as GB5783 from './gb-5783.js';
|
|
18
|
+
export * as GB818 from './gb-818.js';
|
|
19
|
+
export * as GB2672 from './gb-2672.js';
|
|
20
|
+
export * as GB80 from './gb-80.js';
|
|
21
|
+
export * as GB5281 from './gb-5281.js';
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import {frustum, union, type SolidModel} from '@code3d/core';
|
|
2
|
+
import {
|
|
3
|
+
metric,
|
|
4
|
+
validateHead,
|
|
5
|
+
headedScrew,
|
|
6
|
+
hexSocket,
|
|
7
|
+
plainHole,
|
|
8
|
+
atY,
|
|
9
|
+
positive,
|
|
10
|
+
type MetricSize,
|
|
11
|
+
type HeadSpecification,
|
|
12
|
+
type Screw,
|
|
13
|
+
type ClearanceHole,
|
|
14
|
+
type HoleElements,
|
|
15
|
+
type ClearanceHoleOptions as CommonHoleOptions,
|
|
16
|
+
} from './common.js';
|
|
17
|
+
export type {
|
|
18
|
+
ClearanceFit,
|
|
19
|
+
Screw,
|
|
20
|
+
ScrewElements,
|
|
21
|
+
ClearanceHole,
|
|
22
|
+
HoleElements,
|
|
23
|
+
} from './common.js';
|
|
24
|
+
import type {Bound} from '@code3d/core';
|
|
25
|
+
|
|
26
|
+
export type Specification = HeadSpecification &
|
|
27
|
+
Readonly<{hexSocketWidth: number; hexSocketDepth: number; headAngle: 90}>;
|
|
28
|
+
// ISO 10642 dimensions (not the smaller DIN 7991 head), millimetres.
|
|
29
|
+
// https://www.vipafasteners.com/files/0/886-HEXAGON_SOCKET_COUNTERSUNK_HEAD_SCREWS_ISO_10642_UNI_5933_DIN_7991.pdf
|
|
30
|
+
function specification(
|
|
31
|
+
size: MetricSize,
|
|
32
|
+
headDiameter: number,
|
|
33
|
+
headHeight: number,
|
|
34
|
+
hexSocketWidth: number,
|
|
35
|
+
hexSocketDepth: number,
|
|
36
|
+
underHeadRadius: number,
|
|
37
|
+
): Specification {
|
|
38
|
+
return {
|
|
39
|
+
...metric(size),
|
|
40
|
+
headDiameter,
|
|
41
|
+
headHeight,
|
|
42
|
+
hexSocketWidth,
|
|
43
|
+
hexSocketDepth,
|
|
44
|
+
underHeadRadius,
|
|
45
|
+
headAngle: 90,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
export const specifications = {
|
|
49
|
+
M3: specification('M3', 6.72, 1.86, 2, 1.1, 0.1),
|
|
50
|
+
M4: specification('M4', 8.96, 2.48, 2.5, 1.5, 0.2),
|
|
51
|
+
M5: specification('M5', 11.2, 3.1, 3, 1.9, 0.2),
|
|
52
|
+
M6: specification('M6', 13.44, 3.72, 4, 2.2, 0.25),
|
|
53
|
+
M8: specification('M8', 17.92, 4.96, 5, 3, 0.4),
|
|
54
|
+
M10: specification('M10', 22.4, 6.2, 6, 3.6, 0.4),
|
|
55
|
+
M12: specification('M12', 26.88, 7.44, 8, 4.3, 0.6),
|
|
56
|
+
} as const;
|
|
57
|
+
export type Size = keyof typeof specifications;
|
|
58
|
+
export type ScrewInput = Size | Specification;
|
|
59
|
+
export type CountersinkOptions = Readonly<{diameter?: number}>;
|
|
60
|
+
export type ClearanceHoleOptions = Omit<CommonHoleOptions, 'counterbore'> &
|
|
61
|
+
Readonly<{countersink?: boolean | CountersinkOptions}>;
|
|
62
|
+
export type PlainHoleOptions = ClearanceHoleOptions &
|
|
63
|
+
Readonly<{countersink: false}>;
|
|
64
|
+
export type CountersunkHoleOptions = ClearanceHoleOptions &
|
|
65
|
+
Readonly<{countersink?: true | CountersinkOptions}>;
|
|
66
|
+
export type CountersunkHoleElements = HoleElements &
|
|
67
|
+
Readonly<{countersinkTop: Bound; countersinkBottom: Bound}>;
|
|
68
|
+
export type CountersunkHole = SolidModel<CountersunkHoleElements>;
|
|
69
|
+
|
|
70
|
+
export function resolveSpecification(input: ScrewInput): Specification {
|
|
71
|
+
return typeof input === 'string' ? specifications[input] : input;
|
|
72
|
+
}
|
|
73
|
+
function validateCountersink(spec: Specification): void {
|
|
74
|
+
if (
|
|
75
|
+
spec.headAngle !== 90 ||
|
|
76
|
+
Math.abs(spec.headDiameter - spec.nominalDiameter - 2 * spec.headHeight) >
|
|
77
|
+
1e-6
|
|
78
|
+
)
|
|
79
|
+
throw new Error(
|
|
80
|
+
'Countersunk head dimensions must define a 90-degree cone.',
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
export function threadLength(spec: Specification, length: number): number {
|
|
84
|
+
return (
|
|
85
|
+
2 * spec.nominalDiameter + (length <= 125 ? 6 : length <= 200 ? 12 : 25)
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Length includes the countersunk head.
|
|
90
|
+
* @code3d.arguments ['M6', 20]
|
|
91
|
+
* @code3d.param length {kind: 'length'}
|
|
92
|
+
*/
|
|
93
|
+
export function screw(input: ScrewInput, length: number): Screw {
|
|
94
|
+
const spec = resolveSpecification(input);
|
|
95
|
+
validateHead(spec);
|
|
96
|
+
validateCountersink(spec);
|
|
97
|
+
const blank = frustum(
|
|
98
|
+
spec.nominalDiameter / 2,
|
|
99
|
+
spec.headDiameter / 2,
|
|
100
|
+
spec.headHeight,
|
|
101
|
+
);
|
|
102
|
+
const head = hexSocket(
|
|
103
|
+
blank,
|
|
104
|
+
spec.hexSocketWidth,
|
|
105
|
+
spec.hexSocketDepth,
|
|
106
|
+
spec.headHeight,
|
|
107
|
+
);
|
|
108
|
+
return headedScrew(
|
|
109
|
+
head,
|
|
110
|
+
spec,
|
|
111
|
+
length - spec.headHeight,
|
|
112
|
+
threadLength(spec, length),
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/** @code3d.arguments ['M6', 10] */
|
|
117
|
+
export function clearanceHole(
|
|
118
|
+
input: ScrewInput,
|
|
119
|
+
depth: number,
|
|
120
|
+
): CountersunkHole;
|
|
121
|
+
export function clearanceHole(
|
|
122
|
+
input: ScrewInput,
|
|
123
|
+
options: PlainHoleOptions,
|
|
124
|
+
): ClearanceHole;
|
|
125
|
+
export function clearanceHole(
|
|
126
|
+
input: ScrewInput,
|
|
127
|
+
options: CountersunkHoleOptions,
|
|
128
|
+
): CountersunkHole;
|
|
129
|
+
export function clearanceHole(
|
|
130
|
+
input: ScrewInput,
|
|
131
|
+
options: ClearanceHoleOptions,
|
|
132
|
+
): ClearanceHole | CountersunkHole;
|
|
133
|
+
export function clearanceHole(
|
|
134
|
+
input: ScrewInput,
|
|
135
|
+
optionsOrDepth: number | ClearanceHoleOptions,
|
|
136
|
+
): ClearanceHole | CountersunkHole {
|
|
137
|
+
const spec = resolveSpecification(input);
|
|
138
|
+
const options =
|
|
139
|
+
typeof optionsOrDepth === 'number'
|
|
140
|
+
? {depth: optionsOrDepth}
|
|
141
|
+
: optionsOrDepth;
|
|
142
|
+
validateCountersink(spec);
|
|
143
|
+
const shaft = plainHole(spec, options);
|
|
144
|
+
if (options.countersink === false) return shaft;
|
|
145
|
+
const sink =
|
|
146
|
+
options.countersink === true || options.countersink === undefined
|
|
147
|
+
? {}
|
|
148
|
+
: options.countersink;
|
|
149
|
+
const diameter = sink.diameter ?? spec.headDiameter + 0.5;
|
|
150
|
+
const shaftDiameter =
|
|
151
|
+
options.diameter ?? spec.clearance[options.fit ?? 'normal'];
|
|
152
|
+
positive('Countersink diameter', diameter);
|
|
153
|
+
if (diameter < spec.headDiameter || diameter <= shaftDiameter)
|
|
154
|
+
throw new Error(
|
|
155
|
+
'Countersink must accommodate the screw head and exceed the shaft diameter.',
|
|
156
|
+
);
|
|
157
|
+
const depth =
|
|
158
|
+
(diameter - shaftDiameter) /
|
|
159
|
+
(2 * Math.tan((spec.headAngle * Math.PI) / 360));
|
|
160
|
+
if (!Number.isFinite(depth) || depth <= 0 || depth > options.depth)
|
|
161
|
+
throw new Error('Countersink depth must be within the total hole depth.');
|
|
162
|
+
const recess = atY(
|
|
163
|
+
frustum(shaftDiameter / 2, diameter / 2, depth),
|
|
164
|
+
(options.depth - depth) / 2,
|
|
165
|
+
);
|
|
166
|
+
return union([shaft, recess]).expose({
|
|
167
|
+
shaftTop: shaft.shaftTop,
|
|
168
|
+
shaftBottom: shaft.shaftBottom,
|
|
169
|
+
shaftAxis: shaft.shaftAxis,
|
|
170
|
+
countersinkTop: recess.up,
|
|
171
|
+
countersinkBottom: recess.down,
|
|
172
|
+
});
|
|
173
|
+
}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import {cut} from '@code3d/core';
|
|
2
|
+
import {
|
|
3
|
+
definePrimitive,
|
|
4
|
+
replicad,
|
|
5
|
+
type Point2D,
|
|
6
|
+
type Sketch,
|
|
7
|
+
} from '@code3d/core/replicad';
|
|
8
|
+
import {
|
|
9
|
+
metric,
|
|
10
|
+
validateHead,
|
|
11
|
+
headedScrew,
|
|
12
|
+
panHead,
|
|
13
|
+
positive,
|
|
14
|
+
clearanceHole as buildClearanceHole,
|
|
15
|
+
type HeadSpecification,
|
|
16
|
+
type MetricSize,
|
|
17
|
+
type Screw,
|
|
18
|
+
type ClearanceHole,
|
|
19
|
+
type CounterboredHole,
|
|
20
|
+
type ClearanceHoleOptions,
|
|
21
|
+
type PlainHoleOptions,
|
|
22
|
+
type CounterboredHoleOptions,
|
|
23
|
+
} from './common.js';
|
|
24
|
+
export type {
|
|
25
|
+
ClearanceFit,
|
|
26
|
+
Screw,
|
|
27
|
+
ScrewElements,
|
|
28
|
+
ClearanceHole,
|
|
29
|
+
HoleElements,
|
|
30
|
+
CounterboredHole,
|
|
31
|
+
CounterboredHoleElements,
|
|
32
|
+
ClearanceHoleOptions,
|
|
33
|
+
PlainHoleOptions,
|
|
34
|
+
CounterboredHoleOptions,
|
|
35
|
+
CounterboreOptions,
|
|
36
|
+
} from './common.js';
|
|
37
|
+
|
|
38
|
+
export type HexalobularRecess = Readonly<{
|
|
39
|
+
number: number;
|
|
40
|
+
diameter: number;
|
|
41
|
+
innerDiameter: number;
|
|
42
|
+
depth: number;
|
|
43
|
+
}>;
|
|
44
|
+
export type Specification = HeadSpecification &
|
|
45
|
+
Readonly<{headCurvatureRadius: number; recess: HexalobularRecess}>;
|
|
46
|
+
// ISO 14583:2011 head dimensions and minimum recess penetration.
|
|
47
|
+
// https://www.finesz.com/ISO14583.php
|
|
48
|
+
// ISO 10664:2014 nominal driving envelopes A/B (size 45 A = 7.93).
|
|
49
|
+
function specification(
|
|
50
|
+
size: MetricSize,
|
|
51
|
+
headDiameter: number,
|
|
52
|
+
headHeight: number,
|
|
53
|
+
headCurvatureRadius: number,
|
|
54
|
+
underHeadRadius: number,
|
|
55
|
+
number: number,
|
|
56
|
+
diameter: number,
|
|
57
|
+
innerDiameter: number,
|
|
58
|
+
depth: number,
|
|
59
|
+
): Specification {
|
|
60
|
+
return {
|
|
61
|
+
...metric(size),
|
|
62
|
+
headDiameter,
|
|
63
|
+
headHeight,
|
|
64
|
+
headCurvatureRadius,
|
|
65
|
+
underHeadRadius,
|
|
66
|
+
recess: {number, diameter, innerDiameter, depth},
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
export const specifications = {
|
|
70
|
+
M3: specification('M3', 5.6, 2.4, 5, 0.1, 10, 2.8, 2.05, 1.01),
|
|
71
|
+
M4: specification('M4', 8, 3.1, 6.5, 0.2, 20, 3.95, 2.85, 1.27),
|
|
72
|
+
M5: specification('M5', 9.5, 3.7, 8, 0.2, 25, 4.5, 3.25, 1.52),
|
|
73
|
+
M6: specification('M6', 12, 4.6, 10, 0.25, 30, 5.6, 4.05, 2.02),
|
|
74
|
+
M8: specification('M8', 16, 6, 13, 0.4, 45, 7.93, 5.64, 2.79),
|
|
75
|
+
M10: specification('M10', 20, 7.5, 16, 0.4, 50, 8.95, 6.45, 3.62),
|
|
76
|
+
} as const;
|
|
77
|
+
export type Size = keyof typeof specifications;
|
|
78
|
+
export type ScrewInput = Size | Specification;
|
|
79
|
+
export function resolveSpecification(input: ScrewInput): Specification {
|
|
80
|
+
return typeof input === 'string' ? specifications[input] : input;
|
|
81
|
+
}
|
|
82
|
+
export function threadLength(spec: Specification, _length: number): number {
|
|
83
|
+
return spec.nominalDiameter <= 3 ? 25 : 38;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** Nominal representation: twelve tangent circular arcs, not an inspection gauge. */
|
|
87
|
+
const hexalobularTool = definePrimitive(
|
|
88
|
+
(diameter: number, innerDiameter: number, depth: number) => {
|
|
89
|
+
positive('Recess diameter', diameter);
|
|
90
|
+
positive('Inner recess diameter', innerDiameter);
|
|
91
|
+
positive('Recess depth', depth);
|
|
92
|
+
const a = diameter / 2,
|
|
93
|
+
b = innerDiameter / 2,
|
|
94
|
+
re = diameter * 0.1;
|
|
95
|
+
const p = a - re,
|
|
96
|
+
c = Math.cos(Math.PI / 6);
|
|
97
|
+
const ri =
|
|
98
|
+
(re ** 2 - p ** 2 - b ** 2 + 2 * p * b * c) / (2 * (b - p * c - re));
|
|
99
|
+
positive('Recess inner arc radius', ri);
|
|
100
|
+
const radial = (radius: number, angle: number): Point2D => [
|
|
101
|
+
radius * Math.cos(angle),
|
|
102
|
+
radius * Math.sin(angle),
|
|
103
|
+
];
|
|
104
|
+
const tangent = (angle: number, side: number): Point2D => {
|
|
105
|
+
const outer = radial(p, angle),
|
|
106
|
+
inner = radial(b + ri, angle + (side * Math.PI) / 6);
|
|
107
|
+
return [
|
|
108
|
+
outer[0] + (re / (re + ri)) * (inner[0] - outer[0]),
|
|
109
|
+
outer[1] + (re / (re + ri)) * (inner[1] - outer[1]),
|
|
110
|
+
];
|
|
111
|
+
};
|
|
112
|
+
const start = tangent(0, -1);
|
|
113
|
+
const drawing = replicad.draw(start);
|
|
114
|
+
for (let i = 0; i < 6; i++) {
|
|
115
|
+
const angle = (i * Math.PI) / 3;
|
|
116
|
+
drawing.threePointsArcTo(tangent(angle, 1), radial(a, angle));
|
|
117
|
+
drawing.threePointsArcTo(
|
|
118
|
+
i === 5 ? start : tangent(angle + Math.PI / 3, -1),
|
|
119
|
+
radial(b, angle + Math.PI / 6),
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
const profile = drawing.close();
|
|
123
|
+
return (profile.sketchOnPlane('XY') as Sketch)
|
|
124
|
+
.extrude(depth)
|
|
125
|
+
.rotate(-90, [0, 0, 0], [1, 0, 0])
|
|
126
|
+
.translate([0, -depth / 2, 0]);
|
|
127
|
+
},
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* @code3d.arguments ['M6', 18]
|
|
132
|
+
* @code3d.param length {kind: 'length'}
|
|
133
|
+
*/
|
|
134
|
+
export function screw(input: ScrewInput, length: number): Screw {
|
|
135
|
+
const spec = resolveSpecification(input);
|
|
136
|
+
validateHead(spec);
|
|
137
|
+
const recess = spec.recess;
|
|
138
|
+
if (
|
|
139
|
+
recess.innerDiameter >= recess.diameter ||
|
|
140
|
+
recess.diameter >= spec.headDiameter ||
|
|
141
|
+
recess.depth >= spec.headHeight
|
|
142
|
+
)
|
|
143
|
+
throw new Error('Recess must fit inside the head.');
|
|
144
|
+
const head = panHead(
|
|
145
|
+
spec.headDiameter,
|
|
146
|
+
spec.headHeight,
|
|
147
|
+
recess.diameter * 1.05,
|
|
148
|
+
spec.headCurvatureRadius,
|
|
149
|
+
);
|
|
150
|
+
const tool = hexalobularTool(
|
|
151
|
+
recess.diameter,
|
|
152
|
+
recess.innerDiameter,
|
|
153
|
+
recess.depth,
|
|
154
|
+
).relate(part => part.up.on(head.up));
|
|
155
|
+
return headedScrew(
|
|
156
|
+
cut(head, [tool]),
|
|
157
|
+
spec,
|
|
158
|
+
length,
|
|
159
|
+
threadLength(spec, length),
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
/** @code3d.arguments ['M6', 10] */
|
|
163
|
+
export function clearanceHole(input: ScrewInput, depth: number): ClearanceHole;
|
|
164
|
+
export function clearanceHole(
|
|
165
|
+
input: ScrewInput,
|
|
166
|
+
options: PlainHoleOptions,
|
|
167
|
+
): ClearanceHole;
|
|
168
|
+
export function clearanceHole(
|
|
169
|
+
input: ScrewInput,
|
|
170
|
+
options: CounterboredHoleOptions,
|
|
171
|
+
): CounterboredHole;
|
|
172
|
+
export function clearanceHole(
|
|
173
|
+
input: ScrewInput,
|
|
174
|
+
options: ClearanceHoleOptions,
|
|
175
|
+
): ClearanceHole | CounterboredHole;
|
|
176
|
+
export function clearanceHole(
|
|
177
|
+
input: ScrewInput,
|
|
178
|
+
options: number | ClearanceHoleOptions,
|
|
179
|
+
): ClearanceHole | CounterboredHole {
|
|
180
|
+
return buildClearanceHole(resolveSpecification(input), options);
|
|
181
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import {
|
|
2
|
+
headedScrew,
|
|
3
|
+
clearanceHole as buildClearanceHole,
|
|
4
|
+
type Screw,
|
|
5
|
+
type ClearanceHole,
|
|
6
|
+
type CounterboredHole,
|
|
7
|
+
type ClearanceHoleOptions,
|
|
8
|
+
type PlainHoleOptions,
|
|
9
|
+
type CounterboredHoleOptions,
|
|
10
|
+
} from './common.js';
|
|
11
|
+
import {hexHead, specifications, type Specification} from './hex-head.js';
|
|
12
|
+
export {specifications};
|
|
13
|
+
export type {Specification};
|
|
14
|
+
export type {
|
|
15
|
+
ClearanceFit,
|
|
16
|
+
Screw,
|
|
17
|
+
ScrewElements,
|
|
18
|
+
ClearanceHole,
|
|
19
|
+
HoleElements,
|
|
20
|
+
CounterboredHole,
|
|
21
|
+
CounterboredHoleElements,
|
|
22
|
+
ClearanceHoleOptions,
|
|
23
|
+
PlainHoleOptions,
|
|
24
|
+
CounterboredHoleOptions,
|
|
25
|
+
CounterboreOptions,
|
|
26
|
+
} from './common.js';
|
|
27
|
+
export type Size = keyof typeof specifications;
|
|
28
|
+
export type ScrewInput = Size | Specification;
|
|
29
|
+
export function resolveSpecification(input: ScrewInput): Specification {
|
|
30
|
+
return typeof input === 'string' ? specifications[input] : input;
|
|
31
|
+
}
|
|
32
|
+
export function threadLength(spec: Specification, length: number): number {
|
|
33
|
+
return (
|
|
34
|
+
2 * spec.nominalDiameter + (length <= 125 ? 6 : length <= 200 ? 12 : 25)
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* @code3d.arguments ['M6', 30]
|
|
39
|
+
* @code3d.param length {kind: 'length'}
|
|
40
|
+
*/
|
|
41
|
+
export function screw(input: ScrewInput, length: number): Screw {
|
|
42
|
+
const spec = resolveSpecification(input);
|
|
43
|
+
return headedScrew(hexHead(spec), spec, length, threadLength(spec, length));
|
|
44
|
+
}
|
|
45
|
+
/** @code3d.arguments ['M6', 10] */
|
|
46
|
+
export function clearanceHole(input: ScrewInput, depth: number): ClearanceHole;
|
|
47
|
+
export function clearanceHole(
|
|
48
|
+
input: ScrewInput,
|
|
49
|
+
options: PlainHoleOptions,
|
|
50
|
+
): ClearanceHole;
|
|
51
|
+
export function clearanceHole(
|
|
52
|
+
input: ScrewInput,
|
|
53
|
+
options: CounterboredHoleOptions,
|
|
54
|
+
): CounterboredHole;
|
|
55
|
+
export function clearanceHole(
|
|
56
|
+
input: ScrewInput,
|
|
57
|
+
options: ClearanceHoleOptions,
|
|
58
|
+
): ClearanceHole | CounterboredHole;
|
|
59
|
+
export function clearanceHole(
|
|
60
|
+
input: ScrewInput,
|
|
61
|
+
options: number | ClearanceHoleOptions,
|
|
62
|
+
): ClearanceHole | CounterboredHole {
|
|
63
|
+
return buildClearanceHole(resolveSpecification(input), options);
|
|
64
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import {
|
|
2
|
+
headedScrew,
|
|
3
|
+
clearanceHole as buildClearanceHole,
|
|
4
|
+
type Screw,
|
|
5
|
+
type ClearanceHole,
|
|
6
|
+
type CounterboredHole,
|
|
7
|
+
type ClearanceHoleOptions,
|
|
8
|
+
type PlainHoleOptions,
|
|
9
|
+
type CounterboredHoleOptions,
|
|
10
|
+
} from './common.js';
|
|
11
|
+
import {hexHead, specifications, type Specification} from './hex-head.js';
|
|
12
|
+
export {specifications};
|
|
13
|
+
export type {Specification};
|
|
14
|
+
export type {
|
|
15
|
+
ClearanceFit,
|
|
16
|
+
Screw,
|
|
17
|
+
ScrewElements,
|
|
18
|
+
ClearanceHole,
|
|
19
|
+
HoleElements,
|
|
20
|
+
CounterboredHole,
|
|
21
|
+
CounterboredHoleElements,
|
|
22
|
+
ClearanceHoleOptions,
|
|
23
|
+
PlainHoleOptions,
|
|
24
|
+
CounterboredHoleOptions,
|
|
25
|
+
CounterboreOptions,
|
|
26
|
+
} from './common.js';
|
|
27
|
+
export type Size = keyof typeof specifications;
|
|
28
|
+
export type ScrewInput = Size | Specification;
|
|
29
|
+
export function resolveSpecification(input: ScrewInput): Specification {
|
|
30
|
+
return typeof input === 'string' ? specifications[input] : input;
|
|
31
|
+
}
|
|
32
|
+
export function threadLength(spec: Specification, length: number): number {
|
|
33
|
+
return length;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* @code3d.arguments ['M6', 30]
|
|
37
|
+
* @code3d.param length {kind: 'length'}
|
|
38
|
+
*/
|
|
39
|
+
export function screw(input: ScrewInput, length: number): Screw {
|
|
40
|
+
const spec = resolveSpecification(input);
|
|
41
|
+
return headedScrew(hexHead(spec), spec, length, threadLength(spec, length));
|
|
42
|
+
}
|
|
43
|
+
/** @code3d.arguments ['M6', 10] */
|
|
44
|
+
export function clearanceHole(input: ScrewInput, depth: number): ClearanceHole;
|
|
45
|
+
export function clearanceHole(
|
|
46
|
+
input: ScrewInput,
|
|
47
|
+
options: PlainHoleOptions,
|
|
48
|
+
): ClearanceHole;
|
|
49
|
+
export function clearanceHole(
|
|
50
|
+
input: ScrewInput,
|
|
51
|
+
options: CounterboredHoleOptions,
|
|
52
|
+
): CounterboredHole;
|
|
53
|
+
export function clearanceHole(
|
|
54
|
+
input: ScrewInput,
|
|
55
|
+
options: ClearanceHoleOptions,
|
|
56
|
+
): ClearanceHole | CounterboredHole;
|
|
57
|
+
export function clearanceHole(
|
|
58
|
+
input: ScrewInput,
|
|
59
|
+
options: number | ClearanceHoleOptions,
|
|
60
|
+
): ClearanceHole | CounterboredHole {
|
|
61
|
+
return buildClearanceHole(resolveSpecification(input), options);
|
|
62
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import {
|
|
2
|
+
cut,
|
|
3
|
+
frustum,
|
|
4
|
+
intersect,
|
|
5
|
+
type Bound,
|
|
6
|
+
type CanonicalElements,
|
|
7
|
+
type LineAnchor,
|
|
8
|
+
type SolidModel,
|
|
9
|
+
} from '@code3d/core';
|
|
10
|
+
import {definePrimitive, replicad, type Sketch} from '@code3d/core/replicad';
|
|
11
|
+
import {
|
|
12
|
+
metric,
|
|
13
|
+
externalThread,
|
|
14
|
+
hexSocket,
|
|
15
|
+
atY,
|
|
16
|
+
positive,
|
|
17
|
+
type MetricSize,
|
|
18
|
+
type MetricSpecification,
|
|
19
|
+
} from './common.js';
|
|
20
|
+
|
|
21
|
+
export type Specification = MetricSpecification &
|
|
22
|
+
Readonly<{
|
|
23
|
+
hexSocketWidth: number;
|
|
24
|
+
hexSocketDepth: number;
|
|
25
|
+
cupDiameter: number;
|
|
26
|
+
}>;
|
|
27
|
+
// ISO 4029 cup-point set screws, nominal driving width and minimum socket depth.
|
|
28
|
+
// https://www.jcfasteners.com/wp-content/uploads/DIN-916-Grub-Screw-Cup-PT-B4A07-SS304.pdf
|
|
29
|
+
function specification(
|
|
30
|
+
size: MetricSize,
|
|
31
|
+
hexSocketWidth: number,
|
|
32
|
+
hexSocketDepth: number,
|
|
33
|
+
cupDiameter: number,
|
|
34
|
+
): Specification {
|
|
35
|
+
return {...metric(size), hexSocketWidth, hexSocketDepth, cupDiameter};
|
|
36
|
+
}
|
|
37
|
+
export const specifications = {
|
|
38
|
+
M3: specification('M3', 1.5, 1.2, 1.4),
|
|
39
|
+
M4: specification('M4', 2, 1.5, 2),
|
|
40
|
+
M5: specification('M5', 2.5, 2, 2.5),
|
|
41
|
+
M6: specification('M6', 3, 2, 3),
|
|
42
|
+
M8: specification('M8', 4, 3, 5),
|
|
43
|
+
M10: specification('M10', 5, 4, 6),
|
|
44
|
+
M12: specification('M12', 6, 4.8, 8),
|
|
45
|
+
} as const;
|
|
46
|
+
export type Size = keyof typeof specifications;
|
|
47
|
+
export type ScrewInput = Size | Specification;
|
|
48
|
+
export type ScrewElements = CanonicalElements &
|
|
49
|
+
Readonly<{driveTop: Bound; pointBottom: Bound; threadAxis: LineAnchor}>;
|
|
50
|
+
export type Screw = SolidModel<ScrewElements>;
|
|
51
|
+
export function resolveSpecification(input: ScrewInput): Specification {
|
|
52
|
+
return typeof input === 'string' ? specifications[input] : input;
|
|
53
|
+
}
|
|
54
|
+
const cupTool = definePrimitive((radius: number, depth: number) => {
|
|
55
|
+
const profile = replicad
|
|
56
|
+
.draw([0, 0])
|
|
57
|
+
.lineTo([radius, 0])
|
|
58
|
+
.lineTo([0, depth])
|
|
59
|
+
.close();
|
|
60
|
+
return (profile.sketchOnPlane('XZ') as Sketch)
|
|
61
|
+
.revolve([0, 0, 1])
|
|
62
|
+
.rotate(-90, [0, 0, 0], [1, 0, 0])
|
|
63
|
+
.translate([0, -depth / 2, 0]);
|
|
64
|
+
});
|
|
65
|
+
/**
|
|
66
|
+
* Length is the complete headless screw, including its cup point.
|
|
67
|
+
* @code3d.arguments ['M6', 10]
|
|
68
|
+
* @code3d.param length {kind: 'length'}
|
|
69
|
+
*/
|
|
70
|
+
export function screw(input: ScrewInput, length: number): Screw {
|
|
71
|
+
const spec = resolveSpecification(input);
|
|
72
|
+
positive('Screw length', length);
|
|
73
|
+
positive('Cup diameter', spec.cupDiameter);
|
|
74
|
+
if (spec.cupDiameter >= spec.nominalDiameter)
|
|
75
|
+
throw new Error('Cup diameter must be smaller than the nominal diameter.');
|
|
76
|
+
const cupRadius = spec.cupDiameter / 2;
|
|
77
|
+
const cupDepth = cupRadius / Math.sqrt(3);
|
|
78
|
+
if (length <= spec.hexSocketDepth + cupDepth + spec.pitch)
|
|
79
|
+
throw new Error(
|
|
80
|
+
'Screw length must separate the socket from the cup point.',
|
|
81
|
+
);
|
|
82
|
+
const thread = externalThread(spec, length);
|
|
83
|
+
const outerPoint = frustum(cupRadius, cupRadius + length, length);
|
|
84
|
+
const blank = intersect([thread, outerPoint]);
|
|
85
|
+
const driven = hexSocket(
|
|
86
|
+
blank,
|
|
87
|
+
spec.hexSocketWidth,
|
|
88
|
+
spec.hexSocketDepth,
|
|
89
|
+
length,
|
|
90
|
+
);
|
|
91
|
+
// A narrow annular lip remains at the end of the external point chamfer.
|
|
92
|
+
const cup = atY(
|
|
93
|
+
cupTool(cupRadius * 0.85, cupDepth),
|
|
94
|
+
-length / 2 + cupDepth / 2,
|
|
95
|
+
);
|
|
96
|
+
return cut(driven, [cup]).expose({
|
|
97
|
+
driveTop: thread.up,
|
|
98
|
+
pointBottom: thread.down,
|
|
99
|
+
threadAxis: thread.axis,
|
|
100
|
+
});
|
|
101
|
+
}
|