@tscircuit/capacity-autorouter 0.0.28 → 0.0.30
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 +13 -3
- package/dist/index.js +643 -309
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -85,176 +85,6 @@ var BaseSolver = class {
|
|
|
85
85
|
}
|
|
86
86
|
};
|
|
87
87
|
|
|
88
|
-
// node_modules/@tscircuit/math-utils/dist/chunk-CHQOCSFB.js
|
|
89
|
-
function doSegmentsIntersect(p1, q1, p2, q2) {
|
|
90
|
-
const o1 = orientation(p1, q1, p2);
|
|
91
|
-
const o2 = orientation(p1, q1, q2);
|
|
92
|
-
const o3 = orientation(p2, q2, p1);
|
|
93
|
-
const o4 = orientation(p2, q2, q1);
|
|
94
|
-
if (o1 !== o2 && o3 !== o4) {
|
|
95
|
-
return true;
|
|
96
|
-
}
|
|
97
|
-
if (o1 === 0 && onSegment(p1, p2, q1)) return true;
|
|
98
|
-
if (o2 === 0 && onSegment(p1, q2, q1)) return true;
|
|
99
|
-
if (o3 === 0 && onSegment(p2, p1, q2)) return true;
|
|
100
|
-
if (o4 === 0 && onSegment(p2, q1, q2)) return true;
|
|
101
|
-
return false;
|
|
102
|
-
}
|
|
103
|
-
function orientation(p, q, r) {
|
|
104
|
-
const val = (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y);
|
|
105
|
-
if (val === 0) return 0;
|
|
106
|
-
return val > 0 ? 1 : 2;
|
|
107
|
-
}
|
|
108
|
-
function onSegment(p, q, r) {
|
|
109
|
-
return q.x <= Math.max(p.x, r.x) && q.x >= Math.min(p.x, r.x) && q.y <= Math.max(p.y, r.y) && q.y >= Math.min(p.y, r.y);
|
|
110
|
-
}
|
|
111
|
-
function pointToSegmentDistance(p, v, w) {
|
|
112
|
-
const l2 = (w.x - v.x) ** 2 + (w.y - v.y) ** 2;
|
|
113
|
-
if (l2 === 0) return distance(p, v);
|
|
114
|
-
let t = ((p.x - v.x) * (w.x - v.x) + (p.y - v.y) * (w.y - v.y)) / l2;
|
|
115
|
-
t = Math.max(0, Math.min(1, t));
|
|
116
|
-
const projection = {
|
|
117
|
-
x: v.x + t * (w.x - v.x),
|
|
118
|
-
y: v.y + t * (w.y - v.y)
|
|
119
|
-
};
|
|
120
|
-
return distance(p, projection);
|
|
121
|
-
}
|
|
122
|
-
function distance(p1, p2) {
|
|
123
|
-
const dx = p1.x - p2.x;
|
|
124
|
-
const dy = p1.y - p2.y;
|
|
125
|
-
return Math.sqrt(dx * dx + dy * dy);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
// lib/utils/areNodesBordering.ts
|
|
129
|
-
function areNodesBordering(node1, node2) {
|
|
130
|
-
const n1Left = node1.center.x - node1.width / 2;
|
|
131
|
-
const n1Right = node1.center.x + node1.width / 2;
|
|
132
|
-
const n1Top = node1.center.y - node1.height / 2;
|
|
133
|
-
const n1Bottom = node1.center.y + node1.height / 2;
|
|
134
|
-
const n2Left = node2.center.x - node2.width / 2;
|
|
135
|
-
const n2Right = node2.center.x + node2.width / 2;
|
|
136
|
-
const n2Top = node2.center.y - node2.height / 2;
|
|
137
|
-
const n2Bottom = node2.center.y + node2.height / 2;
|
|
138
|
-
const epsilon = 1e-3;
|
|
139
|
-
const shareVerticalBorder = (Math.abs(n1Right - n2Left) < epsilon || Math.abs(n1Left - n2Right) < epsilon) && Math.min(n1Bottom, n2Bottom) - Math.max(n1Top, n2Top) >= epsilon;
|
|
140
|
-
const shareHorizontalBorder = (Math.abs(n1Bottom - n2Top) < epsilon || Math.abs(n1Top - n2Bottom) < epsilon) && Math.min(n1Right, n2Right) - Math.max(n1Left, n2Left) >= epsilon;
|
|
141
|
-
return shareVerticalBorder || shareHorizontalBorder;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
// lib/solvers/CapacityMeshSolver/CapacityMeshEdgeSolver.ts
|
|
145
|
-
var CapacityMeshEdgeSolver = class extends BaseSolver {
|
|
146
|
-
constructor(nodes) {
|
|
147
|
-
super();
|
|
148
|
-
this.nodes = nodes;
|
|
149
|
-
this.edges = [];
|
|
150
|
-
}
|
|
151
|
-
edges;
|
|
152
|
-
getNextCapacityMeshEdgeId() {
|
|
153
|
-
return `ce${this.edges.length}`;
|
|
154
|
-
}
|
|
155
|
-
step() {
|
|
156
|
-
this.edges = [];
|
|
157
|
-
for (let i = 0; i < this.nodes.length; i++) {
|
|
158
|
-
for (let j = i + 1; j < this.nodes.length; j++) {
|
|
159
|
-
if (!(this.nodes[i]._strawNode && this.nodes[j]._strawNode) && areNodesBordering(this.nodes[i], this.nodes[j]) && this.doNodesHaveSharedLayer(this.nodes[i], this.nodes[j])) {
|
|
160
|
-
this.edges.push({
|
|
161
|
-
capacityMeshEdgeId: this.getNextCapacityMeshEdgeId(),
|
|
162
|
-
nodeIds: [
|
|
163
|
-
this.nodes[i].capacityMeshNodeId,
|
|
164
|
-
this.nodes[j].capacityMeshNodeId
|
|
165
|
-
]
|
|
166
|
-
});
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
const targetNodes = this.nodes.filter((node) => node._containsTarget);
|
|
171
|
-
for (const targetNode of targetNodes) {
|
|
172
|
-
const hasEdge = this.edges.some(
|
|
173
|
-
(edge) => edge.nodeIds.includes(targetNode.capacityMeshNodeId)
|
|
174
|
-
);
|
|
175
|
-
if (hasEdge) continue;
|
|
176
|
-
let nearestNode = null;
|
|
177
|
-
let nearestDistance = Infinity;
|
|
178
|
-
for (const node of this.nodes) {
|
|
179
|
-
if (node._containsObstacle) continue;
|
|
180
|
-
if (node._containsTarget) continue;
|
|
181
|
-
const dist = distance(targetNode.center, node.center);
|
|
182
|
-
if (dist < nearestDistance) {
|
|
183
|
-
nearestDistance = dist;
|
|
184
|
-
nearestNode = node;
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
if (nearestNode) {
|
|
188
|
-
this.edges.push({
|
|
189
|
-
capacityMeshEdgeId: this.getNextCapacityMeshEdgeId(),
|
|
190
|
-
nodeIds: [
|
|
191
|
-
targetNode.capacityMeshNodeId,
|
|
192
|
-
nearestNode.capacityMeshNodeId
|
|
193
|
-
]
|
|
194
|
-
});
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
this.solved = true;
|
|
198
|
-
}
|
|
199
|
-
doNodesHaveSharedLayer(node1, node2) {
|
|
200
|
-
return node1.availableZ.some((z) => node2.availableZ.includes(z));
|
|
201
|
-
}
|
|
202
|
-
visualize() {
|
|
203
|
-
const graphics = {
|
|
204
|
-
lines: [],
|
|
205
|
-
points: [],
|
|
206
|
-
rects: this.nodes.map((node) => {
|
|
207
|
-
const lowestZ = Math.min(...node.availableZ);
|
|
208
|
-
return {
|
|
209
|
-
width: Math.max(node.width - 2, node.width * 0.8),
|
|
210
|
-
height: Math.max(node.height - 2, node.height * 0.8),
|
|
211
|
-
center: {
|
|
212
|
-
x: node.center.x + lowestZ * node.width * 0.05,
|
|
213
|
-
y: node.center.y - lowestZ * node.width * 0.05
|
|
214
|
-
},
|
|
215
|
-
fill: node._containsObstacle ? "rgba(255,0,0,0.1)" : {
|
|
216
|
-
"0,1": "rgba(0,0,0,0.1)",
|
|
217
|
-
"0": "rgba(0,200,200, 0.1)",
|
|
218
|
-
"1": "rgba(0,0,200, 0.1)"
|
|
219
|
-
}[node.availableZ.join(",")] ?? "rgba(0,200,200,0.1)",
|
|
220
|
-
label: [
|
|
221
|
-
node.capacityMeshNodeId,
|
|
222
|
-
`availableZ: ${node.availableZ.join(",")}`,
|
|
223
|
-
`target? ${node._containsTarget ?? false}`,
|
|
224
|
-
`obs? ${node._containsObstacle ?? false}`
|
|
225
|
-
].join("\n")
|
|
226
|
-
};
|
|
227
|
-
}),
|
|
228
|
-
circles: []
|
|
229
|
-
};
|
|
230
|
-
for (const edge of this.edges) {
|
|
231
|
-
const node1 = this.nodes.find(
|
|
232
|
-
(node) => node.capacityMeshNodeId === edge.nodeIds[0]
|
|
233
|
-
);
|
|
234
|
-
const node2 = this.nodes.find(
|
|
235
|
-
(node) => node.capacityMeshNodeId === edge.nodeIds[1]
|
|
236
|
-
);
|
|
237
|
-
if (node1?.center && node2?.center) {
|
|
238
|
-
const lowestZ1 = Math.min(...node1.availableZ);
|
|
239
|
-
const lowestZ2 = Math.min(...node2.availableZ);
|
|
240
|
-
const nodeCenter1Adj = {
|
|
241
|
-
x: node1.center.x + lowestZ1 * node1.width * 0.05,
|
|
242
|
-
y: node1.center.y - lowestZ1 * node1.width * 0.05
|
|
243
|
-
};
|
|
244
|
-
const nodeCenter2Adj = {
|
|
245
|
-
x: node2.center.x + lowestZ2 * node2.width * 0.05,
|
|
246
|
-
y: node2.center.y - lowestZ2 * node2.width * 0.05
|
|
247
|
-
};
|
|
248
|
-
graphics.lines.push({
|
|
249
|
-
points: [nodeCenter1Adj, nodeCenter2Adj],
|
|
250
|
-
strokeDash: node1.availableZ.join(",") === node2.availableZ.join(",") ? void 0 : "10 5"
|
|
251
|
-
});
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
return graphics;
|
|
255
|
-
}
|
|
256
|
-
};
|
|
257
|
-
|
|
258
88
|
// node_modules/@babel/runtime/helpers/esm/extends.js
|
|
259
89
|
function _extends() {
|
|
260
90
|
return _extends = Object.assign ? Object.assign.bind() : function(n) {
|
|
@@ -1113,6 +943,29 @@ var mapLayerNameToZ = (layerName, layerCount) => {
|
|
|
1113
943
|
return parseInt(layerName.slice(5));
|
|
1114
944
|
};
|
|
1115
945
|
|
|
946
|
+
// lib/utils/getTunedTotalCapacity1.ts
|
|
947
|
+
var getTunedTotalCapacity1 = (nodeOrWidth, maxCapacityFactor = 1) => {
|
|
948
|
+
const VIA_DIAMETER = 0.6;
|
|
949
|
+
const TRACE_WIDTH = 0.15;
|
|
950
|
+
const obstacleMargin = 0.2;
|
|
951
|
+
const width = "width" in nodeOrWidth ? nodeOrWidth.width : nodeOrWidth;
|
|
952
|
+
const viaLengthAcross = width / (VIA_DIAMETER / 2 + obstacleMargin);
|
|
953
|
+
return (viaLengthAcross / 2) ** 1.1 * maxCapacityFactor;
|
|
954
|
+
};
|
|
955
|
+
var calculateOptimalCapacityDepth = (initialWidth, targetMinCapacity = 0.5, maxDepth = 16) => {
|
|
956
|
+
let depth = 0;
|
|
957
|
+
let width = initialWidth;
|
|
958
|
+
while (depth < maxDepth) {
|
|
959
|
+
const capacity = getTunedTotalCapacity1({ width });
|
|
960
|
+
if (capacity <= targetMinCapacity) {
|
|
961
|
+
break;
|
|
962
|
+
}
|
|
963
|
+
width /= 2;
|
|
964
|
+
depth++;
|
|
965
|
+
}
|
|
966
|
+
return Math.max(1, depth);
|
|
967
|
+
};
|
|
968
|
+
|
|
1116
969
|
// lib/solvers/CapacityMeshSolver/CapacityMeshNodeSolver1.ts
|
|
1117
970
|
var CapacityMeshNodeSolver = class extends BaseSolver {
|
|
1118
971
|
constructor(srj, opts = {}) {
|
|
@@ -1407,7 +1260,9 @@ var CapacityMeshNodeSolver = class extends BaseSolver {
|
|
|
1407
1260
|
node.capacityMeshNodeId,
|
|
1408
1261
|
`availableZ: ${node.availableZ.join(",")}`,
|
|
1409
1262
|
`target? ${node._containsTarget ?? false}`,
|
|
1410
|
-
`obs? ${node._containsObstacle ?? false}
|
|
1263
|
+
`obs? ${node._containsObstacle ?? false}`,
|
|
1264
|
+
`${node.width.toFixed(2)}x${node.height.toFixed(2)}`,
|
|
1265
|
+
`capacity: ${getTunedTotalCapacity1(node).toFixed(2)}`
|
|
1411
1266
|
].join("\n")
|
|
1412
1267
|
});
|
|
1413
1268
|
}
|
|
@@ -1916,6 +1771,46 @@ var CapacitySegmentToPointSolver = class extends BaseSolver {
|
|
|
1916
1771
|
}
|
|
1917
1772
|
};
|
|
1918
1773
|
|
|
1774
|
+
// node_modules/@tscircuit/math-utils/dist/chunk-CHQOCSFB.js
|
|
1775
|
+
function doSegmentsIntersect(p1, q1, p2, q2) {
|
|
1776
|
+
const o1 = orientation(p1, q1, p2);
|
|
1777
|
+
const o2 = orientation(p1, q1, q2);
|
|
1778
|
+
const o3 = orientation(p2, q2, p1);
|
|
1779
|
+
const o4 = orientation(p2, q2, q1);
|
|
1780
|
+
if (o1 !== o2 && o3 !== o4) {
|
|
1781
|
+
return true;
|
|
1782
|
+
}
|
|
1783
|
+
if (o1 === 0 && onSegment(p1, p2, q1)) return true;
|
|
1784
|
+
if (o2 === 0 && onSegment(p1, q2, q1)) return true;
|
|
1785
|
+
if (o3 === 0 && onSegment(p2, p1, q2)) return true;
|
|
1786
|
+
if (o4 === 0 && onSegment(p2, q1, q2)) return true;
|
|
1787
|
+
return false;
|
|
1788
|
+
}
|
|
1789
|
+
function orientation(p, q, r) {
|
|
1790
|
+
const val = (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y);
|
|
1791
|
+
if (val === 0) return 0;
|
|
1792
|
+
return val > 0 ? 1 : 2;
|
|
1793
|
+
}
|
|
1794
|
+
function onSegment(p, q, r) {
|
|
1795
|
+
return q.x <= Math.max(p.x, r.x) && q.x >= Math.min(p.x, r.x) && q.y <= Math.max(p.y, r.y) && q.y >= Math.min(p.y, r.y);
|
|
1796
|
+
}
|
|
1797
|
+
function pointToSegmentDistance(p, v, w) {
|
|
1798
|
+
const l2 = (w.x - v.x) ** 2 + (w.y - v.y) ** 2;
|
|
1799
|
+
if (l2 === 0) return distance(p, v);
|
|
1800
|
+
let t = ((p.x - v.x) * (w.x - v.x) + (p.y - v.y) * (w.y - v.y)) / l2;
|
|
1801
|
+
t = Math.max(0, Math.min(1, t));
|
|
1802
|
+
const projection = {
|
|
1803
|
+
x: v.x + t * (w.x - v.x),
|
|
1804
|
+
y: v.y + t * (w.y - v.y)
|
|
1805
|
+
};
|
|
1806
|
+
return distance(p, projection);
|
|
1807
|
+
}
|
|
1808
|
+
function distance(p1, p2) {
|
|
1809
|
+
const dx = p1.x - p2.x;
|
|
1810
|
+
const dy = p1.y - p2.y;
|
|
1811
|
+
return Math.sqrt(dx * dx + dy * dy);
|
|
1812
|
+
}
|
|
1813
|
+
|
|
1919
1814
|
// lib/solvers/HighDensitySolver/SingleHighDensityRouteSolver.ts
|
|
1920
1815
|
var SingleHighDensityRouteSolver = class extends BaseSolver {
|
|
1921
1816
|
obstacleRoutes;
|
|
@@ -2058,7 +1953,7 @@ var SingleHighDensityRouteSolver = class extends BaseSolver {
|
|
|
2058
1953
|
return false;
|
|
2059
1954
|
}
|
|
2060
1955
|
isNodeTooCloseToEdge(node, isVia) {
|
|
2061
|
-
const margin = isVia ? this.viaDiameter / 2 : this.obstacleMargin;
|
|
1956
|
+
const margin = isVia ? this.viaDiameter / 2 + this.obstacleMargin / 2 : this.obstacleMargin / 2;
|
|
2062
1957
|
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;
|
|
2063
1958
|
if (tooClose && !isVia) {
|
|
2064
1959
|
if (distance(node, this.B) < margin * 2 || distance(node, this.A) < margin * 2) {
|
|
@@ -3134,29 +3029,6 @@ var getConnectivityMapFromSimpleRouteJson = (srj) => {
|
|
|
3134
3029
|
return connMap;
|
|
3135
3030
|
};
|
|
3136
3031
|
|
|
3137
|
-
// lib/utils/getTunedTotalCapacity1.ts
|
|
3138
|
-
var getTunedTotalCapacity1 = (nodeOrWidth, maxCapacityFactor = 1) => {
|
|
3139
|
-
const VIA_DIAMETER = 0.6;
|
|
3140
|
-
const TRACE_WIDTH = 0.15;
|
|
3141
|
-
const obstacleMargin = 0.2;
|
|
3142
|
-
const width = "width" in nodeOrWidth ? nodeOrWidth.width : nodeOrWidth;
|
|
3143
|
-
const viaLengthAcross = width / (VIA_DIAMETER / 2 + obstacleMargin);
|
|
3144
|
-
return (viaLengthAcross / 2) ** 1.1 * maxCapacityFactor;
|
|
3145
|
-
};
|
|
3146
|
-
var calculateOptimalCapacityDepth = (initialWidth, targetMinCapacity = 0.5, maxDepth = 16) => {
|
|
3147
|
-
let depth = 0;
|
|
3148
|
-
let width = initialWidth;
|
|
3149
|
-
while (depth < maxDepth) {
|
|
3150
|
-
const capacity = getTunedTotalCapacity1({ width });
|
|
3151
|
-
if (capacity <= targetMinCapacity) {
|
|
3152
|
-
break;
|
|
3153
|
-
}
|
|
3154
|
-
width /= 2;
|
|
3155
|
-
depth++;
|
|
3156
|
-
}
|
|
3157
|
-
return Math.max(1, depth);
|
|
3158
|
-
};
|
|
3159
|
-
|
|
3160
3032
|
// lib/solvers/NetToPointPairsSolver/buildMinimumSpanningTree.ts
|
|
3161
3033
|
var KDNode = class {
|
|
3162
3034
|
point;
|
|
@@ -3682,6 +3554,7 @@ var MultipleHighDensityRouteStitchSolver = class extends BaseSolver {
|
|
|
3682
3554
|
z: mapLayerNameToZ(c.pointsToConnect[1].layer, opts.layerCount)
|
|
3683
3555
|
}
|
|
3684
3556
|
}));
|
|
3557
|
+
this.MAX_ITERATIONS = 1e5;
|
|
3685
3558
|
}
|
|
3686
3559
|
_step() {
|
|
3687
3560
|
if (this.activeSolver) {
|
|
@@ -4166,16 +4039,16 @@ var UnravelSectionSolver = class extends BaseSolver {
|
|
|
4166
4039
|
segmentPoint.segmentPointId
|
|
4167
4040
|
]);
|
|
4168
4041
|
}
|
|
4169
|
-
for (
|
|
4170
|
-
|
|
4171
|
-
|
|
4172
|
-
|
|
4173
|
-
|
|
4174
|
-
|
|
4175
|
-
|
|
4176
|
-
|
|
4177
|
-
(
|
|
4178
|
-
|
|
4042
|
+
for (const [nodeId, segmentPoints2] of segmentPointsInNode.entries()) {
|
|
4043
|
+
for (let i = 0; i < segmentPoints2.length; i++) {
|
|
4044
|
+
const A = segmentPointMap.get(segmentPoints2[i]);
|
|
4045
|
+
for (let j = i + 1; j < segmentPoints2.length; j++) {
|
|
4046
|
+
const B = segmentPointMap.get(segmentPoints2[j]);
|
|
4047
|
+
if (B.segmentPointId === A.segmentPointId) continue;
|
|
4048
|
+
if (B.segmentId === A.segmentId) continue;
|
|
4049
|
+
if (B.connectionName !== A.connectionName) continue;
|
|
4050
|
+
if (B.directlyConnectedSegmentPointIds.includes(A.segmentPointId))
|
|
4051
|
+
continue;
|
|
4179
4052
|
A.directlyConnectedSegmentPointIds.push(B.segmentPointId);
|
|
4180
4053
|
B.directlyConnectedSegmentPointIds.push(A.segmentPointId);
|
|
4181
4054
|
}
|
|
@@ -5029,9 +4902,9 @@ var UnravelMultiSectionSolver = class extends BaseSolver {
|
|
|
5029
4902
|
var createRectFromCapacityNode = (node, opts = {}) => {
|
|
5030
4903
|
const lowestZ = Math.min(...node.availableZ);
|
|
5031
4904
|
return {
|
|
5032
|
-
center: !opts.rectMargin ? {
|
|
5033
|
-
x: node.center.x + lowestZ * node.width * 0.05,
|
|
5034
|
-
y: node.center.y - lowestZ * node.width * 0.05
|
|
4905
|
+
center: !opts.rectMargin || opts.zOffset ? {
|
|
4906
|
+
x: node.center.x + lowestZ * node.width * (opts.zOffset ?? 0.05),
|
|
4907
|
+
y: node.center.y - lowestZ * node.width * (opts.zOffset ?? 0.05)
|
|
5035
4908
|
} : node.center,
|
|
5036
4909
|
width: opts.rectMargin ? node.width - opts.rectMargin * 2 : Math.max(node.width - 0.5, node.width * 0.8),
|
|
5037
4910
|
height: opts.rectMargin ? node.height - opts.rectMargin * 2 : Math.max(node.height - 0.5, node.height * 0.8),
|
|
@@ -5173,12 +5046,16 @@ var CapacityPathingSolver = class extends BaseSolver {
|
|
|
5173
5046
|
}
|
|
5174
5047
|
return capacityPaths;
|
|
5175
5048
|
}
|
|
5176
|
-
doesNodeHaveCapacityForTrace(node) {
|
|
5049
|
+
doesNodeHaveCapacityForTrace(node, prevNode) {
|
|
5177
5050
|
const usedCapacity = this.usedNodeCapacityMap.get(node.capacityMeshNodeId) ?? 0;
|
|
5178
5051
|
const totalCapacity = this.getTotalCapacity(node);
|
|
5179
5052
|
if (node.availableZ.length === 1 && !node._containsTarget && usedCapacity > 0)
|
|
5180
5053
|
return false;
|
|
5181
|
-
|
|
5054
|
+
let additionalCapacityRequirement = 0;
|
|
5055
|
+
if (node.availableZ.length > 1 && prevNode.availableZ.length === 1) {
|
|
5056
|
+
additionalCapacityRequirement += 0.5;
|
|
5057
|
+
}
|
|
5058
|
+
return usedCapacity + additionalCapacityRequirement < totalCapacity;
|
|
5182
5059
|
}
|
|
5183
5060
|
canTravelThroughObstacle(node, connectionName) {
|
|
5184
5061
|
const goalNodeIds = this.connectionNameToGoalNodeIds.get(connectionName);
|
|
@@ -5246,7 +5123,7 @@ var CapacityPathingSolver = class extends BaseSolver {
|
|
|
5246
5123
|
if (this.visitedNodes?.has(neighborNode.capacityMeshNodeId)) {
|
|
5247
5124
|
continue;
|
|
5248
5125
|
}
|
|
5249
|
-
if (!this.doesNodeHaveCapacityForTrace(neighborNode)) {
|
|
5126
|
+
if (!this.doesNodeHaveCapacityForTrace(neighborNode, currentCandidate.node)) {
|
|
5250
5127
|
continue;
|
|
5251
5128
|
}
|
|
5252
5129
|
const connectionName = this.connectionsWithNodes[this.currentConnectionIndex].connection.name;
|
|
@@ -5285,27 +5162,42 @@ var CapacityPathingSolver = class extends BaseSolver {
|
|
|
5285
5162
|
if (conn.path && conn.path.length > 0) {
|
|
5286
5163
|
const pathPoints = conn.path.map(({ center: { x, y }, width }) => ({
|
|
5287
5164
|
// slight offset to allow viewing overlapping paths
|
|
5288
|
-
x: x + (i % 10 + i % 19) * (
|
|
5289
|
-
y: y + (i % 10 + i % 19) * (
|
|
5165
|
+
x: x + (i % 10 + i % 19) * (5e-3 * width),
|
|
5166
|
+
y: y + (i % 10 + i % 19) * (5e-3 * width)
|
|
5290
5167
|
}));
|
|
5291
5168
|
graphics.lines.push({
|
|
5292
5169
|
points: pathPoints,
|
|
5293
5170
|
strokeColor: this.colorMap[conn.connection.name]
|
|
5294
5171
|
});
|
|
5172
|
+
for (let u = 0; u < pathPoints.length; u++) {
|
|
5173
|
+
const point = pathPoints[u];
|
|
5174
|
+
graphics.points.push({
|
|
5175
|
+
x: point.x,
|
|
5176
|
+
y: point.y,
|
|
5177
|
+
label: [
|
|
5178
|
+
`conn: ${conn.connection.name}`,
|
|
5179
|
+
`node: ${conn.path[u].capacityMeshNodeId}`
|
|
5180
|
+
].join("\n")
|
|
5181
|
+
});
|
|
5182
|
+
}
|
|
5295
5183
|
}
|
|
5296
5184
|
}
|
|
5297
5185
|
}
|
|
5298
5186
|
for (const node of this.nodes) {
|
|
5299
5187
|
const nodeCosts = this.debug_lastNodeCostMap.get(node.capacityMeshNodeId);
|
|
5300
5188
|
graphics.rects.push({
|
|
5301
|
-
...createRectFromCapacityNode(node
|
|
5189
|
+
...createRectFromCapacityNode(node, {
|
|
5190
|
+
rectMargin: 0.025,
|
|
5191
|
+
zOffset: 0.01
|
|
5192
|
+
}),
|
|
5302
5193
|
label: [
|
|
5303
5194
|
`${node.capacityMeshNodeId}`,
|
|
5304
5195
|
`${this.usedNodeCapacityMap.get(node.capacityMeshNodeId)}/${this.getTotalCapacity(node).toFixed(2)}`,
|
|
5305
5196
|
`${node.width.toFixed(2)}x${node.height.toFixed(2)}`,
|
|
5306
5197
|
`g: ${nodeCosts?.g !== void 0 ? nodeCosts.g.toFixed(2) : "?"}`,
|
|
5307
5198
|
`h: ${nodeCosts?.h !== void 0 ? nodeCosts.h.toFixed(2) : "?"}`,
|
|
5308
|
-
`f: ${nodeCosts?.f !== void 0 ? nodeCosts.f.toFixed(2) : "?"}
|
|
5199
|
+
`f: ${nodeCosts?.f !== void 0 ? nodeCosts.f.toFixed(2) : "?"}`,
|
|
5200
|
+
`z: ${node.availableZ.join(", ")}`
|
|
5309
5201
|
].join("\n")
|
|
5310
5202
|
});
|
|
5311
5203
|
}
|
|
@@ -5315,7 +5207,8 @@ var CapacityPathingSolver = class extends BaseSolver {
|
|
|
5315
5207
|
for (const point of conn.connection.pointsToConnect) {
|
|
5316
5208
|
graphics.points.push({
|
|
5317
5209
|
x: point.x,
|
|
5318
|
-
y: point.y
|
|
5210
|
+
y: point.y,
|
|
5211
|
+
label: [`pointsToConnect ${conn.connection.name}`].join("\n")
|
|
5319
5212
|
});
|
|
5320
5213
|
}
|
|
5321
5214
|
}
|
|
@@ -5371,18 +5264,6 @@ var CapacityPathingSolver5 = class extends CapacityPathingSolver {
|
|
|
5371
5264
|
*/
|
|
5372
5265
|
getNodeCapacityPenalty(node) {
|
|
5373
5266
|
return 0.05;
|
|
5374
|
-
if (node.availableZ.length === 1) {
|
|
5375
|
-
return 0;
|
|
5376
|
-
}
|
|
5377
|
-
const totalCapacity = this.getTotalCapacity(node);
|
|
5378
|
-
const usedCapacity = this.usedNodeCapacityMap.get(node.capacityMeshNodeId) ?? 0;
|
|
5379
|
-
const remainingCapacity = totalCapacity - usedCapacity;
|
|
5380
|
-
const dist = this.activeCandidateStraightLineDistance;
|
|
5381
|
-
if (remainingCapacity <= 0) {
|
|
5382
|
-
const penalty = (-remainingCapacity + 1) / totalCapacity * dist * (this.NEGATIVE_CAPACITY_PENALTY_FACTOR / 4);
|
|
5383
|
-
return penalty ** 2;
|
|
5384
|
-
}
|
|
5385
|
-
return 1 / remainingCapacity * dist * this.REDUCED_CAPACITY_PENALTY_FACTOR / 8;
|
|
5386
5267
|
}
|
|
5387
5268
|
/**
|
|
5388
5269
|
* We're rewarding travel into big nodes.
|
|
@@ -5412,6 +5293,7 @@ var StrawSolver = class extends BaseSolver {
|
|
|
5412
5293
|
nodeIdCounter;
|
|
5413
5294
|
constructor(params) {
|
|
5414
5295
|
super();
|
|
5296
|
+
this.MAX_ITERATIONS = 1e5;
|
|
5415
5297
|
this.strawSize = params.strawSize ?? 0.5;
|
|
5416
5298
|
this.multiLayerNodes = [];
|
|
5417
5299
|
this.strawNodes = [];
|
|
@@ -5509,7 +5391,8 @@ var StrawSolver = class extends BaseSolver {
|
|
|
5509
5391
|
layer: node.layer,
|
|
5510
5392
|
availableZ: [...node.availableZ],
|
|
5511
5393
|
_depth: node._depth,
|
|
5512
|
-
_strawNode: true
|
|
5394
|
+
_strawNode: true,
|
|
5395
|
+
_strawParentCapacityMeshNodeId: node.capacityMeshNodeId
|
|
5513
5396
|
});
|
|
5514
5397
|
}
|
|
5515
5398
|
} else {
|
|
@@ -5525,7 +5408,8 @@ var StrawSolver = class extends BaseSolver {
|
|
|
5525
5408
|
layer: node.layer,
|
|
5526
5409
|
availableZ: [...node.availableZ],
|
|
5527
5410
|
_depth: node._depth,
|
|
5528
|
-
_strawNode: true
|
|
5411
|
+
_strawNode: true,
|
|
5412
|
+
_strawParentCapacityMeshNodeId: node.capacityMeshNodeId
|
|
5529
5413
|
});
|
|
5530
5414
|
}
|
|
5531
5415
|
}
|
|
@@ -5581,7 +5465,8 @@ ${node.width}x${node.height}`
|
|
|
5581
5465
|
stroke: "rgba(0, 0, 0, 0.5)",
|
|
5582
5466
|
label: `${node.capacityMeshNodeId}
|
|
5583
5467
|
Layer: ${node.availableZ[0]}
|
|
5584
|
-
${node.width}x${node.height}
|
|
5468
|
+
${node.width}x${node.height}`,
|
|
5469
|
+
layer: `z${node.availableZ.join(",")}`
|
|
5585
5470
|
});
|
|
5586
5471
|
}
|
|
5587
5472
|
for (const node of this.multiLayerNodes) {
|
|
@@ -5601,6 +5486,72 @@ ${node.width}x${node.height}`
|
|
|
5601
5486
|
}
|
|
5602
5487
|
};
|
|
5603
5488
|
|
|
5489
|
+
// lib/utils/areNodesBordering.ts
|
|
5490
|
+
function areNodesBordering(node1, node2) {
|
|
5491
|
+
const n1Left = node1.center.x - node1.width / 2;
|
|
5492
|
+
const n1Right = node1.center.x + node1.width / 2;
|
|
5493
|
+
const n1Top = node1.center.y - node1.height / 2;
|
|
5494
|
+
const n1Bottom = node1.center.y + node1.height / 2;
|
|
5495
|
+
const n2Left = node2.center.x - node2.width / 2;
|
|
5496
|
+
const n2Right = node2.center.x + node2.width / 2;
|
|
5497
|
+
const n2Top = node2.center.y - node2.height / 2;
|
|
5498
|
+
const n2Bottom = node2.center.y + node2.height / 2;
|
|
5499
|
+
const epsilon = 1e-3;
|
|
5500
|
+
const shareVerticalBorder = (Math.abs(n1Right - n2Left) < epsilon || Math.abs(n1Left - n2Right) < epsilon) && Math.min(n1Bottom, n2Bottom) - Math.max(n1Top, n2Top) >= epsilon;
|
|
5501
|
+
const shareHorizontalBorder = (Math.abs(n1Bottom - n2Top) < epsilon || Math.abs(n1Top - n2Bottom) < epsilon) && Math.min(n1Right, n2Right) - Math.max(n1Left, n2Left) >= epsilon;
|
|
5502
|
+
return shareVerticalBorder || shareHorizontalBorder;
|
|
5503
|
+
}
|
|
5504
|
+
|
|
5505
|
+
// lib/data-structures/CapacityNodeTree.ts
|
|
5506
|
+
var CapacityNodeTree = class {
|
|
5507
|
+
constructor(nodes) {
|
|
5508
|
+
this.nodes = nodes;
|
|
5509
|
+
this.buckets = /* @__PURE__ */ new Map();
|
|
5510
|
+
for (const node of nodes) {
|
|
5511
|
+
const nodeMinX = node.center.x - node.width / 2;
|
|
5512
|
+
const nodeMinY = node.center.y - node.height / 2;
|
|
5513
|
+
const nodeMaxX = node.center.x + node.width / 2;
|
|
5514
|
+
const nodeMaxY = node.center.y + node.height / 2;
|
|
5515
|
+
for (let x = nodeMinX; x <= nodeMaxX; x += this.CELL_SIZE) {
|
|
5516
|
+
for (let y = nodeMinY; y <= nodeMaxY; y += this.CELL_SIZE) {
|
|
5517
|
+
const bucketKey = this.getBucketKey(x, y);
|
|
5518
|
+
const bucket = this.buckets.get(bucketKey);
|
|
5519
|
+
if (!bucket) {
|
|
5520
|
+
this.buckets.set(bucketKey, [node]);
|
|
5521
|
+
} else {
|
|
5522
|
+
bucket.push(node);
|
|
5523
|
+
}
|
|
5524
|
+
}
|
|
5525
|
+
}
|
|
5526
|
+
}
|
|
5527
|
+
}
|
|
5528
|
+
buckets;
|
|
5529
|
+
CELL_SIZE = 0.4;
|
|
5530
|
+
getBucketKey(x, y) {
|
|
5531
|
+
return `${Math.floor(x / this.CELL_SIZE)}x${Math.floor(y / this.CELL_SIZE)}`;
|
|
5532
|
+
}
|
|
5533
|
+
getNodesInArea(centerX, centerY, width, height) {
|
|
5534
|
+
const nodes = [];
|
|
5535
|
+
const alreadyAddedNodes = /* @__PURE__ */ new Set();
|
|
5536
|
+
const minX = centerX - width / 2;
|
|
5537
|
+
const minY = centerY - height / 2;
|
|
5538
|
+
const maxX = centerX + width / 2;
|
|
5539
|
+
const maxY = centerY + height / 2;
|
|
5540
|
+
for (let x = minX; x <= maxX; x += this.CELL_SIZE) {
|
|
5541
|
+
for (let y = minY; y <= maxY; y += this.CELL_SIZE) {
|
|
5542
|
+
const bucketKey = this.getBucketKey(x, y);
|
|
5543
|
+
const bucket = this.buckets.get(bucketKey) || [];
|
|
5544
|
+
for (const node of bucket) {
|
|
5545
|
+
if (alreadyAddedNodes.has(node.capacityMeshNodeId)) continue;
|
|
5546
|
+
alreadyAddedNodes.add(node.capacityMeshNodeId);
|
|
5547
|
+
nodes.push(node);
|
|
5548
|
+
}
|
|
5549
|
+
}
|
|
5550
|
+
}
|
|
5551
|
+
return nodes;
|
|
5552
|
+
}
|
|
5553
|
+
};
|
|
5554
|
+
|
|
5604
5555
|
// lib/solvers/SingleLayerNodeMerger/SingleLayerNodeMergerSolver.ts
|
|
5605
5556
|
var EPSILON = 5e-3;
|
|
5606
5557
|
var SingleLayerNodeMergerSolver = class extends BaseSolver {
|
|
@@ -5609,6 +5560,7 @@ var SingleLayerNodeMergerSolver = class extends BaseSolver {
|
|
|
5609
5560
|
absorbedNodeIds;
|
|
5610
5561
|
nextBatchNodeIds;
|
|
5611
5562
|
batchHadModifications;
|
|
5563
|
+
hasComputedAdjacentNodeIds = false;
|
|
5612
5564
|
newNodes;
|
|
5613
5565
|
constructor(nodes) {
|
|
5614
5566
|
super();
|
|
@@ -5619,34 +5571,94 @@ var SingleLayerNodeMergerSolver = class extends BaseSolver {
|
|
|
5619
5571
|
}
|
|
5620
5572
|
this.newNodes = [];
|
|
5621
5573
|
this.absorbedNodeIds = /* @__PURE__ */ new Set();
|
|
5622
|
-
const
|
|
5574
|
+
const unprocessedNodesWithArea = [];
|
|
5623
5575
|
for (const node of nodes) {
|
|
5624
5576
|
if (node.availableZ.length > 1) {
|
|
5625
5577
|
this.newNodes.push(node);
|
|
5626
5578
|
this.absorbedNodeIds.add(node.capacityMeshNodeId);
|
|
5627
5579
|
} else {
|
|
5628
|
-
|
|
5580
|
+
unprocessedNodesWithArea.push([node, node.width * node.height]);
|
|
5629
5581
|
}
|
|
5630
5582
|
}
|
|
5631
|
-
|
|
5632
|
-
|
|
5583
|
+
unprocessedNodesWithArea.sort((a, b) => a[1] - b[1]);
|
|
5584
|
+
for (const [node, area] of unprocessedNodesWithArea) {
|
|
5585
|
+
const unprocessedNode = {
|
|
5586
|
+
...node,
|
|
5587
|
+
center: { ...node.center }
|
|
5588
|
+
};
|
|
5589
|
+
this.nodeMap.set(node.capacityMeshNodeId, unprocessedNode);
|
|
5590
|
+
}
|
|
5591
|
+
this.currentBatchNodeIds = unprocessedNodesWithArea.map(
|
|
5592
|
+
([node]) => node.capacityMeshNodeId
|
|
5593
|
+
);
|
|
5633
5594
|
this.nextBatchNodeIds = [];
|
|
5634
5595
|
this.batchHadModifications = false;
|
|
5635
5596
|
}
|
|
5597
|
+
computeAdjacentNodeIdsForFirstBatch(nodes) {
|
|
5598
|
+
const nodeTrees = [
|
|
5599
|
+
new CapacityNodeTree(nodes.filter((n) => n.availableZ[0] === 0)),
|
|
5600
|
+
new CapacityNodeTree(nodes.filter((n) => n.availableZ[0] === 1))
|
|
5601
|
+
];
|
|
5602
|
+
for (const node of nodes) {
|
|
5603
|
+
const adjacentNodes = [];
|
|
5604
|
+
const z = node.availableZ[0];
|
|
5605
|
+
const nodesInArea = nodeTrees[z].getNodesInArea(
|
|
5606
|
+
node.center.x,
|
|
5607
|
+
node.center.y,
|
|
5608
|
+
node.width * 4,
|
|
5609
|
+
node.height * 4
|
|
5610
|
+
);
|
|
5611
|
+
for (const unprocessedNode of nodesInArea) {
|
|
5612
|
+
if (unprocessedNode._containsTarget && unprocessedNode._targetConnectionName !== node._targetConnectionName)
|
|
5613
|
+
continue;
|
|
5614
|
+
if (unprocessedNode.capacityMeshNodeId === node.capacityMeshNodeId)
|
|
5615
|
+
continue;
|
|
5616
|
+
if (!areNodesBordering(node, unprocessedNode)) continue;
|
|
5617
|
+
adjacentNodes.push(unprocessedNode);
|
|
5618
|
+
}
|
|
5619
|
+
node._adjacentNodeIds = adjacentNodes.map((n) => n.capacityMeshNodeId);
|
|
5620
|
+
}
|
|
5621
|
+
}
|
|
5622
|
+
// getAdjacentSameLayerUnprocessedNodes1(rootNode: CapacityMeshNode) {
|
|
5623
|
+
// const adjacentNodes: CapacityMeshNode[] = []
|
|
5624
|
+
// for (const unprocessedNodeId of this.currentBatchNodeIds) {
|
|
5625
|
+
// const unprocessedNode = this.nodeMap.get(unprocessedNodeId)!
|
|
5626
|
+
// if (!areNodesBordering(rootNode, unprocessedNode)) continue
|
|
5627
|
+
// if (unprocessedNode.availableZ[0] !== rootNode.availableZ[0]) continue
|
|
5628
|
+
// if (
|
|
5629
|
+
// unprocessedNode._containsTarget &&
|
|
5630
|
+
// unprocessedNode._targetConnectionName !== rootNode._targetConnectionName
|
|
5631
|
+
// )
|
|
5632
|
+
// continue
|
|
5633
|
+
// if (this.absorbedNodeIds.has(unprocessedNodeId)) continue
|
|
5634
|
+
// adjacentNodes.push(unprocessedNode)
|
|
5635
|
+
// }
|
|
5636
|
+
// return adjacentNodes
|
|
5637
|
+
// }
|
|
5636
5638
|
getAdjacentSameLayerUnprocessedNodes(rootNode) {
|
|
5639
|
+
return this.getAdjacentSameLayerUnprocessedNodes2(rootNode);
|
|
5640
|
+
}
|
|
5641
|
+
getAdjacentSameLayerUnprocessedNodes2(rootNode) {
|
|
5637
5642
|
const adjacentNodes = [];
|
|
5638
|
-
|
|
5639
|
-
|
|
5640
|
-
|
|
5641
|
-
|
|
5642
|
-
|
|
5643
|
-
|
|
5644
|
-
|
|
5643
|
+
const unprocessedAdjNodes = Array.from(
|
|
5644
|
+
new Set(
|
|
5645
|
+
(rootNode._adjacentNodeIds ?? []).map((a) => this.nodeMap.get(a))
|
|
5646
|
+
)
|
|
5647
|
+
);
|
|
5648
|
+
unprocessedAdjNodes.sort((a, b) => a.width * a.height - b.width * b.height);
|
|
5649
|
+
for (const unprocessedNode of unprocessedAdjNodes) {
|
|
5650
|
+
if (this.absorbedNodeIds.has(unprocessedNode.capacityMeshNodeId)) continue;
|
|
5645
5651
|
adjacentNodes.push(unprocessedNode);
|
|
5646
5652
|
}
|
|
5647
5653
|
return adjacentNodes;
|
|
5648
5654
|
}
|
|
5649
5655
|
_step() {
|
|
5656
|
+
if (!this.hasComputedAdjacentNodeIds) {
|
|
5657
|
+
this.computeAdjacentNodeIdsForFirstBatch(
|
|
5658
|
+
this.currentBatchNodeIds.map((id) => this.nodeMap.get(id))
|
|
5659
|
+
);
|
|
5660
|
+
this.hasComputedAdjacentNodeIds = true;
|
|
5661
|
+
}
|
|
5650
5662
|
let rootNodeId = this.currentBatchNodeIds.pop();
|
|
5651
5663
|
while (rootNodeId && this.absorbedNodeIds.has(rootNodeId)) {
|
|
5652
5664
|
rootNodeId = this.currentBatchNodeIds.pop();
|
|
@@ -5675,6 +5687,19 @@ var SingleLayerNodeMergerSolver = class extends BaseSolver {
|
|
|
5675
5687
|
this.nextBatchNodeIds.push(rootNodeId);
|
|
5676
5688
|
return;
|
|
5677
5689
|
}
|
|
5690
|
+
const absorbAdjacentNodeIds = (nodesToAbsorb) => {
|
|
5691
|
+
for (const adjNode of nodesToAbsorb) {
|
|
5692
|
+
this.absorbedNodeIds.add(adjNode.capacityMeshNodeId);
|
|
5693
|
+
}
|
|
5694
|
+
rootNode._adjacentNodeIds = Array.from(
|
|
5695
|
+
new Set(
|
|
5696
|
+
[
|
|
5697
|
+
...rootNode._adjacentNodeIds ?? [],
|
|
5698
|
+
...nodesToAbsorb.flatMap((n) => n._adjacentNodeIds ?? [])
|
|
5699
|
+
].filter((id) => !this.absorbedNodeIds.has(id))
|
|
5700
|
+
)
|
|
5701
|
+
);
|
|
5702
|
+
};
|
|
5678
5703
|
const adjacentNodesToLeft = adjacentNodes.filter(
|
|
5679
5704
|
(adjNode) => adjNode.center.x < rootNode.center.x && Math.abs(adjNode.center.y - rootNode.center.y) < rootNode.height / 2
|
|
5680
5705
|
);
|
|
@@ -5691,9 +5716,7 @@ var SingleLayerNodeMergerSolver = class extends BaseSolver {
|
|
|
5691
5716
|
if (leftAdjNodesTakeUpEntireHeight && leftAdjNodesAreAllSameSize) {
|
|
5692
5717
|
rootNode.width += leftAdjNodeWidth;
|
|
5693
5718
|
rootNode.center.x = rootNode.center.x - leftAdjNodeWidth / 2;
|
|
5694
|
-
|
|
5695
|
-
this.absorbedNodeIds.add(adjNode.capacityMeshNodeId);
|
|
5696
|
-
}
|
|
5719
|
+
absorbAdjacentNodeIds(adjacentNodesToLeft);
|
|
5697
5720
|
rootNodeHasGrown = true;
|
|
5698
5721
|
}
|
|
5699
5722
|
}
|
|
@@ -5713,9 +5736,7 @@ var SingleLayerNodeMergerSolver = class extends BaseSolver {
|
|
|
5713
5736
|
if (rightAdjNodesTakeUpEntireHeight && rightAdjNodesAreAllSameSize) {
|
|
5714
5737
|
rootNode.width += rightAdjNodeWidth;
|
|
5715
5738
|
rootNode.center.x = rootNode.center.x + rightAdjNodeWidth / 2;
|
|
5716
|
-
|
|
5717
|
-
this.absorbedNodeIds.add(adjNode.capacityMeshNodeId);
|
|
5718
|
-
}
|
|
5739
|
+
absorbAdjacentNodeIds(adjacentNodesToRight);
|
|
5719
5740
|
rootNodeHasGrown = true;
|
|
5720
5741
|
}
|
|
5721
5742
|
}
|
|
@@ -5735,9 +5756,7 @@ var SingleLayerNodeMergerSolver = class extends BaseSolver {
|
|
|
5735
5756
|
if (topAdjNodesTakeUpEntireWidth && topAdjNodesAreAllSameSize) {
|
|
5736
5757
|
rootNode.height += topAdjNodeHeight;
|
|
5737
5758
|
rootNode.center.y = rootNode.center.y + topAdjNodeHeight / 2;
|
|
5738
|
-
|
|
5739
|
-
this.absorbedNodeIds.add(adjNode.capacityMeshNodeId);
|
|
5740
|
-
}
|
|
5759
|
+
absorbAdjacentNodeIds(adjacentNodesToTop);
|
|
5741
5760
|
rootNodeHasGrown = true;
|
|
5742
5761
|
}
|
|
5743
5762
|
}
|
|
@@ -5757,9 +5776,7 @@ var SingleLayerNodeMergerSolver = class extends BaseSolver {
|
|
|
5757
5776
|
if (bottomAdjNodesTakeUpEntireWidth && bottomAdjNodesAreAllSameSize) {
|
|
5758
5777
|
rootNode.height += bottomAdjNodeHeight;
|
|
5759
5778
|
rootNode.center.y = rootNode.center.y - bottomAdjNodeHeight / 2;
|
|
5760
|
-
|
|
5761
|
-
this.absorbedNodeIds.add(adjNode.capacityMeshNodeId);
|
|
5762
|
-
}
|
|
5779
|
+
absorbAdjacentNodeIds(adjacentNodesToBottom);
|
|
5763
5780
|
rootNodeHasGrown = true;
|
|
5764
5781
|
}
|
|
5765
5782
|
}
|
|
@@ -5849,7 +5866,7 @@ var SingleSimplifiedPathSolver = class extends BaseSolver {
|
|
|
5849
5866
|
this.obstacles = params.obstacles;
|
|
5850
5867
|
this.connMap = params.connMap;
|
|
5851
5868
|
this.colorMap = params.colorMap;
|
|
5852
|
-
this.newRoute = [];
|
|
5869
|
+
this.newRoute = [this.inputRoute.route[0]];
|
|
5853
5870
|
this.newVias = [];
|
|
5854
5871
|
}
|
|
5855
5872
|
get simplifiedRoute() {
|
|
@@ -5887,7 +5904,7 @@ var SingleSimplifiedPathSolver = class extends BaseSolver {
|
|
|
5887
5904
|
],
|
|
5888
5905
|
strokeColor: "rgba(255, 0, 0, 0.8)",
|
|
5889
5906
|
strokeDash: this.inputRoute.route[i].z === 1 ? "5, 5" : void 0,
|
|
5890
|
-
layer: this.inputRoute.route[i].z.toString()
|
|
5907
|
+
layer: `z${this.inputRoute.route[i].z.toString()}`
|
|
5891
5908
|
});
|
|
5892
5909
|
}
|
|
5893
5910
|
for (let i = 0; i < this.newRoute.length; i++) {
|
|
@@ -5900,7 +5917,7 @@ var SingleSimplifiedPathSolver = class extends BaseSolver {
|
|
|
5900
5917
|
strokeWidth: 0.15,
|
|
5901
5918
|
strokeColor: "rgba(0, 255, 0, 0.8)",
|
|
5902
5919
|
strokeDash: this.newRoute[i].z === 1 ? [0.4, 0.4] : void 0,
|
|
5903
|
-
layer: this.newRoute[i].z.toString()
|
|
5920
|
+
layer: `z${this.newRoute[i].z.toString()}`
|
|
5904
5921
|
});
|
|
5905
5922
|
}
|
|
5906
5923
|
graphics.points.push({
|
|
@@ -5908,7 +5925,7 @@ var SingleSimplifiedPathSolver = class extends BaseSolver {
|
|
|
5908
5925
|
y: this.newRoute[i].y,
|
|
5909
5926
|
color: "rgba(0, 255, 0, 0.8)",
|
|
5910
5927
|
label: `z: ${this.newRoute[i].z}`,
|
|
5911
|
-
layer: this.newRoute[i].z.toString()
|
|
5928
|
+
layer: `z${this.newRoute[i].z.toString()}`
|
|
5912
5929
|
});
|
|
5913
5930
|
}
|
|
5914
5931
|
for (const via of this.newVias) {
|
|
@@ -5936,7 +5953,7 @@ var SingleSimplifiedPathSolver = class extends BaseSolver {
|
|
|
5936
5953
|
strokeWidth: 0.15,
|
|
5937
5954
|
strokeColor: route.route[i].z === 0 ? "rgba(255, 0, 255, 0.5)" : route.route[i].z === 1 ? "rgba(128, 0, 128, 0.5)" : "rgba(0, 0, 255, 0.5)",
|
|
5938
5955
|
// bottom layer (blue)
|
|
5939
|
-
layer: route.route[i].z.toString()
|
|
5956
|
+
layer: `z${route.route[i].z.toString()}`
|
|
5940
5957
|
});
|
|
5941
5958
|
}
|
|
5942
5959
|
}
|
|
@@ -6034,32 +6051,169 @@ function segmentsIntersect(A1, A2, B1, B2) {
|
|
|
6034
6051
|
return false;
|
|
6035
6052
|
}
|
|
6036
6053
|
|
|
6054
|
+
// lib/data-structures/SegmentTree.ts
|
|
6055
|
+
var getSegmentBounds = (segment) => {
|
|
6056
|
+
return {
|
|
6057
|
+
minX: Math.min(segment[0].x, segment[1].x),
|
|
6058
|
+
maxX: Math.max(segment[0].x, segment[1].x),
|
|
6059
|
+
minY: Math.min(segment[0].y, segment[1].y),
|
|
6060
|
+
maxY: Math.max(segment[0].y, segment[1].y)
|
|
6061
|
+
};
|
|
6062
|
+
};
|
|
6063
|
+
var SegmentTree = class {
|
|
6064
|
+
constructor(segments) {
|
|
6065
|
+
this.segments = segments;
|
|
6066
|
+
this.buckets = /* @__PURE__ */ new Map();
|
|
6067
|
+
for (const segment of segments) {
|
|
6068
|
+
const bounds = getSegmentBounds(segment);
|
|
6069
|
+
for (let x = bounds.minX; x <= bounds.maxX; x += this.CELL_SIZE) {
|
|
6070
|
+
for (let y = bounds.minY; y <= bounds.maxY; y += this.CELL_SIZE) {
|
|
6071
|
+
const bucketKey = this.getBucketKey(x, y);
|
|
6072
|
+
const bucket = this.buckets.get(bucketKey);
|
|
6073
|
+
if (!bucket) {
|
|
6074
|
+
this.buckets.set(bucketKey, [
|
|
6075
|
+
[segment[0], segment[1], this.getSegmentKey(segment)]
|
|
6076
|
+
]);
|
|
6077
|
+
} else {
|
|
6078
|
+
bucket.push([segment[0], segment[1], this.getSegmentKey(segment)]);
|
|
6079
|
+
}
|
|
6080
|
+
}
|
|
6081
|
+
}
|
|
6082
|
+
}
|
|
6083
|
+
}
|
|
6084
|
+
buckets;
|
|
6085
|
+
CELL_SIZE = 0.4;
|
|
6086
|
+
getBucketKey(x, y) {
|
|
6087
|
+
return `${Math.floor(x / this.CELL_SIZE)}x${Math.floor(y / this.CELL_SIZE)}`;
|
|
6088
|
+
}
|
|
6089
|
+
getSegmentKey(segment) {
|
|
6090
|
+
return `${segment[0].x}-${segment[0].y}-${segment[0].z}-${segment[1].x}-${segment[1].y}-${segment[1].z}`;
|
|
6091
|
+
}
|
|
6092
|
+
getSegmentsThatCouldIntersect(A, B) {
|
|
6093
|
+
const segments = [];
|
|
6094
|
+
const alreadyAddedSegments = /* @__PURE__ */ new Set();
|
|
6095
|
+
const minX = Math.min(A.x, B.x) - this.CELL_SIZE;
|
|
6096
|
+
const minY = Math.min(A.y, B.y) - this.CELL_SIZE;
|
|
6097
|
+
const maxX = Math.max(A.x, B.x) + this.CELL_SIZE;
|
|
6098
|
+
const maxY = Math.max(A.y, B.y) + this.CELL_SIZE;
|
|
6099
|
+
for (let x = minX; x <= maxX; x += this.CELL_SIZE) {
|
|
6100
|
+
for (let y = minY; y <= maxY; y += this.CELL_SIZE) {
|
|
6101
|
+
const bucketKey = this.getBucketKey(x, y);
|
|
6102
|
+
const bucket = this.buckets.get(bucketKey) || [];
|
|
6103
|
+
for (const segment of bucket) {
|
|
6104
|
+
const key = segment[2];
|
|
6105
|
+
if (alreadyAddedSegments.has(key)) continue;
|
|
6106
|
+
alreadyAddedSegments.add(key);
|
|
6107
|
+
segments.push(segment);
|
|
6108
|
+
}
|
|
6109
|
+
}
|
|
6110
|
+
}
|
|
6111
|
+
return segments;
|
|
6112
|
+
}
|
|
6113
|
+
};
|
|
6114
|
+
|
|
6037
6115
|
// lib/solvers/SimplifiedPathSolver/SingleSimplifiedPathSolver5_Deg45.ts
|
|
6038
6116
|
var SingleSimplifiedPathSolver5 = class extends SingleSimplifiedPathSolver {
|
|
6039
6117
|
pathSegments = [];
|
|
6040
6118
|
totalPathLength = 0;
|
|
6041
6119
|
headDistanceAlongPath = 0;
|
|
6042
6120
|
tailDistanceAlongPath = 0;
|
|
6043
|
-
|
|
6121
|
+
minStepSize = 0.25;
|
|
6044
6122
|
// Default step size, can be adjusted
|
|
6045
6123
|
lastValidPath = null;
|
|
6046
6124
|
// Store the current valid path
|
|
6047
6125
|
lastValidPathHeadDistance = 0;
|
|
6126
|
+
/** Amount the step size is reduced when the step isn't possible */
|
|
6127
|
+
STEP_SIZE_REDUCTION_FACTOR = 0.25;
|
|
6128
|
+
maxStepSize = 4;
|
|
6129
|
+
currentStepSize = this.maxStepSize;
|
|
6130
|
+
lastHeadMoveDistance = 0;
|
|
6131
|
+
cachedValidPathSegments;
|
|
6048
6132
|
filteredObstacles = [];
|
|
6133
|
+
filteredObstaclePathSegments = [];
|
|
6134
|
+
filteredVias = [];
|
|
6135
|
+
segmentTree;
|
|
6049
6136
|
OBSTACLE_MARGIN = 0.15;
|
|
6050
6137
|
TAIL_JUMP_RATIO = 0.8;
|
|
6051
6138
|
constructor(params) {
|
|
6052
6139
|
super(params);
|
|
6140
|
+
this.cachedValidPathSegments = /* @__PURE__ */ new Set();
|
|
6053
6141
|
if (this.inputRoute.route.length <= 1) {
|
|
6054
6142
|
this.newRoute = [...this.inputRoute.route];
|
|
6055
6143
|
this.solved = true;
|
|
6056
6144
|
return;
|
|
6057
6145
|
}
|
|
6146
|
+
const bounds = this.inputRoute.route.reduce(
|
|
6147
|
+
(acc, point) => {
|
|
6148
|
+
acc.minX = Math.min(acc.minX, point.x);
|
|
6149
|
+
acc.maxX = Math.max(acc.maxX, point.x);
|
|
6150
|
+
acc.minY = Math.min(acc.minY, point.y);
|
|
6151
|
+
acc.maxY = Math.max(acc.maxY, point.y);
|
|
6152
|
+
return acc;
|
|
6153
|
+
},
|
|
6154
|
+
{ minX: Infinity, maxX: -Infinity, minY: Infinity, maxY: -Infinity }
|
|
6155
|
+
);
|
|
6058
6156
|
this.filteredObstacles = this.obstacles.filter(
|
|
6059
6157
|
(obstacle) => !obstacle.connectedTo.some(
|
|
6060
6158
|
(id) => this.connMap.areIdsConnected(this.inputRoute.connectionName, id)
|
|
6061
6159
|
)
|
|
6160
|
+
).filter((obstacle) => {
|
|
6161
|
+
if (obstacle.connectedTo.some(
|
|
6162
|
+
(obsId) => this.connMap.areIdsConnected(this.inputRoute.connectionName, obsId)
|
|
6163
|
+
)) {
|
|
6164
|
+
return false;
|
|
6165
|
+
}
|
|
6166
|
+
const obstacleMinX = obstacle.center.x - obstacle.width / 2 - this.OBSTACLE_MARGIN;
|
|
6167
|
+
const obstacleMaxX = obstacle.center.x + obstacle.width / 2 + this.OBSTACLE_MARGIN;
|
|
6168
|
+
const obstacleMinY = obstacle.center.y - obstacle.height / 2 - this.OBSTACLE_MARGIN;
|
|
6169
|
+
const obstacleMaxY = obstacle.center.y + obstacle.height / 2 + this.OBSTACLE_MARGIN;
|
|
6170
|
+
return obstacleMinX <= bounds.maxX && obstacleMaxX >= bounds.minX && obstacleMinY <= bounds.maxY && obstacleMaxY >= bounds.minY;
|
|
6171
|
+
});
|
|
6172
|
+
this.filteredObstaclePathSegments = this.otherHdRoutes.flatMap(
|
|
6173
|
+
(hdRoute) => {
|
|
6174
|
+
if (this.connMap.areIdsConnected(
|
|
6175
|
+
this.inputRoute.connectionName,
|
|
6176
|
+
hdRoute.connectionName
|
|
6177
|
+
)) {
|
|
6178
|
+
return [];
|
|
6179
|
+
}
|
|
6180
|
+
const route = hdRoute.route;
|
|
6181
|
+
const segments = [];
|
|
6182
|
+
for (let i = 0; i < route.length - 1; i++) {
|
|
6183
|
+
const start = route[i];
|
|
6184
|
+
const end = route[i + 1];
|
|
6185
|
+
const minX = Math.min(start.x, end.x);
|
|
6186
|
+
const maxX = Math.max(start.x, end.x);
|
|
6187
|
+
const minY = Math.min(start.y, end.y);
|
|
6188
|
+
const maxY = Math.max(start.y, end.y);
|
|
6189
|
+
if (minX <= bounds.maxX && maxX >= bounds.minX && minY <= bounds.maxY && maxY >= bounds.minY) {
|
|
6190
|
+
segments.push([start, end]);
|
|
6191
|
+
}
|
|
6192
|
+
}
|
|
6193
|
+
return segments;
|
|
6194
|
+
}
|
|
6062
6195
|
);
|
|
6196
|
+
this.segmentTree = new SegmentTree(this.filteredObstaclePathSegments);
|
|
6197
|
+
this.filteredVias = this.otherHdRoutes.flatMap((hdRoute) => {
|
|
6198
|
+
if (this.connMap.areIdsConnected(
|
|
6199
|
+
this.inputRoute.connectionName,
|
|
6200
|
+
hdRoute.connectionName
|
|
6201
|
+
)) {
|
|
6202
|
+
return [];
|
|
6203
|
+
}
|
|
6204
|
+
const vias = hdRoute.vias;
|
|
6205
|
+
const filteredVias = [];
|
|
6206
|
+
for (const via of vias) {
|
|
6207
|
+
const minX = via.x - hdRoute.viaDiameter / 2;
|
|
6208
|
+
const maxX = via.x + hdRoute.viaDiameter / 2;
|
|
6209
|
+
const minY = via.y - hdRoute.viaDiameter / 2;
|
|
6210
|
+
const maxY = via.y + hdRoute.viaDiameter / 2;
|
|
6211
|
+
if (minX <= bounds.maxX && maxX >= bounds.minX && minY <= bounds.maxY && maxY >= bounds.minY) {
|
|
6212
|
+
filteredVias.push({ ...via, diameter: hdRoute.viaDiameter });
|
|
6213
|
+
}
|
|
6214
|
+
}
|
|
6215
|
+
return filteredVias;
|
|
6216
|
+
});
|
|
6063
6217
|
this.computePathSegments();
|
|
6064
6218
|
}
|
|
6065
6219
|
// Compute the path segments and their distances
|
|
@@ -6097,7 +6251,7 @@ var SingleSimplifiedPathSolver5 = class extends SingleSimplifiedPathSolver {
|
|
|
6097
6251
|
return {
|
|
6098
6252
|
x: segment.start.x + factor * (segment.end.x - segment.start.x),
|
|
6099
6253
|
y: segment.start.y + factor * (segment.end.y - segment.start.y),
|
|
6100
|
-
z: segment.start.z
|
|
6254
|
+
z: factor < 0.5 ? segment.start.z : segment.end.z
|
|
6101
6255
|
// Z doesn't interpolate - use the segment's start z value
|
|
6102
6256
|
};
|
|
6103
6257
|
}
|
|
@@ -6148,33 +6302,24 @@ var SingleSimplifiedPathSolver5 = class extends SingleSimplifiedPathSolver {
|
|
|
6148
6302
|
return false;
|
|
6149
6303
|
}
|
|
6150
6304
|
}
|
|
6151
|
-
|
|
6152
|
-
|
|
6153
|
-
|
|
6154
|
-
|
|
6155
|
-
|
|
6156
|
-
|
|
6157
|
-
|
|
6158
|
-
|
|
6159
|
-
|
|
6160
|
-
const routeEnd = route.route[j + 1];
|
|
6161
|
-
if (routeStart.z === start.z && routeEnd.z === start.z) {
|
|
6162
|
-
if (minimumDistanceBetweenSegments(
|
|
6163
|
-
{ x: start.x, y: start.y },
|
|
6164
|
-
{ x: end.x, y: end.y },
|
|
6165
|
-
{ x: routeStart.x, y: routeStart.y },
|
|
6166
|
-
{ x: routeEnd.x, y: routeEnd.y }
|
|
6167
|
-
) < this.OBSTACLE_MARGIN) {
|
|
6168
|
-
return false;
|
|
6169
|
-
}
|
|
6170
|
-
}
|
|
6171
|
-
}
|
|
6172
|
-
for (const via of route.vias) {
|
|
6173
|
-
if (pointToSegmentDistance(via, start, end) < this.OBSTACLE_MARGIN + route.viaDiameter / 2) {
|
|
6305
|
+
const segmentsThatCouldIntersect = this.segmentTree.getSegmentsThatCouldIntersect(start, end);
|
|
6306
|
+
for (const [otherSegA, otherSegB] of segmentsThatCouldIntersect) {
|
|
6307
|
+
if (otherSegA.z === start.z && otherSegB.z === start.z) {
|
|
6308
|
+
if (minimumDistanceBetweenSegments(
|
|
6309
|
+
{ x: start.x, y: start.y },
|
|
6310
|
+
{ x: end.x, y: end.y },
|
|
6311
|
+
{ x: otherSegA.x, y: otherSegA.y },
|
|
6312
|
+
{ x: otherSegB.x, y: otherSegB.y }
|
|
6313
|
+
) < this.OBSTACLE_MARGIN) {
|
|
6174
6314
|
return false;
|
|
6175
6315
|
}
|
|
6176
6316
|
}
|
|
6177
6317
|
}
|
|
6318
|
+
for (const via of this.filteredVias) {
|
|
6319
|
+
if (pointToSegmentDistance(via, start, end) < this.OBSTACLE_MARGIN + via.diameter / 2) {
|
|
6320
|
+
return false;
|
|
6321
|
+
}
|
|
6322
|
+
}
|
|
6178
6323
|
return true;
|
|
6179
6324
|
}
|
|
6180
6325
|
// Check if a path with multiple points is valid
|
|
@@ -6221,6 +6366,24 @@ var SingleSimplifiedPathSolver5 = class extends SingleSimplifiedPathSolver {
|
|
|
6221
6366
|
}
|
|
6222
6367
|
this.newRoute.push(path[i]);
|
|
6223
6368
|
}
|
|
6369
|
+
this.currentStepSize = this.maxStepSize;
|
|
6370
|
+
}
|
|
6371
|
+
moveHead(distance4) {
|
|
6372
|
+
this.lastHeadMoveDistance = distance4;
|
|
6373
|
+
this.headDistanceAlongPath = Math.min(
|
|
6374
|
+
this.headDistanceAlongPath + distance4,
|
|
6375
|
+
this.totalPathLength
|
|
6376
|
+
);
|
|
6377
|
+
}
|
|
6378
|
+
stepBackAndReduceStepSize() {
|
|
6379
|
+
this.headDistanceAlongPath = Math.max(
|
|
6380
|
+
this.tailDistanceAlongPath,
|
|
6381
|
+
this.headDistanceAlongPath - this.lastHeadMoveDistance
|
|
6382
|
+
);
|
|
6383
|
+
this.currentStepSize = Math.max(
|
|
6384
|
+
this.minStepSize,
|
|
6385
|
+
this.currentStepSize * this.STEP_SIZE_REDUCTION_FACTOR
|
|
6386
|
+
);
|
|
6224
6387
|
}
|
|
6225
6388
|
_step() {
|
|
6226
6389
|
const tailHasReachedEnd = this.tailDistanceAlongPath >= this.totalPathLength;
|
|
@@ -6252,10 +6415,7 @@ var SingleSimplifiedPathSolver5 = class extends SingleSimplifiedPathSolver {
|
|
|
6252
6415
|
}
|
|
6253
6416
|
}
|
|
6254
6417
|
}
|
|
6255
|
-
this.
|
|
6256
|
-
this.headDistanceAlongPath + this.stepSize,
|
|
6257
|
-
this.totalPathLength
|
|
6258
|
-
);
|
|
6418
|
+
this.moveHead(this.currentStepSize);
|
|
6259
6419
|
const tailPoint = this.getPointAtDistance(this.tailDistanceAlongPath);
|
|
6260
6420
|
const headPoint = this.getPointAtDistance(this.headDistanceAlongPath);
|
|
6261
6421
|
const tailIndex = this.getNearestIndexForDistance(
|
|
@@ -6274,21 +6434,26 @@ var SingleSimplifiedPathSolver5 = class extends SingleSimplifiedPathSolver {
|
|
|
6274
6434
|
break;
|
|
6275
6435
|
}
|
|
6276
6436
|
}
|
|
6437
|
+
if (layerChangeBtwHeadAndTail && this.lastHeadMoveDistance > this.minStepSize) {
|
|
6438
|
+
this.stepBackAndReduceStepSize();
|
|
6439
|
+
return;
|
|
6440
|
+
}
|
|
6277
6441
|
if (layerChangeBtwHeadAndTail && layerChangeAtDistance > 0) {
|
|
6442
|
+
const pointBeforeChange = this.getPointAtDistance(layerChangeAtDistance);
|
|
6278
6443
|
if (this.lastValidPath) {
|
|
6279
6444
|
this.addPathToResult(this.lastValidPath);
|
|
6280
6445
|
this.lastValidPath = null;
|
|
6281
6446
|
}
|
|
6282
|
-
const
|
|
6283
|
-
const pointAfterChange = this.inputRoute.route[
|
|
6447
|
+
const indexAfterLayerChange = this.getNearestIndexForDistance(layerChangeAtDistance) + 1;
|
|
6448
|
+
const pointAfterChange = this.inputRoute.route[indexAfterLayerChange];
|
|
6284
6449
|
this.newVias.push({
|
|
6285
6450
|
x: pointAfterChange.x,
|
|
6286
6451
|
y: pointAfterChange.y
|
|
6287
6452
|
});
|
|
6288
6453
|
this.newRoute.push(pointAfterChange);
|
|
6289
|
-
|
|
6290
|
-
if (this.pathSegments[
|
|
6291
|
-
this.tailDistanceAlongPath = this.pathSegments[
|
|
6454
|
+
this.currentStepSize = this.maxStepSize;
|
|
6455
|
+
if (this.pathSegments[indexAfterLayerChange]) {
|
|
6456
|
+
this.tailDistanceAlongPath = this.pathSegments[indexAfterLayerChange].startDistance;
|
|
6292
6457
|
this.headDistanceAlongPath = this.tailDistanceAlongPath;
|
|
6293
6458
|
} else {
|
|
6294
6459
|
console.error("Creating via at end, this is probably not right");
|
|
@@ -6298,9 +6463,13 @@ var SingleSimplifiedPathSolver5 = class extends SingleSimplifiedPathSolver {
|
|
|
6298
6463
|
return;
|
|
6299
6464
|
}
|
|
6300
6465
|
const path45 = this.find45DegreePath(tailPoint, headPoint);
|
|
6466
|
+
if (!path45 && this.lastHeadMoveDistance > this.minStepSize) {
|
|
6467
|
+
this.stepBackAndReduceStepSize();
|
|
6468
|
+
return;
|
|
6469
|
+
}
|
|
6301
6470
|
if (!path45 && !this.lastValidPath) {
|
|
6302
|
-
this.tailDistanceAlongPath += this.
|
|
6303
|
-
this.
|
|
6471
|
+
this.tailDistanceAlongPath += this.minStepSize;
|
|
6472
|
+
this.moveHead(this.minStepSize);
|
|
6304
6473
|
return;
|
|
6305
6474
|
}
|
|
6306
6475
|
if (path45) {
|
|
@@ -6312,11 +6481,8 @@ var SingleSimplifiedPathSolver5 = class extends SingleSimplifiedPathSolver {
|
|
|
6312
6481
|
this.addPathToResult(this.lastValidPath);
|
|
6313
6482
|
this.lastValidPath = null;
|
|
6314
6483
|
this.tailDistanceAlongPath = this.lastValidPathHeadDistance;
|
|
6484
|
+
this.moveHead(this.minStepSize);
|
|
6315
6485
|
}
|
|
6316
|
-
this.headDistanceAlongPath = Math.min(
|
|
6317
|
-
this.headDistanceAlongPath + this.stepSize,
|
|
6318
|
-
this.totalPathLength
|
|
6319
|
-
);
|
|
6320
6486
|
}
|
|
6321
6487
|
visualize() {
|
|
6322
6488
|
const graphics = this.getVisualsForNewRouteAndObstacles();
|
|
@@ -6334,6 +6500,15 @@ var SingleSimplifiedPathSolver5 = class extends SingleSimplifiedPathSolver {
|
|
|
6334
6500
|
color: "orange",
|
|
6335
6501
|
label: ["Head", `z: ${headPoint.z}`].join("\n")
|
|
6336
6502
|
});
|
|
6503
|
+
const tentativeHead = this.getPointAtDistance(
|
|
6504
|
+
this.headDistanceAlongPath + this.currentStepSize
|
|
6505
|
+
);
|
|
6506
|
+
graphics.points.push({
|
|
6507
|
+
x: tentativeHead.x,
|
|
6508
|
+
y: tentativeHead.y,
|
|
6509
|
+
color: "red",
|
|
6510
|
+
label: ["Tentative Head", `z: ${tentativeHead.z}`].join("\n")
|
|
6511
|
+
});
|
|
6337
6512
|
let distance4 = 0;
|
|
6338
6513
|
while (distance4 < this.totalPathLength) {
|
|
6339
6514
|
const point = this.getPointAtDistance(distance4);
|
|
@@ -6481,7 +6656,7 @@ var MultiSimplifiedPathSolver = class extends BaseSolver {
|
|
|
6481
6656
|
strokeColor: "rgba(255, 0, 0, 0.2)",
|
|
6482
6657
|
strokeDash: [0.5, 0.5],
|
|
6483
6658
|
step: 0,
|
|
6484
|
-
layer: route.route[i].z.toString()
|
|
6659
|
+
layer: `z${route.route[i].z.toString()}`
|
|
6485
6660
|
});
|
|
6486
6661
|
}
|
|
6487
6662
|
for (const point of route.vias) {
|
|
@@ -6519,6 +6694,157 @@ var MultiSimplifiedPathSolver = class extends BaseSolver {
|
|
|
6519
6694
|
}
|
|
6520
6695
|
};
|
|
6521
6696
|
|
|
6697
|
+
// lib/solvers/CapacityMeshSolver/CapacityMeshEdgeSolver.ts
|
|
6698
|
+
var CapacityMeshEdgeSolver = class extends BaseSolver {
|
|
6699
|
+
constructor(nodes) {
|
|
6700
|
+
super();
|
|
6701
|
+
this.nodes = nodes;
|
|
6702
|
+
this.edges = [];
|
|
6703
|
+
}
|
|
6704
|
+
edges;
|
|
6705
|
+
getNextCapacityMeshEdgeId() {
|
|
6706
|
+
return `ce${this.edges.length}`;
|
|
6707
|
+
}
|
|
6708
|
+
step() {
|
|
6709
|
+
this.edges = [];
|
|
6710
|
+
for (let i = 0; i < this.nodes.length; i++) {
|
|
6711
|
+
for (let j = i + 1; j < this.nodes.length; j++) {
|
|
6712
|
+
const strawNodesWithSameParent = this.nodes[i]._strawNode && this.nodes[j]._strawNode && this.nodes[i]._strawParentCapacityMeshNodeId === this.nodes[j]._strawParentCapacityMeshNodeId;
|
|
6713
|
+
if (!strawNodesWithSameParent && areNodesBordering(this.nodes[i], this.nodes[j]) && this.doNodesHaveSharedLayer(this.nodes[i], this.nodes[j])) {
|
|
6714
|
+
this.edges.push({
|
|
6715
|
+
capacityMeshEdgeId: this.getNextCapacityMeshEdgeId(),
|
|
6716
|
+
nodeIds: [
|
|
6717
|
+
this.nodes[i].capacityMeshNodeId,
|
|
6718
|
+
this.nodes[j].capacityMeshNodeId
|
|
6719
|
+
]
|
|
6720
|
+
});
|
|
6721
|
+
}
|
|
6722
|
+
}
|
|
6723
|
+
}
|
|
6724
|
+
this.handleTargetNodes();
|
|
6725
|
+
this.solved = true;
|
|
6726
|
+
}
|
|
6727
|
+
handleTargetNodes() {
|
|
6728
|
+
const targetNodes = this.nodes.filter((node) => node._containsTarget);
|
|
6729
|
+
for (const targetNode of targetNodes) {
|
|
6730
|
+
const hasEdge = this.edges.some(
|
|
6731
|
+
(edge) => edge.nodeIds.includes(targetNode.capacityMeshNodeId)
|
|
6732
|
+
);
|
|
6733
|
+
if (hasEdge) continue;
|
|
6734
|
+
let nearestNode = null;
|
|
6735
|
+
let nearestDistance = Infinity;
|
|
6736
|
+
for (const node of this.nodes) {
|
|
6737
|
+
if (node._containsObstacle) continue;
|
|
6738
|
+
if (node._containsTarget) continue;
|
|
6739
|
+
const dist = distance(targetNode.center, node.center);
|
|
6740
|
+
if (dist < nearestDistance) {
|
|
6741
|
+
nearestDistance = dist;
|
|
6742
|
+
nearestNode = node;
|
|
6743
|
+
}
|
|
6744
|
+
}
|
|
6745
|
+
if (nearestNode) {
|
|
6746
|
+
this.edges.push({
|
|
6747
|
+
capacityMeshEdgeId: this.getNextCapacityMeshEdgeId(),
|
|
6748
|
+
nodeIds: [
|
|
6749
|
+
targetNode.capacityMeshNodeId,
|
|
6750
|
+
nearestNode.capacityMeshNodeId
|
|
6751
|
+
]
|
|
6752
|
+
});
|
|
6753
|
+
}
|
|
6754
|
+
}
|
|
6755
|
+
}
|
|
6756
|
+
doNodesHaveSharedLayer(node1, node2) {
|
|
6757
|
+
return node1.availableZ.some((z) => node2.availableZ.includes(z));
|
|
6758
|
+
}
|
|
6759
|
+
visualize() {
|
|
6760
|
+
const graphics = {
|
|
6761
|
+
lines: [],
|
|
6762
|
+
points: [],
|
|
6763
|
+
rects: this.nodes.map((node) => {
|
|
6764
|
+
const lowestZ = Math.min(...node.availableZ);
|
|
6765
|
+
return {
|
|
6766
|
+
width: Math.max(node.width - 2, node.width * 0.8),
|
|
6767
|
+
height: Math.max(node.height - 2, node.height * 0.8),
|
|
6768
|
+
center: {
|
|
6769
|
+
x: node.center.x + lowestZ * node.width * 0.05,
|
|
6770
|
+
y: node.center.y - lowestZ * node.width * 0.05
|
|
6771
|
+
},
|
|
6772
|
+
fill: node._containsObstacle ? "rgba(255,0,0,0.1)" : {
|
|
6773
|
+
"0,1": "rgba(0,0,0,0.1)",
|
|
6774
|
+
"0": "rgba(0,200,200, 0.1)",
|
|
6775
|
+
"1": "rgba(0,0,200, 0.1)"
|
|
6776
|
+
}[node.availableZ.join(",")] ?? "rgba(0,200,200,0.1)",
|
|
6777
|
+
label: [
|
|
6778
|
+
node.capacityMeshNodeId,
|
|
6779
|
+
`availableZ: ${node.availableZ.join(",")}`,
|
|
6780
|
+
`target? ${node._containsTarget ?? false}`,
|
|
6781
|
+
`obs? ${node._containsObstacle ?? false}`
|
|
6782
|
+
].join("\n")
|
|
6783
|
+
};
|
|
6784
|
+
}),
|
|
6785
|
+
circles: []
|
|
6786
|
+
};
|
|
6787
|
+
for (const edge of this.edges) {
|
|
6788
|
+
const node1 = this.nodes.find(
|
|
6789
|
+
(node) => node.capacityMeshNodeId === edge.nodeIds[0]
|
|
6790
|
+
);
|
|
6791
|
+
const node2 = this.nodes.find(
|
|
6792
|
+
(node) => node.capacityMeshNodeId === edge.nodeIds[1]
|
|
6793
|
+
);
|
|
6794
|
+
if (node1?.center && node2?.center) {
|
|
6795
|
+
const lowestZ1 = Math.min(...node1.availableZ);
|
|
6796
|
+
const lowestZ2 = Math.min(...node2.availableZ);
|
|
6797
|
+
const nodeCenter1Adj = {
|
|
6798
|
+
x: node1.center.x + lowestZ1 * node1.width * 0.05,
|
|
6799
|
+
y: node1.center.y - lowestZ1 * node1.width * 0.05
|
|
6800
|
+
};
|
|
6801
|
+
const nodeCenter2Adj = {
|
|
6802
|
+
x: node2.center.x + lowestZ2 * node2.width * 0.05,
|
|
6803
|
+
y: node2.center.y - lowestZ2 * node2.width * 0.05
|
|
6804
|
+
};
|
|
6805
|
+
graphics.lines.push({
|
|
6806
|
+
points: [nodeCenter1Adj, nodeCenter2Adj],
|
|
6807
|
+
strokeDash: node1.availableZ.join(",") === node2.availableZ.join(",") ? void 0 : "10 5"
|
|
6808
|
+
});
|
|
6809
|
+
}
|
|
6810
|
+
}
|
|
6811
|
+
return graphics;
|
|
6812
|
+
}
|
|
6813
|
+
};
|
|
6814
|
+
|
|
6815
|
+
// lib/solvers/CapacityMeshSolver/CapacityMeshEdgeSolver2_NodeTreeOptimization.ts
|
|
6816
|
+
var CapacityMeshEdgeSolver2_NodeTreeOptimization = class extends CapacityMeshEdgeSolver {
|
|
6817
|
+
step() {
|
|
6818
|
+
this.edges = [];
|
|
6819
|
+
const edgeSet = /* @__PURE__ */ new Set();
|
|
6820
|
+
const nodeTree = new CapacityNodeTree(this.nodes);
|
|
6821
|
+
for (let i = 0; i < this.nodes.length; i++) {
|
|
6822
|
+
const A = this.nodes[i];
|
|
6823
|
+
const maybeAdjNodes = nodeTree.getNodesInArea(
|
|
6824
|
+
A.center.x,
|
|
6825
|
+
A.center.y,
|
|
6826
|
+
A.width * 2,
|
|
6827
|
+
A.height * 2
|
|
6828
|
+
);
|
|
6829
|
+
for (const B of maybeAdjNodes) {
|
|
6830
|
+
const areBordering = areNodesBordering(A, B);
|
|
6831
|
+
if (!areBordering) continue;
|
|
6832
|
+
const strawNodesWithSameParent = A._strawNode && B._strawNode && A._strawParentCapacityMeshNodeId === B._strawParentCapacityMeshNodeId;
|
|
6833
|
+
if (!strawNodesWithSameParent && this.doNodesHaveSharedLayer(A, B) && !edgeSet.has(`${A.capacityMeshNodeId}-${B.capacityMeshNodeId}`)) {
|
|
6834
|
+
edgeSet.add(`${A.capacityMeshNodeId}-${B.capacityMeshNodeId}`);
|
|
6835
|
+
edgeSet.add(`${B.capacityMeshNodeId}-${A.capacityMeshNodeId}`);
|
|
6836
|
+
this.edges.push({
|
|
6837
|
+
capacityMeshEdgeId: this.getNextCapacityMeshEdgeId(),
|
|
6838
|
+
nodeIds: [A.capacityMeshNodeId, B.capacityMeshNodeId]
|
|
6839
|
+
});
|
|
6840
|
+
}
|
|
6841
|
+
}
|
|
6842
|
+
}
|
|
6843
|
+
this.handleTargetNodes();
|
|
6844
|
+
this.solved = true;
|
|
6845
|
+
}
|
|
6846
|
+
};
|
|
6847
|
+
|
|
6522
6848
|
// lib/solvers/AutoroutingPipelineSolver.ts
|
|
6523
6849
|
function definePipelineStep(solverName, solverClass, getConstructorParams, opts = {}) {
|
|
6524
6850
|
return {
|
|
@@ -6587,17 +6913,18 @@ var CapacityMeshSolver = class extends BaseSolver {
|
|
|
6587
6913
|
}
|
|
6588
6914
|
}
|
|
6589
6915
|
),
|
|
6590
|
-
// definePipelineStep("nodeSolver", CapacityMeshNodeSolver, (cms) => [
|
|
6591
|
-
// cms.netToPointPairsSolver?.getNewSimpleRouteJson() || cms.srj,
|
|
6592
|
-
// cms.opts,
|
|
6593
|
-
// ]),
|
|
6594
6916
|
definePipelineStep(
|
|
6595
6917
|
"nodeSolver",
|
|
6596
6918
|
CapacityMeshNodeSolver2_NodeUnderObstacle,
|
|
6597
6919
|
(cms) => [
|
|
6598
6920
|
cms.netToPointPairsSolver?.getNewSimpleRouteJson() || cms.srj,
|
|
6599
6921
|
cms.opts
|
|
6600
|
-
]
|
|
6922
|
+
],
|
|
6923
|
+
{
|
|
6924
|
+
onSolved: (cms) => {
|
|
6925
|
+
cms.capacityNodes = cms.nodeSolver?.finishedNodes;
|
|
6926
|
+
}
|
|
6927
|
+
}
|
|
6601
6928
|
),
|
|
6602
6929
|
// definePipelineStep("nodeTargetMerger", CapacityNodeTargetMerger, (cms) => [
|
|
6603
6930
|
// cms.nodeSolver?.finishedNodes || [],
|
|
@@ -6614,7 +6941,12 @@ var CapacityMeshSolver = class extends BaseSolver {
|
|
|
6614
6941
|
definePipelineStep(
|
|
6615
6942
|
"singleLayerNodeMerger",
|
|
6616
6943
|
SingleLayerNodeMergerSolver,
|
|
6617
|
-
(cms) => [cms.nodeSolver?.finishedNodes]
|
|
6944
|
+
(cms) => [cms.nodeSolver?.finishedNodes],
|
|
6945
|
+
{
|
|
6946
|
+
onSolved: (cms) => {
|
|
6947
|
+
cms.capacityNodes = cms.singleLayerNodeMerger?.newNodes;
|
|
6948
|
+
}
|
|
6949
|
+
}
|
|
6618
6950
|
),
|
|
6619
6951
|
definePipelineStep(
|
|
6620
6952
|
"strawSolver",
|
|
@@ -6626,9 +6958,11 @@ var CapacityMeshSolver = class extends BaseSolver {
|
|
|
6626
6958
|
}
|
|
6627
6959
|
}
|
|
6628
6960
|
),
|
|
6629
|
-
definePipelineStep(
|
|
6630
|
-
|
|
6631
|
-
|
|
6961
|
+
definePipelineStep(
|
|
6962
|
+
"edgeSolver",
|
|
6963
|
+
CapacityMeshEdgeSolver2_NodeTreeOptimization,
|
|
6964
|
+
(cms) => [cms.capacityNodes]
|
|
6965
|
+
),
|
|
6632
6966
|
definePipelineStep("pathingSolver", CapacityPathingSolver5, (cms) => [
|
|
6633
6967
|
{
|
|
6634
6968
|
simpleRouteJson: cms.srjWithPointPairs,
|