@tscircuit/capacity-autorouter 0.0.16 → 0.0.18
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/README.md +2 -0
- package/dist/index.d.ts +14 -8
- package/dist/index.js +85 -46
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# @tscircuit/capacity-autorouter
|
|
2
2
|
|
|
3
|
+
[View Online Playground](https://unraveller.vercel.app) · [tscircuit docs](https://docs.tscircuit.com)
|
|
4
|
+
|
|
3
5
|
A high-density PCB autorouter library for node.js and TypeScript projects. Part of the [tscircuit project](https://github.com/tscircuit/tscircuit) · [discord](https://tscircuit.com/join) · [twitter](https://x.com/seveibar) · [try tscircuit online](https://tscircuit.com)
|
|
4
6
|
|
|
5
7
|
Check out this [short youtube explanation of this autorouter](https://youtu.be/MmTk0806fAo)
|
package/dist/index.d.ts
CHANGED
|
@@ -66,6 +66,7 @@ interface CapacityMeshNode {
|
|
|
66
66
|
width: number;
|
|
67
67
|
height: number;
|
|
68
68
|
layer: string;
|
|
69
|
+
availableZ: number[];
|
|
69
70
|
_depth?: number;
|
|
70
71
|
_completelyInsideObstacle?: boolean;
|
|
71
72
|
_containsObstacle?: boolean;
|
|
@@ -92,6 +93,7 @@ declare class BaseSolver {
|
|
|
92
93
|
iterations: number;
|
|
93
94
|
progress: number;
|
|
94
95
|
error: string | null;
|
|
96
|
+
failedSubSolvers?: BaseSolver[];
|
|
95
97
|
/** DO NOT OVERRIDE! Override _step() instead */
|
|
96
98
|
step(): void;
|
|
97
99
|
_step(): void;
|
|
@@ -112,6 +114,12 @@ declare class CapacityMeshEdgeSolver extends BaseSolver {
|
|
|
112
114
|
interface CapacityMeshNodeSolverOptions {
|
|
113
115
|
capacityDepth?: number;
|
|
114
116
|
}
|
|
117
|
+
interface Target {
|
|
118
|
+
x: number;
|
|
119
|
+
y: number;
|
|
120
|
+
connectionName: string;
|
|
121
|
+
availableZ: number[];
|
|
122
|
+
}
|
|
115
123
|
declare class CapacityMeshNodeSolver extends BaseSolver {
|
|
116
124
|
srj: SimpleRouteJson;
|
|
117
125
|
opts: CapacityMeshNodeSolverOptions;
|
|
@@ -119,16 +127,12 @@ declare class CapacityMeshNodeSolver extends BaseSolver {
|
|
|
119
127
|
finishedNodes: CapacityMeshNode[];
|
|
120
128
|
nodeToOverlappingObstaclesMap: Map<CapacityMeshNodeId, Obstacle[]>;
|
|
121
129
|
MAX_DEPTH: number;
|
|
122
|
-
targets:
|
|
123
|
-
x: number;
|
|
124
|
-
y: number;
|
|
125
|
-
connectionName: string;
|
|
126
|
-
}>;
|
|
130
|
+
targets: Target[];
|
|
127
131
|
constructor(srj: SimpleRouteJson, opts?: CapacityMeshNodeSolverOptions);
|
|
128
132
|
_nextNodeCounter: number;
|
|
129
133
|
getNextNodeId(): string;
|
|
130
134
|
getCapacityFromDepth(depth: number): number;
|
|
131
|
-
|
|
135
|
+
getTargetIfNodeContainsTarget(node: CapacityMeshNode): Target | null;
|
|
132
136
|
getOverlappingObstacles(node: CapacityMeshNode): Obstacle[];
|
|
133
137
|
/**
|
|
134
138
|
* Checks if the given mesh node overlaps with any obstacle.
|
|
@@ -233,6 +237,7 @@ interface NodePortSegment {
|
|
|
233
237
|
x: number;
|
|
234
238
|
y: number;
|
|
235
239
|
};
|
|
240
|
+
availableZ: number[];
|
|
236
241
|
connectionNames: string[];
|
|
237
242
|
}
|
|
238
243
|
|
|
@@ -473,7 +478,7 @@ declare class SingleHighDensityRouteSolver extends BaseSolver {
|
|
|
473
478
|
handleSimpleCases(): void;
|
|
474
479
|
get viaPenaltyDistance(): number;
|
|
475
480
|
isNodeTooCloseToObstacle(node: Node, margin?: number, isVia?: boolean): boolean;
|
|
476
|
-
isNodeTooCloseToEdge(node: Node): boolean;
|
|
481
|
+
isNodeTooCloseToEdge(node: Node, isVia?: boolean): boolean;
|
|
477
482
|
doesPathToParentIntersectObstacle(node: Node): boolean;
|
|
478
483
|
computeH(node: Node): number;
|
|
479
484
|
computeG(node: Node): number;
|
|
@@ -504,11 +509,12 @@ declare class IntraNodeRouteSolver extends BaseSolver {
|
|
|
504
509
|
}[];
|
|
505
510
|
totalConnections: number;
|
|
506
511
|
solvedRoutes: HighDensityIntraNodeRoute[];
|
|
507
|
-
|
|
512
|
+
failedSubSolvers: SingleHighDensityRouteSolver[];
|
|
508
513
|
hyperParameters: Partial<HighDensityHyperParameters>;
|
|
509
514
|
minDistBetweenEnteringPoints: number;
|
|
510
515
|
activeSolver: SingleHighDensityRouteSolver | null;
|
|
511
516
|
connMap?: ConnectivityMap;
|
|
517
|
+
get failedSolvers(): SingleHighDensityRouteSolver[];
|
|
512
518
|
constructor(params: {
|
|
513
519
|
nodeWithPortPoints: NodeWithPortPoints;
|
|
514
520
|
colorMap?: Record<string, string>;
|
package/dist/index.js
CHANGED
|
@@ -43,6 +43,7 @@ var BaseSolver = class {
|
|
|
43
43
|
iterations = 0;
|
|
44
44
|
progress = 0;
|
|
45
45
|
error = null;
|
|
46
|
+
failedSubSolvers;
|
|
46
47
|
/** DO NOT OVERRIDE! Override _step() instead */
|
|
47
48
|
step() {
|
|
48
49
|
if (this.solved) return;
|
|
@@ -1092,6 +1093,7 @@ var CapacityMeshNodeSolver = class extends BaseSolver {
|
|
|
1092
1093
|
width: maxWidthHeight,
|
|
1093
1094
|
height: maxWidthHeight,
|
|
1094
1095
|
layer: "top",
|
|
1096
|
+
availableZ: [0, 1],
|
|
1095
1097
|
_depth: 0,
|
|
1096
1098
|
_containsTarget: true,
|
|
1097
1099
|
_containsObstacle: true,
|
|
@@ -1101,7 +1103,11 @@ var CapacityMeshNodeSolver = class extends BaseSolver {
|
|
|
1101
1103
|
this.finishedNodes = [];
|
|
1102
1104
|
this.nodeToOverlappingObstaclesMap = /* @__PURE__ */ new Map();
|
|
1103
1105
|
this.targets = this.srj.connections.flatMap(
|
|
1104
|
-
(c) => c.pointsToConnect.map((p) => ({
|
|
1106
|
+
(c) => c.pointsToConnect.map((p) => ({
|
|
1107
|
+
...p,
|
|
1108
|
+
connectionName: c.name,
|
|
1109
|
+
availableZ: p.layer === "top" ? [0] : [1]
|
|
1110
|
+
}))
|
|
1105
1111
|
);
|
|
1106
1112
|
}
|
|
1107
1113
|
unfinishedNodes;
|
|
@@ -1117,7 +1123,7 @@ var CapacityMeshNodeSolver = class extends BaseSolver {
|
|
|
1117
1123
|
getCapacityFromDepth(depth) {
|
|
1118
1124
|
return (this.MAX_DEPTH - depth + 1) ** 2;
|
|
1119
1125
|
}
|
|
1120
|
-
|
|
1126
|
+
getTargetIfNodeContainsTarget(node) {
|
|
1121
1127
|
const overlappingObstacles = this.getOverlappingObstacles(node);
|
|
1122
1128
|
for (const target of this.targets) {
|
|
1123
1129
|
const targetObstacle = overlappingObstacles.find(
|
|
@@ -1125,11 +1131,11 @@ var CapacityMeshNodeSolver = class extends BaseSolver {
|
|
|
1125
1131
|
);
|
|
1126
1132
|
if (targetObstacle) {
|
|
1127
1133
|
if (doRectsOverlap(node, targetObstacle)) {
|
|
1128
|
-
return target
|
|
1134
|
+
return target;
|
|
1129
1135
|
}
|
|
1130
1136
|
}
|
|
1131
1137
|
if (target.x >= node.center.x - node.width / 2 && target.x <= node.center.x + node.width / 2 && target.y >= node.center.y - node.height / 2 && target.y <= node.center.y + node.height / 2) {
|
|
1132
|
-
return target
|
|
1138
|
+
return target;
|
|
1133
1139
|
}
|
|
1134
1140
|
}
|
|
1135
1141
|
return null;
|
|
@@ -1232,12 +1238,17 @@ var CapacityMeshNodeSolver = class extends BaseSolver {
|
|
|
1232
1238
|
width: childNodeSize.width,
|
|
1233
1239
|
height: childNodeSize.height,
|
|
1234
1240
|
layer: parent.layer,
|
|
1241
|
+
availableZ: [0, 1],
|
|
1235
1242
|
_depth: (parent._depth ?? 0) + 1,
|
|
1236
1243
|
_parent: parent
|
|
1237
1244
|
};
|
|
1238
1245
|
childNode._containsObstacle = this.doesNodeOverlapObstacle(childNode);
|
|
1239
|
-
|
|
1240
|
-
|
|
1246
|
+
const target = this.getTargetIfNodeContainsTarget(childNode);
|
|
1247
|
+
if (target) {
|
|
1248
|
+
childNode._targetConnectionName = target.connectionName;
|
|
1249
|
+
childNode.availableZ = target.availableZ;
|
|
1250
|
+
childNode._containsTarget = true;
|
|
1251
|
+
}
|
|
1241
1252
|
if (childNode._containsObstacle) {
|
|
1242
1253
|
childNode._completelyInsideObstacle = this.isNodeCompletelyInsideObstacle(childNode);
|
|
1243
1254
|
}
|
|
@@ -1294,16 +1305,6 @@ var CapacityMeshNodeSolver = class extends BaseSolver {
|
|
|
1294
1305
|
coordinateSystem: "cartesian",
|
|
1295
1306
|
title: "Capacity Mesh Visualization"
|
|
1296
1307
|
};
|
|
1297
|
-
const allNodes = [...this.finishedNodes, ...this.unfinishedNodes];
|
|
1298
|
-
for (const node of allNodes) {
|
|
1299
|
-
graphics.rects.push({
|
|
1300
|
-
center: node.center,
|
|
1301
|
-
width: Math.max(node.width - 2, node.width * 0.8),
|
|
1302
|
-
height: Math.max(node.height - 2, node.height * 0.8),
|
|
1303
|
-
fill: node._containsObstacle ? "rgba(255,0,0,0.1)" : "rgba(0,0,0,0.1)",
|
|
1304
|
-
label: node.capacityMeshNodeId
|
|
1305
|
-
});
|
|
1306
|
-
}
|
|
1307
1308
|
for (const obstacle of this.srj.obstacles) {
|
|
1308
1309
|
graphics.rects.push({
|
|
1309
1310
|
center: obstacle.center,
|
|
@@ -1314,13 +1315,24 @@ var CapacityMeshNodeSolver = class extends BaseSolver {
|
|
|
1314
1315
|
label: "obstacle"
|
|
1315
1316
|
});
|
|
1316
1317
|
}
|
|
1318
|
+
const allNodes = [...this.finishedNodes, ...this.unfinishedNodes];
|
|
1319
|
+
for (const node of allNodes) {
|
|
1320
|
+
graphics.rects.push({
|
|
1321
|
+
center: node.center,
|
|
1322
|
+
width: Math.max(node.width - 2, node.width * 0.8),
|
|
1323
|
+
height: Math.max(node.height - 2, node.height * 0.8),
|
|
1324
|
+
fill: node._containsObstacle ? "rgba(255,0,0,0.1)" : "rgba(0,0,0,0.1)",
|
|
1325
|
+
label: `${node.capacityMeshNodeId}
|
|
1326
|
+
availableZ: ${node.availableZ.join(",")}`
|
|
1327
|
+
});
|
|
1328
|
+
}
|
|
1317
1329
|
this.srj.connections.forEach((connection, index) => {
|
|
1318
1330
|
const color = COLORS[index % COLORS.length];
|
|
1319
1331
|
for (const pt of connection.pointsToConnect) {
|
|
1320
1332
|
graphics.points.push({
|
|
1321
1333
|
x: pt.x,
|
|
1322
1334
|
y: pt.y,
|
|
1323
|
-
label: `conn-${index}`,
|
|
1335
|
+
label: `conn-${index} (${pt.layer})`,
|
|
1324
1336
|
color
|
|
1325
1337
|
});
|
|
1326
1338
|
}
|
|
@@ -1390,11 +1402,16 @@ var CapacityEdgeToPortSegmentSolver = class extends BaseSolver {
|
|
|
1390
1402
|
const adjNode = this.nodeMap.get(adjNodeId);
|
|
1391
1403
|
if (!adjNode) continue;
|
|
1392
1404
|
const segment = findOverlappingSegment(node, adjNode);
|
|
1405
|
+
const mutuallyAvailableZ = adjNode.availableZ.filter(
|
|
1406
|
+
(z) => node.availableZ.includes(z)
|
|
1407
|
+
);
|
|
1408
|
+
if (mutuallyAvailableZ.length === 0) continue;
|
|
1393
1409
|
const portSegment = {
|
|
1394
1410
|
capacityMeshNodeId: nodeId,
|
|
1395
1411
|
start: segment.start,
|
|
1396
1412
|
end: segment.end,
|
|
1397
|
-
connectionNames: [path.connectionName]
|
|
1413
|
+
connectionNames: [path.connectionName],
|
|
1414
|
+
availableZ: mutuallyAvailableZ
|
|
1398
1415
|
};
|
|
1399
1416
|
nodePortSegments.push(portSegment);
|
|
1400
1417
|
}
|
|
@@ -1413,7 +1430,7 @@ var CapacityEdgeToPortSegmentSolver = class extends BaseSolver {
|
|
|
1413
1430
|
const node = this.nodeMap.get(nodeId);
|
|
1414
1431
|
segments.forEach((segment) => {
|
|
1415
1432
|
const isVertical = segment.start.x === segment.end.x;
|
|
1416
|
-
const THICKNESS = 0.
|
|
1433
|
+
const THICKNESS = 0.1 / segment.connectionNames.length;
|
|
1417
1434
|
for (let i = 0; i < segment.connectionNames.length; i++) {
|
|
1418
1435
|
const offsetAmount = (i / (segment.connectionNames.length - 1 + 1e-6) - 0.5) * THICKNESS;
|
|
1419
1436
|
const offset = {
|
|
@@ -1435,7 +1452,8 @@ var CapacityEdgeToPortSegmentSolver = class extends BaseSolver {
|
|
|
1435
1452
|
this.colorMap[segment.connectionNames[i]],
|
|
1436
1453
|
0.6
|
|
1437
1454
|
),
|
|
1438
|
-
label: `${nodeId}: ${segment.connectionNames.join(", ")}
|
|
1455
|
+
label: `${nodeId}: ${segment.connectionNames.join(", ")}
|
|
1456
|
+
availableZ: ${segment.availableZ.join(",")}`
|
|
1439
1457
|
});
|
|
1440
1458
|
}
|
|
1441
1459
|
});
|
|
@@ -1536,7 +1554,7 @@ var CapacitySegmentToPointSolver = class extends BaseSolver {
|
|
|
1536
1554
|
const center = {
|
|
1537
1555
|
x: (seg.start.x + seg.end.x) / 2,
|
|
1538
1556
|
y: (seg.start.y + seg.end.y) / 2,
|
|
1539
|
-
z: 0
|
|
1557
|
+
z: seg.availableZ[0]
|
|
1540
1558
|
};
|
|
1541
1559
|
seg.assignedPoints = [
|
|
1542
1560
|
{ connectionName: seg.connectionNames[0], point: center }
|
|
@@ -1563,7 +1581,7 @@ var CapacitySegmentToPointSolver = class extends BaseSolver {
|
|
|
1563
1581
|
points.push({
|
|
1564
1582
|
x: candidate.start.x + dx * fraction,
|
|
1565
1583
|
y: candidate.start.y + dy * fraction,
|
|
1566
|
-
z: 0
|
|
1584
|
+
z: candidate.availableZ[0]
|
|
1567
1585
|
});
|
|
1568
1586
|
}
|
|
1569
1587
|
;
|
|
@@ -1809,9 +1827,15 @@ var SingleHighDensityRouteSolver = class extends BaseSolver {
|
|
|
1809
1827
|
}
|
|
1810
1828
|
return false;
|
|
1811
1829
|
}
|
|
1812
|
-
isNodeTooCloseToEdge(node) {
|
|
1813
|
-
const
|
|
1814
|
-
|
|
1830
|
+
isNodeTooCloseToEdge(node, isVia) {
|
|
1831
|
+
const margin = isVia ? this.viaDiameter / 2 : this.obstacleMargin;
|
|
1832
|
+
const tooClose = node.x < this.bounds.minX + margin || node.x > this.bounds.maxX - margin || node.y < this.bounds.minY + margin || node.y > this.bounds.maxY - margin;
|
|
1833
|
+
if (tooClose && !isVia) {
|
|
1834
|
+
if (distance(node, this.B) < margin * 2) {
|
|
1835
|
+
return false;
|
|
1836
|
+
}
|
|
1837
|
+
}
|
|
1838
|
+
return tooClose;
|
|
1815
1839
|
}
|
|
1816
1840
|
doesPathToParentIntersectObstacle(node) {
|
|
1817
1841
|
const parent = node.parent;
|
|
@@ -1865,6 +1889,10 @@ var SingleHighDensityRouteSolver = class extends BaseSolver {
|
|
|
1865
1889
|
this.exploredNodes.add(neighborKey);
|
|
1866
1890
|
continue;
|
|
1867
1891
|
}
|
|
1892
|
+
if (this.isNodeTooCloseToEdge(neighbor, false)) {
|
|
1893
|
+
this.exploredNodes.add(neighborKey);
|
|
1894
|
+
continue;
|
|
1895
|
+
}
|
|
1868
1896
|
if (this.doesPathToParentIntersectObstacle(neighbor)) {
|
|
1869
1897
|
this.debug_nodePathToParentIntersectsObstacle.add(neighborKey);
|
|
1870
1898
|
this.exploredNodes.add(neighborKey);
|
|
@@ -1883,9 +1911,9 @@ var SingleHighDensityRouteSolver = class extends BaseSolver {
|
|
|
1883
1911
|
};
|
|
1884
1912
|
if (!this.exploredNodes.has(this.getNodeKey(viaNeighbor)) && !this.isNodeTooCloseToObstacle(
|
|
1885
1913
|
viaNeighbor,
|
|
1886
|
-
this.viaDiameter / 2 + this.obstacleMargin,
|
|
1914
|
+
this.viaDiameter / 2 + this.obstacleMargin / 2,
|
|
1887
1915
|
true
|
|
1888
|
-
) && !this.isNodeTooCloseToEdge(viaNeighbor)) {
|
|
1916
|
+
) && !this.isNodeTooCloseToEdge(viaNeighbor, true)) {
|
|
1889
1917
|
viaNeighbor.g = this.computeG(viaNeighbor);
|
|
1890
1918
|
viaNeighbor.h = this.computeH(viaNeighbor);
|
|
1891
1919
|
viaNeighbor.f = this.computeF(viaNeighbor.g, viaNeighbor.h);
|
|
@@ -1977,13 +2005,15 @@ var SingleHighDensityRouteSolver = class extends BaseSolver {
|
|
|
1977
2005
|
graphics.points.push({
|
|
1978
2006
|
x: this.A.x,
|
|
1979
2007
|
y: this.A.y,
|
|
1980
|
-
label:
|
|
2008
|
+
label: `Input A
|
|
2009
|
+
z: ${this.A.z}`,
|
|
1981
2010
|
color: "orange"
|
|
1982
2011
|
});
|
|
1983
2012
|
graphics.points.push({
|
|
1984
2013
|
x: this.B.x,
|
|
1985
2014
|
y: this.B.y,
|
|
1986
|
-
label:
|
|
2015
|
+
label: `Input B
|
|
2016
|
+
z: ${this.B.z}`,
|
|
1987
2017
|
color: "orange"
|
|
1988
2018
|
});
|
|
1989
2019
|
graphics.lines.push({
|
|
@@ -2219,11 +2249,15 @@ var IntraNodeRouteSolver = class extends BaseSolver {
|
|
|
2219
2249
|
unsolvedConnections;
|
|
2220
2250
|
totalConnections;
|
|
2221
2251
|
solvedRoutes;
|
|
2222
|
-
|
|
2252
|
+
failedSubSolvers;
|
|
2223
2253
|
hyperParameters;
|
|
2224
2254
|
minDistBetweenEnteringPoints;
|
|
2225
2255
|
activeSolver = null;
|
|
2226
2256
|
connMap;
|
|
2257
|
+
// Legacy compat
|
|
2258
|
+
get failedSolvers() {
|
|
2259
|
+
return this.failedSubSolvers;
|
|
2260
|
+
}
|
|
2227
2261
|
constructor(params) {
|
|
2228
2262
|
const { nodeWithPortPoints, colorMap } = params;
|
|
2229
2263
|
super();
|
|
@@ -2231,7 +2265,7 @@ var IntraNodeRouteSolver = class extends BaseSolver {
|
|
|
2231
2265
|
this.colorMap = colorMap ?? {};
|
|
2232
2266
|
this.solvedRoutes = [];
|
|
2233
2267
|
this.hyperParameters = params.hyperParameters ?? {};
|
|
2234
|
-
this.
|
|
2268
|
+
this.failedSubSolvers = [];
|
|
2235
2269
|
this.connMap = params.connMap;
|
|
2236
2270
|
const unsolvedConnectionsMap = /* @__PURE__ */ new Map();
|
|
2237
2271
|
for (const { connectionName, x, y, z } of nodeWithPortPoints.portPoints) {
|
|
@@ -2292,9 +2326,9 @@ var IntraNodeRouteSolver = class extends BaseSolver {
|
|
|
2292
2326
|
this.solvedRoutes.push(this.activeSolver.solvedPath);
|
|
2293
2327
|
this.activeSolver = null;
|
|
2294
2328
|
} else if (this.activeSolver.failed) {
|
|
2295
|
-
this.
|
|
2329
|
+
this.failedSubSolvers.push(this.activeSolver);
|
|
2296
2330
|
this.activeSolver = null;
|
|
2297
|
-
this.error = this.
|
|
2331
|
+
this.error = this.failedSubSolvers.map((s) => s.error).join("\n");
|
|
2298
2332
|
this.failed = true;
|
|
2299
2333
|
}
|
|
2300
2334
|
return;
|
|
@@ -2302,7 +2336,7 @@ var IntraNodeRouteSolver = class extends BaseSolver {
|
|
|
2302
2336
|
const unsolvedConnection = this.unsolvedConnections.pop();
|
|
2303
2337
|
this.progress = this.computeProgress();
|
|
2304
2338
|
if (!unsolvedConnection) {
|
|
2305
|
-
this.solved = this.
|
|
2339
|
+
this.solved = this.failedSubSolvers.length === 0;
|
|
2306
2340
|
return;
|
|
2307
2341
|
}
|
|
2308
2342
|
if (unsolvedConnection.points.length === 1) {
|
|
@@ -2373,6 +2407,20 @@ var IntraNodeRouteSolver = class extends BaseSolver {
|
|
|
2373
2407
|
}
|
|
2374
2408
|
}
|
|
2375
2409
|
}
|
|
2410
|
+
const bounds = getBoundsFromNodeWithPortPoints(this.nodeWithPortPoints);
|
|
2411
|
+
const { minX, minY, maxX, maxY } = bounds;
|
|
2412
|
+
graphics.lines.push({
|
|
2413
|
+
points: [
|
|
2414
|
+
{ x: minX, y: minY },
|
|
2415
|
+
{ x: maxX, y: minY },
|
|
2416
|
+
{ x: maxX, y: maxY },
|
|
2417
|
+
{ x: minX, y: maxY },
|
|
2418
|
+
{ x: minX, y: minY }
|
|
2419
|
+
],
|
|
2420
|
+
strokeColor: "rgba(255, 0, 0, 0.25)",
|
|
2421
|
+
strokeDash: "4 4",
|
|
2422
|
+
layer: "border"
|
|
2423
|
+
});
|
|
2376
2424
|
return graphics;
|
|
2377
2425
|
}
|
|
2378
2426
|
};
|
|
@@ -3269,6 +3317,7 @@ var CapacityNodeTargetMerger = class extends BaseSolver {
|
|
|
3269
3317
|
width: bounds.maxX - bounds.minX,
|
|
3270
3318
|
height: bounds.maxY - bounds.minY,
|
|
3271
3319
|
layer: connectedNodes[0].layer,
|
|
3320
|
+
availableZ: connectedNodes[0].availableZ,
|
|
3272
3321
|
_completelyInsideObstacle: false,
|
|
3273
3322
|
_containsObstacle: true,
|
|
3274
3323
|
_containsTarget: true,
|
|
@@ -3527,11 +3576,6 @@ var CapacitySegmentPointOptimizer = class extends BaseSolver {
|
|
|
3527
3576
|
const segments = segmentIds.map(
|
|
3528
3577
|
(segmentId) => this.currentMutatedSegments.get(segmentId)
|
|
3529
3578
|
);
|
|
3530
|
-
const points = segments.flatMap((s) => s.assignedPoints);
|
|
3531
|
-
if (points.length <= 2) {
|
|
3532
|
-
if (points.length <= 1) return 0;
|
|
3533
|
-
return 0;
|
|
3534
|
-
}
|
|
3535
3579
|
const {
|
|
3536
3580
|
numEntryExitLayerChanges,
|
|
3537
3581
|
numSameLayerCrossings,
|
|
@@ -3606,10 +3650,6 @@ var CapacitySegmentPointOptimizer = class extends BaseSolver {
|
|
|
3606
3650
|
point2Index: randomPointIndex2
|
|
3607
3651
|
};
|
|
3608
3652
|
}
|
|
3609
|
-
const nodeIds = this.segmentIdToNodeIds.get(segment.nodePortSegmentId);
|
|
3610
|
-
if (nodeIds?.some((nodeId) => this.nodesThatCantFitVias.has(nodeId))) {
|
|
3611
|
-
return null;
|
|
3612
|
-
}
|
|
3613
3653
|
const randomPointIndex = Math.floor(
|
|
3614
3654
|
this.random() * segment.assignedPoints.length
|
|
3615
3655
|
);
|
|
@@ -3815,9 +3855,7 @@ var CapacitySegmentPointOptimizer = class extends BaseSolver {
|
|
|
3815
3855
|
this.solved = true;
|
|
3816
3856
|
return;
|
|
3817
3857
|
}
|
|
3818
|
-
const op = this.
|
|
3819
|
-
this.getRandomWeightedNodeId()
|
|
3820
|
-
);
|
|
3858
|
+
const op = this.getRandomCombinedOperationOnSingleNode();
|
|
3821
3859
|
this.lastCreatedOperation = op;
|
|
3822
3860
|
this.applyOperation(op);
|
|
3823
3861
|
const {
|
|
@@ -4689,6 +4727,7 @@ var convertSrjToGraphicsObject = (srj) => {
|
|
|
4689
4727
|
{ x: routePoint.x, y: routePoint.y },
|
|
4690
4728
|
{ x: nextRoutePoint.x, y: nextRoutePoint.y }
|
|
4691
4729
|
],
|
|
4730
|
+
strokeWidth: 0.15,
|
|
4692
4731
|
strokeColor: safeTransparentize(
|
|
4693
4732
|
{
|
|
4694
4733
|
top: "red",
|