@willcgage/module-schematic 0.13.3 → 0.15.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 +75 -35
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +41 -1
- package/dist/index.d.ts +41 -1
- package/dist/index.js +72 -36
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
+
var FREEMO_ENDPLATE_WIDTH_MIN_INCHES = 12;
|
|
5
|
+
var FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES = 24;
|
|
6
|
+
function endplateWidthInches(ep) {
|
|
7
|
+
const w = ep?.widthInches;
|
|
8
|
+
return typeof w === "number" && w > 0 ? w : FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES;
|
|
9
|
+
}
|
|
10
|
+
function benchworkOutline(doc) {
|
|
11
|
+
const pts = (doc?.outline ?? []).filter(
|
|
12
|
+
(p) => p && Number.isFinite(p.x) && Number.isFinite(p.y)
|
|
13
|
+
);
|
|
14
|
+
return pts.length >= 3 ? pts : null;
|
|
15
|
+
}
|
|
4
16
|
function isLoopDoc(doc) {
|
|
5
17
|
return doc.loop === true || doc.endplates.length === 1;
|
|
6
18
|
}
|
|
@@ -32,6 +44,8 @@ function emptyEditorState(lengthInches) {
|
|
|
32
44
|
crossings: [],
|
|
33
45
|
branches: [],
|
|
34
46
|
poseOverrides: {},
|
|
47
|
+
endplateWidths: {},
|
|
48
|
+
outline: [],
|
|
35
49
|
controlPoints: []
|
|
36
50
|
};
|
|
37
51
|
}
|
|
@@ -93,6 +107,12 @@ function withPoses(endplates, overrides) {
|
|
|
93
107
|
(e) => overrides[e.id] ? { ...e, pose: overrides[e.id] } : e
|
|
94
108
|
);
|
|
95
109
|
}
|
|
110
|
+
function withWidths(endplates, widths) {
|
|
111
|
+
return endplates.map((e) => {
|
|
112
|
+
const w = widths[e.id];
|
|
113
|
+
return typeof w === "number" && w > 0 ? { ...e, widthInches: w } : e;
|
|
114
|
+
});
|
|
115
|
+
}
|
|
96
116
|
function stateToDoc(state, recordNumber) {
|
|
97
117
|
return {
|
|
98
118
|
version: 1,
|
|
@@ -100,42 +120,45 @@ function stateToDoc(state, recordNumber) {
|
|
|
100
120
|
lengthInches: state.lengthInches,
|
|
101
121
|
...state.loop ? { loop: true } : {},
|
|
102
122
|
...state.loop && state.loopReturn === "main2" ? { loopReturn: "main2" } : {},
|
|
103
|
-
endplates:
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
) : [
|
|
114
|
-
{ id: "A", label: "West", tracks: [{ trackId: MAIN_TRACK_ID, lane: 0, config: state.configA }] },
|
|
115
|
-
// Non-loop modules always have a real B ("none" never applies).
|
|
116
|
-
{
|
|
117
|
-
id: "B",
|
|
118
|
-
label: "East",
|
|
119
|
-
tracks: [
|
|
120
|
-
{
|
|
121
|
-
trackId: MAIN_TRACK_ID,
|
|
122
|
-
lane: 0,
|
|
123
|
-
config: state.configB === "none" ? "single" : state.configB
|
|
124
|
-
}
|
|
123
|
+
endplates: withWidths(
|
|
124
|
+
withPoses(
|
|
125
|
+
[
|
|
126
|
+
...state.loop ? (
|
|
127
|
+
// Balloon loop: A is the entry. A standard endplate B on the balloon
|
|
128
|
+
// makes it an INTERCHANGE (second route connects at the loop, e.g.
|
|
129
|
+
// Seaford); configB "none" makes it a pure turnback.
|
|
130
|
+
[
|
|
131
|
+
{ id: "A", label: "Entry", tracks: [{ trackId: MAIN_TRACK_ID, lane: 0, config: state.configA }] },
|
|
132
|
+
...state.configB !== "none" ? [{ id: "B", label: "Interchange", tracks: [{ trackId: MAIN_TRACK_ID, lane: 0, config: state.configB }] }] : []
|
|
125
133
|
]
|
|
126
|
-
|
|
134
|
+
) : [
|
|
135
|
+
{ id: "A", label: "West", tracks: [{ trackId: MAIN_TRACK_ID, lane: 0, config: state.configA }] },
|
|
136
|
+
// Non-loop modules always have a real B ("none" never applies).
|
|
137
|
+
{
|
|
138
|
+
id: "B",
|
|
139
|
+
label: "East",
|
|
140
|
+
tracks: [
|
|
141
|
+
{
|
|
142
|
+
trackId: MAIN_TRACK_ID,
|
|
143
|
+
lane: 0,
|
|
144
|
+
config: state.configB === "none" ? "single" : state.configB
|
|
145
|
+
}
|
|
146
|
+
]
|
|
147
|
+
}
|
|
148
|
+
],
|
|
149
|
+
// Branch endplates C, D, … — junction connections at pos, off one side
|
|
150
|
+
// (#170). A set can carry several (e.g. a second railroad through).
|
|
151
|
+
...state.branches.map((b, i) => ({
|
|
152
|
+
id: String.fromCharCode(67 + i),
|
|
153
|
+
// C, D, E…
|
|
154
|
+
label: b.label || `Branch ${i + 1}`,
|
|
155
|
+
tracks: [{ trackId: MAIN_TRACK_ID, lane: 0, config: b.config }],
|
|
156
|
+
at: { pos: b.pos, side: b.side }
|
|
157
|
+
}))
|
|
127
158
|
],
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
id: String.fromCharCode(67 + i),
|
|
132
|
-
// C, D, E…
|
|
133
|
-
label: b.label || `Branch ${i + 1}`,
|
|
134
|
-
tracks: [{ trackId: MAIN_TRACK_ID, lane: 0, config: b.config }],
|
|
135
|
-
at: { pos: b.pos, side: b.side }
|
|
136
|
-
}))
|
|
137
|
-
],
|
|
138
|
-
state.poseOverrides
|
|
159
|
+
state.poseOverrides
|
|
160
|
+
),
|
|
161
|
+
state.endplateWidths
|
|
139
162
|
),
|
|
140
163
|
tracks: [
|
|
141
164
|
state.loop ? (
|
|
@@ -192,7 +215,10 @@ function stateToDoc(state, recordNumber) {
|
|
|
192
215
|
kind: "mast",
|
|
193
216
|
side: s.side
|
|
194
217
|
}))
|
|
195
|
-
}))
|
|
218
|
+
})),
|
|
219
|
+
// Benchwork footprint outline (module-local inches); only when it's a real
|
|
220
|
+
// ring (≥ 3 vertices).
|
|
221
|
+
...state.outline.length >= 3 ? { outline: state.outline } : {}
|
|
196
222
|
};
|
|
197
223
|
}
|
|
198
224
|
function docToState(doc, fallbackLength, moduleTracks = []) {
|
|
@@ -261,6 +287,14 @@ function docToState(doc, fallbackLength, moduleTracks = []) {
|
|
|
261
287
|
(e) => e.id !== "A" && e.id !== "B" && e.at
|
|
262
288
|
);
|
|
263
289
|
const poseOverrides = poseOverridesFromDoc(d);
|
|
290
|
+
const endplateWidths = {};
|
|
291
|
+
for (const e of d.endplates ?? []) {
|
|
292
|
+
if (typeof e.widthInches === "number" && e.widthInches > 0)
|
|
293
|
+
endplateWidths[e.id] = e.widthInches;
|
|
294
|
+
}
|
|
295
|
+
const outline = (d.outline ?? []).filter(
|
|
296
|
+
(p) => p && Number.isFinite(p.x) && Number.isFinite(p.y)
|
|
297
|
+
);
|
|
264
298
|
return {
|
|
265
299
|
lengthInches: len,
|
|
266
300
|
loop,
|
|
@@ -275,6 +309,8 @@ function docToState(doc, fallbackLength, moduleTracks = []) {
|
|
|
275
309
|
config: ep.tracks?.[0]?.config === "double" ? "double" : "single"
|
|
276
310
|
})),
|
|
277
311
|
poseOverrides,
|
|
312
|
+
endplateWidths,
|
|
313
|
+
outline,
|
|
278
314
|
crossings: (d.crossings ?? []).map((x) => ({
|
|
279
315
|
id: x.id,
|
|
280
316
|
name: x.name ?? "",
|
|
@@ -732,10 +768,13 @@ function poseOverridesFromDoc(doc) {
|
|
|
732
768
|
return out;
|
|
733
769
|
}
|
|
734
770
|
|
|
771
|
+
exports.FREEMO_ENDPLATE_WIDTH_MIN_INCHES = FREEMO_ENDPLATE_WIDTH_MIN_INCHES;
|
|
772
|
+
exports.FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES = FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES;
|
|
735
773
|
exports.MAIN2_TRACK_ID = MAIN2_TRACK_ID;
|
|
736
774
|
exports.MAIN_TRACK_ID = MAIN_TRACK_ID;
|
|
737
775
|
exports.N_SCALE_RATIO = N_SCALE_RATIO;
|
|
738
776
|
exports.asModuleSchematic = asModuleSchematic;
|
|
777
|
+
exports.benchworkOutline = benchworkOutline;
|
|
739
778
|
exports.buildCrossover = buildCrossover;
|
|
740
779
|
exports.buildPassingSiding = buildPassingSiding;
|
|
741
780
|
exports.buildTransition = buildTransition;
|
|
@@ -743,6 +782,7 @@ exports.deriveEndplatePoses = deriveEndplatePoses;
|
|
|
743
782
|
exports.divergeSideForHand = divergeSideForHand;
|
|
744
783
|
exports.docToState = docToState;
|
|
745
784
|
exports.emptyEditorState = emptyEditorState;
|
|
785
|
+
exports.endplateWidthInches = endplateWidthInches;
|
|
746
786
|
exports.geometryTurnDegrees = geometryTurnDegrees;
|
|
747
787
|
exports.inchesToScaleFeet = inchesToScaleFeet;
|
|
748
788
|
exports.isLoopDoc = isLoopDoc;
|