@willcgage/module-schematic 0.107.0 → 0.109.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 +86 -21
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +86 -21
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -2929,27 +2929,49 @@ function graphToDoc(pieces, input) {
|
|
|
2929
2929
|
const epA = endplates[0];
|
|
2930
2930
|
const epB = endplates[1];
|
|
2931
2931
|
const main = walk.routes.find((r) => r.id === "main");
|
|
2932
|
-
const
|
|
2933
|
-
const
|
|
2932
|
+
const start2Key = input.start2 ? `${input.start2.piece}.${input.start2.joint}` : null;
|
|
2933
|
+
const start2IsOpenEnd = !!start2Key && graph.open.includes(start2Key);
|
|
2934
|
+
const walk2 = input.start2 && start2IsOpenEnd ? walkTrackGraph(graph, pieces, input.start2, library) : null;
|
|
2935
|
+
const main2FromBranch = (() => {
|
|
2936
|
+
if (!start2Key || start2IsOpenEnd) return null;
|
|
2937
|
+
const conn = graph.connections.find((c) => c.a === start2Key || c.b === start2Key);
|
|
2938
|
+
if (!conn) return null;
|
|
2939
|
+
const otherKey = conn.a === start2Key ? conn.b : conn.a;
|
|
2940
|
+
const piece = graph.joints.find((j) => j.key === otherKey)?.piece;
|
|
2941
|
+
return walk.routes.find((r) => r.id !== "main" && r.pieces[0] === piece) ?? null;
|
|
2942
|
+
})();
|
|
2943
|
+
const main2 = walk2?.routes.find((r) => r.id === "main") ?? main2FromBranch;
|
|
2934
2944
|
const sharedByDesign = (id) => {
|
|
2935
2945
|
const piece = pieces.find((p) => p.id === id);
|
|
2936
2946
|
return library.find((p) => p.id === piece?.partId)?.kind === "crossover";
|
|
2937
2947
|
};
|
|
2938
|
-
const
|
|
2939
|
-
if (main2 && main2.pieces.some((p) =>
|
|
2948
|
+
const mainPieces = new Set(main.pieces.filter((p) => !sharedByDesign(p)));
|
|
2949
|
+
if (!main2FromBranch && main2 && main2.pieces.some((p) => mainPieces.has(p))) {
|
|
2940
2950
|
warnings.push(
|
|
2941
2951
|
"Main 2 starts on track that Main 1 already runs along \u2014 they are one run, not two"
|
|
2942
2952
|
);
|
|
2943
2953
|
}
|
|
2944
|
-
const twoMains = !!main2 && !main2.pieces.some((p) =>
|
|
2945
|
-
const
|
|
2954
|
+
const twoMains = !!main2 && (!!main2FromBranch || !main2.pieces.some((p) => mainPieces.has(p)));
|
|
2955
|
+
const main2AsBranch = walk2 && main2 && twoMains ? walk.routes.find(
|
|
2956
|
+
(r) => r.id !== "main" && r.pieces.some((p) => main2.pieces.includes(p))
|
|
2957
|
+
) ?? null : null;
|
|
2958
|
+
const main2Lane = twoMains ? (
|
|
2959
|
+
// A branch-born main reaches its lane after an easement, so its SIDE is
|
|
2960
|
+
// how far the run gets laterally, not where its first joint sits.
|
|
2961
|
+
(main2FromBranch ? main2FromBranch.lateral : graph.joints.find((j) => j.key === start2Key)?.y ?? 1) >= 0 ? 1 : -1
|
|
2962
|
+
) : 0;
|
|
2946
2963
|
const lengthInches = round(Math.max(main.toPos, twoMains ? main2.toPos : 0));
|
|
2947
2964
|
const branches = [
|
|
2948
|
-
...walk.routes.filter(
|
|
2949
|
-
|
|
2965
|
+
...walk.routes.filter(
|
|
2966
|
+
(r) => r.id !== "main" && r.pieces.length && r.id !== main2FromBranch?.id && r.id !== main2AsBranch?.id
|
|
2967
|
+
),
|
|
2968
|
+
...walk2 ? walk2.routes.filter((r) => r.id !== "main" && r.pieces.length).map((r) => ({ ...r, id: `main2:${r.id}`, bornAt: r.bornAt })) : []
|
|
2950
2969
|
];
|
|
2951
2970
|
const trackIdOf = /* @__PURE__ */ new Map([["main", MAIN_TRACK_ID]]);
|
|
2952
|
-
if (twoMains)
|
|
2971
|
+
if (twoMains) {
|
|
2972
|
+
trackIdOf.set(main2FromBranch ? main2FromBranch.id : "main2:main", MAIN2_TRACK_ID);
|
|
2973
|
+
if (main2AsBranch) trackIdOf.set(main2AsBranch.id, MAIN2_TRACK_ID);
|
|
2974
|
+
}
|
|
2953
2975
|
for (const r of branches) trackIdOf.set(r.id, r.pieces[0]);
|
|
2954
2976
|
const emitted = /* @__PURE__ */ new Set();
|
|
2955
2977
|
const uniqueBranches = branches.filter((r) => {
|
|
@@ -2980,8 +3002,11 @@ function graphToDoc(pieces, input) {
|
|
|
2980
3002
|
id: MAIN2_TRACK_ID,
|
|
2981
3003
|
role: "main",
|
|
2982
3004
|
lane: main2Lane,
|
|
2983
|
-
|
|
2984
|
-
|
|
3005
|
+
// ⚠️ Only a main that CROSSES the endplates says so. A transition
|
|
3006
|
+
// module's second main begins at a turnout partway along and ends
|
|
3007
|
+
// at one endplate or neither; claiming A→B would tell the catalogue
|
|
3008
|
+
// it presents two tracks at an end where it presents one.
|
|
3009
|
+
...main2FromBranch ? {} : { from: epA?.id ?? "A", ...epB ? { to: epB.id } : {} },
|
|
2985
3010
|
// ⚠️ Its own extent, because a second main need not run the whole
|
|
2986
3011
|
// module: on a transition module it starts or stops partway.
|
|
2987
3012
|
fromPos: round(Math.min(main2.fromPos, main2.toPos)),
|
|
@@ -3026,7 +3051,7 @@ function graphToDoc(pieces, input) {
|
|
|
3026
3051
|
const turnouts = [];
|
|
3027
3052
|
const allTurnouts = [
|
|
3028
3053
|
...walk.turnouts,
|
|
3029
|
-
...
|
|
3054
|
+
...walk2 ? walk2.turnouts.map((t) => ({
|
|
3030
3055
|
...t,
|
|
3031
3056
|
onRoute: t.onRoute === "main" ? "main2:main" : `main2:${t.onRoute}`,
|
|
3032
3057
|
divergeRoute: t.divergeRoute ? `main2:${t.divergeRoute}` : null
|
|
@@ -3056,7 +3081,7 @@ function graphToDoc(pieces, input) {
|
|
|
3056
3081
|
const found = [];
|
|
3057
3082
|
const routesAll = [
|
|
3058
3083
|
...walk.routes.map((r) => ({ r, prefix: "" })),
|
|
3059
|
-
...
|
|
3084
|
+
...walk2 ? walk2.routes.map((r) => ({ r, prefix: "main2:" })) : []
|
|
3060
3085
|
];
|
|
3061
3086
|
const seen = /* @__PURE__ */ new Map();
|
|
3062
3087
|
for (const { r, prefix } of routesAll) {
|
|
@@ -3509,18 +3534,52 @@ function docToGraph(doc, answers = {}, library = BUILT_IN_TRACK_PARTS) {
|
|
|
3509
3534
|
fromPos: a.x0,
|
|
3510
3535
|
toPos: a.x0 + a.geom.lengthInches
|
|
3511
3536
|
}));
|
|
3537
|
+
const attachment = /* @__PURE__ */ new Map();
|
|
3538
|
+
for (const t of turnouts) {
|
|
3539
|
+
const m = mains.find((x) => x.id === t.divergeTrack && x.id !== main.id);
|
|
3540
|
+
if (!m) continue;
|
|
3541
|
+
const from = m.fromPos ?? 0;
|
|
3542
|
+
const to = m.toPos ?? mainLen;
|
|
3543
|
+
if (from > 0 && Math.abs(t.pos - from) < 0.01) attachment.set(m.id, { sw: t, at: "from" });
|
|
3544
|
+
else if (Math.abs(t.pos - to) < 0.01) attachment.set(m.id, { sw: t, at: "to" });
|
|
3545
|
+
else
|
|
3546
|
+
notLaid.push({
|
|
3547
|
+
id: m.id,
|
|
3548
|
+
why: `${t.name || t.id} joins ${m.id} at ${t.pos}\u2033, which is neither end of it \u2014 two mains joined partway along are a crossover, and this document has no connector track between them to lay one from`
|
|
3549
|
+
});
|
|
3550
|
+
}
|
|
3512
3551
|
for (const m of mains) {
|
|
3552
|
+
if (attachment.get(m.id)?.at === "from") continue;
|
|
3513
3553
|
const y = laneOffsetAt(m.lane ?? 0, 0);
|
|
3514
3554
|
const on = turnoutsOn(m.id, y);
|
|
3515
3555
|
for (const l of on) {
|
|
3516
3556
|
pieces.push(l.piece);
|
|
3517
3557
|
laidTurnouts.set(l.t.id, l);
|
|
3518
3558
|
}
|
|
3559
|
+
let endPos = m.toPos ?? mainLen;
|
|
3560
|
+
const closeAt = attachment.get(m.id);
|
|
3561
|
+
if (closeAt?.at === "to") {
|
|
3562
|
+
const l = laidTurnouts.get(closeAt.sw.id);
|
|
3563
|
+
const fj = l ? jointAt(l.piece, l.divergeId) : null;
|
|
3564
|
+
if (fj) {
|
|
3565
|
+
const closing = transition(
|
|
3566
|
+
`${m.id}-close`,
|
|
3567
|
+
{ x: fj.x, y: fj.y, headingDeg: fj.headingDeg },
|
|
3568
|
+
y,
|
|
3569
|
+
-1
|
|
3570
|
+
);
|
|
3571
|
+
if (closing) {
|
|
3572
|
+
pieces.push(closing);
|
|
3573
|
+
const e = jointAt(closing, "b");
|
|
3574
|
+
if (e) endPos = e.x;
|
|
3575
|
+
} else endPos = fj.x;
|
|
3576
|
+
}
|
|
3577
|
+
}
|
|
3519
3578
|
const laidFlex = layFlex(
|
|
3520
3579
|
m.id,
|
|
3521
3580
|
y,
|
|
3522
3581
|
m.fromPos ?? 0,
|
|
3523
|
-
|
|
3582
|
+
endPos,
|
|
3524
3583
|
[...on.map((l) => l.span), ...assemblySpans],
|
|
3525
3584
|
m.flexCuts
|
|
3526
3585
|
);
|
|
@@ -3654,13 +3713,19 @@ function docToGraph(doc, answers = {}, library = BUILT_IN_TRACK_PARTS) {
|
|
|
3654
3713
|
};
|
|
3655
3714
|
const startAt = startOf(main);
|
|
3656
3715
|
if (!startAt) return refuse("nothing was laid on the mainline, so the module has no starting point");
|
|
3657
|
-
const second = mains[1] ?
|
|
3658
|
-
|
|
3659
|
-
|
|
3660
|
-
|
|
3661
|
-
|
|
3662
|
-
|
|
3663
|
-
|
|
3716
|
+
const second = mains[1] ? attachment.get(mains[1].id)?.at === "from" ? (() => {
|
|
3717
|
+
const l = laidTurnouts.get(attachment.get(mains[1].id).sw.id);
|
|
3718
|
+
return l ? { piece: l.piece.id, joint: l.divergeId } : null;
|
|
3719
|
+
})() : startOf(mains[1]) : null;
|
|
3720
|
+
const graph = { pieces, startAt, ...second ? { start2: second } : {} };
|
|
3721
|
+
const derived = graphToDoc(pieces, {
|
|
3722
|
+
startAt,
|
|
3723
|
+
start2: second ?? null,
|
|
3724
|
+
base: doc,
|
|
3725
|
+
library
|
|
3726
|
+
});
|
|
3727
|
+
warnings.push(...derived.warnings);
|
|
3728
|
+
return { graph, refused: null, notLaid, warnings };
|
|
3664
3729
|
}
|
|
3665
3730
|
function frogCasting(cl, opts = {}) {
|
|
3666
3731
|
const g = opts.gaugeInches ?? RAIL_GAUGE_INCHES;
|