@willcgage/module-schematic 0.109.0 → 0.110.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
@@ -3147,8 +3147,12 @@ function graphToDoc(pieces, input) {
3147
3147
  for (const t of tracks) {
3148
3148
  if (t.role === "main") continue;
3149
3149
  const ends = turnouts.filter((sw) => sw.divergeTrack === t.id);
3150
- if (ends.length >= 2 && new Set(ends.map((sw) => sw.onTrack)).size >= 2)
3151
- t.role = "crossover";
3150
+ if (!(ends.length >= 2 && new Set(ends.map((sw) => sw.onTrack)).size >= 2)) continue;
3151
+ t.role = "crossover";
3152
+ const at = ends.map((sw) => sw.pos);
3153
+ t.fromPos = round(Math.min(...at));
3154
+ t.toPos = round(Math.max(...at));
3155
+ t.lane = main2Lane || 1;
3152
3156
  }
3153
3157
  const place = (a, what) => {
3154
3158
  if (!a) return null;
@@ -3415,7 +3419,12 @@ function docToGraph(doc, answers = {}, library = BUILT_IN_TRACK_PARTS) {
3415
3419
  const ends = [branch?.fromPos, branch?.toPos].filter(
3416
3420
  (n) => typeof n === "number" && Number.isFinite(n)
3417
3421
  );
3418
- const divergeFarPos = ends.length ? ends.reduce((a, b) => Math.abs(b - t.pos) > Math.abs(a - t.pos) ? b : a) : void 0;
3422
+ const divergeFarPos = (
3423
+ // ⭐ A crossover half diverges TOWARD its partner. Its diverging track is a
3424
+ // MAIN, whose ends are the whole module, so the ordinary rule has nothing
3425
+ // useful to sign and would point it away from the turnout it feeds.
3426
+ divergeFarOverride.get(t.id) ?? (ends.length ? ends.reduce((a, b) => Math.abs(b - t.pos) > Math.abs(a - t.pos) ? b : a) : void 0)
3427
+ );
3419
3428
  const facing = turnoutFacing({
3420
3429
  pos: t.pos,
3421
3430
  divergeFarPos,
@@ -3532,6 +3541,7 @@ function docToGraph(doc, answers = {}, library = BUILT_IN_TRACK_PARTS) {
3532
3541
  fromPos: a.x0,
3533
3542
  toPos: a.x0 + a.geom.lengthInches
3534
3543
  }));
3544
+ const mainIdsAll = new Set(mains.map((m) => m.id));
3535
3545
  const attachment = /* @__PURE__ */ new Map();
3536
3546
  for (const t of turnouts) {
3537
3547
  const m = mains.find((x) => x.id === t.divergeTrack && x.id !== main.id);
@@ -3540,11 +3550,27 @@ function docToGraph(doc, answers = {}, library = BUILT_IN_TRACK_PARTS) {
3540
3550
  const to = m.toPos ?? mainLen;
3541
3551
  if (from > 0 && Math.abs(t.pos - from) < 0.01) attachment.set(m.id, { sw: t, at: "from" });
3542
3552
  else if (Math.abs(t.pos - to) < 0.01) attachment.set(m.id, { sw: t, at: "to" });
3543
- else
3544
- notLaid.push({
3545
- id: m.id,
3546
- why: `${t.name || t.id} joins ${m.id} at ${t.pos}\u2033, which is neither end of it \u2014 two mains joined partway along are a crossover, and this document has no connector track between them to lay one from`
3547
- });
3553
+ }
3554
+ const mainToMainPairs = [];
3555
+ {
3556
+ const isMain = (id) => mainIdsAll.has(id);
3557
+ const used = /* @__PURE__ */ new Set();
3558
+ for (const t of turnouts) {
3559
+ if (used.has(t.id) || !isMain(t.onTrack) || !isMain(t.divergeTrack)) continue;
3560
+ if (t.onTrack === t.divergeTrack) continue;
3561
+ const partner = turnouts.filter(
3562
+ (u) => !used.has(u.id) && u.id !== t.id && u.onTrack === t.divergeTrack && u.divergeTrack === t.onTrack
3563
+ ).sort((x, y) => Math.abs(x.pos - t.pos) - Math.abs(y.pos - t.pos))[0];
3564
+ if (!partner) continue;
3565
+ used.add(t.id);
3566
+ used.add(partner.id);
3567
+ mainToMainPairs.push({ a: t, b: partner });
3568
+ }
3569
+ }
3570
+ const divergeFarOverride = /* @__PURE__ */ new Map();
3571
+ for (const { a, b } of mainToMainPairs) {
3572
+ divergeFarOverride.set(a.id, b.pos);
3573
+ divergeFarOverride.set(b.id, a.pos);
3548
3574
  }
3549
3575
  for (const m of mains) {
3550
3576
  if (attachment.get(m.id)?.at === "from") continue;
@@ -3599,6 +3625,35 @@ function docToGraph(doc, answers = {}, library = BUILT_IN_TRACK_PARTS) {
3599
3625
  done.add(m.id);
3600
3626
  }
3601
3627
  for (const id of assemblyTracks) done.add(id);
3628
+ for (const [i, pair] of mainToMainPairs.entries()) {
3629
+ const la = laidTurnouts.get(pair.a.id);
3630
+ const lb = laidTurnouts.get(pair.b.id);
3631
+ if (!la || !lb) continue;
3632
+ const ja = jointAt(la.piece, la.divergeId);
3633
+ const jb = jointAt(lb.piece, lb.divergeId);
3634
+ if (!ja || !jb) continue;
3635
+ const dx = jb.x - ja.x;
3636
+ const dy = jb.y - ja.y;
3637
+ const len = Math.hypot(dx, dy);
3638
+ if (!(len > 1e-6)) {
3639
+ notLaid.push({
3640
+ id: pair.a.divergeTrack,
3641
+ why: `${pair.a.name || pair.a.id} and ${pair.b.name || pair.b.id} meet at the same point, so there is no track between them to lay`
3642
+ });
3643
+ continue;
3644
+ }
3645
+ pieces.push({
3646
+ id: `xc-${i}`,
3647
+ partId: flexId,
3648
+ x: ja.x,
3649
+ y: ja.y,
3650
+ rotationDeg: Math.atan2(dy, dx) * 180 / Math.PI,
3651
+ lengthInches: r3(len)
3652
+ });
3653
+ warnings.push(
3654
+ `${pair.a.name || pair.a.id} and ${pair.b.name || pair.b.id} are laid as two separate turnouts with a ${len.toFixed(1)}\u2033 piece of track between them, which is what the document describes. If they are really one crossover assembly, name the product on a connector track and it will be laid as the single piece it is.`
3655
+ );
3656
+ }
3602
3657
  let progressed = true;
3603
3658
  while (progressed) {
3604
3659
  progressed = false;