@willcgage/module-schematic 0.86.0 → 0.90.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.js CHANGED
@@ -1044,6 +1044,10 @@ function stateToDoc(state, recordNumber) {
1044
1044
  track: ind.track,
1045
1045
  fromPos: ind.fromPos,
1046
1046
  toPos: ind.toPos,
1047
+ // Carried, not interpreted. An anchor is what HOLDS the span (ADR
1048
+ // 0001); dropping it here would quietly convert an anchored
1049
+ // industry back into a typed number the next time anyone saved.
1050
+ ...ind.anchor ? { anchor: ind.anchor } : {},
1047
1051
  ...ind.spots?.length ? { spots: ind.spots } : {},
1048
1052
  side: ind.side,
1049
1053
  ...ind.labelMode && ind.labelMode !== "none" ? { labelMode: ind.labelMode } : {},
@@ -1063,7 +1067,11 @@ function stateToDoc(state, recordNumber) {
1063
1067
  ...state.sections.length ? { sections: moduleSections({ sections: state.sections }) } : {},
1064
1068
  // Authored mainline path (module-local inches); only when it's a real path.
1065
1069
  ...state.mainPath.length >= 2 ? { mainPath: state.mainPath } : {},
1066
- ...state.main2Path.length >= 2 ? { main2Path: state.main2Path } : {}
1070
+ ...state.main2Path.length >= 2 ? { main2Path: state.main2Path } : {},
1071
+ // The pieces the owner drew, carried verbatim (ADR 0001). This function
1072
+ // stays dumb about them on purpose: deriving here would put the derivation
1073
+ // in every save path in both apps. `deriveGraphDoc` is the one place.
1074
+ ...state.graph?.pieces?.length ? { graph: state.graph } : {}
1067
1075
  };
1068
1076
  }
1069
1077
  function docToState(doc, fallbackLength, moduleTracks = []) {
@@ -1208,6 +1216,10 @@ function docToState(doc, fallbackLength, moduleTracks = []) {
1208
1216
  sections: moduleSections(d),
1209
1217
  mainPath,
1210
1218
  main2Path,
1219
+ // ⚠️ NOT scaled by `sc()` like every position above it. A piece is placed in
1220
+ // real inches on the board; stretching the module's length does not move it,
1221
+ // and the length is DERIVED from the pieces anyway when a graph is present.
1222
+ ...d.graph?.pieces?.length ? { graph: d.graph } : {},
1211
1223
  crossings: (d.crossings ?? []).map((x) => ({
1212
1224
  id: x.id,
1213
1225
  name: x.name ?? "",
@@ -1242,12 +1254,14 @@ function docToState(doc, fallbackLength, moduleTracks = []) {
1242
1254
  track: s.track,
1243
1255
  fromPos: sc(s.fromPos ?? 0),
1244
1256
  toPos: s.toPos != null ? sc(s.toPos) : len,
1245
- ...s.side ? { side: s.side } : {}
1257
+ ...s.side ? { side: s.side } : {},
1258
+ ...s.anchor ? { anchor: s.anchor } : {}
1246
1259
  })),
1247
1260
  side: ind.side ?? "above",
1248
1261
  labelMode: ind.labelMode ?? "none",
1249
1262
  carTypes: Array.isArray(ind.carTypes) ? ind.carTypes : [],
1250
- moduleIndustryId: ind.moduleIndustryId ?? null
1263
+ moduleIndustryId: ind.moduleIndustryId ?? null,
1264
+ ...ind.anchor ? { anchor: ind.anchor } : {}
1251
1265
  }))
1252
1266
  };
1253
1267
  }
@@ -2232,6 +2246,54 @@ function partGeometry(part, library = BUILT_IN_TRACK_PARTS) {
2232
2246
  divergingEndMeasured: de.measured
2233
2247
  };
2234
2248
  }
