@willcgage/module-schematic 0.65.0 → 0.67.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 CHANGED
@@ -703,18 +703,20 @@ function stateToDoc(state, recordNumber) {
703
703
  ]
704
704
  ) : [
705
705
  { id: "A", label: "West", tracks: [{ trackId: MAIN_TRACK_ID, lane: 0, config: state.configA }] },
706
- // Non-loop modules always have a real B ("none" never applies).
707
- {
708
- id: "B",
709
- label: "East",
710
- tracks: [
711
- {
712
- trackId: MAIN_TRACK_ID,
713
- lane: 0,
714
- config: state.configB === "none" ? "single" : state.configB
715
- }
716
- ]
717
- }
706
+ // ⚠️ `configB: "none"` means the module HAS NO FAR ENDPLATE, and
707
+ // that is not loop-only (#184). An *end of the line* or a *pocket*
708
+ // presents one conforming face and the track simply stops. The
709
+ // standard governs the ends a module offers for joining; it never
710
+ // required a module to offer two. This used to coerce "none" to
711
+ // "single" and emit a B regardless, so a single-ended module was
712
+ // impossible to author.
713
+ ...state.configB !== "none" ? [
714
+ {
715
+ id: "B",
716
+ label: "East",
717
+ tracks: [{ trackId: MAIN_TRACK_ID, lane: 0, config: state.configB }]
718
+ }
719
+ ] : []
718
720
  ],
719
721
  // Branch endplates C, D, … — junction connections at pos, off one side
720
722
  // (#170). A set can carry several (e.g. a second railroad through).
@@ -1779,8 +1781,9 @@ function moduleFeatures(doc) {
1779
1781
  ...crossings.flatMap((x) => [x.laneA, x.laneB]),
1780
1782
  ...crossovers.flatMap((x) => [x.fromLane, x.toLane])
1781
1783
  ];
1782
- let upLane = Math.max(...baseLanes, 0);
1783
- let downLane = Math.min(...baseLanes, 0);
1784
+ const LANE_GAP_FROM_OTHERS = 2;
1785
+ let upLane = Math.max(...baseLanes, 0) + (LANE_GAP_FROM_OTHERS - 1);
1786
+ let downLane = Math.min(...baseLanes, 0) - (LANE_GAP_FROM_OTHERS - 1);
1784
1787
  const branchConnectors = doc.endplates.filter(
1785
1788
  (e) => e.id !== "A" && e.id !== "B" && e.at && !!e.trackId && (doc.tracks ?? []).some((t) => t.id === e.trackId)
1786
1789
  ).map((e) => {
@@ -1791,10 +1794,6 @@ function moduleFeatures(doc) {
1791
1794
  const lane = side === "down" ? --downLane : ++upLane;
1792
1795
  const runInches = pathLengthInches(trk.path) || Math.abs(e.at.pos - startPos) || FREEMO_ENDPLATE_WIDTH_MIN_INCHES;
1793
1796
  const toB = e.at.pos >= startPos;
1794
- const fits = (p) => p >= 0 && p <= len;
1795
- const ahead = startPos + runInches;
1796
- const behind = startPos - runInches;
1797
- const endPos = toB && fits(ahead) ? ahead : !toB && fits(behind) ? behind : fits(toB ? behind : ahead) ? toB ? behind : ahead : ahead;
1798
1797
  return {
1799
1798
  id: e.id,
1800
1799
  label: e.label ?? e.id,
@@ -1805,7 +1804,7 @@ function moduleFeatures(doc) {
1805
1804
  fromLane: sw ? trackLane.get(sw.onTrack) ?? 0 : 0,
1806
1805
  side,
1807
1806
  lane,
1808
- endFrac: clampFrac(endPos),
1807
+ endFrac: toB ? 1 : 0,
1809
1808
  lengthInches: runInches
1810
1809
  };
1811
1810
  });
@@ -1987,7 +1986,7 @@ function deriveEndplatePoses(geo) {
1987
1986
  trackOffsets: offsetsFor(cfg(0), half)
1988
1987
  })
1989
1988
  );
1990
- const noB = geo.geometryType === "dead_end" || geo.loop === true;
1989
+ const noB = geo.geometryType === "dead_end" || geo.loop === true || geo.endplateConfigs?.[1] === "none";
1991
1990
  const end = sectionedEndPose({ sections: geo.sections });
1992
1991
  if (!noB && end) {
1993
1992
  poses.push(