@tscircuit/capacity-autorouter 0.0.64 → 0.0.66

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/README.md CHANGED
@@ -6,6 +6,12 @@ An MIT-licensed full-pipeline PCB autorouter library for node.js and TypeScript
6
6
 
7
7
  Check out this [short youtube explanation of this autorouter](https://youtu.be/MmTk0806fAo)
8
8
 
9
+ ## How to file a bug report
10
+
11
+ 1. You should have [created a bug report via the tscircuit errors tab](https://docs.tscircuit.com/contributing/report-autorouter-bugs)
12
+ 2. Run `bun run bug-report <bug-report-url>`
13
+ 3. This will download the bug report and create a debugging fixture file in the `examples/bug-reports` directory, you can then find the bug report in the server (via `bun run start`)
14
+
9
15
  ## Installation
10
16
 
11
17
  ```bash
package/dist/index.d.ts CHANGED
@@ -420,6 +420,8 @@ interface HighDensityHyperParameters {
420
420
  FLIP_TRACE_ALIGNMENT_DIRECTION: boolean;
421
421
  MULTI_HEAD_POLYLINE_SOLVER: boolean;
422
422
  SEGMENTS_PER_POLYLINE: number;
423
+ BOUNDARY_PADDING: number;
424
+ ITERATION_PENALTY: number;
423
425
  }
424
426
 
425
427
  type Node = {
@@ -754,10 +756,17 @@ declare class HyperSingleIntraNodeSolver extends HyperParameterSupervisorSolver<
754
756
  })[];
755
757
  } | {
756
758
  name: string;
757
- possibleValues: {
759
+ possibleValues: ({
758
760
  MULTI_HEAD_POLYLINE_SOLVER: boolean;
759
761
  SEGMENTS_PER_POLYLINE: number;
760
- }[];
762
+ BOUNDARY_PADDING: number;
763
+ ITERATION_PENALTY?: undefined;
764
+ } | {
765
+ MULTI_HEAD_POLYLINE_SOLVER: boolean;
766
+ SEGMENTS_PER_POLYLINE: number;
767
+ BOUNDARY_PADDING: number;
768
+ ITERATION_PENALTY: number;
769
+ })[];
761
770
  })[];
762
771
  computeG(solver: IntraNodeRouteSolver): number;
763
772
  computeH(solver: IntraNodeRouteSolver): number;
package/dist/index.js CHANGED
@@ -7434,6 +7434,7 @@ var MultiHeadPolyLineIntraNodeSolver = class extends BaseSolver {
7434
7434
  traceWidth = 0.15;
7435
7435
  availableZ = [];
7436
7436
  uniqueConnections = 0;
7437
+ BOUNDARY_PADDING;
7437
7438
  lastCandidate = null;
7438
7439
  maxViaCount;
7439
7440
  minViaCount;
@@ -7446,6 +7447,7 @@ var MultiHeadPolyLineIntraNodeSolver = class extends BaseSolver {
7446
7447
  this.colorMap = params.colorMap ?? generateColorMapFromNodeWithPortPoints(params.nodeWithPortPoints);
7447
7448
  this.hyperParameters = params.hyperParameters ?? {};
7448
7449
  this.SEGMENTS_PER_POLYLINE = params.hyperParameters?.SEGMENTS_PER_POLYLINE ?? 3;
7450
+ this.BOUNDARY_PADDING = params.hyperParameters?.BOUNDARY_PADDING ?? 0.05;
7449
7451
  this.connMap = params.connMap;
7450
7452
  this.cellSize = this.nodeWithPortPoints.width / 1024;
7451
7453
  this.candidates = [];
@@ -7792,33 +7794,71 @@ var MultiHeadPolyLineIntraNodeSolver = class extends BaseSolver {
7792
7794
  const fy = dy / dist * forceMag;
7793
7795
  const sourceIdSeg2 = `seg:${j}:${seg2.p1Idx}:${seg2.p2Idx}`;
7794
7796
  const sourceIdSeg1 = `seg:${i}:${seg1.p1Idx}:${seg1.p2Idx}`;
7795
- addForceContribution(
7796
- i,
7797
+ const endpointForce = (ep, epIdx, otherSeg, targetLine, oppLine, srcIdOpp, srcIdThis) => {
7798
+ const cp = pointToSegmentClosestPoint(
7799
+ ep,
7800
+ otherSeg.p1,
7801
+ otherSeg.p2
7802
+ );
7803
+ const dx2 = ep.x - cp.x;
7804
+ const dy2 = ep.y - cp.y;
7805
+ const dSq2 = dx2 * dx2 + dy2 * dy2;
7806
+ if (dSq2 <= EPSILON4) return;
7807
+ const dist2 = Math.sqrt(dSq2);
7808
+ const mag = SEGMENT_FORCE_MULTIPLIER * FORCE_MAGNITUDE * Math.exp(-FORCE_DECAY_RATE * dist2);
7809
+ const fx2 = dx2 / dist2 * mag;
7810
+ const fy2 = dy2 / dist2 * mag;
7811
+ addForceContribution(targetLine, epIdx, srcIdOpp, fx2, fy2);
7812
+ addForceContribution(
7813
+ oppLine,
7814
+ otherSeg.p1Idx,
7815
+ srcIdThis,
7816
+ -fx2 / 2,
7817
+ -fy2 / 2
7818
+ );
7819
+ addForceContribution(
7820
+ oppLine,
7821
+ otherSeg.p2Idx,
7822
+ srcIdThis,
7823
+ -fx2 / 2,
7824
+ -fy2 / 2
7825
+ );
7826
+ };
7827
+ endpointForce(
7828
+ seg1.p1,
7797
7829
  seg1.p1Idx,
7830
+ seg2,
7831
+ i,
7832
+ j,
7798
7833
  sourceIdSeg2,
7799
- fx / 2,
7800
- fy / 2
7834
+ sourceIdSeg1
7801
7835
  );
7802
- addForceContribution(
7803
- i,
7836
+ endpointForce(
7837
+ seg1.p2,
7804
7838
  seg1.p2Idx,
7839
+ seg2,
7840
+ i,
7841
+ j,
7805
7842
  sourceIdSeg2,
7806
- fx / 2,
7807
- fy / 2
7843
+ sourceIdSeg1
7808
7844
  );
7809
- addForceContribution(
7810
- j,
7845
+ endpointForce(
7846
+ seg2.p1,
7811
7847
  seg2.p1Idx,
7848
+ seg1,
7849
+ j,
7850
+ i,
7812
7851
  sourceIdSeg1,
7813
- -fx / 2,
7814
- -fy / 2
7852
+ sourceIdSeg2
7815
7853
  );
7816
- addForceContribution(
7817
- j,
7854
+ endpointForce(
7855
+ seg2.p2,
7818
7856
  seg2.p2Idx,
7857
+ seg1,
7858
+ j,
7859
+ i,
7819
7860
  sourceIdSeg1,
7820
- -fx / 2,
7821
- -fy / 2
7861
+ sourceIdSeg2
7822
7862
  );
7823
7863
  }
7824
7864
  }
@@ -8046,7 +8086,8 @@ var MultiHeadPolyLineIntraNodeSolver = class extends BaseSolver {
8046
8086
  const radius = this.viaDiameter / 2;
8047
8087
  let boundaryForceX = 0;
8048
8088
  let boundaryForceY = 0;
8049
- const forceMargin = this.viaDiameter / 2;
8089
+ const baseForceMargin = this.viaDiameter / 2;
8090
+ const forceMargin = baseForceMargin + this.BOUNDARY_PADDING;
8050
8091
  const minX = this.bounds.minX + forceMargin;
8051
8092
  const maxX = this.bounds.maxX - forceMargin;
8052
8093
  const minY = this.bounds.minY + forceMargin;
@@ -8070,7 +8111,8 @@ var MultiHeadPolyLineIntraNodeSolver = class extends BaseSolver {
8070
8111
  newX = mPoint.x + netForce.fx;
8071
8112
  newY = mPoint.y + netForce.fy;
8072
8113
  } else {
8073
- const padding = this.traceWidth / 2;
8114
+ const basePadding = this.traceWidth / 2;
8115
+ const padding = basePadding + this.BOUNDARY_PADDING;
8074
8116
  newX = Math.max(
8075
8117
  this.bounds.minX + padding,
8076
8118
  Math.min(this.bounds.maxX - padding, newX)
@@ -8115,8 +8157,8 @@ var MultiHeadPolyLineIntraNodeSolver = class extends BaseSolver {
8115
8157
  );
8116
8158
  const allPointsWithinBounds = candidate.polyLines.every((polyLine) => {
8117
8159
  return polyLine.mPoints.every((mPoint) => {
8118
- const padding = (mPoint.z1 !== mPoint.z2 ? this.viaDiameter / 2 : 0) * // Forgiveness outside bounds
8119
- 0.9;
8160
+ const basePadding = mPoint.z1 !== mPoint.z2 ? this.viaDiameter / 2 : this.traceWidth / 2;
8161
+ const padding = basePadding + this.BOUNDARY_PADDING;
8120
8162
  return withinBounds(mPoint, this.bounds, padding);
8121
8163
  });
8122
8164
  });
@@ -8429,6 +8471,20 @@ var MultiHeadPolyLineIntraNodeSolver2 = class extends MultiHeadPolyLineIntraNode
8429
8471
  netForces[lineIndex][mPointIndex].fy += fy;
8430
8472
  }
8431
8473
  };
8474
+ const endpointForce = (ep, epIdx, otherSeg, targetLine, oppLine) => {
8475
+ const cp = pointToSegmentClosestPoint(ep, otherSeg.p1, otherSeg.p2);
8476
+ const dx = ep.x - cp.x;
8477
+ const dy = ep.y - cp.y;
8478
+ const dSq = dx * dx + dy * dy;
8479
+ if (dSq <= EPSILON4) return;
8480
+ const dist = Math.sqrt(dSq);
8481
+ const mag = SEGMENT_FORCE_MULTIPLIER * FORCE_MAGNITUDE * Math.exp(-FORCE_DECAY_RATE * dist);
8482
+ const fx = dx / dist * mag;
8483
+ const fy = dy / dist * mag;
8484
+ addNetForce(targetLine, epIdx, fx, fy);
8485
+ addNetForce(oppLine, otherSeg.p1Idx, -fx / 2, -fy / 2);
8486
+ addNetForce(oppLine, otherSeg.p2Idx, -fx / 2, -fy / 2);
8487
+ };
8432
8488
  for (let i = 0; i < numPolyLines; i++) {
8433
8489
  for (let j = i + 1; j < numPolyLines; j++) {
8434
8490
  const polyLine1 = polyLines[i];
@@ -8474,28 +8530,10 @@ var MultiHeadPolyLineIntraNodeSolver2 = class extends MultiHeadPolyLineIntraNode
8474
8530
  seg2.p1,
8475
8531
  seg2.p2
8476
8532
  );
8477
- if (minDist < EPSILON4) continue;
8478
- const center1 = {
8479
- x: (seg1.p1.x + seg1.p2.x) / 2,
8480
- y: (seg1.p1.y + seg1.p2.y) / 2
8481
- };
8482
- const center2 = {
8483
- x: (seg2.p1.x + seg2.p2.x) / 2,
8484
- y: (seg2.p1.y + seg2.p2.y) / 2
8485
- };
8486
- const dx = center1.x - center2.x;
8487
- const dy = center1.y - center2.y;
8488
- const dSq = dx * dx + dy * dy;
8489
- if (dSq > EPSILON4) {
8490
- const dist = Math.sqrt(dSq);
8491
- const forceMag = SEGMENT_FORCE_MULTIPLIER * FORCE_MAGNITUDE * Math.exp(-FORCE_DECAY_RATE * dist);
8492
- const fx = dx / dist * forceMag;
8493
- const fy = dy / dist * forceMag;
8494
- addNetForce(i, seg1.p1Idx, fx / 2, fy / 2);
8495
- addNetForce(i, seg1.p2Idx, fx / 2, fy / 2);
8496
- addNetForce(j, seg2.p1Idx, -fx / 2, -fy / 2);
8497
- addNetForce(j, seg2.p2Idx, -fx / 2, -fy / 2);
8498
- }
8533
+ endpointForce(seg1.p1, seg1.p1Idx, seg2, i, j);
8534
+ endpointForce(seg1.p2, seg1.p2Idx, seg2, i, j);
8535
+ endpointForce(seg2.p1, seg2.p1Idx, seg1, j, i);
8536
+ endpointForce(seg2.p2, seg2.p2Idx, seg1, j, i);
8499
8537
  }
8500
8538
  }
8501
8539
  }
@@ -8646,7 +8684,8 @@ var MultiHeadPolyLineIntraNodeSolver2 = class extends MultiHeadPolyLineIntraNode
8646
8684
  const radius = this.viaDiameter / 2;
8647
8685
  let boundaryForceX = 0;
8648
8686
  let boundaryForceY = 0;
8649
- const forceMargin = this.viaDiameter / 2;
8687
+ const baseForceMargin = this.viaDiameter / 2;
8688
+ const forceMargin = baseForceMargin + this.BOUNDARY_PADDING;
8650
8689
  const minX = this.bounds.minX + forceMargin;
8651
8690
  const maxX = this.bounds.maxX - forceMargin;
8652
8691
  const minY = this.bounds.minY + forceMargin;
@@ -8670,7 +8709,8 @@ var MultiHeadPolyLineIntraNodeSolver2 = class extends MultiHeadPolyLineIntraNode
8670
8709
  newX = mPoint.x + currentForceX;
8671
8710
  newY = mPoint.y + currentForceY;
8672
8711
  } else {
8673
- const padding = this.traceWidth / 2;
8712
+ const basePadding = this.traceWidth / 2;
8713
+ const padding = basePadding + this.BOUNDARY_PADDING;
8674
8714
  newX = Math.max(
8675
8715
  this.bounds.minX + padding,
8676
8716
  Math.min(this.bounds.maxX - padding, newX)
@@ -9007,7 +9047,15 @@ var HyperSingleIntraNodeSolver = class extends HyperParameterSupervisorSolver {
9007
9047
  possibleValues: [
9008
9048
  {
9009
9049
  MULTI_HEAD_POLYLINE_SOLVER: true,
9010
- SEGMENTS_PER_POLYLINE: 6
9050
+ SEGMENTS_PER_POLYLINE: 6,
9051
+ BOUNDARY_PADDING: 0.05
9052
+ },
9053
+ {
9054
+ MULTI_HEAD_POLYLINE_SOLVER: true,
9055
+ SEGMENTS_PER_POLYLINE: 6,
9056
+ BOUNDARY_PADDING: -0.05,
9057
+ // Allow vias/traces outside the boundary
9058
+ ITERATION_PENALTY: 1e4
9011
9059
  }
9012
9060
  ]
9013
9061
  }
@@ -9015,7 +9063,7 @@ var HyperSingleIntraNodeSolver = class extends HyperParameterSupervisorSolver {
9015
9063
  }
9016
9064
  computeG(solver) {
9017
9065
  if (solver?.hyperParameters?.MULTI_HEAD_POLYLINE_SOLVER) {
9018
- return 1e3 + solver.iterations / 1e4 + 1e4 * (solver.hyperParameters.SEGMENTS_PER_POLYLINE - 3);
9066
+ return 1e3 + ((solver.hyperParameters?.ITERATION_PENALTY ?? 0) + solver.iterations) / 1e4 + 1e4 * (solver.hyperParameters.SEGMENTS_PER_POLYLINE - 3);
9019
9067
  }
9020
9068
  return solver.iterations / 1e4;
9021
9069
  }