jscad-electronics 0.0.180 → 0.0.182
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/dist/index.d.ts +57 -2
- package/dist/index.js +1320 -892
- package/dist/index.js.map +1 -1
- package/dist/vanilla.d.ts +57 -1
- package/dist/vanilla.js +434 -12
- package/dist/vanilla.js.map +1 -1
- package/package.json +14 -4
package/dist/vanilla.d.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { BufferGeometry } from 'three';
|
|
2
2
|
import * as jscadModeling from '@jscad/modeling';
|
|
3
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
4
|
+
import { NemaMotorModelPropsInput, HexSocketBoltModelPropsInput, SheetMetalModelPropsInput } from '@tscircuit/modelprinter';
|
|
5
|
+
import * as _jscad_modeling_src_geometries_types from '@jscad/modeling/src/geometries/types';
|
|
3
6
|
|
|
4
7
|
type VNode = {
|
|
5
8
|
type: any;
|
|
@@ -21,6 +24,59 @@ type RenderResult = {
|
|
|
21
24
|
|
|
22
25
|
declare function convertCSGToThreeGeom(csg: any): BufferGeometry;
|
|
23
26
|
|
|
27
|
+
type NemaMotorProps = NemaMotorModelPropsInput & {
|
|
28
|
+
bodyColor?: string;
|
|
29
|
+
capColor?: string;
|
|
30
|
+
shaftColor?: string;
|
|
31
|
+
};
|
|
32
|
+
type NemaFrameMotorProps = Omit<NemaMotorProps, "nemaSize">;
|
|
33
|
+
/** Mounting face at Z=0, body along -Z, shaft along +Z; all lengths in mm.
|
|
34
|
+
* Parameters follow the modelprinter NEMA contract; JSCAD builds all geometry.
|
|
35
|
+
*/
|
|
36
|
+
declare function NemaMotor({ bodyColor, capColor, shaftColor, ...props }: NemaMotorProps): react_jsx_runtime.JSX.Element;
|
|
37
|
+
declare const NEMA8: (props: NemaFrameMotorProps) => react_jsx_runtime.JSX.Element;
|
|
38
|
+
declare const NEMA17: (props: NemaFrameMotorProps) => react_jsx_runtime.JSX.Element;
|
|
39
|
+
declare const NEMA23: (props: NemaFrameMotorProps) => react_jsx_runtime.JSX.Element;
|
|
40
|
+
|
|
41
|
+
/** Indexed triangles, counterclockwise from outside; millimeters, Z up. */
|
|
42
|
+
interface HexSocketBoltMesh {
|
|
43
|
+
positions: number[];
|
|
44
|
+
indices: number[];
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Head bearing plane at Z=0; tip at -length; head extends along +Z.
|
|
48
|
+
* Produces a closed surface with a blind hex socket and a right-hand,
|
|
49
|
+
* truncated 60-degree helical thread. Threads are a visual approximation.
|
|
50
|
+
* No renderer dependencies are needed to consume the indexed mesh.
|
|
51
|
+
*/
|
|
52
|
+
declare const createHexSocketBoltMesh: (input: HexSocketBoltModelPropsInput) => HexSocketBoltMesh;
|
|
53
|
+
|
|
54
|
+
type HexSocketBoltProps = HexSocketBoltModelPropsInput & {
|
|
55
|
+
color?: string;
|
|
56
|
+
};
|
|
57
|
+
/** Bearing plane Z=0, tip along -Z, head along +Z. Threads are approximate. */
|
|
58
|
+
declare function createHexSocketBoltGeom(input: HexSocketBoltModelPropsInput): _jscad_modeling_src_geometries_types.Geom3;
|
|
59
|
+
declare function HexSocketBolt({ color, ...props }: HexSocketBoltProps): react_jsx_runtime.JSX.Element;
|
|
60
|
+
|
|
61
|
+
interface SheetMetalMesh {
|
|
62
|
+
positions: number[];
|
|
63
|
+
indices: number[];
|
|
64
|
+
}
|
|
65
|
+
/** Watertight sheet-metal plate, 90-degree angle or U-channel. Millimeters,
|
|
66
|
+
* right-handed +Z up. Base midsurface at Z=0, centered in X/Y; flanges rise
|
|
67
|
+
* above it. Lengths measure straight tangent-to-tangent sections. Bend skins
|
|
68
|
+
* use the specified inside radius and constant material thickness.
|
|
69
|
+
* Holes are through-cut on straight panels only; no bend allowance/unfolding.
|
|
70
|
+
*/
|
|
71
|
+
declare function createSheetMetalMesh(input: SheetMetalModelPropsInput): SheetMetalMesh;
|
|
72
|
+
|
|
73
|
+
type SheetMetalProps = SheetMetalModelPropsInput & {
|
|
74
|
+
color?: string;
|
|
75
|
+
};
|
|
76
|
+
/** Base midsurface Z=0; bends and flanges rise along +Z. Dimensions in mm. */
|
|
77
|
+
declare function createSheetMetalGeom(input: SheetMetalModelPropsInput): _jscad_modeling_src_geometries_types.Geom3;
|
|
78
|
+
declare function SheetMetal({ color, ...props }: SheetMetalProps): react_jsx_runtime.JSX.Element;
|
|
79
|
+
|
|
24
80
|
declare function getJscadModelForFootprint(footprint: string, jscad: typeof jscadModeling): RenderResult;
|
|
25
81
|
declare function getJscadModelForFootprintWithPads(footprint: string, jscad: typeof jscadModeling): RenderResult;
|
|
26
82
|
declare function createJSCADRenderer(jscad: typeof jscadModeling): {
|
|
@@ -29,4 +85,4 @@ declare function createJSCADRenderer(jscad: typeof jscadModeling): {
|
|
|
29
85
|
};
|
|
30
86
|
};
|
|
31
87
|
|
|
32
|
-
export { type ColoredGeom, Fragment, type RenderResult, type VNode, convertCSGToThreeGeom, createJSCADRenderer, getJscadModelForFootprint, getJscadModelForFootprintWithPads, h };
|
|
88
|
+
export { type ColoredGeom, Fragment, HexSocketBolt, type HexSocketBoltMesh, type HexSocketBoltProps, NEMA17, NEMA23, NEMA8, type NemaFrameMotorProps, NemaMotor, type NemaMotorProps, type RenderResult, SheetMetal, type SheetMetalMesh, type SheetMetalProps, type VNode, convertCSGToThreeGeom, createHexSocketBoltGeom, createHexSocketBoltMesh, createJSCADRenderer, createSheetMetalGeom, createSheetMetalMesh, getJscadModelForFootprint, getJscadModelForFootprintWithPads, h };
|
package/dist/vanilla.js
CHANGED
|
@@ -19,6 +19,7 @@ function h(type, props, ...restChildren) {
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
// lib/ExtrudedPads.tsx
|
|
22
|
+
import { mp } from "@tscircuit/modelprinter";
|
|
22
23
|
import { fp } from "@tscircuit/footprinter";
|
|
23
24
|
|
|
24
25
|
// lib/vanilla/primitives.ts
|
|
@@ -36,6 +37,7 @@ var Colorize = /* @__PURE__ */ Symbol("Colorize");
|
|
|
36
37
|
var Polygon = /* @__PURE__ */ Symbol("Polygon");
|
|
37
38
|
var ExtrudeLinear = /* @__PURE__ */ Symbol("ExtrudeLinear");
|
|
38
39
|
var RoundedCylinder = /* @__PURE__ */ Symbol("RoundedCylinder");
|
|
40
|
+
var Custom = /* @__PURE__ */ Symbol("Custom");
|
|
39
41
|
|
|
40
42
|
// lib/vanilla/react-shim.ts
|
|
41
43
|
var Fragment2 = Fragment;
|
|
@@ -170,6 +172,12 @@ var ExtrudedPads = ({
|
|
|
170
172
|
circuitJson,
|
|
171
173
|
footprint
|
|
172
174
|
}) => {
|
|
175
|
+
if (!circuitJson && footprint && ["nema", "hexsocketbolt", "sheetmetal"].includes(
|
|
176
|
+
mp.string(footprint.split("_", 1)[0]).params().fn
|
|
177
|
+
)) {
|
|
178
|
+
mp.string(footprint).json();
|
|
179
|
+
return null;
|
|
180
|
+
}
|
|
173
181
|
if (!circuitJson && footprint) {
|
|
174
182
|
circuitJson = fp.string(footprint).circuitJson();
|
|
175
183
|
}
|
|
@@ -193,6 +201,395 @@ var ExtrudedPads = ({
|
|
|
193
201
|
] });
|
|
194
202
|
};
|
|
195
203
|
|
|
204
|
+
// lib/mechanical/hex-socket-bolt-mesh.ts
|
|
205
|
+
import {
|
|
206
|
+
hexSocketBoltDimensions,
|
|
207
|
+
hexSocketBoltModelPropsSchema
|
|
208
|
+
} from "@tscircuit/modelprinter";
|
|
209
|
+
var createHexSocketBoltMesh = (input) => {
|
|
210
|
+
const props = hexSocketBoltModelPropsSchema.parse(input);
|
|
211
|
+
const {
|
|
212
|
+
diameter,
|
|
213
|
+
threadPitch: pitch,
|
|
214
|
+
headDiameter,
|
|
215
|
+
headHeight,
|
|
216
|
+
socketWidth,
|
|
217
|
+
socketDepth
|
|
218
|
+
} = hexSocketBoltDimensions[props.metricSize];
|
|
219
|
+
const { length, showThreads } = props;
|
|
220
|
+
const segments = 96;
|
|
221
|
+
const steps = Math.max(2, Math.ceil(length / pitch * 24));
|
|
222
|
+
if (steps > 24e3)
|
|
223
|
+
throw new Error(
|
|
224
|
+
"Bolt length exceeds mesh resolution limit (1000 thread turns)"
|
|
225
|
+
);
|
|
226
|
+
const positions = [];
|
|
227
|
+
const indices = [];
|
|
228
|
+
const radius = diameter / 2;
|
|
229
|
+
const depth = pitch * 0.61343;
|
|
230
|
+
const bevel = Math.min(0.2, headHeight * 0.08);
|
|
231
|
+
const tipBevel = Math.min(pitch * 0.6, length / 3);
|
|
232
|
+
const ring = (z, radiusAt) => {
|
|
233
|
+
const start = positions.length / 3;
|
|
234
|
+
for (let i = 0; i < segments; i++) {
|
|
235
|
+
const angle = i * Math.PI * 2 / segments;
|
|
236
|
+
const r = radiusAt(angle);
|
|
237
|
+
positions.push(r * Math.cos(angle), r * Math.sin(angle), z);
|
|
238
|
+
}
|
|
239
|
+
return start;
|
|
240
|
+
};
|
|
241
|
+
const connect = (a, b) => {
|
|
242
|
+
for (let i = 0; i < segments; i++) {
|
|
243
|
+
const next = (i + 1) % segments;
|
|
244
|
+
indices.push(a + i, a + next, b + next, a + i, b + next, b + i);
|
|
245
|
+
}
|
|
246
|
+
};
|
|
247
|
+
const cap = (start, z, upward) => {
|
|
248
|
+
const center = positions.length / 3;
|
|
249
|
+
positions.push(0, 0, z);
|
|
250
|
+
for (let i = 0; i < segments; i++) {
|
|
251
|
+
const a = start + i;
|
|
252
|
+
const b = start + (i + 1) % segments;
|
|
253
|
+
indices.push(center, upward ? a : b, upward ? b : a);
|
|
254
|
+
}
|
|
255
|
+
};
|
|
256
|
+
let previous = -1;
|
|
257
|
+
for (let step = 0; step <= steps; step++) {
|
|
258
|
+
const z = -length + length * step / steps;
|
|
259
|
+
const current = ring(z, (angle) => {
|
|
260
|
+
const phase = ((z / pitch - angle / (2 * Math.PI)) % 1 + 1) % 1;
|
|
261
|
+
const distance2 = Math.min(phase, 1 - phase);
|
|
262
|
+
const groove = Math.min(
|
|
263
|
+
depth,
|
|
264
|
+
Math.max(0, (distance2 - 1 / 16) * pitch * Math.sqrt(3))
|
|
265
|
+
);
|
|
266
|
+
const endRamp = Math.min(
|
|
267
|
+
1,
|
|
268
|
+
(z + length) / tipBevel,
|
|
269
|
+
-z / Math.min(pitch / 2, length / 3)
|
|
270
|
+
);
|
|
271
|
+
const tipCut = tipBevel * Math.max(0, 1 - (z + length) / tipBevel);
|
|
272
|
+
return radius - (showThreads ? groove * endRamp : 0) - tipCut;
|
|
273
|
+
});
|
|
274
|
+
if (previous < 0) cap(current, z, false);
|
|
275
|
+
else connect(previous, current);
|
|
276
|
+
previous = current;
|
|
277
|
+
}
|
|
278
|
+
const addRing = (z, radiusAt) => {
|
|
279
|
+
const current = ring(z, radiusAt);
|
|
280
|
+
connect(previous, current);
|
|
281
|
+
previous = current;
|
|
282
|
+
};
|
|
283
|
+
addRing(0, () => headDiameter / 2 - bevel);
|
|
284
|
+
addRing(bevel, () => headDiameter / 2);
|
|
285
|
+
addRing(headHeight - bevel, () => headDiameter / 2);
|
|
286
|
+
addRing(headHeight, () => headDiameter / 2 - bevel);
|
|
287
|
+
const hexRadius = (angle, acrossFlats) => acrossFlats / 2 / Math.cos((angle + Math.PI / 6) % (Math.PI / 3) - Math.PI / 6);
|
|
288
|
+
addRing(headHeight, (angle) => hexRadius(angle, socketWidth + bevel));
|
|
289
|
+
addRing(headHeight - bevel / 2, (angle) => hexRadius(angle, socketWidth));
|
|
290
|
+
addRing(headHeight - socketDepth, (angle) => hexRadius(angle, socketWidth));
|
|
291
|
+
cap(previous, headHeight - socketDepth, true);
|
|
292
|
+
return { positions, indices };
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
// lib/mechanical/indexedMeshToGeom3.ts
|
|
296
|
+
import jscad from "@jscad/modeling";
|
|
297
|
+
function indexedMeshToGeom3(mesh) {
|
|
298
|
+
const polygons = [];
|
|
299
|
+
for (let i = 0; i < mesh.indices.length; i += 3)
|
|
300
|
+
polygons.push(
|
|
301
|
+
mesh.indices.slice(i, i + 3).map((index) => [
|
|
302
|
+
mesh.positions[index * 3],
|
|
303
|
+
mesh.positions[index * 3 + 1],
|
|
304
|
+
mesh.positions[index * 3 + 2]
|
|
305
|
+
])
|
|
306
|
+
);
|
|
307
|
+
return jscad.geometries.geom3.fromPoints(polygons);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// lib/HexSocketBolt.tsx
|
|
311
|
+
function createHexSocketBoltGeom(input) {
|
|
312
|
+
return indexedMeshToGeom3(createHexSocketBoltMesh(input));
|
|
313
|
+
}
|
|
314
|
+
function HexSocketBolt({
|
|
315
|
+
color = "#737e8f",
|
|
316
|
+
...props
|
|
317
|
+
}) {
|
|
318
|
+
return /* @__PURE__ */ jsx(Colorize, { color, children: /* @__PURE__ */ jsx(Custom, { geometry: createHexSocketBoltGeom(props) }) });
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// lib/mechanical/sheet-metal-mesh.ts
|
|
322
|
+
import earcut from "earcut";
|
|
323
|
+
import {
|
|
324
|
+
sheetMetalModelPropsSchema
|
|
325
|
+
} from "@tscircuit/modelprinter";
|
|
326
|
+
function holeOutline(hole) {
|
|
327
|
+
const radius = (hole.shape === "round" ? hole.diameter : hole.width) / 2;
|
|
328
|
+
const straight = hole.shape === "slot" ? (hole.length - hole.width) / 2 : 0;
|
|
329
|
+
if (straight < 0) throw new Error("Slot length must be at least its width");
|
|
330
|
+
return Array.from({ length: 64 }, (_, i) => {
|
|
331
|
+
if (hole.shape === "round") {
|
|
332
|
+
const angle2 = i * Math.PI / 32;
|
|
333
|
+
return {
|
|
334
|
+
u: hole.u + radius * Math.cos(angle2),
|
|
335
|
+
v: hole.v + radius * Math.sin(angle2)
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
const half = i < 32 ? 1 : -1;
|
|
339
|
+
const angle = -Math.PI / 2 + (i < 32 ? i : i - 32) * Math.PI / 31 + (i < 32 ? 0 : Math.PI);
|
|
340
|
+
const along = half * straight + radius * Math.cos(angle);
|
|
341
|
+
const across = radius * Math.sin(angle);
|
|
342
|
+
return hole.shape === "slot" && hole.axis === "v" ? { u: hole.u - across, v: hole.v + along } : { u: hole.u + along, v: hole.v + across };
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
function createSheetMetalMesh(input) {
|
|
346
|
+
const props = sheetMetalModelPropsSchema.parse(input);
|
|
347
|
+
const { width: width10, baseLength, flangeHeight, thickness, profile } = props;
|
|
348
|
+
const radius = props.insideBendRadius + thickness / 2;
|
|
349
|
+
const positions = [];
|
|
350
|
+
const indices = [];
|
|
351
|
+
const addTriangle = (vertices, reverse = false) => {
|
|
352
|
+
const start = positions.length / 3;
|
|
353
|
+
for (const vertex of vertices) positions.push(...vertex);
|
|
354
|
+
indices.push(start, start + (reverse ? 2 : 1), start + (reverse ? 1 : 2));
|
|
355
|
+
};
|
|
356
|
+
const addQuad = (vertices, reverse = false) => {
|
|
357
|
+
addTriangle([vertices[0], vertices[1], vertices[2]], reverse);
|
|
358
|
+
addTriangle([vertices[0], vertices[2], vertices[3]], reverse);
|
|
359
|
+
};
|
|
360
|
+
const panels = profile === "plate" ? ["base"] : profile === "angle" ? ["base", "right"] : ["base", "left", "right"];
|
|
361
|
+
for (const hole of props.holes) {
|
|
362
|
+
if (!panels.includes(hole.panel))
|
|
363
|
+
throw new Error(`No ${hole.panel} panel on ${profile}`);
|
|
364
|
+
}
|
|
365
|
+
for (const panel of panels) {
|
|
366
|
+
const length = panel === "base" ? baseLength : flangeHeight;
|
|
367
|
+
const holes = props.holes.filter((hole) => hole.panel === panel).map(holeOutline);
|
|
368
|
+
const bounds = holes.map((outline2) => ({
|
|
369
|
+
minU: Math.min(...outline2.map((p) => p.u)),
|
|
370
|
+
maxU: Math.max(...outline2.map((p) => p.u)),
|
|
371
|
+
minV: Math.min(...outline2.map((p) => p.v)),
|
|
372
|
+
maxV: Math.max(...outline2.map((p) => p.v))
|
|
373
|
+
}));
|
|
374
|
+
for (const [i, box] of bounds.entries()) {
|
|
375
|
+
if (box.minU <= -length / 2 || box.maxU >= length / 2 || box.minV <= -width10 / 2 || box.maxV >= width10 / 2)
|
|
376
|
+
throw new Error(`Hole crosses ${panel} panel edge or bend tangent`);
|
|
377
|
+
for (const previous of bounds.slice(0, i))
|
|
378
|
+
if (box.minU <= previous.maxU && box.maxU >= previous.minU && box.minV <= previous.maxV && box.maxV >= previous.minV)
|
|
379
|
+
throw new Error("Hole bounding boxes must not overlap");
|
|
380
|
+
}
|
|
381
|
+
const outline = [
|
|
382
|
+
{ u: -length / 2, v: -width10 / 2 },
|
|
383
|
+
{ u: length / 2, v: -width10 / 2 },
|
|
384
|
+
{ u: length / 2, v: width10 / 2 },
|
|
385
|
+
{ u: -length / 2, v: width10 / 2 }
|
|
386
|
+
];
|
|
387
|
+
const loops = [outline, ...holes.map((hole) => [...hole].reverse())];
|
|
388
|
+
const points = loops.flat();
|
|
389
|
+
const starts = holes.map((_, i) => 4 + i * 64);
|
|
390
|
+
const triangles = earcut(
|
|
391
|
+
points.flatMap((p) => [p.u, p.v]),
|
|
392
|
+
starts
|
|
393
|
+
);
|
|
394
|
+
const project = (point, offset) => panel === "base" ? [point.u, point.v, offset] : [
|
|
395
|
+
(panel === "left" ? -1 : 1) * (baseLength / 2 + radius - offset),
|
|
396
|
+
point.v,
|
|
397
|
+
radius + flangeHeight / 2 + point.u
|
|
398
|
+
];
|
|
399
|
+
const reverse = panel === "left";
|
|
400
|
+
for (let i = 0; i < triangles.length; i += 3) {
|
|
401
|
+
const face2 = triangles.slice(i, i + 3).map((index) => points[index]);
|
|
402
|
+
addTriangle(
|
|
403
|
+
face2.map((p) => project(p, thickness / 2)),
|
|
404
|
+
reverse
|
|
405
|
+
);
|
|
406
|
+
addTriangle(
|
|
407
|
+
face2.map((p) => project(p, -thickness / 2)),
|
|
408
|
+
!reverse
|
|
409
|
+
);
|
|
410
|
+
}
|
|
411
|
+
for (const [loopIndex, loop] of loops.entries())
|
|
412
|
+
for (let i = 0; i < loop.length; i++) {
|
|
413
|
+
const a = loop[i], b = loop[(i + 1) % loop.length];
|
|
414
|
+
if (loopIndex === 0 && a.u === b.u && (panel === "base" && (a.u > 0 && profile !== "plate" || a.u < 0 && profile === "channel") || panel !== "base" && a.u < 0))
|
|
415
|
+
continue;
|
|
416
|
+
addQuad(
|
|
417
|
+
[
|
|
418
|
+
project(a, -thickness / 2),
|
|
419
|
+
project(b, -thickness / 2),
|
|
420
|
+
project(b, thickness / 2),
|
|
421
|
+
project(a, thickness / 2)
|
|
422
|
+
],
|
|
423
|
+
reverse
|
|
424
|
+
);
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
const sides = profile === "plate" ? [] : profile === "angle" ? [1] : [-1, 1];
|
|
428
|
+
for (const side of sides) {
|
|
429
|
+
const project = (angle, crossSection) => {
|
|
430
|
+
const r = radius - crossSection.offset;
|
|
431
|
+
return [
|
|
432
|
+
side * (baseLength / 2 + r * Math.sin(angle)),
|
|
433
|
+
crossSection.y,
|
|
434
|
+
radius - r * Math.cos(angle)
|
|
435
|
+
];
|
|
436
|
+
};
|
|
437
|
+
for (let i = 0; i < 32; i++) {
|
|
438
|
+
const a = i * Math.PI / 64, b = (i + 1) * Math.PI / 64;
|
|
439
|
+
for (const offset of [-thickness / 2, thickness / 2]) {
|
|
440
|
+
addQuad(
|
|
441
|
+
[
|
|
442
|
+
project(a, { y: -width10 / 2, offset }),
|
|
443
|
+
project(b, { y: -width10 / 2, offset }),
|
|
444
|
+
project(b, { y: width10 / 2, offset }),
|
|
445
|
+
project(a, { y: width10 / 2, offset })
|
|
446
|
+
],
|
|
447
|
+
offset < 0 !== side < 0
|
|
448
|
+
);
|
|
449
|
+
}
|
|
450
|
+
for (const y of [-width10 / 2, width10 / 2]) {
|
|
451
|
+
addQuad(
|
|
452
|
+
[
|
|
453
|
+
project(a, { y, offset: -thickness / 2 }),
|
|
454
|
+
project(b, { y, offset: -thickness / 2 }),
|
|
455
|
+
project(b, { y, offset: thickness / 2 }),
|
|
456
|
+
project(a, { y, offset: thickness / 2 })
|
|
457
|
+
],
|
|
458
|
+
y > 0 !== side < 0
|
|
459
|
+
);
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
return { positions, indices };
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
// lib/SheetMetal.tsx
|
|
467
|
+
function createSheetMetalGeom(input) {
|
|
468
|
+
return indexedMeshToGeom3(createSheetMetalMesh(input));
|
|
469
|
+
}
|
|
470
|
+
function SheetMetal({ color = "#737e8f", ...props }) {
|
|
471
|
+
return /* @__PURE__ */ jsx(Colorize, { color, children: /* @__PURE__ */ jsx(Custom, { geometry: createSheetMetalGeom(props) }) });
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
// lib/NemaMotor.tsx
|
|
475
|
+
import jscad2 from "@jscad/modeling";
|
|
476
|
+
|
|
477
|
+
// lib/utils/nemaMotorParameters.ts
|
|
478
|
+
import { mp as mp2, nemaMotorModelPropsSchema } from "@tscircuit/modelprinter";
|
|
479
|
+
var resolveNemaMotorProps = nemaMotorModelPropsSchema.parse.bind(
|
|
480
|
+
nemaMotorModelPropsSchema
|
|
481
|
+
);
|
|
482
|
+
|
|
483
|
+
// lib/utils/nemaMotorGeometry.ts
|
|
484
|
+
var circle = (radius, x = 0, y = 0) => Array.from({ length: 96 }, (_, i) => [
|
|
485
|
+
x + radius * Math.cos(i * Math.PI / 48),
|
|
486
|
+
y + radius * Math.sin(i * Math.PI / 48)
|
|
487
|
+
]);
|
|
488
|
+
var face = (width10, chamfer) => {
|
|
489
|
+
const h2 = width10 / 2, c = chamfer;
|
|
490
|
+
if (c === 0)
|
|
491
|
+
return [
|
|
492
|
+
[-h2, -h2],
|
|
493
|
+
[h2, -h2],
|
|
494
|
+
[h2, h2],
|
|
495
|
+
[-h2, h2]
|
|
496
|
+
];
|
|
497
|
+
return [
|
|
498
|
+
[-h2 + c, -h2],
|
|
499
|
+
[h2 - c, -h2],
|
|
500
|
+
[h2, -h2 + c],
|
|
501
|
+
[h2, h2 - c],
|
|
502
|
+
[h2 - c, h2],
|
|
503
|
+
[-h2 + c, h2],
|
|
504
|
+
[-h2, h2 - c],
|
|
505
|
+
[-h2, -h2 + c]
|
|
506
|
+
];
|
|
507
|
+
};
|
|
508
|
+
function createNemaMotorSections(input) {
|
|
509
|
+
const p = resolveNemaMotorProps(input);
|
|
510
|
+
const sections = [];
|
|
511
|
+
const add = (name, outline, zMin, zMax, holes2 = []) => {
|
|
512
|
+
if (zMax > zMin) sections.push({ name, outline, holes: holes2, zMin, zMax });
|
|
513
|
+
};
|
|
514
|
+
const front = face(p.bodyWidth, p.faceCornerChamfer);
|
|
515
|
+
const core = face(p.bodyWidth, p.bodyCornerChamfer);
|
|
516
|
+
const h2 = p.mountingHoleSpacing / 2;
|
|
517
|
+
const centers = [
|
|
518
|
+
[-h2, -h2],
|
|
519
|
+
[h2, -h2],
|
|
520
|
+
[h2, h2],
|
|
521
|
+
[-h2, h2]
|
|
522
|
+
];
|
|
523
|
+
const holes = centers.map(
|
|
524
|
+
([x, y]) => circle(p.mountingHoleDiameter / 2, x, y)
|
|
525
|
+
);
|
|
526
|
+
const holeDepth = p.mountingHoleThrough ? p.frontCapLength : p.mountingHoleDepth;
|
|
527
|
+
add("frontCap", front, -holeDepth, 0, holes);
|
|
528
|
+
add("frontCap", front, -p.frontCapLength, -holeDepth);
|
|
529
|
+
add("body", core, -p.bodyLength + p.rearCapLength, -p.frontCapLength);
|
|
530
|
+
add(
|
|
531
|
+
"rearCap",
|
|
532
|
+
p.mountingHoleThrough ? core : front,
|
|
533
|
+
-p.bodyLength,
|
|
534
|
+
-p.bodyLength + p.rearCapLength
|
|
535
|
+
);
|
|
536
|
+
add("pilot", circle(p.pilotDiameter / 2), 0, p.pilotLength);
|
|
537
|
+
const r = p.shaftDiameter / 2;
|
|
538
|
+
const round = circle(r);
|
|
539
|
+
if (p.shaftShape === "round")
|
|
540
|
+
add("shaft", round, p.pilotLength, p.shaftLength);
|
|
541
|
+
else {
|
|
542
|
+
const cut = r - p.shaftFlatDepth;
|
|
543
|
+
const angle = Math.acos(cut / r);
|
|
544
|
+
const profile = Array.from({ length: 97 }, (_, i) => {
|
|
545
|
+
const a = angle + (2 * Math.PI - 2 * angle) * i / 96;
|
|
546
|
+
return [r * Math.cos(a), r * Math.sin(a)];
|
|
547
|
+
});
|
|
548
|
+
const rotation = p.shaftFlatAngle * Math.PI / 180;
|
|
549
|
+
const d = profile.map(([x, y]) => [
|
|
550
|
+
x * Math.cos(rotation) - y * Math.sin(rotation),
|
|
551
|
+
x * Math.sin(rotation) + y * Math.cos(rotation)
|
|
552
|
+
]);
|
|
553
|
+
add("shaft", round, p.pilotLength, p.shaftLength - p.shaftFlatLength);
|
|
554
|
+
add("shaft", d, p.shaftLength - p.shaftFlatLength, p.shaftLength);
|
|
555
|
+
}
|
|
556
|
+
return sections;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
// lib/NemaMotor.tsx
|
|
560
|
+
function NemaMotor({
|
|
561
|
+
bodyColor = "#242830",
|
|
562
|
+
capColor = "#aeb5bd",
|
|
563
|
+
shaftColor = "#b8bec6",
|
|
564
|
+
...props
|
|
565
|
+
}) {
|
|
566
|
+
return /* @__PURE__ */ jsx(Fragment2, { children: createNemaMotorSections(props).map((section, index) => {
|
|
567
|
+
const outline = jscad2.geometries.geom2.fromPoints(section.outline);
|
|
568
|
+
const profile = section.holes.length ? jscad2.booleans.subtract(
|
|
569
|
+
outline,
|
|
570
|
+
...section.holes.map((h2) => jscad2.geometries.geom2.fromPoints(h2))
|
|
571
|
+
) : outline;
|
|
572
|
+
const geometry = jscad2.transforms.translate(
|
|
573
|
+
[0, 0, section.zMin],
|
|
574
|
+
jscad2.extrusions.extrudeLinear(
|
|
575
|
+
{ height: section.zMax - section.zMin },
|
|
576
|
+
profile
|
|
577
|
+
)
|
|
578
|
+
);
|
|
579
|
+
return /* @__PURE__ */ jsx(
|
|
580
|
+
Colorize,
|
|
581
|
+
{
|
|
582
|
+
color: section.name === "body" ? bodyColor : section.name === "shaft" ? shaftColor : capColor,
|
|
583
|
+
children: /* @__PURE__ */ jsx(Custom, { geometry })
|
|
584
|
+
},
|
|
585
|
+
`${section.name}-${index}`
|
|
586
|
+
);
|
|
587
|
+
}) });
|
|
588
|
+
}
|
|
589
|
+
var NEMA8 = (props) => /* @__PURE__ */ jsx(NemaMotor, { ...props, nemaSize: 8 });
|
|
590
|
+
var NEMA17 = (props) => /* @__PURE__ */ jsx(NemaMotor, { ...props, nemaSize: 17 });
|
|
591
|
+
var NEMA23 = (props) => /* @__PURE__ */ jsx(NemaMotor, { ...props, nemaSize: 23 });
|
|
592
|
+
|
|
196
593
|
// lib/LGA.tsx
|
|
197
594
|
function LGA(p) {
|
|
198
595
|
for (const k of [
|
|
@@ -489,7 +886,7 @@ function renderFootprinterBodyModel(p) {
|
|
|
489
886
|
|
|
490
887
|
// lib/Footprinter3d.tsx
|
|
491
888
|
import { fp as fp10 } from "@tscircuit/footprinter";
|
|
492
|
-
import { mp } from "@tscircuit/modelprinter";
|
|
889
|
+
import { mp as mp3 } from "@tscircuit/modelprinter";
|
|
493
890
|
|
|
494
891
|
// lib/ChipBody.tsx
|
|
495
892
|
var ChipBody = ({
|
|
@@ -8195,10 +8592,22 @@ var FlexScreen = (props) => {
|
|
|
8195
8592
|
|
|
8196
8593
|
// lib/Footprinter3d.tsx
|
|
8197
8594
|
var Footprinter3d = ({ footprint }) => {
|
|
8198
|
-
const modelFn =
|
|
8199
|
-
if (
|
|
8200
|
-
const model =
|
|
8595
|
+
const modelFn = mp3.string(footprint.split("_", 1)[0]).params().fn;
|
|
8596
|
+
if (mp3.getModelNames().includes(modelFn)) {
|
|
8597
|
+
const model = mp3.string(footprint).json();
|
|
8201
8598
|
switch (model.fn) {
|
|
8599
|
+
case "nema": {
|
|
8600
|
+
const { fn, ...props } = model;
|
|
8601
|
+
return /* @__PURE__ */ jsx(NemaMotor, { ...props });
|
|
8602
|
+
}
|
|
8603
|
+
case "hexsocketbolt": {
|
|
8604
|
+
const { fn, ...props } = model;
|
|
8605
|
+
return /* @__PURE__ */ jsx(HexSocketBolt, { ...props });
|
|
8606
|
+
}
|
|
8607
|
+
case "sheetmetal": {
|
|
8608
|
+
const { fn, ...props } = model;
|
|
8609
|
+
return /* @__PURE__ */ jsx(SheetMetal, { ...props });
|
|
8610
|
+
}
|
|
8202
8611
|
case "flexscreen": {
|
|
8203
8612
|
const { fn: _, ...flexScreenProps } = model;
|
|
8204
8613
|
return /* @__PURE__ */ jsx(FlexScreen, { ...flexScreenProps });
|
|
@@ -8942,6 +9351,9 @@ function renderNode(node, colorCtx, renderCtx) {
|
|
|
8942
9351
|
else geom = hulls.hull(geoms);
|
|
8943
9352
|
return [{ geom, color: colorCtx }];
|
|
8944
9353
|
}
|
|
9354
|
+
if (type === Custom) {
|
|
9355
|
+
return [{ geom: props.geometry, color: colorCtx }];
|
|
9356
|
+
}
|
|
8945
9357
|
if (type === Polygon) {
|
|
8946
9358
|
const points = props?.points ?? [];
|
|
8947
9359
|
const g2 = geometries.geom2.fromPoints(points);
|
|
@@ -9002,8 +9414,8 @@ function renderNode(node, colorCtx, renderCtx) {
|
|
|
9002
9414
|
}
|
|
9003
9415
|
return (children ?? []).flatMap((c) => renderNode(c, colorCtx, renderCtx));
|
|
9004
9416
|
}
|
|
9005
|
-
function render(root,
|
|
9006
|
-
const geometries = renderNode(root, void 0, { jscad });
|
|
9417
|
+
function render(root, jscad3) {
|
|
9418
|
+
const geometries = renderNode(root, void 0, { jscad: jscad3 });
|
|
9007
9419
|
return { geometries };
|
|
9008
9420
|
}
|
|
9009
9421
|
|
|
@@ -9091,24 +9503,24 @@ function convertCSGToThreeGeom(csg) {
|
|
|
9091
9503
|
}
|
|
9092
9504
|
|
|
9093
9505
|
// lib/vanilla/index.ts
|
|
9094
|
-
function getJscadModelForFootprint(footprint,
|
|
9506
|
+
function getJscadModelForFootprint(footprint, jscad3) {
|
|
9095
9507
|
const vnode = h(Footprinter3d, { footprint });
|
|
9096
|
-
return render(vnode,
|
|
9508
|
+
return render(vnode, jscad3);
|
|
9097
9509
|
}
|
|
9098
|
-
function getJscadModelForFootprintWithPads(footprint,
|
|
9510
|
+
function getJscadModelForFootprintWithPads(footprint, jscad3) {
|
|
9099
9511
|
const vnode = h(
|
|
9100
9512
|
Fragment,
|
|
9101
9513
|
{},
|
|
9102
9514
|
h(Footprinter3d, { footprint }),
|
|
9103
9515
|
h(ExtrudedPads, { footprint })
|
|
9104
9516
|
);
|
|
9105
|
-
return render(vnode,
|
|
9517
|
+
return render(vnode, jscad3);
|
|
9106
9518
|
}
|
|
9107
|
-
function createJSCADRenderer(
|
|
9519
|
+
function createJSCADRenderer(jscad3) {
|
|
9108
9520
|
function createJSCADRoot(container) {
|
|
9109
9521
|
return {
|
|
9110
9522
|
render(element) {
|
|
9111
|
-
const { geometries } = render(element,
|
|
9523
|
+
const { geometries } = render(element, jscad3);
|
|
9112
9524
|
container.splice(0, container.length, ...geometries);
|
|
9113
9525
|
}
|
|
9114
9526
|
};
|
|
@@ -9117,8 +9529,18 @@ function createJSCADRenderer(jscad) {
|
|
|
9117
9529
|
}
|
|
9118
9530
|
export {
|
|
9119
9531
|
Fragment,
|
|
9532
|
+
HexSocketBolt,
|
|
9533
|
+
NEMA17,
|
|
9534
|
+
NEMA23,
|
|
9535
|
+
NEMA8,
|
|
9536
|
+
NemaMotor,
|
|
9537
|
+
SheetMetal,
|
|
9120
9538
|
convertCSGToThreeGeom,
|
|
9539
|
+
createHexSocketBoltGeom,
|
|
9540
|
+
createHexSocketBoltMesh,
|
|
9121
9541
|
createJSCADRenderer,
|
|
9542
|
+
createSheetMetalGeom,
|
|
9543
|
+
createSheetMetalMesh,
|
|
9122
9544
|
getJscadModelForFootprint,
|
|
9123
9545
|
getJscadModelForFootprintWithPads,
|
|
9124
9546
|
h
|