@tscircuit/capacity-autorouter 0.0.42 → 0.0.43

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
@@ -68,6 +68,9 @@ var BaseSolver = class {
68
68
  }
69
69
  _step() {
70
70
  }
71
+ getConstructorParams() {
72
+ throw new Error("getConstructorParams not implemented");
73
+ }
71
74
  solve() {
72
75
  const startTime = Date.now();
73
76
  while (!this.solved && !this.failed) {
@@ -1938,6 +1941,86 @@ function distance(p1, p2) {
1938
1941
  return Math.sqrt(dx * dx + dy * dy);
1939
1942
  }
1940
1943
 
1944
+ // node_modules/@tscircuit/math-utils/dist/chunk-MHHTZHOJ.js
1945
+ function getBoundingBox(box) {
1946
+ const halfWidth = box.width / 2;
1947
+ const halfHeight = box.height / 2;
1948
+ return {
1949
+ minX: box.center.x - halfWidth,
1950
+ maxX: box.center.x + halfWidth,
1951
+ minY: box.center.y - halfHeight,
1952
+ maxY: box.center.y + halfHeight
1953
+ };
1954
+ }
1955
+ function computeDistanceBetweenBoxes(boxA, boxB) {
1956
+ const a = getBoundingBox(boxA);
1957
+ const b = getBoundingBox(boxB);
1958
+ const dx = Math.max(a.minX - b.maxX, b.minX - a.maxX, 0);
1959
+ const dy = Math.max(a.minY - b.maxY, b.minY - a.maxY, 0);
1960
+ const pointA = { x: 0, y: 0 };
1961
+ const pointB = { x: 0, y: 0 };
1962
+ if (dx === 0 && dy === 0) {
1963
+ return { distance: 0, pointA: boxA.center, pointB: boxB.center };
1964
+ }
1965
+ pointA.x = clamp(boxA.center.x, b.minX, b.maxX);
1966
+ pointA.y = clamp(boxA.center.y, b.minY, b.maxY);
1967
+ pointB.x = clamp(boxB.center.x, a.minX, a.maxX);
1968
+ pointB.y = clamp(boxB.center.y, a.minY, a.maxY);
1969
+ const distance6 = Math.hypot(pointA.x - pointB.x, pointA.y - pointB.y);
1970
+ return { distance: distance6, pointA, pointB };
1971
+ }
1972
+ function clamp(value, min, max) {
1973
+ return Math.max(min, Math.min(max, value));
1974
+ }
1975
+
1976
+ // node_modules/@tscircuit/math-utils/dist/chunk-OMVVSGKD.js
1977
+ function segmentToBoundsMinDistance(a, b, bounds) {
1978
+ const topLeft = { x: bounds.minX, y: bounds.minY };
1979
+ const topRight = { x: bounds.maxX, y: bounds.minY };
1980
+ const bottomLeft = { x: bounds.minX, y: bounds.maxY };
1981
+ const bottomRight = { x: bounds.maxX, y: bounds.maxY };
1982
+ if (doSegmentsIntersect(a, b, topLeft, topRight) || doSegmentsIntersect(a, b, topRight, bottomRight) || doSegmentsIntersect(a, b, bottomRight, bottomLeft) || doSegmentsIntersect(a, b, bottomLeft, topLeft)) {
1983
+ return 0;
1984
+ }
1985
+ if (a.x >= bounds.minX && a.x <= bounds.maxX && a.y >= bounds.minY && a.y <= bounds.maxY && b.x >= bounds.minX && b.x <= bounds.maxX && b.y >= bounds.minY && b.y <= bounds.maxY) {
1986
+ return 0;
1987
+ }
1988
+ const distances = [
1989
+ pointToSegmentDistance(topLeft, a, b),
1990
+ pointToSegmentDistance(topRight, a, b),
1991
+ pointToSegmentDistance(bottomLeft, a, b),
1992
+ pointToSegmentDistance(bottomRight, a, b)
1993
+ ];
1994
+ if (a.x >= bounds.minX && a.x <= bounds.maxX && a.y >= bounds.minY && a.y <= bounds.maxY) {
1995
+ return 0;
1996
+ }
1997
+ if (b.x >= bounds.minX && b.x <= bounds.maxX && b.y >= bounds.minY && b.y <= bounds.maxY) {
1998
+ return 0;
1999
+ }
2000
+ if (a.x < bounds.minX || a.x > bounds.maxX || a.y < bounds.minY || a.y > bounds.maxY) {
2001
+ const closestX = clamp(a.x, bounds.minX, bounds.maxX);
2002
+ const closestY = clamp(a.y, bounds.minY, bounds.maxY);
2003
+ distances.push(distance(a, { x: closestX, y: closestY }));
2004
+ }
2005
+ if (b.x < bounds.minX || b.x > bounds.maxX || b.y < bounds.minY || b.y > bounds.maxY) {
2006
+ const closestX = clamp(b.x, bounds.minX, bounds.maxX);
2007
+ const closestY = clamp(b.y, bounds.minY, bounds.maxY);
2008
+ distances.push(distance(b, { x: closestX, y: closestY }));
2009
+ }
2010
+ return Math.min(...distances);
2011
+ }
2012
+ function segmentToBoxMinDistance(a, b, box) {
2013
+ const halfWidth = box.width / 2;
2014
+ const halfHeight = box.height / 2;
2015
+ const bounds = {
2016
+ minX: box.center.x - halfWidth,
2017
+ maxX: box.center.x + halfWidth,
2018
+ minY: box.center.y - halfHeight,
2019
+ maxY: box.center.y + halfHeight
2020
+ };
2021
+ return segmentToBoundsMinDistance(a, b, bounds);
2022
+ }
2023
+
1941
2024
  // lib/data-structures/SingleRouteCandidatePriorityQueue.ts
1942
2025
  var SingleRouteCandidatePriorityQueue = class {
1943
2026
  heap = [];
@@ -3573,13 +3656,13 @@ function findClosestPointToABCWithinBounds(A, B, C, radius, bounds) {
3573
3656
  x: (A.x + B.x + C.x) / 3,
3574
3657
  y: (A.y + B.y + C.y) / 3
3575
3658
  };
3576
- const distance5 = (p1, p2) => {
3659
+ const distance6 = (p1, p2) => {
3577
3660
  return Math.sqrt((p2.x - p1.x) ** 2 + (p2.y - p1.y) ** 2);
3578
3661
  };
3579
3662
  const isValidPoint = (point) => {
3580
- const distToA = distance5(point, A);
3581
- const distToB = distance5(point, B);
3582
- const distToC = distance5(point, C);
3663
+ const distToA = distance6(point, A);
3664
+ const distToB = distance6(point, B);
3665
+ const distToC = distance6(point, C);
3583
3666
  const withinBounds = point.x >= bounds.minX && point.x <= bounds.maxX && point.y >= bounds.minY && point.y <= bounds.maxY;
3584
3667
  return distToA >= radius && distToB >= radius && distToC >= radius && withinBounds;
3585
3668
  };
@@ -3623,10 +3706,10 @@ function findClosestPointToABCWithinBounds(A, B, C, radius, bounds) {
3623
3706
  };
3624
3707
  const result = [];
3625
3708
  const epsilon = 1e-6;
3626
- if (Math.abs(distance5(intersection1, c1) - r) < epsilon && Math.abs(distance5(intersection1, c2) - r) < epsilon) {
3709
+ if (Math.abs(distance6(intersection1, c1) - r) < epsilon && Math.abs(distance6(intersection1, c2) - r) < epsilon) {
3627
3710
  result.push(intersection1);
3628
3711
  }
3629
- if (Math.abs(distance5(intersection2, c1) - r) < epsilon && Math.abs(distance5(intersection2, c2) - r) < epsilon) {
3712
+ if (Math.abs(distance6(intersection2, c1) - r) < epsilon && Math.abs(distance6(intersection2, c2) - r) < epsilon) {
3630
3713
  result.push(intersection2);
3631
3714
  }
3632
3715
  return result;
@@ -3650,7 +3733,7 @@ function findClosestPointToABCWithinBounds(A, B, C, radius, bounds) {
3650
3733
  const interiorCandidates = validCandidates.filter((p) => !isOnBoundary(p));
3651
3734
  if (interiorCandidates.length > 0) {
3652
3735
  interiorCandidates.sort(
3653
- (a, b) => distance5(a, avgPoint) - distance5(b, avgPoint)
3736
+ (a, b) => distance6(a, avgPoint) - distance6(b, avgPoint)
3654
3737
  );
3655
3738
  return interiorCandidates[0];
3656
3739
  }
@@ -3662,7 +3745,7 @@ function findClosestPointToABCWithinBounds(A, B, C, radius, bounds) {
3662
3745
  for (let y = bounds.minY + 1; y < bounds.maxY; y += gridStep) {
3663
3746
  const point = { x, y };
3664
3747
  if (isValidPoint(point)) {
3665
- const dist = distance5(point, avgPoint);
3748
+ const dist = distance6(point, avgPoint);
3666
3749
  if (dist < bestDistance) {
3667
3750
  bestDistance = dist;
3668
3751
  bestPoint = point;
@@ -3697,7 +3780,7 @@ function findClosestPointToABCWithinBounds(A, B, C, radius, bounds) {
3697
3780
  const validBoundaryPoints = boundaryPoints.filter(isValidPoint);
3698
3781
  if (validBoundaryPoints.length > 0) {
3699
3782
  validBoundaryPoints.sort(
3700
- (a, b) => distance5(a, avgPoint) - distance5(b, avgPoint)
3783
+ (a, b) => distance6(a, avgPoint) - distance6(b, avgPoint)
3701
3784
  );
3702
3785
  return validBoundaryPoints[0];
3703
3786
  }
@@ -3705,9 +3788,9 @@ function findClosestPointToABCWithinBounds(A, B, C, radius, bounds) {
3705
3788
  let leastBadPoint = { x: bounds.minX, y: bounds.minY };
3706
3789
  for (const point of [...allCandidates, ...boundaryPoints]) {
3707
3790
  if (point.x >= bounds.minX && point.x <= bounds.maxX && point.y >= bounds.minY && point.y <= bounds.maxY) {
3708
- const violationA = Math.max(0, radius - distance5(point, A));
3709
- const violationB = Math.max(0, radius - distance5(point, B));
3710
- const violationC = Math.max(0, radius - distance5(point, C));
3791
+ const violationA = Math.max(0, radius - distance6(point, A));
3792
+ const violationB = Math.max(0, radius - distance6(point, B));
3793
+ const violationC = Math.max(0, radius - distance6(point, C));
3711
3794
  const totalViolation = violationA + violationB + violationC;
3712
3795
  if (totalViolation < minViolation) {
3713
3796
  minViolation = totalViolation;
@@ -3722,12 +3805,62 @@ function findClosestPointToABCWithinBounds(A, B, C, radius, bounds) {
3722
3805
  function findPointToGetAroundCircle(A, C, Q) {
3723
3806
  const B = computeTangentPoint(C, A, Q.center, Q.radius);
3724
3807
  const D = computeTangentPoint(A, C, Q.center, Q.radius);
3725
- const E = computeIntersection(
3726
- { x: C.x, y: C.y },
3727
- { x: B.x, y: B.y },
3728
- { x: A.x, y: A.y },
3729
- { x: D.x, y: D.y }
3730
- );
3808
+ const distBC = distance2(B, C);
3809
+ const distAD = distance2(A, D);
3810
+ const minDistThreshold = 1e-6;
3811
+ const BIsValid = distBC > minDistThreshold;
3812
+ const DIsValid = distAD > minDistThreshold;
3813
+ let E;
3814
+ if (!BIsValid || !DIsValid) {
3815
+ const midAC = {
3816
+ x: (A.x + C.x) / 2,
3817
+ y: (A.y + C.y) / 2
3818
+ };
3819
+ const distFromCenter = distance2(midAC, Q.center);
3820
+ if (distFromCenter < Q.radius * 1.1) {
3821
+ const dirFromCenter = {
3822
+ x: (midAC.x - Q.center.x) / distFromCenter,
3823
+ y: (midAC.y - Q.center.y) / distFromCenter
3824
+ };
3825
+ E = {
3826
+ x: Q.center.x + dirFromCenter.x * Q.radius * 1.2,
3827
+ y: Q.center.y + dirFromCenter.y * Q.radius * 1.2
3828
+ };
3829
+ } else {
3830
+ E = midAC;
3831
+ }
3832
+ } else {
3833
+ E = {
3834
+ x: (B.x + D.x) / 2,
3835
+ y: (B.y + D.y) / 2
3836
+ };
3837
+ const distBE = distance2(B, E);
3838
+ const distDE = distance2(D, E);
3839
+ if (Math.abs(distBE - distDE) > Math.min(distBE, distDE) * 0.5) {
3840
+ const distAB = distance2(A, B);
3841
+ const distCD = distance2(C, D);
3842
+ const totalDist = distAB + distCD;
3843
+ if (totalDist > minDistThreshold) {
3844
+ const weightB = distCD / totalDist;
3845
+ const weightD = distAB / totalDist;
3846
+ E = {
3847
+ x: B.x * weightB + D.x * weightD,
3848
+ y: B.y * weightB + D.y * weightD
3849
+ };
3850
+ }
3851
+ }
3852
+ const distEToCenter = distance2(E, Q.center);
3853
+ if (distEToCenter < Q.radius * 1.05) {
3854
+ const dirFromCenter = {
3855
+ x: (E.x - Q.center.x) / distEToCenter,
3856
+ y: (E.y - Q.center.y) / distEToCenter
3857
+ };
3858
+ E = {
3859
+ x: Q.center.x + dirFromCenter.x * Q.radius * 1.2,
3860
+ y: Q.center.y + dirFromCenter.y * Q.radius * 1.2
3861
+ };
3862
+ }
3863
+ }
3731
3864
  return { B, D, E };
3732
3865
  }
3733
3866
  function computeTangentPoint(observationPoint, referencePoint, circleCenter, radius) {
@@ -3736,8 +3869,29 @@ function computeTangentPoint(observationPoint, referencePoint, circleCenter, rad
3736
3869
  circleCenter.y - observationPoint.y
3737
3870
  ];
3738
3871
  const CQLength = Math.sqrt(CQ[0] * CQ[0] + CQ[1] * CQ[1]);
3739
- if (CQLength < radius) {
3740
- return observationPoint;
3872
+ if (CQLength <= radius) {
3873
+ if (CQLength < 1e-8) {
3874
+ const refVec = [
3875
+ referencePoint.x - observationPoint.x,
3876
+ referencePoint.y - observationPoint.y
3877
+ ];
3878
+ const refLength = Math.sqrt(refVec[0] * refVec[0] + refVec[1] * refVec[1]);
3879
+ if (refLength < 1e-8) {
3880
+ return {
3881
+ x: circleCenter.x + radius,
3882
+ y: circleCenter.y
3883
+ };
3884
+ }
3885
+ return {
3886
+ x: circleCenter.x + refVec[0] / refLength * radius,
3887
+ y: circleCenter.y + refVec[1] / refLength * radius
3888
+ };
3889
+ }
3890
+ const CQUnit2 = [CQ[0] / CQLength, CQ[1] / CQLength];
3891
+ return {
3892
+ x: circleCenter.x - CQUnit2[0] * radius,
3893
+ y: circleCenter.y - CQUnit2[1] * radius
3894
+ };
3741
3895
  }
3742
3896
  const CR = [
3743
3897
  referencePoint.x - observationPoint.x,
@@ -3761,23 +3915,108 @@ function computeTangentPoint(observationPoint, referencePoint, circleCenter, rad
3761
3915
  y: observationPoint.y + d * unitToTangent[1]
3762
3916
  };
3763
3917
  }
3764
- function computeIntersection(p1, p2, p3, p4) {
3765
- const a1 = p2.y - p1.y;
3766
- const b1 = p1.x - p2.x;
3767
- const c1 = a1 * p1.x + b1 * p1.y;
3768
- const a2 = p4.y - p3.y;
3769
- const b2 = p3.x - p4.x;
3770
- const c2 = a2 * p3.x + b2 * p3.y;
3771
- const det = a1 * b2 - a2 * b1;
3772
- if (Math.abs(det) < 1e-8) {
3773
- return {
3774
- x: (p1.x + p3.x) / 2,
3775
- y: (p1.y + p3.y) / 2
3776
- };
3918
+ function distance2(p1, p2) {
3919
+ const dx = p2.x - p1.x;
3920
+ const dy = p2.y - p1.y;
3921
+ return Math.sqrt(dx * dx + dy * dy);
3922
+ }
3923
+
3924
+ // lib/solvers/HighDensitySolver/TwoRouteHighDensitySolver/calculateSideTraversal.ts
3925
+ var EPSILON = 1e-9;
3926
+ function calculateSegmentTraversal(startPoint, endPoint, bounds) {
3927
+ const startAngle = pointToAngle(startPoint, bounds);
3928
+ let endAngle = pointToAngle(endPoint, bounds);
3929
+ if (endAngle < startAngle) {
3930
+ endAngle += 2 * Math.PI;
3931
+ }
3932
+ if (Math.abs(endAngle - startAngle) < EPSILON) {
3933
+ return { left: 0, top: 0, right: 0, bottom: 0 };
3934
+ }
3935
+ return calculateSidePercentages(startAngle, endAngle, bounds);
3936
+ }
3937
+ function calculateTraversalPercentages(A, B, C, bounds) {
3938
+ const percentagesAB = calculateSegmentTraversal(A, B, bounds);
3939
+ const percentagesBC = calculateSegmentTraversal(B, C, bounds);
3940
+ const totalPercentages = {
3941
+ left: Math.min(1, percentagesAB.left + percentagesBC.left),
3942
+ top: Math.min(1, percentagesAB.top + percentagesBC.top),
3943
+ right: Math.min(1, percentagesAB.right + percentagesBC.right),
3944
+ bottom: Math.min(1, percentagesAB.bottom + percentagesBC.bottom)
3945
+ };
3946
+ for (const key in totalPercentages) {
3947
+ if (Math.abs(totalPercentages[key]) < EPSILON) {
3948
+ totalPercentages[key] = 0;
3949
+ }
3950
+ }
3951
+ return totalPercentages;
3952
+ }
3953
+ function pointToAngle(point, bounds) {
3954
+ const width = bounds.maxX - bounds.minX;
3955
+ const height = bounds.maxY - bounds.minY;
3956
+ if (width < EPSILON && height < EPSILON) return 0;
3957
+ const perimeter = 2 * (width + height);
3958
+ if (perimeter < EPSILON) return 0;
3959
+ let distance6 = 0;
3960
+ if (Math.abs(point.y - bounds.maxY) < EPSILON && point.x >= bounds.minX - EPSILON && point.x <= bounds.maxX + EPSILON) {
3961
+ distance6 = Math.max(0, Math.min(width, point.x - bounds.minX));
3962
+ } else if (Math.abs(point.x - bounds.maxX) < EPSILON && point.y >= bounds.minY - EPSILON && point.y <= bounds.maxY + EPSILON) {
3963
+ distance6 = width + Math.max(0, Math.min(height, bounds.maxY - point.y));
3964
+ } else if (Math.abs(point.y - bounds.minY) < EPSILON && point.x >= bounds.minX - EPSILON && point.x <= bounds.maxX + EPSILON) {
3965
+ distance6 = width + height + Math.max(0, Math.min(width, bounds.maxX - point.x));
3966
+ } else if (Math.abs(point.x - bounds.minX) < EPSILON && point.y >= bounds.minY - EPSILON && point.y <= bounds.maxY + EPSILON) {
3967
+ distance6 = width + height + width + Math.max(0, Math.min(height, point.y - bounds.minY));
3968
+ } else {
3969
+ throw new Error(
3970
+ `Point (${point.x}, ${point.y}) does not lie on the boundary defined by ${JSON.stringify(bounds)}`
3971
+ );
3777
3972
  }
3778
- const x = (b2 * c1 - b1 * c2) / det;
3779
- const y = (a1 * c2 - a2 * c1) / det;
3780
- return { x, y };
3973
+ distance6 = Math.max(0, Math.min(perimeter, distance6));
3974
+ return perimeter > EPSILON ? distance6 / perimeter * (2 * Math.PI) : 0;
3975
+ }
3976
+ function calculateSidePercentages(startAngle, endAngle, bounds) {
3977
+ const width = bounds.maxX - bounds.minX;
3978
+ const height = bounds.maxY - bounds.minY;
3979
+ if (width < EPSILON && height < EPSILON)
3980
+ return { left: 0, top: 0, right: 0, bottom: 0 };
3981
+ const perimeter = 2 * (width + height);
3982
+ if (perimeter < EPSILON) return { left: 0, top: 0, right: 0, bottom: 0 };
3983
+ const angleTopEnd = width / perimeter * (2 * Math.PI);
3984
+ const angleRightEnd = (width + height) / perimeter * (2 * Math.PI);
3985
+ const angleBottomEnd = (width + width + height) / perimeter * (2 * Math.PI);
3986
+ const angleLeftEnd = 2 * Math.PI;
3987
+ const sides = [
3988
+ { name: "top", start: 0, end: angleTopEnd, length: width },
3989
+ { name: "right", start: angleTopEnd, end: angleRightEnd, length: height },
3990
+ {
3991
+ name: "bottom",
3992
+ start: angleRightEnd,
3993
+ end: angleBottomEnd,
3994
+ length: width
3995
+ },
3996
+ { name: "left", start: angleBottomEnd, end: angleLeftEnd, length: height }
3997
+ // Ends at 2PI
3998
+ ];
3999
+ const result = { left: 0, top: 0, right: 0, bottom: 0 };
4000
+ const totalAngleTraversal = endAngle - startAngle;
4001
+ if (totalAngleTraversal < EPSILON) return result;
4002
+ for (const side of sides) {
4003
+ const sideAngleRange = side.end - side.start;
4004
+ if (sideAngleRange < EPSILON || side.length < EPSILON) continue;
4005
+ const overlapStart = Math.max(startAngle, side.start);
4006
+ const overlapEnd = Math.min(endAngle, side.end);
4007
+ if (overlapStart < overlapEnd - EPSILON) {
4008
+ const traversedAngleOnSide = overlapEnd - overlapStart;
4009
+ const percentage = traversedAngleOnSide / sideAngleRange;
4010
+ result[side.name] += Math.max(0, percentage);
4011
+ }
4012
+ }
4013
+ for (const key in result) {
4014
+ result[key] = Math.max(
4015
+ 0,
4016
+ Math.min(1, result[key])
4017
+ );
4018
+ }
4019
+ return result;
3781
4020
  }
3782
4021
 
3783
4022
  // lib/solvers/HighDensitySolver/TwoRouteHighDensitySolver/SingleTransitionCrossingRouteSolver.ts
@@ -3864,17 +4103,30 @@ var SingleTransitionCrossingRouteSolver = class extends BaseSolver {
3864
4103
  const ntrP1 = transitionRoute.A.z !== flatRouteZ ? transitionRoute.A : transitionRoute.B;
3865
4104
  const marginFromBorderWithTrace = this.obstacleMargin * 2 + this.viaDiameter / 2 + this.traceThickness;
3866
4105
  const marginFromBorderWithoutTrace = this.obstacleMargin + this.viaDiameter / 2;
4106
+ const A = flatRoute.A;
4107
+ const B = ntrP1;
4108
+ const C = flatRoute.B;
4109
+ const sideTraversal = calculateTraversalPercentages(A, B, C, this.bounds);
4110
+ const viaBounds = {
4111
+ minX: this.bounds.minX + (sideTraversal.left > 0.5 ? marginFromBorderWithTrace : marginFromBorderWithoutTrace),
4112
+ minY: this.bounds.minY + (sideTraversal.bottom > 0.5 ? marginFromBorderWithTrace : marginFromBorderWithoutTrace),
4113
+ maxX: this.bounds.maxX - (sideTraversal.right > 0.5 ? marginFromBorderWithTrace : marginFromBorderWithoutTrace),
4114
+ maxY: this.bounds.maxY - (sideTraversal.top > 0.5 ? marginFromBorderWithTrace : marginFromBorderWithoutTrace)
4115
+ };
4116
+ if (viaBounds.maxY < viaBounds.minY) {
4117
+ viaBounds.minY = (viaBounds.minY + viaBounds.maxY) / 2;
4118
+ viaBounds.maxY = viaBounds.minY;
4119
+ }
4120
+ if (viaBounds.maxX < viaBounds.minX) {
4121
+ viaBounds.minX = (viaBounds.minX + viaBounds.maxX) / 2;
4122
+ viaBounds.maxX = viaBounds.minX;
4123
+ }
3867
4124
  return findClosestPointToABCWithinBounds(
3868
- flatRoute.A,
3869
- flatRoute.B,
3870
- ntrP1,
4125
+ A,
4126
+ B,
4127
+ C,
3871
4128
  marginFromBorderWithTrace,
3872
- {
3873
- minX: this.bounds.minX + marginFromBorderWithoutTrace,
3874
- minY: this.bounds.minY + marginFromBorderWithoutTrace,
3875
- maxX: this.bounds.maxX - marginFromBorderWithTrace,
3876
- maxY: this.bounds.maxY - marginFromBorderWithTrace
3877
- }
4129
+ viaBounds
3878
4130
  );
3879
4131
  }
3880
4132
  /**
@@ -4662,13 +4914,13 @@ function buildMinimumSpanningTree(points) {
4662
4914
  if (point.x === neighbor.x && point.y === neighbor.y) {
4663
4915
  continue;
4664
4916
  }
4665
- const distance5 = Math.sqrt(
4917
+ const distance6 = Math.sqrt(
4666
4918
  (point.x - neighbor.x) ** 2 + (point.y - neighbor.y) ** 2
4667
4919
  );
4668
4920
  edges.push({
4669
4921
  from: point,
4670
4922
  to: neighbor,
4671
- weight: distance5
4923
+ weight: distance6
4672
4924
  });
4673
4925
  }
4674
4926
  }
@@ -6489,11 +6741,11 @@ var CapacityPathingSolver = class extends BaseSolver {
6489
6741
  let closestNode = this.nodes[0];
6490
6742
  let minDistance = Number.MAX_VALUE;
6491
6743
  for (const node of nodesWithTargets) {
6492
- const distance5 = Math.sqrt(
6744
+ const distance6 = Math.sqrt(
6493
6745
  (node.center.x - point.x) ** 2 + (node.center.y - point.y) ** 2
6494
6746
  );
6495
- if (distance5 < minDistance) {
6496
- minDistance = distance5;
6747
+ if (distance6 < minDistance) {
6748
+ minDistance = distance6;
6497
6749
  closestNode = node;
6498
6750
  }
6499
6751
  }
@@ -7085,7 +7337,7 @@ var CapacityNodeTree = class {
7085
7337
  };
7086
7338
 
7087
7339
  // lib/solvers/SingleLayerNodeMerger/SingleLayerNodeMergerSolver.ts
7088
- var EPSILON = 5e-3;
7340
+ var EPSILON2 = 5e-3;
7089
7341
  var SingleLayerNodeMergerSolver = class extends BaseSolver {
7090
7342
  nodeMap;
7091
7343
  currentBatchNodeIds;
@@ -7244,7 +7496,7 @@ var SingleLayerNodeMergerSolver = class extends BaseSolver {
7244
7496
  adjacentNodesToLeft.reduce((acc, adjNode) => {
7245
7497
  return acc + adjNode.height;
7246
7498
  }, 0) - rootNode.height
7247
- ) < EPSILON;
7499
+ ) < EPSILON2;
7248
7500
  if (leftAdjNodesTakeUpEntireHeight && leftAdjNodesAreAllSameSize) {
7249
7501
  rootNode.width += leftAdjNodeWidth;
7250
7502
  rootNode.center.x = rootNode.center.x - leftAdjNodeWidth / 2;
@@ -7264,7 +7516,7 @@ var SingleLayerNodeMergerSolver = class extends BaseSolver {
7264
7516
  adjacentNodesToRight.reduce((acc, adjNode) => {
7265
7517
  return acc + adjNode.height;
7266
7518
  }, 0) - rootNode.height
7267
- ) < EPSILON;
7519
+ ) < EPSILON2;
7268
7520
  if (rightAdjNodesTakeUpEntireHeight && rightAdjNodesAreAllSameSize) {
7269
7521
  rootNode.width += rightAdjNodeWidth;
7270
7522
  rootNode.center.x = rootNode.center.x + rightAdjNodeWidth / 2;
@@ -7284,7 +7536,7 @@ var SingleLayerNodeMergerSolver = class extends BaseSolver {
7284
7536
  adjacentNodesToTop.reduce((acc, adjNode) => {
7285
7537
  return acc + adjNode.width;
7286
7538
  }, 0) - rootNode.width
7287
- ) < EPSILON;
7539
+ ) < EPSILON2;
7288
7540
  if (topAdjNodesTakeUpEntireWidth && topAdjNodesAreAllSameSize) {
7289
7541
  rootNode.height += topAdjNodeHeight;
7290
7542
  rootNode.center.y = rootNode.center.y + topAdjNodeHeight / 2;
@@ -7304,7 +7556,7 @@ var SingleLayerNodeMergerSolver = class extends BaseSolver {
7304
7556
  adjacentNodesToBottom.reduce((acc, adjNode) => {
7305
7557
  return acc + adjNode.width;
7306
7558
  }, 0) - rootNode.width
7307
- ) < EPSILON;
7559
+ ) < EPSILON2;
7308
7560
  if (bottomAdjNodesTakeUpEntireWidth && bottomAdjNodesAreAllSameSize) {
7309
7561
  rootNode.height += bottomAdjNodeHeight;
7310
7562
  rootNode.center.y = rootNode.center.y - bottomAdjNodeHeight / 2;
@@ -7401,6 +7653,15 @@ var SingleSimplifiedPathSolver = class extends BaseSolver {
7401
7653
  this.newRoute = [this.inputRoute.route[0]];
7402
7654
  this.newVias = [];
7403
7655
  }
7656
+ getConstructorParams() {
7657
+ return {
7658
+ inputRoute: this.inputRoute,
7659
+ otherHdRoutes: this.otherHdRoutes,
7660
+ obstacles: this.obstacles,
7661
+ connMap: this.connMap.netMap,
7662
+ colorMap: this.colorMap
7663
+ };
7664
+ }
7404
7665
  get simplifiedRoute() {
7405
7666
  return {
7406
7667
  connectionName: this.inputRoute.connectionName,
@@ -7541,23 +7802,23 @@ function pointToSegmentDistance4(P, Q1, Q2) {
7541
7802
  const w = { x: P.x - Q1.x, y: P.y - Q1.y };
7542
7803
  const c1 = dotProduct(w, v);
7543
7804
  if (c1 <= 0) {
7544
- return distance4(P, Q1);
7805
+ return distance5(P, Q1);
7545
7806
  }
7546
7807
  const c2 = dotProduct(v, v);
7547
7808
  if (c2 <= c1) {
7548
- return distance4(P, Q2);
7809
+ return distance5(P, Q2);
7549
7810
  }
7550
7811
  const b = c1 / c2;
7551
7812
  const Pb = {
7552
7813
  x: Q1.x + b * v.x,
7553
7814
  y: Q1.y + b * v.y
7554
7815
  };
7555
- return distance4(P, Pb);
7816
+ return distance5(P, Pb);
7556
7817
  }
7557
7818
  function dotProduct(v1, v2) {
7558
7819
  return v1.x * v2.x + v1.y * v2.y;
7559
7820
  }
7560
- function distance4(p1, p2) {
7821
+ function distance5(p1, p2) {
7561
7822
  const dx = p2.x - p1.x;
7562
7823
  const dy = p2.y - p1.y;
7563
7824
  return Math.sqrt(dx * dx + dy * dy);
@@ -7617,6 +7878,7 @@ var SegmentTree = class {
7617
7878
  }
7618
7879
  buckets;
7619
7880
  CELL_SIZE = 0.4;
7881
+ SEGMENT_MARGIN = 0.2;
7620
7882
  getBucketKey(x, y) {
7621
7883
  return `${Math.floor(x / this.CELL_SIZE)}x${Math.floor(y / this.CELL_SIZE)}`;
7622
7884
  }
@@ -7626,10 +7888,10 @@ var SegmentTree = class {
7626
7888
  getSegmentsThatCouldIntersect(A, B) {
7627
7889
  const segments = [];
7628
7890
  const alreadyAddedSegments = /* @__PURE__ */ new Set();
7629
- const minX = Math.min(A.x, B.x);
7630
- const minY = Math.min(A.y, B.y);
7631
- const maxX = Math.max(A.x, B.x);
7632
- const maxY = Math.max(A.y, B.y);
7891
+ const minX = Math.min(A.x, B.x) - this.SEGMENT_MARGIN;
7892
+ const minY = Math.min(A.y, B.y) - this.SEGMENT_MARGIN;
7893
+ const maxX = Math.max(A.x, B.x) + this.SEGMENT_MARGIN;
7894
+ const maxY = Math.max(A.y, B.y) + this.SEGMENT_MARGIN;
7633
7895
  const bucketMinX = Math.floor(minX / this.CELL_SIZE) * this.CELL_SIZE;
7634
7896
  const bucketMinY = Math.floor(minY / this.CELL_SIZE) * this.CELL_SIZE;
7635
7897
  for (let x = bucketMinX; x <= maxX; x += this.CELL_SIZE) {
@@ -7669,7 +7931,8 @@ var SingleSimplifiedPathSolver5 = class extends SingleSimplifiedPathSolver {
7669
7931
  filteredObstaclePathSegments = [];
7670
7932
  filteredVias = [];
7671
7933
  segmentTree;
7672
- OBSTACLE_MARGIN = 0.15;
7934
+ OBSTACLE_MARGIN = 0.1;
7935
+ TRACE_THICKNESS = 0.15;
7673
7936
  TAIL_JUMP_RATIO = 0.8;
7674
7937
  constructor(params) {
7675
7938
  super(params);
@@ -7689,6 +7952,14 @@ var SingleSimplifiedPathSolver5 = class extends SingleSimplifiedPathSolver {
7689
7952
  },
7690
7953
  { minX: Infinity, maxX: -Infinity, minY: Infinity, maxY: -Infinity }
7691
7954
  );
7955
+ const boundsBox = {
7956
+ center: {
7957
+ x: (bounds.minX + bounds.maxX) / 2,
7958
+ y: (bounds.minY + bounds.maxY) / 2
7959
+ },
7960
+ width: bounds.maxX - bounds.minX,
7961
+ height: bounds.maxY - bounds.minY
7962
+ };
7692
7963
  this.filteredObstacles = this.obstacles.filter(
7693
7964
  (obstacle) => !obstacle.connectedTo.some(
7694
7965
  (id) => this.connMap.areIdsConnected(this.inputRoute.connectionName, id)
@@ -7699,11 +7970,11 @@ var SingleSimplifiedPathSolver5 = class extends SingleSimplifiedPathSolver {
7699
7970
  )) {
7700
7971
  return false;
7701
7972
  }
7702
- const obstacleMinX = obstacle.center.x - obstacle.width / 2 - this.OBSTACLE_MARGIN;
7703
- const obstacleMaxX = obstacle.center.x + obstacle.width / 2 + this.OBSTACLE_MARGIN;
7704
- const obstacleMinY = obstacle.center.y - obstacle.height / 2 - this.OBSTACLE_MARGIN;
7705
- const obstacleMaxY = obstacle.center.y + obstacle.height / 2 + this.OBSTACLE_MARGIN;
7706
- return obstacleMinX <= bounds.maxX && obstacleMaxX >= bounds.minX && obstacleMinY <= bounds.maxY && obstacleMaxY >= bounds.minY;
7973
+ const { distance: distance6 } = computeDistanceBetweenBoxes(boundsBox, obstacle);
7974
+ if (distance6 < this.OBSTACLE_MARGIN + 0.5) {
7975
+ return true;
7976
+ }
7977
+ return false;
7707
7978
  });
7708
7979
  this.filteredObstaclePathSegments = this.otherHdRoutes.flatMap(
7709
7980
  (hdRoute) => {
@@ -7775,15 +8046,15 @@ var SingleSimplifiedPathSolver5 = class extends SingleSimplifiedPathSolver {
7775
8046
  return p1.x === p2.x && p1.y === p2.y && p1.z === p2.z;
7776
8047
  }
7777
8048
  // Get point at a specific distance along the path
7778
- getPointAtDistance(distance5) {
7779
- distance5 = Math.max(0, Math.min(distance5, this.totalPathLength));
8049
+ getPointAtDistance(distance6) {
8050
+ distance6 = Math.max(0, Math.min(distance6, this.totalPathLength));
7780
8051
  const segment = this.pathSegments.find(
7781
- (seg) => distance5 >= seg.startDistance && distance5 <= seg.endDistance
8052
+ (seg) => distance6 >= seg.startDistance && distance6 <= seg.endDistance
7782
8053
  );
7783
8054
  if (!segment) {
7784
8055
  return this.inputRoute.route[this.inputRoute.route.length - 1];
7785
8056
  }
7786
- const factor = (distance5 - segment.startDistance) / segment.length;
8057
+ const factor = (distance6 - segment.startDistance) / segment.length;
7787
8058
  return {
7788
8059
  x: segment.start.x + factor * (segment.end.x - segment.start.x),
7789
8060
  y: segment.start.y + factor * (segment.end.y - segment.start.y),
@@ -7792,17 +8063,17 @@ var SingleSimplifiedPathSolver5 = class extends SingleSimplifiedPathSolver {
7792
8063
  };
7793
8064
  }
7794
8065
  // Find nearest index in the original route for a given distance
7795
- getNearestIndexForDistance(distance5) {
7796
- if (distance5 <= 0) return 0;
7797
- if (distance5 >= this.totalPathLength)
8066
+ getNearestIndexForDistance(distance6) {
8067
+ if (distance6 <= 0) return 0;
8068
+ if (distance6 >= this.totalPathLength)
7798
8069
  return this.inputRoute.route.length - 1;
7799
8070
  const segmentIndex = this.pathSegments.findIndex(
7800
- (seg) => distance5 >= seg.startDistance && distance5 <= seg.endDistance
8071
+ (seg) => distance6 >= seg.startDistance && distance6 <= seg.endDistance
7801
8072
  );
7802
8073
  if (segmentIndex === -1) return 0;
7803
8074
  const segment = this.pathSegments[segmentIndex];
7804
8075
  const midDistance = (segment.startDistance + segment.endDistance) / 2;
7805
- return distance5 > midDistance ? segmentIndex + 1 : segmentIndex;
8076
+ return distance6 > midDistance ? segmentIndex + 1 : segmentIndex;
7806
8077
  }
7807
8078
  // Check if a path segment is valid
7808
8079
  isValidPathSegment(start, end) {
@@ -7810,49 +8081,27 @@ var SingleSimplifiedPathSolver5 = class extends SingleSimplifiedPathSolver {
7810
8081
  if (!obstacle.zLayers?.includes(start.z)) {
7811
8082
  continue;
7812
8083
  }
7813
- const obstacleLeft = obstacle.center.x - obstacle.width / 2 - this.OBSTACLE_MARGIN;
7814
- const obstacleRight = obstacle.center.x + obstacle.width / 2 + this.OBSTACLE_MARGIN;
7815
- const obstacleTop = obstacle.center.y - obstacle.height / 2 - this.OBSTACLE_MARGIN;
7816
- const obstacleBottom = obstacle.center.y + obstacle.height / 2 + this.OBSTACLE_MARGIN;
7817
- if (doSegmentsIntersect(
7818
- { x: start.x, y: start.y },
7819
- { x: end.x, y: end.y },
7820
- { x: obstacleLeft, y: obstacleTop },
7821
- { x: obstacleRight, y: obstacleTop }
7822
- ) || doSegmentsIntersect(
7823
- { x: start.x, y: start.y },
7824
- { x: end.x, y: end.y },
7825
- { x: obstacleRight, y: obstacleTop },
7826
- { x: obstacleRight, y: obstacleBottom }
7827
- ) || doSegmentsIntersect(
7828
- { x: start.x, y: start.y },
7829
- { x: end.x, y: end.y },
7830
- { x: obstacleRight, y: obstacleBottom },
7831
- { x: obstacleLeft, y: obstacleBottom }
7832
- ) || doSegmentsIntersect(
7833
- { x: start.x, y: start.y },
7834
- { x: end.x, y: end.y },
7835
- { x: obstacleLeft, y: obstacleBottom },
7836
- { x: obstacleLeft, y: obstacleTop }
7837
- )) {
8084
+ const distToObstacle = segmentToBoxMinDistance(start, end, obstacle);
8085
+ if (distToObstacle < this.OBSTACLE_MARGIN + this.TRACE_THICKNESS / 2) {
7838
8086
  return false;
7839
8087
  }
7840
8088
  }
7841
8089
  const segmentsThatCouldIntersect = this.segmentTree.getSegmentsThatCouldIntersect(start, end);
7842
- for (const [otherSegA, otherSegB] of segmentsThatCouldIntersect) {
8090
+ for (const [otherSegA, otherSegB, segId] of segmentsThatCouldIntersect) {
7843
8091
  if (otherSegA.z === start.z && otherSegB.z === start.z) {
7844
- if (minimumDistanceBetweenSegments(
8092
+ const distBetweenSegments = minimumDistanceBetweenSegments(
7845
8093
  { x: start.x, y: start.y },
7846
8094
  { x: end.x, y: end.y },
7847
8095
  { x: otherSegA.x, y: otherSegA.y },
7848
8096
  { x: otherSegB.x, y: otherSegB.y }
7849
- ) < this.OBSTACLE_MARGIN) {
8097
+ );
8098
+ if (distBetweenSegments < this.OBSTACLE_MARGIN + this.TRACE_THICKNESS) {
7850
8099
  return false;
7851
8100
  }
7852
8101
  }
7853
8102
  }
7854
8103
  for (const via of this.filteredVias) {
7855
- if (pointToSegmentDistance(via, start, end) < this.OBSTACLE_MARGIN + via.diameter / 2) {
8104
+ if (pointToSegmentDistance(via, start, end) < this.OBSTACLE_MARGIN + via.diameter / 2 + this.TRACE_THICKNESS / 2) {
7856
8105
  return false;
7857
8106
  }
7858
8107
  }
@@ -7904,10 +8153,10 @@ var SingleSimplifiedPathSolver5 = class extends SingleSimplifiedPathSolver {
7904
8153
  }
7905
8154
  this.currentStepSize = this.maxStepSize;
7906
8155
  }
7907
- moveHead(distance5) {
7908
- this.lastHeadMoveDistance = distance5;
8156
+ moveHead(distance6) {
8157
+ this.lastHeadMoveDistance = distance6;
7909
8158
  this.headDistanceAlongPath = Math.min(
7910
- this.headDistanceAlongPath + distance5,
8159
+ this.headDistanceAlongPath + distance6,
7911
8160
  this.totalPathLength
7912
8161
  );
7913
8162
  }
@@ -8045,9 +8294,9 @@ var SingleSimplifiedPathSolver5 = class extends SingleSimplifiedPathSolver {
8045
8294
  color: "red",
8046
8295
  label: ["Tentative Head", `z: ${tentativeHead.z}`].join("\n")
8047
8296
  });
8048
- let distance5 = 0;
8049
- while (distance5 < this.totalPathLength) {
8050
- const point = this.getPointAtDistance(distance5);
8297
+ let distance6 = 0;
8298
+ while (distance6 < this.totalPathLength) {
8299
+ const point = this.getPointAtDistance(distance6);
8051
8300
  graphics.circles.push({
8052
8301
  center: {
8053
8302
  x: point.x,
@@ -8056,7 +8305,7 @@ var SingleSimplifiedPathSolver5 = class extends SingleSimplifiedPathSolver {
8056
8305
  radius: 0.05,
8057
8306
  fill: "rgba(100, 100, 100, 0.5)"
8058
8307
  });
8059
- distance5 += this.totalPathLength / 20;
8308
+ distance6 += this.totalPathLength / 20;
8060
8309
  }
8061
8310
  if (this.lastValidPath && this.lastValidPath.length > 1) {
8062
8311
  for (let i = 0; i < this.lastValidPath.length - 1; i++) {