@tscircuit/capacity-autorouter 0.0.29 → 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 +11 -2
- package/dist/index.js +559 -252
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -85,177 +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
|
-
const strawNodesWithSameParent = this.nodes[i]._strawNode && this.nodes[j]._strawNode && this.nodes[i]._strawParentCapacityMeshNodeId === this.nodes[j]._strawParentCapacityMeshNodeId;
|
|
160
|
-
if (!strawNodesWithSameParent && areNodesBordering(this.nodes[i], this.nodes[j]) && this.doNodesHaveSharedLayer(this.nodes[i], this.nodes[j])) {
|
|
161
|
-
this.edges.push({
|
|
162
|
-
capacityMeshEdgeId: this.getNextCapacityMeshEdgeId(),
|
|
163
|
-
nodeIds: [
|
|
164
|
-
this.nodes[i].capacityMeshNodeId,
|
|
165
|
-
this.nodes[j].capacityMeshNodeId
|
|
166
|
-
]
|
|
167
|
-
});
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
const targetNodes = this.nodes.filter((node) => node._containsTarget);
|
|
172
|
-
for (const targetNode of targetNodes) {
|
|
173
|
-
const hasEdge = this.edges.some(
|
|
174
|
-
(edge) => edge.nodeIds.includes(targetNode.capacityMeshNodeId)
|
|
175
|
-
);
|
|
176
|
-
if (hasEdge) continue;
|
|
177
|
-
let nearestNode = null;
|
|
178
|
-
let nearestDistance = Infinity;
|
|
179
|
-
for (const node of this.nodes) {
|
|
180
|
-
if (node._containsObstacle) continue;
|
|
181
|
-
if (node._containsTarget) continue;
|
|
182
|
-
const dist = distance(targetNode.center, node.center);
|
|
183
|
-
if (dist < nearestDistance) {
|
|
184
|
-
nearestDistance = dist;
|
|
185
|
-
nearestNode = node;
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
if (nearestNode) {
|
|
189
|
-
this.edges.push({
|
|
190
|
-
capacityMeshEdgeId: this.getNextCapacityMeshEdgeId(),
|
|
191
|
-
nodeIds: [
|
|
192
|
-
targetNode.capacityMeshNodeId,
|
|
193
|
-
nearestNode.capacityMeshNodeId
|
|
194
|
-
]
|
|
195
|
-
});
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
this.solved = true;
|
|
199
|
-
}
|
|
200
|
-
doNodesHaveSharedLayer(node1, node2) {
|
|
201
|
-
return node1.availableZ.some((z) => node2.availableZ.includes(z));
|
|
202
|
-
}
|
|
203
|
-
visualize() {
|
|
204
|
-
const graphics = {
|
|
205
|
-
lines: [],
|
|
206
|
-
points: [],
|
|
207
|
-
rects: this.nodes.map((node) => {
|
|
208
|
-
const lowestZ = Math.min(...node.availableZ);
|
|
209
|
-
return {
|
|
210
|
-
width: Math.max(node.width - 2, node.width * 0.8),
|
|
211
|
-
height: Math.max(node.height - 2, node.height * 0.8),
|
|
212
|
-
center: {
|
|
213
|
-
x: node.center.x + lowestZ * node.width * 0.05,
|
|
214
|
-
y: node.center.y - lowestZ * node.width * 0.05
|
|
215
|
-
},
|
|
216
|
-
fill: node._containsObstacle ? "rgba(255,0,0,0.1)" : {
|
|
217
|
-
"0,1": "rgba(0,0,0,0.1)",
|
|
218
|
-
"0": "rgba(0,200,200, 0.1)",
|
|
219
|
-
"1": "rgba(0,0,200, 0.1)"
|
|
220
|
-
}[node.availableZ.join(",")] ?? "rgba(0,200,200,0.1)",
|
|
221
|
-
label: [
|
|
222
|
-
node.capacityMeshNodeId,
|
|
223
|
-
`availableZ: ${node.availableZ.join(",")}`,
|
|
224
|
-
`target? ${node._containsTarget ?? false}`,
|
|
225
|
-
`obs? ${node._containsObstacle ?? false}`
|
|
226
|
-
].join("\n")
|
|
227
|
-
};
|
|
228
|
-
}),
|
|
229
|
-
circles: []
|
|
230
|
-
};
|
|
231
|
-
for (const edge of this.edges) {
|
|
232
|
-
const node1 = this.nodes.find(
|
|
233
|
-
(node) => node.capacityMeshNodeId === edge.nodeIds[0]
|
|
234
|
-
);
|
|
235
|
-
const node2 = this.nodes.find(
|
|
236
|
-
(node) => node.capacityMeshNodeId === edge.nodeIds[1]
|
|
237
|
-
);
|
|
238
|
-
if (node1?.center && node2?.center) {
|
|
239
|
-
const lowestZ1 = Math.min(...node1.availableZ);
|
|
240
|
-
const lowestZ2 = Math.min(...node2.availableZ);
|
|
241
|
-
const nodeCenter1Adj = {
|
|
242
|
-
x: node1.center.x + lowestZ1 * node1.width * 0.05,
|
|
243
|
-
y: node1.center.y - lowestZ1 * node1.width * 0.05
|
|
244
|
-
};
|
|
245
|
-
const nodeCenter2Adj = {
|
|
246
|
-
x: node2.center.x + lowestZ2 * node2.width * 0.05,
|
|
247
|
-
y: node2.center.y - lowestZ2 * node2.width * 0.05
|
|
248
|
-
};
|
|
249
|
-
graphics.lines.push({
|
|
250
|
-
points: [nodeCenter1Adj, nodeCenter2Adj],
|
|
251
|
-
strokeDash: node1.availableZ.join(",") === node2.availableZ.join(",") ? void 0 : "10 5"
|
|
252
|
-
});
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
return graphics;
|
|
256
|
-
}
|
|
257
|
-
};
|
|
258
|
-
|
|
259
88
|
// node_modules/@babel/runtime/helpers/esm/extends.js
|
|
260
89
|
function _extends() {
|
|
261
90
|
return _extends = Object.assign ? Object.assign.bind() : function(n) {
|
|
@@ -1942,6 +1771,46 @@ var CapacitySegmentToPointSolver = class extends BaseSolver {
|
|
|
1942
1771
|
}
|
|
1943
1772
|
};
|
|
1944
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
|
+
|
|
1945
1814
|
// lib/solvers/HighDensitySolver/SingleHighDensityRouteSolver.ts
|
|
1946
1815
|
var SingleHighDensityRouteSolver = class extends BaseSolver {
|
|
1947
1816
|
obstacleRoutes;
|
|
@@ -3685,6 +3554,7 @@ var MultipleHighDensityRouteStitchSolver = class extends BaseSolver {
|
|
|
3685
3554
|
z: mapLayerNameToZ(c.pointsToConnect[1].layer, opts.layerCount)
|
|
3686
3555
|
}
|
|
3687
3556
|
}));
|
|
3557
|
+
this.MAX_ITERATIONS = 1e5;
|
|
3688
3558
|
}
|
|
3689
3559
|
_step() {
|
|
3690
3560
|
if (this.activeSolver) {
|
|
@@ -4169,16 +4039,16 @@ var UnravelSectionSolver = class extends BaseSolver {
|
|
|
4169
4039
|
segmentPoint.segmentPointId
|
|
4170
4040
|
]);
|
|
4171
4041
|
}
|
|
4172
|
-
for (
|
|
4173
|
-
|
|
4174
|
-
|
|
4175
|
-
|
|
4176
|
-
|
|
4177
|
-
|
|
4178
|
-
|
|
4179
|
-
|
|
4180
|
-
(
|
|
4181
|
-
|
|
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;
|
|
4182
4052
|
A.directlyConnectedSegmentPointIds.push(B.segmentPointId);
|
|
4183
4053
|
B.directlyConnectedSegmentPointIds.push(A.segmentPointId);
|
|
4184
4054
|
}
|
|
@@ -5423,6 +5293,7 @@ var StrawSolver = class extends BaseSolver {
|
|
|
5423
5293
|
nodeIdCounter;
|
|
5424
5294
|
constructor(params) {
|
|
5425
5295
|
super();
|
|
5296
|
+
this.MAX_ITERATIONS = 1e5;
|
|
5426
5297
|
this.strawSize = params.strawSize ?? 0.5;
|
|
5427
5298
|
this.multiLayerNodes = [];
|
|
5428
5299
|
this.strawNodes = [];
|
|
@@ -5615,6 +5486,72 @@ ${node.width}x${node.height}`
|
|
|
5615
5486
|
}
|
|
5616
5487
|
};
|
|
5617
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
|
+
|
|
5618
5555
|
// lib/solvers/SingleLayerNodeMerger/SingleLayerNodeMergerSolver.ts
|
|
5619
5556
|
var EPSILON = 5e-3;
|
|
5620
5557
|
var SingleLayerNodeMergerSolver = class extends BaseSolver {
|
|
@@ -5623,6 +5560,7 @@ var SingleLayerNodeMergerSolver = class extends BaseSolver {
|
|
|
5623
5560
|
absorbedNodeIds;
|
|
5624
5561
|
nextBatchNodeIds;
|
|
5625
5562
|
batchHadModifications;
|
|
5563
|
+
hasComputedAdjacentNodeIds = false;
|
|
5626
5564
|
newNodes;
|
|
5627
5565
|
constructor(nodes) {
|
|
5628
5566
|
super();
|
|
@@ -5633,41 +5571,94 @@ var SingleLayerNodeMergerSolver = class extends BaseSolver {
|
|
|
5633
5571
|
}
|
|
5634
5572
|
this.newNodes = [];
|
|
5635
5573
|
this.absorbedNodeIds = /* @__PURE__ */ new Set();
|
|
5636
|
-
const
|
|
5574
|
+
const unprocessedNodesWithArea = [];
|
|
5637
5575
|
for (const node of nodes) {
|
|
5638
5576
|
if (node.availableZ.length > 1) {
|
|
5639
5577
|
this.newNodes.push(node);
|
|
5640
5578
|
this.absorbedNodeIds.add(node.capacityMeshNodeId);
|
|
5641
5579
|
} else {
|
|
5642
|
-
|
|
5580
|
+
unprocessedNodesWithArea.push([node, node.width * node.height]);
|
|
5643
5581
|
}
|
|
5644
5582
|
}
|
|
5645
|
-
|
|
5646
|
-
for (const [
|
|
5647
|
-
const
|
|
5648
|
-
this.nodeMap.set(nodeId, {
|
|
5583
|
+
unprocessedNodesWithArea.sort((a, b) => a[1] - b[1]);
|
|
5584
|
+
for (const [node, area] of unprocessedNodesWithArea) {
|
|
5585
|
+
const unprocessedNode = {
|
|
5649
5586
|
...node,
|
|
5650
5587
|
center: { ...node.center }
|
|
5651
|
-
}
|
|
5588
|
+
};
|
|
5589
|
+
this.nodeMap.set(node.capacityMeshNodeId, unprocessedNode);
|
|
5652
5590
|
}
|
|
5653
|
-
this.currentBatchNodeIds =
|
|
5591
|
+
this.currentBatchNodeIds = unprocessedNodesWithArea.map(
|
|
5592
|
+
([node]) => node.capacityMeshNodeId
|
|
5593
|
+
);
|
|
5654
5594
|
this.nextBatchNodeIds = [];
|
|
5655
5595
|
this.batchHadModifications = false;
|
|
5656
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
|
+
// }
|
|
5657
5638
|
getAdjacentSameLayerUnprocessedNodes(rootNode) {
|
|
5639
|
+
return this.getAdjacentSameLayerUnprocessedNodes2(rootNode);
|
|
5640
|
+
}
|
|
5641
|
+
getAdjacentSameLayerUnprocessedNodes2(rootNode) {
|
|
5658
5642
|
const adjacentNodes = [];
|
|
5659
|
-
|
|
5660
|
-
|
|
5661
|
-
|
|
5662
|
-
|
|
5663
|
-
|
|
5664
|
-
|
|
5665
|
-
|
|
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;
|
|
5666
5651
|
adjacentNodes.push(unprocessedNode);
|
|
5667
5652
|
}
|
|
5668
5653
|
return adjacentNodes;
|
|
5669
5654
|
}
|
|
5670
5655
|
_step() {
|
|
5656
|
+
if (!this.hasComputedAdjacentNodeIds) {
|
|
5657
|
+
this.computeAdjacentNodeIdsForFirstBatch(
|
|
5658
|
+
this.currentBatchNodeIds.map((id) => this.nodeMap.get(id))
|
|
5659
|
+
);
|
|
5660
|
+
this.hasComputedAdjacentNodeIds = true;
|
|
5661
|
+
}
|
|
5671
5662
|
let rootNodeId = this.currentBatchNodeIds.pop();
|
|
5672
5663
|
while (rootNodeId && this.absorbedNodeIds.has(rootNodeId)) {
|
|
5673
5664
|
rootNodeId = this.currentBatchNodeIds.pop();
|
|
@@ -5696,6 +5687,19 @@ var SingleLayerNodeMergerSolver = class extends BaseSolver {
|
|
|
5696
5687
|
this.nextBatchNodeIds.push(rootNodeId);
|
|
5697
5688
|
return;
|
|
5698
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
|
+
};
|
|
5699
5703
|
const adjacentNodesToLeft = adjacentNodes.filter(
|
|
5700
5704
|
(adjNode) => adjNode.center.x < rootNode.center.x && Math.abs(adjNode.center.y - rootNode.center.y) < rootNode.height / 2
|
|
5701
5705
|
);
|
|
@@ -5712,9 +5716,7 @@ var SingleLayerNodeMergerSolver = class extends BaseSolver {
|
|
|
5712
5716
|
if (leftAdjNodesTakeUpEntireHeight && leftAdjNodesAreAllSameSize) {
|
|
5713
5717
|
rootNode.width += leftAdjNodeWidth;
|
|
5714
5718
|
rootNode.center.x = rootNode.center.x - leftAdjNodeWidth / 2;
|
|
5715
|
-
|
|
5716
|
-
this.absorbedNodeIds.add(adjNode.capacityMeshNodeId);
|
|
5717
|
-
}
|
|
5719
|
+
absorbAdjacentNodeIds(adjacentNodesToLeft);
|
|
5718
5720
|
rootNodeHasGrown = true;
|
|
5719
5721
|
}
|
|
5720
5722
|
}
|
|
@@ -5734,9 +5736,7 @@ var SingleLayerNodeMergerSolver = class extends BaseSolver {
|
|
|
5734
5736
|
if (rightAdjNodesTakeUpEntireHeight && rightAdjNodesAreAllSameSize) {
|
|
5735
5737
|
rootNode.width += rightAdjNodeWidth;
|
|
5736
5738
|
rootNode.center.x = rootNode.center.x + rightAdjNodeWidth / 2;
|
|
5737
|
-
|
|
5738
|
-
this.absorbedNodeIds.add(adjNode.capacityMeshNodeId);
|
|
5739
|
-
}
|
|
5739
|
+
absorbAdjacentNodeIds(adjacentNodesToRight);
|
|
5740
5740
|
rootNodeHasGrown = true;
|
|
5741
5741
|
}
|
|
5742
5742
|
}
|
|
@@ -5756,9 +5756,7 @@ var SingleLayerNodeMergerSolver = class extends BaseSolver {
|
|
|
5756
5756
|
if (topAdjNodesTakeUpEntireWidth && topAdjNodesAreAllSameSize) {
|
|
5757
5757
|
rootNode.height += topAdjNodeHeight;
|
|
5758
5758
|
rootNode.center.y = rootNode.center.y + topAdjNodeHeight / 2;
|
|
5759
|
-
|
|
5760
|
-
this.absorbedNodeIds.add(adjNode.capacityMeshNodeId);
|
|
5761
|
-
}
|
|
5759
|
+
absorbAdjacentNodeIds(adjacentNodesToTop);
|
|
5762
5760
|
rootNodeHasGrown = true;
|
|
5763
5761
|
}
|
|
5764
5762
|
}
|
|
@@ -5778,9 +5776,7 @@ var SingleLayerNodeMergerSolver = class extends BaseSolver {
|
|
|
5778
5776
|
if (bottomAdjNodesTakeUpEntireWidth && bottomAdjNodesAreAllSameSize) {
|
|
5779
5777
|
rootNode.height += bottomAdjNodeHeight;
|
|
5780
5778
|
rootNode.center.y = rootNode.center.y - bottomAdjNodeHeight / 2;
|
|
5781
|
-
|
|
5782
|
-
this.absorbedNodeIds.add(adjNode.capacityMeshNodeId);
|
|
5783
|
-
}
|
|
5779
|
+
absorbAdjacentNodeIds(adjacentNodesToBottom);
|
|
5784
5780
|
rootNodeHasGrown = true;
|
|
5785
5781
|
}
|
|
5786
5782
|
}
|
|
@@ -5870,7 +5866,7 @@ var SingleSimplifiedPathSolver = class extends BaseSolver {
|
|
|
5870
5866
|
this.obstacles = params.obstacles;
|
|
5871
5867
|
this.connMap = params.connMap;
|
|
5872
5868
|
this.colorMap = params.colorMap;
|
|
5873
|
-
this.newRoute = [];
|
|
5869
|
+
this.newRoute = [this.inputRoute.route[0]];
|
|
5874
5870
|
this.newVias = [];
|
|
5875
5871
|
}
|
|
5876
5872
|
get simplifiedRoute() {
|
|
@@ -6055,32 +6051,169 @@ function segmentsIntersect(A1, A2, B1, B2) {
|
|
|
6055
6051
|
return false;
|
|
6056
6052
|
}
|
|
6057
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
|
+
|
|
6058
6115
|
// lib/solvers/SimplifiedPathSolver/SingleSimplifiedPathSolver5_Deg45.ts
|
|
6059
6116
|
var SingleSimplifiedPathSolver5 = class extends SingleSimplifiedPathSolver {
|
|
6060
6117
|
pathSegments = [];
|
|
6061
6118
|
totalPathLength = 0;
|
|
6062
6119
|
headDistanceAlongPath = 0;
|
|
6063
6120
|
tailDistanceAlongPath = 0;
|
|
6064
|
-
|
|
6121
|
+
minStepSize = 0.25;
|
|
6065
6122
|
// Default step size, can be adjusted
|
|
6066
6123
|
lastValidPath = null;
|
|
6067
6124
|
// Store the current valid path
|
|
6068
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;
|
|
6069
6132
|
filteredObstacles = [];
|
|
6133
|
+
filteredObstaclePathSegments = [];
|
|
6134
|
+
filteredVias = [];
|
|
6135
|
+
segmentTree;
|
|
6070
6136
|
OBSTACLE_MARGIN = 0.15;
|
|
6071
6137
|
TAIL_JUMP_RATIO = 0.8;
|
|
6072
6138
|
constructor(params) {
|
|
6073
6139
|
super(params);
|
|
6140
|
+
this.cachedValidPathSegments = /* @__PURE__ */ new Set();
|
|
6074
6141
|
if (this.inputRoute.route.length <= 1) {
|
|
6075
6142
|
this.newRoute = [...this.inputRoute.route];
|
|
6076
6143
|
this.solved = true;
|
|
6077
6144
|
return;
|
|
6078
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
|
+
);
|
|
6079
6156
|
this.filteredObstacles = this.obstacles.filter(
|
|
6080
6157
|
(obstacle) => !obstacle.connectedTo.some(
|
|
6081
6158
|
(id) => this.connMap.areIdsConnected(this.inputRoute.connectionName, id)
|
|
6082
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
|
+
}
|
|
6083
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
|
+
});
|
|
6084
6217
|
this.computePathSegments();
|
|
6085
6218
|
}
|
|
6086
6219
|
// Compute the path segments and their distances
|
|
@@ -6118,7 +6251,7 @@ var SingleSimplifiedPathSolver5 = class extends SingleSimplifiedPathSolver {
|
|
|
6118
6251
|
return {
|
|
6119
6252
|
x: segment.start.x + factor * (segment.end.x - segment.start.x),
|
|
6120
6253
|
y: segment.start.y + factor * (segment.end.y - segment.start.y),
|
|
6121
|
-
z: segment.start.z
|
|
6254
|
+
z: factor < 0.5 ? segment.start.z : segment.end.z
|
|
6122
6255
|
// Z doesn't interpolate - use the segment's start z value
|
|
6123
6256
|
};
|
|
6124
6257
|
}
|
|
@@ -6169,33 +6302,24 @@ var SingleSimplifiedPathSolver5 = class extends SingleSimplifiedPathSolver {
|
|
|
6169
6302
|
return false;
|
|
6170
6303
|
}
|
|
6171
6304
|
}
|
|
6172
|
-
|
|
6173
|
-
|
|
6174
|
-
|
|
6175
|
-
|
|
6176
|
-
|
|
6177
|
-
|
|
6178
|
-
|
|
6179
|
-
|
|
6180
|
-
|
|
6181
|
-
const routeEnd = route.route[j + 1];
|
|
6182
|
-
if (routeStart.z === start.z && routeEnd.z === start.z) {
|
|
6183
|
-
if (minimumDistanceBetweenSegments(
|
|
6184
|
-
{ x: start.x, y: start.y },
|
|
6185
|
-
{ x: end.x, y: end.y },
|
|
6186
|
-
{ x: routeStart.x, y: routeStart.y },
|
|
6187
|
-
{ x: routeEnd.x, y: routeEnd.y }
|
|
6188
|
-
) < this.OBSTACLE_MARGIN) {
|
|
6189
|
-
return false;
|
|
6190
|
-
}
|
|
6191
|
-
}
|
|
6192
|
-
}
|
|
6193
|
-
for (const via of route.vias) {
|
|
6194
|
-
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) {
|
|
6195
6314
|
return false;
|
|
6196
6315
|
}
|
|
6197
6316
|
}
|
|
6198
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
|
+
}
|
|
6199
6323
|
return true;
|
|
6200
6324
|
}
|
|
6201
6325
|
// Check if a path with multiple points is valid
|
|
@@ -6242,6 +6366,24 @@ var SingleSimplifiedPathSolver5 = class extends SingleSimplifiedPathSolver {
|
|
|
6242
6366
|
}
|
|
6243
6367
|
this.newRoute.push(path[i]);
|
|
6244
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
|
+
);
|
|
6245
6387
|
}
|
|
6246
6388
|
_step() {
|
|
6247
6389
|
const tailHasReachedEnd = this.tailDistanceAlongPath >= this.totalPathLength;
|
|
@@ -6273,10 +6415,7 @@ var SingleSimplifiedPathSolver5 = class extends SingleSimplifiedPathSolver {
|
|
|
6273
6415
|
}
|
|
6274
6416
|
}
|
|
6275
6417
|
}
|
|
6276
|
-
this.
|
|
6277
|
-
this.headDistanceAlongPath + this.stepSize,
|
|
6278
|
-
this.totalPathLength
|
|
6279
|
-
);
|
|
6418
|
+
this.moveHead(this.currentStepSize);
|
|
6280
6419
|
const tailPoint = this.getPointAtDistance(this.tailDistanceAlongPath);
|
|
6281
6420
|
const headPoint = this.getPointAtDistance(this.headDistanceAlongPath);
|
|
6282
6421
|
const tailIndex = this.getNearestIndexForDistance(
|
|
@@ -6295,21 +6434,26 @@ var SingleSimplifiedPathSolver5 = class extends SingleSimplifiedPathSolver {
|
|
|
6295
6434
|
break;
|
|
6296
6435
|
}
|
|
6297
6436
|
}
|
|
6437
|
+
if (layerChangeBtwHeadAndTail && this.lastHeadMoveDistance > this.minStepSize) {
|
|
6438
|
+
this.stepBackAndReduceStepSize();
|
|
6439
|
+
return;
|
|
6440
|
+
}
|
|
6298
6441
|
if (layerChangeBtwHeadAndTail && layerChangeAtDistance > 0) {
|
|
6442
|
+
const pointBeforeChange = this.getPointAtDistance(layerChangeAtDistance);
|
|
6299
6443
|
if (this.lastValidPath) {
|
|
6300
6444
|
this.addPathToResult(this.lastValidPath);
|
|
6301
6445
|
this.lastValidPath = null;
|
|
6302
6446
|
}
|
|
6303
|
-
const
|
|
6304
|
-
const pointAfterChange = this.inputRoute.route[
|
|
6447
|
+
const indexAfterLayerChange = this.getNearestIndexForDistance(layerChangeAtDistance) + 1;
|
|
6448
|
+
const pointAfterChange = this.inputRoute.route[indexAfterLayerChange];
|
|
6305
6449
|
this.newVias.push({
|
|
6306
6450
|
x: pointAfterChange.x,
|
|
6307
6451
|
y: pointAfterChange.y
|
|
6308
6452
|
});
|
|
6309
6453
|
this.newRoute.push(pointAfterChange);
|
|
6310
|
-
|
|
6311
|
-
if (this.pathSegments[
|
|
6312
|
-
this.tailDistanceAlongPath = this.pathSegments[
|
|
6454
|
+
this.currentStepSize = this.maxStepSize;
|
|
6455
|
+
if (this.pathSegments[indexAfterLayerChange]) {
|
|
6456
|
+
this.tailDistanceAlongPath = this.pathSegments[indexAfterLayerChange].startDistance;
|
|
6313
6457
|
this.headDistanceAlongPath = this.tailDistanceAlongPath;
|
|
6314
6458
|
} else {
|
|
6315
6459
|
console.error("Creating via at end, this is probably not right");
|
|
@@ -6319,9 +6463,13 @@ var SingleSimplifiedPathSolver5 = class extends SingleSimplifiedPathSolver {
|
|
|
6319
6463
|
return;
|
|
6320
6464
|
}
|
|
6321
6465
|
const path45 = this.find45DegreePath(tailPoint, headPoint);
|
|
6466
|
+
if (!path45 && this.lastHeadMoveDistance > this.minStepSize) {
|
|
6467
|
+
this.stepBackAndReduceStepSize();
|
|
6468
|
+
return;
|
|
6469
|
+
}
|
|
6322
6470
|
if (!path45 && !this.lastValidPath) {
|
|
6323
|
-
this.tailDistanceAlongPath += this.
|
|
6324
|
-
this.
|
|
6471
|
+
this.tailDistanceAlongPath += this.minStepSize;
|
|
6472
|
+
this.moveHead(this.minStepSize);
|
|
6325
6473
|
return;
|
|
6326
6474
|
}
|
|
6327
6475
|
if (path45) {
|
|
@@ -6333,11 +6481,8 @@ var SingleSimplifiedPathSolver5 = class extends SingleSimplifiedPathSolver {
|
|
|
6333
6481
|
this.addPathToResult(this.lastValidPath);
|
|
6334
6482
|
this.lastValidPath = null;
|
|
6335
6483
|
this.tailDistanceAlongPath = this.lastValidPathHeadDistance;
|
|
6484
|
+
this.moveHead(this.minStepSize);
|
|
6336
6485
|
}
|
|
6337
|
-
this.headDistanceAlongPath = Math.min(
|
|
6338
|
-
this.headDistanceAlongPath + this.stepSize,
|
|
6339
|
-
this.totalPathLength
|
|
6340
|
-
);
|
|
6341
6486
|
}
|
|
6342
6487
|
visualize() {
|
|
6343
6488
|
const graphics = this.getVisualsForNewRouteAndObstacles();
|
|
@@ -6355,6 +6500,15 @@ var SingleSimplifiedPathSolver5 = class extends SingleSimplifiedPathSolver {
|
|
|
6355
6500
|
color: "orange",
|
|
6356
6501
|
label: ["Head", `z: ${headPoint.z}`].join("\n")
|
|
6357
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
|
+
});
|
|
6358
6512
|
let distance4 = 0;
|
|
6359
6513
|
while (distance4 < this.totalPathLength) {
|
|
6360
6514
|
const point = this.getPointAtDistance(distance4);
|
|
@@ -6540,6 +6694,157 @@ var MultiSimplifiedPathSolver = class extends BaseSolver {
|
|
|
6540
6694
|
}
|
|
6541
6695
|
};
|
|
6542
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
|
+
|
|
6543
6848
|
// lib/solvers/AutoroutingPipelineSolver.ts
|
|
6544
6849
|
function definePipelineStep(solverName, solverClass, getConstructorParams, opts = {}) {
|
|
6545
6850
|
return {
|
|
@@ -6653,9 +6958,11 @@ var CapacityMeshSolver = class extends BaseSolver {
|
|
|
6653
6958
|
}
|
|
6654
6959
|
}
|
|
6655
6960
|
),
|
|
6656
|
-
definePipelineStep(
|
|
6657
|
-
|
|
6658
|
-
|
|
6961
|
+
definePipelineStep(
|
|
6962
|
+
"edgeSolver",
|
|
6963
|
+
CapacityMeshEdgeSolver2_NodeTreeOptimization,
|
|
6964
|
+
(cms) => [cms.capacityNodes]
|
|
6965
|
+
),
|
|
6659
6966
|
definePipelineStep("pathingSolver", CapacityPathingSolver5, (cms) => [
|
|
6660
6967
|
{
|
|
6661
6968
|
simpleRouteJson: cms.srjWithPointPairs,
|