@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.d.ts +10 -3
- package/dist/index.js +591 -22
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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:
|
|
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
|
|
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 =
|
|
12540
|
+
MAX_ATTEMPTS_PER_NODE = 1;
|
|
11997
12541
|
MINIMUM_PROBABILITY_OF_FAILURE_TO_OPTIMIZE = 0.05;
|
|
11998
|
-
MAX_EXPANSION_DEGREES =
|
|
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 =
|
|
13042
|
-
const distA2 =
|
|
13043
|
-
const distB1 =
|
|
13044
|
-
const distB2 =
|
|
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
|
|
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
|
-
|
|
14550
|
-
|
|
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
|
-
"
|
|
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.
|
|
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
|
|
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
|
-
|
|
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.
|
|
15485
|
+
if (this.pathingOptimizer) {
|
|
14917
15486
|
const lines = [];
|
|
14918
|
-
for (const connection of this.
|
|
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) => ({
|