@tscircuit/schematic-trace-solver 0.0.177 → 0.0.179

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.
Files changed (21) hide show
  1. package/dist/index.d.ts +10 -1
  2. package/dist/index.js +331 -122
  3. package/lib/solvers/AvailableNetOrientationSolver/AvailableNetOrientationSolver.ts +79 -2
  4. package/lib/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver.ts +6 -1
  5. package/lib/solvers/TraceCleanupSolver/TraceCleanupSolver.ts +25 -0
  6. package/lib/solvers/TraceCleanupSolver/rerouteGeneratedNetLabelConnectorCrossings.ts +194 -0
  7. package/lib/solvers/TraceCleanupSolver/sub-solver/findIntersectionsWithObstacles.ts +19 -5
  8. package/lib/solvers/TraceCleanupSolver/sub-solver/generateLShapeRerouteCandidates.ts +35 -5
  9. package/package.json +1 -1
  10. package/site/bug-reports/bug-report-20260902T092101Z.page.tsx +4 -0
  11. package/site/bug-reports/bug-report-20260902T092425Z.page.tsx +4 -0
  12. package/tests/bug-reports/bug-report-20260902T092101Z/__snapshots__/bug-report-20260902T092101Z.snap.svg +117 -0
  13. package/tests/bug-reports/bug-report-20260902T092101Z/bug-report-20260902T092101Z.json +162 -0
  14. package/tests/bug-reports/bug-report-20260902T092101Z/bug-report-20260902T092101Z.test.ts +28 -0
  15. package/tests/bug-reports/bug-report-20260902T092425Z/__snapshots__/bug-report-20260902T092425Z.snap.svg +136 -0
  16. package/tests/bug-reports/bug-report-20260902T092425Z/bug-report-20260902T092425Z.json +238 -0
  17. package/tests/bug-reports/bug-report-20260902T092425Z/bug-report-20260902T092425Z.test.ts +12 -0
  18. package/tests/repros/__snapshots__/repro-pmp11282-isolated-dcdc.snap.svg +10 -10
  19. package/tests/repros/__snapshots__/repro-wireless-mouse-charger-section.snap.svg +2 -2
  20. package/tests/solvers/TraceCleanupSolver/alignSameNetRails-pipeline-label-connector.test.ts +4 -2
  21. package/tests/solvers/TraceCleanupSolver/reroute-generated-net-label-connector-crossings.test.ts +160 -0
package/dist/index.js CHANGED
@@ -325,19 +325,19 @@ var doesPairCrossRestrictedCenterLines = (params) => {
325
325
  chipMap
326
326
  });
327
327
  if (restrictedCenterLines.size === 0) return false;
328
- const EPS16 = 1e-9;
328
+ const EPS17 = 1e-9;
329
329
  const crossesSegment = (a, b) => {
330
330
  for (const [, rcl] of restrictedCenterLines) {
331
331
  if (rcl.axes.has("x") && typeof rcl.x === "number") {
332
- if ((a.x - rcl.x) * (b.x - rcl.x) < -EPS16) return true;
332
+ if ((a.x - rcl.x) * (b.x - rcl.x) < -EPS17) return true;
333
333
  }
334
334
  if (rcl.axes.has("y") && typeof rcl.y === "number") {
335
- if ((a.y - rcl.y) * (b.y - rcl.y) < -EPS16) return true;
335
+ if ((a.y - rcl.y) * (b.y - rcl.y) < -EPS17) return true;
336
336
  }
337
337
  }
338
338
  return false;
339
339
  };
