@code3d/screws 0.0.1-alpha.4 → 0.0.1-alpha.6

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.
Files changed (158) hide show
  1. package/README.md +228 -40
  2. package/bld/chunks/chunk-2DGVQRQ5.js +78 -0
  3. package/bld/chunks/chunk-2DGVQRQ5.js.map +7 -0
  4. package/bld/chunks/chunk-4FMUSJBB.js +27 -0
  5. package/bld/chunks/chunk-4FMUSJBB.js.map +7 -0
  6. package/bld/chunks/chunk-7UGU5EFV.js +87 -0
  7. package/bld/chunks/chunk-7UGU5EFV.js.map +7 -0
  8. package/bld/chunks/chunk-DKS4VANI.js +27 -0
  9. package/bld/chunks/chunk-DKS4VANI.js.map +7 -0
  10. package/bld/chunks/chunk-ES62SR3Q.js +21 -0
  11. package/bld/chunks/chunk-ES62SR3Q.js.map +7 -0
  12. package/bld/chunks/chunk-ESLSQKZW.js +25 -0
  13. package/bld/chunks/chunk-ESLSQKZW.js.map +7 -0
  14. package/bld/chunks/chunk-GAX6375G.js +25 -0
  15. package/bld/chunks/chunk-GAX6375G.js.map +7 -0
  16. package/bld/chunks/chunk-GIIOR3XJ.js +49 -0
  17. package/bld/chunks/chunk-GIIOR3XJ.js.map +7 -0
  18. package/bld/chunks/chunk-HPPYZYCK.js +23 -0
  19. package/bld/chunks/chunk-HPPYZYCK.js.map +7 -0
  20. package/bld/chunks/chunk-IXFHRZSY.js +121 -0
  21. package/bld/chunks/chunk-IXFHRZSY.js.map +7 -0
  22. package/bld/chunks/chunk-MEIKYZ23.js +84 -0
  23. package/bld/chunks/chunk-MEIKYZ23.js.map +7 -0
  24. package/bld/chunks/chunk-O34BMYJV.js +84 -0
  25. package/bld/chunks/chunk-O34BMYJV.js.map +7 -0
  26. package/bld/chunks/chunk-P3M5KQ5U.js +46 -0
  27. package/bld/chunks/chunk-P3M5KQ5U.js.map +7 -0
  28. package/bld/chunks/chunk-PFFNLWWR.js +25 -0
  29. package/bld/chunks/chunk-PFFNLWWR.js.map +7 -0
  30. package/bld/chunks/chunk-SDUJLXOE.js +46 -0
  31. package/bld/chunks/chunk-SDUJLXOE.js.map +7 -0
  32. package/bld/chunks/chunk-SDYJF2XK.js +25 -0
  33. package/bld/chunks/chunk-SDYJF2XK.js.map +7 -0
  34. package/bld/chunks/chunk-SGDNOA44.js +92 -0
  35. package/bld/chunks/chunk-SGDNOA44.js.map +7 -0
  36. package/bld/chunks/chunk-SPFHOFBC.js +125 -0
  37. package/bld/chunks/chunk-SPFHOFBC.js.map +7 -0
  38. package/bld/chunks/chunk-VVX3WOBG.js +160 -0
  39. package/bld/chunks/chunk-VVX3WOBG.js.map +7 -0
  40. package/bld/chunks/chunk-W62ASGIP.js +25 -0
  41. package/bld/chunks/chunk-W62ASGIP.js.map +7 -0
  42. package/bld/chunks/chunk-Z5LEGL77.js +464 -0
  43. package/bld/chunks/chunk-Z5LEGL77.js.map +7 -0
  44. package/bld/chunks/chunk-ZNWKI54A.js +25 -0
  45. package/bld/chunks/chunk-ZNWKI54A.js.map +7 -0
  46. package/bld/library/common.d.ts +104 -0
  47. package/bld/library/common.d.ts.map +1 -0
  48. package/bld/library/gb-2672.d.ts +8 -0
  49. package/bld/library/gb-2672.d.ts.map +1 -0
  50. package/bld/library/gb-2672.js +17 -0
  51. package/bld/library/gb-2672.js.map +7 -0
  52. package/bld/library/gb-5281.d.ts +8 -0
  53. package/bld/library/gb-5281.d.ts.map +1 -0
  54. package/bld/library/gb-5281.js +15 -0
  55. package/bld/library/gb-5281.js.map +7 -0
  56. package/bld/library/gb-5782.d.ts +8 -0
  57. package/bld/library/gb-5782.d.ts.map +1 -0
  58. package/bld/library/gb-5782.js +19 -0
  59. package/bld/library/gb-5782.js.map +7 -0
  60. package/bld/library/gb-5783.d.ts +8 -0
  61. package/bld/library/gb-5783.d.ts.map +1 -0
  62. package/bld/library/gb-5783.js +19 -0
  63. package/bld/library/gb-5783.js.map +7 -0
  64. package/bld/library/gb-70-1.d.ts +8 -0
  65. package/bld/library/gb-70-1.d.ts.map +1 -0
  66. package/bld/library/gb-70-1.js +17 -0
  67. package/bld/library/gb-70-1.js.map +7 -0
  68. package/bld/library/gb-70-2.d.ts +8 -0
  69. package/bld/library/gb-70-2.d.ts.map +1 -0
  70. package/bld/library/gb-70-2.js +17 -0
  71. package/bld/library/gb-70-2.js.map +7 -0
  72. package/bld/library/gb-70-3.d.ts +8 -0
  73. package/bld/library/gb-70-3.d.ts.map +1 -0
  74. package/bld/library/gb-70-3.js +17 -0
  75. package/bld/library/gb-70-3.js.map +7 -0
  76. package/bld/library/gb-70-4.d.ts +8 -0
  77. package/bld/library/gb-70-4.d.ts.map +1 -0
  78. package/bld/library/gb-70-4.js +17 -0
  79. package/bld/library/gb-70-4.js.map +7 -0
  80. package/bld/library/gb-80.d.ts +8 -0
  81. package/bld/library/gb-80.d.ts.map +1 -0
  82. package/bld/library/gb-80.js +13 -0
  83. package/bld/library/gb-80.js.map +7 -0
  84. package/bld/library/gb-818.d.ts +8 -0
  85. package/bld/library/gb-818.d.ts.map +1 -0
  86. package/bld/library/gb-818.js +17 -0
  87. package/bld/library/gb-818.js.map +7 -0
  88. package/bld/library/hex-head.d.ts +18 -0
  89. package/bld/library/hex-head.d.ts.map +1 -0
  90. package/bld/library/index.d.ts +19 -0
  91. package/bld/library/index.d.ts.map +1 -1
  92. package/bld/library/index.js +80 -455
  93. package/bld/library/index.js.map +3 -3
  94. package/bld/library/iso-10642.d.ts +51 -0
  95. package/bld/library/iso-10642.d.ts.map +1 -0
  96. package/bld/library/iso-10642.js +16 -0
  97. package/bld/library/iso-10642.js.map +7 -0
  98. package/bld/library/iso-14583.d.ts +35 -0
  99. package/bld/library/iso-14583.d.ts.map +1 -0
  100. package/bld/library/iso-14583.js +16 -0
  101. package/bld/library/iso-14583.js.map +7 -0
  102. package/bld/library/iso-4014.d.ts +20 -0
  103. package/bld/library/iso-4014.d.ts.map +1 -0
  104. package/bld/library/iso-4014.js +18 -0
  105. package/bld/library/iso-4014.js.map +7 -0
  106. package/bld/library/iso-4017.d.ts +20 -0
  107. package/bld/library/iso-4017.d.ts.map +1 -0
  108. package/bld/library/iso-4017.js +18 -0
  109. package/bld/library/iso-4017.js.map +7 -0
  110. package/bld/library/iso-4029.d.ts +32 -0
  111. package/bld/library/iso-4029.d.ts.map +1 -0
  112. package/bld/library/iso-4029.js +12 -0
  113. package/bld/library/iso-4029.js.map +7 -0
  114. package/bld/library/iso-4762.d.ts +10 -152
  115. package/bld/library/iso-4762.d.ts.map +1 -1
  116. package/bld/library/iso-4762.js +16 -0
  117. package/bld/library/iso-4762.js.map +7 -0
  118. package/bld/library/iso-7045.d.ts +33 -0
  119. package/bld/library/iso-7045.d.ts.map +1 -0
  120. package/bld/library/iso-7045.js +16 -0
  121. package/bld/library/iso-7045.js.map +7 -0
  122. package/bld/library/iso-7379.d.ts +56 -0
  123. package/bld/library/iso-7379.d.ts.map +1 -0
  124. package/bld/library/iso-7379.js +14 -0
  125. package/bld/library/iso-7379.js.map +7 -0
  126. package/bld/library/iso-7380-1.d.ts +31 -0
  127. package/bld/library/iso-7380-1.d.ts.map +1 -0
  128. package/bld/library/iso-7380-1.js +16 -0
  129. package/bld/library/iso-7380-1.js.map +7 -0
  130. package/bld/library/iso-7380-2.d.ts +33 -0
  131. package/bld/library/iso-7380-2.d.ts.map +1 -0
  132. package/bld/library/iso-7380-2.js +16 -0
  133. package/bld/library/iso-7380-2.js.map +7 -0
  134. package/package.json +82 -2
  135. package/src/library/common.ts +367 -0
  136. package/src/library/gb-2672.ts +7 -0
  137. package/src/library/gb-5281.ts +7 -0
  138. package/src/library/gb-5782.ts +7 -0
  139. package/src/library/gb-5783.ts +7 -0
  140. package/src/library/gb-70-1.ts +7 -0
  141. package/src/library/gb-70-2.ts +7 -0
  142. package/src/library/gb-70-3.ts +7 -0
  143. package/src/library/gb-70-4.ts +7 -0
  144. package/src/library/gb-80.ts +7 -0
  145. package/src/library/gb-818.ts +7 -0
  146. package/src/library/hex-head.ts +53 -0
  147. package/src/library/index.ts +20 -0
  148. package/src/library/iso-10642.ts +173 -0
  149. package/src/library/iso-14583.ts +181 -0
  150. package/src/library/iso-4014.ts +64 -0
  151. package/src/library/iso-4017.ts +62 -0
  152. package/src/library/iso-4029.ts +101 -0
  153. package/src/library/iso-4762.ts +70 -300
  154. package/src/library/iso-7045.ts +134 -0
  155. package/src/library/iso-7379.ts +230 -0
  156. package/src/library/iso-7380-1.ts +110 -0
  157. package/src/library/iso-7380-2.ts +135 -0
  158. package/src/library/thread.ts +7 -1
