@tscircuit/capacity-autorouter 0.0.56 → 0.0.57

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
@@ -2945,6 +2945,27 @@ function distance(p1, p2) {
2945
2945
  const dy = p1.y - p2.y;
2946
2946
  return Math.sqrt(dx * dx + dy * dy);
2947
2947
  }
2948
+ function getSegmentIntersection(a, b, u, v) {
2949
+ const dx1 = b.x - a.x;
2950
+ const dy1 = b.y - a.y;
2951
+ const dx2 = v.x - u.x;
2952
+ const dy2 = v.y - u.y;
2953
+ const dx3 = a.x - u.x;
2954
+ const dy3 = a.y - u.y;
2955
+ const denominator = dx1 * dy2 - dy1 * dx2;
2956
+ if (Math.abs(denominator) < 1e-10) {
2957
+ return null;
2958
+ }
2959
+ const t = (dy3 * dx2 - dx3 * dy2) / denominator;
2960
+ const s = (dx1 * dy3 - dy1 * dx3) / denominator;
2961
+ const epsilon = 1e-9;
2962
+ if (t >= -epsilon && t <= 1 + epsilon && s >= -epsilon && s <= 1 + epsilon) {
2963
+ const intersectionX = a.x + t * dx1;
2964
+ const intersectionY = a.y + t * dy1;
2965
+ return { x: intersectionX, y: intersectionY };
2966
+ }
2967
+ return null;
2968
+ }
2948
2969
 
2949
2970
  // node_modules/@tscircuit/math-utils/dist/chunk-MHHTZHOJ.js