2249
+ function pieceRoutePaths(piece, library = BUILT_IN_TRACK_PARTS) {
2250
+ const part = library.find((p) => p.id === piece.partId);
2251
+ if (!part) return [];
2252
+ const geo = partGeometry(part, library);
2253
+ if (!geo) return [];
2254
+ const joints = placedJoints([piece], library);
2255
+ const at = (id) => joints.find((j) => j.joint === id);
2256
+ const RAD = Math.PI / 180;
2257
+ const c = Math.cos(piece.rotationDeg * RAD);
2258
+ const s = Math.sin(piece.rotationDeg * RAD);
2259
+ const place = (x, y) => {
2260
+ const ly = piece.flipped ? -y : y;
2261
+ return { x: piece.x + x * c - ly * s, y: piece.y + x * s + ly * c };
2262
+ };
2263
+ const out = [];
2264
+ for (const route of geo.routes) {
2265
+ const a = at(route[0]);
2266
+ const b = at(route[1]);
2267
+ if (!a || !b) continue;
2268
+ const ends = [{ x: a.x, y: a.y }, { x: b.x, y: b.y }];
2269
+ const diverging = route.some((r) => r === "diverge" || r === "legA" || r === "legB");
2270
+ if (!diverging || part.kind === "flex") {
2271
+ out.push({ route, points: ends });
2272
+ continue;
2273
+ }
2274
+ const lead = part.lead?.inches ?? 0;
2275
+ const pts0 = part.pointsOffset?.inches ?? 0;
2276
+ const far = geo.joints.find((j) => j.id === route[1]) ?? geo.joints.find((j) => j.id === route[0]);
2277
+ if (!far || !(lead > 0)) {
2278
+ out.push({ route, points: ends });
2279
+ continue;
2280
+ }
2281
+ const isWye = part.kind === "wye";
2282
+ const closure = turnoutClosure(isWye ? part.frogNumber * 2 : part.frogNumber, {
2283
+ leadInches: lead
2284
+ });
2285
+ const mirror = route.includes("legB") ? -1 : 1;
2286
+ const pts = [place(0, 0), place(pts0, 0)];
2287
+ const steps = 12;
2288
+ for (let i = 1; i <= steps; i++) {
2289
+ const x = pts0 + (far.x - pts0) * i / steps;
2290
+ pts.push(place(x, mirror * closure.offsetAt(x - pts0)));
2291
+ }
2292
+ pts[pts.length - 1] = { x: b.x, y: b.y };
2293
+ out.push({ route, points: route[0] === "throat" ? pts : pts.slice().reverse() });
2294
+ }
2295
+ return out;
2296
+ }
2235
2297
  function partsPlaceable(library = BUILT_IN_TRACK_PARTS) {
2236
2298
  const placeable = [];
2237
2299
  const blocked = [];
@@ -2316,6 +2378,36 @@ function buildTrackGraph(pieces, library = BUILT_IN_TRACK_PARTS, snapInches = JO
2316
2378
  }
2317
2379
  return { joints, connections, open, conflicts, unplaceable };
2318
2380
  }
2381
+ function snapPiece(moving, others, library = BUILT_IN_TRACK_PARTS, withinInches = 0.5) {
2382
+ const mine = placedJoints([moving], library);
2383
+ if (!mine.length) return null;
2384
+ const graph = buildTrackGraph(others, library);
2385
+ const taken = new Set(graph.connections.flatMap((c2) => [c2.a, c2.b]));
2386
+ const open = graph.joints.filter((j) => !taken.has(j.key));
2387
+ let best = null;
2388
+ for (const m of mine)
2389
+ for (const t of open) {
2390
+ const d = Math.hypot(t.x - m.x, t.y - m.y);
2391
+ if (d <= withinInches && (!best || d < best.d)) best = { m, t, d };
2392
+ }
2393
+ if (!best) return null;
2394
+ const RAD = Math.PI / 180;
2395
+ const dRot = norm360(best.t.headingDeg + 180 - best.m.headingDeg);
2396
+ const c = Math.cos(dRot * RAD);
2397
+ const s = Math.sin(dRot * RAD);
2398
+ const ox = moving.x - best.m.x;
2399
+ const oy = moving.y - best.m.y;
2400
+ return {
2401
+ piece: {
2402
+ ...moving,
2403
+ rotationDeg: norm360(moving.rotationDeg + dRot),
2404
+ x: best.t.x + ox * c - oy * s,
2405
+ y: best.t.y + ox * s + oy * c
2406
+ },
2407
+ from: best.m.key,
2408
+ to: best.t.key
2409
+ };
2410
+ }
2319
2411
  function walkTrackGraph(graph, pieces, startAt, library = BUILT_IN_TRACK_PARTS) {
2320
2412
  const byKey = new Map(graph.joints.map((j) => [j.key, j]));
2321
2413
  const pieceById = new Map(pieces.map((p) => [p.id, p]));
@@ -2346,6 +2438,7 @@ function walkTrackGraph(graph, pieces, startAt, library = BUILT_IN_TRACK_PARTS)
2346
2438
  bornAt,
2347
2439
  endsAt: null,
2348
2440
  pieces: [],
2441
+ spans: [],
2349
2442
  lateral: 0
2350
2443
  };
