@willcgage/module-schematic 0.33.0 → 0.35.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.d.cts CHANGED
@@ -117,6 +117,13 @@ interface SchematicTurnout {
117
117
  * the same way) instead of leaving as a straight diagonal. Physical-render
118
118
  * only; the operations view stays topological. */
119
119
  curved?: boolean | null;
120
+ /** Rotate the turnout 180° — the points face the other way along the track.
121
+ * HAND is which turnout you own; how it's INSTALLED is a separate choice, and
122
+ * the drawn orientation can't always be inferred from where the diverging
123
+ * track happens to run. A siding at the far end of a module is the case that
124
+ * forces it: the body has nowhere to go but back toward the module, so the
125
+ * derived facing comes out backwards. */
126
+ flipped?: boolean | null;
120
127
  }
121
128
  interface SchematicSignal {
122
129
  id: string;
@@ -600,6 +607,8 @@ interface EditorTurnout {
600
607
  kind: TurnoutKind;
601
608
  /** Frog number ("size") — #4, #6, #8, etc. Governs the diverging angle. */
602
609
  size?: number;
610
+ /** Rotate the turnout 180° — the points face the other way (#turnout-flip). */
611
+ flipped?: boolean;
603
612
  /** A curved turnout — the diverging route bows into an arc rather than a
604
613
  * straight diagonal. Physical-render only (the operations view is topological). */
605
614
  curved?: boolean;
@@ -912,7 +921,10 @@ interface ModuleFeatures {
912
921
  * right-hand throws to the opposite side. `kind` is the source of truth for the
913
922
  * drawn side (#bug1) — the stored lane's sign is reconciled to match it.
914
923
  */
915
- declare function divergeSideForHand(kind: TurnoutKind | undefined, stubDir: number): -1 | 0 | 1;
924
+ declare function divergeSideForHand(kind: TurnoutKind | undefined, stubDir: number,
925
+ /** The turnout is installed the other way round — the points face the far
926
+ * direction, which swaps the side the diverging route leaves on. */
927
+ flipped?: boolean | null): -1 | 0 | 1;
916
928
  /**
917
929
  * Resolve a schematic doc into positioned drawables. `pos` (inches) becomes a
918
930
  * fraction of the module length; endplate A = 0, B = length; turnouts sit at
package/dist/index.d.ts CHANGED
@@ -117,6 +117,13 @@ interface SchematicTurnout {
117
117
  * the same way) instead of leaving as a straight diagonal. Physical-render
118
118
  * only; the operations view stays topological. */
119
119
  curved?: boolean | null;
120
+ /** Rotate the turnout 180° — the points face the other way along the track.
121
+ * HAND is which turnout you own; how it's INSTALLED is a separate choice, and
122
+ * the drawn orientation can't always be inferred from where the diverging
123
+ * track happens to run. A siding at the far end of a module is the case that
124
+ * forces it: the body has nowhere to go but back toward the module, so the
125
+ * derived facing comes out backwards. */
126
+ flipped?: boolean | null;
120
127
  }
121
128
  interface SchematicSignal {
122
129
  id: string;
@@ -600,6 +607,8 @@ interface EditorTurnout {
600
607
  kind: TurnoutKind;
601
608
  /** Frog number ("size") — #4, #6, #8, etc. Governs the diverging angle. */
602
609
  size?: number;
610
+ /** Rotate the turnout 180° — the points face the other way (#turnout-flip). */
611
+ flipped?: boolean;
603
612
  /** A curved turnout — the diverging route bows into an arc rather than a
604
613
  * straight diagonal. Physical-render only (the operations view is topological). */
605
614
  curved?: boolean;
@@ -912,7 +921,10 @@ interface ModuleFeatures {
912
921
  * right-hand throws to the opposite side. `kind` is the source of truth for the
913
922
  * drawn side (#bug1) — the stored lane's sign is reconciled to match it.
914
923
  */
915
- declare function divergeSideForHand(kind: TurnoutKind | undefined, stubDir: number): -1 | 0 | 1;
924
+ declare function divergeSideForHand(kind: TurnoutKind | undefined, stubDir: number,
925
+ /** The turnout is installed the other way round — the points face the far
926
+ * direction, which swaps the side the diverging route leaves on. */
927
+ flipped?: boolean | null): -1 | 0 | 1;
916
928
  /**
917
929
  * Resolve a schematic doc into positioned drawables. `pos` (inches) becomes a
918
930
  * fraction of the module length; endplate A = 0, B = length; turnouts sit at
package/dist/index.js CHANGED
@@ -553,18 +553,22 @@ function main1Track(state) {
553
553
  }
554
554
  function main2Track(state) {
555
555
  const bothDouble = state.configA === "double" && state.configB === "double";
556
- const sw = state.turnouts.find(isTransitionTurnout);
556
+ const sws = state.turnouts.filter((t) => isTransitionTurnout(t) && t.divergeTrack === MAIN2_TRACK_ID).sort((a, b) => a.pos - b.pos);
557
557
  const lane = state.mainsSwapped ? 0 : 1;
558
- if (bothDouble || !sw || sw.divergeTrack !== MAIN2_TRACK_ID) {
558
+ if (bothDouble || !sws.length) {
559
559
  return { id: MAIN2_TRACK_ID, role: "main", lane, from: "A", to: "B" };
560
560
  }
561
- return state.configA === "double" ? (
562
- // Double at A: Main 2 runs from A and ends at the turnout.
563
- { id: MAIN2_TRACK_ID, role: "main", lane, fromPos: 0, toPos: sw.pos }
564
- ) : (
565
- // Double at B: Main 2 begins at the turnout and runs to B.
566
- { id: MAIN2_TRACK_ID, role: "main", lane, fromPos: sw.pos, toPos: state.lengthInches }
567
- );
561
+ const track = (fromPos, toPos) => ({
562
+ id: MAIN2_TRACK_ID,
563
+ role: "main",
564
+ lane,
565
+ fromPos,
566
+ toPos
567
+ });
568
+ if (state.configA === "double") return track(0, sws[0].pos);
569
+ if (state.configB === "double") return track(sws[0].pos, state.lengthInches);
570
+ if (sws.length >= 2) return track(sws[0].pos, sws[sws.length - 1].pos);
571
+ return track(sws[0].pos, state.lengthInches);
568
572
  }
569
573
  function buildTransition(state) {
570
574
  const aDouble = state.configA === "double";
@@ -682,7 +686,12 @@ function stateToDoc(state, recordNumber) {
682
686
  // double) Main 2 only runs from the mainline turnout to the double end —
683
687
  // the turnout that diverges to main2 is the single source of truth for
684
688
  // where the transition sits (fd#175 / FMN-0038).
685
- ...!state.loop && (state.configA === "double" || state.configB === "double") ? [main2Track(state)] : [],
689
+ // …and on a module that's SINGLE at both ends but goes double in the
690
+ // middle to form a siding: the turnouts are what make Main 2 exist, so a
691
+ // pair of them is reason enough to emit it (#118). Without this the
692
+ // second main simply wasn't in the doc, and neither the board nor the
693
+ // dispatcher panel could draw it.
694
+ ...!state.loop && (state.configA === "double" || state.configB === "double" || state.turnouts.some((t) => isTransitionTurnout(t) && t.divergeTrack === MAIN2_TRACK_ID)) ? [main2Track(state)] : [],
686
695
  ...state.loop && state.loopReturn === "main2" ? [{ id: MAIN2_TRACK_ID, role: "main", lane: 1, fromPos: 0, toPos: state.lengthInches }] : [],
687
696
  ...state.extraTracks.map((t) => ({
688
697
  id: t.id,
@@ -705,7 +714,8 @@ function stateToDoc(state, recordNumber) {
705
714
  kind: t.kind,
706
715
  name: t.name || void 0,
707
716
  ...t.size ? { size: t.size } : {},
708
- ...t.curved ? { curved: true } : {}
717
+ ...t.curved ? { curved: true } : {},
718
+ ...t.flipped ? { flipped: true } : {}
709
719
  })),
710
720
  ...state.crossings.length > 0 ? {
711
721
  crossings: state.crossings.map((x) => ({
@@ -876,7 +886,8 @@ function docToState(doc, fallbackLength, moduleTracks = []) {
876
886
  divergeTrack: t.divergeTrack,
877
887
  kind: t.kind ?? "right",
878
888
  ...t.size ? { size: t.size } : {},
879
- ...t.curved ? { curved: true } : {}
889
+ ...t.curved ? { curved: true } : {},
890
+ ...t.flipped ? { flipped: true } : {}
880
891
  })),
881
892
  controlPoints: readControlPoints(d, sc),
882
893
  industries: (d.industries ?? []).map((ind) => ({
@@ -1009,9 +1020,9 @@ function buildCrossover(state) {
1009
1020
  ];
1010
1021
  return { track, turnouts };
1011
1022
  }
1012
- function divergeSideForHand(kind, stubDir) {
1023
+ function divergeSideForHand(kind, stubDir, flipped) {
1013
1024
  if (kind !== "left" && kind !== "right") return 0;
1014
- const s = stubDir >= 0 ? 1 : -1;
1025
+ const s = (stubDir >= 0 ? 1 : -1) * (flipped ? -1 : 1);
1015
1026
  return kind === "left" ? s : -s;
1016
1027
  }
1017
1028
  function moduleFeatures(doc) {