jscad-electronics 0.0.179 → 0.0.181
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 +87 -2
- package/dist/index.js +1686 -1188
- package/dist/index.js.map +1 -1
- package/dist/vanilla.d.ts +57 -1
- package/dist/vanilla.js +500 -12
- package/dist/vanilla.js.map +1 -1
- package/package.json +15 -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 = ({
|
|
@@ -961,6 +1358,66 @@ var A0603 = ({ color = "#333" }) => {
|
|
|
961
1358
|
] });
|
|
962
1359
|
};
|
|
963
1360
|
|
|
1361
|
+
// lib/SmdLED.tsx
|
|
1362
|
+
var smdLedDimensions = {
|
|
1363
|
+
"0402": { length: 1, width: 0.5, height: 0.5, terminalLength: 0.2 },
|
|
1364
|
+
"0603": { length: 1.62, width: 0.8, height: 0.615, terminalLength: 0.21 },
|
|
1365
|
+
"0805": { length: 2, width: 1.25, height: 0.75, terminalLength: 0.35 }
|
|
1366
|
+
};
|
|
1367
|
+
function SmdLED({
|
|
1368
|
+
footprint,
|
|
1369
|
+
color = "#ffe8a0"
|
|
1370
|
+
}) {
|
|
1371
|
+
const p = smdLedDimensions[footprint];
|
|
1372
|
+
if (footprint === "0603")
|
|
1373
|
+
return /* @__PURE__ */ jsxs(Fragment2, { children: [
|
|
1374
|
+
/* @__PURE__ */ jsx(Colorize, { color: "#f0eee7", children: /* @__PURE__ */ jsx(
|
|
1375
|
+
RoundedCuboid,
|
|
1376
|
+
{
|
|
1377
|
+
size: [1.2, 0.79, 0.6],
|
|
1378
|
+
roundRadius: 0.02,
|
|
1379
|
+
center: [0, 0, 0.31]
|
|
1380
|
+
}
|
|
1381
|
+
) }),
|
|
1382
|
+
/* @__PURE__ */ jsx(Colorize, { color: "#c7c9ca", children: [-1, 1].map((sign) => /* @__PURE__ */ jsx(
|
|
1383
|
+
Cuboid,
|
|
1384
|
+
{
|
|
1385
|
+
size: [0.21, 0.8, 0.22],
|
|
1386
|
+
center: [sign * 0.705, 0, 0.11]
|
|
1387
|
+
},
|
|
1388
|
+
sign
|
|
1389
|
+
)) }),
|
|
1390
|
+
/* @__PURE__ */ jsx(Colorize, { color, children: /* @__PURE__ */ jsx(Cuboid, { size: [0.72, 0.52, 0.01], center: [0, 0, 0.61] }) })
|
|
1391
|
+
] });
|
|
1392
|
+
const terminalThickness = Math.min(0.1, p.height / 4);
|
|
1393
|
+
const apertureHeight = 0.02;
|
|
1394
|
+
return /* @__PURE__ */ jsxs(Fragment2, { children: [
|
|
1395
|
+
/* @__PURE__ */ jsx(Colorize, { color: "#f0eee7", children: /* @__PURE__ */ jsx(Translate, { z: (p.height + terminalThickness - apertureHeight) / 2, children: /* @__PURE__ */ jsx(
|
|
1396
|
+
Cuboid,
|
|
1397
|
+
{
|
|
1398
|
+
size: [
|
|
1399
|
+
p.length,
|
|
1400
|
+
p.width,
|
|
1401
|
+
p.height - terminalThickness - apertureHeight
|
|
1402
|
+
]
|
|
1403
|
+
}
|
|
1404
|
+
) }) }),
|
|
1405
|
+
/* @__PURE__ */ jsx(Colorize, { color: "#c7c9ca", children: [-1, 1].map((sign) => /* @__PURE__ */ jsx(
|
|
1406
|
+
Translate,
|
|
1407
|
+
{
|
|
1408
|
+
offset: [
|
|
1409
|
+
sign * (p.length - p.terminalLength) / 2,
|
|
1410
|
+
0,
|
|
1411
|
+
terminalThickness / 2
|
|
1412
|
+
],
|
|
1413
|
+
children: /* @__PURE__ */ jsx(Cuboid, { size: [p.terminalLength, p.width, terminalThickness] })
|
|
1414
|
+
},
|
|
1415
|
+
sign
|
|
1416
|
+
)) }),
|
|
1417
|
+
/* @__PURE__ */ jsx(Colorize, { color, children: /* @__PURE__ */ jsx(Translate, { z: p.height - apertureHeight / 2, children: /* @__PURE__ */ jsx(Cuboid, { size: [p.length * 0.45, p.width * 0.65, apertureHeight] }) }) })
|
|
1418
|
+
] });
|
|
1419
|
+
}
|
|
1420
|
+
|
|
964
1421
|
// lib/A0805.tsx
|
|
965
1422
|
var fullLength3 = 2;
|
|
966
1423
|
var width3 = 1.25;
|
|
@@ -8135,10 +8592,22 @@ var FlexScreen = (props) => {
|
|
|
8135
8592
|
|
|
8136
8593
|
// lib/Footprinter3d.tsx
|
|
8137
8594
|
var Footprinter3d = ({ footprint }) => {
|
|
8138
|
-
const modelFn =
|
|
8139
|
-
if (
|
|
8140
|
-
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();
|
|
8141
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
|
+
}
|
|
8142
8611
|
case "flexscreen": {
|
|
8143
8612
|
const { fn: _, ...flexScreenProps } = model;
|
|
8144
8613
|
return /* @__PURE__ */ jsx(FlexScreen, { ...flexScreenProps });
|
|
@@ -8306,6 +8775,12 @@ var Footprinter3d = ({ footprint }) => {
|
|
|
8306
8775
|
);
|
|
8307
8776
|
case "led5050":
|
|
8308
8777
|
return /* @__PURE__ */ jsx(Led5050, { color });
|
|
8778
|
+
case "led": {
|
|
8779
|
+
const imperial = String(fpJson.imperial);
|
|
8780
|
+
if (imperial === "0402" || imperial === "0603" || imperial === "0805")
|
|
8781
|
+
return /* @__PURE__ */ jsx(SmdLED, { footprint: imperial, color });
|
|
8782
|
+
break;
|
|
8783
|
+
}
|
|
8309
8784
|
case "cap": {
|
|
8310
8785
|
switch (fpJson.imperial) {
|
|
8311
8786
|
case "0402":
|
|
@@ -8876,6 +9351,9 @@ function renderNode(node, colorCtx, renderCtx) {
|
|
|
8876
9351
|
else geom = hulls.hull(geoms);
|
|
8877
9352
|
return [{ geom, color: colorCtx }];
|
|
8878
9353
|
}
|
|
9354
|
+
if (type === Custom) {
|
|
9355
|
+
return [{ geom: props.geometry, color: colorCtx }];
|
|
9356
|
+
}
|
|
8879
9357
|
if (type === Polygon) {
|
|
8880
9358
|
const points = props?.points ?? [];
|
|
8881
9359
|
const g2 = geometries.geom2.fromPoints(points);
|
|
@@ -8936,8 +9414,8 @@ function renderNode(node, colorCtx, renderCtx) {
|
|
|
8936
9414
|
}
|
|
8937
9415
|
return (children ?? []).flatMap((c) => renderNode(c, colorCtx, renderCtx));
|
|
8938
9416
|
}
|
|
8939
|
-
function render(root,
|
|
8940
|
-
const geometries = renderNode(root, void 0, { jscad });
|
|
9417
|
+
function render(root, jscad3) {
|
|
9418
|
+
const geometries = renderNode(root, void 0, { jscad: jscad3 });
|
|
8941
9419
|
return { geometries };
|
|
8942
9420
|
}
|
|
8943
9421
|
|
|
@@ -9025,24 +9503,24 @@ function convertCSGToThreeGeom(csg) {
|
|
|
9025
9503
|
}
|
|
9026
9504
|
|
|
9027
9505
|
// lib/vanilla/index.ts
|
|
9028
|
-
function getJscadModelForFootprint(footprint,
|
|
9506
|
+
function getJscadModelForFootprint(footprint, jscad3) {
|
|
9029
9507
|
const vnode = h(Footprinter3d, { footprint });
|
|
9030
|
-
return render(vnode,
|
|
9508
|
+
return render(vnode, jscad3);
|
|
9031
9509
|
}
|
|
9032
|
-
function getJscadModelForFootprintWithPads(footprint,
|
|
9510
|
+
function getJscadModelForFootprintWithPads(footprint, jscad3) {
|
|
9033
9511
|
const vnode = h(
|
|
9034
9512
|
Fragment,
|
|
9035
9513
|
{},
|
|
9036
9514
|
h(Footprinter3d, { footprint }),
|
|
9037
9515
|
h(ExtrudedPads, { footprint })
|
|
9038
9516
|
);
|
|
9039
|
-
return render(vnode,
|
|
9517
|
+
return render(vnode, jscad3);
|
|
9040
9518
|
}
|
|
9041
|
-
function createJSCADRenderer(
|
|
9519
|
+
function createJSCADRenderer(jscad3) {
|
|
9042
9520
|
function createJSCADRoot(container) {
|
|
9043
9521
|
return {
|
|
9044
9522
|
render(element) {
|
|
9045
|
-
const { geometries } = render(element,
|
|
9523
|
+
const { geometries } = render(element, jscad3);
|
|
9046
9524
|
container.splice(0, container.length, ...geometries);
|
|
9047
9525
|
}
|
|
9048
9526
|
};
|
|
@@ -9051,8 +9529,18 @@ function createJSCADRenderer(jscad) {
|
|
|
9051
9529
|
}
|
|
9052
9530
|
export {
|
|
9053
9531
|
Fragment,
|
|
9532
|
+
HexSocketBolt,
|
|
9533
|
+
NEMA17,
|
|
9534
|
+
NEMA23,
|
|
9535
|
+
NEMA8,
|
|
9536
|
+
NemaMotor,
|
|
9537
|
+
SheetMetal,
|
|
9054
9538
|
convertCSGToThreeGeom,
|
|
9539
|
+
createHexSocketBoltGeom,
|
|
9540
|
+
createHexSocketBoltMesh,
|
|
9055
9541
|
createJSCADRenderer,
|
|
9542
|
+
createSheetMetalGeom,
|
|
9543
|
+
createSheetMetalMesh,
|
|
9056
9544
|
getJscadModelForFootprint,
|
|
9057
9545
|
getJscadModelForFootprintWithPads,
|
|
9058
9546
|
h
|