@willcgage/module-schematic 0.47.0 → 0.49.0
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.cjs +91 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +39 -1
- package/dist/index.d.ts +39 -1
- package/dist/index.js +91 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -478,6 +478,9 @@ function moduleFootprint(input) {
|
|
|
478
478
|
// endplate A's face (the far face would be a spurious plate at the throat).
|
|
479
479
|
endplateFaces: input.loop ? endplateFaceSegments(centerline, widthA, widthB, offA, offB).slice(0, 1) : endplateFaceSegments(centerline, widthA, widthB, offA, offB),
|
|
480
480
|
outline: sectionOutlines.length || !authored ? null : sampleBenchworkOutline(authored),
|
|
481
|
+
// The donut hole, arc-sampled — only when there's a solid outline to punch it
|
|
482
|
+
// out of (a sectioned module isn't a donut). Renderers cut it from `outline`.
|
|
483
|
+
outlineInner: sectionOutlines.length || !authored || !input.outlineInner || input.outlineInner.length < 3 ? null : sampleBenchworkOutline(input.outlineInner),
|
|
481
484
|
sectionOutlines
|
|
482
485
|
};
|
|
483
486
|
}
|
|
@@ -559,6 +562,7 @@ function emptyEditorState(lengthInches) {
|
|
|
559
562
|
endplateWidths: {},
|
|
560
563
|
endplateTrackOffsets: {},
|
|
561
564
|
outline: [],
|
|
565
|
+
outlineInner: [],
|
|
562
566
|
sectionBreaks: [],
|
|
563
567
|
sections: [],
|
|
564
568
|
controlPoints: [],
|
|
@@ -795,6 +799,8 @@ function stateToDoc(state, recordNumber) {
|
|
|
795
799
|
// Benchwork footprint outline (module-local inches); only when it's a real
|
|
796
800
|
// ring (≥ 3 vertices).
|
|
797
801
|
...state.outline.length >= 3 ? { outline: state.outline } : {},
|
|
802
|
+
// Benchwork hole (donut inner boundary), when it's a real ring.
|
|
803
|
+
...state.outlineInner.length >= 3 ? { outlineInner: state.outlineInner } : {},
|
|
798
804
|
// Internal section joints (inches from A), when the module has more than one.
|
|
799
805
|
...state.sectionBreaks.length ? { sectionBreaks: state.sectionBreaks } : {},
|
|
800
806
|
// Sections as objects — emitted only once the owner has some, so a module
|
|
@@ -886,6 +892,11 @@ function docToState(doc, fallbackLength, moduleTracks = []) {
|
|
|
886
892
|
y: p.y,
|
|
887
893
|
...Number.isFinite(p.bulge) && p.bulge ? { bulge: p.bulge } : {}
|
|
888
894
|
}));
|
|
895
|
+
const outlineInner = (d.outlineInner ?? []).filter((p) => p && Number.isFinite(p.x) && Number.isFinite(p.y)).map((p) => ({
|
|
896
|
+
x: p.x,
|
|
897
|
+
y: p.y,
|
|
898
|
+
...Number.isFinite(p.bulge) && p.bulge ? { bulge: p.bulge } : {}
|
|
899
|
+
}));
|
|
889
900
|
const mainPath = trackPath(d.mainPath) ?? [];
|
|
890
901
|
const main2Track_ = (d.tracks ?? []).find((t) => t.id === MAIN2_TRACK_ID);
|
|
891
902
|
const main2Path = trackPath(d.main2Path ?? main2Track_?.path) ?? [];
|
|
@@ -909,6 +920,7 @@ function docToState(doc, fallbackLength, moduleTracks = []) {
|
|
|
909
920
|
endplateWidths,
|
|
910
921
|
endplateTrackOffsets,
|
|
911
922
|
outline,
|
|
923
|
+
outlineInner,
|
|
912
924
|
sectionBreaks: (d.sectionBreaks ?? []).filter((n) => Number.isFinite(n)).map((n) => sc(n)),
|
|
913
925
|
sections: moduleSections(d),
|
|
914
926
|
mainPath,
|
|
@@ -1322,6 +1334,84 @@ function moduleFeatures(doc) {
|
|
|
1322
1334
|
laneMax: Math.max(...allLanes)
|
|
1323
1335
|
};
|
|
1324
1336
|
}
|
|
1337
|
+
function returnLoop(shape, opts) {
|
|
1338
|
+
const L = Math.max(1, opts.leadInches);
|
|
1339
|
+
const R = Math.max(1, opts.radius);
|
|
1340
|
+
const hw = Math.min(opts.boardHalfWidth ?? 6, R - 1);
|
|
1341
|
+
const T = { x: L, y: 0 };
|
|
1342
|
+
const r2 = (v) => Math.round(v * 100) / 100;
|
|
1343
|
+
const rd = (pts) => pts.map((p) => ({ x: r2(p.x), y: r2(p.y) }));
|
|
1344
|
+
const arc = (cx, cy, r, a0, a12, steps) => {
|
|
1345
|
+
const out = [];
|
|
1346
|
+
for (let i = 0; i <= steps; i++) out.push({ x: cx + r * Math.cos(a0 + (a12 - a0) * i / steps), y: cy + r * Math.sin(a0 + (a12 - a0) * i / steps) });
|
|
1347
|
+
return out;
|
|
1348
|
+
};
|
|
1349
|
+
const D = shape === "circle" || shape === "square" ? R * 1.15 : R * 1.6;
|
|
1350
|
+
const offY = shape === "offset-teardrop" ? R * 0.7 : 0;
|
|
1351
|
+
const C = { x: L + D, y: offY };
|
|
1352
|
+
const dist = Math.hypot(C.x - T.x, C.y - T.y);
|
|
1353
|
+
const ac = Math.acos(Math.min(1, R / dist));
|
|
1354
|
+
const base = Math.atan2(T.y - C.y, T.x - C.x);
|
|
1355
|
+
const a1 = base + ac;
|
|
1356
|
+
const a2 = base - ac;
|
|
1357
|
+
const P1 = { x: C.x + R * Math.cos(a1), y: C.y + R * Math.sin(a1) };
|
|
1358
|
+
const P2 = { x: C.x + R * Math.cos(a2), y: C.y + R * Math.sin(a2) };
|
|
1359
|
+
const loop = [T, P1, ...arc(C.x, C.y, R, a1, a2 + 2 * Math.PI, 64).slice(1), T];
|
|
1360
|
+
const legDir = (P) => Math.atan2(P.y - T.y, P.x - T.x);
|
|
1361
|
+
const half = Math.abs((legDir(P1) - legDir(P2) + Math.PI) % (2 * Math.PI) - Math.PI) / 2;
|
|
1362
|
+
const ringOuter = (rr) => {
|
|
1363
|
+
const xTop = C.x - Math.sqrt(Math.max(0, rr * rr - (hw - C.y) ** 2));
|
|
1364
|
+
const xBot = C.x - Math.sqrt(Math.max(0, rr * rr - (-hw - C.y) ** 2));
|
|
1365
|
+
const tTop = Math.atan2(hw - C.y, xTop - C.x);
|
|
1366
|
+
const tBot = Math.atan2(-hw - C.y, xBot - C.x);
|
|
1367
|
+
return [
|
|
1368
|
+
{ x: 0, y: hw },
|
|
1369
|
+
{ x: xTop, y: hw },
|
|
1370
|
+
...arc(C.x, C.y, rr, tTop, tBot - 2 * Math.PI, 48).slice(1, -1),
|
|
1371
|
+
{ x: xBot, y: -hw },
|
|
1372
|
+
{ x: 0, y: -hw }
|
|
1373
|
+
];
|
|
1374
|
+
};
|
|
1375
|
+
const Ri = R - hw;
|
|
1376
|
+
if (shape === "square") {
|
|
1377
|
+
const xL = C.x - R - hw;
|
|
1378
|
+
const xR = C.x + R + hw;
|
|
1379
|
+
const yT = R + hw;
|
|
1380
|
+
const outerSquare = [
|
|
1381
|
+
{ x: 0, y: hw },
|
|
1382
|
+
{ x: xL, y: hw },
|
|
1383
|
+
{ x: xL, y: yT },
|
|
1384
|
+
{ x: xR, y: yT },
|
|
1385
|
+
{ x: xR, y: -yT },
|
|
1386
|
+
{ x: xL, y: -yT },
|
|
1387
|
+
{ x: xL, y: -hw },
|
|
1388
|
+
{ x: 0, y: -hw }
|
|
1389
|
+
];
|
|
1390
|
+
const iHalf = (R - hw) / Math.SQRT2;
|
|
1391
|
+
const holeSquare = iHalf > 2 ? [
|
|
1392
|
+
{ x: C.x - iHalf, y: iHalf },
|
|
1393
|
+
{ x: C.x + iHalf, y: iHalf },
|
|
1394
|
+
{ x: C.x + iHalf, y: -iHalf },
|
|
1395
|
+
{ x: C.x - iHalf, y: -iHalf }
|
|
1396
|
+
] : [];
|
|
1397
|
+
return {
|
|
1398
|
+
throat: T,
|
|
1399
|
+
loop: rd(loop),
|
|
1400
|
+
wyeLegs: [rd([T, P1]), rd([T, P2])],
|
|
1401
|
+
wyeHalfAngleDeg: r2(half * 180 / Math.PI),
|
|
1402
|
+
outlineOuter: rd(outerSquare),
|
|
1403
|
+
outlineInner: rd(holeSquare)
|
|
1404
|
+
};
|
|
1405
|
+
}
|
|
1406
|
+
return {
|
|
1407
|
+
throat: T,
|
|
1408
|
+
loop: rd(loop),
|
|
1409
|
+
wyeLegs: [rd([T, P1]), rd([T, P2])],
|
|
1410
|
+
wyeHalfAngleDeg: r2(half * 180 / Math.PI),
|
|
1411
|
+
outlineOuter: rd(ringOuter(R + hw)),
|
|
1412
|
+
outlineInner: Ri > 2 ? rd(arc(C.x, C.y, Ri, 0, 2 * Math.PI, 40)) : []
|
|
1413
|
+
};
|
|
1414
|
+
}
|
|
1325
1415
|
function geometryTurnDegrees(geometryType, geometryDegrees) {
|
|
1326
1416
|
switch (geometryType) {
|
|
1327
1417
|
case "corner_45":
|
|
@@ -1535,6 +1625,7 @@ exports.nextId = nextId;
|
|
|
1535
1625
|
exports.poseNeedsManual = poseNeedsManual;
|
|
1536
1626
|
exports.poseOverridesFromDoc = poseOverridesFromDoc;
|
|
1537
1627
|
exports.remapPos = remapPos;
|
|
1628
|
+
exports.returnLoop = returnLoop;
|
|
1538
1629
|
exports.sampleBenchworkOutline = sampleBenchworkOutline;
|
|
1539
1630
|
exports.samplePath = samplePath;
|
|
1540
1631
|
exports.scaleFeetToInches = scaleFeetToInches;
|