@willcgage/module-schematic 0.18.0 → 0.20.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 +59 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +40 -2
- package/dist/index.d.ts +40 -2
- package/dist/index.js +58 -7
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -78,6 +78,11 @@ interface SchematicTrack {
|
|
|
78
78
|
* endplate A (past the throat = in the loop), lane is the ladder/arc index —
|
|
79
79
|
* one record drives both the unrolled fan and a geometric render. */
|
|
80
80
|
inLoop?: boolean;
|
|
81
|
+
/** Authored 2-D path for this track (module-local inches, open path with
|
|
82
|
+
* arcs) — the PHYSICAL shape a bent/rotated spur draws. Absent = derive from
|
|
83
|
+
* the main centre-line + lane, as before. Physical view only; the operations
|
|
84
|
+
* view stays positional (#2d-track). */
|
|
85
|
+
path?: BenchworkPoint[] | null;
|
|
81
86
|
}
|
|
82
87
|
interface SchematicTurnout {
|
|
83
88
|
id: string;
|
|
@@ -87,6 +92,8 @@ interface SchematicTurnout {
|
|
|
87
92
|
kind?: TurnoutKind;
|
|
88
93
|
name?: string | null;
|
|
89
94
|
address?: string | null;
|
|
95
|
+
/** Frog number ("size") — #4, #6, #8, etc. Governs the diverging angle. */
|
|
96
|
+
size?: number | null;
|
|
90
97
|
}
|
|
91
98
|
interface SchematicSignal {
|
|
92
99
|
id: string;
|
|
@@ -195,6 +202,10 @@ interface ModuleSchematicDoc {
|
|
|
195
202
|
outline?: BenchworkPoint[];
|
|
196
203
|
/** @deprecated pre-grouping flat signals; read for back-compat. */
|
|
197
204
|
signals?: SchematicSignal[];
|
|
205
|
+
/** Authored mainline centre-line (module-local inches, open path with arcs).
|
|
206
|
+
* Present = the owner drew the real shape; absent = derive from geometry.
|
|
207
|
+
* Physical view only — the operations view stays derived (#2d-track). */
|
|
208
|
+
mainPath?: BenchworkPoint[] | null;
|
|
198
209
|
}
|
|
199
210
|
/** A benchwork-outline vertex, module-local inches. The edge from this vertex
|
|
200
211
|
* to the NEXT one is a straight line, unless `bulge` is set — then it's a
|
|
@@ -222,6 +233,19 @@ declare function sampleBenchworkOutline(pts: BenchworkPoint[], segsPerArc?: numb
|
|
|
222
233
|
x: number;
|
|
223
234
|
y: number;
|
|
224
235
|
}[];
|
|
236
|
+
/**
|
|
237
|
+
* Expand an OPEN track path (whose edges may be arcs) into a dense polyline —
|
|
238
|
+
* the open-ended sibling of sampleBenchworkOutline (which closes the ring).
|
|
239
|
+
* Used for authored track centre-lines (a drawn mainline or spur). The final
|
|
240
|
+
* vertex is always emitted so the path reaches its end.
|
|
241
|
+
*/
|
|
242
|
+
declare function samplePath(pts: BenchworkPoint[], segsPerArc?: number): {
|
|
243
|
+
x: number;
|
|
244
|
+
y: number;
|
|
245
|
+
}[];
|
|
246
|
+
/** Normalise an authored track path from a doc, or null if it isn't a real path
|
|
247
|
+
* (needs ≥ 2 valid points). Keeps per-vertex bulge. */
|
|
248
|
+
declare function trackPath(path: BenchworkPoint[] | null | undefined): BenchworkPoint[] | null;
|
|
225
249
|
interface ModuleFootprintInput {
|
|
226
250
|
/** Mainline length (falls back to footprint length), inches. */
|
|
227
251
|
lengthInches: number;
|
|
@@ -232,6 +256,10 @@ interface ModuleFootprintInput {
|
|
|
232
256
|
endplateWidths?: Record<string, number>;
|
|
233
257
|
/** Authored benchwork outline (module-local inches), or absent for the band. */
|
|
234
258
|
outline?: BenchworkPoint[] | null;
|
|
259
|
+
/** Authored mainline centre-line (module-local inches, open path with arcs).
|
|
260
|
+
* When present it wins over the geometry-derived centre-line — the owner drew
|
|
261
|
+
* the real shape (#2d-track, physical view only). */
|
|
262
|
+
mainPath?: BenchworkPoint[] | null;
|
|
235
263
|
}
|
|
236
264
|
interface OutlineFace {
|
|
237
265
|
/** The endplate face's two corners + midpoint (the track point). */
|
|
@@ -249,7 +277,9 @@ interface ModuleFootprint {
|
|
|
249
277
|
/** Authored outline (arc-sampled closed ring) or null → render the band. */
|
|
250
278
|
outline: BenchworkPoint[] | null;
|
|
251
279
|
}
|
|
252
|
-
/** Module-local main track centre-line (A→B), sampling arcs for curves/corners.
|
|
280
|
+
/** Module-local main track centre-line (A→B), sampling arcs for curves/corners.
|
|
281
|
+
* An authored `mainPath` wins — the owner drew the real shape; otherwise the
|
|
282
|
+
* centre-line is derived from the geometry fields (length + type/degrees/offset). */
|
|
253
283
|
declare function moduleCenterline(input: ModuleFootprintInput): BenchworkPoint[];
|
|
254
284
|
/** Benchwork band: the centre-line offset ±half-width, tapering widthA→widthB. */
|
|
255
285
|
declare function benchworkBand(center: BenchworkPoint[], widthA?: number, widthB?: number): BenchworkPoint[];
|
|
@@ -295,6 +325,9 @@ interface EditorTrack {
|
|
|
295
325
|
trackName: string;
|
|
296
326
|
/** Inside the balloon of a loop module (#165). */
|
|
297
327
|
inLoop?: boolean;
|
|
328
|
+
/** Authored 2-D path (module-local inches) — a bent/rotated spur's real
|
|
329
|
+
* shape. Absent = derive from the main + lane (#2d-track). */
|
|
330
|
+
path?: BenchworkPoint[];
|
|
298
331
|
}
|
|
299
332
|
/** A module_tracks row as loaded for the editor. */
|
|
300
333
|
interface ModuleTrackRow {
|
|
@@ -309,6 +342,8 @@ interface EditorTurnout {
|
|
|
309
342
|
onTrack: string;
|
|
310
343
|
divergeTrack: string;
|
|
311
344
|
kind: TurnoutKind;
|
|
345
|
+
/** Frog number ("size") — #4, #6, #8, etc. Governs the diverging angle. */
|
|
346
|
+
size?: number;
|
|
312
347
|
}
|
|
313
348
|
interface EditorCpSignal {
|
|
314
349
|
id: string;
|
|
@@ -393,6 +428,9 @@ interface EditorState {
|
|
|
393
428
|
controlPoints: EditorControlPoint[];
|
|
394
429
|
/** Rail-served industries — car-spot spans on a track (#industries). */
|
|
395
430
|
industries: EditorIndustry[];
|
|
431
|
+
/** Authored mainline centre-line (module-local inches) — empty = derive from
|
|
432
|
+
* geometry. The owner-drawn real shape (#2d-track, physical view only). */
|
|
433
|
+
mainPath: BenchworkPoint[];
|
|
396
434
|
}
|
|
397
435
|
/** Build the empty editor state for a module of the given length. */
|
|
398
436
|
declare function emptyEditorState(lengthInches: number): EditorState;
|
|
@@ -671,4 +709,4 @@ declare function poseOverridesFromDoc(doc: ModuleSchematicDoc): Record<string, {
|
|
|
671
709
|
heading: number;
|
|
672
710
|
}>;
|
|
673
711
|
|
|
674
|
-
export { type BenchworkPoint, type BranchConnector, type DrawCrossing, type DrawCrossover, type DrawIndustry, type DrawSignal, type DrawTrack, type DrawTurnout, type EditorBranch, type EditorControlPoint, type EditorCpSignal, type EditorCrossing, type EditorIndustry, type EditorState, type EditorTrack, type EditorTurnout, type EndplateBConfig, type EndplatePose, FREEMO_ENDPLATE_WIDTH_MIN_INCHES, FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES, type GeometryType, type IndustryLabelMode, MAIN2_TRACK_ID, MAIN_TRACK_ID, type ModuleFeatures, type ModuleFootprint, type ModuleFootprintInput, type ModuleGeometryInput, type ModuleSchematicDoc, type ModuleTrackRow, N_CAR_LENGTH_INCHES, N_SCALE_RATIO, type OutlineFace, type SchematicBlock, type SchematicControlPoint, type SchematicCrossing, type SchematicEndplate, type SchematicEndplateTrack, type SchematicIndustry, type SchematicSignal, type SchematicTrack, type SchematicTurnout, type SignalFacing, type SignalSide, type TrackConfig, type TrackRole, type TurnoutKind, asModuleSchematic, benchworkBand, benchworkOutline, buildCrossover, buildPassingSiding, buildTransition, carCapacity, deriveEndplatePoses, divergeSideForHand, docToState, emptyEditorState, endplateFaceSegments, endplateWidthInches, geometryTurnDegrees, inchesToScaleFeet, isLoopDoc, isTransitionTurnout, moduleCenterline, moduleFeatures, moduleFootprint, nextId, poseNeedsManual, poseOverridesFromDoc, sampleBenchworkOutline, scaleFeetToInches, stateToDoc };
|
|
712
|
+
export { type BenchworkPoint, type BranchConnector, type DrawCrossing, type DrawCrossover, type DrawIndustry, type DrawSignal, type DrawTrack, type DrawTurnout, type EditorBranch, type EditorControlPoint, type EditorCpSignal, type EditorCrossing, type EditorIndustry, type EditorState, type EditorTrack, type EditorTurnout, type EndplateBConfig, type EndplatePose, FREEMO_ENDPLATE_WIDTH_MIN_INCHES, FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES, type GeometryType, type IndustryLabelMode, MAIN2_TRACK_ID, MAIN_TRACK_ID, type ModuleFeatures, type ModuleFootprint, type ModuleFootprintInput, type ModuleGeometryInput, type ModuleSchematicDoc, type ModuleTrackRow, N_CAR_LENGTH_INCHES, N_SCALE_RATIO, type OutlineFace, type SchematicBlock, type SchematicControlPoint, type SchematicCrossing, type SchematicEndplate, type SchematicEndplateTrack, type SchematicIndustry, type SchematicSignal, type SchematicTrack, type SchematicTurnout, type SignalFacing, type SignalSide, type TrackConfig, type TrackRole, type TurnoutKind, asModuleSchematic, benchworkBand, benchworkOutline, buildCrossover, buildPassingSiding, buildTransition, carCapacity, deriveEndplatePoses, divergeSideForHand, docToState, emptyEditorState, endplateFaceSegments, endplateWidthInches, geometryTurnDegrees, inchesToScaleFeet, isLoopDoc, isTransitionTurnout, moduleCenterline, moduleFeatures, moduleFootprint, nextId, poseNeedsManual, poseOverridesFromDoc, sampleBenchworkOutline, samplePath, scaleFeetToInches, stateToDoc, trackPath };
|
package/dist/index.d.ts
CHANGED
|
@@ -78,6 +78,11 @@ interface SchematicTrack {
|
|
|
78
78
|
* endplate A (past the throat = in the loop), lane is the ladder/arc index —
|
|
79
79
|
* one record drives both the unrolled fan and a geometric render. */
|
|
80
80
|
inLoop?: boolean;
|
|
81
|
+
/** Authored 2-D path for this track (module-local inches, open path with
|
|
82
|
+
* arcs) — the PHYSICAL shape a bent/rotated spur draws. Absent = derive from
|
|
83
|
+
* the main centre-line + lane, as before. Physical view only; the operations
|
|
84
|
+
* view stays positional (#2d-track). */
|
|
85
|
+
path?: BenchworkPoint[] | null;
|
|
81
86
|
}
|
|
82
87
|
interface SchematicTurnout {
|
|
83
88
|
id: string;
|
|
@@ -87,6 +92,8 @@ interface SchematicTurnout {
|
|
|
87
92
|
kind?: TurnoutKind;
|
|
88
93
|
name?: string | null;
|
|
89
94
|
address?: string | null;
|
|
95
|
+
/** Frog number ("size") — #4, #6, #8, etc. Governs the diverging angle. */
|
|
96
|
+
size?: number | null;
|
|
90
97
|
}
|
|
91
98
|
interface SchematicSignal {
|
|
92
99
|
id: string;
|
|
@@ -195,6 +202,10 @@ interface ModuleSchematicDoc {
|
|
|
195
202
|
outline?: BenchworkPoint[];
|
|
196
203
|
/** @deprecated pre-grouping flat signals; read for back-compat. */
|
|
197
204
|
signals?: SchematicSignal[];
|
|
205
|
+
/** Authored mainline centre-line (module-local inches, open path with arcs).
|
|
206
|
+
* Present = the owner drew the real shape; absent = derive from geometry.
|
|
207
|
+
* Physical view only — the operations view stays derived (#2d-track). */
|
|
208
|
+
mainPath?: BenchworkPoint[] | null;
|
|
198
209
|
}
|
|
199
210
|
/** A benchwork-outline vertex, module-local inches. The edge from this vertex
|
|
200
211
|
* to the NEXT one is a straight line, unless `bulge` is set — then it's a
|
|
@@ -222,6 +233,19 @@ declare function sampleBenchworkOutline(pts: BenchworkPoint[], segsPerArc?: numb
|
|
|
222
233
|
x: number;
|
|
223
234
|
y: number;
|
|
224
235
|
}[];
|
|
236
|
+
/**
|
|
237
|
+
* Expand an OPEN track path (whose edges may be arcs) into a dense polyline —
|
|
238
|
+
* the open-ended sibling of sampleBenchworkOutline (which closes the ring).
|
|
239
|
+
* Used for authored track centre-lines (a drawn mainline or spur). The final
|
|
240
|
+
* vertex is always emitted so the path reaches its end.
|
|
241
|
+
*/
|
|
242
|
+
declare function samplePath(pts: BenchworkPoint[], segsPerArc?: number): {
|
|
243
|
+
x: number;
|
|
244
|
+
y: number;
|
|
245
|
+
}[];
|
|
246
|
+
/** Normalise an authored track path from a doc, or null if it isn't a real path
|
|
247
|
+
* (needs ≥ 2 valid points). Keeps per-vertex bulge. */
|
|
248
|
+
declare function trackPath(path: BenchworkPoint[] | null | undefined): BenchworkPoint[] | null;
|
|
225
249
|
interface ModuleFootprintInput {
|
|
226
250
|
/** Mainline length (falls back to footprint length), inches. */
|
|
227
251
|
lengthInches: number;
|
|
@@ -232,6 +256,10 @@ interface ModuleFootprintInput {
|
|
|
232
256
|
endplateWidths?: Record<string, number>;
|
|
233
257
|
/** Authored benchwork outline (module-local inches), or absent for the band. */
|
|
234
258
|
outline?: BenchworkPoint[] | null;
|
|
259
|
+
/** Authored mainline centre-line (module-local inches, open path with arcs).
|
|
260
|
+
* When present it wins over the geometry-derived centre-line — the owner drew
|
|
261
|
+
* the real shape (#2d-track, physical view only). */
|
|
262
|
+
mainPath?: BenchworkPoint[] | null;
|
|
235
263
|
}
|
|
236
264
|
interface OutlineFace {
|
|
237
265
|
/** The endplate face's two corners + midpoint (the track point). */
|
|
@@ -249,7 +277,9 @@ interface ModuleFootprint {
|
|
|
249
277
|
/** Authored outline (arc-sampled closed ring) or null → render the band. */
|
|
250
278
|
outline: BenchworkPoint[] | null;
|
|
251
279
|
}
|
|
252
|
-
/** Module-local main track centre-line (A→B), sampling arcs for curves/corners.
|
|
280
|
+
/** Module-local main track centre-line (A→B), sampling arcs for curves/corners.
|
|
281
|
+
* An authored `mainPath` wins — the owner drew the real shape; otherwise the
|
|
282
|
+
* centre-line is derived from the geometry fields (length + type/degrees/offset). */
|
|
253
283
|
declare function moduleCenterline(input: ModuleFootprintInput): BenchworkPoint[];
|
|
254
284
|
/** Benchwork band: the centre-line offset ±half-width, tapering widthA→widthB. */
|
|
255
285
|
declare function benchworkBand(center: BenchworkPoint[], widthA?: number, widthB?: number): BenchworkPoint[];
|
|
@@ -295,6 +325,9 @@ interface EditorTrack {
|
|
|
295
325
|
trackName: string;
|
|
296
326
|
/** Inside the balloon of a loop module (#165). */
|
|
297
327
|
inLoop?: boolean;
|
|
328
|
+
/** Authored 2-D path (module-local inches) — a bent/rotated spur's real
|
|
329
|
+
* shape. Absent = derive from the main + lane (#2d-track). */
|
|
330
|
+
path?: BenchworkPoint[];
|
|
298
331
|
}
|
|
299
332
|
/** A module_tracks row as loaded for the editor. */
|
|
300
333
|
interface ModuleTrackRow {
|
|
@@ -309,6 +342,8 @@ interface EditorTurnout {
|
|
|
309
342
|
onTrack: string;
|
|
310
343
|
divergeTrack: string;
|
|
311
344
|
kind: TurnoutKind;
|
|
345
|
+
/** Frog number ("size") — #4, #6, #8, etc. Governs the diverging angle. */
|
|
346
|
+
size?: number;
|
|
312
347
|
}
|
|
313
348
|
interface EditorCpSignal {
|
|
314
349
|
id: string;
|
|
@@ -393,6 +428,9 @@ interface EditorState {
|
|
|
393
428
|
controlPoints: EditorControlPoint[];
|
|
394
429
|
/** Rail-served industries — car-spot spans on a track (#industries). */
|
|
395
430
|
industries: EditorIndustry[];
|
|
431
|
+
/** Authored mainline centre-line (module-local inches) — empty = derive from
|
|
432
|
+
* geometry. The owner-drawn real shape (#2d-track, physical view only). */
|
|
433
|
+
mainPath: BenchworkPoint[];
|
|
396
434
|
}
|
|
397
435
|
/** Build the empty editor state for a module of the given length. */
|
|
398
436
|
declare function emptyEditorState(lengthInches: number): EditorState;
|
|
@@ -671,4 +709,4 @@ declare function poseOverridesFromDoc(doc: ModuleSchematicDoc): Record<string, {
|
|
|
671
709
|
heading: number;
|
|
672
710
|
}>;
|
|
673
711
|
|
|
674
|
-
export { type BenchworkPoint, type BranchConnector, type DrawCrossing, type DrawCrossover, type DrawIndustry, type DrawSignal, type DrawTrack, type DrawTurnout, type EditorBranch, type EditorControlPoint, type EditorCpSignal, type EditorCrossing, type EditorIndustry, type EditorState, type EditorTrack, type EditorTurnout, type EndplateBConfig, type EndplatePose, FREEMO_ENDPLATE_WIDTH_MIN_INCHES, FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES, type GeometryType, type IndustryLabelMode, MAIN2_TRACK_ID, MAIN_TRACK_ID, type ModuleFeatures, type ModuleFootprint, type ModuleFootprintInput, type ModuleGeometryInput, type ModuleSchematicDoc, type ModuleTrackRow, N_CAR_LENGTH_INCHES, N_SCALE_RATIO, type OutlineFace, type SchematicBlock, type SchematicControlPoint, type SchematicCrossing, type SchematicEndplate, type SchematicEndplateTrack, type SchematicIndustry, type SchematicSignal, type SchematicTrack, type SchematicTurnout, type SignalFacing, type SignalSide, type TrackConfig, type TrackRole, type TurnoutKind, asModuleSchematic, benchworkBand, benchworkOutline, buildCrossover, buildPassingSiding, buildTransition, carCapacity, deriveEndplatePoses, divergeSideForHand, docToState, emptyEditorState, endplateFaceSegments, endplateWidthInches, geometryTurnDegrees, inchesToScaleFeet, isLoopDoc, isTransitionTurnout, moduleCenterline, moduleFeatures, moduleFootprint, nextId, poseNeedsManual, poseOverridesFromDoc, sampleBenchworkOutline, scaleFeetToInches, stateToDoc };
|
|
712
|
+
export { type BenchworkPoint, type BranchConnector, type DrawCrossing, type DrawCrossover, type DrawIndustry, type DrawSignal, type DrawTrack, type DrawTurnout, type EditorBranch, type EditorControlPoint, type EditorCpSignal, type EditorCrossing, type EditorIndustry, type EditorState, type EditorTrack, type EditorTurnout, type EndplateBConfig, type EndplatePose, FREEMO_ENDPLATE_WIDTH_MIN_INCHES, FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES, type GeometryType, type IndustryLabelMode, MAIN2_TRACK_ID, MAIN_TRACK_ID, type ModuleFeatures, type ModuleFootprint, type ModuleFootprintInput, type ModuleGeometryInput, type ModuleSchematicDoc, type ModuleTrackRow, N_CAR_LENGTH_INCHES, N_SCALE_RATIO, type OutlineFace, type SchematicBlock, type SchematicControlPoint, type SchematicCrossing, type SchematicEndplate, type SchematicEndplateTrack, type SchematicIndustry, type SchematicSignal, type SchematicTrack, type SchematicTurnout, type SignalFacing, type SignalSide, type TrackConfig, type TrackRole, type TurnoutKind, asModuleSchematic, benchworkBand, benchworkOutline, buildCrossover, buildPassingSiding, buildTransition, carCapacity, deriveEndplatePoses, divergeSideForHand, docToState, emptyEditorState, endplateFaceSegments, endplateWidthInches, geometryTurnDegrees, inchesToScaleFeet, isLoopDoc, isTransitionTurnout, moduleCenterline, moduleFeatures, moduleFootprint, nextId, poseNeedsManual, poseOverridesFromDoc, sampleBenchworkOutline, samplePath, scaleFeetToInches, stateToDoc, trackPath };
|
package/dist/index.js
CHANGED
|
@@ -43,6 +43,45 @@ function sampleBenchworkOutline(pts, segsPerArc = 20) {
|
|
|
43
43
|
}
|
|
44
44
|
return out;
|
|
45
45
|
}
|
|
46
|
+
function samplePath(pts, segsPerArc = 20) {
|
|
47
|
+
const n = pts.length;
|
|
48
|
+
if (n < 2) return pts.map((p) => ({ x: p.x, y: p.y }));
|
|
49
|
+
const out = [];
|
|
50
|
+
for (let i = 0; i < n - 1; i++) {
|
|
51
|
+
const p0 = pts[i];
|
|
52
|
+
const p1 = pts[i + 1];
|
|
53
|
+
out.push({ x: p0.x, y: p0.y });
|
|
54
|
+
const bulge = p0.bulge ?? 0;
|
|
55
|
+
if (!bulge) continue;
|
|
56
|
+
const dx = p1.x - p0.x;
|
|
57
|
+
const dy = p1.y - p0.y;
|
|
58
|
+
const c = Math.hypot(dx, dy);
|
|
59
|
+
if (c < 1e-6) continue;
|
|
60
|
+
const nx = -dy / c;
|
|
61
|
+
const ny = dx / c;
|
|
62
|
+
const mid = { x: (p0.x + p1.x) / 2 + nx * bulge, y: (p0.y + p1.y) / 2 + ny * bulge };
|
|
63
|
+
const circ = circleThrough(p0, mid, p1);
|
|
64
|
+
if (!circ) continue;
|
|
65
|
+
const a0 = Math.atan2(p0.y - circ.cy, p0.x - circ.cx);
|
|
66
|
+
const am = Math.atan2(mid.y - circ.cy, mid.x - circ.cx);
|
|
67
|
+
const a1 = Math.atan2(p1.y - circ.cy, p1.x - circ.cx);
|
|
68
|
+
const sweep = arcSweep(a0, a1, am);
|
|
69
|
+
for (let s = 1; s < segsPerArc; s++) {
|
|
70
|
+
const a = a0 + sweep * s / segsPerArc;
|
|
71
|
+
out.push({ x: circ.cx + circ.r * Math.cos(a), y: circ.cy + circ.r * Math.sin(a) });
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
out.push({ x: pts[n - 1].x, y: pts[n - 1].y });
|
|
75
|
+
return out;
|
|
76
|
+
}
|
|
77
|
+
function trackPath(path) {
|
|
78
|
+
const pts = (path ?? []).filter((p) => p && Number.isFinite(p.x) && Number.isFinite(p.y)).map((p) => ({
|
|
79
|
+
x: p.x,
|
|
80
|
+
y: p.y,
|
|
81
|
+
...Number.isFinite(p.bulge) && p.bulge ? { bulge: p.bulge } : {}
|
|
82
|
+
}));
|
|
83
|
+
return pts.length >= 2 ? pts : null;
|
|
84
|
+
}
|
|
46
85
|
function circleThrough(a, b, c) {
|
|
47
86
|
const d = 2 * (a.x * (b.y - c.y) + b.x * (c.y - a.y) + c.x * (a.y - b.y));
|
|
48
87
|
if (Math.abs(d) < 1e-9) return null;
|
|
@@ -65,6 +104,8 @@ function arcSweep(a0, a1, am) {
|
|
|
65
104
|
}
|
|
66
105
|
var DEG_FP = Math.PI / 180;
|
|
67
106
|
function moduleCenterline(input) {
|
|
107
|
+
const drawn = trackPath(input.mainPath);
|
|
108
|
+
if (drawn) return samplePath(drawn);
|
|
68
109
|
const L = input.lengthInches > 0 ? input.lengthInches : 24;
|
|
69
110
|
const gt = input.geometryType;
|
|
70
111
|
if (gt === "dead_end") return [{ x: 0, y: 0 }];
|
|
@@ -174,7 +215,8 @@ function emptyEditorState(lengthInches) {
|
|
|
174
215
|
endplateWidths: {},
|
|
175
216
|
outline: [],
|
|
176
217
|
controlPoints: [],
|
|
177
|
-
industries: []
|
|
218
|
+
industries: [],
|
|
219
|
+
mainPath: []
|
|
178
220
|
};
|
|
179
221
|
}
|
|
180
222
|
function isTransitionTurnout(t) {
|
|
@@ -311,7 +353,8 @@ function stateToDoc(state, recordNumber) {
|
|
|
311
353
|
moduleTrackId: t.moduleTrackId,
|
|
312
354
|
trackName: t.trackName || void 0,
|
|
313
355
|
capacityFeet: Math.round(inchesToScaleFeet(Math.abs(t.toPos - t.fromPos))),
|
|
314
|
-
...state.loop && t.inLoop ? { inLoop: true } : {}
|
|
356
|
+
...state.loop && t.inLoop ? { inLoop: true } : {},
|
|
357
|
+
...t.path && t.path.length >= 2 ? { path: t.path } : {}
|
|
315
358
|
}))
|
|
316
359
|
],
|
|
317
360
|
turnouts: state.turnouts.map((t) => ({
|
|
@@ -320,7 +363,8 @@ function stateToDoc(state, recordNumber) {
|
|
|
320
363
|
onTrack: t.onTrack,
|
|
321
364
|
divergeTrack: t.divergeTrack,
|
|
322
365
|
kind: t.kind,
|
|
323
|
-
name: t.name || void 0
|
|
366
|
+
name: t.name || void 0,
|
|
367
|
+
...t.size ? { size: t.size } : {}
|
|
324
368
|
})),
|
|
325
369
|
...state.crossings.length > 0 ? {
|
|
326
370
|
crossings: state.crossings.map((x) => ({
|
|
@@ -361,7 +405,9 @@ function stateToDoc(state, recordNumber) {
|
|
|
361
405
|
} : {},
|
|
362
406
|
// Benchwork footprint outline (module-local inches); only when it's a real
|
|
363
407
|
// ring (≥ 3 vertices).
|
|
364
|
-
...state.outline.length >= 3 ? { outline: state.outline } : {}
|
|
408
|
+
...state.outline.length >= 3 ? { outline: state.outline } : {},
|
|
409
|
+
// Authored mainline path (module-local inches); only when it's a real path.
|
|
410
|
+
...state.mainPath.length >= 2 ? { mainPath: state.mainPath } : {}
|
|
365
411
|
};
|
|
366
412
|
}
|
|
367
413
|
function docToState(doc, fallbackLength, moduleTracks = []) {
|
|
@@ -391,7 +437,9 @@ function docToState(doc, fallbackLength, moduleTracks = []) {
|
|
|
391
437
|
toPos: t.toPos != null ? sc(t.toPos) : len,
|
|
392
438
|
moduleTrackId,
|
|
393
439
|
trackName: t.trackName ?? nameOf(moduleTrackId),
|
|
394
|
-
...t.inLoop ? { inLoop: true } : {}
|
|
440
|
+
...t.inLoop ? { inLoop: true } : {},
|
|
441
|
+
// Authored path kept as-drawn (a physical shape, not rescaled with length).
|
|
442
|
+
...trackPath(t.path) ? { path: trackPath(t.path) } : {}
|
|
395
443
|
});
|
|
396
444
|
}
|
|
397
445
|
}
|
|
@@ -440,6 +488,7 @@ function docToState(doc, fallbackLength, moduleTracks = []) {
|
|
|
440
488
|
y: p.y,
|
|
441
489
|
...Number.isFinite(p.bulge) && p.bulge ? { bulge: p.bulge } : {}
|
|
442
490
|
}));
|
|
491
|
+
const mainPath = trackPath(d.mainPath) ?? [];
|
|
443
492
|
return {
|
|
444
493
|
lengthInches: len,
|
|
445
494
|
loop,
|
|
@@ -456,6 +505,7 @@ function docToState(doc, fallbackLength, moduleTracks = []) {
|
|
|
456
505
|
poseOverrides,
|
|
457
506
|
endplateWidths,
|
|
458
507
|
outline,
|
|
508
|
+
mainPath,
|
|
459
509
|
crossings: (d.crossings ?? []).map((x) => ({
|
|
460
510
|
id: x.id,
|
|
461
511
|
name: x.name ?? "",
|
|
@@ -470,7 +520,8 @@ function docToState(doc, fallbackLength, moduleTracks = []) {
|
|
|
470
520
|
pos: sc(t.pos),
|
|
471
521
|
onTrack: t.onTrack,
|
|
472
522
|
divergeTrack: t.divergeTrack,
|
|
473
|
-
kind: t.kind ?? "right"
|
|
523
|
+
kind: t.kind ?? "right",
|
|
524
|
+
...t.size ? { size: t.size } : {}
|
|
474
525
|
})),
|
|
475
526
|
controlPoints: readControlPoints(d, sc),
|
|
476
527
|
industries: (d.industries ?? []).map((ind) => ({
|
|
@@ -942,6 +993,6 @@ function poseOverridesFromDoc(doc) {
|
|
|
942
993
|
return out;
|
|
943
994
|
}
|
|
944
995
|
|
|
945
|
-
export { FREEMO_ENDPLATE_WIDTH_MIN_INCHES, FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES, MAIN2_TRACK_ID, MAIN_TRACK_ID, N_CAR_LENGTH_INCHES, N_SCALE_RATIO, asModuleSchematic, benchworkBand, benchworkOutline, buildCrossover, buildPassingSiding, buildTransition, carCapacity, deriveEndplatePoses, divergeSideForHand, docToState, emptyEditorState, endplateFaceSegments, endplateWidthInches, geometryTurnDegrees, inchesToScaleFeet, isLoopDoc, isTransitionTurnout, moduleCenterline, moduleFeatures, moduleFootprint, nextId, poseNeedsManual, poseOverridesFromDoc, sampleBenchworkOutline, scaleFeetToInches, stateToDoc };
|
|
996
|
+
export { FREEMO_ENDPLATE_WIDTH_MIN_INCHES, FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES, MAIN2_TRACK_ID, MAIN_TRACK_ID, N_CAR_LENGTH_INCHES, N_SCALE_RATIO, asModuleSchematic, benchworkBand, benchworkOutline, buildCrossover, buildPassingSiding, buildTransition, carCapacity, deriveEndplatePoses, divergeSideForHand, docToState, emptyEditorState, endplateFaceSegments, endplateWidthInches, geometryTurnDegrees, inchesToScaleFeet, isLoopDoc, isTransitionTurnout, moduleCenterline, moduleFeatures, moduleFootprint, nextId, poseNeedsManual, poseOverridesFromDoc, sampleBenchworkOutline, samplePath, scaleFeetToInches, stateToDoc, trackPath };
|
|
946
997
|
//# sourceMappingURL=index.js.map
|
|
947
998
|
//# sourceMappingURL=index.js.map
|