@tscircuit/capacity-autorouter 0.0.51 → 0.0.52

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
@@ -4030,20 +4030,17 @@ function distance2(p1, p2) {
4030
4030
 
4031
4031
  // lib/solvers/HighDensitySolver/TwoRouteHighDensitySolver/calculateSideTraversal.ts
4032
4032
  var EPSILON2 = 1e-9;
4033
- function calculateSegmentTraversal(startPoint, endPoint, bounds) {
4033
+ function calculateSegmentTraversal(startPoint, endPoint, bounds, turnDirection = "cw") {
4034
4034
  const startAngle = pointToAngle(startPoint, bounds);
4035
- let endAngle = pointToAngle(endPoint, bounds);
4036
- if (endAngle < startAngle) {
4037
- endAngle += 2 * Math.PI;
4038
- }
4035
+ const endAngle = pointToAngle(endPoint, bounds);
4039
4036
  if (Math.abs(endAngle - startAngle) < EPSILON2) {
4040
4037
  return { left: 0, top: 0, right: 0, bottom: 0 };
4041
4038
  }
4042
- return calculateSidePercentages(startAngle, endAngle, bounds);
4039
+ return calculateSidePercentages(startAngle, endAngle, bounds, turnDirection);
4043
4040
  }
4044
- function calculateTraversalPercentages(A, B, C, bounds) {
4045
- const percentagesAB = calculateSegmentTraversal(A, B, bounds);
4046
- const percentagesBC = calculateSegmentTraversal(B, C, bounds);
4041
+ function calculateTraversalPercentages(A, B, C, bounds, turnDirection) {
4042
+ const percentagesAB = calculateSegmentTraversal(A, B, bounds, turnDirection);
4043
+ const percentagesBC = calculateSegmentTraversal(B, C, bounds, turnDirection);
4047
4044
  const totalPercentages = {
4048
4045
  left: Math.min(1, percentagesAB.left + percentagesBC.left),
4049
4046
  top: Math.min(1, percentagesAB.top + percentagesBC.top),
@@ -4080,7 +4077,7 @@ function pointToAngle(point, bounds) {
4080
4077
  distance6 = Math.max(0, Math.min(perimeter, distance6));
4081
4078
  return perimeter > EPSILON2 ? distance6 / perimeter * (2 * Math.PI) : 0;
4082
4079
  }
4083
- function calculateSidePercentages(startAngle, endAngle, bounds) {
4080
+ function calculateSidePercentages(startAngle, endAngle, bounds, turnDirection) {
4084
4081
  const width = bounds.maxX - bounds.minX;
4085
4082
  const height = bounds.maxY - bounds.minY;
4086
4083
  if (width < EPSILON2 && height < EPSILON2)
@@ -4104,17 +4101,54 @@ function calculateSidePercentages(startAngle, endAngle, bounds) {
4104
4101
  // Ends at 2PI
4105
4102
  ];
4106
4103
  const result = { left: 0, top: 0, right: 0, bottom: 0 };
4107
- const totalAngleTraversal = endAngle - startAngle;
4108
- if (totalAngleTraversal < EPSILON2) return result;
4104
+ const calculateTraversalOverlap = (sStart, sEnd, tStart, tEnd, wrapsAround) => {
4105
+ const effectiveSEnd = sEnd > 2 * Math.PI - EPSILON2 ? 2 * Math.PI : sEnd;
4106
+ if (effectiveSEnd <= sStart + EPSILON2) return 0;
4107
+ if (!wrapsAround) {
4108
+ const overlapStart = Math.max(sStart, tStart);
4109
+ const overlapEnd = Math.min(effectiveSEnd, tEnd);
4110
+ return Math.max(0, overlapEnd - overlapStart);
4111
+ } else {
4112
+ const overlap1Start = Math.max(sStart, tStart);
4113
+ const overlap1End = Math.min(effectiveSEnd, 2 * Math.PI);
4114
+ const overlap1 = Math.max(0, overlap1End - overlap1Start);
4115
+ const overlap2Start = Math.max(sStart, 0);
4116
+ const overlap2End = Math.min(effectiveSEnd, tEnd);
4117
+ const overlap2 = Math.max(0, overlap2End - overlap2Start);
4118
+ return overlap1 + overlap2;
4119
+ }
4120
+ };
4109
4121
  for (const side of sides) {
4110
4122
  const sideAngleRange = side.end - side.start;
4111
4123
  if (sideAngleRange < EPSILON2 || side.length < EPSILON2) continue;
4112
- const overlapStart = Math.max(startAngle, side.start);
4113
- const overlapEnd = Math.min(endAngle, side.end);
4114
- if (overlapStart < overlapEnd - EPSILON2) {
4115
- const traversedAngleOnSide = overlapEnd - overlapStart;
4124
+ let traversedAngleOnSide = 0;
4125
+ if (turnDirection === "cw") {
4126
+ const wraps = startAngle > endAngle + EPSILON2;
4127
+ traversedAngleOnSide = calculateTraversalOverlap(
4128
+ side.start,
4129
+ side.end,
4130
+ startAngle,
4131
+ endAngle,
4132
+ wraps
4133
+ );
4134
+ } else {
4135
+ const wraps = endAngle > startAngle + EPSILON2;
4136
+ traversedAngleOnSide = calculateTraversalOverlap(
4137
+ side.start,
4138
+ side.end,
4139
+ endAngle,
4140
+ // Start of equivalent CW traversal
4141
+ startAngle,
4142
+ // End of equivalent CW traversal
4143
+ wraps
4144
+ );
4145
+ }
4146
+ if (traversedAngleOnSide > EPSILON2) {
4116
4147
  const percentage = traversedAngleOnSide / sideAngleRange;
4117
- result[side.name] += Math.max(0, percentage);
4148
+ result[side.name] += Math.max(
4149
+ 0,
4150
+ Number.isFinite(percentage) ? percentage : 0
4151
+ );
4118
4152
  }
4119
4153
  }
4120
4154
  for (const key in result) {
@@ -4126,6 +4160,28 @@ function calculateSidePercentages(startAngle, endAngle, bounds) {
4126
4160
  return result;
4127
4161
  }
4128
4162
 
4163
+ // lib/solvers/HighDensitySolver/TwoRouteHighDensitySolver/computeTurnDirection.ts
4164
+ function triangleDirection({
4165
+ angleA,
4166
+ angleB,
4167
+ angleC
4168
+ }) {
4169
+ const Ax = Math.cos(angleA);
4170
+ const Ay = Math.sin(angleA);
4171
+ const Bx = Math.cos(angleB);
4172
+ const By = Math.sin(angleB);
4173
+ const Cx = Math.cos(angleC);
4174
+ const Cy = Math.sin(angleC);
4175
+ const signedArea = (Bx - Ax) * (Cy - Ay) - (By - Ay) * (Cx - Ax);
4176
+ return signedArea < 0 ? "ccw" : "cw";
4177
+ }
4178
+ function computeTurnDirection(A, B, C, bounds) {
4179
+ const angleA = pointToAngle(A, bounds);
4180
+ const angleB = pointToAngle(B, bounds);
4181
+ const angleC = pointToAngle(C, bounds);
4182
+ return triangleDirection({ angleA, angleB, angleC });
4183
+ }
4184
+
4129
4185
  // lib/solvers/HighDensitySolver/TwoRouteHighDensitySolver/SingleTransitionCrossingRouteSolver.ts
4130
4186
  var SingleTransitionCrossingRouteSolver = class extends BaseSolver {
4131
4187
  // Input parameters
@@ -4213,7 +4269,14 @@ var SingleTransitionCrossingRouteSolver = class extends BaseSolver {
4213
4269
  const A = flatRoute.A;
4214
4270
  const B = ntrP1;
4215
4271
  const C = flatRoute.B;
4216
- const sideTraversal = calculateTraversalPercentages(A, B, C, this.bounds);
4272
+ const turnDirection = computeTurnDirection(A, B, C, this.bounds);
4273
+ const sideTraversal = calculateTraversalPercentages(
4274
+ A,
4275
+ B,
4276
+ C,
4277
+ this.bounds,
4278
+ turnDirection
4279
+ );
4217
4280
  const viaBounds = {
4218
4281
  minX: this.bounds.minX + (sideTraversal.left > 0.5 ? marginFromBorderWithTrace : marginFromBorderWithoutTrace),
4219
4282
  minY: this.bounds.minY + (sideTraversal.bottom > 0.5 ? marginFromBorderWithTrace : marginFromBorderWithoutTrace),
@@ -4291,23 +4354,29 @@ var SingleTransitionCrossingRouteSolver = class extends BaseSolver {
4291
4354
  otherRouteStart.z !== flatStart.z ? otherRouteStart : otherRouteEnd,
4292
4355
  this.traceThickness
4293
4356
  );
4294
- const p1 = findPointToGetAroundCircle(flatStart, p2, {
4295
- center: { x: via.x, y: via.y },
4296
- radius: minDistFromViaToTrace
4297
- }).E;
4298
- const p3 = findPointToGetAroundCircle(p2, flatEnd, {
4357
+ const viaCircle = {
4299
4358
  center: { x: via.x, y: via.y },
4300
4359
  radius: minDistFromViaToTrace
4301
- }).E;
4302
- const p1IsNeeded = pointToSegmentDistance(via, flatStart, p2) < minDistFromViaToTrace;
4303
- const p3IsNeeded = pointToSegmentDistance(via, p2, flatEnd) < minDistFromViaToTrace;
4360
+ };
4361
+ const p1 = findPointToGetAroundCircle(flatStart, p2, viaCircle).E;
4362
+ const p3 = findPointToGetAroundCircle(p2, flatEnd, viaCircle).E;
4363
+ const p0_5 = findPointToGetAroundCircle(flatStart, p1, viaCircle).E;
4364
+ const p1_5 = findPointToGetAroundCircle(p1, p2, viaCircle).E;
4365
+ const p2_5 = findPointToGetAroundCircle(p2, p3, viaCircle).E;
4366
+ const p3_5 = findPointToGetAroundCircle(p3, flatEnd, viaCircle).E;
4367
+ const p2_better = findPointToGetAroundCircle(p1_5, p2_5, viaCircle).E;
4304
4368
  return {
4305
4369
  connectionName: flatRouteConnectionName,
4306
4370
  route: [
4307
4371
  { x: flatStart.x, y: flatStart.y, z: flatStart.z ?? 0 },
4308
- ...p1IsNeeded ? [{ x: p1.x, y: p1.y, z: flatStart.z ?? 0 }] : [],
4309
- { x: p2.x, y: p2.y, z: flatStart.z ?? 0 },
4310
- ...p3IsNeeded ? [{ x: p3.x, y: p3.y, z: flatStart.z ?? 0 }] : [],
4372
+ { x: p0_5.x, y: p0_5.y, z: flatStart.z ?? 0 },
4373
+ { x: p1.x, y: p1.y, z: flatStart.z ?? 0 },
4374
+ { x: p1_5.x, y: p1_5.y, z: flatStart.z ?? 0 },
4375
+ // { x: p2.x, y: p2.y, z: flatStart.z ?? 0 },
4376
+ { x: p2_better.x, y: p2_better.y, z: flatStart.z ?? 0 },
4377
+ { x: p2_5.x, y: p2_5.y, z: flatStart.z ?? 0 },
4378
+ { x: p3.x, y: p3.y, z: flatStart.z ?? 0 },
4379
+ { x: p3_5.x, y: p3_5.y, z: flatStart.z ?? 0 },
4311
4380
  { x: flatEnd.x, y: flatEnd.y, z: flatEnd.z ?? 0 }
4312
4381
  ],
4313
4382
  traceThickness: this.traceThickness,
@@ -7926,13 +7995,13 @@ function minimumDistanceBetweenSegments(A1, A2, B1, B2) {
7926
7995
  if (segmentsIntersect(A1, A2, B1, B2)) {
7927
7996
  return 0;
7928
7997
  }
7929
- const distA1 = pointToSegmentDistance4(A1, B1, B2);
7930
- const distA2 = pointToSegmentDistance4(A2, B1, B2);
7931
- const distB1 = pointToSegmentDistance4(B1, A1, A2);
7932
- const distB2 = pointToSegmentDistance4(B2, A1, A2);
7998
+ const distA1 = pointToSegmentDistance5(A1, B1, B2);
7999
+ const distA2 = pointToSegmentDistance5(A2, B1, B2);
8000
+ const distB1 = pointToSegmentDistance5(B1, A1, A2);
8001
+ const distB2 = pointToSegmentDistance5(B2, A1, A2);
7933
8002
  return Math.min(distA1, distA2, distB1, distB2);
7934
8003
  }
7935
- function pointToSegmentDistance4(P, Q1, Q2) {
8004
+ function pointToSegmentDistance5(P, Q1, Q2) {
7936
8005
  const v = { x: Q2.x - Q1.x, y: Q2.y - Q1.y };
7937
8006
  const w = { x: P.x - Q1.x, y: P.y - Q1.y };
7938
8007
  const c1 = dotProduct(w, v);