@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 CHANGED
@@ -45,6 +45,45 @@ function sampleBenchworkOutline(pts, segsPerArc = 20) {
45
45
  }
46
46
  return out;
47
47
  }
48
+ function samplePath(pts, segsPerArc = 20) {
49
+ const n = pts.length;
50
+ if (n < 2) return pts.map((p) => ({ x: p.x, y: p.y }));
51
+ const out = [];
52
+ for (let i = 0; i < n - 1; i++) {
53
+ const p0 = pts[i];
54
+ const p1 = pts[i + 1];
55
+ out.push({ x: p0.x, y: p0.y });
56
+ const bulge = p0.bulge ?? 0;
57
+ if (!bulge) continue;
58
+ const dx = p1.x - p0.x;
59
+ const dy = p1.y - p0.y;
60
+ const c = Math.hypot(dx, dy);
61
+ if (c < 1e-6) continue;
62
+ const nx = -dy / c;
63
+ const ny = dx / c;
64
+ const mid = { x: (p0.x + p1.x) / 2 + nx * bulge, y: (p0.y + p1.y) / 2 + ny * bulge };
65
+ const circ = circleThrough(p0, mid, p1);
66
+ if (!circ) continue;
67
+ const a0 = Math.atan2(p0.y - circ.cy, p0.x - circ.cx);
68
+ const am = Math.atan2(mid.y - circ.cy, mid.x - circ.cx);
69
+ const a1 = Math.atan2(p1.y - circ.cy, p1.x - circ.cx);
70
+ const sweep = arcSweep(a0, a1, am);
71
+ for (let s = 1; s < segsPerArc; s++) {
72
+ const a = a0 + sweep * s / segsPerArc;
73
+ out.push({ x: circ.cx + circ.r * Math.cos(a), y: circ.cy + circ.r * Math.sin(a) });
74
+ }
75
+ }
76
+ out.push({ x: pts[n - 1].x, y: pts[n - 1].y });
77
+ return out;
78
+ }
79
+ function trackPath(path) {
80
+ const pts = (path ?? []).filter((p) => p && Number.isFinite(p.x) && Number.isFinite(p.y)).map((p) => ({
81
+ x: p.x,
82
+ y: p.y,
83
+ ...Number.isFinite(p.bulge) && p.bulge ? { bulge: p.bulge } : {}
84
+ }));
85
+ return pts.length >= 2 ? pts : null;
86
+ }
48
87
  function circleThrough(a, b, c) {
49
88
  const d = 2 * (a.x * (b.y - c.y) + b.x * (c.y - a.y) + c.x * (a.y - b.y));
50
89
  if (Math.abs(d) < 1e-9) return null;
@@ -67,6 +106,8 @@ function arcSweep(a0, a1, am) {
67
106
  }
68
107
  var DEG_FP = Math.PI / 180;
69
108
  function moduleCenterline(input) {
109
+ const drawn = trackPath(input.mainPath);
110
+ if (drawn) return samplePath(drawn);
70
111
  const L = input.lengthInches > 0 ? input.lengthInches : 24;
71
112
  const gt = input.geometryType;
72
113
  if (gt === "dead_end") return [{ x: 0, y: 0 }];
@@ -176,7 +217,8 @@ function emptyEditorState(lengthInches) {
176
217
  endplateWidths: {},
177
218
  outline: [],
178
219
  controlPoints: [],
179
- industries: []
220
+ industries: [],
221
+ mainPath: []
180
222
  };
181
223
  }
182
224
  function isTransitionTurnout(t) {
@@ -313,7 +355,8 @@ function stateToDoc(state, recordNumber) {
313
355
  moduleTrackId: t.moduleTrackId,
314
356
  trackName: t.trackName || void 0,
315
357
  capacityFeet: Math.round(inchesToScaleFeet(Math.abs(t.toPos - t.fromPos))),
316
- ...state.loop && t.inLoop ? { inLoop: true } : {}
358
+ ...state.loop && t.inLoop ? { inLoop: true } : {},
359
+ ...t.path && t.path.length >= 2 ? { path: t.path } : {}
317
360
  }))