2351
2444
  let cur = startKey;
@@ -2403,7 +2496,15 @@ function walkTrackGraph(graph, pieces, startAt, library = BUILT_IN_TRACK_PARTS)
2403
2496
  for (const j of graph.joints)
2404
2497
  if (j.piece === here.piece && Math.abs(j.y) > Math.abs(route.lateral))
2405
2498
  route.lateral = j.y;
2499
+ const entered = pos;
2406
2500
  pos += gap(here, exit);
2501
+ route.spans.push({
2502
+ piece: here.piece,
2503
+ entryJoint: here.joint,
2504
+ exitJoint,
2505
+ fromPos: entered,
2506
+ toPos: pos
2507
+ });
2407
2508
  route.toPos = pos;
2408
2509
  const next = exit ? link.get(exit.key) : void 0;
2409
2510
  if (!next) break;
@@ -2420,6 +2521,12 @@ function walkTrackGraph(graph, pieces, startAt, library = BUILT_IN_TRACK_PARTS)
2420
2521
  warnings.push(`the route diverging at ${b.from} is not connected to anything`);
2421
2522
  continue;
2422
2523
  }
2524
+ const already = routes.find((r2) => r2.pieces.includes(byKey.get(start).piece));
2525
+ if (already) {
2526
+ const swFar = turnouts.find((t) => t.id === b.from);
2527
+ if (swFar && !swFar.divergeRoute) swFar.divergeRoute = already.id;
2528
+ continue;
2529
+ }
2423
2530
  n += 1;
2424
2531
  const r = walk(start, b.at + b.skew, `route${n}`, b.from);
2425
2532
  r.fromPos = b.at;
@@ -2434,6 +2541,153 @@ function walkTrackGraph(graph, pieces, startAt, library = BUILT_IN_TRACK_PARTS)
2434
2541
  for (const c of graph.conflicts) warnings.push(c.reason);
2435
2542
  return { routes, turnouts, warnings };
2436
2543
  }