340
- if (Math.abs(p1.x - p2.x) < EPS16 || Math.abs(p1.y - p2.y) < EPS16) {
340
+ if (Math.abs(p1.x - p2.x) < EPS17 || Math.abs(p1.y - p2.y) < EPS17) {
341
341
  return crossesSegment({ x: p1.x, y: p1.y }, { x: p2.x, y: p2.y });
342
342
  }
343
343
  const elbowHV = { x: p2.x, y: p1.y };
@@ -1581,8 +1581,8 @@ var SchematicTraceSingleLineSolver2 = class extends BaseSolver {
1581
1581
  if (!collision) {
1582
1582
  const first = path[0];
1583
1583
  const last = path[path.length - 1];
1584
- const EPS16 = 1e-9;
1585
- const samePoint = (p, q) => Math.abs(p.x - q.x) < EPS16 && Math.abs(p.y - q.y) < EPS16;
1584
+ const EPS17 = 1e-9;
1585
+ const samePoint = (p, q) => Math.abs(p.x - q.x) < EPS17 && Math.abs(p.y - q.y) < EPS17;
1586
1586
  if (samePoint(first, { x: PA.x, y: PA.y }) && samePoint(last, { x: PB.x, y: PB.y })) {
1587
1587
  this.solvedTracePath = path;
1588
1588
  this.solved = true;
@@ -1893,13 +1893,13 @@ var applyJogToTerminalSegment = ({
1893
1893
  segmentIndex: si,
1894
1894
  offset,
1895
1895
  JOG_SIZE,
1896
- EPS: EPS16 = 1e-6
1896
+ EPS: EPS17 = 1e-6
1897
1897
  }) => {
1898
1898
  if (si !== 0 && si !== pts.length - 2) return;
1899
1899
  const start = pts[si];
1900
1900
  const end = pts[si + 1];
1901
- const isVertical6 = Math.abs(start.x - end.x) < EPS16;
1902
- const isHorizontal5 = Math.abs(start.y - end.y) < EPS16;
1901
+ const isVertical6 = Math.abs(start.x - end.x) < EPS17;
1902
+ const isHorizontal5 = Math.abs(start.y - end.y) < EPS17;
1903
1903
  if (!isVertical6 && !isHorizontal5) return;
1904
1904
  const segDir = isVertical6 ? end.y > start.y ? 1 : -1 : end.x > start.x ? 1 : -1;
1905
1905
  if (pts.length === 2) {
@@ -2333,7 +2333,7 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
2333
2333
  return islands;
2334
2334
  }
2335
2335
  findNextOverlapIssue() {
2336
- const EPS16 = 2e-3;
2336
+ const EPS17 = 2e-3;
2337
2337
  const netIds = Object.keys(this.traceNetIslands);
2338
2338
  for (let i = 0; i < netIds.length; i++) {
2339
2339
  for (let j = i + 1; j < netIds.length; j++) {
@@ -2360,7 +2360,7 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
2360
2360
  segmentBIndex,
2361
2361
  rangeOverlap
2362
2362
  }) => {
2363
- if (rangeOverlap > EPS16) {
2363
+ if (rangeOverlap > EPS17) {
2364
2364
  const keyA = `${pathAIndex}:${segmentAIndex}`;
2365
2365
  const keyB = `${pathBIndex}:${segmentBIndex}`;
2366
2366
  if (!seenA.has(keyA)) {
@@ -2379,7 +2379,7 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
2379
2379
  }
2380
2380
  return;
2381
2381
  }
2382
- if (rangeOverlap < -EPS16) return;
2382
+ if (rangeOverlap < -EPS17) return;
2383
2383
  const pathA = pathsA[pathAIndex].tracePath;
2384
2384
  const pathB = pathsB[pathBIndex].tracePath;
2385
2385
  const segmentAStart = pathA[segmentAIndex];
@@ -2402,8 +2402,8 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
2402
2402
  for (let sa = 0; sa < ptsA.length - 1; sa++) {
2403
2403
  const a1 = ptsA[sa];
2404
2404
  const a2 = ptsA[sa + 1];
2405
- const aVert = Math.abs(a1.x - a2.x) < EPS16;
2406
- const aHorz = Math.abs(a1.y - a2.y) < EPS16;
2405
+ const aVert = Math.abs(a1.x - a2.x) < EPS17;
2406
+ const aHorz = Math.abs(a1.y - a2.y) < EPS17;
2407
2407
  if (!aVert && !aHorz) continue;
2408
2408
  for (let pb = 0; pb < pathsB.length; pb++) {
2409
2409
  const pathB = pathsB[pb];
@@ -2414,11 +2414,11 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
2414
2414
  for (let sb = 0; sb < ptsB.length - 1; sb++) {
2415
2415
  const b1 = ptsB[sb];
2416
2416
  const b2 = ptsB[sb + 1];
2417
- const bVert = Math.abs(b1.x - b2.x) < EPS16;
2418
- const bHorz = Math.abs(b1.y - b2.y) < EPS16;
2417
+ const bVert = Math.abs(b1.x - b2.x) < EPS17;
2418
+ const bHorz = Math.abs(b1.y - b2.y) < EPS17;
2419
2419
  if (!bVert && !bHorz) continue;
2420
2420
  if (aVert && bVert) {
2421
- if (Math.abs(a1.x - b1.x) < EPS16) {
2421
+ if (Math.abs(a1.x - b1.x) < EPS17) {
2422
2422
  recordCollinearInteraction({
2423
2423
  pathAIndex: pa,
2424
2424
  segmentAIndex: sa,
@@ -2428,7 +2428,7 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
2428
2428
  });
2429
2429
  }
2430
2430
  } else if (aHorz && bHorz) {
2431
- if (Math.abs(a1.y - b1.y) < EPS16) {
2431
+ if (Math.abs(a1.y - b1.y) < EPS17) {
2432
2432
  recordCollinearInteraction({
2433
2433
  pathAIndex: pa,
2434
2434
  segmentAIndex: sa,
@@ -2484,14 +2484,14 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
2484
2484
  return null;
2485
2485
  }
2486
2486
  findNextDiagonalSegment() {
2487
- const EPS16 = 2e-3;
2487
+ const EPS17 = 2e-3;
2488
2488
  for (const mspPairId in this.correctedTraceMap) {
2489
2489
  const tracePath = this.correctedTraceMap[mspPairId].tracePath;
2490
2490
  for (let i = 0; i < tracePath.length - 1; i++) {
2491
2491
  const p1 = tracePath[i];
2492
2492
  const p2 = tracePath[i + 1];
2493
- const isHorizontal5 = Math.abs(p1.y - p2.y) < EPS16;
2494
- const isVertical6 = Math.abs(p1.x - p2.x) < EPS16;
2493
+ const isHorizontal5 = Math.abs(p1.y - p2.y) < EPS17;
2494
+ const isVertical6 = Math.abs(p1.x - p2.x) < EPS17;
2495
2495
  if (!isHorizontal5 && !isVertical6) {
2496
2496
  return { mspPairId, tracePath, i, p1, p2 };
2497
2497
  }
@@ -2505,13 +2505,13 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
2505
2505
  return false;
2506
2506
  }
2507
2507
  const { mspPairId, tracePath, i, p1, p2 } = diagonalInfo;
2508
- const EPS16 = 2e-3;
2508
+ const EPS17 = 2e-3;
2509
2509
  const p0 = i > 0 ? tracePath[i - 1] : null;
2510
2510
  const p3 = i + 2 < tracePath.length ? tracePath[i + 2] : null;
2511
- const prevIsVertical = p0 ? Math.abs(p0.x - p1.x) < EPS16 : false;
2512
- const prevIsHorizontal = p0 ? Math.abs(p0.y - p1.y) < EPS16 : false;
2513
- const nextIsVertical = p3 ? Math.abs(p2.x - p3.x) < EPS16 : false;
2514
- const nextIsHorizontal = p3 ? Math.abs(p2.y - p3.y) < EPS16 : false;
2511
+ const prevIsVertical = p0 ? Math.abs(p0.x - p1.x) < EPS17 : false;
2512
+ const prevIsHorizontal = p0 ? Math.abs(p0.y - p1.y) < EPS17 : false;
2513
+ const nextIsVertical = p3 ? Math.abs(p2.x - p3.x) < EPS17 : false;
2514
+ const nextIsHorizontal = p3 ? Math.abs(p2.y - p3.y) < EPS17 : false;
2515
2515
  const elbow1 = { x: p1.x, y: p2.y };
2516
2516
  const elbow2 = { x: p2.x, y: p1.y };
2517
2517
  let score1 = 0;
@@ -2673,24 +2673,24 @@ var ChipObstacleSpatialIndex = class {
2673
2673
  };
2674
2674
 
2675
2675
  // lib/solvers/NetLabelPlacementSolver/SingleNetLabelPlacementSolver/collisions.ts
2676
- function segmentIntersectsRect2(p1, p2, rect, EPS16 = 1e-9) {
2677
- const isVert = Math.abs(p1.x - p2.x) < EPS16;
2678
- const isHorz = Math.abs(p1.y - p2.y) < EPS16;
2676
+ function segmentIntersectsRect2(p1, p2, rect, EPS17 = 1e-9) {
2677
+ const isVert = Math.abs(p1.x - p2.x) < EPS17;
2678
+ const isHorz = Math.abs(p1.y - p2.y) < EPS17;
2679
2679
  if (!isVert && !isHorz) return false;
2680
2680
  if (isVert) {
2681
2681
  const x = p1.x;
2682
- if (x < rect.minX - EPS16 || x > rect.maxX + EPS16) return false;
2682
+ if (x < rect.minX - EPS17 || x > rect.maxX + EPS17) return false;
2683
2683
  const segMinY = Math.min(p1.y, p2.y);
2684
2684
  const segMaxY = Math.max(p1.y, p2.y);
2685
2685
  const overlap = Math.min(segMaxY, rect.maxY) - Math.max(segMinY, rect.minY);
2686
- return overlap > EPS16;
2686
+ return overlap > EPS17;
2687
2687
  } else {
2688
2688
  const y = p1.y;
2689
- if (y < rect.minY - EPS16 || y > rect.maxY + EPS16) return false;
2689
+ if (y < rect.minY - EPS17 || y > rect.maxY + EPS17) return false;
2690
2690
  const segMinX = Math.min(p1.x, p2.x);
2691
2691
  const segMaxX = Math.max(p1.x, p2.x);
2692
2692
  const overlap = Math.min(segMaxX, rect.maxX) - Math.max(segMinX, rect.minX);
2693
- return overlap > EPS16;
2693
+ return overlap > EPS17;
2694
2694
  }
2695
2695
  }
2696
2696
  function rectIntersectsAnyTrace(bounds, inputTraceMap, hostPathId, hostSegIndex) {
@@ -3089,14 +3089,14 @@ var SingleNetLabelPlacementSolver = class extends BaseSolver {
3089
3089
  };
3090
3090
  let bestCandidate = null;
3091
3091
  let bestScore = -Infinity;
3092
- const EPS16 = 1e-6;
3092
+ const EPS17 = 1e-6;
3093
3093
  for (const curr of tracesToScan) {
3094
3094
  const pts = curr.tracePath.slice();
3095
3095
  for (let si = 0; si < pts.length - 1; si++) {
3096
3096
  const a = pts[si];
3097
3097
  const b = pts[si + 1];
3098
- const isH = Math.abs(a.y - b.y) < EPS16;
3099
- const isV = Math.abs(a.x - b.x) < EPS16;
3098
+ const isH = Math.abs(a.y - b.y) < EPS17;
3099
+ const isV = Math.abs(a.x - b.x) < EPS17;
3100
3100
  if (!isH && !isV) continue;
3101
3101
  const segmentAllowed = isH ? ["y+", "y-"] : ["x+", "x-"];
3102
3102
  const candidateOrients = orientations.filter(
@@ -6619,13 +6619,17 @@ var findIntersectionsWithObstacles = (p1, p2, obstacles) => {
6619
6619
  return intersections;
6620
6620
  };
6621
6621
  var isSamePoint = (first, second) => Math.abs(first.x - second.x) < EPS9 && Math.abs(first.y - second.y) < EPS9;
6622
- var findPerpendicularPathCrossings = (path, otherPath) => {
6622
+ var findPerpendicularPathCrossings = (path, otherPath, options = {}) => {
6623
6623
  const crossings = [];
6624
- for (let pathSegmentIndex = 1; pathSegmentIndex < path.length - 2; pathSegmentIndex++) {
6624
+ const firstPathSegmentIndex = options.includeTerminalSegments ? 0 : 1;
6625
+ const lastPathSegmentIndex = options.includeTerminalSegments ? path.length - 1 : path.length - 2;
6626
+ const firstOtherPathSegmentIndex = options.includeTerminalSegments ? 0 : 1;
6627
+ const lastOtherPathSegmentIndex = options.includeTerminalSegments ? otherPath.length - 1 : otherPath.length - 2;
6628
+ for (let pathSegmentIndex = firstPathSegmentIndex; pathSegmentIndex < lastPathSegmentIndex; pathSegmentIndex++) {
6625
6629
  const start = path[pathSegmentIndex];
6626
6630
  const end = path[pathSegmentIndex + 1];
6627
6631
  const isVertical6 = Math.abs(start.x - end.x) < EPS9;
6628
- for (let otherPathSegmentIndex = 1; otherPathSegmentIndex < otherPath.length - 2; otherPathSegmentIndex++) {
6632
+ for (let otherPathSegmentIndex = firstOtherPathSegmentIndex; otherPathSegmentIndex < lastOtherPathSegmentIndex; otherPathSegmentIndex++) {
6629
6633
  const otherStart = otherPath[otherPathSegmentIndex];
6630
6634
  const otherEnd = otherPath[otherPathSegmentIndex + 1];
6631
6635
  const otherIsVertical = Math.abs(otherStart.x - otherEnd.x) < EPS9;
@@ -6765,6 +6769,7 @@ var generatePerpendicularTraceDetours = ({
6765
6769
  segmentIndex,
6766
6770
  obstacleStart,
6767
6771
  obstacleEnd,
6772
+ obstacleBounds,
6768
6773
  chipBounds,
6769
6774
  clearance
6770
6775
  }) => {
@@ -6773,18 +6778,34 @@ var generatePerpendicularTraceDetours = ({
6773
6778
  const end = path[index + 1];
6774
6779
  const movingAxis = Math.abs(start.x - end.x) < EPS10 ? "y" : "x";
6775
6780
  const detourAxis = movingAxis === "x" ? "y" : "x";
6776
- const gate = obstacleStart[movingAxis] + Math.sign(start[movingAxis] - obstacleStart[movingAxis]) * clearance;
6777
- const obstacleRange = [obstacleStart[detourAxis], obstacleEnd[detourAxis]];
6781
+ const bounds = obstacleBounds ?? {
6782
+ minX: Math.min(obstacleStart.x, obstacleEnd.x),
6783
+ minY: Math.min(obstacleStart.y, obstacleEnd.y),
6784
+ maxX: Math.max(obstacleStart.x, obstacleEnd.x),
6785
+ maxY: Math.max(obstacleStart.y, obstacleEnd.y)
6786
+ };
6787
+ const movingLowBound = movingAxis === "x" ? "minX" : "minY";
6788
+ const movingHighBound = movingAxis === "x" ? "maxX" : "maxY";
6789
+ let gate = obstacleStart[movingAxis] + Math.sign(start[movingAxis] - obstacleStart[movingAxis]) * clearance;
6790
+ if (obstacleBounds) {
6791
+ const startSide = start[movingAxis] < (bounds[movingLowBound] + bounds[movingHighBound]) / 2 ? -1 : 1;
6792
+ gate = bounds[startSide < 0 ? movingLowBound : movingHighBound] + startSide * clearance;
6793
+ }
6778
6794
  const lowBound = detourAxis === "x" ? "minX" : "minY";
6779
6795
  const highBound = detourAxis === "x" ? "maxX" : "maxY";
6796
+ const minDetour = bounds[lowBound] - clearance;
6797
+ const maxDetour = bounds[highBound] + clearance;
6798
+ const nextAnchor = obstacleBounds ? path[index + 2] : void 0;
6799
+ const balancedDetour = nextAnchor ? nextAnchor[detourAxis] < minDetour ? (nextAnchor[detourAxis] + minDetour) / 2 : nextAnchor[detourAxis] > maxDetour ? (nextAnchor[detourAxis] + maxDetour) / 2 : void 0 : void 0;
6780
6800
  const detourCoordinates = [
6781
- Math.min(...obstacleRange) - clearance,
6782
- Math.max(...obstacleRange) + clearance,
6783
- ...chipBounds.flatMap((bounds) => [
6784
- bounds[lowBound] - clearance,
6785
- bounds[highBound] + clearance
6801
+ balancedDetour,
6802
+ minDetour,
6803
+ maxDetour,
6804
+ ...chipBounds.flatMap((bounds2) => [
6805
+ bounds2[lowBound] - clearance,
6806
+ bounds2[highBound] + clearance
6786
6807
  ])
6787
- ];
6808
+ ].filter((coordinate) => coordinate !== void 0);
6788
6809
  return [...new Set(detourCoordinates)].map(
6789
6810
  (detour) => simplifyPath([
6790
6811
  ...path.slice(0, index + 1),
@@ -7391,6 +7412,126 @@ var is4PointRectangle = (path) => {
7391
7412
  return isHVHC || isVHVC;
7392
7413
  };
7393
7414
 
7415
+ // lib/solvers/TraceCleanupSolver/rerouteGeneratedNetLabelConnectorCrossings.ts
7416
+ var EPS12 = 1e-6;
7417
+ var getConnectorObstacleBounds = (connector, segmentIndex, labels) => {
7418
+ const start = connector.tracePath[segmentIndex];
7419
+ const end = connector.tracePath[segmentIndex + 1];
7420
+ const bounds = {
7421
+ minX: Math.min(start.x, end.x),
7422
+ minY: Math.min(start.y, end.y),
7423
+ maxX: Math.max(start.x, end.x),
7424
+ maxY: Math.max(start.y, end.y)
7425
+ };
7426
+ for (const label of labels) {
7427
+ if (label.globalConnNetId !== connector.globalConnNetId) continue;
7428
+ if (!label.pinIds.every((pinId) => connector.pinIds.includes(pinId)))
7429
+ continue;
7430
+ if (!tracePathContainsPoint(connector.tracePath, label.anchorPoint))
7431
+ continue;
7432
+ const labelBounds = getRectBounds(label.center, label.width, label.height);
7433
+ bounds.minX = Math.min(bounds.minX, labelBounds.minX);
7434
+ bounds.minY = Math.min(bounds.minY, labelBounds.minY);
7435
+ bounds.maxX = Math.max(bounds.maxX, labelBounds.maxX);
7436
+ bounds.maxY = Math.max(bounds.maxY, labelBounds.maxY);
7437
+ }
7438
+ return bounds;
7439
+ };
7440
+ var getEligibleConnectorCrossings = (traces, connectorTraceIds, eligibleTraceIds) => {
7441
+ const crossings = [];
7442
+ for (const connector of traces) {
7443
+ if (!connectorTraceIds.has(connector.mspPairId)) continue;
7444
+ for (let traceIndex = 0; traceIndex < traces.length; traceIndex++) {
7445
+ const trace = traces[traceIndex];
7446
+ if (trace.mspPairId === connector.mspPairId) continue;
7447
+ if (connectorTraceIds.has(trace.mspPairId)) continue;
7448
+ if (trace.globalConnNetId === connector.globalConnNetId) continue;
7449
+ if (eligibleTraceIds && !eligibleTraceIds.has(trace.mspPairId)) continue;
7450
+ for (const crossing of findPerpendicularPathCrossings(
7451
+ trace.tracePath,
7452
+ connector.tracePath,
7453
+ { includeTerminalSegments: true }
7454
+ )) {
7455
+ crossings.push({
7456
+ traceIndex,
7457
+ connector,
7458
+ connectorSegmentIndex: crossing.otherPathSegmentIndex,
7459
+ traceSegmentIndex: crossing.pathSegmentIndex
7460
+ });
7461
+ }
7462
+ }
7463
+ }
7464
+ return crossings;
7465
+ };
7466
+ var rerouteGeneratedNetLabelConnectorCrossings = ({
7467
+ inputProblem,
7468
+ traces,
7469
+ netLabelPlacements,
7470
+ mergedLabelNetIdMap,
7471
+ clearance,
7472
+ eligibleTraceIds,
7473
+ connectorTraceIds
7474
+ }) => {
7475
+ const outputTraces = [...traces];
7476
+ const componentAndTextObstacles = getObstacleRects(inputProblem).filter(
7477
+ (obstacle) => obstacle.kind === "chip" || obstacle.kind === "text_box"
7478
+ );
7479
+ let reroutedTraceCount = 0;
7480
+ while (true) {
7481
+ const candidates = getEligibleConnectorCrossings(
7482
+ outputTraces,
7483
+ connectorTraceIds,
7484
+ eligibleTraceIds
7485
+ ).flatMap((crossing) => {
7486
+ const trace = outputTraces[crossing.traceIndex];
7487
+ const obstacleBounds = getConnectorObstacleBounds(
7488
+ crossing.connector,
7489
+ crossing.connectorSegmentIndex,
7490
+ netLabelPlacements
7491
+ );
7492
+ const foreignTraces = outputTraces.filter(
7493
+ (otherTrace) => otherTrace.mspPairId !== trace.mspPairId && otherTrace.globalConnNetId !== trace.globalConnNetId
7494
+ );
7495
+ const foreignLabelBounds = netLabelPlacements.filter((label) => {
7496
+ const mergedNetIds = mergedLabelNetIdMap[label.globalConnNetId];
7497
+ return mergedNetIds ? !mergedNetIds.has(trace.globalConnNetId) : label.globalConnNetId !== trace.globalConnNetId;
7498
+ }).map((label) => getRectBounds(label.center, label.width, label.height));
7499
+ return generatePerpendicularTraceDetours({
7500
+ trace,
7501
+ segmentIndex: crossing.traceSegmentIndex,
7502
+ obstacleStart: crossing.connector.tracePath[crossing.connectorSegmentIndex],
7503
+ obstacleEnd: crossing.connector.tracePath[crossing.connectorSegmentIndex + 1],
7504
+ obstacleBounds,
7505
+ chipBounds: [],
7506
+ clearance
7507
+ }).filter(
7508
+ (candidate) => getPathLength2(candidate.path) <= getPathLength2(trace.tracePath) + EPS12 && countTurns(candidate.path) <= countTurns(trace.tracePath) + 2 && !isPathCollidingWithObstacles(
7509
+ candidate.path,
7510
+ componentAndTextObstacles
7511
+ ) && !hasCollisionsWithLabels(candidate.path, foreignLabelBounds) && !isPathColliding(candidate.path, foreignTraces, trace.mspPairId).isColliding && !doesPathCoincideWithTraces(candidate.path, foreignTraces)
7512
+ ).map((candidate) => ({
7513
+ ...candidate,
7514
+ traceIndex: crossing.traceIndex
7515
+ }));
7516
+ });
7517
+ candidates.sort((first, second) => {
7518
+ const lengthDifference = getPathLength2(first.path) - getPathLength2(second.path);
7519
+ return Math.abs(lengthDifference) > EPS12 ? lengthDifference : countTurns(first.path) - countTurns(second.path);
7520
+ });
7521
+ const bestCandidate = candidates[0];
7522
+ if (!bestCandidate) break;
7523
+ outputTraces[bestCandidate.traceIndex] = {
7524
+ ...outputTraces[bestCandidate.traceIndex],
7525
+ tracePath: bestCandidate.path
7526
+ };
7527
+ reroutedTraceCount++;
7528
+ }
7529
+ return {
7530
+ traces: outputTraces,
7531
+ reroutedTraceCount
7532
+ };
7533
+ };
7534
+
7394
7535
  // lib/solvers/TraceCleanupSolver/TraceCleanupSolver.ts
7395
7536
  var DEFAULT_OPERATIONS = [
7396
7537
  "untangling_traces",
@@ -7442,6 +7583,9 @@ var TraceCleanupSolver = class extends BaseSolver {
7442
7583
  case "untangling_traces":
7443
7584
  this._runUntangleTracesStep();
7444
7585
  break;
7586
+ case "rerouting_generated_net_label_connector_crossings":
7587
+ this._runGeneratedNetLabelConnectorCrossingRerouteStep();
7588
+ break;
7445
7589
  case "minimizing_turns":
7446
7590
  this._runMinimizeTurnsStep();
7447
7591
  break;
@@ -7465,6 +7609,23 @@ var TraceCleanupSolver = class extends BaseSolver {
7465
7609
  allTraces: Array.from(this.tracesMap.values())
7466
7610
  });
7467
7611
  }
7612
+ _runGeneratedNetLabelConnectorCrossingRerouteStep() {
7613
+ const result = rerouteGeneratedNetLabelConnectorCrossings({
7614
+ inputProblem: this.input.inputProblem,
7615
+ traces: this.outputTraces,
7616
+ netLabelPlacements: this.input.allLabelPlacements,
7617
+ mergedLabelNetIdMap: this.input.mergedLabelNetIdMap,
7618
+ clearance: this.input.paddingBuffer,
7619
+ eligibleTraceIds: this.input.eligibleTraceIds,
7620
+ connectorTraceIds: this.input.netLabelConnectorTraceIds ?? /* @__PURE__ */ new Set()
7621
+ });
7622
+ this.outputTraces = result.traces;
7623
+ this.tracesMap = new Map(
7624
+ this.outputTraces.map((trace) => [trace.mspPairId, trace])
7625
+ );
7626
+ this.stats.reroutedGeneratedConnectorCrossingTraceCount = result.reroutedTraceCount;
7627
+ this._advancePipeline();
7628
+ }
7468
7629
  _runMinimizeTurnsStep() {
7469
7630
  if (this.traceIdQueue.length === 0) {
7470
7631
  this._advancePipeline();
@@ -8502,16 +8663,16 @@ var createPortOnlyLabelConnectorTrace = ({
8502
8663
  var LABEL_SEARCH_STEP = 0.05;
8503
8664
  var MAX_RECORDED_CANDIDATES = 2e3;
8504
8665
  var WICK_CLEARANCE = 1e-3;
8505
- var EPS12 = 1e-9;
8506
- var TRACE_BOUNDARY_TOLERANCE = WICK_CLEARANCE + EPS12;
8666
+ var EPS13 = 1e-9;
8667
+ var TRACE_BOUNDARY_TOLERANCE = WICK_CLEARANCE + EPS13;
8507
8668
  var CANDIDATE_SELECTED_COLOR2 = "blue";
8508
8669
  var CANDIDATE_REJECTED_COLOR2 = "red";
8509
8670
 
8510
8671
  // lib/solvers/AvailableNetOrientationSolver/geometry.ts
8511
8672
  var isYOrientation = (orientation) => orientation === "y+" || orientation === "y-";
8512
8673
  var isXOrientation = (orientation) => orientation === "x+" || orientation === "x-";
8513
- var rectsOverlap2 = (a, b) => Math.min(a.maxX, b.maxX) - Math.max(a.minX, b.minX) > EPS12 && Math.min(a.maxY, b.maxY) - Math.max(a.minY, b.minY) > EPS12;
8514
- var rangesOverlap = (minA, maxA, minB, maxB) => Math.min(maxA, maxB) - Math.max(minA, minB) > EPS12;
8674
+ var rectsOverlap2 = (a, b) => Math.min(a.maxX, b.maxX) - Math.max(a.minX, b.minX) > EPS13 && Math.min(a.maxY, b.maxY) - Math.max(a.minY, b.minY) > EPS13;
8675
+ var rangesOverlap = (minA, maxA, minB, maxB) => Math.min(maxA, maxB) - Math.max(minA, minB) > EPS13;
8515
8676
  var traceCrossesBoundsInterior = (bounds, traceMap) => {
8516
8677
  for (const trace of Object.values(traceMap)) {
8517
8678
  const points = trace.tracePath;
@@ -8534,7 +8695,7 @@ var segmentCrossesBoundsInterior = (p1, p2, bounds) => {
8534
8695
  return false;
8535
8696
  }
8536
8697
  if (sameX2(p1, p2)) {
8537
- if (p1.x <= interiorBounds.minX + EPS12 || p1.x >= interiorBounds.maxX - EPS12) {
8698
+ if (p1.x <= interiorBounds.minX + EPS13 || p1.x >= interiorBounds.maxX - EPS13) {
8538
8699
  return false;
8539
8700
  }
8540
8701
  return rangesOverlap(
@@ -8545,7 +8706,7 @@ var segmentCrossesBoundsInterior = (p1, p2, bounds) => {
8545
8706
  );
8546
8707
  }
8547
8708
  if (sameY2(p1, p2)) {
8548
- if (p1.y <= interiorBounds.minY + EPS12 || p1.y >= interiorBounds.maxY - EPS12) {
8709
+ if (p1.y <= interiorBounds.minY + EPS13 || p1.y >= interiorBounds.maxY - EPS13) {
8549
8710
  return false;
8550
8711
  }
8551
8712
  return rangesOverlap(
@@ -8593,8 +8754,8 @@ var simplifyOrthogonalPath = (path) => {
8593
8754
  return simplified;
8594
8755
  };
8595
8756
  var pointsEqual2 = (a, b) => sameX2(a, b) && sameY2(a, b);
8596
- var sameX2 = (a, b) => Math.abs(a.x - b.x) <= EPS12;
8597
- var sameY2 = (a, b) => Math.abs(a.y - b.y) <= EPS12;
8757
+ var sameX2 = (a, b) => Math.abs(a.x - b.x) <= EPS13;
8758
+ var sameY2 = (a, b) => Math.abs(a.y - b.y) <= EPS13;
8598
8759
  var getMaxSearchDistance = (inputProblem) => {
8599
8760
  const maxChipWidth = Math.max(
8600
8761
  ...inputProblem.chips.map((chip) => chip.width),
@@ -8753,7 +8914,7 @@ var AvailableNetOrientationObstacleIndex = class {
8753
8914
  }
8754
8915
  getTraceSegmentsInBounds(bounds) {
8755
8916
  if (!this.traceSegmentIndex) return [];
8756
- const searchBounds = getPaddedBounds(bounds, EPS12);
8917
+ const searchBounds = getPaddedBounds(bounds, EPS13);
8757
8918
  return this.traceSegmentIndex.search(
8758
8919
  searchBounds.minX,
8759
8920
  searchBounds.minY,
@@ -8766,7 +8927,7 @@ var AvailableNetOrientationObstacleIndex = class {
8766
8927
  for (let pointIndex = 0; pointIndex < tracePath.length - 1; pointIndex++) {
8767
8928
  const segmentBounds = getPaddedBounds(
8768
8929
  getSegmentBounds(tracePath[pointIndex], tracePath[pointIndex + 1]),
8769
- EPS12
8930
+ EPS13
8770
8931
  );
8771
8932
  for (const labelIndex of this.getLabelIndicesInBounds(segmentBounds)) {
8772
8933
  labelIndices.add(labelIndex);
@@ -8779,7 +8940,7 @@ var AvailableNetOrientationObstacleIndex = class {
8779
8940
  const start = tracePath[pointIndex];
8780
8941
  const end = tracePath[pointIndex + 1];
8781
8942
  const nearbyChips = this.chipObstacleSpatialIndex.getChipsInBounds(
8782
- getPaddedBounds(getSegmentBounds(start, end), EPS12)
8943
+ getPaddedBounds(getSegmentBounds(start, end), EPS13)
8783
8944
  );
8784
8945
  for (const chip of nearbyChips) {
8785
8946
  if (segmentCrossesBoundsInterior(start, end, chip.bounds)) return true;
@@ -8926,7 +9087,8 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
8926
9087
  getOutput() {
8927
9088
  return {
8928
9089
  traces: this.traces,
8929
- netLabelPlacements: this.outputNetLabelPlacements
9090
+ netLabelPlacements: this.outputNetLabelPlacements,
9091
+ netLabelConnectorTraceIds: this.netLabelConnectorTraceIds
8930
9092
  };
8931
9093
  }
8932
9094
  getProcessableLabelIndices() {
@@ -9247,7 +9409,7 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
9247
9409
  index,
9248
9410
  pin: this.pinMap[otherLabel.pinIds[0]]
9249
9411
  })).filter(
9250
- ({ index, pin: otherPin }) => this.crowdedPortOnlyLabelIndices.has(index) && otherPin?.chipId === pin.chipId && otherPin.x > pin.x + EPS12
9412
+ ({ index, pin: otherPin }) => this.crowdedPortOnlyLabelIndices.has(index) && otherPin?.chipId === pin.chipId && otherPin.x > pin.x + EPS13
9251
9413
  ).sort((a, b) => a.pin.x - b.pin.x)[0]?.pin;
9252
9414
  if (orientation === "y-" && nextPinToRight) return null;
9253
9415
  const anchorX = orientation === "y-" ? Math.max(
@@ -9280,7 +9442,7 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
9280
9442
  const centeredAnchorY = hasUpFacingStack ? (lowestUpFacingLabelY + highestUpFacingLabelY) / 2 : stackedAnchorY;
9281
9443
  const anchorYs = orientation === "y-" ? [centeredAnchorY, stackedAnchorY] : [stackedAnchorY];
9282
9444
  for (const anchorY of anchorYs) {
9283
- if (anchorY - label.anchorPoint.y > this.maxSearchDistance + EPS12) {
9445
+ if (anchorY - label.anchorPoint.y > this.maxSearchDistance + EPS13) {
9284
9446
  continue;
9285
9447
  }
9286
9448
  const candidate = this.createCandidate(
@@ -9309,11 +9471,11 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
9309
9471
  if (trace.globalConnNetId !== label.globalConnNetId) return false;
9310
9472
  const path = trace.tracePath;
9311
9473
  return path.some((point, pointIndex) => {
9312
- if (Math.abs(point.x - label.anchorPoint.x) > EPS12 || Math.abs(point.y - label.anchorPoint.y) > EPS12) {
9474
+ if (Math.abs(point.x - label.anchorPoint.x) > EPS13 || Math.abs(point.y - label.anchorPoint.y) > EPS13) {
9313
9475
  return false;
9314
9476
  }
9315
9477
  return [path[pointIndex - 1], path[pointIndex + 1]].some(
9316
- (neighbor) => neighbor && Math.abs(neighbor.x - point.x) <= EPS12 && (neighbor.y - point.y) * direction.y > EPS12
9478
+ (neighbor) => neighbor && Math.abs(neighbor.x - point.x) <= EPS13 && (neighbor.y - point.y) * direction.y > EPS13
9317
9479
  );
9318
9480
  });
9319
9481
  });
@@ -9403,7 +9565,7 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
9403
9565
  orientation
9404
9566
  );
9405
9567
  if (outwardDirection.x === 0 && outwardDirection.y === 0) continue;
9406
- for (let distance7 = LABEL_SEARCH_STEP; distance7 <= this.maxSearchDistance + EPS12; distance7 += LABEL_SEARCH_STEP) {
9568
+ for (let distance7 = LABEL_SEARCH_STEP; distance7 <= this.maxSearchDistance + EPS13; distance7 += LABEL_SEARCH_STEP) {
9407
9569
  const anchorPoint = {
9408
9570
  x: connectorSource.x + outwardDirection.x * distance7,
9409
9571
  y: connectorSource.y + outwardDirection.y * distance7
@@ -9481,7 +9643,7 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
9481
9643
  const furthestRowPoints = points.filter(
9482
9644
  (point) => Math.abs(
9483
9645
  point.x * direction.x + point.y * direction.y - furthestAlong
9484
- ) <= EPS12
9646
+ ) <= EPS13
9485
9647
  );
9486
9648
  const directHostPinIds = new Set(
9487
9649
  [...directHostTraceIds].flatMap(
@@ -9502,7 +9664,7 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
9502
9664
  preferNearestBendOnOutwardRow: adjacentTraces.some(
9503
9665
  (trace) => furthestRowPoints.some(
9504
9666
  (point) => trace.tracePath.some(
9505
- (tracePoint) => Math.abs(tracePoint.x - point.x) <= EPS12 && Math.abs(tracePoint.y - point.y) <= EPS12
9667
+ (tracePoint) => Math.abs(tracePoint.x - point.x) <= EPS13 && Math.abs(tracePoint.y - point.y) <= EPS13
9506
9668
  )
9507
9669
  )
9508
9670
  )
@@ -9514,7 +9676,7 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
9514
9676
  for (let i = 0; i < otherTrace.tracePath.length - 1; i++) {
9515
9677
  const start = otherTrace.tracePath[i];
9516
9678
  const end = otherTrace.tracePath[i + 1];
9517
- if (Math.abs(start.x - end.x) <= EPS12 && Math.abs(start.y - end.y) > EPS12) {
9679
+ if (Math.abs(start.x - end.x) <= EPS13 && Math.abs(start.y - end.y) > EPS13) {
9518
9680
  verticalRailXs.add(start.x);
9519
9681
  }
9520
9682
  }
@@ -9522,7 +9684,7 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
9522
9684
  for (let i = 0; i < trace.tracePath.length - 1; i++) {
9523
9685
  const start = trace.tracePath[i];
9524
9686
  const end = trace.tracePath[i + 1];
9525
- if (Math.abs(start.x - end.x) <= EPS12 && Math.abs(start.y - end.y) > EPS12 && [...verticalRailXs].some((x) => Math.abs(x - start.x) <= EPS12)) {
9687
+ if (Math.abs(start.x - end.x) <= EPS13 && Math.abs(start.y - end.y) > EPS13 && [...verticalRailXs].some((x) => Math.abs(x - start.x) <= EPS13)) {
9526
9688
  return true;
9527
9689
  }
9528
9690
  }
@@ -9541,7 +9703,7 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
9541
9703
  );
9542
9704
  const maxSearchDistance = this.getSearchDistanceLimit(label, orientation);
9543
9705
  const maxOutwardDistance = outwardDirection.x === 0 && outwardDirection.y === 0 ? 0 : this.maxSearchDistance;
9544
- for (let outwardDistance = 0; outwardDistance <= maxOutwardDistance + EPS12; outwardDistance += LABEL_SEARCH_STEP) {
9706
+ for (let outwardDistance = 0; outwardDistance <= maxOutwardDistance + EPS13; outwardDistance += LABEL_SEARCH_STEP) {
9545
9707
  const baseAnchor = {
9546
9708
  x: initialBaseAnchor.x + outwardDirection.x * outwardDistance,
9547
9709
  y: initialBaseAnchor.y + outwardDirection.y * outwardDistance
@@ -9617,16 +9779,21 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
9617
9779
  connectorSource,
9618
9780
  startDistance = LABEL_SEARCH_STEP
9619
9781
  } = params;
9620
- for (let distance7 = startDistance; distance7 <= maxSearchDistance + EPS12; distance7 += LABEL_SEARCH_STEP) {
9782
+ for (let distance7 = startDistance; distance7 <= maxSearchDistance + EPS13; distance7 += LABEL_SEARCH_STEP) {
9621
9783
  const anchorPoint = {
9622
9784
  x: baseAnchor.x + direction.x * distance7,
9623
9785
  y: baseAnchor.y + direction.y * distance7
9624
9786
  };
9787
+ const projectedConnectorSource = connectorSource ?? (phase === "lateral-shift" ? this.findProjectedConnectorSourceOnHostTrace(
9788
+ label,
9789
+ anchorPoint,
9790
+ orientation
9791
+ ) : void 0);
9625
9792
  const candidate = this.createCandidate(
9626
9793
  label,
9627
9794
  anchorPoint,
9628
9795
  orientation,
9629
- connectorSource
9796
+ projectedConnectorSource
9630
9797
  );
9631
9798
  const result = this.evaluateCandidate(
9632
9799
  candidate,
@@ -9680,6 +9847,13 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
9680
9847
  candidate.anchorPoint
9681
9848
  ]);
9682
9849
  }
9850
+ if (candidate.connectorSource) {
9851
+ return getConnectorTracePath(
9852
+ candidate.connectorSource,
9853
+ candidate.anchorPoint,
9854
+ candidate.orientation
9855
+ );
9856
+ }
9683
9857
  if (candidate.phase === "lateral-shift") {
9684
9858
  const chipOutwardDir = this.crowdedPortOnlyLabelIndices.has(labelIndex) ? this.getChipOutwardDirection(label.anchorPoint) : (() => {
9685
9859
  const orientDir = dir(candidate.orientation);
@@ -9699,11 +9873,41 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
9699
9873
  ]);
9700
9874
  }
9701
9875
  return getConnectorTracePath(
9702
- candidate.connectorSource ?? label.anchorPoint,
9876
+ label.anchorPoint,
9703
9877
  candidate.anchorPoint,
9704
9878
  candidate.orientation
9705
9879
  );
9706
9880
  }
9881
+ /**
9882
+ * A laterally shifted label can branch directly from the interior of its
9883
+ * existing host trace. Prefer that tee over running a new connector beside
9884
+ * the host trace from the old label anchor.
9885
+ */
9886
+ findProjectedConnectorSourceOnHostTrace(label, targetAnchor, orientation) {
9887
+ const orientationDirection = dir(orientation);
9888
+ const projectedSources = [];
9889
+ for (const traceId of label.mspConnectionPairIds) {
9890
+ const hostTrace = this.traceMap[traceId];
9891
+ if (!hostTrace) continue;
9892
+ for (let pointIndex = 0; pointIndex < hostTrace.tracePath.length - 1; pointIndex++) {
9893
+ const start = hostTrace.tracePath[pointIndex];
9894
+ const end = hostTrace.tracePath[pointIndex + 1];
9895
+ const segmentIsPerpendicularToLabel = isYOrientation(orientation) ? Math.abs(start.y - end.y) <= EPS13 : Math.abs(start.x - end.x) <= EPS13;
9896
+ if (!segmentIsPerpendicularToLabel) continue;
9897
+ const source = isYOrientation(orientation) ? { x: targetAnchor.x, y: start.y } : { x: start.x, y: targetAnchor.y };
9898
+ if (!tracePathContainsPoint([start, end], label.anchorPoint) || !tracePathContainsPoint([start, end], source)) {
9899
+ continue;
9900
+ }
9901
+ const targetDistanceAlongOrientation = (targetAnchor.x - source.x) * orientationDirection.x + (targetAnchor.y - source.y) * orientationDirection.y;
9902
+ if (targetDistanceAlongOrientation >= -EPS13) {
9903
+ projectedSources.push(source);
9904
+ }
9905
+ }
9906
+ }
9907
+ return projectedSources.sort(
9908
+ (first, second) => Math.abs(first.x - targetAnchor.x) + Math.abs(first.y - targetAnchor.y) - (Math.abs(second.x - targetAnchor.x) + Math.abs(second.y - targetAnchor.y))
9909
+ )[0];
9910
+ }
9707
9911
  isStandaloneSinglePinNetLabel(label) {
9708
9912
  return this.inputProblem.netConnections.some(
9709
9913
  (connection) => connection.netId === label.netId && connection.pinIds.length === 1 && connection.pinIds[0] === label.pinIds[0]
@@ -9907,6 +10111,7 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
9907
10111
  label,
9908
10112
  {
9909
10113
  anchorPoint: candidate.anchorPoint,
10114
+ connectorSource: phase === "lateral-shift" ? candidate.connectorSource : void 0,
9910
10115
  orientation: candidate.orientation,
9911
10116
  phase
9912
10117
  },
@@ -9946,9 +10151,9 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
9946
10151
  const { anchorPoint, orientation } = candidate;
9947
10152
  const chipBounds = chip.bounds;
9948
10153
  if (isYOrientation(orientation)) {
9949
- return anchorPoint.x < chipBounds.minX - EPS12 || anchorPoint.x > chipBounds.maxX + EPS12;
10154
+ return anchorPoint.x < chipBounds.minX - EPS13 || anchorPoint.x > chipBounds.maxX + EPS13;
9950
10155
  }
9951
- return anchorPoint.y < chipBounds.minY - EPS12 || anchorPoint.y > chipBounds.maxY + EPS12;
10156
+ return anchorPoint.y < chipBounds.minY - EPS13 || anchorPoint.y > chipBounds.maxY + EPS13;
9952
10157
  });
9953
10158
  }
9954
10159
  staysOutsideConnectedPinRow(params) {
@@ -9956,9 +10161,9 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
9956
10161
  const pin = this.pinMap[label.pinIds[0]];
9957
10162
  if (!pin || !isYOrientation(candidate.orientation)) return false;
9958
10163
  if (candidate.anchorPoint.x < pin.x) {
9959
- return bounds.maxX <= pin.x + CONNECTED_PIN_ROW_OVERLAP_TOLERANCE + EPS12;
10164
+ return bounds.maxX <= pin.x + CONNECTED_PIN_ROW_OVERLAP_TOLERANCE + EPS13;
9960
10165
  }
9961
- return bounds.minX >= pin.x - CONNECTED_PIN_ROW_OVERLAP_TOLERANCE - EPS12;
10166
+ return bounds.minX >= pin.x - CONNECTED_PIN_ROW_OVERLAP_TOLERANCE - EPS13;
9962
10167
  }
9963
10168
  getBoundsStatus(candidateBoundsCheck) {
9964
10169
  const { bounds, labelIndex, label, ignoreChipCollisions } = candidateBoundsCheck;
@@ -10039,14 +10244,14 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
10039
10244
  candidate.width,
10040
10245
  candidate.height
10041
10246
  );
10042
- if (labelBounds.minY < chip.bounds.minY - EPS12 || labelBounds.maxY > chip.bounds.maxY + EPS12) {
10247
+ if (labelBounds.minY < chip.bounds.minY - EPS13 || labelBounds.maxY > chip.bounds.maxY + EPS13) {
10043
10248
  return false;
10044
10249
  }
10045
- if (candidate.anchorPoint.x >= chip.bounds.minX - EPS12 && candidate.anchorPoint.x <= chip.bounds.maxX + EPS12) {
10250
+ if (candidate.anchorPoint.x >= chip.bounds.minX - EPS13 && candidate.anchorPoint.x <= chip.bounds.maxX + EPS13) {
10046
10251
  return false;
10047
10252
  }
10048
10253
  return chip.pins.every(
10049
- (pin) => label.pinIds.includes(pin.pinId) || pin.y <= labelBounds.minY + EPS12 || pin.y >= labelBounds.maxY - EPS12
10254
+ (pin) => label.pinIds.includes(pin.pinId) || pin.y <= labelBounds.minY + EPS13 || pin.y >= labelBounds.maxY - EPS13
10050
10255
  );
10051
10256
  }
10052
10257
  getTextBlockedMultiPinRailTraces(label, orientation) {
@@ -10073,20 +10278,20 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
10073
10278
  const pins = [...connectedPinIds].map((pinId) => this.pinMap[pinId]);
10074
10279
  const direction = dir(orientation);
10075
10280
  const pinX = pins[0].x;
10076
- if (pins.some((pin) => Math.abs(pin.x - pinX) > EPS12)) return null;
10077
- const sidePins = this.inputProblem.chips.find((chip) => chip.chipId === componentId).pins.filter((pin) => Math.abs(pin.x - pinX) <= EPS12);
10281
+ if (pins.some((pin) => Math.abs(pin.x - pinX) > EPS13)) return null;
10282
+ const sidePins = this.inputProblem.chips.find((chip) => chip.chipId === componentId).pins.filter((pin) => Math.abs(pin.x - pinX) <= EPS13);
10078
10283
  const minY = Math.min(...pins.map((pin) => pin.y));
10079
10284
  const maxY = Math.max(...pins.map((pin) => pin.y));
10080
10285
  if (sidePins.some(
10081
- (pin) => pin.y >= minY - EPS12 && pin.y <= maxY + EPS12 && !connectedPinIds.has(pin.pinId)
10082
- ) || orientation === "y-" && minY > Math.min(...sidePins.map((pin) => pin.y)) + EPS12 || orientation === "y+" && maxY < Math.max(...sidePins.map((pin) => pin.y)) - EPS12) {
10286
+ (pin) => pin.y >= minY - EPS13 && pin.y <= maxY + EPS13 && !connectedPinIds.has(pin.pinId)
10287
+ ) || orientation === "y-" && minY > Math.min(...sidePins.map((pin) => pin.y)) + EPS13 || orientation === "y+" && maxY < Math.max(...sidePins.map((pin) => pin.y)) - EPS13) {
10083
10288
  return null;
10084
10289
  }
10085
10290
  const outerPinPosition = Math.max(
10086
10291
  ...pins.map((pin) => pin.x * direction.x + pin.y * direction.y)
10087
10292
  );
10088
10293
  const blockedByText = (this.inputProblem.textBoxes ?? []).some(
10089
- (textBox) => textBox.chipId === componentId && textBox.center.x * direction.x + textBox.center.y * direction.y > outerPinPosition + EPS12
10294
+ (textBox) => textBox.chipId === componentId && textBox.center.x * direction.x + textBox.center.y * direction.y > outerPinPosition + EPS13
10090
10295
  );
10091
10296
  return blockedByText ? [...connectedTraces] : null;
10092
10297
  }
@@ -10102,7 +10307,7 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
10102
10307
  ...new Set(
10103
10308
  localTraces.flatMap((trace) => trace.tracePath.map((point) => point.x))
10104
10309
  )
10105
- ].filter((x) => Math.abs(x - pinX) > EPS12).sort((a, b) => Math.abs(a - pinX) - Math.abs(b - pinX));
10310
+ ].filter((x) => Math.abs(x - pinX) > EPS13).sort((a, b) => Math.abs(a - pinX) - Math.abs(b - pinX));
10106
10311
  for (const x of railXs) {
10107
10312
  const connectorSource = { x, y: connectorY };
10108
10313
  if (!Object.values(this.traceMap).some(
@@ -10165,8 +10370,8 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
10165
10370
  if (!chip) return null;
10166
10371
  const sides = new Set(
10167
10372
  pins.map((pin) => {
10168
- if (Math.abs(pin.x - chip.bounds.minX) <= EPS12) return "left";
10169
- if (Math.abs(pin.x - chip.bounds.maxX) <= EPS12) return "right";
10373
+ if (Math.abs(pin.x - chip.bounds.minX) <= EPS13) return "left";
10374
+ if (Math.abs(pin.x - chip.bounds.maxX) <= EPS13) return "right";
10170
10375
  return null;
10171
10376
  })
10172
10377
  );
@@ -10205,16 +10410,16 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
10205
10410
  }
10206
10411
  sharesChipBoundary(bounds) {
10207
10412
  const boundarySearchBounds = {
10208
- minX: bounds.minX - WICK_CLEARANCE - EPS12,
10209
- minY: bounds.minY - WICK_CLEARANCE - EPS12,
10210
- maxX: bounds.maxX + WICK_CLEARANCE + EPS12,
10211
- maxY: bounds.maxY + WICK_CLEARANCE + EPS12
10413
+ minX: bounds.minX - WICK_CLEARANCE - EPS13,
10414
+ minY: bounds.minY - WICK_CLEARANCE - EPS13,
10415
+ maxX: bounds.maxX + WICK_CLEARANCE + EPS13,
10416
+ maxY: bounds.maxY + WICK_CLEARANCE + EPS13
10212
10417
  };
10213
10418
  const nearbyChips = this.chipObstacleSpatialIndex.getChipsInBounds(boundarySearchBounds);
10214
10419
  for (const chip of nearbyChips) {
10215
10420
  const chipBounds = chip.bounds;
10216
- const adjacentToVerticalSide = Math.abs(bounds.minX - chipBounds.maxX) <= WICK_CLEARANCE + EPS12 || Math.abs(bounds.maxX - chipBounds.minX) <= WICK_CLEARANCE + EPS12;
10217
- const adjacentToHorizontalSide = Math.abs(bounds.minY - chipBounds.maxY) <= WICK_CLEARANCE + EPS12 || Math.abs(bounds.maxY - chipBounds.minY) <= WICK_CLEARANCE + EPS12;
10421
+ const adjacentToVerticalSide = Math.abs(bounds.minX - chipBounds.maxX) <= WICK_CLEARANCE + EPS13 || Math.abs(bounds.maxX - chipBounds.minX) <= WICK_CLEARANCE + EPS13;
10422
+ const adjacentToHorizontalSide = Math.abs(bounds.minY - chipBounds.maxY) <= WICK_CLEARANCE + EPS13 || Math.abs(bounds.maxY - chipBounds.minY) <= WICK_CLEARANCE + EPS13;
10218
10423
  if (adjacentToVerticalSide && rangesOverlap(
10219
10424
  bounds.minY,
10220
10425
  bounds.maxY,
@@ -10276,7 +10481,7 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
10276
10481
  let nearestDistance = Number.POSITIVE_INFINITY;
10277
10482
  for (const chip of this.chipObstacleSpatialIndex.chips) {
10278
10483
  const bounds = chip.bounds;
10279
- if (point.x < bounds.minX - EPS12 || point.x > bounds.maxX + EPS12 || point.y < bounds.minY - EPS12 || point.y > bounds.maxY + EPS12) {
10484
+ if (point.x < bounds.minX - EPS13 || point.x > bounds.maxX + EPS13 || point.y < bounds.minY - EPS13 || point.y > bounds.maxY + EPS13) {
10280
10485
  continue;
10281
10486
  }
10282
10487
  for (const [side, distance7] of getSideDistances(point, bounds)) {
@@ -10293,8 +10498,8 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
10293
10498
  let nearestDistanceSq = Number.POSITIVE_INFINITY;
10294
10499
  for (const chip of this.chipObstacleSpatialIndex.chips) {
10295
10500
  const bounds = chip.bounds;
10296
- const dx = point.x < bounds.minX - EPS12 ? bounds.minX - point.x : point.x > bounds.maxX + EPS12 ? point.x - bounds.maxX : 0;
10297
- const dy = point.y < bounds.minY - EPS12 ? bounds.minY - point.y : point.y > bounds.maxY + EPS12 ? point.y - bounds.maxY : 0;
10501
+ const dx = point.x < bounds.minX - EPS13 ? bounds.minX - point.x : point.x > bounds.maxX + EPS13 ? point.x - bounds.maxX : 0;
10502
+ const dy = point.y < bounds.minY - EPS13 ? bounds.minY - point.y : point.y > bounds.maxY + EPS13 ? point.y - bounds.maxY : 0;
10298
10503
  if (dx === 0 && dy === 0) continue;
10299
10504
  const distanceSq = dx ** 2 + dy ** 2;
10300
10505
  if (distanceSq >= nearestDistanceSq) continue;
@@ -10854,11 +11059,11 @@ var getOrientationConstraint = (inputProblem, label) => {
10854
11059
  };
10855
11060
 
10856
11061
  // lib/solvers/TraceAnchoredNetLabelOverlapSolver/geometry.ts
10857
- var EPS13 = 1e-6;
11062
+ var EPS14 = 1e-6;
10858
11063
  var TRACE_BOUNDARY_TOLERANCE2 = 1e-6;
10859
11064
  var getLabelBounds = (label) => getRectBounds(label.center, label.width, label.height);
10860
- var rectsOverlap3 = (a, b) => Math.min(a.maxX, b.maxX) - Math.max(a.minX, b.minX) > EPS13 && Math.min(a.maxY, b.maxY) - Math.max(a.minY, b.minY) > EPS13;
10861
- var rectsTouchOrOverlap = (a, b) => Math.min(a.maxX, b.maxX) - Math.max(a.minX, b.minX) >= -EPS13 && Math.min(a.maxY, b.maxY) - Math.max(a.minY, b.minY) >= -EPS13;
11065
+ var rectsOverlap3 = (a, b) => Math.min(a.maxX, b.maxX) - Math.max(a.minX, b.minX) > EPS14 && Math.min(a.maxY, b.maxY) - Math.max(a.minY, b.minY) > EPS14;
11066
+ var rectsTouchOrOverlap = (a, b) => Math.min(a.maxX, b.maxX) - Math.max(a.minX, b.minX) >= -EPS14 && Math.min(a.maxY, b.maxY) - Math.max(a.minY, b.minY) >= -EPS14;
10862
11067
  var traceCrossesBoundsInterior2 = (bounds, traces) => {
10863
11068
  for (const trace of traces) {
10864
11069
  const points = trace.tracePath;
@@ -10904,7 +11109,7 @@ var getPointAtTraceDistance = (trace, distance7) => {
10904
11109
  const end = trace.tracePath[i + 1];
10905
11110
  const segmentLength = getManhattanDistance(start, end);
10906
11111
  const nextDistance = pathDistance + segmentLength;
10907
- if (distance7 <= nextDistance + EPS13) {
11112
+ if (distance7 <= nextDistance + EPS14) {
10908
11113
  const offset = Math.max(
10909
11114
  0,
10910
11115
  Math.min(segmentLength, distance7 - pathDistance)
@@ -10943,7 +11148,7 @@ var segmentCrossesBoundsInterior2 = (start, end, bounds) => {
10943
11148
  return false;
10944
11149
  }
10945
11150
  if (isVertical4(start, end)) {
10946
- if (start.x <= interior.minX + EPS13 || start.x >= interior.maxX - EPS13) {
11151
+ if (start.x <= interior.minX + EPS14 || start.x >= interior.maxX - EPS14) {
10947
11152
  return false;
10948
11153
  }
10949
11154
  return rangesOverlap2(
@@ -10954,7 +11159,7 @@ var segmentCrossesBoundsInterior2 = (start, end, bounds) => {
10954
11159
  );
10955
11160
  }
10956
11161
  if (isHorizontal3(start, end)) {
10957
- if (start.y <= interior.minY + EPS13 || start.y >= interior.maxY - EPS13) {
11162
+ if (start.y <= interior.minY + EPS14 || start.y >= interior.maxY - EPS14) {
10958
11163
  return false;
10959
11164
  }
10960
11165
  return rangesOverlap2(
@@ -10968,10 +11173,10 @@ var segmentCrossesBoundsInterior2 = (start, end, bounds) => {
10968
11173
  };
10969
11174
  var isPointOnSegment2 = (point, start, end) => {
10970
11175
  if (isHorizontal3(start, end)) {
10971
- return Math.abs(point.y - start.y) <= EPS13 && point.x >= Math.min(start.x, end.x) - EPS13 && point.x <= Math.max(start.x, end.x) + EPS13;
11176
+ return Math.abs(point.y - start.y) <= EPS14 && point.x >= Math.min(start.x, end.x) - EPS14 && point.x <= Math.max(start.x, end.x) + EPS14;
10972
11177
  }
10973
11178
  if (isVertical4(start, end)) {
10974
- return Math.abs(point.x - start.x) <= EPS13 && point.y >= Math.min(start.y, end.y) - EPS13 && point.y <= Math.max(start.y, end.y) + EPS13;
11179
+ return Math.abs(point.x - start.x) <= EPS14 && point.y >= Math.min(start.y, end.y) - EPS14 && point.y <= Math.max(start.y, end.y) + EPS14;
10975
11180
  }
10976
11181
  return false;
10977
11182
  };
@@ -10979,9 +11184,9 @@ var getSegmentDirection = (start, end) => ({
10979
11184
  x: isVertical4(start, end) ? 0 : Math.sign(end.x - start.x),
10980
11185
  y: isHorizontal3(start, end) ? 0 : Math.sign(end.y - start.y)
10981
11186
  });
10982
- var isHorizontal3 = (start, end) => Math.abs(start.y - end.y) <= EPS13;
10983
- var isVertical4 = (start, end) => Math.abs(start.x - end.x) <= EPS13;
10984
- var rangesOverlap2 = (minA, maxA, minB, maxB) => Math.min(maxA, maxB) - Math.max(minA, minB) > EPS13;
11187
+ var isHorizontal3 = (start, end) => Math.abs(start.y - end.y) <= EPS14;
11188
+ var isVertical4 = (start, end) => Math.abs(start.x - end.x) <= EPS14;
11189
+ var rangesOverlap2 = (minA, maxA, minB, maxB) => Math.min(maxA, maxB) - Math.max(minA, minB) > EPS14;
10985
11190
  var getUniquePinCount2 = (pinIds) => new Set(pinIds).size;
10986
11191
 
10987
11192
  // lib/solvers/TraceAnchoredNetLabelOverlapSolver/candidates.ts
@@ -11038,7 +11243,7 @@ var getCandidateDistances = (traceLength, vertexDistances) => {
11038
11243
  for (const distance7 of vertexDistances) {
11039
11244
  distances.add(roundDistance(distance7));
11040
11245
  }
11041
- return [...distances].filter((distance7) => distance7 >= -EPS13 && distance7 <= traceLength + EPS13).sort((a, b) => a - b);
11246
+ return [...distances].filter((distance7) => distance7 >= -EPS14 && distance7 <= traceLength + EPS14).sort((a, b) => a - b);
11042
11247
  };
11043
11248
  var getOrientationsForPoint = (params) => {
11044
11249
  const { inputProblem, label, point, orientationConstraint } = params;
@@ -11127,13 +11332,13 @@ var getOutwardOrientationOptions = (point, chipBounds) => {
11127
11332
  };
11128
11333
  var getOutwardAxisOption = (params) => {
11129
11334
  const { value, min, max, center, positiveOrientation, negativeOrientation } = params;
11130
- if (value > max + EPS13) {
11335
+ if (value > max + EPS14) {
11131
11336
  return {
11132
11337
  orientation: positiveOrientation,
11133
11338
  outwardScore: 1 + value - max
11134
11339
  };
11135
11340
  }
11136
- if (value < min - EPS13) {
11341
+ if (value < min - EPS14) {
11137
11342
  return {
11138
11343
  orientation: negativeOrientation,
11139
11344
  outwardScore: 1 + min - value
@@ -11144,7 +11349,7 @@ var getOutwardAxisOption = (params) => {
11144
11349
  outwardScore: getNormalizedCenterDistance(value, center, max - min)
11145
11350
  };
11146
11351
  };
11147
- var getNormalizedCenterDistance = (value, center, span) => Math.abs(value - center) / Math.max(EPS13, span / 2);
11352
+ var getNormalizedCenterDistance = (value, center, span) => Math.abs(value - center) / Math.max(EPS14, span / 2);
11148
11353
  var ALL_ORIENTATIONS = ["x+", "x-", "y+", "y-"];
11149
11354
  var getFlippedOrientation = (orientation) => {
11150
11355
  switch (orientation) {
@@ -11212,7 +11417,7 @@ var getNetLabelHeight = (inputProblem, label) => {
11212
11417
  )?.netLabelHeight;
11213
11418
  };
11214
11419
  var roundDistance = (distance7) => Number(distance7.toFixed(6));
11215
- var isSamePlacement = (label, point, orientation) => Math.abs(point.x - label.anchorPoint.x) <= EPS13 && Math.abs(point.y - label.anchorPoint.y) <= EPS13 && orientation === label.orientation;
11420
+ var isSamePlacement = (label, point, orientation) => Math.abs(point.x - label.anchorPoint.x) <= EPS14 && Math.abs(point.y - label.anchorPoint.y) <= EPS14 && orientation === label.orientation;
11216
11421
 
11217
11422
  // lib/solvers/TraceAnchoredNetLabelOverlapSolver/visualize.ts
11218
11423
  var CANDIDATE_SELECTED_COLOR4 = "blue";
@@ -15032,15 +15237,15 @@ var pathIntersectsRenderedLabel = (path, label) => {
15032
15237
  };
15033
15238
 
15034
15239
  // lib/solvers/InlineNetLabelSolver/restoreReroutesAroundSupersededLabels.ts
15035
- var EPS14 = 1e-6;
15240
+ var EPS15 = 1e-6;
15036
15241
  var getPathLength5 = (path) => path.slice(1).reduce((length, point, pointIndex) => {
15037
15242
  const previousPoint = path[pointIndex];
15038
15243
  return length + Math.abs(point.x - previousPoint.x) + Math.abs(point.y - previousPoint.y);
15039
15244
  }, 0);
15040
15245
  var pathsEqual = (first, second) => first.length === second.length && first.every(
15041
- (point, index) => Math.abs(point.x - second[index].x) <= EPS14 && Math.abs(point.y - second[index].y) <= EPS14
15246
+ (point, index) => Math.abs(point.x - second[index].x) <= EPS15 && Math.abs(point.y - second[index].y) <= EPS15
15042
15247
  );
15043
- var isStrictlySimpler = (candidate, current) => candidate.length < current.length && getPathLength5(candidate) <= getPathLength5(current) + EPS14;
15248
+ var isStrictlySimpler = (candidate, current) => candidate.length < current.length && getPathLength5(candidate) <= getPathLength5(current) + EPS15;
15044
15249
  var getIntersectionKeys = (path, otherPath) => {
15045
15250
  const intersections = /* @__PURE__ */ new Set();
15046
15251
  for (let pathIndex = 0; pathIndex < path.length - 1; pathIndex++) {
@@ -16095,12 +16300,12 @@ var getTraceRecoveryConnectivityMaps = (inputProblem) => {
16095
16300
  };
16096
16301
 
16097
16302
  // lib/solvers/NetLabelToTraceSolver/reduceTraceCrossings.ts
16098
- var EPS15 = 1e-9;
16099
- var isHorizontal4 = (start, end) => Math.abs(start.y - end.y) < EPS15;
16100
- var isVertical5 = (start, end) => Math.abs(start.x - end.x) < EPS15;
16303
+ var EPS16 = 1e-9;
16304
+ var isHorizontal4 = (start, end) => Math.abs(start.y - end.y) < EPS16;
16305
+ var isVertical5 = (start, end) => Math.abs(start.x - end.x) < EPS16;
16101
16306
  var compactConsecutivePoints = (path) => path.filter((point, index) => {
16102
16307
  const previousPoint = path[index - 1];
16103
- return !previousPoint || Math.abs(point.x - previousPoint.x) >= EPS15 || Math.abs(point.y - previousPoint.y) >= EPS15;
16308
+ return !previousPoint || Math.abs(point.x - previousPoint.x) >= EPS16 || Math.abs(point.y - previousPoint.y) >= EPS16;
16104
16309
  });
16105
16310
  var isValidOrthogonalPath = (path) => {
16106
16311
  if (path.length < 2 || !path.every((point, index) => {
@@ -16138,7 +16343,7 @@ var getEndpointAlignedSegmentCandidates = (tracePath) => {
16138
16343
  }
16139
16344
  const alignedCoordinates = segmentIsVertical ? [previousPoint.x, nextPoint.x] : [previousPoint.y, nextPoint.y];
16140
16345
  for (const alignedCoordinate of alignedCoordinates) {
16141
- if (Math.abs(alignedCoordinate - (segmentIsVertical ? start.x : start.y)) < EPS15) {
16346
+ if (Math.abs(alignedCoordinate - (segmentIsVertical ? start.x : start.y)) < EPS16) {
16142
16347
  continue;
16143
16348
  }
16144
16349
  const candidate = tracePath.map((point) => ({ ...point }));
@@ -16914,10 +17119,14 @@ var SchematicTracePipelineSolver = class extends BaseSolver {
16914
17119
  allLabelPlacements: collisionOutput.netLabelPlacements,
16915
17120
  mergedLabelNetIdMap: labelMergingOutput.mergedLabelNetIdMap,
16916
17121
  paddingBuffer: 0.1,
16917
- operations: ["aligning_same_net_rails"],
17122
+ operations: [
17123
+ "rerouting_generated_net_label_connector_crossings",
17124
+ "aligning_same_net_rails"
17125
+ ],
16918
17126
  eligibleTraceIds: new Set(
16919
17127
  instance.traceCleanupSolver.getOutput().traces.map((trace) => trace.mspPairId)
16920
- )
17128
+ ),
17129
+ netLabelConnectorTraceIds: instance.availableNetOrientationSolver.netLabelConnectorTraceIds
16921
17130
  }
16922
17131
  ];
16923
17132
  }