@willcgage/module-schematic 0.41.0 → 0.42.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
@@ -695,7 +695,9 @@ function stateToDoc(state, recordNumber) {
695
695
  // C, D, E…
696
696
  label: b.label || `Branch ${i + 1}`,
697
697
  tracks: [{ trackId: MAIN_TRACK_ID, lane: 0, config: b.config }],
698
- at: { pos: b.pos, side: b.side }
698
+ at: { pos: b.pos, side: b.side },
699
+ kind: b.kind ?? "branch",
700
+ ...b.trackId ? { trackId: b.trackId } : {}
699
701
  }))
700
702
  ],
701
703
  state.poseOverrides
@@ -897,7 +899,9 @@ function docToState(doc, fallbackLength, moduleTracks = []) {
897
899
  label: ep.label ?? "Branch",
898
900
  pos: sc(ep.at.pos),
899
901
  side: ep.at.side === "down" ? "down" : "up",
900
- config: ep.tracks?.[0]?.config === "double" ? "double" : "single"
902
+ config: ep.tracks?.[0]?.config === "double" ? "double" : "single",
903
+ kind: ep.kind === "main" ? "main" : "branch",
904
+ trackId: ep.trackId ?? null
901
905
  })),
902
906
  poseOverrides,
903
907
  endplateWidths,
@@ -1407,6 +1411,67 @@ function deriveEndplatePoses(geo) {
1407
1411
  }
1408
1412
  return poses;
1409
1413
  }
1414
+ var ENDPLATE_LEAD_INCHES = 4;
1415
+ var ENDPLATE_FASCIA_CLEAR_INCHES = 4;
1416
+ function endplateLead(pose, leadInches = ENDPLATE_LEAD_INCHES) {
1417
+ const inwardHeading = norm360(pose.heading + 180);
1418
+ const r = inwardHeading * DEG;
1419
+ return {
1420
+ face: { x: pose.x, y: pose.y },
1421
+ inboard: { x: pose.x + Math.cos(r) * leadInches, y: pose.y + Math.sin(r) * leadInches },
1422
+ inwardHeading
1423
+ };
1424
+ }
1425
+ function trackMeetsEndplateIssues(path, pose, opts) {
1426
+ const issues = [];
1427
+ const lead = opts?.leadInches ?? ENDPLATE_LEAD_INCHES;
1428
+ const tol = opts?.toleranceDeg ?? 5;
1429
+ if (path && path.length >= 2) {
1430
+ const seq = (opts?.end ?? "last") === "last" ? [...path].reverse() : path.slice();
1431
+ const p0 = seq[0];
1432
+ const p1 = seq[1];
1433
+ const wantIn = norm360(pose.heading + 180);
1434
+ const inHead = norm360(Math.atan2(p1.y - p0.y, p1.x - p0.x) / DEG);
1435
+ const diff = Math.abs((inHead - wantIn + 540) % 360 - 180);
1436
+ if (diff > tol)
1437
+ issues.push({
1438
+ code: "not-perpendicular",
1439
+ message: `Track must cross the endplate square (within ${tol}\xB0); it is off by ${Math.round(diff)}\xB0.`
1440
+ });
1441
+ const r = wantIn * DEG;
1442
+ const ux = Math.cos(r);
1443
+ const uy = Math.sin(r);
1444
+ let curved = false;
1445
+ let acc = 0;
1446
+ for (let i = 1; i < seq.length && acc < lead; i++) {
1447
+ const a = seq[i - 1];
1448
+ const b = seq[i];
1449
+ if (a.bulge) curved = true;
1450
+ const rx = b.x - p0.x;
1451
+ const ry = b.y - p0.y;
1452
+ const along = rx * ux + ry * uy;
1453
+ const lat = Math.abs(rx * -uy + ry * ux);
1454
+ if (along <= lead + 0.01 && lat > 0.25) curved = true;
1455
+ acc += Math.hypot(b.x - a.x, b.y - a.y);
1456
+ }
1457
+ if (curved)
1458
+ issues.push({
1459
+ code: "short-lead",
1460
+ message: `The first ${lead}\u2033 from the endplate must be straight and perpendicular.`
1461
+ });
1462
+ }
1463
+ const w = opts?.faceWidthInches;
1464
+ const off = opts?.trackOffsetInches;
1465
+ if (typeof w === "number" && w > 0 && typeof off === "number") {
1466
+ const clear = w / 2 - Math.abs(off);
1467
+ if (clear < ENDPLATE_FASCIA_CLEAR_INCHES)
1468
+ issues.push({
1469
+ code: "fascia-clearance",
1470
+ message: `Track must stay \u2265${ENDPLATE_FASCIA_CLEAR_INCHES}\u2033 from either fascia; it is ${clear.toFixed(1)}\u2033.`
1471
+ });
1472
+ }
1473
+ return issues;
1474
+ }
1410
1475
  function poseNeedsManual(geometryType) {
1411
1476
  return geometryType === "wye" || geometryType === "other";
1412
1477
  }
@@ -1420,6 +1485,8 @@ function poseOverridesFromDoc(doc) {
1420
1485
  return out;
1421
1486
  }
1422
1487
 
1488
+ exports.ENDPLATE_FASCIA_CLEAR_INCHES = ENDPLATE_FASCIA_CLEAR_INCHES;
1489
+ exports.ENDPLATE_LEAD_INCHES = ENDPLATE_LEAD_INCHES;
1423
1490
  exports.FREEMO_ENDPLATE_TRACK_FASCIA_CLEARANCE_INCHES = FREEMO_ENDPLATE_TRACK_FASCIA_CLEARANCE_INCHES;
1424
1491
  exports.FREEMO_ENDPLATE_WIDTH_MIN_INCHES = FREEMO_ENDPLATE_WIDTH_MIN_INCHES;
1425
1492
  exports.FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES = FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES;
@@ -1442,6 +1509,7 @@ exports.divergeSideForHand = divergeSideForHand;
1442
1509
  exports.docToState = docToState;
1443
1510
  exports.emptyEditorState = emptyEditorState;
1444
1511
  exports.endplateFaceSegments = endplateFaceSegments;
1512
+ exports.endplateLead = endplateLead;
1445
1513
  exports.endplateTrackOffsetFor = endplateTrackOffsetFor;
1446
1514
  exports.endplateTrackOffsetInches = endplateTrackOffsetInches;
1447
1515
  exports.endplateWidthInches = endplateWidthInches;
@@ -1475,6 +1543,7 @@ exports.sectionedEndPose = sectionedEndPose;
1475
1543
  exports.sliceCenterline = sliceCenterline;
1476
1544
  exports.stateToDoc = stateToDoc;
1477
1545
  exports.toSectionRelative = toSectionRelative;
1546
+ exports.trackMeetsEndplateIssues = trackMeetsEndplateIssues;
1478
1547
  exports.trackPath = trackPath;
1479
1548
  //# sourceMappingURL=index.cjs.map
1480
1549
  //# sourceMappingURL=index.cjs.map