@willcgage/module-schematic 0.49.5 → 0.50.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 +46 -19
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +47 -2
- package/dist/index.d.ts +47 -2
- package/dist/index.js +44 -20
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -541,12 +541,23 @@ function carCapacity(fromPos, toPos, carLengthInches = N_CAR_LENGTH_INCHES) {
|
|
|
541
541
|
if (!(carLengthInches > 0)) return 0;
|
|
542
542
|
return Math.max(0, Math.floor(Math.abs(toPos - fromPos) / carLengthInches));
|
|
543
543
|
}
|
|
544
|
+
function healSelfDivergingTurnouts(turnouts) {
|
|
545
|
+
if (!turnouts?.some((t) => t.onTrack === t.divergeTrack)) return turnouts;
|
|
546
|
+
return turnouts.map((t) => {
|
|
547
|
+
if (t.onTrack !== t.divergeTrack) return t;
|
|
548
|
+
if (t.onTrack === MAIN_TRACK_ID) return { ...t, divergeTrack: MAIN2_TRACK_ID };
|
|
549
|
+
if (t.onTrack === MAIN2_TRACK_ID) return { ...t, divergeTrack: MAIN_TRACK_ID };
|
|
550
|
+
return t;
|
|
551
|
+
});
|
|
552
|
+
}
|
|
544
553
|
function asModuleSchematic(x) {
|
|
545
554
|
if (!x || typeof x !== "object") return null;
|
|
546
555
|
const d = x;
|
|
547
556
|
if (typeof d.version !== "number") return null;
|
|
548
557
|
if (!Array.isArray(d.endplates) || !Array.isArray(d.tracks)) return null;
|
|
549
|
-
|
|
558
|
+
const doc = d;
|
|
559
|
+
const healed = healSelfDivergingTurnouts(doc.turnouts);
|
|
560
|
+
return healed === doc.turnouts ? doc : { ...doc, turnouts: healed };
|
|
550
561
|
}
|
|
551
562
|
function emptyEditorState(lengthInches) {
|
|
552
563
|
return {
|
|
@@ -935,24 +946,19 @@ function docToState(doc, fallbackLength, moduleTracks = []) {
|
|
|
935
946
|
trackB: x.tracks?.[1] ?? MAIN_TRACK_ID
|
|
936
947
|
})),
|
|
937
948
|
extraTracks,
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
...t.size ? { size: t.size } : {},
|
|
952
|
-
...t.curved ? { curved: true } : {},
|
|
953
|
-
...t.flipped ? { flipped: true } : {}
|
|
954
|
-
};
|
|
955
|
-
}),
|
|
949
|
+
// Heal a turnout that diverges into the track it sits on (#172) with the
|
|
950
|
+
// same helper the read path uses, so the editor and every renderer agree.
|
|
951
|
+
turnouts: (healSelfDivergingTurnouts(d.turnouts) ?? []).map((t) => ({
|
|
952
|
+
id: t.id,
|
|
953
|
+
name: t.name ?? "",
|
|
954
|
+
pos: sc(t.pos),
|
|
955
|
+
onTrack: t.onTrack,
|
|
956
|
+
divergeTrack: t.divergeTrack,
|
|
957
|
+
kind: t.kind ?? "right",
|
|
958
|
+
...t.size ? { size: t.size } : {},
|
|
959
|
+
...t.curved ? { curved: true } : {},
|
|
960
|
+
...t.flipped ? { flipped: true } : {}
|
|
961
|
+
})),
|
|
956
962
|
controlPoints: readControlPoints(d, sc),
|
|
957
963
|
industries: (d.industries ?? []).map((ind) => ({
|
|
958
964
|
id: ind.id,
|
|
@@ -1084,6 +1090,24 @@ function buildCrossover(state) {
|
|
|
1084
1090
|
];
|
|
1085
1091
|
return { track, turnouts };
|
|
1086
1092
|
}
|
|
1093
|
+
var RAIL_GAUGE_INCHES = 0.354;
|
|
1094
|
+
var TURNOUT_LEAD_INCHES_PER_FROG = 0.482;
|
|
1095
|
+
function turnoutClosure(size, opts = {}) {
|
|
1096
|
+
const N = size > 0 ? size : 6;
|
|
1097
|
+
const g = opts.gaugeInches ?? RAIL_GAUGE_INCHES;
|
|
1098
|
+
const lead = Math.max(0.01, opts.leadInches ?? N * TURNOUT_LEAD_INCHES_PER_FROG);
|
|
1099
|
+
const frogSlope = 1 / N;
|
|
1100
|
+
const k = (lead / N - g) / (lead * lead);
|
|
1101
|
+
const switchSlope = Math.max(0, frogSlope - 2 * k * lead);
|
|
1102
|
+
return {
|
|
1103
|
+
lead,
|
|
1104
|
+
switchSlope,
|
|
1105
|
+
frogSlope,
|
|
1106
|
+
// Past the frog the route is straight at the frog angle — the closure curve
|
|
1107
|
+
// has done its work, so don't keep bending (that's the tangent Option 1).
|
|
1108
|
+
offsetAt: (s) => s <= lead ? switchSlope * s + k * s * s : g + frogSlope * (s - lead)
|
|
1109
|
+
};
|
|
1110
|
+
}
|
|
1087
1111
|
function divergeSideForHand(kind, stubDir, flipped) {
|
|
1088
1112
|
if (kind !== "left" && kind !== "right") return 0;
|
|
1089
1113
|
const s = (stubDir >= 0 ? 1 : -1) * (flipped ? -1 : 1);
|
|
@@ -1607,6 +1631,8 @@ exports.MAIN2_TRACK_ID = MAIN2_TRACK_ID;
|
|
|
1607
1631
|
exports.MAIN_TRACK_ID = MAIN_TRACK_ID;
|
|
1608
1632
|
exports.N_CAR_LENGTH_INCHES = N_CAR_LENGTH_INCHES;
|
|
1609
1633
|
exports.N_SCALE_RATIO = N_SCALE_RATIO;
|
|
1634
|
+
exports.RAIL_GAUGE_INCHES = RAIL_GAUGE_INCHES;
|
|
1635
|
+
exports.TURNOUT_LEAD_INCHES_PER_FROG = TURNOUT_LEAD_INCHES_PER_FROG;
|
|
1610
1636
|
exports.WHOLE_MODULE_SECTION_ID = WHOLE_MODULE_SECTION_ID;
|
|
1611
1637
|
exports.asModuleSchematic = asModuleSchematic;
|
|
1612
1638
|
exports.benchworkBand = benchworkBand;
|
|
@@ -1658,5 +1684,6 @@ exports.stateToDoc = stateToDoc;
|
|
|
1658
1684
|
exports.toSectionRelative = toSectionRelative;
|
|
1659
1685
|
exports.trackMeetsEndplateIssues = trackMeetsEndplateIssues;
|
|
1660
1686
|
exports.trackPath = trackPath;
|
|
1687
|
+
exports.turnoutClosure = turnoutClosure;
|
|
1661
1688
|
//# sourceMappingURL=index.cjs.map
|
|
1662
1689
|
//# sourceMappingURL=index.cjs.map
|