@willcgage/module-schematic 0.59.0 → 0.61.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
@@ -117,6 +117,15 @@ function samplePath(pts, segsPerArc = 20) {
117
117
  out.push({ x: pts[n - 1].x, y: pts[n - 1].y });
118
118
  return out;
119
119
  }
120
+ function pathLengthInches(path) {
121
+ const pts = trackPath(path);
122
+ if (!pts) return 0;
123
+ const poly = samplePath(pts);
124
+ let total = 0;
125
+ for (let i = 1; i < poly.length; i++)
126
+ total += Math.hypot(poly[i].x - poly[i - 1].x, poly[i].y - poly[i - 1].y);
127
+ return total;
128
+ }
120
129
  function trackPath(path) {
121
130
  const pts = (path ?? []).filter((p) => p && Number.isFinite(p.x) && Number.isFinite(p.y)).map((p) => ({
122
131
  x: p.x,
@@ -1475,6 +1484,32 @@ function turnoutClosure(size, opts = {}) {
1475
1484
  }
1476
1485
  };
1477
1486
  }
1487
+ function frogCasting(cl, opts = {}) {
1488
+ const g = opts.gaugeInches ?? RAIL_GAUGE_INCHES;
1489
+ const w = opts.reachInches ?? g * 1.5;
1490
+ const fw = opts.flangewayInches ?? g * 0.12;
1491
+ const m = cl.frogSlope;
1492
+ const lead = cl.lead;
1493
+ const apex = { x: lead, y: g / 2 };
1494
+ const point = [
1495
+ { x: lead + w, y: g / 2 },
1496
+ apex,
1497
+ { x: lead + w, y: g / 2 + m * w }
1498
+ ];
1499
+ const wings = [
1500
+ [
1501
+ { x: lead - w, y: g / 2 - fw },
1502
+ { x: lead - w * 0.35, y: g / 2 - fw },
1503
+ { x: lead + w * 0.35, y: g / 2 - fw * 0.5 }
1504
+ ],
1505
+ [
1506
+ { x: lead - w, y: g / 2 + m * -w + fw },
1507
+ { x: lead - w * 0.35, y: g / 2 + m * -w * 0.35 + fw },
1508
+ { x: lead + w * 0.35, y: g / 2 + m * w * 0.35 + fw * 0.5 }
1509
+ ]
1510
+ ];
1511
+ return { point, wings, apex };
1512
+ }
1478
1513
  function divergeSideForHand(kind, stubDir, flipped) {
1479
1514
  if (kind !== "left" && kind !== "right") return 0;
1480
1515
  const s = (stubDir >= 0 ? 1 : -1) * (flipped ? -1 : 1);
@@ -1541,7 +1576,7 @@ function moduleFeatures(doc) {
1541
1576
  if (parentLane === 0) {
1542
1577
  const [from, to] = ext;
1543
1578
  const far = Math.abs(to - sw.pos) >= Math.abs(from - sw.pos) ? to : from;
1544
- const s = divergeSideForHand(sw.kind, far - sw.pos);
1579
+ const s = divergeSideForHand(sw.kind, far - sw.pos, sw.flipped);
1545
1580
  sign = s !== 0 ? s : Math.sign(trk.lane) || 1;
1546
1581
  } else {
1547
1582
  sign = Math.sign(parentLane) || 1;
@@ -1656,15 +1691,43 @@ function moduleFeatures(doc) {
1656
1691
  laneA: trackLane.get(x.tracks?.[0] ?? "") ?? 0,
1657
1692
  laneB: trackLane.get(x.tracks?.[1] ?? "") ?? 1
1658
1693
  }));
1694
+ const main2Lane = trackLane.has(MAIN2_TRACK_ID) ? trackLane.get(MAIN2_TRACK_ID) : null;
1695
+ const baseLanes = [
1696
+ 0,
1697
+ main2Lane ?? (doubleMain ? 1 : 0),
1698
+ ...extraTracks.map((t) => t.lane),
1699
+ ...signals.map((s) => s.lane),
1700
+ ...crossings.flatMap((x) => [x.laneA, x.laneB]),
1701
+ ...crossovers.flatMap((x) => [x.fromLane, x.toLane])
1702
+ ];
1703
+ let upLane = Math.max(...baseLanes, 0);
1704
+ let downLane = Math.min(...baseLanes, 0);
1659
1705
  const branchConnectors = doc.endplates.filter(
1660
1706
  (e) => e.id !== "A" && e.id !== "B" && e.at && !!e.trackId && (doc.tracks ?? []).some((t) => t.id === e.trackId)
1661
1707
  ).map((e) => {
1708
+ const trk = (doc.tracks ?? []).find((t) => t.id === e.trackId);
1662
1709
  const sw = (doc.turnouts ?? []).find((t) => t.divergeTrack === e.trackId);
1710
+ const startPos = sw ? sw.pos : e.at.pos;
1711
+ const side = e.at.side === "down" ? "down" : "up";
1712
+ const lane = side === "down" ? --downLane : ++upLane;
1713
+ const runInches = pathLengthInches(trk.path) || Math.abs(e.at.pos - startPos) || FREEMO_ENDPLATE_WIDTH_MIN_INCHES;
1714
+ const toB = e.at.pos >= startPos;
1715
+ const fits = (p) => p >= 0 && p <= len;
1716
+ const ahead = startPos + runInches;
1717
+ const behind = startPos - runInches;
1718
+ const endPos = toB && fits(ahead) ? ahead : !toB && fits(behind) ? behind : fits(toB ? behind : ahead) ? toB ? behind : ahead : ahead;
1663
1719
  return {
1664
1720
  id: e.id,
1665
1721
  label: e.label ?? e.id,
1666
- posFrac: clampFrac(sw ? sw.pos : e.at.pos),
1667
- side: e.at.side === "down" ? "down" : "up"
1722
+ name: trk.trackName ?? "",
1723
+ trackId: trk.id,
1724
+ kind: e.kind === "main" ? "main" : "branch",
1725
+ posFrac: clampFrac(startPos),
1726
+ fromLane: sw ? trackLane.get(sw.onTrack) ?? 0 : 0,
1727
+ side,
1728
+ lane,
1729
+ endFrac: clampFrac(endPos),
1730
+ lengthInches: runInches
1668
1731
  };
1669
1732
  });
1670
1733
  const industries = (doc.industries ?? []).flatMap((ind) => {
@@ -1689,15 +1752,7 @@ function moduleFeatures(doc) {
1689
1752
  };
1690
1753
  });
1691
1754
  });
1692
- const main2Lane = trackLane.has(MAIN2_TRACK_ID) ? trackLane.get(MAIN2_TRACK_ID) : null;
1693
- const allLanes = [
1694
- 0,
1695
- main2Lane ?? (doubleMain ? 1 : 0),
1696
- ...extraTracks.map((t) => t.lane),
1697
- ...signals.map((s) => s.lane),
1698
- ...crossings.flatMap((x) => [x.laneA, x.laneB]),
1699
- ...crossovers.flatMap((x) => [x.fromLane, x.toLane])
1700
- ];
1755
+ const allLanes = [...baseLanes, ...branchConnectors.map((b) => b.lane)];
1701
1756
  const loop = isLoopDoc(doc);
1702
1757
  const main2 = doc.tracks.find((t) => t.id === MAIN2_TRACK_ID);
1703
1758
  const main2Positioned = !!main2 && (main2.fromPos != null || main2.toPos != null) && !loop;
@@ -2021,6 +2076,7 @@ exports.endplateLead = endplateLead;
2021
2076
  exports.endplateTrackOffsetFor = endplateTrackOffsetFor;
2022
2077
  exports.endplateTrackOffsetInches = endplateTrackOffsetInches;
2023
2078
  exports.endplateWidthInches = endplateWidthInches;
2079
+ exports.frogCasting = frogCasting;
2024
2080
  exports.frogNumberFromName = frogNumberFromName;
2025
2081
  exports.fromSectionRelative = fromSectionRelative;
2026
2082
  exports.geometryTurnDegrees = geometryTurnDegrees;
@@ -2038,6 +2094,7 @@ exports.moduleSections = moduleSections;
2038
2094
  exports.nextId = nextId;
2039
2095
  exports.parseXtpLibrary = parseXtpLibrary;
2040
2096
  exports.partOutlineAtFrog = partOutlineAtFrog;
2097
+ exports.pathLengthInches = pathLengthInches;
2041
2098
  exports.poseNeedsManual = poseNeedsManual;
2042
2099
  exports.poseOverridesFromDoc = poseOverridesFromDoc;
2043
2100
  exports.remapPos = remapPos;