@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.d.ts +11 -3
- package/dist/index.js +595 -24
- 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",
|
|
@@ -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 =
|
|
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;
|
|
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 =
|
|
13042
|
-
const distA2 =
|
|
13043
|
-
const distB1 =
|
|
13044
|
-
const distB2 =
|
|
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
|
|
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
|
-
|
|
14550
|
-
|
|
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
|
-
"
|
|
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.
|
|
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
|
|
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
|
-
|
|
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.
|
|
15487
|
+
if (this.pathingOptimizer) {
|
|
14917
15488
|
const lines = [];
|
|
14918
|
-
for (const connection of this.
|
|
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) => ({
|