@tscircuit/capacity-autorouter 0.0.56 → 0.0.58

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",
@@ -11530,7 +12074,7 @@ var CapacityPathingSingleSectionSolver = class extends BaseSolver {
11530
12074
  this.nodeMap = new Map(
11531
12075
  this.sectionNodes.map((n) => [n.capacityMeshNodeId, n])
11532
12076
  );
11533
- this.nodeEdgeMap = getNodeEdgeMap(this.sectionEdges);
12077
+ this.nodeEdgeMap = params.nodeEdgeMap ?? getNodeEdgeMap(this.sectionEdges);
11534
12078
  this.colorMap = params.colorMap ?? {};
11535
12079
  this.usedNodeCapacityMap = new Map(
11536
12080
  this.sectionNodes.map((node) => [node.capacityMeshNodeId, 0])
@@ -11993,21 +12537,27 @@ 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;
12004
12553
  this.edges = params.edges;
12554
+ this.nodeEdgeMap = getNodeEdgeMap(this.edges);
12005
12555
  this.colorMap = params.colorMap ?? {};
12006
12556
  this.nodeMap = new Map(
12007
12557
  this.nodes.map((node) => [node.capacityMeshNodeId, node])
12008
12558
  );
12009
12559
  this.nodeEdgeMap = getNodeEdgeMap(this.edges);
12010
- this.initialSolver = new CapacityPathingGreedySolver({
12560
+ this.initialSolver = params.initialPathingSolver || new CapacityPathingGreedySolver({
12011
12561
  simpleRouteJson: this.simpleRouteJson,
12012
12562
  nodes: this.nodes,
12013
12563
  edges: this.edges,
@@ -12086,7 +12636,8 @@ var CapacityPathingMultiSectionSolver = class extends BaseSolver {
12086
12636
  sectionEdges: section.sectionEdges,
12087
12637
  sectionNodes: section.sectionNodes,
12088
12638
  colorMap: this.colorMap,
12089
- centerNodeId: section.centerNodeId
12639
+ centerNodeId: section.centerNodeId,
12640
+ nodeEdgeMap: this.nodeEdgeMap
12090
12641
  });
12091
12642
  this.activeSubSolver = this.sectionSolver;
12092
12643
  this.nodeOptimizationAttemptCountMap.set(
@@ -12160,9 +12711,11 @@ var CapacityPathingMultiSectionSolver = class extends BaseSolver {
12160
12711
  sectionNodeIds
12161
12712
  });
12162
12713
  if (afterScore > beforeScore) {
12714
+ this.stats.successfulOptimizations++;
12163
12715
  this._mergeSolvedSectionPaths(solvedSectionSolver);
12164
12716
  this._recalculateNodeCapacityUsage();
12165
12717
  } else {
12718
+ this.stats.failedOptimizations++;
12166
12719
  }
12167
12720
  }
12168
12721
  }
@@ -13038,13 +13591,13 @@ function minimumDistanceBetweenSegments(A1, A2, B1, B2) {
13038
13591
  if (segmentsIntersect(A1, A2, B1, B2)) {
13039
13592
  return 0;
13040
13593
  }
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);
13594
+ const distA1 = pointToSegmentDistance6(A1, B1, B2);
13595
+ const distA2 = pointToSegmentDistance6(A2, B1, B2);
13596
+ const distB1 = pointToSegmentDistance6(B1, A1, A2);
13597
+ const distB2 = pointToSegmentDistance6(B2, A1, A2);
13045
13598
  return Math.min(distA1, distA2, distB1, distB2);
13046
13599
  }
13047
- function pointToSegmentDistance5(P, Q1, Q2) {
13600
+ function pointToSegmentDistance6(P, Q1, Q2) {
13048
13601
  const v = { x: Q2.x - Q1.x, y: Q2.y - Q1.y };
13049
13602
  const w = { x: P.x - Q1.x, y: P.y - Q1.y };
13050
13603
  const c1 = dotProduct(w, v);
@@ -14546,8 +15099,8 @@ var AutoroutingPipelineSolver = class extends BaseSolver {
14546
15099
  nodeSolver;
14547
15100
  nodeTargetMerger;
14548
15101
  edgeSolver;
14549
- pathingSolver;
14550
- // Updated type
15102
+ initialPathingSolver;
15103
+ pathingOptimizer;
14551
15104
  edgeToPortSegmentSolver;
14552
15105
  colorMap;
14553
15106
  segmentToPointSolver;
@@ -14634,12 +15187,28 @@ var AutoroutingPipelineSolver = class extends BaseSolver {
14634
15187
  (cms) => [cms.capacityNodes]
14635
15188
  ),
14636
15189
  definePipelineStep(
14637
- "pathingSolver",
15190
+ "initialPathingSolver",
15191
+ CapacityPathingGreedySolver,
15192
+ (cms) => [
15193
+ {
15194
+ simpleRouteJson: cms.srjWithPointPairs,
15195
+ nodes: cms.capacityNodes,
15196
+ edges: cms.edgeSolver?.edges || [],
15197
+ colorMap: cms.colorMap,
15198
+ hyperParameters: {
15199
+ MAX_CAPACITY_FACTOR: 1
15200
+ }
15201
+ }
15202
+ ]
15203
+ ),
15204
+ definePipelineStep(
15205
+ "pathingOptimizer",
14638
15206
  // CapacityPathingSolver5,
14639
15207
  CapacityPathingMultiSectionSolver,
14640
15208
  (cms) => [
14641
15209
  // Replaced solver class
14642
15210
  {
15211
+ initialPathingSolver: cms.initialPathingSolver,
14643
15212
  simpleRouteJson: cms.srjWithPointPairs,
14644
15213
  nodes: cms.capacityNodes,
14645
15214
  edges: cms.edgeSolver?.edges || [],
@@ -14657,7 +15226,7 @@ var AutoroutingPipelineSolver = class extends BaseSolver {
14657
15226
  {
14658
15227
  nodes: cms.capacityNodes,
14659
15228
  edges: cms.edgeSolver?.edges || [],
14660
- capacityPaths: cms.pathingSolver?.getCapacityPaths() || [],
15229
+ capacityPaths: cms.pathingOptimizer?.getCapacityPaths() || [],
14661
15230
  colorMap: cms.colorMap
14662
15231
  }
14663
15232
  ]
@@ -14816,7 +15385,8 @@ var AutoroutingPipelineSolver = class extends BaseSolver {
14816
15385
  const singleLayerNodeMergerViz = this.singleLayerNodeMerger?.visualize();
14817
15386
  const strawSolverViz = this.strawSolver?.visualize();
14818
15387
  const edgeViz = this.edgeSolver?.visualize();
14819
- const pathingViz = this.pathingSolver?.visualize();
15388
+ const initialPathingViz = this.initialPathingSolver?.visualize();
15389
+ const pathingOptimizerViz = this.pathingOptimizer?.visualize();
14820
15390
  const edgeToPortSegmentViz = this.edgeToPortSegmentSolver?.visualize();
14821
15391
  const segmentToPointViz = this.segmentToPointSolver?.visualize();
14822
15392
  const segmentOptimizationViz = this.unravelMultiSectionSolver?.visualize() ?? this.segmentToPointOptimizer?.visualize();
@@ -14871,7 +15441,8 @@ var AutoroutingPipelineSolver = class extends BaseSolver {
14871
15441
  singleLayerNodeMergerViz,
14872
15442
  strawSolverViz,
14873
15443
  edgeViz,
14874
- pathingViz,
15444
+ initialPathingViz,
15445
+ pathingOptimizerViz,
14875
15446
  edgeToPortSegmentViz,
14876
15447
  segmentToPointViz,
14877
15448
  segmentOptimizationViz,
@@ -14913,9 +15484,9 @@ var AutoroutingPipelineSolver = class extends BaseSolver {
14913
15484
  }
14914
15485
  return { lines };
14915
15486
  }
14916
- if (this.pathingSolver) {
15487
+ if (this.pathingOptimizer) {
14917
15488
  const lines = [];
14918
- for (const connection of this.pathingSolver.connectionsWithNodes) {
15489
+ for (const connection of this.pathingOptimizer.connectionsWithNodes) {
14919
15490
  if (!connection.path) continue;
14920
15491
  lines.push({
14921
15492
  points: connection.path.map((n) => ({