@tscircuit/capacity-autorouter 0.0.43 → 0.0.45
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 +1 -0
- package/dist/index.js +282 -149
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1642,30 +1642,40 @@ var CapacityEdgeToPortSegmentSolver = class extends BaseSolver {
|
|
|
1642
1642
|
const node = this.nodeMap.get(nodeId);
|
|
1643
1643
|
segments.forEach((segment) => {
|
|
1644
1644
|
const isVertical = segment.start.x === segment.end.x;
|
|
1645
|
-
const THICKNESS = 0.
|
|
1645
|
+
const THICKNESS = 0.05;
|
|
1646
1646
|
for (let i = 0; i < segment.connectionNames.length; i++) {
|
|
1647
|
-
const offsetAmount = (i / (segment.connectionNames.length - 1 + 1e-6) - 0.5) * THICKNESS;
|
|
1648
1647
|
const offset = {
|
|
1649
|
-
x:
|
|
1650
|
-
y:
|
|
1648
|
+
x: 0.05 * Math.max(...segment.availableZ),
|
|
1649
|
+
y: 0.05 * Math.max(...segment.availableZ)
|
|
1651
1650
|
};
|
|
1652
1651
|
const trueSegmentCenter = {
|
|
1653
|
-
x: (segment.start.x + segment.end.x) / 2
|
|
1654
|
-
y: (segment.start.y + segment.end.y) / 2
|
|
1652
|
+
x: (segment.start.x + segment.end.x) / 2,
|
|
1653
|
+
y: (segment.start.y + segment.end.y) / 2
|
|
1655
1654
|
};
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1655
|
+
const segmentCenter = {
|
|
1656
|
+
x: trueSegmentCenter.x + offset.x,
|
|
1657
|
+
y: trueSegmentCenter.y + offset.y
|
|
1658
|
+
};
|
|
1659
|
+
if (offset.x > 0) {
|
|
1660
|
+
graphics.lines.push({
|
|
1661
|
+
points: [trueSegmentCenter, segmentCenter],
|
|
1662
|
+
strokeColor: "rgba(0, 0, 0, 0.25)",
|
|
1663
|
+
strokeDash: "5 5"
|
|
1664
|
+
});
|
|
1665
|
+
}
|
|
1666
|
+
graphics.points.push({
|
|
1667
|
+
x: segmentCenter.x,
|
|
1668
|
+
y: segmentCenter.y,
|
|
1669
|
+
label: `${nodeId}: ${segment.connectionNames.join(", ")}
|
|
1670
|
+
availableZ: ${segment.availableZ.join(",")}
|
|
1671
|
+
nodePortSegmentId: ${segment.nodePortSegmentId}`
|
|
1672
|
+
});
|
|
1673
|
+
graphics.lines.push({
|
|
1674
|
+
points: [segment.start, segment.end],
|
|
1675
|
+
strokeColor: safeTransparentize(
|
|
1664
1676
|
this.colorMap[segment.connectionNames[i]],
|
|
1665
1677
|
0.6
|
|
1666
|
-
)
|
|
1667
|
-
label: `${nodeId}: ${segment.connectionNames.join(", ")}
|
|
1668
|
-
availableZ: ${segment.availableZ.join(",")}`
|
|
1678
|
+
)
|
|
1669
1679
|
});
|
|
1670
1680
|
}
|
|
1671
1681
|
});
|
|
@@ -1710,19 +1720,50 @@ function findOverlappingSegment(node, adjNode) {
|
|
|
1710
1720
|
};
|
|
1711
1721
|
}
|
|
1712
1722
|
}
|
|
1723
|
+
var EPSILON = 1e-9;
|
|
1724
|
+
function coordsAreEqual(p1, p2) {
|
|
1725
|
+
return Math.abs(p1.x - p2.x) < EPSILON && Math.abs(p1.y - p2.y) < EPSILON;
|
|
1726
|
+
}
|
|
1727
|
+
function availableZAreEqual(zA1, zA2) {
|
|
1728
|
+
if (zA1.length !== zA2.length) {
|
|
1729
|
+
return false;
|
|
1730
|
+
}
|
|
1731
|
+
for (let i = 0; i < zA1.length; i++) {
|
|
1732
|
+
if (zA1[i] !== zA2[i]) {
|
|
1733
|
+
return false;
|
|
1734
|
+
}
|
|
1735
|
+
}
|
|
1736
|
+
return true;
|
|
1737
|
+
}
|
|
1713
1738
|
function combineSegments(segments) {
|
|
1714
1739
|
const mergedSegments = [];
|
|
1715
|
-
const remainingSegments =
|
|
1740
|
+
const remainingSegments = segments.map((s) => ({
|
|
1741
|
+
...s,
|
|
1742
|
+
connectionNames: [...s.connectionNames],
|
|
1743
|
+
availableZ: [...s.availableZ].sort((a, b) => a - b)
|
|
1744
|
+
// Ensure Z is sorted for comparison
|
|
1745
|
+
}));
|
|
1716
1746
|
while (remainingSegments.length > 0) {
|
|
1717
1747
|
const segmentUnderTest = remainingSegments.pop();
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1748
|
+
let foundMatch = false;
|
|
1749
|
+
for (let i = 0; i < mergedSegments.length; i++) {
|
|
1750
|
+
const mergedSegment = mergedSegments[i];
|
|
1751
|
+
const geometryMatch = coordsAreEqual(mergedSegment.start, segmentUnderTest.start) && coordsAreEqual(mergedSegment.end, segmentUnderTest.end) || coordsAreEqual(mergedSegment.start, segmentUnderTest.end) && coordsAreEqual(mergedSegment.end, segmentUnderTest.start);
|
|
1752
|
+
const zMatch = availableZAreEqual(
|
|
1753
|
+
mergedSegment.availableZ,
|
|
1754
|
+
segmentUnderTest.availableZ
|
|
1724
1755
|
);
|
|
1725
|
-
|
|
1756
|
+
if (geometryMatch && zMatch) {
|
|
1757
|
+
const currentConnections = new Set(mergedSegment.connectionNames);
|
|
1758
|
+
segmentUnderTest.connectionNames.forEach(
|
|
1759
|
+
(cn) => currentConnections.add(cn)
|
|
1760
|
+
);
|
|
1761
|
+
mergedSegment.connectionNames = Array.from(currentConnections);
|
|
1762
|
+
foundMatch = true;
|
|
1763
|
+
break;
|
|
1764
|
+
}
|
|
1765
|
+
}
|
|
1766
|
+
if (!foundMatch) {
|
|
1726
1767
|
mergedSegments.push(segmentUnderTest);
|
|
1727
1768
|
}
|
|
1728
1769
|
}
|
|
@@ -1847,25 +1888,49 @@ var CapacitySegmentToPointSolver = class extends BaseSolver {
|
|
|
1847
1888
|
*/
|
|
1848
1889
|
visualize() {
|
|
1849
1890
|
const graphics = {
|
|
1850
|
-
points:
|
|
1851
|
-
(seg) => seg.assignedPoints.map((ap) => ({
|
|
1852
|
-
x: ap.point.x,
|
|
1853
|
-
y: ap.point.y,
|
|
1854
|
-
label: [
|
|
1855
|
-
`${seg.capacityMeshNodeId}-${ap.connectionName}`,
|
|
1856
|
-
`z: ${seg.availableZ.join(",")}`
|
|
1857
|
-
].join("\n"),
|
|
1858
|
-
color: this.colorMap[ap.connectionName],
|
|
1859
|
-
step: 4
|
|
1860
|
-
}))
|
|
1861
|
-
),
|
|
1891
|
+
points: [],
|
|
1862
1892
|
lines: this.solvedSegments.map((seg) => ({
|
|
1863
1893
|
points: [seg.start, seg.end],
|
|
1864
1894
|
step: 4
|
|
1865
1895
|
})),
|
|
1866
1896
|
rects: [],
|
|
1867
|
-
circles: []
|
|
1897
|
+
circles: [],
|
|
1898
|
+
coordinateSystem: "cartesian",
|
|
1899
|
+
title: "Capacity Segment to Point Solver"
|
|
1868
1900
|
};
|
|
1901
|
+
for (let i = 0; i < this.solvedSegments.length; i++) {
|
|
1902
|
+
const seg = this.solvedSegments[i];
|
|
1903
|
+
for (let j = 0; j < seg.assignedPoints.length; j++) {
|
|
1904
|
+
const ap = seg.assignedPoints[j];
|
|
1905
|
+
const truePoint = {
|
|
1906
|
+
x: ap.point.x,
|
|
1907
|
+
y: ap.point.y
|
|
1908
|
+
};
|
|
1909
|
+
const offsetPoint = {
|
|
1910
|
+
x: ap.point.x + ap.point.z * 0.05,
|
|
1911
|
+
y: ap.point.y + ap.point.z * 0.05
|
|
1912
|
+
};
|
|
1913
|
+
if (ap.point.z !== 0) {
|
|
1914
|
+
graphics.lines.push({
|
|
1915
|
+
points: [truePoint, offsetPoint],
|
|
1916
|
+
strokeColor: "rgba(0, 0, 0, 0.25)",
|
|
1917
|
+
strokeDash: "5 5",
|
|
1918
|
+
step: 4
|
|
1919
|
+
});
|
|
1920
|
+
}
|
|
1921
|
+
graphics.points.push({
|
|
1922
|
+
x: offsetPoint.x,
|
|
1923
|
+
y: offsetPoint.y,
|
|
1924
|
+
label: [
|
|
1925
|
+
`${seg.capacityMeshNodeId}-${ap.connectionName}`,
|
|
1926
|
+
`z: ${seg.availableZ.join(",")}`,
|
|
1927
|
+
`nodePortSegmentId: ${seg.nodePortSegmentId}`
|
|
1928
|
+
].join("\n"),
|
|
1929
|
+
color: this.colorMap[ap.connectionName],
|
|
1930
|
+
step: 4
|
|
1931
|
+
});
|
|
1932
|
+
}
|
|
1933
|
+
}
|
|
1869
1934
|
const dashedLines = [];
|
|
1870
1935
|
const nodeConnections = {};
|
|
1871
1936
|
for (const seg of this.solvedSegments) {
|
|
@@ -2075,6 +2140,12 @@ var SingleRouteCandidatePriorityQueue = class {
|
|
|
2075
2140
|
this.heapifyDown();
|
|
2076
2141
|
return item;
|
|
2077
2142
|
}
|
|
2143
|
+
peek() {
|
|
2144
|
+
if (this.heap.length === 0) {
|
|
2145
|
+
return null;
|
|
2146
|
+
}
|
|
2147
|
+
return this.heap[0];
|
|
2148
|
+
}
|
|
2078
2149
|
enqueue(item) {
|
|
2079
2150
|
this.heap.push(item);
|
|
2080
2151
|
this.heapifyUp();
|
|
@@ -2157,16 +2228,6 @@ var SingleHighDensityRouteSolver = class extends BaseSolver {
|
|
|
2157
2228
|
this.obstacleMargin = opts.obstacleMargin ?? 0.2;
|
|
2158
2229
|
this.layerCount = opts.layerCount ?? 2;
|
|
2159
2230
|
this.exploredNodes = /* @__PURE__ */ new Set();
|
|
2160
|
-
this.candidates = new SingleRouteCandidatePriorityQueue([
|
|
2161
|
-
{
|
|
2162
|
-
...opts.A,
|
|
2163
|
-
z: opts.A.z ?? 0,
|
|
2164
|
-
g: 0,
|
|
2165
|
-
h: 0,
|
|
2166
|
-
f: 0,
|
|
2167
|
-
parent: null
|
|
2168
|
-
}
|
|
2169
|
-
]);
|
|
2170
2231
|
this.straightLineDistance = distance(this.A, this.B);
|
|
2171
2232
|
this.futureConnections = opts.futureConnections ?? [];
|
|
2172
2233
|
this.MAX_ITERATIONS = 5e3;
|
|
@@ -2189,6 +2250,25 @@ var SingleHighDensityRouteSolver = class extends BaseSolver {
|
|
|
2189
2250
|
if (this.futureConnections && this.futureConnections.length === 0 && this.obstacleRoutes.length === 0) {
|
|
2190
2251
|
this.handleSimpleCases();
|
|
2191
2252
|
}
|
|
2253
|
+
this.candidates = new SingleRouteCandidatePriorityQueue([
|
|
2254
|
+
{
|
|
2255
|
+
...opts.A,
|
|
2256
|
+
x: Math.floor(opts.A.x / this.cellStep) * this.cellStep,
|
|
2257
|
+
y: Math.floor(opts.A.y / this.cellStep) * this.cellStep,
|
|
2258
|
+
z: opts.A.z ?? 0,
|
|
2259
|
+
g: 0,
|
|
2260
|
+
h: 0,
|
|
2261
|
+
f: 0,
|
|
2262
|
+
parent: {
|
|
2263
|
+
...opts.A,
|
|
2264
|
+
z: opts.A.z ?? 0,
|
|
2265
|
+
g: 0,
|
|
2266
|
+
h: 0,
|
|
2267
|
+
f: 0,
|
|
2268
|
+
parent: null
|
|
2269
|
+
}
|
|
2270
|
+
}
|
|
2271
|
+
]);
|
|
2192
2272
|
}
|
|
2193
2273
|
handleSimpleCases() {
|
|
2194
2274
|
this.solved = true;
|
|
@@ -2468,6 +2548,19 @@ z: ${this.B.z}`,
|
|
|
2468
2548
|
label: `Explored (z=${z})`
|
|
2469
2549
|
});
|
|
2470
2550
|
}
|
|
2551
|
+
if (this.candidates.peek()) {
|
|
2552
|
+
const nextNode = this.candidates.peek();
|
|
2553
|
+
graphics.rects.push({
|
|
2554
|
+
center: {
|
|
2555
|
+
x: nextNode.x + nextNode.z * this.cellStep / 20,
|
|
2556
|
+
y: nextNode.y + nextNode.z * this.cellStep / 20
|
|
2557
|
+
},
|
|
2558
|
+
fill: "rgba(0, 255, 0, 0.8)",
|
|
2559
|
+
width: this.cellStep * 0.9,
|
|
2560
|
+
height: this.cellStep * 0.9,
|
|
2561
|
+
label: `Next (z=${nextNode.z})`
|
|
2562
|
+
});
|
|
2563
|
+
}
|
|
2471
2564
|
for (const route of this.obstacleRoutes) {
|
|
2472
2565
|
for (const via of route.vias) {
|
|
2473
2566
|
graphics.circles.push({
|
|
@@ -3922,14 +4015,14 @@ function distance2(p1, p2) {
|
|
|
3922
4015
|
}
|
|
3923
4016
|
|
|
3924
4017
|
// lib/solvers/HighDensitySolver/TwoRouteHighDensitySolver/calculateSideTraversal.ts
|
|
3925
|
-
var
|
|
4018
|
+
var EPSILON2 = 1e-9;
|
|
3926
4019
|
function calculateSegmentTraversal(startPoint, endPoint, bounds) {
|
|
3927
4020
|
const startAngle = pointToAngle(startPoint, bounds);
|
|
3928
4021
|
let endAngle = pointToAngle(endPoint, bounds);
|
|
3929
4022
|
if (endAngle < startAngle) {
|
|
3930
4023
|
endAngle += 2 * Math.PI;
|
|
3931
4024
|
}
|
|
3932
|
-
if (Math.abs(endAngle - startAngle) <
|
|
4025
|
+
if (Math.abs(endAngle - startAngle) < EPSILON2) {
|
|
3933
4026
|
return { left: 0, top: 0, right: 0, bottom: 0 };
|
|
3934
4027
|
}
|
|
3935
4028
|
return calculateSidePercentages(startAngle, endAngle, bounds);
|
|
@@ -3944,7 +4037,7 @@ function calculateTraversalPercentages(A, B, C, bounds) {
|
|
|
3944
4037
|
bottom: Math.min(1, percentagesAB.bottom + percentagesBC.bottom)
|
|
3945
4038
|
};
|
|
3946
4039
|
for (const key in totalPercentages) {
|
|
3947
|
-
if (Math.abs(totalPercentages[key]) <
|
|
4040
|
+
if (Math.abs(totalPercentages[key]) < EPSILON2) {
|
|
3948
4041
|
totalPercentages[key] = 0;
|
|
3949
4042
|
}
|
|
3950
4043
|
}
|
|
@@ -3953,17 +4046,17 @@ function calculateTraversalPercentages(A, B, C, bounds) {
|
|
|
3953
4046
|
function pointToAngle(point, bounds) {
|
|
3954
4047
|
const width = bounds.maxX - bounds.minX;
|
|
3955
4048
|
const height = bounds.maxY - bounds.minY;
|
|
3956
|
-
if (width <
|
|
4049
|
+
if (width < EPSILON2 && height < EPSILON2) return 0;
|
|
3957
4050
|
const perimeter = 2 * (width + height);
|
|
3958
|
-
if (perimeter <
|
|
4051
|
+
if (perimeter < EPSILON2) return 0;
|
|
3959
4052
|
let distance6 = 0;
|
|
3960
|
-
if (Math.abs(point.y - bounds.maxY) <
|
|
4053
|
+
if (Math.abs(point.y - bounds.maxY) < EPSILON2 && point.x >= bounds.minX - EPSILON2 && point.x <= bounds.maxX + EPSILON2) {
|
|
3961
4054
|
distance6 = Math.max(0, Math.min(width, point.x - bounds.minX));
|
|
3962
|
-
} else if (Math.abs(point.x - bounds.maxX) <
|
|
4055
|
+
} else if (Math.abs(point.x - bounds.maxX) < EPSILON2 && point.y >= bounds.minY - EPSILON2 && point.y <= bounds.maxY + EPSILON2) {
|
|
3963
4056
|
distance6 = width + Math.max(0, Math.min(height, bounds.maxY - point.y));
|
|
3964
|
-
} else if (Math.abs(point.y - bounds.minY) <
|
|
4057
|
+
} else if (Math.abs(point.y - bounds.minY) < EPSILON2 && point.x >= bounds.minX - EPSILON2 && point.x <= bounds.maxX + EPSILON2) {
|
|
3965
4058
|
distance6 = width + height + Math.max(0, Math.min(width, bounds.maxX - point.x));
|
|
3966
|
-
} else if (Math.abs(point.x - bounds.minX) <
|
|
4059
|
+
} else if (Math.abs(point.x - bounds.minX) < EPSILON2 && point.y >= bounds.minY - EPSILON2 && point.y <= bounds.maxY + EPSILON2) {
|
|
3967
4060
|
distance6 = width + height + width + Math.max(0, Math.min(height, point.y - bounds.minY));
|
|
3968
4061
|
} else {
|
|
3969
4062
|
throw new Error(
|
|
@@ -3971,15 +4064,15 @@ function pointToAngle(point, bounds) {
|
|
|
3971
4064
|
);
|
|
3972
4065
|
}
|
|
3973
4066
|
distance6 = Math.max(0, Math.min(perimeter, distance6));
|
|
3974
|
-
return perimeter >
|
|
4067
|
+
return perimeter > EPSILON2 ? distance6 / perimeter * (2 * Math.PI) : 0;
|
|
3975
4068
|
}
|
|
3976
4069
|
function calculateSidePercentages(startAngle, endAngle, bounds) {
|
|
3977
4070
|
const width = bounds.maxX - bounds.minX;
|
|
3978
4071
|
const height = bounds.maxY - bounds.minY;
|
|
3979
|
-
if (width <
|
|
4072
|
+
if (width < EPSILON2 && height < EPSILON2)
|
|
3980
4073
|
return { left: 0, top: 0, right: 0, bottom: 0 };
|
|
3981
4074
|
const perimeter = 2 * (width + height);
|
|
3982
|
-
if (perimeter <
|
|
4075
|
+
if (perimeter < EPSILON2) return { left: 0, top: 0, right: 0, bottom: 0 };
|
|
3983
4076
|
const angleTopEnd = width / perimeter * (2 * Math.PI);
|
|
3984
4077
|
const angleRightEnd = (width + height) / perimeter * (2 * Math.PI);
|
|
3985
4078
|
const angleBottomEnd = (width + width + height) / perimeter * (2 * Math.PI);
|
|
@@ -3998,13 +4091,13 @@ function calculateSidePercentages(startAngle, endAngle, bounds) {
|
|
|
3998
4091
|
];
|
|
3999
4092
|
const result = { left: 0, top: 0, right: 0, bottom: 0 };
|
|
4000
4093
|
const totalAngleTraversal = endAngle - startAngle;
|
|
4001
|
-
if (totalAngleTraversal <
|
|
4094
|
+
if (totalAngleTraversal < EPSILON2) return result;
|
|
4002
4095
|
for (const side of sides) {
|
|
4003
4096
|
const sideAngleRange = side.end - side.start;
|
|
4004
|
-
if (sideAngleRange <
|
|
4097
|
+
if (sideAngleRange < EPSILON2 || side.length < EPSILON2) continue;
|
|
4005
4098
|
const overlapStart = Math.max(startAngle, side.start);
|
|
4006
4099
|
const overlapEnd = Math.min(endAngle, side.end);
|
|
4007
|
-
if (overlapStart < overlapEnd -
|
|
4100
|
+
if (overlapStart < overlapEnd - EPSILON2) {
|
|
4008
4101
|
const traversedAngleOnSide = overlapEnd - overlapStart;
|
|
4009
4102
|
const percentage = traversedAngleOnSide / sideAngleRange;
|
|
4010
4103
|
result[side.name] += Math.max(0, percentage);
|
|
@@ -5389,6 +5482,7 @@ var convertSrjToGraphicsObject = (srj) => {
|
|
|
5389
5482
|
const circles = [];
|
|
5390
5483
|
const points = [];
|
|
5391
5484
|
const colorMap = getColorMap(srj);
|
|
5485
|
+
const layerCount = 2;
|
|
5392
5486
|
if (srj.connections) {
|
|
5393
5487
|
for (const connection of srj.connections) {
|
|
5394
5488
|
for (const point of connection.pointsToConnect) {
|
|
@@ -5396,6 +5490,7 @@ var convertSrjToGraphicsObject = (srj) => {
|
|
|
5396
5490
|
x: point.x,
|
|
5397
5491
|
y: point.y,
|
|
5398
5492
|
color: colorMap[connection.name],
|
|
5493
|
+
layer: point.layer ?? ("z" in point ? mapZToLayerName(point.z, layerCount) : "top"),
|
|
5399
5494
|
label: `${connection.name} (${point.layer})`
|
|
5400
5495
|
});
|
|
5401
5496
|
}
|
|
@@ -5412,7 +5507,8 @@ var convertSrjToGraphicsObject = (srj) => {
|
|
|
5412
5507
|
radius: 0.3,
|
|
5413
5508
|
// 0.6 via diameter
|
|
5414
5509
|
fill: "blue",
|
|
5415
|
-
stroke: "none"
|
|
5510
|
+
stroke: "none",
|
|
5511
|
+
layer: "z0,1"
|
|
5416
5512
|
});
|
|
5417
5513
|
} else if (routePoint.route_type === "wire" && nextRoutePoint.route_type === "wire" && nextRoutePoint.layer === routePoint.layer) {
|
|
5418
5514
|
lines.push({
|
|
@@ -5420,6 +5516,7 @@ var convertSrjToGraphicsObject = (srj) => {
|
|
|
5420
5516
|
{ x: routePoint.x, y: routePoint.y },
|
|
5421
5517
|
{ x: nextRoutePoint.x, y: nextRoutePoint.y }
|
|
5422
5518
|
],
|
|
5519
|
+
layer: `z${mapLayerNameToZ(routePoint.layer, layerCount)}`,
|
|
5423
5520
|
strokeWidth: 0.15,
|
|
5424
5521
|
strokeColor: safeTransparentize(
|
|
5425
5522
|
{
|
|
@@ -5443,7 +5540,8 @@ var convertSrjToGraphicsObject = (srj) => {
|
|
|
5443
5540
|
center: o.center,
|
|
5444
5541
|
width: o.width,
|
|
5445
5542
|
height: o.height,
|
|
5446
|
-
fill: "rgba(255,0,0,0.5)"
|
|
5543
|
+
fill: "rgba(255,0,0,0.5)",
|
|
5544
|
+
layer: `z${o.layers.map(mapLayerNameToZ).join(",")}`
|
|
5447
5545
|
})
|
|
5448
5546
|
),
|
|
5449
5547
|
circles,
|
|
@@ -5456,23 +5554,26 @@ var convertSrjToGraphicsObject = (srj) => {
|
|
|
5456
5554
|
function getNodesNearNode(params) {
|
|
5457
5555
|
const { nodeId, nodeIdToSegmentIds, segmentIdToNodeIds, hops } = params;
|
|
5458
5556
|
if (hops === 0) return [nodeId];
|
|
5459
|
-
const
|
|
5460
|
-
const
|
|
5461
|
-
|
|
5462
|
-
const
|
|
5463
|
-
|
|
5464
|
-
|
|
5465
|
-
|
|
5466
|
-
|
|
5467
|
-
|
|
5468
|
-
|
|
5469
|
-
|
|
5470
|
-
|
|
5471
|
-
|
|
5557
|
+
const visitedNodes = /* @__PURE__ */ new Set([nodeId]);
|
|
5558
|
+
const exploreQueue = [{ nodeId, remainingHops: hops }];
|
|
5559
|
+
while (exploreQueue.length > 0) {
|
|
5560
|
+
const { nodeId: node, remainingHops } = exploreQueue.shift();
|
|
5561
|
+
if (remainingHops === 0) continue;
|
|
5562
|
+
const segments = nodeIdToSegmentIds.get(node) || [];
|
|
5563
|
+
for (const segmentId of segments) {
|
|
5564
|
+
const adjacentNodeIds = segmentIdToNodeIds.get(segmentId) || [];
|
|
5565
|
+
for (const adjacentNodeId of adjacentNodeIds) {
|
|
5566
|
+
if (!visitedNodes.has(adjacentNodeId)) {
|
|
5567
|
+
visitedNodes.add(adjacentNodeId);
|
|
5568
|
+
exploreQueue.push({
|
|
5569
|
+
nodeId: adjacentNodeId,
|
|
5570
|
+
remainingHops: remainingHops - 1
|
|
5571
|
+
});
|
|
5572
|
+
}
|
|
5472
5573
|
}
|
|
5473
5574
|
}
|
|
5474
5575
|
}
|
|
5475
|
-
return Array.from(
|
|
5576
|
+
return Array.from(visitedNodes);
|
|
5476
5577
|
}
|
|
5477
5578
|
|
|
5478
5579
|
// lib/solvers/UnravelSolver/createPointModificationsHash.ts
|
|
@@ -6257,7 +6358,7 @@ var getDedupedSegments = (assignedSegments) => {
|
|
|
6257
6358
|
const dedupedSegPointMap = /* @__PURE__ */ new Map();
|
|
6258
6359
|
let highestSegmentId = -1;
|
|
6259
6360
|
for (const seg of assignedSegments) {
|
|
6260
|
-
const segKey = `${seg.start.x}-${seg.start.y}-${seg.end.x}-${seg.end.y}`;
|
|
6361
|
+
const segKey = `${seg.start.x}-${seg.start.y}-${seg.end.x}-${seg.end.y}-${seg.availableZ.join(",")}`;
|
|
6261
6362
|
const existingSeg = dedupedSegPointMap.get(segKey);
|
|
6262
6363
|
if (!existingSeg) {
|
|
6263
6364
|
highestSegmentId++;
|
|
@@ -6271,36 +6372,48 @@ var getDedupedSegments = (assignedSegments) => {
|
|
|
6271
6372
|
return dedupedSegments;
|
|
6272
6373
|
};
|
|
6273
6374
|
|
|
6274
|
-
// lib/
|
|
6275
|
-
var
|
|
6375
|
+
// lib/solvers/UnravelSolver/calculateCrossingProbabilityOfFailure.ts
|
|
6376
|
+
var calculateNodeProbabilityOfFailure = (node, numSameLayerCrossings, numEntryExitLayerChanges, numTransitionCrossings) => {
|
|
6377
|
+
if (node?._containsTarget) return 0;
|
|
6378
|
+
const totalCapacity = getTunedTotalCapacity1(node);
|
|
6379
|
+
const estNumVias = numSameLayerCrossings * 0.82 + numEntryExitLayerChanges * 0.41 + numTransitionCrossings * 0.2;
|
|
6380
|
+
const estUsedCapacity = (estNumVias / 2) ** 1.1;
|
|
6381
|
+
const approxProb = estUsedCapacity / totalCapacity;
|
|
6382
|
+
return approxProb;
|
|
6383
|
+
};
|
|
6384
|
+
|
|
6385
|
+
// lib/utils/getIntraNodeCrossingsFromSegmentPoints.ts
|
|
6386
|
+
var getIntraNodeCrossingsFromSegmentPoints = (segmentPoints) => {
|
|
6276
6387
|
let numSameLayerCrossings = 0;
|
|
6277
|
-
const pointPairs = [];
|
|
6278
|
-
const transitionPairPoints = [];
|
|
6279
6388
|
let numEntryExitLayerChanges = 0;
|
|
6280
|
-
|
|
6281
|
-
|
|
6282
|
-
|
|
6283
|
-
|
|
6284
|
-
|
|
6285
|
-
if (transitionPairPoints.some((p) => p.connectionName === aConnName)) {
|
|
6286
|
-
continue;
|
|
6389
|
+
let numTransitionCrossings = 0;
|
|
6390
|
+
const connectionGroups = /* @__PURE__ */ new Map();
|
|
6391
|
+
for (const point of segmentPoints) {
|
|
6392
|
+
if (!connectionGroups.has(point.connectionName)) {
|
|
6393
|
+
connectionGroups.set(point.connectionName, []);
|
|
6287
6394
|
}
|
|
6288
|
-
|
|
6289
|
-
|
|
6290
|
-
|
|
6291
|
-
|
|
6292
|
-
|
|
6293
|
-
|
|
6294
|
-
|
|
6295
|
-
|
|
6296
|
-
|
|
6297
|
-
|
|
6395
|
+
connectionGroups.get(point.connectionName).push(point);
|
|
6396
|
+
}
|
|
6397
|
+
const pointPairs = [];
|
|
6398
|
+
const transitionPairPoints = [];
|
|
6399
|
+
for (const [connectionName, points] of connectionGroups.entries()) {
|
|
6400
|
+
if (points.length < 2) continue;
|
|
6401
|
+
const firstPoint = points[0];
|
|
6402
|
+
for (let i = 1; i < points.length; i++) {
|
|
6403
|
+
const secondPoint = points[i];
|
|
6404
|
+
const pointPair = {
|
|
6405
|
+
connectionName,
|
|
6406
|
+
z: firstPoint.z,
|
|
6407
|
+
points: [firstPoint, secondPoint]
|
|
6408
|
+
};
|
|
6409
|
+
if (firstPoint.z !== secondPoint.z) {
|
|
6298
6410
|
numEntryExitLayerChanges++;
|
|
6299
|
-
transitionPairPoints.push(
|
|
6300
|
-
|
|
6411
|
+
transitionPairPoints.push({
|
|
6412
|
+
connectionName,
|
|
6413
|
+
points: [firstPoint, secondPoint]
|
|
6414
|
+
});
|
|
6301
6415
|
} else {
|
|
6302
6416
|
pointPairs.push(pointPair);
|
|
6303
|
-
break;
|
|
6304
6417
|
}
|
|
6305
6418
|
}
|
|
6306
6419
|
}
|
|
@@ -6318,7 +6431,6 @@ var getIntraNodeCrossingsFromSegments = (segments) => {
|
|
|
6318
6431
|
}
|
|
6319
6432
|
}
|
|
6320
6433
|
}
|
|
6321
|
-
let numTransitionCrossings = 0;
|
|
6322
6434
|
for (let i = 0; i < transitionPairPoints.length; i++) {
|
|
6323
6435
|
for (let j = i + 1; j < transitionPairPoints.length; j++) {
|
|
6324
6436
|
const pair1 = transitionPairPoints[i];
|
|
@@ -6354,16 +6466,6 @@ var getIntraNodeCrossingsFromSegments = (segments) => {
|
|
|
6354
6466
|
};
|
|
6355
6467
|
};
|
|
6356
6468
|
|
|
6357
|
-
// lib/solvers/UnravelSolver/calculateCrossingProbabilityOfFailure.ts
|
|
6358
|
-
var calculateNodeProbabilityOfFailure = (node, numSameLayerCrossings, numEntryExitLayerChanges, numTransitionCrossings) => {
|
|
6359
|
-
if (node?._containsTarget) return 0;
|
|
6360
|
-
const totalCapacity = getTunedTotalCapacity1(node);
|
|
6361
|
-
const estNumVias = numSameLayerCrossings * 0.82 + numEntryExitLayerChanges * 0.41 + numTransitionCrossings * 0.2;
|
|
6362
|
-
const estUsedCapacity = (estNumVias / 2) ** 1.1;
|
|
6363
|
-
const approxProb = estUsedCapacity / totalCapacity;
|
|
6364
|
-
return approxProb;
|
|
6365
|
-
};
|
|
6366
|
-
|
|
6367
6469
|
// lib/solvers/UnravelSolver/UnravelMultiSectionSolver.ts
|
|
6368
6470
|
var UnravelMultiSectionSolver = class extends BaseSolver {
|
|
6369
6471
|
nodeMap;
|
|
@@ -6437,8 +6539,10 @@ var UnravelMultiSectionSolver = class extends BaseSolver {
|
|
|
6437
6539
|
numSameLayerCrossings,
|
|
6438
6540
|
numEntryExitLayerChanges,
|
|
6439
6541
|
numTransitionCrossings
|
|
6440
|
-
} =
|
|
6441
|
-
this.
|
|
6542
|
+
} = getIntraNodeCrossingsFromSegmentPoints(
|
|
6543
|
+
(this.nodeToSegmentPointMap.get(node.capacityMeshNodeId) ?? []).map(
|
|
6544
|
+
(segPointId) => this.segmentPointMap.get(segPointId)
|
|
6545
|
+
)
|
|
6442
6546
|
);
|
|
6443
6547
|
const probabilityOfFailure = calculateNodeProbabilityOfFailure(
|
|
6444
6548
|
node,
|
|
@@ -6501,12 +6605,18 @@ var UnravelMultiSectionSolver = class extends BaseSolver {
|
|
|
6501
6605
|
segmentPoint.y = pointModification.y ?? segmentPoint.y;
|
|
6502
6606
|
segmentPoint.z = pointModification.z ?? segmentPoint.z;
|
|
6503
6607
|
}
|
|
6504
|
-
|
|
6505
|
-
|
|
6506
|
-
|
|
6507
|
-
|
|
6508
|
-
this.
|
|
6509
|
-
);
|
|
6608
|
+
const possiblyImpactedNodeIds = getNodesNearNode({
|
|
6609
|
+
hops: this.activeSolver.MUTABLE_HOPS + 2,
|
|
6610
|
+
nodeId: this.activeSolver.rootNodeId,
|
|
6611
|
+
nodeIdToSegmentIds: this.nodeIdToSegmentIds,
|
|
6612
|
+
segmentIdToNodeIds: this.segmentIdToNodeIds
|
|
6613
|
+
});
|
|
6614
|
+
for (const nodeId of possiblyImpactedNodeIds) {
|
|
6615
|
+
this.nodePfMap.set(
|
|
6616
|
+
nodeId,
|
|
6617
|
+
this.computeNodePf(this.nodeMap.get(nodeId))
|
|
6618
|
+
);
|
|
6619
|
+
}
|
|
6510
6620
|
}
|
|
6511
6621
|
this.activeSolver = null;
|
|
6512
6622
|
}
|
|
@@ -7337,7 +7447,7 @@ var CapacityNodeTree = class {
|
|
|
7337
7447
|
};
|
|
7338
7448
|
|
|
7339
7449
|
// lib/solvers/SingleLayerNodeMerger/SingleLayerNodeMergerSolver.ts
|
|
7340
|
-
var
|
|
7450
|
+
var EPSILON3 = 5e-3;
|
|
7341
7451
|
var SingleLayerNodeMergerSolver = class extends BaseSolver {
|
|
7342
7452
|
nodeMap;
|
|
7343
7453
|
currentBatchNodeIds;
|
|
@@ -7496,7 +7606,7 @@ var SingleLayerNodeMergerSolver = class extends BaseSolver {
|
|
|
7496
7606
|
adjacentNodesToLeft.reduce((acc, adjNode) => {
|
|
7497
7607
|
return acc + adjNode.height;
|
|
7498
7608
|
}, 0) - rootNode.height
|
|
7499
|
-
) <
|
|
7609
|
+
) < EPSILON3;
|
|
7500
7610
|
if (leftAdjNodesTakeUpEntireHeight && leftAdjNodesAreAllSameSize) {
|
|
7501
7611
|
rootNode.width += leftAdjNodeWidth;
|
|
7502
7612
|
rootNode.center.x = rootNode.center.x - leftAdjNodeWidth / 2;
|
|
@@ -7516,7 +7626,7 @@ var SingleLayerNodeMergerSolver = class extends BaseSolver {
|
|
|
7516
7626
|
adjacentNodesToRight.reduce((acc, adjNode) => {
|
|
7517
7627
|
return acc + adjNode.height;
|
|
7518
7628
|
}, 0) - rootNode.height
|
|
7519
|
-
) <
|
|
7629
|
+
) < EPSILON3;
|
|
7520
7630
|
if (rightAdjNodesTakeUpEntireHeight && rightAdjNodesAreAllSameSize) {
|
|
7521
7631
|
rootNode.width += rightAdjNodeWidth;
|
|
7522
7632
|
rootNode.center.x = rootNode.center.x + rightAdjNodeWidth / 2;
|
|
@@ -7536,7 +7646,7 @@ var SingleLayerNodeMergerSolver = class extends BaseSolver {
|
|
|
7536
7646
|
adjacentNodesToTop.reduce((acc, adjNode) => {
|
|
7537
7647
|
return acc + adjNode.width;
|
|
7538
7648
|
}, 0) - rootNode.width
|
|
7539
|
-
) <
|
|
7649
|
+
) < EPSILON3;
|
|
7540
7650
|
if (topAdjNodesTakeUpEntireWidth && topAdjNodesAreAllSameSize) {
|
|
7541
7651
|
rootNode.height += topAdjNodeHeight;
|
|
7542
7652
|
rootNode.center.y = rootNode.center.y + topAdjNodeHeight / 2;
|
|
@@ -7556,7 +7666,7 @@ var SingleLayerNodeMergerSolver = class extends BaseSolver {
|
|
|
7556
7666
|
adjacentNodesToBottom.reduce((acc, adjNode) => {
|
|
7557
7667
|
return acc + adjNode.width;
|
|
7558
7668
|
}, 0) - rootNode.width
|
|
7559
|
-
) <
|
|
7669
|
+
) < EPSILON3;
|
|
7560
7670
|
if (bottomAdjNodesTakeUpEntireWidth && bottomAdjNodesAreAllSameSize) {
|
|
7561
7671
|
rootNode.height += bottomAdjNodeHeight;
|
|
7562
7672
|
rootNode.center.y = rootNode.center.y - bottomAdjNodeHeight / 2;
|
|
@@ -7750,6 +7860,14 @@ var SingleSimplifiedPathSolver = class extends BaseSolver {
|
|
|
7750
7860
|
});
|
|
7751
7861
|
}
|
|
7752
7862
|
}
|
|
7863
|
+
if ("filteredObstaclePathSegments" in this) {
|
|
7864
|
+
const filteredObstaclePathSegments = this.filteredObstaclePathSegments;
|
|
7865
|
+
for (const [start, end] of filteredObstaclePathSegments) {
|
|
7866
|
+
graphics.lines.push({
|
|
7867
|
+
points: [start, end]
|
|
7868
|
+
});
|
|
7869
|
+
}
|
|
7870
|
+
}
|
|
7753
7871
|
return graphics;
|
|
7754
7872
|
}
|
|
7755
7873
|
};
|
|
@@ -7854,23 +7972,33 @@ var getSegmentBounds = (segment) => {
|
|
|
7854
7972
|
};
|
|
7855
7973
|
};
|
|
7856
7974
|
var SegmentTree = class {
|
|
7975
|
+
// traceThickness + obstacleMargin
|
|
7857
7976
|
constructor(segments) {
|
|
7858
7977
|
this.segments = segments;
|
|
7859
7978
|
this.buckets = /* @__PURE__ */ new Map();
|
|
7979
|
+
const segmentsById = /* @__PURE__ */ new Map();
|
|
7860
7980
|
for (const segment of segments) {
|
|
7981
|
+
const segmentKey = this.getSegmentKey(segment);
|
|
7982
|
+
if (segmentsById.has(segmentKey)) continue;
|
|
7983
|
+
segmentsById.set(segmentKey, segment);
|
|
7861
7984
|
const bounds = getSegmentBounds(segment);
|
|
7862
|
-
const
|
|
7863
|
-
const
|
|
7864
|
-
|
|
7865
|
-
|
|
7866
|
-
|
|
7985
|
+
const minIndexX = Math.floor(bounds.minX / this.CELL_SIZE);
|
|
7986
|
+
const maxIndexX = Math.floor(bounds.maxX / this.CELL_SIZE);
|
|
7987
|
+
const minIndexY = Math.floor(bounds.minY / this.CELL_SIZE);
|
|
7988
|
+
const maxIndexY = Math.floor(bounds.maxY / this.CELL_SIZE);
|
|
7989
|
+
for (let ix = minIndexX; ix <= maxIndexX; ix++) {
|
|
7990
|
+
for (let iy = minIndexY; iy <= maxIndexY; iy++) {
|
|
7991
|
+
const bucketKey = `${ix}x${iy}`;
|
|
7867
7992
|
const bucket = this.buckets.get(bucketKey);
|
|
7993
|
+
const segmentWithId = [
|
|
7994
|
+
segment[0],
|
|
7995
|
+
segment[1],
|
|
7996
|
+
segmentKey
|
|
7997
|
+
];
|
|
7868
7998
|
if (!bucket) {
|
|
7869
|
-
this.buckets.set(bucketKey, [
|
|
7870
|
-
[segment[0], segment[1], this.getSegmentKey(segment)]
|
|
7871
|
-
]);
|
|
7999
|
+
this.buckets.set(bucketKey, [segmentWithId]);
|
|
7872
8000
|
} else {
|
|
7873
|
-
bucket.push(
|
|
8001
|
+
bucket.push(segmentWithId);
|
|
7874
8002
|
}
|
|
7875
8003
|
}
|
|
7876
8004
|
}
|
|
@@ -7878,7 +8006,7 @@ var SegmentTree = class {
|
|
|
7878
8006
|
}
|
|
7879
8007
|
buckets;
|
|
7880
8008
|
CELL_SIZE = 0.4;
|
|
7881
|
-
SEGMENT_MARGIN = 0.
|
|
8009
|
+
SEGMENT_MARGIN = 0.4;
|
|
7882
8010
|
getBucketKey(x, y) {
|
|
7883
8011
|
return `${Math.floor(x / this.CELL_SIZE)}x${Math.floor(y / this.CELL_SIZE)}`;
|
|
7884
8012
|
}
|
|
@@ -7892,17 +8020,22 @@ var SegmentTree = class {
|
|
|
7892
8020
|
const minY = Math.min(A.y, B.y) - this.SEGMENT_MARGIN;
|
|
7893
8021
|
const maxX = Math.max(A.x, B.x) + this.SEGMENT_MARGIN;
|
|
7894
8022
|
const maxY = Math.max(A.y, B.y) + this.SEGMENT_MARGIN;
|
|
7895
|
-
const
|
|
7896
|
-
const
|
|
7897
|
-
|
|
7898
|
-
|
|
7899
|
-
|
|
7900
|
-
|
|
7901
|
-
|
|
7902
|
-
|
|
7903
|
-
|
|
7904
|
-
|
|
7905
|
-
|
|
8023
|
+
const minIndexX = Math.floor(minX / this.CELL_SIZE);
|
|
8024
|
+
const maxIndexX = Math.floor(maxX / this.CELL_SIZE);
|
|
8025
|
+
const minIndexY = Math.floor(minY / this.CELL_SIZE);
|
|
8026
|
+
const maxIndexY = Math.floor(maxY / this.CELL_SIZE);
|
|
8027
|
+
for (let ix = minIndexX; ix <= maxIndexX; ix++) {
|
|
8028
|
+
for (let iy = minIndexY; iy <= maxIndexY; iy++) {
|
|
8029
|
+
const bucketKey = `${ix}x${iy}`;
|
|
8030
|
+
const bucket = this.buckets.get(bucketKey);
|
|
8031
|
+
if (bucket) {
|
|
8032
|
+
for (const segment of bucket) {
|
|
8033
|
+
const key = segment[2];
|
|
8034
|
+
if (!alreadyAddedSegments.has(key)) {
|
|
8035
|
+
alreadyAddedSegments.add(key);
|
|
8036
|
+
segments.push(segment);
|
|
8037
|
+
}
|
|
8038
|
+
}
|
|
7906
8039
|
}
|
|
7907
8040
|
}
|
|
7908
8041
|
}
|