@willcgage/module-schematic 0.57.0 → 0.59.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 +66 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +50 -1
- package/dist/index.d.ts +50 -1
- package/dist/index.js +66 -6
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -769,7 +769,8 @@ function stateToDoc(state, recordNumber) {
|
|
|
769
769
|
name: t.name || void 0,
|
|
770
770
|
...t.size ? { size: t.size } : {},
|
|
771
771
|
...t.curved ? { curved: true } : {},
|
|
772
|
-
...t.flipped ? { flipped: true } : {}
|
|
772
|
+
...t.flipped ? { flipped: true } : {},
|
|
773
|
+
...t.partId ? { partId: t.partId } : {}
|
|
773
774
|
})),
|
|
774
775
|
...state.crossings.length > 0 ? {
|
|
775
776
|
crossings: state.crossings.map((x) => ({
|
|
@@ -957,7 +958,8 @@ function docToState(doc, fallbackLength, moduleTracks = []) {
|
|
|
957
958
|
kind: t.kind ?? "right",
|
|
958
959
|
...t.size ? { size: t.size } : {},
|
|
959
960
|
...t.curved ? { curved: true } : {},
|
|
960
|
-
...t.flipped ? { flipped: true } : {}
|
|
961
|
+
...t.flipped ? { flipped: true } : {},
|
|
962
|
+
...t.partId ? { partId: t.partId } : {}
|
|
961
963
|
})),
|
|
962
964
|
controlPoints: readControlPoints(d, sc),
|
|
963
965
|
industries: (d.industries ?? []).map((ind) => ({
|
|
@@ -1399,6 +1401,44 @@ function mergeImportedParts(imported, library = BUILT_IN_TRACK_PARTS, sourceName
|
|
|
1399
1401
|
}
|
|
1400
1402
|
return out;
|
|
1401
1403
|
}
|
|
1404
|
+
function partOutlineAtFrog(part, leadInches, stepsPerCurve = 16) {
|
|
1405
|
+
const ends = part.ends ?? [];
|
|
1406
|
+
const segs = part.segments ?? [];
|
|
1407
|
+
if (!segs.length || ends.length < 2) return null;
|
|
1408
|
+
let points = ends[0];
|
|
1409
|
+
if (ends.length >= 3) {
|
|
1410
|
+
let bestPair = Infinity;
|
|
1411
|
+
let pairIdx = [1, 2];
|
|
1412
|
+
for (let i = 0; i < ends.length; i++) {
|
|
1413
|
+
for (let j = i + 1; j < ends.length; j++) {
|
|
1414
|
+
const d = Math.hypot(ends[i].x - ends[j].x, ends[i].y - ends[j].y);
|
|
1415
|
+
if (d < bestPair) {
|
|
1416
|
+
bestPair = d;
|
|
1417
|
+
pairIdx = [i, j];
|
|
1418
|
+
}
|
|
1419
|
+
}
|
|
1420
|
+
}
|
|
1421
|
+
const odd = ends.findIndex((_, k) => k !== pairIdx[0] && k !== pairIdx[1]);
|
|
1422
|
+
if (odd >= 0) points = ends[odd];
|
|
1423
|
+
}
|
|
1424
|
+
const a = points.angleDeg * Math.PI / 180;
|
|
1425
|
+
const ux = -Math.sin(a);
|
|
1426
|
+
const uy = -Math.cos(a);
|
|
1427
|
+
const toLocal = (p) => {
|
|
1428
|
+
const dx = p.x - points.x;
|
|
1429
|
+
const dy = p.y - points.y;
|
|
1430
|
+
return { x: dx * ux + dy * uy, y: dx * -uy + dy * ux };
|
|
1431
|
+
};
|
|
1432
|
+
let sign = 1;
|
|
1433
|
+
const offAxis = ends.filter((e) => e !== points).map(toLocal).sort((p, q) => Math.abs(q.y) - Math.abs(p.y))[0];
|
|
1434
|
+
if (offAxis && offAxis.y < 0) sign = -1;
|
|
1435
|
+
return samplePartSegments(segs, stepsPerCurve).map(
|
|
1436
|
+
(poly) => poly.map((p) => {
|
|
1437
|
+
const l = toLocal(p);
|
|
1438
|
+
return { x: l.x - leadInches, y: l.y * sign };
|
|
1439
|
+
})
|
|
1440
|
+
);
|
|
1441
|
+
}
|
|
1402
1442
|
function turnoutClosure(size, opts = {}) {
|
|
1403
1443
|
const N = size > 0 ? size : 6;
|
|
1404
1444
|
const g = opts.gaugeInches ?? RAIL_GAUGE_INCHES;
|
|
@@ -1406,13 +1446,33 @@ function turnoutClosure(size, opts = {}) {
|
|
|
1406
1446
|
const frogSlope = 1 / N;
|
|
1407
1447
|
const k = (lead / N - g) / (lead * lead);
|
|
1408
1448
|
const switchSlope = Math.max(0, frogSlope - 2 * k * lead);
|
|
1449
|
+
const target = opts.arriveAtInches;
|
|
1450
|
+
let a = Infinity;
|
|
1451
|
+
let b = 0;
|
|
1452
|
+
if (target != null && target > g) {
|
|
1453
|
+
b = Math.max(0.01, opts.easeInches ?? lead);
|
|
1454
|
+
a = (target - g) / frogSlope - b / 2;
|
|
1455
|
+
if (a < 0) {
|
|
1456
|
+
a = 0;
|
|
1457
|
+
b = 2 * (target - g) / frogSlope;
|
|
1458
|
+
}
|
|
1459
|
+
}
|
|
1460
|
+
const span = target != null && target > g ? lead + a + b : Infinity;
|
|
1409
1461
|
return {
|
|
1410
1462
|
lead,
|
|
1411
1463
|
switchSlope,
|
|
1412
1464
|
frogSlope,
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
offsetAt: (s) =>
|
|
1465
|
+
span,
|
|
1466
|
+
easeInches: b,
|
|
1467
|
+
offsetAt: (s) => {
|
|
1468
|
+
if (s <= lead) return switchSlope * s + k * s * s;
|
|
1469
|
+
const past = s - lead;
|
|
1470
|
+
if (past <= a) return g + frogSlope * past;
|
|
1471
|
+
if (target == null) return g + frogSlope * past;
|
|
1472
|
+
const u = Math.min(past - a, b);
|
|
1473
|
+
const eased = g + frogSlope * a + frogSlope * u - frogSlope * u * u / (2 * b);
|
|
1474
|
+
return past - a >= b ? target : eased;
|
|
1475
|
+
}
|
|
1416
1476
|
};
|
|
1417
1477
|
}
|
|
1418
1478
|
function divergeSideForHand(kind, stubDir, flipped) {
|
|
@@ -1977,6 +2037,7 @@ exports.moduleLengthFromSections = moduleLengthFromSections;
|
|
|
1977
2037
|
exports.moduleSections = moduleSections;
|
|
1978
2038
|
exports.nextId = nextId;
|
|
1979
2039
|
exports.parseXtpLibrary = parseXtpLibrary;
|
|
2040
|
+
exports.partOutlineAtFrog = partOutlineAtFrog;
|
|
1980
2041
|
exports.poseNeedsManual = poseNeedsManual;
|
|
1981
2042
|
exports.poseOverridesFromDoc = poseOverridesFromDoc;
|
|
1982
2043
|
exports.remapPos = remapPos;
|