@@ -0,0 +1,464 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
+ var __export = (target, all) => {
4
+ for (var name in all)
5
+ __defProp(target, name, { get: all[name], enumerable: true });
6
+ };
7
+
8
+ // packages/screws/src/library/common.ts
9
+ import {
10
+ offset,
11
+ cylinder,
12
+ cut,
13
+ frustum,
14
+ intersect,
15
+ loft,
16
+ rectangle,
17
+ regularPrism,
18
+ sphere,
19
+ union
20
+ } from "@code3d/core";
21
+
22
+ // packages/screws/src/library/thread.ts
23
+ import {
24
+ definePrimitive,
25
+ replicad
26
+ } from "@code3d/core/replicad";
27
+ var { Plane, draw, makeCylinder, makeHelix, makeSolid, weldShellsAndFaces } = replicad;
28
+ var loopSteps = Array.from({ length: 21 }, (_, index) => index / 20);
29
+ var helicalThread = definePrimitive(
30
+ (options) => {
31
+ validateHelicalThread(options);
32
+ const {
33
+ majorDiameter,
34
+ minorDiameter,
35
+ leftHanded = false,
36
+ ...dimensions
37
+ } = options;
38
+ return makeHelicalThreadShape({
39
+ ...dimensions,
40
+ majorRadius: majorDiameter / 2,
41
+ minorRadius: minorDiameter / 2,
42
+ leftHanded
43
+ });
44
+ }
45
+ );
46
+ function validateHelicalThread({
47
+ pitch,
48
+ y,
49
+ majorDiameter,
50
+ minorDiameter,
51
+ rootWidth,
52
+ crestWidth
53
+ }) {
54
+ assertPositive("pitch", pitch);
55
+ assertPositive("y", y);
56
+ assertPositive("majorDiameter", majorDiameter);
57
+ assertPositive("minorDiameter", minorDiameter);
58
+ assertPositive("rootWidth", rootWidth);
59
+ assertPositive("crestWidth", crestWidth);
60
+ if (y < pitch) {
61
+ throw new Error("y must be at least one thread pitch.");
62
+ }
63
+ if (minorDiameter >= majorDiameter) {
64
+ throw new Error("minorDiameter must be smaller than majorDiameter.");
65
+ }
66
+ if (crestWidth >= rootWidth || rootWidth > pitch) {
67
+ throw new Error(
68
+ "The thread profile requires crestWidth < rootWidth <= pitch."
69
+ );
70
+ }
71
+ }
72
+ __name(validateHelicalThread, "validateHelicalThread");
73
+ function makeHelicalThreadShape({
74
+ pitch,
75
+ y,
76
+ majorRadius,
77
+ minorRadius,
78
+ rootWidth,
79
+ crestWidth,
80
+ leftHanded
81
+ }) {
82
+ const toothHeight = majorRadius - minorRadius;
83
+ const profile = threadProfile(rootWidth, crestWidth, toothHeight);
84
+ const teeth = fadedThread(pitch, minorRadius, y, profile, leftHanded);
85
+ const core = makeCylinder(minorRadius + 0.05, y);
86
+ const threaded = core.fuse(teeth);
87
+ core.delete();
88
+ teeth.delete();
89
+ const envelope = makeCylinder(majorRadius + pitch, y);
90
+ const trimmed = threaded.intersect(envelope);
91
+ threaded.delete();
92
+ envelope.delete();
93
+ return trimmed.rotate(-90, [0, 0, 0], [1, 0, 0]).translate([0, -y / 2, 0]);
94
+ }
95
+ __name(makeHelicalThreadShape, "makeHelicalThreadShape");
96
+ function threadProfile(rootWidth, crestWidth, toothHeight) {
97
+ const rootHalf = rootWidth / 2;
98
+ const crestHalf = crestWidth / 2;
99
+ return draw([rootHalf, -0.05]).vLine(0.05).lineTo([crestHalf, toothHeight]).hLineTo(-crestHalf).lineTo([-rootHalf, 0]).vLine(-0.05).close();
100
+ }
101
+ __name(threadProfile, "threadProfile");
102
+ function fadedThread(pitch, radius, length, profile, leftHanded) {
103
+ const bottomEnd = fadedEnd(pitch, radius, profile, true, leftHanded);
104
+ const totalLoops = length / pitch - 0.5;
105
+ const fullLoops = Math.floor(totalLoops);
106
+ const leftover = totalLoops - fullLoops;
107
+ const singleLoop = basicThreadLoop(
108
+ pitch,
109
+ radius,
110
+ profile,
111
+ 1,
112
+ "none",
113
+ leftHanded
114
+ );
115
+ const shells = Array.from(
116
+ { length: fullLoops },
117
+ (_, index) => singleLoop.clone().translate([0, 0, index * pitch])
118
+ );
119
+ singleLoop.delete();
120
+ if (leftover > 1e-9) {
121
+ shells.push(
122
+ basicThreadLoop(
123
+ pitch,
124
+ radius,
125
+ profile,
126
+ leftover,
127
+ "none",
128
+ leftHanded
129
+ ).translate([0, 0, fullLoops * pitch])
130
+ );
131
+ }
132
+ const topEnd = fadedEnd(pitch, radius, profile, false, leftHanded).translate([0, 0, totalLoops * pitch]).rotate(360 * leftover, [0, 0, 0], [0, 0, 1]);
133
+ const thread = makeSolid([bottomEnd, ...shells, topEnd]).translate([
134
+ 0,
135
+ 0,
136
+ pitch / 4
137
+ ]);
138
+ bottomEnd.delete();
139
+ shells.forEach((shell) => shell.delete());
140
+ topEnd.delete();
141
+ return thread;
142
+ }
143
+ __name(fadedThread, "fadedThread");
144
+ function basicThreadLoop(pitch, radius, profile, loopFraction, includeEnd, leftHanded) {
145
+ const helix = makeHelix(
146
+ pitch,
147
+ pitch * clamp(loopFraction, 0, 1),
148
+ radius,
149
+ [0, 0, 0],
150
+ [0, 0, 1],
151
+ leftHanded
152
+ );
153
+ const profiles = loopSteps.map((step) => {
154
+ const position = helix.pointAt(step);
155
+ const tangent = helix.tangentAt(step);
156
+ const plane = new Plane(position, [0, 0, 1], tangent);
157
+ const sketch = profile.sketchOnPlane(plane);
158
+ plane.delete();
159
+ return sketch;
160
+ });
161
+ helix.delete();
162
+ const ends = [];
163
+ if (includeEnd === "first" || includeEnd === "both") {
164
+ ends.push(profiles[0].faces());
165
+ }
166
+ if (includeEnd === "last" || includeEnd === "both") {
167
+ const face = profiles.at(-1).faces();
168
+ face.wrapped.Reverse();
169
+ ends.push(face);
170
+ }
171
+ const shell = profiles[0].loftWith(profiles.slice(1), { ruled: false }, true);
172
+ if (ends.length === 0) return shell;
173
+ const closed = weldShellsAndFaces([shell, ...ends]);
174
+ shell.delete();
175
+ ends.forEach((face) => face.delete());
176
+ return closed;
177
+ }
178
+ __name(basicThreadLoop, "basicThreadLoop");
179
+ function fadedEnd(pitch, radius, profile, bottom, leftHanded) {
180
+ const length = pitch / 4;
181
+ const helix = makeHelix(
182
+ pitch,
183
+ length,
184
+ radius,
185
+ [0, 0, 0],
186
+ [0, 0, bottom ? -1 : 1],
187
+ leftHanded
188
+ );
189
+ const profiles = loopSteps.map((step, index) => {
190
+ const position = helix.pointAt(step);
191
+ let tangent = helix.tangentAt(step);
192
+ if (bottom) tangent = tangent.multiply(-1);
193
+ const plane = new Plane(position, [0, 0, 1], tangent);
194
+ const sketch = profile.scale((loopSteps.length - index) / loopSteps.length, [0, 0]).sketchOnPlane(plane);
195
+ plane.delete();
196
+ return sketch;
197
+ });
198
+ helix.delete();
199
+ const endFace = profiles.at(-1).faces();
200
+ const shell = profiles[0].loftWith(profiles.slice(1), { ruled: false }, true);
201
+ const closed = weldShellsAndFaces([shell, endFace]);
202
+ shell.delete();
203
+ endFace.delete();
204
+ return bottom ? closed.rotate(180, [0, 0, 0], [0, 0, 1]) : closed;
205
+ }
206
+ __name(fadedEnd, "fadedEnd");
207
+ function assertPositive(name, value) {
208
+ if (!Number.isFinite(value) || value <= 0) {
209
+ throw new Error(`${name} must be a positive finite number.`);
210
+ }
211
+ }
212
+ __name(assertPositive, "assertPositive");
213
+ function clamp(value, minimum, maximum) {
214
+ return Math.min(Math.max(value, minimum), maximum);
215
+ }
216
+ __name(clamp, "clamp");
217
+
218
+ // packages/screws/src/library/common.ts
219
+ var metricDimensions = {
220
+ M3: [3, 0.5, 3.2, 3.4, 3.6],
221
+ M4: [4, 0.7, 4.3, 4.5, 4.8],
222
+ M5: [5, 0.8, 5.3, 5.5, 5.8],
223
+ M6: [6, 1, 6.4, 6.6, 7],
224
+ M8: [8, 1.25, 8.4, 9, 10],
225
+ M10: [10, 1.5, 10.5, 11, 12],
226
+ M12: [12, 1.75, 13, 13.5, 14.5]
227
+ };
228
+ function metric(designation) {
229
+ const [nominalDiameter, pitch, close, normal, loose] = metricDimensions[designation];
230
+ return {
231
+ designation,
232
+ nominalDiameter,
233
+ pitch,
234
+ clearance: { close, normal, loose }
235
+ };
236
+ }
237
+ __name(metric, "metric");
238
+ function positive(name, value) {
239
+ if (!Number.isFinite(value) || value <= 0)
240
+ throw new Error(`${name} must be a positive finite number.`);
241
+ }
242
+ __name(positive, "positive");
243
+ function validateMetric(spec) {
244
+ positive("Nominal diameter", spec.nominalDiameter);
245
+ positive("Pitch", spec.pitch);
246
+ if (spec.pitch >= spec.nominalDiameter)
247
+ throw new Error("Pitch must be smaller than the nominal diameter.");
248
+ }
249
+ __name(validateMetric, "validateMetric");
250
+ function validateHead(spec) {
251
+ validateMetric(spec);
252
+ positive("Head diameter", spec.headDiameter);
253
+ positive("Head height", spec.headHeight);
254
+ positive("Under-head radius", spec.underHeadRadius);
255
+ if (spec.headDiameter <= spec.nominalDiameter)
256
+ throw new Error("Head diameter must exceed the nominal diameter.");
257
+ }
258
+ __name(validateHead, "validateHead");
259
+ function atY(model, y) {
260
+ return model.originOffset(0, -y, 0);
261
+ }
262
+ __name(atY, "atY");
263
+ function externalThread(spec, length) {
264
+ validateMetric(spec);
265
+ positive("Thread length", length);
266
+ const fundamentalHeight = Math.sqrt(3) / 2 * spec.pitch;
267
+ return helicalThread({
268
+ pitch: spec.pitch,
269
+ y: length,
270
+ majorDiameter: spec.nominalDiameter,
271
+ minorDiameter: spec.nominalDiameter - 2 * (5 / 8 * fundamentalHeight),
272
+ rootWidth: 3 / 4 * spec.pitch,
273
+ crestWidth: 1 / 8 * spec.pitch
274
+ });
275
+ }
276
+ __name(externalThread, "externalThread");
277
+ function shank(spec, length, threadedLength, radius) {
278
+ positive("Screw length", length);
279
+ positive("Thread length", threadedLength);
280
+ if (length <= spec.pitch + radius)
281
+ throw new Error(
282
+ "Screw length must leave room for at least one full thread pitch."
283
+ );
284
+ const bodyLength = length - radius;
285
+ const threadLength = Math.min(bodyLength, threadedLength);
286
+ const plainLength = bodyLength - threadLength;
287
+ const overlap = Math.min(0.08, spec.pitch / 10);
288
+ const transition = atY(
289
+ frustum(
290
+ spec.nominalDiameter / 2,
291
+ spec.nominalDiameter / 2 + radius,
292
+ radius
293
+ ),
294
+ -radius / 2
295
+ );
296
+ const parts = [transition];
297
+ if (plainLength > 0)
298
+ parts.push(
299
+ atY(
300
+ cylinder(spec.nominalDiameter / 2, plainLength + overlap),
301
+ -radius - plainLength / 2 + overlap / 2
302
+ )
303
+ );
304
+ const thread = atY(
305
+ externalThread(spec, threadLength + overlap),
306
+ -length + (threadLength + overlap) / 2
307
+ );
308
+ parts.push(thread);
309
+ return union(parts).expose({
310
+ shankTop: transition.up,
311
+ shankBottom: thread.down,
312
+ shankAxis: thread.axis
313
+ });
314
+ }
315
+ __name(shank, "shank");
316
+ function headedScrew(head, spec, length, threadedLength) {
317
+ validateHead(spec);
318
+ const shaft = shank(
319
+ spec,
320
+ length,
321
+ threadedLength,
322
+ spec.underHeadRadius
323
+ ).relate((part) => part.on(head.down));
324
+ return union([head, shaft]).expose({
325
+ headTop: head.up,
326
+ headBottom: head.down,
327
+ shankTop: shaft.shankTop,
328
+ shankBottom: shaft.shankBottom,
329
+ shankAxis: shaft.shankAxis
330
+ });
331
+ }
332
+ __name(headedScrew, "headedScrew");
333
+ function hexSocket(head, width, depth, height) {
334
+ positive("Hex socket width", width);
335
+ positive("Hex socket depth", depth);
336
+ if (depth >= height)
337
+ throw new Error("Hex socket depth must be smaller than the head height.");
338
+ const tool = regularPrism(width / Math.sqrt(3), depth + 0.2, 6, 30).relate(
339
+ (part) => [part.down.on(head.up), offset(0, -depth, 0)]
340
+ );
341
+ return cut(head, [tool]);
342
+ }
343
+ __name(hexSocket, "hexSocket");
344
+ function roundHead(diameter, height, crownDiameter) {
345
+ positive("Head diameter", diameter);
346
+ positive("Head height", height);
347
+ positive("Crown diameter", crownDiameter);
348
+ if (crownDiameter >= diameter)
349
+ throw new Error("Crown diameter must be smaller than the head diameter.");
350
+ const radius = diameter / 2;
351
+ const crown = crownDiameter / 2;
352
+ const center = (height * height + crown * crown - radius * radius) / (2 * height);
353
+ const ball = atY(sphere(Math.hypot(radius, center)), center - height / 2);
354
+ return intersect([cylinder(radius, height), ball]);
355
+ }
356
+ __name(roundHead, "roundHead");
357
+ function panHead(diameter, height, crownDiameter, curvatureRadius) {
358
+ positive("Head curvature radius", curvatureRadius);
359
+ if (curvatureRadius <= diameter / 2)
360
+ throw new Error(
361
+ "Head curvature radius must exceed half the head diameter."
362
+ );
363
+ const capHeight = Math.sqrt(curvatureRadius ** 2 - (crownDiameter / 2) ** 2) - Math.sqrt(curvatureRadius ** 2 - (diameter / 2) ** 2);
364
+ if (!Number.isFinite(capHeight) || capHeight <= 0 || capHeight >= height)
365
+ throw new Error("Pan head crown must leave a cylindrical barrel.");
366
+ const barrel = cylinder(diameter / 2, height - capHeight);
367
+ const cap = atY(roundHead(diameter, capHeight, crownDiameter), height / 2);
368
+ return union([barrel, cap]);
369
+ }
370
+ __name(panHead, "panHead");
371
+ function crossSocket(head, recess, type) {
372
+ const { diameter, depth, width } = recess;
373
+ positive("Cross recess diameter", diameter);
374
+ positive("Cross recess depth", depth);
375
+ positive("Cross recess width", width);
376
+ const bottom = rectangle(width * 0.7, diameter * 0.5);
377
+ const top = rectangle(width, diameter).originOffset(0, -depth, 0);
378
+ const wing = loft([bottom, top]);
379
+ const tools = [wing, wing.rotate(0, 90, 0)];
380
+ if (type === "Z") {
381
+ const rib = loft([
382
+ rectangle(width * 0.2, diameter * 0.45),
383
+ rectangle(width * 0.35, diameter * 0.85).originOffset(0, -depth, 0)
384
+ ]);
385
+ tools.push(rib.rotate(0, 45, 0), rib.rotate(0, 135, 0));
386
+ }
387
+ const tool = union(tools).relate((part) => part.up.on(head.up));
388
+ return cut(head, [tool]);
389
+ }
390
+ __name(crossSocket, "crossSocket");
391
+ function plainHole(spec, options) {
392
+ validateMetric(spec);
393
+ positive("Hole depth", options.depth);
394
+ const diameter = options.diameter ?? spec.clearance[options.fit ?? "normal"];
395
+ positive("Clearance diameter", diameter);
396
+ if (diameter <= spec.nominalDiameter)
397
+ throw new Error(
398
+ "Clearance-hole diameter must exceed the nominal screw diameter."
399
+ );
400
+ const shaft = cylinder(diameter / 2, options.depth);
401
+ return shaft.expose({
402
+ shaftTop: shaft.up,
403
+ shaftBottom: shaft.down,
404
+ shaftAxis: shaft.axis
405
+ });
406
+ }
407
+ __name(plainHole, "plainHole");
408
+ function clearanceHole(spec, optionsOrDepth, defaultCounterbore = false) {
409
+ const options = typeof optionsOrDepth === "number" ? { depth: optionsOrDepth } : optionsOrDepth;
410
+ return withCounterbore(
411
+ plainHole(spec, options),
412
+ spec,
413
+ options,
414
+ defaultCounterbore
415
+ );
416
+ }
417
+ __name(clearanceHole, "clearanceHole");
418
+ function withCounterbore(shaft, spec, options, defaultCounterbore = false) {
419
+ const counterboreOption = options.counterbore ?? defaultCounterbore;
420
+ if (counterboreOption === false) return shaft;
421
+ const counterbore = counterboreOption === true ? {} : counterboreOption;
422
+ const axialClearance = counterbore.axialClearance ?? 0.5;
423
+ if (!Number.isFinite(axialClearance) || axialClearance < 0)
424
+ throw new Error("Axial clearance must be a nonnegative finite number.");
425
+ const depth = counterbore.depth ?? spec.headHeight + axialClearance;
426
+ const diameter = counterbore.diameter ?? spec.counterboreDiameter ?? spec.headDiameter + 1;
427
+ positive("Counterbore depth", depth);
428
+ positive("Counterbore diameter", diameter);
429
+ if (depth > options.depth)
430
+ throw new Error("Counterbore depth must be within the total hole depth.");
431
+ if (diameter < spec.headDiameter)
432
+ throw new Error("Counterbore diameter must accommodate the screw head.");
433
+ const recess = atY(
434
+ cylinder(diameter / 2, depth),
435
+ (options.depth - depth) / 2
436
+ );
437
+ return union([shaft, recess]).expose({
438
+ shaftTop: shaft.shaftTop,
439
+ shaftBottom: shaft.shaftBottom,
440
+ shaftAxis: shaft.shaftAxis,
441
+ counterboreTop: recess.up,
442
+ counterboreBottom: recess.down
443
+ });
444
+ }
445
+ __name(withCounterbore, "withCounterbore");
446
+
447
+ export {
448
+ __name,
449
+ __export,
450
+ metric,
451
+ positive,
452
+ validateHead,
453
+ atY,
454
+ externalThread,
455
+ headedScrew,
456
+ hexSocket,
457
+ roundHead,
458
+ panHead,
459
+ crossSocket,
460
+ plainHole,
461
+ clearanceHole,
462
+ withCounterbore
463
+ };
464
+ //# sourceMappingURL=chunk-Z5LEGL77.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/library/common.ts", "../../src/library/thread.ts"],
4
+ "sourcesContent": ["import {\n offset,\n cylinder,\n cut,\n frustum,\n intersect,\n loft,\n rectangle,\n regularPrism,\n sphere,\n union,\n type Bound,\n type CanonicalElements,\n type LineAnchor,\n type SolidModel,\n} from '@code3d/core';\nimport {helicalThread} from './thread.js';\n\nexport type ClearanceFit = 'close' | 'normal' | 'loose';\nexport type MetricSpecification = Readonly<{\n designation: string;\n nominalDiameter: number;\n pitch: number;\n clearance: Readonly<Record<ClearanceFit, number>>;\n}>;\n\n// ISO metric coarse pitches and ISO 273 clearance series, millimetres.\nconst metricDimensions = {\n M3: [3, 0.5, 3.2, 3.4, 3.6],\n M4: [4, 0.7, 4.3, 4.5, 4.8],\n M5: [5, 0.8, 5.3, 5.5, 5.8],\n M6: [6, 1, 6.4, 6.6, 7],\n M8: [8, 1.25, 8.4, 9, 10],\n M10: [10, 1.5, 10.5, 11, 12],\n M12: [12, 1.75, 13, 13.5, 14.5],\n} as const;\nexport type MetricSize = keyof typeof metricDimensions;\n\nexport function metric(designation: MetricSize): MetricSpecification {\n const [nominalDiameter, pitch, close, normal, loose] =\n metricDimensions[designation];\n return {\n designation,\n nominalDiameter,\n pitch,\n clearance: {close, normal, loose},\n };\n}\n\nexport type ShankElements = Readonly<{\n shankTop: Bound;\n shankBottom: Bound;\n shankAxis: LineAnchor;\n}>;\nexport type ScrewElements = CanonicalElements &\n ShankElements &\n Readonly<{\n headTop: Bound;\n headBottom: Bound;\n }>;\nexport type Screw = SolidModel<ScrewElements>;\nexport type HoleElements = CanonicalElements &\n Readonly<{\n shaftTop: Bound;\n shaftBottom: Bound;\n shaftAxis: LineAnchor;\n }>;\nexport type CounterboredHoleElements = HoleElements &\n Readonly<{\n counterboreTop: Bound;\n counterboreBottom: Bound;\n }>;\nexport type ClearanceHole = SolidModel<HoleElements>;\nexport type CounterboredHole = SolidModel<CounterboredHoleElements>;\n\nexport type HeadSpecification = MetricSpecification &\n Readonly<{\n headDiameter: number;\n headHeight: number;\n underHeadRadius: number;\n }>;\nexport type CounterboreOptions = Readonly<{\n diameter?: number;\n depth?: number;\n axialClearance?: number;\n}>;\nexport type ClearanceHoleOptions = Readonly<{\n depth: number;\n fit?: ClearanceFit;\n diameter?: number;\n counterbore?: boolean | CounterboreOptions;\n}>;\nexport type PlainHoleOptions = ClearanceHoleOptions &\n Readonly<{counterbore?: false}>;\nexport type CounterboredHoleOptions = ClearanceHoleOptions &\n Readonly<{\n counterbore: true | CounterboreOptions;\n }>;\n\nexport function positive(name: string, value: number): void {\n if (!Number.isFinite(value) || value <= 0)\n throw new Error(`${name} must be a positive finite number.`);\n}\n\nexport function validateMetric(spec: MetricSpecification): void {\n positive('Nominal diameter', spec.nominalDiameter);\n positive('Pitch', spec.pitch);\n if (spec.pitch >= spec.nominalDiameter)\n throw new Error('Pitch must be smaller than the nominal diameter.');\n}\n\nexport function validateHead(spec: HeadSpecification): void {\n validateMetric(spec);\n positive('Head diameter', spec.headDiameter);\n positive('Head height', spec.headHeight);\n positive('Under-head radius', spec.underHeadRadius);\n if (spec.headDiameter <= spec.nominalDiameter)\n throw new Error('Head diameter must exceed the nominal diameter.');\n}\n\n/** Translate geometry within the package's common Y-axis frame. */\nexport function atY<T extends SolidModel>(model: T, y: number) {\n return model.originOffset(0, -y, 0);\n}\n\nexport function externalThread(spec: MetricSpecification, length: number) {\n validateMetric(spec);\n positive('Thread length', length);\n const fundamentalHeight = (Math.sqrt(3) / 2) * spec.pitch;\n return helicalThread({\n pitch: spec.pitch,\n y: length,\n majorDiameter: spec.nominalDiameter,\n minorDiameter: spec.nominalDiameter - 2 * ((5 / 8) * fundamentalHeight),\n rootWidth: (3 / 4) * spec.pitch,\n crestWidth: (1 / 8) * spec.pitch,\n });\n}\n\n/** Shaft top is Y=0; its tip is Y=-length, including the blended ends. */\nexport function shank(\n spec: MetricSpecification,\n length: number,\n threadedLength: number,\n radius: number,\n) {\n positive('Screw length', length);\n positive('Thread length', threadedLength);\n if (length <= spec.pitch + radius)\n throw new Error(\n 'Screw length must leave room for at least one full thread pitch.',\n );\n const bodyLength = length - radius;\n const threadLength = Math.min(bodyLength, threadedLength);\n const plainLength = bodyLength - threadLength;\n const overlap = Math.min(0.08, spec.pitch / 10);\n const transition = atY(\n frustum(\n spec.nominalDiameter / 2,\n spec.nominalDiameter / 2 + radius,\n radius,\n ),\n -radius / 2,\n );\n const parts: SolidModel[] = [transition];\n if (plainLength > 0)\n parts.push(\n atY(\n cylinder(spec.nominalDiameter / 2, plainLength + overlap),\n -radius - plainLength / 2 + overlap / 2,\n ),\n );\n const thread = atY(\n externalThread(spec, threadLength + overlap),\n -length + (threadLength + overlap) / 2,\n );\n parts.push(thread);\n return union(parts).expose({\n shankTop: transition.up,\n shankBottom: thread.down,\n shankAxis: thread.axis,\n });\n}\n\nexport function headedScrew(\n head: SolidModel,\n spec: HeadSpecification,\n length: number,\n threadedLength: number,\n): Screw {\n validateHead(spec);\n const shaft = shank(\n spec,\n length,\n threadedLength,\n spec.underHeadRadius,\n ).relate(part => part.on(head.down));\n return union([head, shaft]).expose({\n headTop: head.up,\n headBottom: head.down,\n shankTop: shaft.shankTop,\n shankBottom: shaft.shankBottom,\n shankAxis: shaft.shankAxis,\n });\n}\n\nexport function hexSocket(\n head: SolidModel,\n width: number,\n depth: number,\n height: number,\n): SolidModel {\n positive('Hex socket width', width);\n positive('Hex socket depth', depth);\n if (depth >= height)\n throw new Error('Hex socket depth must be smaller than the head height.');\n const tool = regularPrism(width / Math.sqrt(3), depth + 0.2, 6, 30).relate(\n part => [part.down.on(head.up), offset(0, -depth, 0)],\n );\n return cut(head, [tool]);\n}\n\n/** Spherical head with a small flat crown surrounding the driving recess. */\nexport function roundHead(\n diameter: number,\n height: number,\n crownDiameter: number,\n): SolidModel {\n positive('Head diameter', diameter);\n positive('Head height', height);\n positive('Crown diameter', crownDiameter);\n if (crownDiameter >= diameter)\n throw new Error('Crown diameter must be smaller than the head diameter.');\n const radius = diameter / 2;\n const crown = crownDiameter / 2;\n const center =\n (height * height + crown * crown - radius * radius) / (2 * height);\n const ball = atY(sphere(Math.hypot(radius, center)), center - height / 2);\n return intersect([cylinder(radius, height), ball]);\n}\n\nexport function panHead(\n diameter: number,\n height: number,\n crownDiameter: number,\n curvatureRadius: number,\n): SolidModel {\n positive('Head curvature radius', curvatureRadius);\n if (curvatureRadius <= diameter / 2)\n throw new Error(\n 'Head curvature radius must exceed half the head diameter.',\n );\n const capHeight =\n Math.sqrt(curvatureRadius ** 2 - (crownDiameter / 2) ** 2) -\n Math.sqrt(curvatureRadius ** 2 - (diameter / 2) ** 2);\n if (!Number.isFinite(capHeight) || capHeight <= 0 || capHeight >= height)\n throw new Error('Pan head crown must leave a cylindrical barrel.');\n const barrel = cylinder(diameter / 2, height - capHeight);\n const cap = atY(roundHead(diameter, capHeight, crownDiameter), height / 2);\n return union([barrel, cap]);\n}\n\nexport type CrossRecessType = 'H' | 'Z';\nexport type CrossRecess = Readonly<{\n number: number;\n diameter: number;\n depth: number;\n width: number;\n}>;\n\n/** Tapered cruciform drive; type Z adds its four intermediate ribs. */\nexport function crossSocket(\n head: SolidModel,\n recess: CrossRecess,\n type: CrossRecessType,\n): SolidModel {\n const {diameter, depth, width} = recess;\n positive('Cross recess diameter', diameter);\n positive('Cross recess depth', depth);\n positive('Cross recess width', width);\n const bottom = rectangle(width * 0.7, diameter * 0.5);\n const top = rectangle(width, diameter).originOffset(0, -depth, 0);\n const wing = loft([bottom, top]);\n const tools = [wing, wing.rotate(0, 90, 0)];\n if (type === 'Z') {\n const rib = loft([\n rectangle(width * 0.2, diameter * 0.45),\n rectangle(width * 0.35, diameter * 0.85).originOffset(0, -depth, 0),\n ]);\n tools.push(rib.rotate(0, 45, 0), rib.rotate(0, 135, 0));\n }\n const tool = union(tools).relate(part => part.up.on(head.up));\n return cut(head, [tool]);\n}\n\nexport function plainHole(\n spec: MetricSpecification,\n options: Omit<ClearanceHoleOptions, 'counterbore'>,\n): ClearanceHole {\n validateMetric(spec);\n positive('Hole depth', options.depth);\n const diameter = options.diameter ?? spec.clearance[options.fit ?? 'normal'];\n positive('Clearance diameter', diameter);\n if (diameter <= spec.nominalDiameter)\n throw new Error(\n 'Clearance-hole diameter must exceed the nominal screw diameter.',\n );\n const shaft = cylinder(diameter / 2, options.depth);\n return shaft.expose({\n shaftTop: shaft.up,\n shaftBottom: shaft.down,\n shaftAxis: shaft.axis,\n });\n}\n\nexport function clearanceHole(\n spec: HeadSpecification & {counterboreDiameter?: number},\n optionsOrDepth: number | ClearanceHoleOptions,\n defaultCounterbore = false,\n): ClearanceHole | CounterboredHole {\n const options =\n typeof optionsOrDepth === 'number'\n ? {depth: optionsOrDepth}\n : optionsOrDepth;\n return withCounterbore(\n plainHole(spec, options),\n spec,\n options,\n defaultCounterbore,\n );\n}\n\n/** Add a head recess to a centered Y-axis passage, preserving its references. */\nexport function withCounterbore(\n shaft: ClearanceHole,\n spec: Pick<HeadSpecification, 'headDiameter' | 'headHeight'> &\n Readonly<{counterboreDiameter?: number}>,\n options: Pick<ClearanceHoleOptions, 'depth' | 'counterbore'>,\n defaultCounterbore = false,\n): ClearanceHole | CounterboredHole {\n const counterboreOption = options.counterbore ?? defaultCounterbore;\n if (counterboreOption === false) return shaft;\n const counterbore = counterboreOption === true ? {} : counterboreOption;\n const axialClearance = counterbore.axialClearance ?? 0.5;\n if (!Number.isFinite(axialClearance) || axialClearance < 0)\n throw new Error('Axial clearance must be a nonnegative finite number.');\n const depth = counterbore.depth ?? spec.headHeight + axialClearance;\n const diameter =\n counterbore.diameter ?? spec.counterboreDiameter ?? spec.headDiameter + 1;\n positive('Counterbore depth', depth);\n positive('Counterbore diameter', diameter);\n if (depth > options.depth)\n throw new Error('Counterbore depth must be within the total hole depth.');\n if (diameter < spec.headDiameter)\n throw new Error('Counterbore diameter must accommodate the screw head.');\n const recess = atY(\n cylinder(diameter / 2, depth),\n (options.depth - depth) / 2,\n );\n return union([shaft, recess]).expose({\n shaftTop: shaft.shaftTop,\n shaftBottom: shaft.shaftBottom,\n shaftAxis: shaft.shaftAxis,\n counterboreTop: recess.up,\n counterboreBottom: recess.down,\n });\n}\n", "import {\n definePrimitive,\n replicad,\n type Drawing,\n type Face,\n type Shape3D,\n type Sketch,\n} from '@code3d/core/replicad';\n\nconst {Plane, draw, makeCylinder, makeHelix, makeSolid, weldShellsAndFaces} =\n replicad;\n\ntype HelicalThreadOptions = Readonly<{\n pitch: number;\n y: number;\n majorDiameter: number;\n minorDiameter: number;\n rootWidth: number;\n crestWidth: number;\n leftHanded?: boolean;\n}>;\n\nconst loopSteps = Array.from({length: 21}, (_, index) => index / 20);\n\nexport const helicalThread = definePrimitive(\n (options: HelicalThreadOptions) => {\n validateHelicalThread(options);\n const {\n majorDiameter,\n minorDiameter,\n leftHanded = false,\n ...dimensions\n } = options;\n return makeHelicalThreadShape({\n ...dimensions,\n majorRadius: majorDiameter / 2,\n minorRadius: minorDiameter / 2,\n leftHanded,\n });\n },\n);\n\nfunction validateHelicalThread({\n pitch,\n y,\n majorDiameter,\n minorDiameter,\n rootWidth,\n crestWidth,\n}: HelicalThreadOptions): void {\n assertPositive('pitch', pitch);\n assertPositive('y', y);\n assertPositive('majorDiameter', majorDiameter);\n assertPositive('minorDiameter', minorDiameter);\n assertPositive('rootWidth', rootWidth);\n assertPositive('crestWidth', crestWidth);\n if (y < pitch) {\n throw new Error('y must be at least one thread pitch.');\n }\n if (minorDiameter >= majorDiameter) {\n throw new Error('minorDiameter must be smaller than majorDiameter.');\n }\n if (crestWidth >= rootWidth || rootWidth > pitch) {\n throw new Error(\n 'The thread profile requires crestWidth < rootWidth <= pitch.',\n );\n }\n}\n\ntype HelicalThreadShapeOptions = Readonly<{\n pitch: number;\n y: number;\n majorRadius: number;\n minorRadius: number;\n rootWidth: number;\n crestWidth: number;\n leftHanded: boolean;\n}>;\n\n/**\n * Builds a closed external thread around its minor-diameter core. The lofted\n * end treatment follows the MIT-licensed replicad-threads construction by\n * Steve Genoud, adapted here to code3d's Y-axis and geometry ownership model.\n */\nfunction makeHelicalThreadShape({\n pitch,\n y,\n majorRadius,\n minorRadius,\n rootWidth,\n crestWidth,\n leftHanded,\n}: HelicalThreadShapeOptions): Shape3D {\n const toothHeight = majorRadius - minorRadius;\n const profile = threadProfile(rootWidth, crestWidth, toothHeight);\n const teeth = fadedThread(pitch, minorRadius, y, profile, leftHanded);\n const core = makeCylinder(minorRadius + 0.05, y);\n const threaded = core.fuse(teeth);\n core.delete();\n teeth.delete();\n // The axial profile width extends past the fade's quarter-pitch centreline.\n // Face both ends. Keep the tool clear of the crest to avoid tangent slivers.\n const envelope = makeCylinder(majorRadius + pitch, y);\n const trimmed = threaded.intersect(envelope);\n threaded.delete();\n envelope.delete();\n return trimmed.rotate(-90, [0, 0, 0], [1, 0, 0]).translate([0, -y / 2, 0]);\n}\n\nfunction threadProfile(\n rootWidth: number,\n crestWidth: number,\n toothHeight: number,\n): Drawing {\n const rootHalf = rootWidth / 2;\n const crestHalf = crestWidth / 2;\n return draw([rootHalf, -0.05])\n .vLine(0.05)\n .lineTo([crestHalf, toothHeight])\n .hLineTo(-crestHalf)\n .lineTo([-rootHalf, 0])\n .vLine(-0.05)\n .close();\n}\n\nfunction fadedThread(\n pitch: number,\n radius: number,\n length: number,\n profile: Drawing,\n leftHanded: boolean,\n): Shape3D {\n const bottomEnd = fadedEnd(pitch, radius, profile, true, leftHanded);\n const totalLoops = length / pitch - 0.5;\n const fullLoops = Math.floor(totalLoops);\n const leftover = totalLoops - fullLoops;\n const singleLoop = basicThreadLoop(\n pitch,\n radius,\n profile,\n 1,\n 'none',\n leftHanded,\n );\n const shells = Array.from({length: fullLoops}, (_, index) =>\n singleLoop.clone().translate([0, 0, index * pitch]),\n );\n singleLoop.delete();\n if (leftover > 1e-9) {\n shells.push(\n basicThreadLoop(\n pitch,\n radius,\n profile,\n leftover,\n 'none',\n leftHanded,\n ).translate([0, 0, fullLoops * pitch]),\n );\n }\n const topEnd = fadedEnd(pitch, radius, profile, false, leftHanded)\n .translate([0, 0, totalLoops * pitch])\n .rotate(360 * leftover, [0, 0, 0], [0, 0, 1]);\n const thread = makeSolid([bottomEnd, ...shells, topEnd]).translate([\n 0,\n 0,\n pitch / 4,\n ]);\n bottomEnd.delete();\n shells.forEach(shell => shell.delete());\n topEnd.delete();\n return thread;\n}\n\nfunction basicThreadLoop(\n pitch: number,\n radius: number,\n profile: Drawing,\n loopFraction: number,\n includeEnd: 'none' | 'first' | 'last' | 'both',\n leftHanded: boolean,\n) {\n const helix = makeHelix(\n pitch,\n pitch * clamp(loopFraction, 0, 1),\n radius,\n [0, 0, 0],\n [0, 0, 1],\n leftHanded,\n );\n const profiles = loopSteps.map(step => {\n const position = helix.pointAt(step);\n const tangent = helix.tangentAt(step);\n const plane = new Plane(position, [0, 0, 1], tangent);\n const sketch = profile.sketchOnPlane(plane) as Sketch;\n plane.delete();\n return sketch;\n });\n helix.delete();\n\n const ends: Face[] = [];\n if (includeEnd === 'first' || includeEnd === 'both') {\n ends.push(profiles[0].faces());\n }\n if (includeEnd === 'last' || includeEnd === 'both') {\n const face = profiles.at(-1)!.faces();\n face.wrapped.Reverse();\n ends.push(face);\n }\n const shell = profiles[0].loftWith(profiles.slice(1), {ruled: false}, true);\n if (ends.length === 0) return shell;\n const closed = weldShellsAndFaces([shell, ...ends]);\n shell.delete();\n ends.forEach(face => face.delete());\n return closed;\n}\n\nfunction fadedEnd(\n pitch: number,\n radius: number,\n profile: Drawing,\n bottom: boolean,\n leftHanded: boolean,\n) {\n const length = pitch / 4;\n const helix = makeHelix(\n pitch,\n length,\n radius,\n [0, 0, 0],\n [0, 0, bottom ? -1 : 1],\n leftHanded,\n );\n const profiles = loopSteps.map((step, index) => {\n const position = helix.pointAt(step);\n let tangent = helix.tangentAt(step);\n if (bottom) tangent = tangent.multiply(-1);\n const plane = new Plane(position, [0, 0, 1], tangent);\n const sketch = profile\n .scale((loopSteps.length - index) / loopSteps.length, [0, 0])\n .sketchOnPlane(plane) as Sketch;\n plane.delete();\n return sketch;\n });\n helix.delete();\n const endFace = profiles.at(-1)!.faces();\n const shell = profiles[0].loftWith(profiles.slice(1), {ruled: false}, true);\n const closed = weldShellsAndFaces([shell, endFace]);\n shell.delete();\n endFace.delete();\n return bottom ? closed.rotate(180, [0, 0, 0], [0, 0, 1]) : closed;\n}\n\nfunction assertPositive(name: string, value: number): void {\n if (!Number.isFinite(value) || value <= 0) {\n throw new Error(`${name} must be a positive finite number.`);\n }\n}\n\nfunction clamp(value: number, minimum: number, maximum: number): number {\n return Math.min(Math.max(value, minimum), maximum);\n}\n"],
5
+ "mappings": ";;;;;;;;AAAA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAKK;;;ACfP;AAAA,EACE;AAAA,EACA;AAAA,OAKK;AAEP,IAAM,EAAC,OAAO,MAAM,cAAc,WAAW,WAAW,mBAAkB,IACxE;AAYF,IAAM,YAAY,MAAM,KAAK,EAAC,QAAQ,GAAE,GAAG,CAAC,GAAG,UAAU,QAAQ,EAAE;AAE5D,IAAM,gBAAgB;AAAA,EAC3B,CAAC,YAAkC;AACjC,0BAAsB,OAAO;AAC7B,UAAM;AAAA,MACJ;AAAA,MACA;AAAA,MACA,aAAa;AAAA,MACb,GAAG;AAAA,IACL,IAAI;AACJ,WAAO,uBAAuB;AAAA,MAC5B,GAAG;AAAA,MACH,aAAa,gBAAgB;AAAA,MAC7B,aAAa,gBAAgB;AAAA,MAC7B;AAAA,IACF,CAAC;AAAA,EACH;AACF;AAEA,SAAS,sBAAsB;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA+B;AAC7B,iBAAe,SAAS,KAAK;AAC7B,iBAAe,KAAK,CAAC;AACrB,iBAAe,iBAAiB,aAAa;AAC7C,iBAAe,iBAAiB,aAAa;AAC7C,iBAAe,aAAa,SAAS;AACrC,iBAAe,cAAc,UAAU;AACvC,MAAI,IAAI,OAAO;AACb,UAAM,IAAI,MAAM,sCAAsC;AAAA,EACxD;AACA,MAAI,iBAAiB,eAAe;AAClC,UAAM,IAAI,MAAM,mDAAmD;AAAA,EACrE;AACA,MAAI,cAAc,aAAa,YAAY,OAAO;AAChD,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACF;AAzBS;AA0CT,SAAS,uBAAuB;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAuC;AACrC,QAAM,cAAc,cAAc;AAClC,QAAM,UAAU,cAAc,WAAW,YAAY,WAAW;AAChE,QAAM,QAAQ,YAAY,OAAO,aAAa,GAAG,SAAS,UAAU;AACpE,QAAM,OAAO,aAAa,cAAc,MAAM,CAAC;AAC/C,QAAM,WAAW,KAAK,KAAK,KAAK;AAChC,OAAK,OAAO;AACZ,QAAM,OAAO;AAGb,QAAM,WAAW,aAAa,cAAc,OAAO,CAAC;AACpD,QAAM,UAAU,SAAS,UAAU,QAAQ;AAC3C,WAAS,OAAO;AAChB,WAAS,OAAO;AAChB,SAAO,QAAQ,OAAO,KAAK,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,EAAE,UAAU,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC;AAC3E;AAvBS;AAyBT,SAAS,cACP,WACA,YACA,aACS;AACT,QAAM,WAAW,YAAY;AAC7B,QAAM,YAAY,aAAa;AAC/B,SAAO,KAAK,CAAC,UAAU,KAAK,CAAC,EAC1B,MAAM,IAAI,EACV,OAAO,CAAC,WAAW,WAAW,CAAC,EAC/B,QAAQ,CAAC,SAAS,EAClB,OAAO,CAAC,CAAC,UAAU,CAAC,CAAC,EACrB,MAAM,KAAK,EACX,MAAM;AACX;AAdS;AAgBT,SAAS,YACP,OACA,QACA,QACA,SACA,YACS;AACT,QAAM,YAAY,SAAS,OAAO,QAAQ,SAAS,MAAM,UAAU;AACnE,QAAM,aAAa,SAAS,QAAQ;AACpC,QAAM,YAAY,KAAK,MAAM,UAAU;AACvC,QAAM,WAAW,aAAa;AAC9B,QAAM,aAAa;AAAA,IACjB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,QAAM,SAAS,MAAM;AAAA,IAAK,EAAC,QAAQ,UAAS;AAAA,IAAG,CAAC,GAAG,UACjD,WAAW,MAAM,EAAE,UAAU,CAAC,GAAG,GAAG,QAAQ,KAAK,CAAC;AAAA,EACpD;AACA,aAAW,OAAO;AAClB,MAAI,WAAW,MAAM;AACnB,WAAO;AAAA,MACL;AAAA,QACE;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,EAAE,UAAU,CAAC,GAAG,GAAG,YAAY,KAAK,CAAC;AAAA,IACvC;AAAA,EACF;AACA,QAAM,SAAS,SAAS,OAAO,QAAQ,SAAS,OAAO,UAAU,EAC9D,UAAU,CAAC,GAAG,GAAG,aAAa,KAAK,CAAC,EACpC,OAAO,MAAM,UAAU,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC;AAC9C,QAAM,SAAS,UAAU,CAAC,WAAW,GAAG,QAAQ,MAAM,CAAC,EAAE,UAAU;AAAA,IACjE;AAAA,IACA;AAAA,IACA,QAAQ;AAAA,EACV,CAAC;AACD,YAAU,OAAO;AACjB,SAAO,QAAQ,WAAS,MAAM,OAAO,CAAC;AACtC,SAAO,OAAO;AACd,SAAO;AACT;AA/CS;AAiDT,SAAS,gBACP,OACA,QACA,SACA,cACA,YACA,YACA;AACA,QAAM,QAAQ;AAAA,IACZ;AAAA,IACA,QAAQ,MAAM,cAAc,GAAG,CAAC;AAAA,IAChC;AAAA,IACA,CAAC,GAAG,GAAG,CAAC;AAAA,IACR,CAAC,GAAG,GAAG,CAAC;AAAA,IACR;AAAA,EACF;AACA,QAAM,WAAW,UAAU,IAAI,UAAQ;AACrC,UAAM,WAAW,MAAM,QAAQ,IAAI;AACnC,UAAM,UAAU,MAAM,UAAU,IAAI;AACpC,UAAM,QAAQ,IAAI,MAAM,UAAU,CAAC,GAAG,GAAG,CAAC,GAAG,OAAO;AACpD,UAAM,SAAS,QAAQ,cAAc,KAAK;AAC1C,UAAM,OAAO;AACb,WAAO;AAAA,EACT,CAAC;AACD,QAAM,OAAO;AAEb,QAAM,OAAe,CAAC;AACtB,MAAI,eAAe,WAAW,eAAe,QAAQ;AACnD,SAAK,KAAK,SAAS,CAAC,EAAE,MAAM,CAAC;AAAA,EAC/B;AACA,MAAI,eAAe,UAAU,eAAe,QAAQ;AAClD,UAAM,OAAO,SAAS,GAAG,EAAE,EAAG,MAAM;AACpC,SAAK,QAAQ,QAAQ;AACrB,SAAK,KAAK,IAAI;AAAA,EAChB;AACA,QAAM,QAAQ,SAAS,CAAC,EAAE,SAAS,SAAS,MAAM,CAAC,GAAG,EAAC,OAAO,MAAK,GAAG,IAAI;AAC1E,MAAI,KAAK,WAAW,EAAG,QAAO;AAC9B,QAAM,SAAS,mBAAmB,CAAC,OAAO,GAAG,IAAI,CAAC;AAClD,QAAM,OAAO;AACb,OAAK,QAAQ,UAAQ,KAAK,OAAO,CAAC;AAClC,SAAO;AACT;AAzCS;AA2CT,SAAS,SACP,OACA,QACA,SACA,QACA,YACA;AACA,QAAM,SAAS,QAAQ;AACvB,QAAM,QAAQ;AAAA,IACZ;AAAA,IACA;AAAA,IACA;AAAA,IACA,CAAC,GAAG,GAAG,CAAC;AAAA,IACR,CAAC,GAAG,GAAG,SAAS,KAAK,CAAC;AAAA,IACtB;AAAA,EACF;AACA,QAAM,WAAW,UAAU,IAAI,CAAC,MAAM,UAAU;AAC9C,UAAM,WAAW,MAAM,QAAQ,IAAI;AACnC,QAAI,UAAU,MAAM,UAAU,IAAI;AAClC,QAAI,OAAQ,WAAU,QAAQ,SAAS,EAAE;AACzC,UAAM,QAAQ,IAAI,MAAM,UAAU,CAAC,GAAG,GAAG,CAAC,GAAG,OAAO;AACpD,UAAM,SAAS,QACZ,OAAO,UAAU,SAAS,SAAS,UAAU,QAAQ,CAAC,GAAG,CAAC,CAAC,EAC3D,cAAc,KAAK;AACtB,UAAM,OAAO;AACb,WAAO;AAAA,EACT,CAAC;AACD,QAAM,OAAO;AACb,QAAM,UAAU,SAAS,GAAG,EAAE,EAAG,MAAM;AACvC,QAAM,QAAQ,SAAS,CAAC,EAAE,SAAS,SAAS,MAAM,CAAC,GAAG,EAAC,OAAO,MAAK,GAAG,IAAI;AAC1E,QAAM,SAAS,mBAAmB,CAAC,OAAO,OAAO,CAAC;AAClD,QAAM,OAAO;AACb,UAAQ,OAAO;AACf,SAAO,SAAS,OAAO,OAAO,KAAK,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,IAAI;AAC7D;AAlCS;AAoCT,SAAS,eAAe,MAAc,OAAqB;AACzD,MAAI,CAAC,OAAO,SAAS,KAAK,KAAK,SAAS,GAAG;AACzC,UAAM,IAAI,MAAM,GAAG,IAAI,oCAAoC;AAAA,EAC7D;AACF;AAJS;AAMT,SAAS,MAAM,OAAe,SAAiB,SAAyB;AACtE,SAAO,KAAK,IAAI,KAAK,IAAI,OAAO,OAAO,GAAG,OAAO;AACnD;AAFS;;;ADxOT,IAAM,mBAAmB;AAAA,EACvB,IAAI,CAAC,GAAG,KAAK,KAAK,KAAK,GAAG;AAAA,EAC1B,IAAI,CAAC,GAAG,KAAK,KAAK,KAAK,GAAG;AAAA,EAC1B,IAAI,CAAC,GAAG,KAAK,KAAK,KAAK,GAAG;AAAA,EAC1B,IAAI,CAAC,GAAG,GAAG,KAAK,KAAK,CAAC;AAAA,EACtB,IAAI,CAAC,GAAG,MAAM,KAAK,GAAG,EAAE;AAAA,EACxB,KAAK,CAAC,IAAI,KAAK,MAAM,IAAI,EAAE;AAAA,EAC3B,KAAK,CAAC,IAAI,MAAM,IAAI,MAAM,IAAI;AAChC;AAGO,SAAS,OAAO,aAA8C;AACnE,QAAM,CAAC,iBAAiB,OAAO,OAAO,QAAQ,KAAK,IACjD,iBAAiB,WAAW;AAC9B,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA,WAAW,EAAC,OAAO,QAAQ,MAAK;AAAA,EAClC;AACF;AATgB;AA6DT,SAAS,SAAS,MAAc,OAAqB;AAC1D,MAAI,CAAC,OAAO,SAAS,KAAK,KAAK,SAAS;AACtC,UAAM,IAAI,MAAM,GAAG,IAAI,oCAAoC;AAC/D;AAHgB;AAKT,SAAS,eAAe,MAAiC;AAC9D,WAAS,oBAAoB,KAAK,eAAe;AACjD,WAAS,SAAS,KAAK,KAAK;AAC5B,MAAI,KAAK,SAAS,KAAK;AACrB,UAAM,IAAI,MAAM,kDAAkD;AACtE;AALgB;AAOT,SAAS,aAAa,MAA+B;AAC1D,iBAAe,IAAI;AACnB,WAAS,iBAAiB,KAAK,YAAY;AAC3C,WAAS,eAAe,KAAK,UAAU;AACvC,WAAS,qBAAqB,KAAK,eAAe;AAClD,MAAI,KAAK,gBAAgB,KAAK;AAC5B,UAAM,IAAI,MAAM,iDAAiD;AACrE;AAPgB;AAUT,SAAS,IAA0B,OAAU,GAAW;AAC7D,SAAO,MAAM,aAAa,GAAG,CAAC,GAAG,CAAC;AACpC;AAFgB;AAIT,SAAS,eAAe,MAA2B,QAAgB;AACxE,iBAAe,IAAI;AACnB,WAAS,iBAAiB,MAAM;AAChC,QAAM,oBAAqB,KAAK,KAAK,CAAC,IAAI,IAAK,KAAK;AACpD,SAAO,cAAc;AAAA,IACnB,OAAO,KAAK;AAAA,IACZ,GAAG;AAAA,IACH,eAAe,KAAK;AAAA,IACpB,eAAe,KAAK,kBAAkB,KAAM,IAAI,IAAK;AAAA,IACrD,WAAY,IAAI,IAAK,KAAK;AAAA,IAC1B,YAAa,IAAI,IAAK,KAAK;AAAA,EAC7B,CAAC;AACH;AAZgB;AAeT,SAAS,MACd,MACA,QACA,gBACA,QACA;AACA,WAAS,gBAAgB,MAAM;AAC/B,WAAS,iBAAiB,cAAc;AACxC,MAAI,UAAU,KAAK,QAAQ;AACzB,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AACF,QAAM,aAAa,SAAS;AAC5B,QAAM,eAAe,KAAK,IAAI,YAAY,cAAc;AACxD,QAAM,cAAc,aAAa;AACjC,QAAM,UAAU,KAAK,IAAI,MAAM,KAAK,QAAQ,EAAE;AAC9C,QAAM,aAAa;AAAA,IACjB;AAAA,MACE,KAAK,kBAAkB;AAAA,MACvB,KAAK,kBAAkB,IAAI;AAAA,MAC3B;AAAA,IACF;AAAA,IACA,CAAC,SAAS;AAAA,EACZ;AACA,QAAM,QAAsB,CAAC,UAAU;AACvC,MAAI,cAAc;AAChB,UAAM;AAAA,MACJ;AAAA,QACE,SAAS,KAAK,kBAAkB,GAAG,cAAc,OAAO;AAAA,QACxD,CAAC,SAAS,cAAc,IAAI,UAAU;AAAA,MACxC;AAAA,IACF;AACF,QAAM,SAAS;AAAA,IACb,eAAe,MAAM,eAAe,OAAO;AAAA,IAC3C,CAAC,UAAU,eAAe,WAAW;AAAA,EACvC;AACA,QAAM,KAAK,MAAM;AACjB,SAAO,MAAM,KAAK,EAAE,OAAO;AAAA,IACzB,UAAU,WAAW;AAAA,IACrB,aAAa,OAAO;AAAA,IACpB,WAAW,OAAO;AAAA,EACpB,CAAC;AACH;AA1CgB;AA4CT,SAAS,YACd,MACA,MACA,QACA,gBACO;AACP,eAAa,IAAI;AACjB,QAAM,QAAQ;AAAA,IACZ;AAAA,IACA;AAAA,IACA;AAAA,IACA,KAAK;AAAA,EACP,EAAE,OAAO,UAAQ,KAAK,GAAG,KAAK,IAAI,CAAC;AACnC,SAAO,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,OAAO;AAAA,IACjC,SAAS,KAAK;AAAA,IACd,YAAY,KAAK;AAAA,IACjB,UAAU,MAAM;AAAA,IAChB,aAAa,MAAM;AAAA,IACnB,WAAW,MAAM;AAAA,EACnB,CAAC;AACH;AApBgB;AAsBT,SAAS,UACd,MACA,OACA,OACA,QACY;AACZ,WAAS,oBAAoB,KAAK;AAClC,WAAS,oBAAoB,KAAK;AAClC,MAAI,SAAS;AACX,UAAM,IAAI,MAAM,wDAAwD;AAC1E,QAAM,OAAO,aAAa,QAAQ,KAAK,KAAK,CAAC,GAAG,QAAQ,KAAK,GAAG,EAAE,EAAE;AAAA,IAClE,UAAQ,CAAC,KAAK,KAAK,GAAG,KAAK,EAAE,GAAG,OAAO,GAAG,CAAC,OAAO,CAAC,CAAC;AAAA,EACtD;AACA,SAAO,IAAI,MAAM,CAAC,IAAI,CAAC;AACzB;AAdgB;AAiBT,SAAS,UACd,UACA,QACA,eACY;AACZ,WAAS,iBAAiB,QAAQ;AAClC,WAAS,eAAe,MAAM;AAC9B,WAAS,kBAAkB,aAAa;AACxC,MAAI,iBAAiB;AACnB,UAAM,IAAI,MAAM,wDAAwD;AAC1E,QAAM,SAAS,WAAW;AAC1B,QAAM,QAAQ,gBAAgB;AAC9B,QAAM,UACH,SAAS,SAAS,QAAQ,QAAQ,SAAS,WAAW,IAAI;AAC7D,QAAM,OAAO,IAAI,OAAO,KAAK,MAAM,QAAQ,MAAM,CAAC,GAAG,SAAS,SAAS,CAAC;AACxE,SAAO,UAAU,CAAC,SAAS,QAAQ,MAAM,GAAG,IAAI,CAAC;AACnD;AAhBgB;AAkBT,SAAS,QACd,UACA,QACA,eACA,iBACY;AACZ,WAAS,yBAAyB,eAAe;AACjD,MAAI,mBAAmB,WAAW;AAChC,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AACF,QAAM,YACJ,KAAK,KAAK,mBAAmB,KAAK,gBAAgB,MAAM,CAAC,IACzD,KAAK,KAAK,mBAAmB,KAAK,WAAW,MAAM,CAAC;AACtD,MAAI,CAAC,OAAO,SAAS,SAAS,KAAK,aAAa,KAAK,aAAa;AAChE,UAAM,IAAI,MAAM,iDAAiD;AACnE,QAAM,SAAS,SAAS,WAAW,GAAG,SAAS,SAAS;AACxD,QAAM,MAAM,IAAI,UAAU,UAAU,WAAW,aAAa,GAAG,SAAS,CAAC;AACzE,SAAO,MAAM,CAAC,QAAQ,GAAG,CAAC;AAC5B;AAnBgB;AA8BT,SAAS,YACd,MACA,QACA,MACY;AACZ,QAAM,EAAC,UAAU,OAAO,MAAK,IAAI;AACjC,WAAS,yBAAyB,QAAQ;AAC1C,WAAS,sBAAsB,KAAK;AACpC,WAAS,sBAAsB,KAAK;AACpC,QAAM,SAAS,UAAU,QAAQ,KAAK,WAAW,GAAG;AACpD,QAAM,MAAM,UAAU,OAAO,QAAQ,EAAE,aAAa,GAAG,CAAC,OAAO,CAAC;AAChE,QAAM,OAAO,KAAK,CAAC,QAAQ,GAAG,CAAC;AAC/B,QAAM,QAAQ,CAAC,MAAM,KAAK,OAAO,GAAG,IAAI,CAAC,CAAC;AAC1C,MAAI,SAAS,KAAK;AAChB,UAAM,MAAM,KAAK;AAAA,MACf,UAAU,QAAQ,KAAK,WAAW,IAAI;AAAA,MACtC,UAAU,QAAQ,MAAM,WAAW,IAAI,EAAE,aAAa,GAAG,CAAC,OAAO,CAAC;AAAA,IACpE,CAAC;AACD,UAAM,KAAK,IAAI,OAAO,GAAG,IAAI,CAAC,GAAG,IAAI,OAAO,GAAG,KAAK,CAAC,CAAC;AAAA,EACxD;AACA,QAAM,OAAO,MAAM,KAAK,EAAE,OAAO,UAAQ,KAAK,GAAG,GAAG,KAAK,EAAE,CAAC;AAC5D,SAAO,IAAI,MAAM,CAAC,IAAI,CAAC;AACzB;AAtBgB;AAwBT,SAAS,UACd,MACA,SACe;AACf,iBAAe,IAAI;AACnB,WAAS,cAAc,QAAQ,KAAK;AACpC,QAAM,WAAW,QAAQ,YAAY,KAAK,UAAU,QAAQ,OAAO,QAAQ;AAC3E,WAAS,sBAAsB,QAAQ;AACvC,MAAI,YAAY,KAAK;AACnB,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AACF,QAAM,QAAQ,SAAS,WAAW,GAAG,QAAQ,KAAK;AAClD,SAAO,MAAM,OAAO;AAAA,IAClB,UAAU,MAAM;AAAA,IAChB,aAAa,MAAM;AAAA,IACnB,WAAW,MAAM;AAAA,EACnB,CAAC;AACH;AAlBgB;AAoBT,SAAS,cACd,MACA,gBACA,qBAAqB,OACa;AAClC,QAAM,UACJ,OAAO,mBAAmB,WACtB,EAAC,OAAO,eAAc,IACtB;AACN,SAAO;AAAA,IACL,UAAU,MAAM,OAAO;AAAA,IACvB;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAfgB;AAkBT,SAAS,gBACd,OACA,MAEA,SACA,qBAAqB,OACa;AAClC,QAAM,oBAAoB,QAAQ,eAAe;AACjD,MAAI,sBAAsB,MAAO,QAAO;AACxC,QAAM,cAAc,sBAAsB,OAAO,CAAC,IAAI;AACtD,QAAM,iBAAiB,YAAY,kBAAkB;AACrD,MAAI,CAAC,OAAO,SAAS,cAAc,KAAK,iBAAiB;AACvD,UAAM,IAAI,MAAM,sDAAsD;AACxE,QAAM,QAAQ,YAAY,SAAS,KAAK,aAAa;AACrD,QAAM,WACJ,YAAY,YAAY,KAAK,uBAAuB,KAAK,eAAe;AAC1E,WAAS,qBAAqB,KAAK;AACnC,WAAS,wBAAwB,QAAQ;AACzC,MAAI,QAAQ,QAAQ;AAClB,UAAM,IAAI,MAAM,wDAAwD;AAC1E,MAAI,WAAW,KAAK;AAClB,UAAM,IAAI,MAAM,uDAAuD;AACzE,QAAM,SAAS;AAAA,IACb,SAAS,WAAW,GAAG,KAAK;AAAA,KAC3B,QAAQ,QAAQ,SAAS;AAAA,EAC5B;AACA,SAAO,MAAM,CAAC,OAAO,MAAM,CAAC,EAAE,OAAO;AAAA,IACnC,UAAU,MAAM;AAAA,IAChB,aAAa,MAAM;AAAA,IACnB,WAAW,MAAM;AAAA,IACjB,gBAAgB,OAAO;AAAA,IACvB,mBAAmB,OAAO;AAAA,EAC5B,CAAC;AACH;AAjCgB;",
6
+ "names": []
7
+ }
@@ -0,0 +1,25 @@
1
+ import {
2
+ clearanceHole,
3
+ resolveSpecification,
4
+ screw,
5
+ specifications,
6
+ threadLength
7
+ } from "./chunk-IXFHRZSY.js";
8
+ import {
9
+ __export
10
+ } from "./chunk-Z5LEGL77.js";
11
+
12
+ // packages/screws/src/library/gb-70-3.ts
13
+ var gb_70_3_exports = {};
14
+ __export(gb_70_3_exports, {
15
+ clearanceHole: () => clearanceHole,
16
+ resolveSpecification: () => resolveSpecification,
17
+ screw: () => screw,
18
+ specifications: () => specifications,
19
+ threadLength: () => threadLength
20
+ });
21
+
22
+ export {
23
+ gb_70_3_exports
24
+ };
25
+ //# sourceMappingURL=chunk-ZNWKI54A.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/library/gb-70-3.ts"],
4
+ "sourcesContent": ["/**\n * GB/T 70.3-2023 (MOD ISO 10642:2019).\n * Shares the corresponding ISO module's nominal geometry within our preset\n * range. See the package README for sizes, hole allowances and modeling limits.\n * https://std.samr.gov.cn/gb/search/gbDetailed?id=FC816D05003162EBE05397BE0A0AD5FA\n */\nexport * from './iso-10642.js';\n"],
5
+ "mappings": ";;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;",
6
+ "names": []
7
+ }
@@ -0,0 +1,104 @@
1
+ import { type Bound, type CanonicalElements, type LineAnchor, type SolidModel } from '@code3d/core';
2
+ export type ClearanceFit = 'close' | 'normal' | 'loose';
3
+ export type MetricSpecification = Readonly<{
4
+ designation: string;
5
+ nominalDiameter: number;
6
+ pitch: number;
7
+ clearance: Readonly<Record<ClearanceFit, number>>;
8
+ }>;
9
+ declare const metricDimensions: {
10
+ readonly M3: readonly [3, 0.5, 3.2, 3.4, 3.6];
11
+ readonly M4: readonly [4, 0.7, 4.3, 4.5, 4.8];
12
+ readonly M5: readonly [5, 0.8, 5.3, 5.5, 5.8];
13
+ readonly M6: readonly [6, 1, 6.4, 6.6, 7];
14
+ readonly M8: readonly [8, 1.25, 8.4, 9, 10];
15
+ readonly M10: readonly [10, 1.5, 10.5, 11, 12];
16
+ readonly M12: readonly [12, 1.75, 13, 13.5, 14.5];
17
+ };
18
+ export type MetricSize = keyof typeof metricDimensions;
19
+ export declare function metric(designation: MetricSize): MetricSpecification;
20
+ export type ShankElements = Readonly<{
21
+ shankTop: Bound;
22
+ shankBottom: Bound;
23
+ shankAxis: LineAnchor;
24
+ }>;
25
+ export type ScrewElements = CanonicalElements & ShankElements & Readonly<{
26
+ headTop: Bound;
27
+ headBottom: Bound;
28
+ }>;
29
+ export type Screw = SolidModel<ScrewElements>;
30
+ export type HoleElements = CanonicalElements & Readonly<{
31
+ shaftTop: Bound;
32
+ shaftBottom: Bound;
33
+ shaftAxis: LineAnchor;
34
+ }>;
35
+ export type CounterboredHoleElements = HoleElements & Readonly<{
36
+ counterboreTop: Bound;
37
+ counterboreBottom: Bound;
38
+ }>;
39
+ export type ClearanceHole = SolidModel<HoleElements>;
40
+ export type CounterboredHole = SolidModel<CounterboredHoleElements>;
41
+ export type HeadSpecification = MetricSpecification & Readonly<{
42
+ headDiameter: number;
43
+ headHeight: number;
44
+ underHeadRadius: number;
45
+ }>;
46
+ export type CounterboreOptions = Readonly<{
47
+ diameter?: number;
48
+ depth?: number;
49
+ axialClearance?: number;
50
+ }>;
51
+ export type ClearanceHoleOptions = Readonly<{
52
+ depth: number;
53
+ fit?: ClearanceFit;
54
+ diameter?: number;
55
+ counterbore?: boolean | CounterboreOptions;
56
+ }>;
57
+ export type PlainHoleOptions = ClearanceHoleOptions & Readonly<{
58
+ counterbore?: false;
59
+ }>;
60
+ export type CounterboredHoleOptions = ClearanceHoleOptions & Readonly<{
61
+ counterbore: true | CounterboreOptions;
62
+ }>;
63
+ export declare function positive(name: string, value: number): void;
64
+ export declare function validateMetric(spec: MetricSpecification): void;
65
+ export declare function validateHead(spec: HeadSpecification): void;
66
+ /** Translate geometry within the package's common Y-axis frame. */
67
+ export declare function atY<T extends SolidModel>(model: T, y: number): SolidModel<Readonly<{
68
+ center: import("@code3d/core").PointAnchor;
69
+ axis: LineAnchor;
70
+ }>>;
71
+ export declare function externalThread(spec: MetricSpecification, length: number): SolidModel;
72
+ /** Shaft top is Y=0; its tip is Y=-length, including the blended ends. */
73
+ export declare function shank(spec: MetricSpecification, length: number, threadedLength: number, radius: number): SolidModel<import("@code3d/core").MergedElements<Readonly<{
74
+ center: import("@code3d/core").PointAnchor;
75
+ axis: LineAnchor;
76
+ }>, Readonly<{
77
+ readonly shankTop: Bound;
78
+ readonly shankBottom: Bound;
79
+ readonly shankAxis: LineAnchor;
80
+ }>>>;
81
+ export declare function headedScrew(head: SolidModel, spec: HeadSpecification, length: number, threadedLength: number): Screw;
82
+ export declare function hexSocket(head: SolidModel, width: number, depth: number, height: number): SolidModel;
83
+ /** Spherical head with a small flat crown surrounding the driving recess. */
84
+ export declare function roundHead(diameter: number, height: number, crownDiameter: number): SolidModel;
85
+ export declare function panHead(diameter: number, height: number, crownDiameter: number, curvatureRadius: number): SolidModel;
86
+ export type CrossRecessType = 'H' | 'Z';
87
+ export type CrossRecess = Readonly<{
88
+ number: number;
89
+ diameter: number;
90
+ depth: number;
91
+ width: number;
92
+ }>;
93
+ /** Tapered cruciform drive; type Z adds its four intermediate ribs. */
94
+ export declare function crossSocket(head: SolidModel, recess: CrossRecess, type: CrossRecessType): SolidModel;
95
+ export declare function plainHole(spec: MetricSpecification, options: Omit<ClearanceHoleOptions, 'counterbore'>): ClearanceHole;
96
+ export declare function clearanceHole(spec: HeadSpecification & {
97
+ counterboreDiameter?: number;
98
+ }, optionsOrDepth: number | ClearanceHoleOptions, defaultCounterbore?: boolean): ClearanceHole | CounterboredHole;
99
+ /** Add a head recess to a centered Y-axis passage, preserving its references. */
100
+ export declare function withCounterbore(shaft: ClearanceHole, spec: Pick<HeadSpecification, 'headDiameter' | 'headHeight'> & Readonly<{
101
+ counterboreDiameter?: number;
102
+ }>, options: Pick<ClearanceHoleOptions, 'depth' | 'counterbore'>, defaultCounterbore?: boolean): ClearanceHole | CounterboredHole;
103
+ export {};
104
+ //# sourceMappingURL=common.d.ts.map