2950
2971
  function getBoundingBox(box) {
@@ -3057,6 +3078,14 @@ function pointToSegmentClosestPoint(p, a, b) {
3057
3078
  return closestPoint;
3058
3079
  }
3059
3080
 
3081
+ // node_modules/@tscircuit/math-utils/dist/chunk-SLG2OU3P.js
3082
+ function midpoint(p1, p2) {
3083
+ return {
3084
+ x: (p1.x + p2.x) / 2,
3085
+ y: (p1.y + p2.y) / 2
3086
+ };
3087
+ }
3088
+
3060
3089
  // lib/data-structures/SingleRouteCandidatePriorityQueue.ts
3061
3090
  var SingleRouteCandidatePriorityQueue = class {
3062
3091
  heap = [];
@@ -6140,6 +6169,23 @@ var SingleTransitionCrossingRouteSolver = class extends BaseSolver {
6140
6169
  }
6141
6170
  };
6142
6171
 
6172
+ // lib/utils/getPortPairs.ts
6173
+ var getPortPairMap = (nodeWithPortPoints) => {
6174
+ const portPairMap = /* @__PURE__ */ new Map();
6175
+ nodeWithPortPoints.portPoints.forEach((portPoint) => {
6176
+ if (!portPairMap.has(portPoint.connectionName)) {
6177
+ portPairMap.set(portPoint.connectionName, {
6178
+ start: portPoint,
6179
+ end: null,
6180
+ connectionName: portPoint.connectionName
6181
+ });
6182
+ } else {
6183
+ portPairMap.get(portPoint.connectionName).end = portPoint;
6184
+ }
6185
+ });
6186
+ return portPairMap;
6187
+ };
6188
+
6143
6189
  // lib/utils/generateColorMapFromNodeWithPortPoints.ts
6144
6190
  var generateColorMapFromNodeWithPortPoints = (nodeWithPortPoints, connMap) => {
6145
6191
  const colorMap = {};
@@ -6149,6 +6195,320 @@ var generateColorMapFromNodeWithPortPoints = (nodeWithPortPoints, connMap) => {
6149
6195
  return colorMap;
6150
6196
  };
6151
6197
 
6198
+ // lib/solvers/ViaPossibilitiesSolver/ViaPossibilitiesSolver2.ts
6199
+ var ViaPossibilitiesSolver2 = class extends BaseSolver {
6200
+ bounds;
6201
+ maxViaCount;
6202
+ portPairMap;
6203
+ colorMap;
6204
+ nodeWidth;
6205
+ availableZ;
6206
+ hyperParameters;
6207
+ VIA_INTERSECTION_BUFFER_DISTANCE = 0.05;
6208
+ PLACEHOLDER_WALL_BUFFER_DISTANCE = 0.1;
6209
+ NEW_HEAD_WALL_BUFFER_DISTANCE = 0.05;
6210
+ unprocessedConnections;
6211
+ completedPaths = /* @__PURE__ */ new Map();
6212
+ placeholderPaths = /* @__PURE__ */ new Map();
6213
+ currentHead;
6214
+ currentConnectionName;
6215
+ currentPath;
6216
+ constructor({
6217
+ nodeWithPortPoints,
6218
+ colorMap,
6219
+ hyperParameters
6220
+ }) {
6221
+ super();
6222
+ this.MAX_ITERATIONS = 1e5;
6223
+ this.colorMap = colorMap ?? generateColorMapFromNodeWithPortPoints(nodeWithPortPoints);
6224
+ this.maxViaCount = 5;
6225
+ this.bounds = getBoundsFromNodeWithPortPoints(nodeWithPortPoints);
6226
+ this.nodeWidth = this.bounds.maxX - this.bounds.minX;
6227
+ this.portPairMap = getPortPairMap(nodeWithPortPoints);
6228
+ this.stats.solutionsFound = 0;
6229
+ this.availableZ = nodeWithPortPoints.availableZ ?? [0, 1];
6230
+ this.hyperParameters = hyperParameters ?? {
6231
+ SHUFFLE_SEED: 0
6232
+ };
6233
+ this.unprocessedConnections = Array.from(this.portPairMap.keys()).sort();
6234
+ if (hyperParameters?.SHUFFLE_SEED) {
6235
+ this.unprocessedConnections = cloneAndShuffleArray(
6236
+ this.unprocessedConnections,
6237
+ hyperParameters.SHUFFLE_SEED
6238
+ );
6239
+ }
6240
+ const nodeCenterX = (this.bounds.minX + this.bounds.maxX) / 2;
6241
+ const nodeCenterY = (this.bounds.minY + this.bounds.maxY) / 2;
6242
+ for (const [connectionName, { start: start2, end }] of this.portPairMap.entries()) {
6243
+ if (start2.z === end.z) {
6244
+ const isVertical = Math.abs(start2.x - end.x) < 1e-9;
6245
+ const isHorizontal = Math.abs(start2.y - end.y) < 1e-9;
6246
+ if (isVertical || isHorizontal) {
6247
+ this.placeholderPaths.set(connectionName, [
6248
+ start2,
6249
+ this._padByPlaceholderWallBuffer(start2),
6250
+ this._padByPlaceholderWallBuffer(end),
6251
+ end
6252
+ ]);
6253
+ } else {
6254
+ this.placeholderPaths.set(connectionName, [start2, end]);
6255
+ }
6256
+ } else {
6257
+ const midX = (start2.x + end.x) / 2;
6258
+ const midY = (start2.y + end.y) / 2;
6259
+ const midStart = this._padByPlaceholderWallBuffer({
6260
+ x: midX,
6261
+ y: midY,
6262
+ z: start2.z
6263
+ });
6264
+ const midEnd = this._padByPlaceholderWallBuffer({
6265
+ x: midX,
6266
+ y: midY,
6267
+ z: end.z
6268
+ });
6269
+ this.placeholderPaths.set(connectionName, [
6270
+ start2,
6271
+ this._padByPlaceholderWallBuffer(start2),
6272
+ midStart,
6273
+ midEnd,
6274
+ this._padByPlaceholderWallBuffer(end),
6275
+ end
6276
+ ]);
6277
+ }
6278
+ }
6279
+ this.currentConnectionName = this.unprocessedConnections.pop();
6280
+ const start = this.portPairMap.get(this.currentConnectionName).start;
6281
+ this.currentHead = this._padByNewHeadWallBuffer(start);
6282
+ this.currentPath = [start, this.currentHead];
6283
+ this.placeholderPaths.delete(this.currentConnectionName);
6284
+ }
6285
+ _padByNewHeadWallBuffer(point) {
6286
+ return {
6287
+ x: clamp(
6288
+ point.x,
6289
+ this.bounds.minX + this.NEW_HEAD_WALL_BUFFER_DISTANCE,
6290
+ this.bounds.maxX - this.NEW_HEAD_WALL_BUFFER_DISTANCE
6291
+ ),
6292
+ y: clamp(
6293
+ point.y,
6294
+ this.bounds.minY + this.NEW_HEAD_WALL_BUFFER_DISTANCE,
6295
+ this.bounds.maxY - this.NEW_HEAD_WALL_BUFFER_DISTANCE
6296
+ ),
6297
+ z: point.z
6298
+ };
6299
+ }
6300
+ _padByPlaceholderWallBuffer(point) {
6301
+ return {
6302
+ x: clamp(
6303
+ point.x,
6304
+ this.bounds.minX + this.PLACEHOLDER_WALL_BUFFER_DISTANCE,
6305
+ this.bounds.maxX - this.PLACEHOLDER_WALL_BUFFER_DISTANCE
6306
+ ),
6307
+ y: clamp(
6308
+ point.y,
6309
+ this.bounds.minY + this.PLACEHOLDER_WALL_BUFFER_DISTANCE,
6310
+ this.bounds.maxY - this.PLACEHOLDER_WALL_BUFFER_DISTANCE
6311
+ ),
6312
+ z: point.z
6313
+ };
6314
+ }
6315
+ _step() {
6316
+ if (this.solved) return;
6317
+ const targetEnd = this.portPairMap.get(this.currentConnectionName).end;
6318
+ const proposedSegment = [this.currentHead, targetEnd];
6319
+ let closestIntersection = null;
6320
+ let intersectedSegmentZ = null;
6321
+ const checkIntersectionsWithPathMap = (pathMap) => {
6322
+ for (const path of pathMap.values()) {
6323
+ for (let i = 0; i < path.length - 1; i++) {
6324
+ const segment = [path[i], path[i + 1]];
6325
+ if (segment[0].x === segment[1].x && segment[0].y === segment[1].y) {
6326
+ continue;
6327
+ }
6328
+ if (segment[0].z !== this.currentHead.z) {
6329
+ continue;
6330
+ }
6331
+ const intersection = getSegmentIntersection(
6332
+ proposedSegment[0],
6333
+ proposedSegment[1],
6334
+ segment[0],
6335
+ segment[1]
6336
+ );
6337
+ if (intersection) {
6338
+ const distToIntersection = distance(this.currentHead, intersection);
6339
+ if (distToIntersection < 1e-6) continue;
6340
+ if (!closestIntersection || distToIntersection < closestIntersection.dist) {
6341
+ closestIntersection = {
6342
+ point: intersection,
6343
+ dist: distToIntersection
6344
+ };
6345
+ intersectedSegmentZ = segment[0].z;
6346
+ }
6347
+ }
6348
+ }
6349
+ }
6350
+ };
6351
+ checkIntersectionsWithPathMap(this.completedPaths);
6352
+ checkIntersectionsWithPathMap(this.placeholderPaths);
6353
+ const needsZChange = this.currentHead.z !== targetEnd.z;
6354
+ if (closestIntersection) {
6355
+ let viaXY;
6356
+ const distToIntersection = closestIntersection.dist;
6357
+ if (distToIntersection < this.VIA_INTERSECTION_BUFFER_DISTANCE) {
6358
+ viaXY = midpoint(this.currentHead, closestIntersection.point);
6359
+ } else {
6360
+ const intersectionPoint = closestIntersection.point;
6361
+ const vectorX = intersectionPoint.x - this.currentHead.x;
6362
+ const vectorY = intersectionPoint.y - this.currentHead.y;
6363
+ const ratio = (distToIntersection - this.VIA_INTERSECTION_BUFFER_DISTANCE) / distToIntersection;
6364
+ viaXY = {
6365
+ x: this.currentHead.x + vectorX * ratio,
6366
+ y: this.currentHead.y + vectorY * ratio
6367
+ };
6368
+ }
6369
+ const nextZ = this.availableZ.find((z) => z !== intersectedSegmentZ);
6370
+ if (nextZ === void 0) {
6371
+ console.error("Could not determine next Z level for via placement!");
6372
+ this.failed = true;
6373
+ return;
6374
+ }
6375
+ const viaPoint1 = { ...viaXY, z: this.currentHead.z };
6376
+ const viaPoint2 = { ...viaXY, z: nextZ };
6377
+ this.currentPath.push(viaPoint1, viaPoint2);
6378
+ this.currentHead = viaPoint2;
6379
+ } else if (needsZChange) {
6380
+ let viaXY;
6381
+ const distToTarget = distance(this.currentHead, targetEnd);
6382
+ if (distToTarget < this.VIA_INTERSECTION_BUFFER_DISTANCE) {
6383
+ viaXY = midpoint(this.currentHead, targetEnd);
6384
+ } else {
6385
+ const vectorX = targetEnd.x - this.currentHead.x;
6386
+ const vectorY = targetEnd.y - this.currentHead.y;
6387
+ const ratio = (distToTarget - this.VIA_INTERSECTION_BUFFER_DISTANCE) / distToTarget;
6388
+ viaXY = {
6389
+ x: this.currentHead.x + vectorX * ratio,
6390
+ y: this.currentHead.y + vectorY * ratio
6391
+ };
6392
+ }
6393
+ const nextZ = targetEnd.z;
6394
+ const viaPoint1 = { ...viaXY, z: this.currentHead.z };
6395
+ const viaPoint2 = { ...viaXY, z: nextZ };
6396
+ this.currentPath.push(viaPoint1, viaPoint2);
6397
+ this.currentHead = viaPoint2;
6398
+ } else {
6399
+ this.currentPath.push(targetEnd);
6400
+ this.completedPaths.set(this.currentConnectionName, this.currentPath);
6401
+ if (this.unprocessedConnections.length === 0) {
6402
+ this.solved = true;
6403
+ this.stats.solutionsFound = 1;
6404
+ } else {
6405
+ this.currentConnectionName = this.unprocessedConnections.pop();
6406
+ const { start } = this.portPairMap.get(this.currentConnectionName);
6407
+ this.currentHead = this._padByNewHeadWallBuffer(start);
6408
+ this.currentPath = [start, this.currentHead];
6409
+ this.placeholderPaths.delete(this.currentConnectionName);
6410
+ }
6411
+ }
6412
+ }
6413
+ visualize() {
6414
+ const graphics = {
6415
+ points: [],
6416
+ lines: [],
6417
+ circles: [],
6418
+ rects: [],
6419
+ title: "Via Possibilities Solver State",
6420
+ coordinateSystem: "cartesian"
6421
+ };
6422
+ const colorMap = this.colorMap;
6423
+ graphics.lines.push({
6424
+ points: [
6425
+ { x: this.bounds.minX, y: this.bounds.minY },
6426
+ { x: this.bounds.maxX, y: this.bounds.minY },
6427
+ { x: this.bounds.maxX, y: this.bounds.maxY },
6428
+ { x: this.bounds.minX, y: this.bounds.maxY },
6429
+ { x: this.bounds.minX, y: this.bounds.minY }
6430
+ ],
6431
+ strokeColor: "gray",
6432
+ strokeWidth: 0.01
6433
+ });
6434
+ for (const [connectionName, { start, end }] of this.portPairMap.entries()) {
6435
+ const color = this.colorMap[connectionName] ?? "black";
6436
+ graphics.points.push({
6437
+ x: start.x,
6438
+ y: start.y,
6439
+ color,
6440
+ label: `Port: ${connectionName} Start (z${start.z})`
6441
+ });
6442
+ graphics.points.push({
6443
+ x: end.x,
6444
+ y: end.y,
6445
+ color,
6446
+ label: `Port: ${connectionName} End (z${end.z})`
6447
+ });
6448
+ }
6449
+ const drawPath = (pathMap, labelPrefix) => {
6450
+ for (const [connectionName, path] of pathMap.entries()) {
6451
+ const color = colorMap[connectionName] ?? "black";
6452
+ for (let i = 0; i < path.length - 1; i++) {
6453
+ const p1 = path[i];
6454
+ const p2 = path[i + 1];
6455
+ if (p1.x === p2.x && p1.y === p2.y && p1.z !== p2.z) {
6456
+ graphics.circles.push({
6457
+ center: { x: p1.x, y: p1.y },
6458
+ radius: 0.3,
6459
+ // Diameter 0.6
6460
+ fill: safeTransparentize(color, 0.5),
6461
+ label: `${labelPrefix}: ${connectionName} Via (z${p1.z}->z${p2.z})`
6462
+ });
6463
+ } else {
6464
+ graphics.lines.push({
6465
+ points: [p1, p2],
6466
+ strokeColor: safeTransparentize(color, 0.5),
6467
+ strokeDash: p1.z === 0 ? void 0 : [0.1, 0.1],
6468
+ strokeWidth: 0.1,
6469
+ label: `${labelPrefix}: ${connectionName} (z${p1.z})`
6470
+ });
6471
+ }
6472
+ }
6473
+ }
6474
+ };
6475
+ drawPath(this.placeholderPaths, "Placeholder");
6476
+ drawPath(this.completedPaths, "Completed");
6477
+ if (this.currentPath && this.currentPath.length > 0) {
6478
+ const color = colorMap[this.currentConnectionName] ?? "orange";
6479
+ for (let i = 0; i < this.currentPath.length - 1; i++) {
6480
+ const p1 = this.currentPath[i];
6481
+ const p2 = this.currentPath[i + 1];
6482
+ if (p1.x === p2.x && p1.y === p2.y && p1.z !== p2.z) {
6483
+ graphics.circles.push({
6484
+ center: { x: p1.x, y: p1.y },
6485
+ radius: 0.3,
6486
+ fill: safeTransparentize(color, 0.5),
6487
+ label: `Current: ${this.currentConnectionName} Via (z${p1.z}->z${p2.z})`
6488
+ });
6489
+ } else {
6490
+ graphics.lines.push({
6491
+ points: [p1, p2],
6492
+ strokeColor: safeTransparentize(color, 0.5),
6493
+ strokeWidth: 0.15,
6494
+ // Thicker
6495
+ strokeDash: "2,2",
6496
+ // Dashed
6497
+ label: `Current: ${this.currentConnectionName} (z${p1.z})`
6498
+ });
6499
+ }
6500
+ }
6501
+ graphics.points.push({
6502
+ x: this.currentHead.x,
6503
+ y: this.currentHead.y,
6504
+ color: "green",
6505
+ label: `Current Head: ${this.currentConnectionName} (z${this.currentHead.z})`
6506
+ });
6507
+ }
6508
+ return graphics;
6509
+ }
6510
+ };
6511
+
6152
6512
  // lib/utils/getIntraNodeCrossings.ts
6153
6513
  var getIntraNodeCrossings = (node) => {
6154
6514
  let numSameLayerCrossings = 0;
@@ -8277,6 +8637,191 @@ var MultiHeadPolyLineIntraNodeSolver2 = class extends MultiHeadPolyLineIntraNode
8277
8637
  }
8278
8638
  };
8279
8639
 
8640
+ // lib/solvers/HighDensitySolver/MultiHeadPolyLineIntraNodeSolver/MultiHeadPolyLineIntraNodeSolver3_ViaPossibilitiesSolverIntegration.ts
8641
+ var hashPolyLines = (polyLines) => {
8642
+ return polyLines.flatMap(
8643
+ (pl) => `${pl.connectionName}-${pl.mPoints.map((mp) => `${mp.x.toFixed(2)},${mp.y.toFixed(2)},${mp.z1},${mp.z2}`)}`
8644
+ ).sort().join("|");
8645
+ };
8646
+ function factorial(n) {
8647
+ if (!Number.isInteger(n) || n < 0) {
8648
+ throw new RangeError("n must be a non-negative integer");
8649
+ }
8650
+ let result = 1;
8651
+ for (let i = 2; i <= n; i++) {
8652
+ result *= i;
8653
+ }
8654
+ return result;
8655
+ }
8656
+ var MultiHeadPolyLineIntraNodeSolver3 = class extends MultiHeadPolyLineIntraNodeSolver2 {
8657
+ constructor(params) {
8658
+ super(params);
8659
+ this.MAX_ITERATIONS = 1e3;
8660
+ }
8661
+ createInitialCandidateFromSeed(shuffleSeed) {
8662
+ const viaSolver = new ViaPossibilitiesSolver2({
8663
+ nodeWithPortPoints: this.nodeWithPortPoints,
8664
+ colorMap: this.colorMap,
8665
+ // Pass relevant hyperparameters if needed, e.g., shuffle seed
8666
+ hyperParameters: {
8667
+ SHUFFLE_SEED: shuffleSeed
8668
+ }
8669
+ });
8670
+ viaSolver.solve();
8671
+ if (viaSolver.failed || !viaSolver.solved) {
8672
+ this.failed = true;
8673
+ this.error = viaSolver.error ?? "ViaPossibilitiesSolver2 failed to find a solution.";
8674
+ console.error(this.error);
8675
+ return null;
8676
+ }
8677
+ const polyLines = [];
8678
+ let totalViaCount = 0;
8679
+ for (const [
8680
+ connectionName,
8681
+ pathPoints
8682
+ ] of viaSolver.completedPaths.entries()) {
8683
+ if (pathPoints.length < 2) {
8684
+ console.warn(
8685
+ `Skipping connection "${connectionName}" due to insufficient points (${pathPoints.length}) in ViaPossibilitiesSolver2 path.`
8686
+ );
8687
+ continue;
8688
+ }
8689
+ const startPoint = pathPoints[0];
8690
+ const endPoint = pathPoints[pathPoints.length - 1];
8691
+ const middlePointsRaw = pathPoints.slice(1, -1);
8692
+ const mPoints = [];
8693
+ let currentViaCount = 0;
8694
+ let lastZ = startPoint.z;
8695
+ for (let i = 0; i < middlePointsRaw.length; i++) {
8696
+ const currentRawPoint = middlePointsRaw[i];
8697
+ const nextRawPoint = i + 1 < middlePointsRaw.length ? middlePointsRaw[i + 1] : endPoint;
8698
+ const isViaStart = i + 1 < middlePointsRaw.length && currentRawPoint.x === nextRawPoint.x && currentRawPoint.y === nextRawPoint.y && currentRawPoint.z !== nextRawPoint.z;
8699
+ const z1 = lastZ;
8700
+ const z2 = isViaStart ? nextRawPoint.z : currentRawPoint.z;
8701
+ mPoints.push({
8702
+ x: currentRawPoint.x,
8703
+ y: currentRawPoint.y,
8704
+ z1,
8705
+ z2
8706
+ });
8707
+ if (z1 !== z2) {
8708
+ currentViaCount++;
8709
+ i++;
8710
+ lastZ = z2;
8711
+ } else {
8712
+ lastZ = currentRawPoint.z;
8713
+ }
8714
+ }
8715
+ totalViaCount += currentViaCount;
8716
+ const targetSegmentCount = this.SEGMENTS_PER_POLYLINE;
8717
+ let currentSegments = mPoints.length + 1;
8718
+ while (currentSegments < targetSegmentCount) {
8719
+ let longestSegmentLength = -1;
8720
+ let longestSegmentIndex = -1;
8721
+ let p1 = null;
8722
+ let p2 = null;
8723
+ const fullPathPoints = [
8724
+ {
8725
+ ...startPoint,
8726
+ z1: startPoint.z,
8727
+ z2: startPoint.z,
8728
+ connectionName
8729
+ },
8730
+ ...mPoints,
8731
+ { ...endPoint, z1: endPoint.z, z2: endPoint.z, connectionName }
8732
+ ];
8733
+ for (let k = 0; k < fullPathPoints.length - 1; k++) {
8734
+ const segP1 = fullPathPoints[k];
8735
+ const segP2 = fullPathPoints[k + 1];
8736
+ if (segP1.x === segP2.x && segP1.y === segP2.y) {
8737
+ continue;
8738
+ }
8739
+ const len = distance(segP1, segP2);
8740
+ if (len > longestSegmentLength) {
8741
+ longestSegmentLength = len;
8742
+ longestSegmentIndex = k;
8743
+ p1 = segP1;
8744
+ p2 = segP2;
8745
+ }
8746
+ }
8747
+ if (longestSegmentIndex === -1 || !p1 || !p2) {
8748
+ console.warn(
8749
+ `Could not find longest segment for ${connectionName} while trying to reach ${targetSegmentCount} segments.`
8750
+ );
8751
+ break;
8752
+ }
8753
+ const midX = (p1.x + p2.x) / 2;
8754
+ const midY = (p1.y + p2.y) / 2;
8755
+ const segmentZ = p1.z2;
8756
+ const newMPoint = {
8757
+ x: midX,
8758
+ y: midY,
8759
+ z1: segmentZ,
8760
+ // New point is on the same layer
8761
+ z2: segmentZ
8762
+ };
8763
+ mPoints.splice(longestSegmentIndex, 0, newMPoint);
8764
+ currentSegments++;
8765
+ }
8766
+ polyLines.push({
8767
+ connectionName,
8768
+ start: {
8769
+ // Use original start/end points from ViaSolver
8770
+ ...startPoint,
8771
+ z1: startPoint.z,
8772
+ z2: startPoint.z
8773
+ // Start point is not a via itself
8774
+ },
8775
+ end: {
8776
+ ...endPoint,
8777
+ z1: endPoint.z,
8778
+ // End point uses its own Z as z1
8779
+ z2: endPoint.z
8780
+ // End point is not a via itself
8781
+ },
8782
+ mPoints
8783
+ });
8784
+ }
8785
+ if (polyLines.length === 0) {
8786
+ this.failed = true;
8787
+ this.error = "No valid polylines generated from ViaPossibilitiesSolver2.";
8788
+ console.error(this.error);
8789
+ return null;
8790
+ }
8791
+ const minGaps = this.computeMinGapBtwPolyLines(polyLines);
8792
+ const h = this.computeH({ minGaps, forces: [] });
8793
+ const initialCandidate = {
8794
+ polyLines,
8795
+ g: 0,
8796
+ h,
8797
+ f: 0 + h,
8798
+ // f = g + h
8799
+ viaCount: totalViaCount,
8800
+ minGaps
8801
+ };
8802
+ initialCandidate.g = this.computeG(polyLines, initialCandidate);
8803
+ initialCandidate.f = initialCandidate.g + initialCandidate.h;
8804
+ return initialCandidate;
8805
+ }
8806
+ setupInitialPolyLines() {
8807
+ this.candidates = [];
8808
+ const maxCandidatesToGenerate = Math.min(
8809
+ 2e3,
8810
+ factorial(this.uniqueConnections)
8811
+ );
8812
+ const candidatePolylineHashes = /* @__PURE__ */ new Set();
8813
+ for (let i = 0; i < maxCandidatesToGenerate; i++) {
8814
+ const newCandidate = this.createInitialCandidateFromSeed(i);
8815
+ if (!newCandidate) continue;
8816
+ const newCandidatePolylineHash = hashPolyLines(newCandidate.polyLines);
8817
+ if (candidatePolylineHashes.has(newCandidatePolylineHash)) continue;
8818
+ candidatePolylineHashes.add(newCandidatePolylineHash);
8819
+ this.candidates.push(newCandidate);
8820
+ }
8821
+ this.candidates.sort((a, b) => a.f - b.f);
8822
+ }
8823
+ };
8824
+
8280
8825
  // lib/solvers/HyperHighDensitySolver/HyperSingleIntraNodeSolver.ts
8281
8826
  var HyperSingleIntraNodeSolver = class extends HyperParameterSupervisorSolver {
8282
8827
  constructorParams;
@@ -8399,11 +8944,7 @@ var HyperSingleIntraNodeSolver = class extends HyperParameterSupervisorSolver {
8399
8944
  possibleValues: [
8400
8945
  {
8401
8946
  MULTI_HEAD_POLYLINE_SOLVER: true,
8402
- SEGMENTS_PER_POLYLINE: 3
8403
- },
8404
- {
8405
- MULTI_HEAD_POLYLINE_SOLVER: true,
8406
- SEGMENTS_PER_POLYLINE: 4
8947
+ SEGMENTS_PER_POLYLINE: 6
8407
8948
  }
8408
8949
  ]
8409
8950
  }
@@ -8430,7 +8971,7 @@ var HyperSingleIntraNodeSolver = class extends HyperParameterSupervisorSolver {
8430
8971
  });
8431
8972
  }