318
361
  ],
319
362
  turnouts: state.turnouts.map((t) => ({
@@ -322,7 +365,8 @@ function stateToDoc(state, recordNumber) {
322
365
  onTrack: t.onTrack,
323
366
  divergeTrack: t.divergeTrack,
324
367
  kind: t.kind,
325
- name: t.name || void 0
368
+ name: t.name || void 0,
369
+ ...t.size ? { size: t.size } : {}
326
370
  })),
327
371
  ...state.crossings.length > 0 ? {
328
372
  crossings: state.crossings.map((x) => ({
@@ -363,7 +407,9 @@ function stateToDoc(state, recordNumber) {
363
407
  } : {},
364
408
  // Benchwork footprint outline (module-local inches); only when it's a real
365
409
  // ring (≥ 3 vertices).
366
- ...state.outline.length >= 3 ? { outline: state.outline } : {}
410
+ ...state.outline.length >= 3 ? { outline: state.outline } : {},
411
+ // Authored mainline path (module-local inches); only when it's a real path.
412
+ ...state.mainPath.length >= 2 ? { mainPath: state.mainPath } : {}
367
413
  };
368
414
  }
369
415
  function docToState(doc, fallbackLength, moduleTracks = []) {
@@ -393,7 +439,9 @@ function docToState(doc, fallbackLength, moduleTracks = []) {
393
439
  toPos: t.toPos != null ? sc(t.toPos) : len,
394
440
  moduleTrackId,
395
441
  trackName: t.trackName ?? nameOf(moduleTrackId),
396
- ...t.inLoop ? { inLoop: true } : {}
442
+ ...t.inLoop ? { inLoop: true } : {},
443
+ // Authored path kept as-drawn (a physical shape, not rescaled with length).
444
+ ...trackPath(t.path) ? { path: trackPath(t.path) } : {}
397
445
  });
398
446
  }
399
447
  }
@@ -442,6 +490,7 @@ function docToState(doc, fallbackLength, moduleTracks = []) {
442
490
  y: p.y,
443
491
  ...Number.isFinite(p.bulge) && p.bulge ? { bulge: p.bulge } : {}
444
492
  }));
493
+ const mainPath = trackPath(d.mainPath) ?? [];
445
494
  return {
446
495
  lengthInches: len,
447
496
  loop,
@@ -458,6 +507,7 @@ function docToState(doc, fallbackLength, moduleTracks = []) {
458
507
  poseOverrides,
459
508
  endplateWidths,
460
509
  outline,
510
+ mainPath,
461
511
  crossings: (d.crossings ?? []).map((x) => ({
462
512
  id: x.id,
463
513
  name: x.name ?? "",
@@ -472,7 +522,8 @@ function docToState(doc, fallbackLength, moduleTracks = []) {
472
522
  pos: sc(t.pos),
473
523
  onTrack: t.onTrack,
474
524
  divergeTrack: t.divergeTrack,
475
- kind: t.kind ?? "right"
525
+ kind: t.kind ?? "right",
526
+ ...t.size ? { size: t.size } : {}
476
527
  })),
477
528
  controlPoints: readControlPoints(d, sc),
478
529
  industries: (d.industries ?? []).map((ind) => ({
@@ -974,7 +1025,9 @@ exports.nextId = nextId;
974
1025
  exports.poseNeedsManual = poseNeedsManual;
975
1026
  exports.poseOverridesFromDoc = poseOverridesFromDoc;
976
1027
  exports.sampleBenchworkOutline = sampleBenchworkOutline;
1028
+ exports.samplePath = samplePath;
977
1029
  exports.scaleFeetToInches = scaleFeetToInches;
978
1030
  exports.stateToDoc = stateToDoc;
1031
+ exports.trackPath = trackPath;
979
1032
  //# sourceMappingURL=index.cjs.map
980
1033
  //# sourceMappingURL=index.cjs.map