@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 +19 -20
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +37 -22
- package/dist/index.d.ts +37 -22
- package/dist/index.js +19 -20
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -789,9 +789,11 @@ interface EditorBranch {
|
|
|
789
789
|
* draws track to it; the plate is placed first, connected later). */
|
|
790
790
|
trackId?: string | null;
|
|
791
791
|
}
|
|
792
|
-
/** Endplate B
|
|
793
|
-
*
|
|
794
|
-
*
|
|
792
|
+
/** Endplate B's configuration — or `"none"`, meaning **the module has no far
|
|
793
|
+
* endplate**: an end of the line, a pocket, or a loop's pure turnback. On a
|
|
794
|
+
* loop, a standard endplate B instead makes the balloon an INTERCHANGE (a second
|
|
795
|
+
* route connects there, e.g. Seaford). A module presents one conforming face,
|
|
796
|
+
* or two, or more; the standard governs the faces it offers, not how many (#184). */
|
|
795
797
|
type EndplateBConfig = TrackConfig | "none";
|
|
796
798
|
interface EditorState {
|
|
797
799
|
lengthInches: number;
|
|
@@ -972,24 +974,32 @@ interface DrawCrossover {
|
|
|
972
974
|
toLane: number;
|
|
973
975
|
}
|
|
974
976
|
/**
|
|
975
|
-
* A route leaving the module at a third endplate
|
|
976
|
-
*
|
|
977
|
-
* `posFrac`, drops to its own `lane`, then runs to `endFrac` and ends at an
|
|
978
|
-
* endplate face.
|
|
977
|
+
* A route leaving the module at a third endplate — and an endplate is an
|
|
978
|
+
* endplate, whatever letter it carries (#183).
|
|
979
979
|
*
|
|
980
|
-
*
|
|
981
|
-
*
|
|
982
|
-
*
|
|
983
|
-
* route
|
|
984
|
-
*
|
|
985
|
-
*
|
|
980
|
+
* There is no split in the standard between "the two ends" and "the others": an
|
|
981
|
+
* endplate is the standardised face where a module joins another module, and a
|
|
982
|
+
* module may present two, three, or one. So a route to C is drawn the way a
|
|
983
|
+
* route to A or B is drawn — **it runs to the edge of the module and terminates
|
|
984
|
+
* in an endplate face carrying its letter**, rather than stopping partway along
|
|
985
|
+
* the strip as a stub.
|
|
986
|
+
*
|
|
987
|
+
* ⚠️ Because it runs the full width it would otherwise read as just another
|
|
988
|
+
* parallel main, which is exactly the confusion a dispatcher must not have. Its
|
|
989
|
+
* lane is therefore placed with a clear GAP beyond every other lane (see
|
|
990
|
+
* `laneGapFromOthers`), and it ends at a plate rather than running off the edge.
|
|
991
|
+
* The two requirements — full width, and not-a-parallel-main — are in tension by
|
|
992
|
+
* design, and the separation is what resolves it.
|
|
993
|
+
*
|
|
994
|
+
* The LETTER is the module's own fact and is fine to draw. The DESTINATION
|
|
995
|
+
* ("to Fillmore") depends on which module is physically attached at that
|
|
996
|
+
* junction, so it stays Free-Dispatcher's to derive at runtime.
|
|
986
997
|
*/
|
|
987
998
|
interface BranchConnector {
|
|
988
999
|
/** Endplate id — "C", "D", … */
|
|
989
1000
|
id: string;
|
|
990
|
-
/** The
|
|
991
|
-
* physically attached, so FD derives
|
|
992
|
-
* the owner's local name, for tooltips and FD's fallback. */
|
|
1001
|
+
/** The owner's local name for the plate. NOT the destination — that depends
|
|
1002
|
+
* on what's physically attached, so FD derives it at runtime. */
|
|
993
1003
|
label: string;
|
|
994
1004
|
/** The route's own name, from the track. */
|
|
995
1005
|
name: string;
|
|
@@ -1005,12 +1015,15 @@ interface BranchConnector {
|
|
|
1005
1015
|
fromLane: number;
|
|
1006
1016
|
/** Which side of the module it exits. */
|
|
1007
1017
|
side: "up" | "down";
|
|
1008
|
-
/** The branch's own lane, signed by `side
|
|
1009
|
-
* lane
|
|
1018
|
+
/** The branch's own lane, signed by `side`, placed a clear GAP beyond every
|
|
1019
|
+
* other lane so it can't be mistaken for a parallel main — already folded
|
|
1020
|
+
* into laneMin/laneMax. */
|
|
1010
1021
|
lane: number;
|
|
1011
|
-
/** Where the run ends
|
|
1022
|
+
/** Where the run ends and the endplate face is drawn: the module EDGE, 0 or
|
|
1023
|
+
* 1, because this is an end of the module like any other (#183). */
|
|
1012
1024
|
endFrac: number;
|
|
1013
|
-
/** The route's own arc length, inches.
|
|
1025
|
+
/** The route's own arc length on this module, inches — for the tooltip. The
|
|
1026
|
+
* drawn run is the strip's width, not this. */
|
|
1014
1027
|
lengthInches: number;
|
|
1015
1028
|
}
|
|
1016
1029
|
/** An industry — draw a car-spot span beside its track's lane, on `side`, with
|
|
@@ -1656,8 +1669,10 @@ interface ModuleGeometryInput {
|
|
|
1656
1669
|
geometryType?: string | null;
|
|
1657
1670
|
geometryDegrees?: number | null;
|
|
1658
1671
|
geometryOffsetInches?: number | null;
|
|
1659
|
-
/** Axial endplate configs (A first, then B). Missing → single.
|
|
1660
|
-
|
|
1672
|
+
/** Axial endplate configs (A first, then B). Missing → single. `"none"` at B
|
|
1673
|
+
* means the module has no far endplate at all — an end of the line, a pocket,
|
|
1674
|
+
* or a turnback (#184). */
|
|
1675
|
+
endplateConfigs?: ("single" | "double" | "none" | null | undefined)[];
|
|
1661
1676
|
/** Branch endplates (from the schematic doc, #170), positioned along the
|
|
1662
1677
|
* mainline axis. */
|
|
1663
1678
|
branches?: {
|
package/dist/index.d.ts
CHANGED
|
@@ -789,9 +789,11 @@ interface EditorBranch {
|
|
|
789
789
|
* draws track to it; the plate is placed first, connected later). */
|
|
790
790
|
trackId?: string | null;
|
|
791
791
|
}
|
|
792
|
-
/** Endplate B
|
|
793
|
-
*
|
|
794
|
-
*
|
|
792
|
+
/** Endplate B's configuration — or `"none"`, meaning **the module has no far
|
|
793
|
+
* endplate**: an end of the line, a pocket, or a loop's pure turnback. On a
|
|
794
|
+
* loop, a standard endplate B instead makes the balloon an INTERCHANGE (a second
|
|
795
|
+
* route connects there, e.g. Seaford). A module presents one conforming face,
|
|
796
|
+
* or two, or more; the standard governs the faces it offers, not how many (#184). */
|
|
795
797
|
type EndplateBConfig = TrackConfig | "none";
|
|
796
798
|
interface EditorState {
|
|
797
799
|
lengthInches: number;
|
|
@@ -972,24 +974,32 @@ interface DrawCrossover {
|
|
|
972
974
|
toLane: number;
|
|
973
975
|
}
|
|
974
976
|
/**
|
|
975
|
-
* A route leaving the module at a third endplate
|
|
976
|
-
*
|
|
977
|
-
* `posFrac`, drops to its own `lane`, then runs to `endFrac` and ends at an
|
|
978
|
-
* endplate face.
|
|
977
|
+
* A route leaving the module at a third endplate — and an endplate is an
|
|
978
|
+
* endplate, whatever letter it carries (#183).
|
|
979
979
|
*
|
|
980
|
-
*
|
|
981
|
-
*
|
|
982
|
-
*
|
|
983
|
-
* route
|
|
984
|
-
*
|
|
985
|
-
*
|
|
980
|
+
* There is no split in the standard between "the two ends" and "the others": an
|
|
981
|
+
* endplate is the standardised face where a module joins another module, and a
|
|
982
|
+
* module may present two, three, or one. So a route to C is drawn the way a
|
|
983
|
+
* route to A or B is drawn — **it runs to the edge of the module and terminates
|
|
984
|
+
* in an endplate face carrying its letter**, rather than stopping partway along
|
|
985
|
+
* the strip as a stub.
|
|
986
|
+
*
|
|
987
|
+
* ⚠️ Because it runs the full width it would otherwise read as just another
|
|
988
|
+
* parallel main, which is exactly the confusion a dispatcher must not have. Its
|
|
989
|
+
* lane is therefore placed with a clear GAP beyond every other lane (see
|
|
990
|
+
* `laneGapFromOthers`), and it ends at a plate rather than running off the edge.
|
|
991
|
+
* The two requirements — full width, and not-a-parallel-main — are in tension by
|
|
992
|
+
* design, and the separation is what resolves it.
|
|
993
|
+
*
|
|
994
|
+
* The LETTER is the module's own fact and is fine to draw. The DESTINATION
|
|
995
|
+
* ("to Fillmore") depends on which module is physically attached at that
|
|
996
|
+
* junction, so it stays Free-Dispatcher's to derive at runtime.
|
|
986
997
|
*/
|
|
987
998
|
interface BranchConnector {
|
|
988
999
|
/** Endplate id — "C", "D", … */
|
|
989
1000
|
id: string;
|
|
990
|
-
/** The
|
|
991
|
-
* physically attached, so FD derives
|
|
992
|
-
* the owner's local name, for tooltips and FD's fallback. */
|
|
1001
|
+
/** The owner's local name for the plate. NOT the destination — that depends
|
|
1002
|
+
* on what's physically attached, so FD derives it at runtime. */
|
|
993
1003
|
label: string;
|
|
994
1004
|
/** The route's own name, from the track. */
|
|
995
1005
|
name: string;
|
|
@@ -1005,12 +1015,15 @@ interface BranchConnector {
|
|
|
1005
1015
|
fromLane: number;
|
|
1006
1016
|
/** Which side of the module it exits. */
|
|
1007
1017
|
side: "up" | "down";
|
|
1008
|
-
/** The branch's own lane, signed by `side
|
|
1009
|
-
* lane
|
|
1018
|
+
/** The branch's own lane, signed by `side`, placed a clear GAP beyond every
|
|
1019
|
+
* other lane so it can't be mistaken for a parallel main — already folded
|
|
1020
|
+
* into laneMin/laneMax. */
|
|
1010
1021
|
lane: number;
|
|
1011
|
-
/** Where the run ends
|
|
1022
|
+
/** Where the run ends and the endplate face is drawn: the module EDGE, 0 or
|
|
1023
|
+
* 1, because this is an end of the module like any other (#183). */
|
|
1012
1024
|
endFrac: number;
|
|
1013
|
-
/** The route's own arc length, inches.
|
|
1025
|
+
/** The route's own arc length on this module, inches — for the tooltip. The
|
|
1026
|
+
* drawn run is the strip's width, not this. */
|
|
1014
1027
|
lengthInches: number;
|
|
1015
1028
|
}
|
|
1016
1029
|
/** An industry — draw a car-spot span beside its track's lane, on `side`, with
|
|
@@ -1656,8 +1669,10 @@ interface ModuleGeometryInput {
|
|
|
1656
1669
|
geometryType?: string | null;
|
|
1657
1670
|
geometryDegrees?: number | null;
|
|
1658
1671
|
geometryOffsetInches?: number | null;
|
|
1659
|
-
/** Axial endplate configs (A first, then B). Missing → single.
|
|
1660
|
-
|
|
1672
|
+
/** Axial endplate configs (A first, then B). Missing → single. `"none"` at B
|
|
1673
|
+
* means the module has no far endplate at all — an end of the line, a pocket,
|
|
1674
|
+
* or a turnback (#184). */
|
|
1675
|
+
endplateConfigs?: ("single" | "double" | "none" | null | undefined)[];
|
|
1661
1676
|
/** Branch endplates (from the schematic doc, #170), positioned along the
|
|
1662
1677
|
* mainline axis. */
|
|
1663
1678
|
branches?: {
|
package/dist/index.js
CHANGED
|
@@ -701,18 +701,20 @@ function stateToDoc(state, recordNumber) {
|
|
|
701
701
|
]
|
|
702
702
|
) : [
|
|
703
703
|
{ id: "A", label: "West", tracks: [{ trackId: MAIN_TRACK_ID, lane: 0, config: state.configA }] },
|
|
704
|
-
//
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
704
|
+
// ⚠️ `configB: "none"` means the module HAS NO FAR ENDPLATE, and
|
|
705
|
+
// that is not loop-only (#184). An *end of the line* or a *pocket*
|
|
706
|
+
// presents one conforming face and the track simply stops. The
|
|
707
|
+
// standard governs the ends a module offers for joining; it never
|
|
708
|
+
// required a module to offer two. This used to coerce "none" to
|
|
709
|
+
// "single" and emit a B regardless, so a single-ended module was
|
|
710
|
+
// impossible to author.
|
|
711
|
+
...state.configB !== "none" ? [
|
|
712
|
+
{
|
|
713
|
+
id: "B",
|
|
714
|
+
label: "East",
|
|
715
|
+
tracks: [{ trackId: MAIN_TRACK_ID, lane: 0, config: state.configB }]
|
|
716
|
+
}
|
|
717
|
+
] : []
|
|
716
718
|
],
|
|
717
719
|
// Branch endplates C, D, … — junction connections at pos, off one side
|
|
718
720
|
// (#170). A set can carry several (e.g. a second railroad through).
|
|
@@ -1777,8 +1779,9 @@ function moduleFeatures(doc) {
|
|
|
1777
1779
|
...crossings.flatMap((x) => [x.laneA, x.laneB]),
|
|
1778
1780
|
...crossovers.flatMap((x) => [x.fromLane, x.toLane])
|
|
1779
1781
|
];
|
|
1780
|
-
|
|
1781
|
-
let
|
|
1782
|
+
const LANE_GAP_FROM_OTHERS = 2;
|
|
1783
|
+
let upLane = Math.max(...baseLanes, 0) + (LANE_GAP_FROM_OTHERS - 1);
|
|
1784
|
+
let downLane = Math.min(...baseLanes, 0) - (LANE_GAP_FROM_OTHERS - 1);
|
|
1782
1785
|
const branchConnectors = doc.endplates.filter(
|
|
1783
1786
|
(e) => e.id !== "A" && e.id !== "B" && e.at && !!e.trackId && (doc.tracks ?? []).some((t) => t.id === e.trackId)
|
|
1784
1787
|
).map((e) => {
|
|
@@ -1789,10 +1792,6 @@ function moduleFeatures(doc) {
|
|
|
1789
1792
|
const lane = side === "down" ? --downLane : ++upLane;
|
|
1790
1793
|
const runInches = pathLengthInches(trk.path) || Math.abs(e.at.pos - startPos) || FREEMO_ENDPLATE_WIDTH_MIN_INCHES;
|
|
1791
1794
|
const toB = e.at.pos >= startPos;
|
|
1792
|
-
const fits = (p) => p >= 0 && p <= len;
|
|
1793
|
-
const ahead = startPos + runInches;
|
|
1794
|
-
const behind = startPos - runInches;
|
|
1795
|
-
const endPos = toB && fits(ahead) ? ahead : !toB && fits(behind) ? behind : fits(toB ? behind : ahead) ? toB ? behind : ahead : ahead;
|
|
1796
1795
|
return {
|
|
1797
1796
|
id: e.id,
|
|
1798
1797
|
label: e.label ?? e.id,
|
|
@@ -1803,7 +1802,7 @@ function moduleFeatures(doc) {
|
|
|
1803
1802
|
fromLane: sw ? trackLane.get(sw.onTrack) ?? 0 : 0,
|
|
1804
1803
|
side,
|
|
1805
1804
|
lane,
|
|
1806
|
-
endFrac:
|
|
1805
|
+
endFrac: toB ? 1 : 0,
|
|
1807
1806
|
lengthInches: runInches
|
|
1808
1807
|
};
|
|
1809
1808
|
});
|
|
@@ -1985,7 +1984,7 @@ function deriveEndplatePoses(geo) {
|
|
|
1985
1984
|
trackOffsets: offsetsFor(cfg(0), half)
|
|
1986
1985
|
})
|
|
1987
1986
|
);
|
|
1988
|
-
const noB = geo.geometryType === "dead_end" || geo.loop === true;
|
|
1987
|
+
const noB = geo.geometryType === "dead_end" || geo.loop === true || geo.endplateConfigs?.[1] === "none";
|
|
1989
1988
|
const end = sectionedEndPose({ sections: geo.sections });
|
|
1990
1989
|
if (!noB && end) {
|
|
1991
1990
|
poses.push(
|