8432
8973
  if (hyperParameters.MULTI_HEAD_POLYLINE_SOLVER) {
8433
- return new MultiHeadPolyLineIntraNodeSolver2({
8974
+ return new MultiHeadPolyLineIntraNodeSolver3({
8434
8975
  nodeWithPortPoints: this.nodeWithPortPoints,
8435
8976
  hyperParameters
8436
8977
  });
@@ -8551,6 +9092,7 @@ var HighDensitySolver = class extends BaseSolver {
8551
9092
  points: segment.points,
8552
9093
  label: segment.connectionName,
8553
9094
  strokeColor: segment.z === 0 ? segment.color : safeTransparentize(segment.color, 0.75),
9095
+ layer: `z${segment.z}`,
8554
9096
  strokeWidth: route.traceThickness,
8555
9097
  strokeDash: segment.z !== 0 ? "10, 5" : void 0
8556
9098
  });
@@ -8558,6 +9100,7 @@ var HighDensitySolver = class extends BaseSolver {
8558
9100
  for (const via of route.vias) {
8559
9101
  graphics.circles.push({
8560
9102
  center: via,
9103
+ layer: "z0,1",
8561
9104
  radius: route.viaDiameter / 2,
8562
9105
  fill: this.colorMap[route.connectionName],
8563
9106
  label: `${route.connectionName} via`
@@ -8573,6 +9116,7 @@ var HighDensitySolver = class extends BaseSolver {
8573
9116
  x: node.center.x - rectWidth / 2,
8574
9117
  y: node.center.y - rectHeight / 2
8575
9118
  },
9119
+ layer: "did_not_connect",
8576
9120
  width: rectWidth,
8577
9121
  height: rectHeight,
8578
9122
  fill: "red",
@@ -11993,11 +12537,16 @@ var CapacityPathingMultiSectionSolver = class extends BaseSolver {
11993
12537
  nodeOptimizationAttemptCountMap = /* @__PURE__ */ new Map();
11994
12538
  currentSection = null;
11995
12539
  sectionSolver = null;
11996
- MAX_ATTEMPTS_PER_NODE = 10;
12540
+ MAX_ATTEMPTS_PER_NODE = 1;
11997
12541
  MINIMUM_PROBABILITY_OF_FAILURE_TO_OPTIMIZE = 0.05;
11998
- MAX_EXPANSION_DEGREES = 3;
12542
+ MAX_EXPANSION_DEGREES = 5;
12543
+ stats;
11999
12544
  constructor(params) {
12000
12545
  super();
12546
+ this.stats = {
12547
+ successfulOptimizations: 0,
12548
+ failedOptimizations: 0
12549
+ };
12001
12550
  this.MAX_ITERATIONS = 1e7;
12002
12551
  this.simpleRouteJson = params.simpleRouteJson;
12003
12552
  this.nodes = params.nodes;
@@ -12007,7 +12556,7 @@ var CapacityPathingMultiSectionSolver = class extends BaseSolver {
12007
12556
  this.nodes.map((node) => [node.capacityMeshNodeId, node])
12008
12557
  );
12009
12558
  this.nodeEdgeMap = getNodeEdgeMap(this.edges);
12010
- this.initialSolver = new CapacityPathingGreedySolver({
12559
+ this.initialSolver = params.initialPathingSolver || new CapacityPathingGreedySolver({
12011
12560
  simpleRouteJson: this.simpleRouteJson,
12012
12561
  nodes: this.nodes,
12013
12562
  edges: this.edges,
@@ -12160,9 +12709,11 @@ var CapacityPathingMultiSectionSolver = class extends BaseSolver {
12160
12709
  sectionNodeIds
12161
12710
  });
12162
12711
  if (afterScore > beforeScore) {
12712
+ this.stats.successfulOptimizations++;
12163
12713
  this._mergeSolvedSectionPaths(solvedSectionSolver);
12164
12714
  this._recalculateNodeCapacityUsage();
12165
12715
  } else {
12716
+ this.stats.failedOptimizations++;
12166
12717
  }
12167
12718
  }
12168
12719
  }
@@ -13038,13 +13589,13 @@ function minimumDistanceBetweenSegments(A1, A2, B1, B2) {
13038
13589
  if (segmentsIntersect(A1, A2, B1, B2)) {
13039
13590
  return 0;
13040
13591
  }
13041
- const distA1 = pointToSegmentDistance5(A1, B1, B2);
13042
- const distA2 = pointToSegmentDistance5(A2, B1, B2);
13043
- const distB1 = pointToSegmentDistance5(B1, A1, A2);
13044
- const distB2 = pointToSegmentDistance5(B2, A1, A2);
13592
+ const distA1 = pointToSegmentDistance6(A1, B1, B2);
13593
+ const distA2 = pointToSegmentDistance6(A2, B1, B2);
13594
+ const distB1 = pointToSegmentDistance6(B1, A1, A2);
13595
+ const distB2 = pointToSegmentDistance6(B2, A1, A2);
13045
13596
  return Math.min(distA1, distA2, distB1, distB2);
13046
13597
  }
13047
- function pointToSegmentDistance5(P, Q1, Q2) {
13598
+ function pointToSegmentDistance6(P, Q1, Q2) {
13048
13599
  const v = { x: Q2.x - Q1.x, y: Q2.y - Q1.y };
13049
13600
  const w = { x: P.x - Q1.x, y: P.y - Q1.y };
13050
13601
  const c1 = dotProduct(w, v);
@@ -14546,8 +15097,8 @@ var AutoroutingPipelineSolver = class extends BaseSolver {
14546
15097
  nodeSolver;
14547
15098
  nodeTargetMerger;
14548
15099
  edgeSolver;
14549
- pathingSolver;
14550
- // Updated type
15100
+ initialPathingSolver;
15101
+ pathingOptimizer;
14551
15102
  edgeToPortSegmentSolver;
14552
15103
  colorMap;
14553
15104
  segmentToPointSolver;
@@ -14634,12 +15185,28 @@ var AutoroutingPipelineSolver = class extends BaseSolver {
14634
15185
  (cms) => [cms.capacityNodes]
14635
15186
  ),
14636
15187
  definePipelineStep(
14637
- "pathingSolver",
15188
+ "initialPathingSolver",
15189
+ CapacityPathingGreedySolver,
15190
+ (cms) => [
15191
+ {
15192
+ simpleRouteJson: cms.srjWithPointPairs,
15193
+ nodes: cms.capacityNodes,
15194
+ edges: cms.edgeSolver?.edges || [],
15195
+ colorMap: cms.colorMap,
15196
+ hyperParameters: {
15197
+ MAX_CAPACITY_FACTOR: 1
15198
+ }
15199
+ }
15200
+ ]
15201
+ ),
15202
+ definePipelineStep(
15203
+ "pathingOptimizer",
14638
15204
  // CapacityPathingSolver5,
14639
15205
  CapacityPathingMultiSectionSolver,
14640
15206
  (cms) => [
14641
15207
  // Replaced solver class
14642
15208
  {
15209
+ initialPathingSolver: cms.initialPathingSolver,
14643
15210
  simpleRouteJson: cms.srjWithPointPairs,
14644
15211
  nodes: cms.capacityNodes,
14645
15212
  edges: cms.edgeSolver?.edges || [],
@@ -14657,7 +15224,7 @@ var AutoroutingPipelineSolver = class extends BaseSolver {
14657
15224
  {
14658
15225
  nodes: cms.capacityNodes,
14659
15226
  edges: cms.edgeSolver?.edges || [],
14660
- capacityPaths: cms.pathingSolver?.getCapacityPaths() || [],
15227
+ capacityPaths: cms.pathingOptimizer?.getCapacityPaths() || [],
14661
15228
  colorMap: cms.colorMap
14662
15229
  }
14663
15230
  ]
@@ -14816,7 +15383,8 @@ var AutoroutingPipelineSolver = class extends BaseSolver {
14816
15383
  const singleLayerNodeMergerViz = this.singleLayerNodeMerger?.visualize();
14817
15384
  const strawSolverViz = this.strawSolver?.visualize();
14818
15385
  const edgeViz = this.edgeSolver?.visualize();
14819
- const pathingViz = this.pathingSolver?.visualize();
15386
+ const initialPathingViz = this.initialPathingSolver?.visualize();
15387
+ const pathingOptimizerViz = this.pathingOptimizer?.visualize();
14820
15388
  const edgeToPortSegmentViz = this.edgeToPortSegmentSolver?.visualize();
14821
15389
  const segmentToPointViz = this.segmentToPointSolver?.visualize();
14822
15390
  const segmentOptimizationViz = this.unravelMultiSectionSolver?.visualize() ?? this.segmentToPointOptimizer?.visualize();
@@ -14871,7 +15439,8 @@ var AutoroutingPipelineSolver = class extends BaseSolver {
14871
15439
  singleLayerNodeMergerViz,
14872
15440
  strawSolverViz,
14873
15441
  edgeViz,
14874
- pathingViz,
15442
+ initialPathingViz,
15443
+ pathingOptimizerViz,
14875
15444
  edgeToPortSegmentViz,
14876
15445
  segmentToPointViz,
14877
15446
  segmentOptimizationViz,
@@ -14913,9 +15482,9 @@ var AutoroutingPipelineSolver = class extends BaseSolver {
14913
15482
  }
14914
15483
  return { lines };
14915
15484
  }
14916
- if (this.pathingSolver) {
15485
+ if (this.pathingOptimizer) {
14917
15486
  const lines = [];
14918
- for (const connection of this.pathingSolver.connectionsWithNodes) {
15487
+ for (const connection of this.pathingOptimizer.connectionsWithNodes) {
14919
15488
  if (!connection.path) continue;
14920
15489
  lines.push({
14921
15490
  points: connection.path.map((n) => ({