2544
+ function resolveGraphAnchor(anchor, walk, pieces, library = BUILT_IN_TRACK_PARTS) {
2545
+ const piece = pieces.find((p) => p.id === anchor.piece);
2546
+ const part = piece ? library.find((x) => x.id === piece.partId) : void 0;
2547
+ const origin = part?.kind === "flex" ? "a" : "throat";
2548
+ for (const r of walk.routes) {
2549
+ const span = r.spans.find((s) => s.piece === anchor.piece);
2550
+ if (!span) continue;
2551
+ if (span.entryJoint === origin)
2552
+ return { pos: span.fromPos + anchor.atInches, routeId: r.id, reversed: false };
2553
+ if (span.exitJoint === origin)
2554
+ return { pos: span.toPos - anchor.atInches, routeId: r.id, reversed: true };
2555
+ return null;
2556
+ }
2557
+ return null;
2558
+ }
2559
+ function graphToDoc(pieces, input) {
2560
+ const library = input.library ?? BUILT_IN_TRACK_PARTS;
2561
+ const graph = buildTrackGraph(pieces, library);
2562
+ const walk = walkTrackGraph(graph, pieces, input.startAt, library);
2563
+ const warnings = [...walk.warnings];
2564
+ const round = (n) => Math.round(n * 100) / 100;
2565
+ const base = input.base ?? {};
2566
+ const endplates = base.endplates && base.endplates.length ? base.endplates : [{ id: "A", label: "West" }, { id: "B", label: "East" }];
2567
+ const epA = endplates[0];
2568
+ const epB = endplates[1];
2569
+ const main = walk.routes.find((r) => r.id === "main");
2570
+ const lengthInches = round(main.toPos);
2571
+ const branches = walk.routes.filter((r) => r.id !== "main" && r.pieces.length);
2572
+ const trackIdOf = /* @__PURE__ */ new Map([["main", MAIN_TRACK_ID]]);
2573
+ for (const r of branches) trackIdOf.set(r.id, r.pieces[0]);
2574
+ const laneOf = (r) => {
2575
+ const side = Math.sign(r.lateral) || 1;
2576
+ const sameSide = branches.filter((x) => (Math.sign(x.lateral) || 1) === side).sort((a, b) => Math.abs(a.lateral) - Math.abs(b.lateral));
2577
+ return side * (sameSide.indexOf(r) + 1);
2578
+ };
2579
+ const tracks = [
2580
+ {
2581
+ id: MAIN_TRACK_ID,
2582
+ role: "main",
2583
+ lane: 0,
2584
+ from: epA?.id ?? "A",
2585
+ ...epB ? { to: epB.id } : {}
2586
+ }
2587
+ ];
2588
+ for (const r of branches) {
2589
+ const id = trackIdOf.get(r.id);
2590
+ const meta = input.meta?.[id] ?? {};
2591
+ tracks.push({
2592
+ id,
2593
+ // It runs back into a second turnout, or it doesn't. That is the whole
2594
+ // difference between a siding and a spur, and it is read, not declared.
2595
+ role: r.endsAt ? "siding" : "spur",
2596
+ lane: laneOf(r),
2597
+ fromPos: round(Math.min(r.fromPos, r.toPos)),
2598
+ toPos: round(Math.max(r.fromPos, r.toPos)),
2599
+ ...meta.trackName ? { trackName: meta.trackName } : {},
2600
+ ...meta.capacityFeet != null ? { capacityFeet: meta.capacityFeet } : {},
2601
+ ...meta.moduleTrackId != null ? { moduleTrackId: meta.moduleTrackId } : {}
2602
+ });
2603
+ }
2604
+ const pieceById = new Map(pieces.map((p) => [p.id, p]));
2605
+ const turnouts = [];
2606
+ for (const t of walk.turnouts) {
2607
+ const diverge = t.divergeRoute ? trackIdOf.get(t.divergeRoute) : void 0;
2608
+ if (!diverge) {
2609
+ warnings.push(
2610
+ `${t.id} is placed but its diverging route goes nowhere, so it is not in the operations view`
2611
+ );
2612
+ continue;
2613
+ }
2614
+ const piece = pieceById.get(t.id);
2615
+ const part = piece ? library.find((p) => p.id === piece.partId) : void 0;
2616
+ turnouts.push({
2617
+ id: t.id,
2618
+ pos: round(t.pos),
2619
+ onTrack: trackIdOf.get(t.onRoute) ?? MAIN_TRACK_ID,
2620
+ divergeTrack: diverge,
2621
+ ...piece?.name ? { name: piece.name } : {},
2622
+ ...part?.frogNumber != null ? { size: part.frogNumber } : {},
2623
+ ...part ? { partId: part.id } : {}
2624
+ });
2625
+ }
2626
+ turnouts.sort((a, b) => a.pos - b.pos);
2627
+ const place = (a, what) => {
2628
+ if (!a) return null;
2629
+ const hit = resolveGraphAnchor(a, walk, pieces, library);
2630
+ if (!hit) {
2631
+ warnings.push(
2632
+ `${what} is anchored to ${a.piece}, which is not on any route \u2014 its authored position stands`
2633
+ );
2634
+ return null;
2635
+ }
2636
+ return hit;
2637
+ };
2638
+ const spanAt = (hit, from, to) => {
2639
+ const len = Math.abs(to - from);
2640
+ return hit.reversed ? [round(hit.pos - len), round(hit.pos)] : [round(hit.pos), round(hit.pos + len)];
2641
+ };
2642
+ const industries = base.industries?.map((ind) => {
2643
+ const hit = place(ind.anchor, `industry "${ind.name}"`);
2644
+ const spots = ind.spots?.map((s) => {
2645
+ const sh = place(s.anchor, `a spot of industry "${ind.name}"`);
2646
+ if (!sh) return s;
2647
+ const [from, to] = spanAt(sh, s.fromPos, s.toPos);
2648
+ return { ...s, track: trackIdOf.get(sh.routeId) ?? s.track, fromPos: from, toPos: to };
2649
+ });
2650
+ if (!hit) return spots ? { ...ind, spots } : ind;
2651
+ const [fromPos, toPos] = spanAt(hit, ind.fromPos, ind.toPos);
2652
+ return {
2653
+ ...ind,
2654
+ track: trackIdOf.get(hit.routeId) ?? ind.track,
2655
+ fromPos,
2656
+ toPos,
2657
+ ...spots ? { spots } : {}
2658
+ };
2659
+ });
2660
+ const signals = base.signals?.map((sig) => {
2661
+ const hit = place(sig.anchor, `signal "${sig.name ?? sig.id}"`);
2662
+ return hit ? { ...sig, pos: round(hit.pos), track: trackIdOf.get(hit.routeId) ?? sig.track } : sig;
2663
+ });
2664
+ const doc = {
2665
+ version: 1,
2666
+ ...base,
2667
+ lengthInches,
2668
+ endplates,
2669
+ tracks,
2670
+ turnouts,
2671
+ ...industries ? { industries } : {},
2672
+ ...signals ? { signals } : {}
2673
+ };
2674
+ return { doc, graph, walk, warnings };
2675
+ }
2676
+ function deriveGraphDoc(doc, library = BUILT_IN_TRACK_PARTS) {
2677
+ const g = doc.graph;
2678
+ if (!g || !g.pieces?.length || !g.startAt) return { doc, warnings: [] };
2679
+ const meta = {};
2680
+ for (const t of doc.tracks ?? []) {
2681
+ if (t.role === "main") continue;
2682
+ meta[t.id] = {
2683
+ ...t.trackName ? { trackName: t.trackName } : {},
2684
+ ...t.capacityFeet != null ? { capacityFeet: t.capacityFeet } : {},
2685
+ ...t.moduleTrackId != null ? { moduleTrackId: t.moduleTrackId } : {}
2686
+ };
2687
+ }
2688
+ const out = graphToDoc(g.pieces, { startAt: g.startAt, base: doc, meta, library });
2689
+ return { doc: out.doc, warnings: out.warnings };
2690
+ }
2437
2691
  function frogCasting(cl, opts = {}) {
2438
2692
  const g = opts.gaugeInches ?? RAIL_GAUGE_INCHES;
2439
2693
  const w = opts.reachInches ?? g * 1.5;
@@ -3067,6 +3321,6 @@ function poseOverridesFromDoc(doc) {
3067
3321
  return out;
3068
3322
  }
3069
3323
 
3070
- export { ATLAS_CODE55_N, BUILT_IN_TRACK_PARTS, CLEARANCE_SPACING_INCHES, CODE55_RAIL_HEIGHT_INCHES, DEFAULT_FLEX_PART_ID, ENDPLATE_FASCIA_CLEAR_INCHES, ENDPLATE_LEAD_INCHES, FAST_TRACKS_N_ME55, FAST_TRACKS_N_ME55_CROSSOVERS, FLEX_TRACK_PARTS, FREEMO_ENDPLATE_TRACK_FASCIA_CLEARANCE_INCHES, FREEMO_ENDPLATE_WIDTH_MIN_INCHES, FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES, FREEMO_TRACK_SPACING_INCHES, JOINT_SNAP_INCHES, MAIN2_TRACK_ID, MAIN_TRACK_ID, N_CAR_LENGTH_INCHES, N_SCALE_RATIO, PINCH_EASE_INCHES, RAIL_GAUGE_INCHES, TIE_HALF_LENGTH_INCHES, TURNOUT_LEAD_INCHES_PER_FROG, WHOLE_MODULE_SECTION_ID, asModuleSchematic, assessSectionEnd, assessSectionJoint, benchworkBand, benchworkOutline, buildCrossover, buildPassingSiding, buildTrackGraph, buildTransition, carCapacity, checkEndplateWidth, clearancePointPastFrogInches, crossoverPinches, deriveEndplatePoses, divergeSideForHand, docToState, emptyEditorState, endplateCentreOffsetInches, endplateEdgePose, endplateFaceSegments, endplateLead, endplateTrackOffsetInches, endplateWidthInches, flexPartFor, flexParts, flexPieces, flexUsage, frogCasting, frogNumberFromName, fromSectionRelative, geometryTurnDegrees, hasNoFarEndplate, importedPartToTrackPart, inchesToScaleFeet, isLoopDoc, isTransitionTurnout, laneOffsetAt, leadInchesForSize, maxFlexPieceInches, mergeImportedParts, mergeStoredParts, moduleCenterline, moduleFeatures, moduleFootprint, moduleLengthFromSections, moduleSections, nextId, parseXtpLibrary, partExtent, partExtentForSize, partGeometry, partGeometryGap, partOutlineAtFrog, partsPlaceable, pastFrogInchesForSize, pathLengthInches, placedJoints, poseNeedsManual, poseOverridesFromDoc, remapPos, resizeFlexPiece, returnLoop, sampleBenchworkOutline, samplePartSegments, samplePath, scaleFeetToInches, sectionAdjacency, sectionBand, sectionBreaksFromSections, sectionComponents, sectionFootprints, sectionNeighbours, sectionSpans, sectionSpansOrWhole, sectionedCenterline, sectionedEndPose, sliceCenterline, spanOverhang, stateToDoc, storedPartToTrackPart, toSectionRelative, trackMeetsEndplateIssues, trackPart, trackPath, turnoutClosure, turnoutFacing, turnoutOccupiedSpan, turnoutPartForSize, usableCapacity, walkTrackGraph };
3324
+ export { ATLAS_CODE55_N, BUILT_IN_TRACK_PARTS, CLEARANCE_SPACING_INCHES, CODE55_RAIL_HEIGHT_INCHES, DEFAULT_FLEX_PART_ID, ENDPLATE_FASCIA_CLEAR_INCHES, ENDPLATE_LEAD_INCHES, FAST_TRACKS_N_ME55, FAST_TRACKS_N_ME55_CROSSOVERS, FLEX_TRACK_PARTS, FREEMO_ENDPLATE_TRACK_FASCIA_CLEARANCE_INCHES, FREEMO_ENDPLATE_WIDTH_MIN_INCHES, FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES, FREEMO_TRACK_SPACING_INCHES, JOINT_SNAP_INCHES, MAIN2_TRACK_ID, MAIN_TRACK_ID, N_CAR_LENGTH_INCHES, N_SCALE_RATIO, PINCH_EASE_INCHES, RAIL_GAUGE_INCHES, TIE_HALF_LENGTH_INCHES, TURNOUT_LEAD_INCHES_PER_FROG, WHOLE_MODULE_SECTION_ID, asModuleSchematic, assessSectionEnd, assessSectionJoint, benchworkBand, benchworkOutline, buildCrossover, buildPassingSiding, buildTrackGraph, buildTransition, carCapacity, checkEndplateWidth, clearancePointPastFrogInches, crossoverPinches, deriveEndplatePoses, deriveGraphDoc, divergeSideForHand, docToState, emptyEditorState, endplateCentreOffsetInches, endplateEdgePose, endplateFaceSegments, endplateLead, endplateTrackOffsetInches, endplateWidthInches, flexPartFor, flexParts, flexPieces, flexUsage, frogCasting, frogNumberFromName, fromSectionRelative, geometryTurnDegrees, graphToDoc, hasNoFarEndplate, importedPartToTrackPart, inchesToScaleFeet, isLoopDoc, isTransitionTurnout, laneOffsetAt, leadInchesForSize, maxFlexPieceInches, mergeImportedParts, mergeStoredParts, moduleCenterline, moduleFeatures, moduleFootprint, moduleLengthFromSections, moduleSections, nextId, parseXtpLibrary, partExtent, partExtentForSize, partGeometry, partGeometryGap, partOutlineAtFrog, partsPlaceable, pastFrogInchesForSize, pathLengthInches, pieceRoutePaths, placedJoints, poseNeedsManual, poseOverridesFromDoc, remapPos, resizeFlexPiece, resolveGraphAnchor, returnLoop, sampleBenchworkOutline, samplePartSegments, samplePath, scaleFeetToInches, sectionAdjacency, sectionBand, sectionBreaksFromSections, sectionComponents, sectionFootprints, sectionNeighbours, sectionSpans, sectionSpansOrWhole, sectionedCenterline, sectionedEndPose, sliceCenterline, snapPiece, spanOverhang, stateToDoc, storedPartToTrackPart, toSectionRelative, trackMeetsEndplateIssues, trackPart, trackPath, turnoutClosure, turnoutFacing, turnoutOccupiedSpan, turnoutPartForSize, usableCapacity, walkTrackGraph };
3071
3325
  //# sourceMappingURL=index.js.map
3072
3326
  //# sourceMappingURL=index.js.map