@tscircuit/schematic-trace-solver 0.0.40 → 0.0.42
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 +155 -9
- package/dist/index.js +998 -479
- package/lib/solvers/LongDistancePairSolver/LongDistancePairSolver.ts +238 -0
- package/lib/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver.ts +61 -26
- package/lib/solvers/TraceLabelOverlapAvoidanceSolver/TraceLabelOverlapAvoidanceSolver.ts +94 -192
- package/lib/solvers/TraceLabelOverlapAvoidanceSolver/rerouteCollidingTrace.ts +13 -24
- package/lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/LabelMergingSolver/LabelMergingSolver.ts +205 -0
- package/lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/OverlapAvoidanceStepSolver/OverlapAvoidanceStepSolver.ts +144 -0
- package/lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/SingleOverlapSolver/SingleOverlapSolver.ts +117 -0
- package/lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/TraceCleanupSolver/TraceCleanupSolver.ts +132 -0
- package/lib/solvers/TraceLabelOverlapAvoidanceSolver/{balanceLShapes.ts → sub-solvers/TraceCleanupSolver/balanceLShapes.ts} +12 -10
- package/lib/solvers/TraceLabelOverlapAvoidanceSolver/{hasCollisions.ts → sub-solvers/TraceCleanupSolver/hasCollisions.ts} +1 -1
- package/lib/solvers/TraceLabelOverlapAvoidanceSolver/{hasCollisionsWithLabels.ts → sub-solvers/TraceCleanupSolver/hasCollisionsWithLabels.ts} +1 -1
- package/lib/solvers/TraceLabelOverlapAvoidanceSolver/{minimizeTurnsWithFilteredLabels.ts → sub-solvers/TraceCleanupSolver/minimizeTurnsWithFilteredLabels.ts} +6 -6
- package/lib/solvers/TraceLabelOverlapAvoidanceSolver/{simplifyPath.ts → sub-solvers/TraceCleanupSolver/simplifyPath.ts} +1 -1
- package/lib/solvers/TraceLabelOverlapAvoidanceSolver/{turnMinimization.ts → sub-solvers/TraceCleanupSolver/turnMinimization.ts} +0 -2
- package/lib/solvers/TraceLabelOverlapAvoidanceSolver/tryFourPointDetour.ts +104 -0
- package/lib/solvers/TraceLabelOverlapAvoidanceSolver/trySnipAndReconnect.ts +24 -154
- package/lib/utils/does-trace-overlap-with-existing-traces.ts +33 -0
- package/package.json +1 -1
- package/site/examples/example25.page.tsx +4 -0
- package/tests/assets/1.input.json +379 -0
- package/tests/assets/2.input.json +330 -0
- package/tests/assets/3.input.json +388 -0
- package/tests/assets/MergedNetLabelObstacles.test.input.json +154 -0
- package/tests/assets/OverlapAvoidanceStepSolver.test.input.json +682 -0
- package/tests/assets/SingleOverlapSolver.test.input.json +170 -0
- package/tests/assets/TraceCleanupSolver.test.input.json +216 -0
- package/tests/assets/TraceLabelOverlapAvoidanceSolver.test.input.json +424 -0
- package/tests/assets/example25.json +96 -0
- package/tests/examples/__snapshots__/example03.snap.svg +67 -76
- package/tests/examples/__snapshots__/example10.snap.svg +24 -30
- package/tests/examples/__snapshots__/example13.snap.svg +81 -84
- package/tests/examples/__snapshots__/example15.snap.svg +5 -8
- package/tests/examples/__snapshots__/example21.snap.svg +68 -74
- package/tests/examples/__snapshots__/example25.snap.svg +3 -3
- package/tests/examples/__snapshots__/example26.snap.svg +3 -3
- package/tests/examples/__snapshots__/example28.snap.svg +273 -0
- package/tests/examples/example28.test.ts +13 -0
- package/tests/solvers/TraceLabelOverlapAvoidanceSolver/TraceLabelOverlapAvoidanceSolver.test.ts +18 -0
- package/tests/solvers/TraceLabelOverlapAvoidanceSolver/__snapshots__/TraceLabelOverlapAvoidanceSolver.snap.svg +243 -0
- package/tests/solvers/TraceLabelOverlapAvoidanceSolver/renderComparisonView/__snapshots__/renderComparisonView01.snap.svg +223 -0
- package/tests/solvers/TraceLabelOverlapAvoidanceSolver/renderComparisonView/__snapshots__/renderComparisonView02.snap.svg +205 -0
- package/tests/solvers/TraceLabelOverlapAvoidanceSolver/renderComparisonView/__snapshots__/renderComparisonView03.snap.svg +184 -0
- package/tests/solvers/TraceLabelOverlapAvoidanceSolver/renderComparisonView/renderComparisonView01.test.ts +29 -0
- package/tests/solvers/TraceLabelOverlapAvoidanceSolver/renderComparisonView/renderComparisonView02.test.ts +27 -0
- package/tests/solvers/TraceLabelOverlapAvoidanceSolver/renderComparisonView/renderComparisonView03.test.ts +39 -0
- package/tests/solvers/TraceLabelOverlapAvoidanceSolver/sub-solver/MergedNetLabelObstacles.test.ts +14 -0
- package/tests/solvers/TraceLabelOverlapAvoidanceSolver/sub-solver/OverlapAvoidanceStepSolver.test.ts +20 -0
- package/tests/solvers/TraceLabelOverlapAvoidanceSolver/sub-solver/SingleOverlapSolver.test.ts +10 -0
- package/tests/solvers/TraceLabelOverlapAvoidanceSolver/sub-solver/TraceCleanupSolver.test.ts +19 -0
- package/tests/solvers/TraceLabelOverlapAvoidanceSolver/sub-solver/__snapshots__/MergedNetLabelObstacles.snap.svg +140 -0
- package/tests/solvers/TraceLabelOverlapAvoidanceSolver/sub-solver/__snapshots__/OverlapAvoidanceStepSolver.snap.svg +216 -0
- package/tests/solvers/TraceLabelOverlapAvoidanceSolver/sub-solver/__snapshots__/SingleOverlapSolver.snap.svg +125 -0
- package/tests/solvers/TraceLabelOverlapAvoidanceSolver/sub-solver/__snapshots__/TraceCleanupSolver.snap.svg +119 -0
- /package/lib/solvers/TraceLabelOverlapAvoidanceSolver/{countTurns.ts → sub-solvers/TraceCleanupSolver/countTurns.ts} +0 -0
- /package/lib/solvers/TraceLabelOverlapAvoidanceSolver/{tryConnectPoints.ts → sub-solvers/TraceCleanupSolver/tryConnectPoints.ts} +0 -0
package/dist/index.js
CHANGED
|
@@ -2196,48 +2196,193 @@ var NetLabelPlacementSolver = class extends BaseSolver {
|
|
|
2196
2196
|
}
|
|
2197
2197
|
};
|
|
2198
2198
|
|
|
2199
|
-
// lib/solvers/
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2199
|
+
// lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/LabelMergingSolver/LabelMergingSolver.ts
|
|
2200
|
+
var MergedNetLabelObstacleSolver = class extends BaseSolver {
|
|
2201
|
+
input;
|
|
2202
|
+
output;
|
|
2203
|
+
inputProblem;
|
|
2204
|
+
traces;
|
|
2205
|
+
constructor(solverInput) {
|
|
2206
|
+
super();
|
|
2207
|
+
this.input = solverInput;
|
|
2208
|
+
this.inputProblem = solverInput.inputProblem;
|
|
2209
|
+
this.traces = solverInput.traces;
|
|
2210
|
+
this.output = {
|
|
2211
|
+
netLabelPlacements: solverInput.netLabelPlacements,
|
|
2212
|
+
mergedLabelNetIdMap: {}
|
|
2213
|
+
};
|
|
2214
|
+
}
|
|
2215
|
+
_step() {
|
|
2216
|
+
const originalLabels = this.input.netLabelPlacements;
|
|
2217
|
+
const mergedLabelNetIdMap = {};
|
|
2218
|
+
if (!originalLabels || originalLabels.length === 0) {
|
|
2219
|
+
this.output = {
|
|
2220
|
+
netLabelPlacements: [],
|
|
2221
|
+
mergedLabelNetIdMap: {}
|
|
2222
|
+
};
|
|
2223
|
+
this.solved = true;
|
|
2224
|
+
return;
|
|
2225
|
+
}
|
|
2226
|
+
const labelGroups = {};
|
|
2227
|
+
for (const p of originalLabels) {
|
|
2228
|
+
if (p.pinIds.length === 0) continue;
|
|
2229
|
+
const chipId = p.pinIds[0].split(".")[0];
|
|
2230
|
+
if (!chipId) continue;
|
|
2231
|
+
const key = `${chipId}-${p.orientation}`;
|
|
2232
|
+
if (!(key in labelGroups)) {
|
|
2233
|
+
labelGroups[key] = [];
|
|
2234
|
+
}
|
|
2235
|
+
labelGroups[key].push(p);
|
|
2236
|
+
}
|
|
2237
|
+
const finalPlacements = [];
|
|
2238
|
+
for (const [key, group] of Object.entries(labelGroups)) {
|
|
2239
|
+
if (group.length <= 1) {
|
|
2240
|
+
finalPlacements.push(...group);
|
|
2241
|
+
continue;
|
|
2242
|
+
}
|
|
2243
|
+
let minX = Infinity;
|
|
2244
|
+
let minY = Infinity;
|
|
2245
|
+
let maxX = -Infinity;
|
|
2246
|
+
let maxY = -Infinity;
|
|
2247
|
+
for (const p of group) {
|
|
2248
|
+
const bounds = getRectBounds(p.center, p.width, p.height);
|
|
2249
|
+
minX = Math.min(minX, bounds.minX);
|
|
2250
|
+
minY = Math.min(minY, bounds.minY);
|
|
2251
|
+
maxX = Math.max(maxX, bounds.maxX);
|
|
2252
|
+
maxY = Math.max(maxY, bounds.maxY);
|
|
2253
|
+
}
|
|
2254
|
+
const newWidth = maxX - minX;
|
|
2255
|
+
const newHeight = maxY - minY;
|
|
2256
|
+
const template = group[0];
|
|
2257
|
+
const syntheticId = `merged-group-${key}`;
|
|
2258
|
+
const originalNetIds = new Set(group.map((p) => p.globalConnNetId));
|
|
2259
|
+
mergedLabelNetIdMap[syntheticId] = originalNetIds;
|
|
2260
|
+
finalPlacements.push({
|
|
2261
|
+
...template,
|
|
2262
|
+
globalConnNetId: syntheticId,
|
|
2263
|
+
width: newWidth,
|
|
2264
|
+
height: newHeight,
|
|
2265
|
+
center: { x: minX + newWidth / 2, y: minY + newHeight / 2 },
|
|
2266
|
+
pinIds: [...new Set(group.flatMap((p) => p.pinIds))],
|
|
2267
|
+
mspConnectionPairIds: [
|
|
2268
|
+
...new Set(group.flatMap((p) => p.mspConnectionPairIds))
|
|
2269
|
+
]
|
|
2270
|
+
});
|
|
2271
|
+
}
|
|
2272
|
+
this.output = {
|
|
2273
|
+
netLabelPlacements: finalPlacements,
|
|
2274
|
+
mergedLabelNetIdMap
|
|
2275
|
+
};
|
|
2276
|
+
this.solved = true;
|
|
2277
|
+
}
|
|
2278
|
+
getOutput() {
|
|
2279
|
+
return this.output;
|
|
2280
|
+
}
|
|
2281
|
+
visualize() {
|
|
2282
|
+
const graphics = visualizeInputProblem(this.inputProblem, {
|
|
2283
|
+
chipAlpha: 0.1,
|
|
2284
|
+
connectionAlpha: 0.1
|
|
2285
|
+
});
|
|
2286
|
+
if (!graphics.rects) graphics.rects = [];
|
|
2287
|
+
if (!graphics.lines) graphics.lines = [];
|
|
2288
|
+
if (!graphics.points) graphics.points = [];
|
|
2289
|
+
if (!graphics.texts) graphics.texts = [];
|
|
2290
|
+
const originalLabelsById = /* @__PURE__ */ new Map();
|
|
2291
|
+
for (const label of this.input.netLabelPlacements) {
|
|
2292
|
+
originalLabelsById.set(label.globalConnNetId, label);
|
|
2293
|
+
}
|
|
2294
|
+
for (const trace of this.traces) {
|
|
2295
|
+
const line = {
|
|
2296
|
+
points: trace.tracePath.map((p) => ({ x: p.x, y: p.y })),
|
|
2297
|
+
strokeColor: "blue"
|
|
2298
|
+
};
|
|
2299
|
+
graphics.lines.push(line);
|
|
2300
|
+
}
|
|
2301
|
+
for (const finalLabel of this.output.netLabelPlacements) {
|
|
2302
|
+
const isMerged = finalLabel.globalConnNetId.startsWith("merged-group-");
|
|
2303
|
+
const color = getColorFromString(finalLabel.globalConnNetId);
|
|
2304
|
+
if (isMerged) {
|
|
2305
|
+
graphics.rects.push({
|
|
2306
|
+
center: finalLabel.center,
|
|
2307
|
+
width: finalLabel.width,
|
|
2308
|
+
height: finalLabel.height,
|
|
2309
|
+
fill: color.replace(/, 1\)/, ", 0.2)"),
|
|
2310
|
+
// semi-transparent
|
|
2311
|
+
stroke: color,
|
|
2312
|
+
label: finalLabel.globalConnNetId
|
|
2313
|
+
});
|
|
2314
|
+
const originalNetIds = this.output.mergedLabelNetIdMap[finalLabel.globalConnNetId];
|
|
2315
|
+
if (originalNetIds) {
|
|
2316
|
+
for (const originalNetId of originalNetIds) {
|
|
2317
|
+
const originalLabel = originalLabelsById.get(originalNetId);
|
|
2318
|
+
if (originalLabel) {
|
|
2319
|
+
const bounds = getRectBounds(
|
|
2320
|
+
originalLabel.center,
|
|
2321
|
+
originalLabel.width,
|
|
2322
|
+
originalLabel.height
|
|
2323
|
+
);
|
|
2324
|
+
const p1 = { x: bounds.minX, y: bounds.minY };
|
|
2325
|
+
const p2 = { x: bounds.maxX, y: bounds.minY };
|
|
2326
|
+
const p3 = { x: bounds.maxX, y: bounds.maxY };
|
|
2327
|
+
const p4 = { x: bounds.minX, y: bounds.maxY };
|
|
2328
|
+
graphics.lines.push({
|
|
2329
|
+
points: [p1, p2, p3, p4, p1],
|
|
2330
|
+
strokeColor: color,
|
|
2331
|
+
strokeDash: "4 4"
|
|
2332
|
+
});
|
|
2333
|
+
graphics.lines.push({
|
|
2334
|
+
points: [originalLabel.center, finalLabel.center],
|
|
2335
|
+
strokeColor: color,
|
|
2336
|
+
strokeDash: "2 2"
|
|
2337
|
+
});
|
|
2338
|
+
}
|
|
2214
2339
|
}
|
|
2215
|
-
overlaps.push({ trace, label });
|
|
2216
|
-
break;
|
|
2217
2340
|
}
|
|
2341
|
+
} else {
|
|
2342
|
+
graphics.rects.push({
|
|
2343
|
+
center: finalLabel.center,
|
|
2344
|
+
width: finalLabel.width,
|
|
2345
|
+
height: finalLabel.height,
|
|
2346
|
+
stroke: color,
|
|
2347
|
+
label: finalLabel.globalConnNetId
|
|
2348
|
+
});
|
|
2218
2349
|
}
|
|
2219
2350
|
}
|
|
2351
|
+
return graphics;
|
|
2220
2352
|
}
|
|
2221
|
-
return overlaps;
|
|
2222
2353
|
};
|
|
2223
2354
|
|
|
2224
|
-
// lib/solvers/TraceLabelOverlapAvoidanceSolver/
|
|
2225
|
-
var
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
firstInsideIndex = i;
|
|
2355
|
+
// lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/TraceCleanupSolver/hasCollisions.ts
|
|
2356
|
+
var hasCollisions = (pathSegments, obstacles) => {
|
|
2357
|
+
for (let i = 0; i < pathSegments.length - 1; i++) {
|
|
2358
|
+
const p1 = pathSegments[i];
|
|
2359
|
+
const p2 = pathSegments[i + 1];
|
|
2360
|
+
for (const obstacle of obstacles) {
|
|
2361
|
+
if (segmentIntersectsRect(p1, p2, obstacle)) {
|
|
2362
|
+
return true;
|
|
2233
2363
|
}
|
|
2234
|
-
lastInsideIndex = i;
|
|
2235
2364
|
}
|
|
2236
2365
|
}
|
|
2237
|
-
return
|
|
2366
|
+
return false;
|
|
2238
2367
|
};
|
|
2239
2368
|
|
|
2240
|
-
// lib/solvers/TraceLabelOverlapAvoidanceSolver/
|
|
2369
|
+
// lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/TraceCleanupSolver/countTurns.ts
|
|
2370
|
+
var countTurns = (points) => {
|
|
2371
|
+
let turns = 0;
|
|
2372
|
+
for (let i = 1; i < points.length - 1; i++) {
|
|
2373
|
+
const prev = points[i - 1];
|
|
2374
|
+
const curr = points[i];
|
|
2375
|
+
const next = points[i + 1];
|
|
2376
|
+
const prevVertical = prev.x === curr.x;
|
|
2377
|
+
const nextVertical = curr.x === next.x;
|
|
2378
|
+
if (prevVertical !== nextVertical) {
|
|
2379
|
+
turns++;
|
|
2380
|
+
}
|
|
2381
|
+
}
|
|
2382
|
+
return turns;
|
|
2383
|
+
};
|
|
2384
|
+
|
|
2385
|
+
// lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/TraceCleanupSolver/simplifyPath.ts
|
|
2241
2386
|
var simplifyPath = (path) => {
|
|
2242
2387
|
if (path.length < 3) return path;
|
|
2243
2388
|
const newPath = [path[0]];
|
|
@@ -2266,282 +2411,40 @@ var simplifyPath = (path) => {
|
|
|
2266
2411
|
return finalPath;
|
|
2267
2412
|
};
|
|
2268
2413
|
|
|
2269
|
-
// lib/solvers/TraceLabelOverlapAvoidanceSolver/
|
|
2270
|
-
var
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
})
|
|
2277
|
-
if (firstInsideIndex <= 0 || lastInsideIndex >= initialTrace.tracePath.length - 1) {
|
|
2278
|
-
return null;
|
|
2279
|
-
}
|
|
2280
|
-
const entryPoint = initialTrace.tracePath[firstInsideIndex - 1];
|
|
2281
|
-
const exitPoint = initialTrace.tracePath[lastInsideIndex + 1];
|
|
2282
|
-
const pathToEntry = initialTrace.tracePath.slice(0, firstInsideIndex);
|
|
2283
|
-
const pathFromExit = initialTrace.tracePath.slice(lastInsideIndex + 1);
|
|
2284
|
-
const candidateDetours = [];
|
|
2285
|
-
if (entryPoint.x !== exitPoint.x && entryPoint.y !== exitPoint.y) {
|
|
2286
|
-
candidateDetours.push([{ x: exitPoint.x, y: entryPoint.y }]);
|
|
2287
|
-
candidateDetours.push([{ x: entryPoint.x, y: exitPoint.y }]);
|
|
2288
|
-
} else if (entryPoint.x === exitPoint.x || entryPoint.y === exitPoint.y) {
|
|
2289
|
-
const newPath = [...pathToEntry, ...pathFromExit];
|
|
2290
|
-
const simplified = simplifyPath(newPath);
|
|
2291
|
-
if (!isPathCollidingWithObstacles(simplified, obstacles)) {
|
|
2292
|
-
return { ...initialTrace, tracePath: simplified };
|
|
2293
|
-
}
|
|
2294
|
-
}
|
|
2295
|
-
for (let i = 0; i < candidateDetours.length; i++) {
|
|
2296
|
-
const detour = candidateDetours[i];
|
|
2297
|
-
const newFullPath = [...pathToEntry, ...detour, ...pathFromExit];
|
|
2298
|
-
const simplified = simplifyPath(newFullPath);
|
|
2299
|
-
if (!isPathCollidingWithObstacles(simplified, obstacles)) {
|
|
2300
|
-
return { ...initialTrace, tracePath: simplified };
|
|
2301
|
-
}
|
|
2302
|
-
}
|
|
2303
|
-
candidateDetours.length = 0;
|
|
2304
|
-
const buffer = 0.1;
|
|
2305
|
-
const leftX = labelBounds.minX - buffer;
|
|
2306
|
-
const rightX = labelBounds.maxX + buffer;
|
|
2307
|
-
const topY = labelBounds.maxY + buffer;
|
|
2308
|
-
const bottomY = labelBounds.minY - buffer;
|
|
2309
|
-
if ((entryPoint.x <= labelBounds.minX || exitPoint.x <= labelBounds.minX) && entryPoint.x < labelBounds.maxX && exitPoint.x < labelBounds.maxX) {
|
|
2310
|
-
candidateDetours.push([
|
|
2311
|
-
{ x: leftX, y: entryPoint.y },
|
|
2312
|
-
{ x: leftX, y: exitPoint.y }
|
|
2313
|
-
]);
|
|
2314
|
-
}
|
|
2315
|
-
if ((entryPoint.x >= labelBounds.maxX || exitPoint.x >= labelBounds.maxX) && entryPoint.x > labelBounds.minX && exitPoint.x > labelBounds.minX) {
|
|
2316
|
-
candidateDetours.push([
|
|
2317
|
-
{ x: rightX, y: entryPoint.y },
|
|
2318
|
-
{ x: rightX, y: exitPoint.y }
|
|
2319
|
-
]);
|
|
2320
|
-
}
|
|
2321
|
-
if ((entryPoint.y >= labelBounds.maxY || exitPoint.y >= labelBounds.maxY) && entryPoint.y > labelBounds.minY && exitPoint.y > labelBounds.minY) {
|
|
2322
|
-
candidateDetours.push([
|
|
2323
|
-
{ x: entryPoint.x, y: topY },
|
|
2324
|
-
{ x: exitPoint.x, y: topY }
|
|
2325
|
-
]);
|
|
2326
|
-
}
|
|
2327
|
-
if ((entryPoint.y <= labelBounds.minY || exitPoint.y <= labelBounds.minY) && entryPoint.y < labelBounds.maxY && exitPoint.y < labelBounds.maxY) {
|
|
2328
|
-
candidateDetours.push([
|
|
2329
|
-
{ x: entryPoint.x, y: bottomY },
|
|
2330
|
-
{ x: exitPoint.x, y: bottomY }
|
|
2331
|
-
]);
|
|
2414
|
+
// lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/TraceCleanupSolver/tryConnectPoints.ts
|
|
2415
|
+
var tryConnectPoints = (start, end) => {
|
|
2416
|
+
const candidates = [];
|
|
2417
|
+
if (start.x === end.x || start.y === end.y) {
|
|
2418
|
+
candidates.push([start, end]);
|
|
2419
|
+
} else {
|
|
2420
|
+
candidates.push([start, { x: end.x, y: start.y }, end]);
|
|
2421
|
+
candidates.push([start, { x: start.x, y: end.y }, end]);
|
|
2332
2422
|
}
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2423
|
+
return candidates;
|
|
2424
|
+
};
|
|
2425
|
+
|
|
2426
|
+
// lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/TraceCleanupSolver/hasCollisionsWithLabels.ts
|
|
2427
|
+
var hasCollisionsWithLabels = (pathSegments, labels) => {
|
|
2428
|
+
for (let i = 0; i < pathSegments.length - 1; i++) {
|
|
2429
|
+
const p1 = pathSegments[i];
|
|
2430
|
+
const p2 = pathSegments[i + 1];
|
|
2431
|
+
for (const label of labels) {
|
|
2432
|
+
if (segmentIntersectsRect(p1, p2, label)) {
|
|
2433
|
+
return true;
|
|
2434
|
+
}
|
|
2339
2435
|
}
|
|
2340
2436
|
}
|
|
2341
|
-
return
|
|
2437
|
+
return false;
|
|
2342
2438
|
};
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2439
|
+
|
|
2440
|
+
// lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/TraceCleanupSolver/turnMinimization.ts
|
|
2441
|
+
var minimizeTurns = ({
|
|
2442
|
+
path,
|
|
2347
2443
|
obstacles,
|
|
2348
|
-
|
|
2349
|
-
detourCount
|
|
2444
|
+
labelBounds
|
|
2350
2445
|
}) => {
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
if (segmentIntersectsRect(
|
|
2354
|
-
initialTrace.tracePath[i],
|
|
2355
|
-
initialTrace.tracePath[i + 1],
|
|
2356
|
-
labelBounds
|
|
2357
|
-
)) {
|
|
2358
|
-
collidingSegIndex = i;
|
|
2359
|
-
break;
|
|
2360
|
-
}
|
|
2361
|
-
}
|
|
2362
|
-
if (collidingSegIndex === -1) return initialTrace;
|
|
2363
|
-
const pA = initialTrace.tracePath[collidingSegIndex];
|
|
2364
|
-
const pB = initialTrace.tracePath[collidingSegIndex + 1];
|
|
2365
|
-
if (!pA || !pB) return null;
|
|
2366
|
-
const candidateDetours = [];
|
|
2367
|
-
const paddedLabelBounds = getRectBounds(
|
|
2368
|
-
label.center,
|
|
2369
|
-
label.width,
|
|
2370
|
-
label.height
|
|
2371
|
-
);
|
|
2372
|
-
const effectivePadding = paddingBuffer + detourCount * paddingBuffer;
|
|
2373
|
-
if (isVertical(pA, pB)) {
|
|
2374
|
-
const xCandidates = [
|
|
2375
|
-
paddedLabelBounds.maxX + effectivePadding,
|
|
2376
|
-
paddedLabelBounds.minX - effectivePadding
|
|
2377
|
-
];
|
|
2378
|
-
for (const newX of xCandidates) {
|
|
2379
|
-
candidateDetours.push(
|
|
2380
|
-
pB.y > pA.y ? [
|
|
2381
|
-
{ x: pA.x, y: paddedLabelBounds.minY - effectivePadding },
|
|
2382
|
-
{ x: newX, y: paddedLabelBounds.minY - effectivePadding },
|
|
2383
|
-
{ x: newX, y: paddedLabelBounds.maxY + effectivePadding },
|
|
2384
|
-
{ x: pB.x, y: paddedLabelBounds.maxY + effectivePadding }
|
|
2385
|
-
] : [
|
|
2386
|
-
{ x: pA.x, y: paddedLabelBounds.maxY + effectivePadding },
|
|
2387
|
-
{ x: newX, y: paddedLabelBounds.maxY + effectivePadding },
|
|
2388
|
-
{ x: newX, y: paddedLabelBounds.minY - effectivePadding },
|
|
2389
|
-
{ x: pB.x, y: paddedLabelBounds.minY - effectivePadding }
|
|
2390
|
-
]
|
|
2391
|
-
);
|
|
2392
|
-
}
|
|
2393
|
-
} else {
|
|
2394
|
-
const yCandidates = [
|
|
2395
|
-
paddedLabelBounds.maxY + effectivePadding,
|
|
2396
|
-
paddedLabelBounds.minY - effectivePadding
|
|
2397
|
-
];
|
|
2398
|
-
for (const newY of yCandidates) {
|
|
2399
|
-
candidateDetours.push(
|
|
2400
|
-
pB.x > pA.x ? [
|
|
2401
|
-
{ x: paddedLabelBounds.minX - effectivePadding, y: pA.y },
|
|
2402
|
-
{ x: paddedLabelBounds.minX - effectivePadding, y: newY },
|
|
2403
|
-
{ x: paddedLabelBounds.maxX + effectivePadding, y: newY },
|
|
2404
|
-
{ x: paddedLabelBounds.maxX + effectivePadding, y: pB.y }
|
|
2405
|
-
] : [
|
|
2406
|
-
{ x: paddedLabelBounds.maxX + effectivePadding, y: pA.y },
|
|
2407
|
-
{ x: paddedLabelBounds.maxX + effectivePadding, y: newY },
|
|
2408
|
-
{ x: paddedLabelBounds.minX - effectivePadding, y: newY },
|
|
2409
|
-
{ x: paddedLabelBounds.minX - effectivePadding, y: pB.y }
|
|
2410
|
-
]
|
|
2411
|
-
);
|
|
2412
|
-
}
|
|
2413
|
-
}
|
|
2414
|
-
for (const detourPoints of candidateDetours) {
|
|
2415
|
-
const finalPath = [
|
|
2416
|
-
...initialTrace.tracePath.slice(0, collidingSegIndex + 1),
|
|
2417
|
-
...detourPoints,
|
|
2418
|
-
...initialTrace.tracePath.slice(collidingSegIndex + 1)
|
|
2419
|
-
];
|
|
2420
|
-
const simplifiedFinalPath = simplifyPath(finalPath);
|
|
2421
|
-
if (!isPathCollidingWithObstacles(simplifiedFinalPath, obstacles)) {
|
|
2422
|
-
return { ...initialTrace, tracePath: simplifiedFinalPath };
|
|
2423
|
-
}
|
|
2424
|
-
}
|
|
2425
|
-
return null;
|
|
2426
|
-
};
|
|
2427
|
-
|
|
2428
|
-
// lib/solvers/TraceLabelOverlapAvoidanceSolver/rerouteCollidingTrace.ts
|
|
2429
|
-
var rerouteCollidingTrace = ({
|
|
2430
|
-
trace,
|
|
2431
|
-
label,
|
|
2432
|
-
problem,
|
|
2433
|
-
paddingBuffer,
|
|
2434
|
-
detourCount
|
|
2435
|
-
}) => {
|
|
2436
|
-
const initialTrace = { ...trace, tracePath: simplifyPath(trace.tracePath) };
|
|
2437
|
-
if (trace.globalConnNetId === label.globalConnNetId) {
|
|
2438
|
-
return initialTrace;
|
|
2439
|
-
}
|
|
2440
|
-
const obstacles = getObstacleRects(problem);
|
|
2441
|
-
const labelPadding = paddingBuffer;
|
|
2442
|
-
const labelBoundsRaw = getRectBounds(label.center, label.width, label.height);
|
|
2443
|
-
const labelBounds = {
|
|
2444
|
-
minX: labelBoundsRaw.minX - labelPadding,
|
|
2445
|
-
minY: labelBoundsRaw.minY - labelPadding,
|
|
2446
|
-
maxX: labelBoundsRaw.maxX + labelPadding,
|
|
2447
|
-
maxY: labelBoundsRaw.maxY + labelPadding,
|
|
2448
|
-
chipId: `netlabel-${label.netId}`
|
|
2449
|
-
};
|
|
2450
|
-
const fourPointResult = tryFourPointDetour({
|
|
2451
|
-
initialTrace,
|
|
2452
|
-
label,
|
|
2453
|
-
labelBounds,
|
|
2454
|
-
obstacles,
|
|
2455
|
-
paddingBuffer,
|
|
2456
|
-
detourCount
|
|
2457
|
-
});
|
|
2458
|
-
if (fourPointResult) {
|
|
2459
|
-
initialTrace.tracePath = fourPointResult.tracePath;
|
|
2460
|
-
}
|
|
2461
|
-
const { firstInsideIndex, lastInsideIndex } = findTraceViolationZone(
|
|
2462
|
-
initialTrace.tracePath,
|
|
2463
|
-
labelBounds
|
|
2464
|
-
);
|
|
2465
|
-
const snipReconnectResult = trySnipAndReconnect({
|
|
2466
|
-
initialTrace,
|
|
2467
|
-
firstInsideIndex,
|
|
2468
|
-
lastInsideIndex,
|
|
2469
|
-
labelBounds,
|
|
2470
|
-
obstacles
|
|
2471
|
-
});
|
|
2472
|
-
if (snipReconnectResult) {
|
|
2473
|
-
return snipReconnectResult;
|
|
2474
|
-
}
|
|
2475
|
-
if (fourPointResult) {
|
|
2476
|
-
return fourPointResult;
|
|
2477
|
-
}
|
|
2478
|
-
return initialTrace;
|
|
2479
|
-
};
|
|
2480
|
-
|
|
2481
|
-
// lib/solvers/TraceLabelOverlapAvoidanceSolver/hasCollisions.ts
|
|
2482
|
-
var hasCollisions = (pathSegments, obstacles) => {
|
|
2483
|
-
for (let i = 0; i < pathSegments.length - 1; i++) {
|
|
2484
|
-
const p1 = pathSegments[i];
|
|
2485
|
-
const p2 = pathSegments[i + 1];
|
|
2486
|
-
for (const obstacle of obstacles) {
|
|
2487
|
-
if (segmentIntersectsRect(p1, p2, obstacle)) {
|
|
2488
|
-
return true;
|
|
2489
|
-
}
|
|
2490
|
-
}
|
|
2491
|
-
}
|
|
2492
|
-
return false;
|
|
2493
|
-
};
|
|
2494
|
-
|
|
2495
|
-
// lib/solvers/TraceLabelOverlapAvoidanceSolver/countTurns.ts
|
|
2496
|
-
var countTurns = (points) => {
|
|
2497
|
-
let turns = 0;
|
|
2498
|
-
for (let i = 1; i < points.length - 1; i++) {
|
|
2499
|
-
const prev = points[i - 1];
|
|
2500
|
-
const curr = points[i];
|
|
2501
|
-
const next = points[i + 1];
|
|
2502
|
-
const prevVertical = prev.x === curr.x;
|
|
2503
|
-
const nextVertical = curr.x === next.x;
|
|
2504
|
-
if (prevVertical !== nextVertical) {
|
|
2505
|
-
turns++;
|
|
2506
|
-
}
|
|
2507
|
-
}
|
|
2508
|
-
return turns;
|
|
2509
|
-
};
|
|
2510
|
-
|
|
2511
|
-
// lib/solvers/TraceLabelOverlapAvoidanceSolver/tryConnectPoints.ts
|
|
2512
|
-
var tryConnectPoints = (start, end) => {
|
|
2513
|
-
const candidates = [];
|
|
2514
|
-
if (start.x === end.x || start.y === end.y) {
|
|
2515
|
-
candidates.push([start, end]);
|
|
2516
|
-
} else {
|
|
2517
|
-
candidates.push([start, { x: end.x, y: start.y }, end]);
|
|
2518
|
-
candidates.push([start, { x: start.x, y: end.y }, end]);
|
|
2519
|
-
}
|
|
2520
|
-
return candidates;
|
|
2521
|
-
};
|
|
2522
|
-
|
|
2523
|
-
// lib/solvers/TraceLabelOverlapAvoidanceSolver/hasCollisionsWithLabels.ts
|
|
2524
|
-
var hasCollisionsWithLabels = (pathSegments, labels) => {
|
|
2525
|
-
for (let i = 0; i < pathSegments.length - 1; i++) {
|
|
2526
|
-
const p1 = pathSegments[i];
|
|
2527
|
-
const p2 = pathSegments[i + 1];
|
|
2528
|
-
for (const label of labels) {
|
|
2529
|
-
if (segmentIntersectsRect(p1, p2, label)) {
|
|
2530
|
-
return true;
|
|
2531
|
-
}
|
|
2532
|
-
}
|
|
2533
|
-
}
|
|
2534
|
-
return false;
|
|
2535
|
-
};
|
|
2536
|
-
|
|
2537
|
-
// lib/solvers/TraceLabelOverlapAvoidanceSolver/turnMinimization.ts
|
|
2538
|
-
var minimizeTurns = ({
|
|
2539
|
-
path,
|
|
2540
|
-
obstacles,
|
|
2541
|
-
labelBounds
|
|
2542
|
-
}) => {
|
|
2543
|
-
if (path.length <= 2) {
|
|
2544
|
-
return path;
|
|
2446
|
+
if (path.length <= 2) {
|
|
2447
|
+
return path;
|
|
2545
2448
|
}
|
|
2546
2449
|
const recognizeStairStepPattern = (pathToCheck, startIdx) => {
|
|
2547
2450
|
if (startIdx >= pathToCheck.length - 3) return -1;
|
|
@@ -2595,7 +2498,6 @@ var minimizeTurns = ({
|
|
|
2595
2498
|
);
|
|
2596
2499
|
if (!collidesWithObstacles && !collidesWithLabels) {
|
|
2597
2500
|
const newTurns = countTurns(testPath);
|
|
2598
|
-
const turnsRemoved = stairEndIdx - startIdx - 1;
|
|
2599
2501
|
optimizedPath = testPath;
|
|
2600
2502
|
currentTurns = newTurns;
|
|
2601
2503
|
improved = true;
|
|
@@ -2677,16 +2579,16 @@ var minimizeTurns = ({
|
|
|
2677
2579
|
return finalSimplifiedPath;
|
|
2678
2580
|
};
|
|
2679
2581
|
|
|
2680
|
-
// lib/solvers/TraceLabelOverlapAvoidanceSolver/minimizeTurnsWithFilteredLabels.ts
|
|
2582
|
+
// lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/TraceCleanupSolver/minimizeTurnsWithFilteredLabels.ts
|
|
2681
2583
|
var minimizeTurnsWithFilteredLabels = ({
|
|
2682
2584
|
traces,
|
|
2683
|
-
|
|
2585
|
+
inputProblem,
|
|
2684
2586
|
allLabelPlacements,
|
|
2685
2587
|
mergedLabelNetIdMap,
|
|
2686
2588
|
paddingBuffer
|
|
2687
2589
|
}) => {
|
|
2688
2590
|
let changesMade = false;
|
|
2689
|
-
const obstacles = getObstacleRects(
|
|
2591
|
+
const obstacles = getObstacleRects(inputProblem);
|
|
2690
2592
|
const newTraces = traces.map((trace) => {
|
|
2691
2593
|
const originalPath = trace.tracePath;
|
|
2692
2594
|
const filteredLabels = allLabelPlacements.filter((label) => {
|
|
@@ -2724,10 +2626,10 @@ var minimizeTurnsWithFilteredLabels = ({
|
|
|
2724
2626
|
}
|
|
2725
2627
|
};
|
|
2726
2628
|
|
|
2727
|
-
// lib/solvers/TraceLabelOverlapAvoidanceSolver/balanceLShapes.ts
|
|
2629
|
+
// lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/TraceCleanupSolver/balanceLShapes.ts
|
|
2728
2630
|
var balanceLShapes = ({
|
|
2729
2631
|
traces,
|
|
2730
|
-
|
|
2632
|
+
inputProblem,
|
|
2731
2633
|
allLabelPlacements
|
|
2732
2634
|
}) => {
|
|
2733
2635
|
const TOLERANCE = 1e-5;
|
|
@@ -2752,7 +2654,7 @@ var balanceLShapes = ({
|
|
|
2752
2654
|
}
|
|
2753
2655
|
}
|
|
2754
2656
|
}
|
|
2755
|
-
const obstacles = getObstacleRects(
|
|
2657
|
+
const obstacles = getObstacleRects(inputProblem).map((obs) => ({
|
|
2756
2658
|
...obs,
|
|
2757
2659
|
minX: obs.minX + TOLERANCE,
|
|
2758
2660
|
maxX: obs.maxX - TOLERANCE,
|
|
@@ -2779,7 +2681,7 @@ var balanceLShapes = ({
|
|
|
2779
2681
|
}));
|
|
2780
2682
|
};
|
|
2781
2683
|
const newTraces = traces.map((trace) => {
|
|
2782
|
-
|
|
2684
|
+
const newPath = [...trace.tracePath];
|
|
2783
2685
|
if (newPath.length < 4) {
|
|
2784
2686
|
return { ...trace };
|
|
2785
2687
|
}
|
|
@@ -2789,7 +2691,8 @@ var balanceLShapes = ({
|
|
|
2789
2691
|
);
|
|
2790
2692
|
if (newPath.length === 4) {
|
|
2791
2693
|
const [p0, p1, p2, p3] = newPath;
|
|
2792
|
-
let p1New
|
|
2694
|
+
let p1New;
|
|
2695
|
+
let p2New;
|
|
2793
2696
|
const isHVHShape = p0.y === p1.y && p1.x === p2.x && p2.y === p3.y;
|
|
2794
2697
|
if (isHVHShape) {
|
|
2795
2698
|
const idealX = (p0.x + p3.x) / 2;
|
|
@@ -2828,7 +2731,8 @@ var balanceLShapes = ({
|
|
|
2828
2731
|
if (!isValidZShape) {
|
|
2829
2732
|
continue;
|
|
2830
2733
|
}
|
|
2831
|
-
let p2New
|
|
2734
|
+
let p2New;
|
|
2735
|
+
let p3New;
|
|
2832
2736
|
const len1Original = isHVHZShape ? Math.abs(p1.x - p2.x) : Math.abs(p1.y - p2.y);
|
|
2833
2737
|
const len2Original = isHVHZShape ? Math.abs(p3.x - p4.x) : Math.abs(p3.y - p4.y);
|
|
2834
2738
|
if (Math.abs(len1Original - len2Original) < 1e-3) {
|
|
@@ -2851,198 +2755,610 @@ var balanceLShapes = ({
|
|
|
2851
2755
|
i = 0;
|
|
2852
2756
|
}
|
|
2853
2757
|
}
|
|
2854
|
-
const finalSimplifiedPath = simplifyPath(newPath);
|
|
2855
|
-
return {
|
|
2856
|
-
...trace,
|
|
2857
|
-
tracePath: finalSimplifiedPath
|
|
2858
|
-
};
|
|
2859
|
-
});
|
|
2860
|
-
if (changesMade) {
|
|
2861
|
-
return newTraces;
|
|
2862
|
-
} else {
|
|
2863
|
-
return null;
|
|
2758
|
+
const finalSimplifiedPath = simplifyPath(newPath);
|
|
2759
|
+
return {
|
|
2760
|
+
...trace,
|
|
2761
|
+
tracePath: finalSimplifiedPath
|
|
2762
|
+
};
|
|
2763
|
+
});
|
|
2764
|
+
if (changesMade) {
|
|
2765
|
+
return newTraces;
|
|
2766
|
+
} else {
|
|
2767
|
+
return null;
|
|
2768
|
+
}
|
|
2769
|
+
};
|
|
2770
|
+
|
|
2771
|
+
// lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/TraceCleanupSolver/TraceCleanupSolver.ts
|
|
2772
|
+
var TraceCleanupSolver = class extends BaseSolver {
|
|
2773
|
+
input;
|
|
2774
|
+
outputTraces;
|
|
2775
|
+
pipelineStepIndex = 0;
|
|
2776
|
+
tracesToProcess;
|
|
2777
|
+
minimizedTraces = null;
|
|
2778
|
+
balancedTraces = null;
|
|
2779
|
+
constructor(solverInput) {
|
|
2780
|
+
super();
|
|
2781
|
+
this.input = solverInput;
|
|
2782
|
+
this.outputTraces = [...solverInput.allTraces];
|
|
2783
|
+
this.tracesToProcess = this.outputTraces.filter(
|
|
2784
|
+
(t) => this.input.targetTraceIds.has(t.mspPairId)
|
|
2785
|
+
);
|
|
2786
|
+
}
|
|
2787
|
+
_step() {
|
|
2788
|
+
const {
|
|
2789
|
+
targetTraceIds,
|
|
2790
|
+
inputProblem,
|
|
2791
|
+
allLabelPlacements,
|
|
2792
|
+
mergedLabelNetIdMap,
|
|
2793
|
+
paddingBuffer
|
|
2794
|
+
} = this.input;
|
|
2795
|
+
if (targetTraceIds.size === 0) {
|
|
2796
|
+
this.solved = true;
|
|
2797
|
+
return;
|
|
2798
|
+
}
|
|
2799
|
+
switch (this.pipelineStepIndex) {
|
|
2800
|
+
case 0: {
|
|
2801
|
+
const minimizedTracesResult = minimizeTurnsWithFilteredLabels({
|
|
2802
|
+
traces: this.tracesToProcess,
|
|
2803
|
+
inputProblem,
|
|
2804
|
+
allLabelPlacements,
|
|
2805
|
+
mergedLabelNetIdMap,
|
|
2806
|
+
paddingBuffer
|
|
2807
|
+
});
|
|
2808
|
+
this.minimizedTraces = minimizedTracesResult ?? this.tracesToProcess;
|
|
2809
|
+
const tracesMap = new Map(
|
|
2810
|
+
this.input.allTraces.map((t) => [t.mspPairId, t])
|
|
2811
|
+
);
|
|
2812
|
+
for (const trace of this.minimizedTraces) {
|
|
2813
|
+
tracesMap.set(trace.mspPairId, trace);
|
|
2814
|
+
}
|
|
2815
|
+
this.outputTraces = Array.from(tracesMap.values());
|
|
2816
|
+
this.pipelineStepIndex++;
|
|
2817
|
+
break;
|
|
2818
|
+
}
|
|
2819
|
+
case 1: {
|
|
2820
|
+
const balancedTracesResult = balanceLShapes({
|
|
2821
|
+
traces: this.minimizedTraces,
|
|
2822
|
+
inputProblem,
|
|
2823
|
+
allLabelPlacements
|
|
2824
|
+
});
|
|
2825
|
+
this.balancedTraces = balancedTracesResult ?? this.minimizedTraces;
|
|
2826
|
+
const tracesMap = new Map(
|
|
2827
|
+
this.input.allTraces.map((t) => [t.mspPairId, t])
|
|
2828
|
+
);
|
|
2829
|
+
for (const trace of this.balancedTraces) {
|
|
2830
|
+
tracesMap.set(trace.mspPairId, trace);
|
|
2831
|
+
}
|
|
2832
|
+
this.outputTraces = Array.from(tracesMap.values());
|
|
2833
|
+
this.pipelineStepIndex++;
|
|
2834
|
+
break;
|
|
2835
|
+
}
|
|
2836
|
+
case 2: {
|
|
2837
|
+
this.solved = true;
|
|
2838
|
+
break;
|
|
2839
|
+
}
|
|
2840
|
+
}
|
|
2841
|
+
}
|
|
2842
|
+
getOutput() {
|
|
2843
|
+
return {
|
|
2844
|
+
traces: this.outputTraces
|
|
2845
|
+
};
|
|
2846
|
+
}
|
|
2847
|
+
visualize() {
|
|
2848
|
+
const graphics = visualizeInputProblem(this.input.inputProblem, {
|
|
2849
|
+
chipAlpha: 0.1,
|
|
2850
|
+
connectionAlpha: 0.1
|
|
2851
|
+
});
|
|
2852
|
+
if (!graphics.lines) graphics.lines = [];
|
|
2853
|
+
if (!graphics.points) graphics.points = [];
|
|
2854
|
+
if (!graphics.rects) graphics.rects = [];
|
|
2855
|
+
if (!graphics.circles) graphics.circles = [];
|
|
2856
|
+
if (!graphics.texts) graphics.texts = [];
|
|
2857
|
+
for (const trace of this.outputTraces) {
|
|
2858
|
+
const line = {
|
|
2859
|
+
points: trace.tracePath.map((p) => ({ x: p.x, y: p.y })),
|
|
2860
|
+
strokeColor: "blue"
|
|
2861
|
+
};
|
|
2862
|
+
graphics.lines.push(line);
|
|
2863
|
+
}
|
|
2864
|
+
return graphics;
|
|
2865
|
+
}
|
|
2866
|
+
};
|
|
2867
|
+
|
|
2868
|
+
// lib/solvers/TraceLabelOverlapAvoidanceSolver/detectTraceLabelOverlap.ts
|
|
2869
|
+
var detectTraceLabelOverlap = (traces, netLabels) => {
|
|
2870
|
+
const overlaps = [];
|
|
2871
|
+
for (const trace of traces) {
|
|
2872
|
+
for (const label of netLabels) {
|
|
2873
|
+
const labelBounds = getRectBounds(label.center, label.width, label.height);
|
|
2874
|
+
for (let i = 0; i < trace.tracePath.length - 1; i++) {
|
|
2875
|
+
const p1 = trace.tracePath[i];
|
|
2876
|
+
const p2 = trace.tracePath[i + 1];
|
|
2877
|
+
if (segmentIntersectsRect2(p1, p2, labelBounds)) {
|
|
2878
|
+
if (trace.globalConnNetId === label.globalConnNetId) {
|
|
2879
|
+
break;
|
|
2880
|
+
}
|
|
2881
|
+
overlaps.push({ trace, label });
|
|
2882
|
+
break;
|
|
2883
|
+
}
|
|
2884
|
+
}
|
|
2885
|
+
}
|
|
2886
|
+
}
|
|
2887
|
+
return overlaps;
|
|
2888
|
+
};
|
|
2889
|
+
|
|
2890
|
+
// lib/solvers/TraceLabelOverlapAvoidanceSolver/violation.ts
|
|
2891
|
+
var findTraceViolationZone = (path, labelBounds) => {
|
|
2892
|
+
const isPointInside = (p) => p.x > labelBounds.minX && p.x < labelBounds.maxX && p.y > labelBounds.minY && p.y < labelBounds.maxY;
|
|
2893
|
+
let firstInsideIndex = -1;
|
|
2894
|
+
let lastInsideIndex = -1;
|
|
2895
|
+
for (let i = 0; i < path.length; i++) {
|
|
2896
|
+
if (isPointInside(path[i])) {
|
|
2897
|
+
if (firstInsideIndex === -1) {
|
|
2898
|
+
firstInsideIndex = i;
|
|
2899
|
+
}
|
|
2900
|
+
lastInsideIndex = i;
|
|
2901
|
+
}
|
|
2902
|
+
}
|
|
2903
|
+
return { firstInsideIndex, lastInsideIndex };
|
|
2904
|
+
};
|
|
2905
|
+
|
|
2906
|
+
// lib/solvers/TraceLabelOverlapAvoidanceSolver/trySnipAndReconnect.ts
|
|
2907
|
+
var generateSnipAndReconnectCandidates = ({
|
|
2908
|
+
initialTrace,
|
|
2909
|
+
firstInsideIndex,
|
|
2910
|
+
lastInsideIndex,
|
|
2911
|
+
labelBounds,
|
|
2912
|
+
paddingBuffer,
|
|
2913
|
+
detourCount
|
|
2914
|
+
}) => {
|
|
2915
|
+
if (firstInsideIndex <= 0 || lastInsideIndex >= initialTrace.tracePath.length - 1) {
|
|
2916
|
+
return [];
|
|
2917
|
+
}
|
|
2918
|
+
const entryPoint = initialTrace.tracePath[firstInsideIndex - 1];
|
|
2919
|
+
const exitPoint = initialTrace.tracePath[lastInsideIndex + 1];
|
|
2920
|
+
const pathToEntry = initialTrace.tracePath.slice(0, firstInsideIndex);
|
|
2921
|
+
const pathFromExit = initialTrace.tracePath.slice(lastInsideIndex + 1);
|
|
2922
|
+
const allCandidateDetours = [];
|
|
2923
|
+
if (entryPoint.x !== exitPoint.x && entryPoint.y !== exitPoint.y) {
|
|
2924
|
+
allCandidateDetours.push([{ x: exitPoint.x, y: entryPoint.y }]);
|
|
2925
|
+
allCandidateDetours.push([{ x: entryPoint.x, y: exitPoint.y }]);
|
|
2926
|
+
} else if (entryPoint.x === exitPoint.x || entryPoint.y === exitPoint.y) {
|
|
2927
|
+
allCandidateDetours.push([]);
|
|
2928
|
+
}
|
|
2929
|
+
const buffer = paddingBuffer + detourCount * paddingBuffer;
|
|
2930
|
+
const leftX = labelBounds.minX - buffer;
|
|
2931
|
+
const rightX = labelBounds.maxX + buffer;
|
|
2932
|
+
const topY = labelBounds.maxY + buffer;
|
|
2933
|
+
const bottomY = labelBounds.minY - buffer;
|
|
2934
|
+
if ((entryPoint.x <= labelBounds.minX || exitPoint.x <= labelBounds.minX) && entryPoint.x < labelBounds.maxX && exitPoint.x < labelBounds.maxX) {
|
|
2935
|
+
allCandidateDetours.push([
|
|
2936
|
+
{ x: leftX, y: entryPoint.y },
|
|
2937
|
+
{ x: leftX, y: exitPoint.y }
|
|
2938
|
+
]);
|
|
2939
|
+
}
|
|
2940
|
+
if ((entryPoint.x >= labelBounds.maxX || exitPoint.x >= labelBounds.maxX) && entryPoint.x > labelBounds.minX && exitPoint.x > labelBounds.minX) {
|
|
2941
|
+
allCandidateDetours.push([
|
|
2942
|
+
{ x: rightX, y: entryPoint.y },
|
|
2943
|
+
{ x: rightX, y: exitPoint.y }
|
|
2944
|
+
]);
|
|
2945
|
+
}
|
|
2946
|
+
if ((entryPoint.y >= labelBounds.maxY || exitPoint.y >= labelBounds.maxY) && entryPoint.y > labelBounds.minY && exitPoint.y > labelBounds.minY) {
|
|
2947
|
+
allCandidateDetours.push([
|
|
2948
|
+
{ x: entryPoint.x, y: topY },
|
|
2949
|
+
{ x: exitPoint.x, y: topY }
|
|
2950
|
+
]);
|
|
2951
|
+
}
|
|
2952
|
+
if ((entryPoint.y <= labelBounds.minY || exitPoint.y <= labelBounds.minY) && entryPoint.y < labelBounds.maxY && exitPoint.y < labelBounds.maxY) {
|
|
2953
|
+
allCandidateDetours.push([
|
|
2954
|
+
{ x: entryPoint.x, y: bottomY },
|
|
2955
|
+
{ x: exitPoint.x, y: bottomY }
|
|
2956
|
+
]);
|
|
2957
|
+
}
|
|
2958
|
+
return allCandidateDetours.map((detour) => [
|
|
2959
|
+
...pathToEntry,
|
|
2960
|
+
...detour,
|
|
2961
|
+
...pathFromExit
|
|
2962
|
+
]);
|
|
2963
|
+
};
|
|
2964
|
+
|
|
2965
|
+
// lib/solvers/TraceLabelOverlapAvoidanceSolver/tryFourPointDetour.ts
|
|
2966
|
+
var generateFourPointDetourCandidates = ({
|
|
2967
|
+
initialTrace,
|
|
2968
|
+
label,
|
|
2969
|
+
labelBounds,
|
|
2970
|
+
paddingBuffer,
|
|
2971
|
+
detourCount
|
|
2972
|
+
}) => {
|
|
2973
|
+
let collidingSegIndex = -1;
|
|
2974
|
+
for (let i = 0; i < initialTrace.tracePath.length - 1; i++) {
|
|
2975
|
+
if (segmentIntersectsRect(
|
|
2976
|
+
initialTrace.tracePath[i],
|
|
2977
|
+
initialTrace.tracePath[i + 1],
|
|
2978
|
+
labelBounds
|
|
2979
|
+
)) {
|
|
2980
|
+
collidingSegIndex = i;
|
|
2981
|
+
break;
|
|
2982
|
+
}
|
|
2983
|
+
}
|
|
2984
|
+
if (collidingSegIndex === -1) return [];
|
|
2985
|
+
const pA = initialTrace.tracePath[collidingSegIndex];
|
|
2986
|
+
const pB = initialTrace.tracePath[collidingSegIndex + 1];
|
|
2987
|
+
if (!pA || !pB) return [];
|
|
2988
|
+
const candidateDetours = [];
|
|
2989
|
+
const paddedLabelBounds = getRectBounds(
|
|
2990
|
+
label.center,
|
|
2991
|
+
label.width,
|
|
2992
|
+
label.height
|
|
2993
|
+
);
|
|
2994
|
+
const effectivePadding = paddingBuffer + detourCount * paddingBuffer;
|
|
2995
|
+
if (isVertical(pA, pB)) {
|
|
2996
|
+
const xCandidates = [
|
|
2997
|
+
paddedLabelBounds.maxX + effectivePadding,
|
|
2998
|
+
paddedLabelBounds.minX - effectivePadding
|
|
2999
|
+
];
|
|
3000
|
+
for (const newX of xCandidates) {
|
|
3001
|
+
candidateDetours.push(
|
|
3002
|
+
pB.y > pA.y ? [
|
|
3003
|
+
{ x: pA.x, y: paddedLabelBounds.minY - effectivePadding },
|
|
3004
|
+
{ x: newX, y: paddedLabelBounds.minY - effectivePadding },
|
|
3005
|
+
{ x: newX, y: paddedLabelBounds.maxY + effectivePadding },
|
|
3006
|
+
{ x: pB.x, y: paddedLabelBounds.maxY + effectivePadding }
|
|
3007
|
+
] : [
|
|
3008
|
+
{ x: pA.x, y: paddedLabelBounds.maxY + effectivePadding },
|
|
3009
|
+
{ x: newX, y: paddedLabelBounds.maxY + effectivePadding },
|
|
3010
|
+
{ x: newX, y: paddedLabelBounds.minY - effectivePadding },
|
|
3011
|
+
{ x: pB.x, y: paddedLabelBounds.minY - effectivePadding }
|
|
3012
|
+
]
|
|
3013
|
+
);
|
|
3014
|
+
}
|
|
3015
|
+
} else {
|
|
3016
|
+
const yCandidates = [
|
|
3017
|
+
paddedLabelBounds.maxY + effectivePadding,
|
|
3018
|
+
paddedLabelBounds.minY - effectivePadding
|
|
3019
|
+
];
|
|
3020
|
+
for (const newY of yCandidates) {
|
|
3021
|
+
candidateDetours.push(
|
|
3022
|
+
pB.x > pA.x ? [
|
|
3023
|
+
{ x: paddedLabelBounds.minX - effectivePadding, y: pA.y },
|
|
3024
|
+
{ x: paddedLabelBounds.minX - effectivePadding, y: newY },
|
|
3025
|
+
{ x: paddedLabelBounds.maxX + effectivePadding, y: newY },
|
|
3026
|
+
{ x: paddedLabelBounds.maxX + effectivePadding, y: pB.y }
|
|
3027
|
+
] : [
|
|
3028
|
+
{ x: paddedLabelBounds.maxX + effectivePadding, y: pA.y },
|
|
3029
|
+
{ x: paddedLabelBounds.maxX + effectivePadding, y: newY },
|
|
3030
|
+
{ x: paddedLabelBounds.minX - effectivePadding, y: newY },
|
|
3031
|
+
{ x: paddedLabelBounds.minX - effectivePadding, y: pB.y }
|
|
3032
|
+
]
|
|
3033
|
+
);
|
|
3034
|
+
}
|
|
3035
|
+
}
|
|
3036
|
+
return candidateDetours.map((detourPoints) => [
|
|
3037
|
+
...initialTrace.tracePath.slice(0, collidingSegIndex + 1),
|
|
3038
|
+
...detourPoints,
|
|
3039
|
+
...initialTrace.tracePath.slice(collidingSegIndex + 1)
|
|
3040
|
+
]);
|
|
3041
|
+
};
|
|
3042
|
+
|
|
3043
|
+
// lib/solvers/TraceLabelOverlapAvoidanceSolver/rerouteCollidingTrace.ts
|
|
3044
|
+
var generateRerouteCandidates = ({
|
|
3045
|
+
trace,
|
|
3046
|
+
label,
|
|
3047
|
+
paddingBuffer,
|
|
3048
|
+
detourCount
|
|
3049
|
+
}) => {
|
|
3050
|
+
const initialTrace = { ...trace, tracePath: simplifyPath(trace.tracePath) };
|
|
3051
|
+
if (trace.globalConnNetId === label.globalConnNetId) {
|
|
3052
|
+
return [initialTrace.tracePath];
|
|
3053
|
+
}
|
|
3054
|
+
const labelPadding = paddingBuffer;
|
|
3055
|
+
const labelBoundsRaw = getRectBounds(label.center, label.width, label.height);
|
|
3056
|
+
const labelBounds = {
|
|
3057
|
+
minX: labelBoundsRaw.minX - labelPadding,
|
|
3058
|
+
minY: labelBoundsRaw.minY - labelPadding,
|
|
3059
|
+
maxX: labelBoundsRaw.maxX + labelPadding,
|
|
3060
|
+
maxY: labelBoundsRaw.maxY + labelPadding,
|
|
3061
|
+
chipId: `netlabel-${label.netId}`
|
|
3062
|
+
};
|
|
3063
|
+
const fourPointCandidates = generateFourPointDetourCandidates({
|
|
3064
|
+
initialTrace,
|
|
3065
|
+
label,
|
|
3066
|
+
labelBounds,
|
|
3067
|
+
paddingBuffer,
|
|
3068
|
+
detourCount
|
|
3069
|
+
});
|
|
3070
|
+
const { firstInsideIndex, lastInsideIndex } = findTraceViolationZone(
|
|
3071
|
+
initialTrace.tracePath,
|
|
3072
|
+
labelBounds
|
|
3073
|
+
);
|
|
3074
|
+
const snipReconnectCandidates = generateSnipAndReconnectCandidates({
|
|
3075
|
+
initialTrace,
|
|
3076
|
+
firstInsideIndex,
|
|
3077
|
+
lastInsideIndex,
|
|
3078
|
+
labelBounds,
|
|
3079
|
+
paddingBuffer,
|
|
3080
|
+
detourCount
|
|
3081
|
+
});
|
|
3082
|
+
return [...fourPointCandidates, ...snipReconnectCandidates];
|
|
3083
|
+
};
|
|
3084
|
+
|
|
3085
|
+
// lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/SingleOverlapSolver/SingleOverlapSolver.ts
|
|
3086
|
+
var SingleOverlapSolver = class extends BaseSolver {
|
|
3087
|
+
queuedCandidatePaths;
|
|
3088
|
+
solvedTracePath = null;
|
|
3089
|
+
initialTrace;
|
|
3090
|
+
problem;
|
|
3091
|
+
obstacles;
|
|
3092
|
+
label;
|
|
3093
|
+
constructor(solverInput) {
|
|
3094
|
+
super();
|
|
3095
|
+
this.initialTrace = solverInput.trace;
|
|
3096
|
+
this.problem = solverInput.problem;
|
|
3097
|
+
this.label = solverInput.label;
|
|
3098
|
+
const candidates = generateRerouteCandidates({
|
|
3099
|
+
...solverInput
|
|
3100
|
+
});
|
|
3101
|
+
const getPathLength = (pts) => {
|
|
3102
|
+
let len = 0;
|
|
3103
|
+
for (let i = 0; i < pts.length - 1; i++) {
|
|
3104
|
+
const dx = pts[i + 1].x - pts[i].x;
|
|
3105
|
+
const dy = pts[i + 1].y - pts[i].y;
|
|
3106
|
+
len += Math.sqrt(dx * dx + dy * dy);
|
|
3107
|
+
}
|
|
3108
|
+
return len;
|
|
3109
|
+
};
|
|
3110
|
+
this.queuedCandidatePaths = candidates.sort(
|
|
3111
|
+
(a, b) => getPathLength(a) - getPathLength(b)
|
|
3112
|
+
);
|
|
3113
|
+
this.obstacles = getObstacleRects(this.problem);
|
|
3114
|
+
}
|
|
3115
|
+
_step() {
|
|
3116
|
+
if (this.queuedCandidatePaths.length === 0) {
|
|
3117
|
+
this.failed = true;
|
|
3118
|
+
return;
|
|
3119
|
+
}
|
|
3120
|
+
const nextCandidatePath = this.queuedCandidatePaths.shift();
|
|
3121
|
+
const simplifiedPath = simplifyPath(nextCandidatePath);
|
|
3122
|
+
if (!isPathCollidingWithObstacles(simplifiedPath, this.obstacles)) {
|
|
3123
|
+
this.solvedTracePath = simplifiedPath;
|
|
3124
|
+
this.solved = true;
|
|
3125
|
+
}
|
|
3126
|
+
}
|
|
3127
|
+
visualize() {
|
|
3128
|
+
const graphics = visualizeInputProblem(this.problem, {
|
|
3129
|
+
chipAlpha: 0.1,
|
|
3130
|
+
connectionAlpha: 0.1
|
|
3131
|
+
});
|
|
3132
|
+
if (!graphics.lines) graphics.lines = [];
|
|
3133
|
+
if (!graphics.rects) graphics.rects = [];
|
|
3134
|
+
graphics.lines.push({
|
|
3135
|
+
points: this.initialTrace.tracePath,
|
|
3136
|
+
strokeColor: "red",
|
|
3137
|
+
strokeDash: "4 4"
|
|
3138
|
+
});
|
|
3139
|
+
graphics.rects.push({
|
|
3140
|
+
center: this.label.center,
|
|
3141
|
+
width: this.label.width,
|
|
3142
|
+
height: this.label.height,
|
|
3143
|
+
fill: "rgba(255, 0, 0, 0.2)"
|
|
3144
|
+
});
|
|
3145
|
+
if (this.queuedCandidatePaths.length > 0) {
|
|
3146
|
+
graphics.lines.push({
|
|
3147
|
+
points: this.queuedCandidatePaths[0],
|
|
3148
|
+
strokeColor: "orange"
|
|
3149
|
+
});
|
|
3150
|
+
}
|
|
3151
|
+
if (this.solvedTracePath) {
|
|
3152
|
+
graphics.lines.push({
|
|
3153
|
+
points: this.solvedTracePath,
|
|
3154
|
+
strokeColor: "green"
|
|
3155
|
+
});
|
|
3156
|
+
}
|
|
3157
|
+
return graphics;
|
|
2864
3158
|
}
|
|
2865
3159
|
};
|
|
2866
3160
|
|
|
2867
|
-
// lib/solvers/TraceLabelOverlapAvoidanceSolver/
|
|
2868
|
-
var
|
|
2869
|
-
|
|
2870
|
-
traces;
|
|
2871
|
-
netTempLabelPlacements;
|
|
3161
|
+
// lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/OverlapAvoidanceStepSolver/OverlapAvoidanceStepSolver.ts
|
|
3162
|
+
var OverlapAvoidanceStepSolver = class extends BaseSolver {
|
|
3163
|
+
inputProblem;
|
|
2872
3164
|
netLabelPlacements;
|
|
2873
|
-
updatedTraces;
|
|
2874
3165
|
mergedLabelNetIdMap;
|
|
2875
|
-
|
|
3166
|
+
allTraces;
|
|
3167
|
+
modifiedTraces = [];
|
|
3168
|
+
detourCountByLabel = {};
|
|
2876
3169
|
PADDING_BUFFER = 0.1;
|
|
3170
|
+
activeSubSolver = null;
|
|
3171
|
+
overlapQueue = [];
|
|
3172
|
+
recentlyFailed = /* @__PURE__ */ new Set();
|
|
2877
3173
|
constructor(solverInput) {
|
|
2878
3174
|
super();
|
|
2879
|
-
this.
|
|
2880
|
-
this.
|
|
2881
|
-
this.
|
|
2882
|
-
this.
|
|
2883
|
-
this.detourCountByLabel = {};
|
|
2884
|
-
const originalLabels = solverInput.netLabelPlacements;
|
|
2885
|
-
this.netLabelPlacements = originalLabels;
|
|
2886
|
-
if (!originalLabels || originalLabels.length === 0) {
|
|
2887
|
-
this.netTempLabelPlacements = [];
|
|
2888
|
-
return;
|
|
2889
|
-
}
|
|
2890
|
-
const labelGroups = {};
|
|
2891
|
-
for (const p of originalLabels) {
|
|
2892
|
-
if (p.pinIds.length === 0) continue;
|
|
2893
|
-
const chipId = p.pinIds[0].split(".")[0];
|
|
2894
|
-
if (!chipId) continue;
|
|
2895
|
-
const key = `${chipId}-${p.orientation}`;
|
|
2896
|
-
if (!(key in labelGroups)) {
|
|
2897
|
-
labelGroups[key] = [];
|
|
2898
|
-
}
|
|
2899
|
-
labelGroups[key].push(p);
|
|
2900
|
-
}
|
|
2901
|
-
const finalPlacements = [];
|
|
2902
|
-
for (const [key, group] of Object.entries(labelGroups)) {
|
|
2903
|
-
if (group.length <= 1) {
|
|
2904
|
-
finalPlacements.push(...group);
|
|
2905
|
-
continue;
|
|
2906
|
-
}
|
|
2907
|
-
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
2908
|
-
for (const p of group) {
|
|
2909
|
-
const bounds = getRectBounds(p.center, p.width, p.height);
|
|
2910
|
-
minX = Math.min(minX, bounds.minX);
|
|
2911
|
-
minY = Math.min(minY, bounds.minY);
|
|
2912
|
-
maxX = Math.max(maxX, bounds.maxX);
|
|
2913
|
-
maxY = Math.max(maxY, bounds.maxY);
|
|
2914
|
-
}
|
|
2915
|
-
const newWidth = maxX - minX;
|
|
2916
|
-
const newHeight = maxY - minY;
|
|
2917
|
-
const template = group[0];
|
|
2918
|
-
const syntheticId = `merged-group-${key}`;
|
|
2919
|
-
const originalNetIds = new Set(group.map((p) => p.globalConnNetId));
|
|
2920
|
-
this.mergedLabelNetIdMap[syntheticId] = originalNetIds;
|
|
2921
|
-
finalPlacements.push({
|
|
2922
|
-
...template,
|
|
2923
|
-
globalConnNetId: syntheticId,
|
|
2924
|
-
width: newWidth,
|
|
2925
|
-
height: newHeight,
|
|
2926
|
-
center: { x: minX + newWidth / 2, y: minY + newHeight / 2 },
|
|
2927
|
-
pinIds: [...new Set(group.flatMap((p) => p.pinIds))],
|
|
2928
|
-
mspConnectionPairIds: [
|
|
2929
|
-
...new Set(group.flatMap((p) => p.mspConnectionPairIds))
|
|
2930
|
-
]
|
|
2931
|
-
});
|
|
2932
|
-
}
|
|
2933
|
-
this.netTempLabelPlacements = finalPlacements;
|
|
3175
|
+
this.inputProblem = solverInput.inputProblem;
|
|
3176
|
+
this.netLabelPlacements = solverInput.netLabelPlacements;
|
|
3177
|
+
this.mergedLabelNetIdMap = solverInput.mergedLabelNetIdMap;
|
|
3178
|
+
this.allTraces = [...solverInput.traces];
|
|
2934
3179
|
}
|
|
2935
3180
|
_step() {
|
|
2936
|
-
if (
|
|
2937
|
-
this.
|
|
3181
|
+
if (this.activeSubSolver) {
|
|
3182
|
+
this.activeSubSolver.step();
|
|
3183
|
+
if (this.activeSubSolver.solved) {
|
|
3184
|
+
const solvedPath = this.activeSubSolver.solvedTracePath;
|
|
3185
|
+
if (solvedPath) {
|
|
3186
|
+
const traceIndex = this.allTraces.findIndex(
|
|
3187
|
+
(t) => t.mspPairId === this.activeSubSolver.initialTrace.mspPairId
|
|
3188
|
+
);
|
|
3189
|
+
if (traceIndex !== -1) {
|
|
3190
|
+
this.allTraces[traceIndex].tracePath = solvedPath;
|
|
3191
|
+
this.modifiedTraces.push(this.allTraces[traceIndex]);
|
|
3192
|
+
}
|
|
3193
|
+
}
|
|
3194
|
+
this.activeSubSolver = null;
|
|
3195
|
+
this.recentlyFailed.clear();
|
|
3196
|
+
} else if (this.activeSubSolver.failed) {
|
|
3197
|
+
const overlapId = `${this.activeSubSolver.initialTrace.mspPairId}-${this.activeSubSolver.label.globalConnNetId}`;
|
|
3198
|
+
this.recentlyFailed.add(overlapId);
|
|
3199
|
+
this.activeSubSolver = null;
|
|
3200
|
+
}
|
|
2938
3201
|
return;
|
|
2939
3202
|
}
|
|
2940
|
-
this.detourCountByLabel = {};
|
|
2941
3203
|
const overlaps = detectTraceLabelOverlap(
|
|
2942
|
-
this.
|
|
2943
|
-
this.
|
|
2944
|
-
)
|
|
2945
|
-
if (overlaps.length === 0) {
|
|
2946
|
-
this.solved = true;
|
|
2947
|
-
return;
|
|
2948
|
-
}
|
|
2949
|
-
const unfriendlyOverlaps = overlaps.filter((o) => {
|
|
3204
|
+
this.allTraces,
|
|
3205
|
+
this.netLabelPlacements
|
|
3206
|
+
).filter((o) => {
|
|
2950
3207
|
const originalNetIds = this.mergedLabelNetIdMap[o.label.globalConnNetId];
|
|
2951
3208
|
if (originalNetIds) {
|
|
2952
3209
|
return !originalNetIds.has(o.trace.globalConnNetId);
|
|
2953
3210
|
}
|
|
2954
3211
|
return o.trace.globalConnNetId !== o.label.globalConnNetId;
|
|
2955
3212
|
});
|
|
2956
|
-
if (
|
|
3213
|
+
if (overlaps.length === 0) {
|
|
2957
3214
|
this.solved = true;
|
|
2958
3215
|
return;
|
|
2959
3216
|
}
|
|
2960
|
-
const
|
|
2961
|
-
|
|
2962
|
-
|
|
3217
|
+
const nonFailedOverlaps = overlaps.filter((o) => {
|
|
3218
|
+
const overlapId = `${o.trace.mspPairId}-${o.label.globalConnNetId}`;
|
|
3219
|
+
return !this.recentlyFailed.has(overlapId);
|
|
3220
|
+
});
|
|
3221
|
+
if (nonFailedOverlaps.length === 0) {
|
|
3222
|
+
this.solved = true;
|
|
3223
|
+
return;
|
|
2963
3224
|
}
|
|
2964
|
-
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
trace: currentTraceState,
|
|
2974
|
-
label: overlap.label,
|
|
2975
|
-
problem: this.problem,
|
|
2976
|
-
paddingBuffer: this.PADDING_BUFFER,
|
|
2977
|
-
detourCount
|
|
2978
|
-
});
|
|
2979
|
-
if (newTrace.tracePath !== currentTraceState.tracePath) {
|
|
3225
|
+
this.overlapQueue = nonFailedOverlaps;
|
|
3226
|
+
const nextOverlap = this.overlapQueue.shift();
|
|
3227
|
+
if (nextOverlap) {
|
|
3228
|
+
const traceToFix = this.allTraces.find(
|
|
3229
|
+
(t) => t.mspPairId === nextOverlap.trace.mspPairId
|
|
3230
|
+
);
|
|
3231
|
+
if (traceToFix) {
|
|
3232
|
+
const labelId = nextOverlap.label.globalConnNetId;
|
|
3233
|
+
const detourCount = this.detourCountByLabel[labelId] || 0;
|
|
2980
3234
|
this.detourCountByLabel[labelId] = detourCount + 1;
|
|
3235
|
+
this.activeSubSolver = new SingleOverlapSolver({
|
|
3236
|
+
trace: traceToFix,
|
|
3237
|
+
label: nextOverlap.label,
|
|
3238
|
+
problem: this.inputProblem,
|
|
3239
|
+
paddingBuffer: this.PADDING_BUFFER,
|
|
3240
|
+
detourCount
|
|
3241
|
+
});
|
|
2981
3242
|
}
|
|
2982
|
-
updatedTracesMap[currentTraceState.mspPairId] = newTrace;
|
|
2983
|
-
processedTraceIds.add(currentTraceState.mspPairId);
|
|
2984
|
-
}
|
|
2985
|
-
this.updatedTraces = Object.values(updatedTracesMap);
|
|
2986
|
-
const minimizedTraces = minimizeTurnsWithFilteredLabels({
|
|
2987
|
-
traces: this.updatedTraces,
|
|
2988
|
-
problem: this.problem,
|
|
2989
|
-
allLabelPlacements: this.netTempLabelPlacements,
|
|
2990
|
-
// Use temp labels which include merged ones
|
|
2991
|
-
mergedLabelNetIdMap: this.mergedLabelNetIdMap,
|
|
2992
|
-
paddingBuffer: this.PADDING_BUFFER
|
|
2993
|
-
});
|
|
2994
|
-
if (minimizedTraces) {
|
|
2995
|
-
this.updatedTraces = minimizedTraces;
|
|
2996
3243
|
}
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
|
|
3244
|
+
}
|
|
3245
|
+
getOutput() {
|
|
3246
|
+
return {
|
|
3247
|
+
allTraces: this.allTraces,
|
|
3248
|
+
modifiedTraces: this.modifiedTraces
|
|
3249
|
+
};
|
|
3250
|
+
}
|
|
3251
|
+
visualize() {
|
|
3252
|
+
if (this.activeSubSolver) {
|
|
3253
|
+
return this.activeSubSolver.visualize();
|
|
3004
3254
|
}
|
|
3005
|
-
const
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3255
|
+
const graphics = visualizeInputProblem(this.inputProblem);
|
|
3256
|
+
if (!graphics.lines) graphics.lines = [];
|
|
3257
|
+
for (const trace of this.allTraces) {
|
|
3258
|
+
graphics.lines.push({
|
|
3259
|
+
points: trace.tracePath,
|
|
3260
|
+
strokeColor: "purple"
|
|
3261
|
+
});
|
|
3262
|
+
}
|
|
3263
|
+
return graphics;
|
|
3264
|
+
}
|
|
3265
|
+
};
|
|
3266
|
+
|
|
3267
|
+
// lib/solvers/TraceLabelOverlapAvoidanceSolver/TraceLabelOverlapAvoidanceSolver.ts
|
|
3268
|
+
var TraceLabelOverlapAvoidanceSolver = class extends BaseSolver {
|
|
3269
|
+
inputProblem;
|
|
3270
|
+
traces;
|
|
3271
|
+
netLabelPlacements;
|
|
3272
|
+
// sub-solver instances
|
|
3273
|
+
labelMergingSolver;
|
|
3274
|
+
overlapAvoidanceSolver;
|
|
3275
|
+
traceCleanupSolver;
|
|
3276
|
+
pipelineStepIndex = 0;
|
|
3277
|
+
constructor(solverInput) {
|
|
3278
|
+
super();
|
|
3279
|
+
this.inputProblem = solverInput.inputProblem;
|
|
3280
|
+
this.traces = solverInput.traces;
|
|
3281
|
+
this.netLabelPlacements = solverInput.netLabelPlacements;
|
|
3282
|
+
}
|
|
3283
|
+
_step() {
|
|
3284
|
+
if (this.activeSubSolver) {
|
|
3285
|
+
this.activeSubSolver.step();
|
|
3286
|
+
if (this.activeSubSolver.solved) {
|
|
3287
|
+
this.activeSubSolver = null;
|
|
3288
|
+
this.pipelineStepIndex++;
|
|
3289
|
+
} else if (this.activeSubSolver.failed) {
|
|
3290
|
+
this.failed = true;
|
|
3291
|
+
this.activeSubSolver = null;
|
|
3292
|
+
}
|
|
3293
|
+
return;
|
|
3294
|
+
}
|
|
3295
|
+
switch (this.pipelineStepIndex) {
|
|
3296
|
+
case 0:
|
|
3297
|
+
this.labelMergingSolver = new MergedNetLabelObstacleSolver({
|
|
3298
|
+
netLabelPlacements: this.netLabelPlacements,
|
|
3299
|
+
inputProblem: this.inputProblem,
|
|
3300
|
+
traces: this.traces
|
|
3301
|
+
});
|
|
3302
|
+
this.activeSubSolver = this.labelMergingSolver;
|
|
3303
|
+
break;
|
|
3304
|
+
case 1:
|
|
3305
|
+
this.overlapAvoidanceSolver = new OverlapAvoidanceStepSolver({
|
|
3306
|
+
inputProblem: this.inputProblem,
|
|
3307
|
+
traces: this.traces,
|
|
3308
|
+
netLabelPlacements: this.labelMergingSolver.getOutput().netLabelPlacements,
|
|
3309
|
+
mergedLabelNetIdMap: this.labelMergingSolver.getOutput().mergedLabelNetIdMap
|
|
3310
|
+
});
|
|
3311
|
+
this.activeSubSolver = this.overlapAvoidanceSolver;
|
|
3312
|
+
break;
|
|
3313
|
+
case 2:
|
|
3314
|
+
this.traceCleanupSolver = new TraceCleanupSolver({
|
|
3315
|
+
inputProblem: this.inputProblem,
|
|
3316
|
+
allTraces: this.overlapAvoidanceSolver.getOutput().allTraces,
|
|
3317
|
+
targetTraceIds: new Set(
|
|
3318
|
+
this.overlapAvoidanceSolver.getOutput().modifiedTraces.map(
|
|
3319
|
+
(t) => t.mspPairId
|
|
3320
|
+
)
|
|
3321
|
+
),
|
|
3322
|
+
allLabelPlacements: this.labelMergingSolver.getOutput().netLabelPlacements,
|
|
3323
|
+
mergedLabelNetIdMap: this.labelMergingSolver.getOutput().mergedLabelNetIdMap,
|
|
3324
|
+
paddingBuffer: 0.01
|
|
3325
|
+
});
|
|
3326
|
+
this.activeSubSolver = this.traceCleanupSolver;
|
|
3327
|
+
break;
|
|
3328
|
+
default:
|
|
3329
|
+
this.solved = true;
|
|
3330
|
+
break;
|
|
3014
3331
|
}
|
|
3015
|
-
this.solved = true;
|
|
3016
3332
|
}
|
|
3017
3333
|
getOutput() {
|
|
3018
3334
|
return {
|
|
3019
|
-
traces: this.
|
|
3020
|
-
netLabelPlacements: this.netLabelPlacements
|
|
3335
|
+
traces: this.traceCleanupSolver?.getOutput().traces ?? this.traces,
|
|
3336
|
+
netLabelPlacements: this.labelMergingSolver?.getOutput().netLabelPlacements ?? this.netLabelPlacements
|
|
3021
3337
|
};
|
|
3022
3338
|
}
|
|
3023
3339
|
visualize() {
|
|
3024
|
-
|
|
3340
|
+
if (this.activeSubSolver) {
|
|
3341
|
+
return this.activeSubSolver.visualize();
|
|
3342
|
+
}
|
|
3343
|
+
const graphics = visualizeInputProblem(this.inputProblem);
|
|
3025
3344
|
if (!graphics.lines) graphics.lines = [];
|
|
3026
|
-
if (!graphics.circles) graphics.circles = [];
|
|
3027
|
-
if (!graphics.texts) graphics.texts = [];
|
|
3028
3345
|
if (!graphics.rects) graphics.rects = [];
|
|
3029
|
-
|
|
3346
|
+
const output = this.getOutput();
|
|
3347
|
+
for (const trace of output.traces) {
|
|
3030
3348
|
graphics.lines.push({
|
|
3031
3349
|
points: trace.tracePath,
|
|
3032
3350
|
strokeColor: "purple"
|
|
3033
3351
|
});
|
|
3034
3352
|
}
|
|
3035
|
-
for (const
|
|
3353
|
+
for (const label of output.netLabelPlacements) {
|
|
3354
|
+
const color = getColorFromString(label.globalConnNetId, 0.3);
|
|
3036
3355
|
graphics.rects.push({
|
|
3037
|
-
center:
|
|
3038
|
-
width:
|
|
3039
|
-
height:
|
|
3040
|
-
fill:
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
x: p.anchorPoint.x,
|
|
3044
|
-
y: p.anchorPoint.y,
|
|
3045
|
-
color: getColorFromString(p.globalConnNetId, 0.9)
|
|
3356
|
+
center: label.center,
|
|
3357
|
+
width: label.width,
|
|
3358
|
+
height: label.height,
|
|
3359
|
+
fill: color,
|
|
3360
|
+
stroke: color.replace("0.3", "1"),
|
|
3361
|
+
label: label.globalConnNetId
|
|
3046
3362
|
});
|
|
3047
3363
|
}
|
|
3048
3364
|
return graphics;
|
|
@@ -3100,22 +3416,208 @@ var expandChipsToFitPins = (problem) => {
|
|
|
3100
3416
|
}
|
|
3101
3417
|
};
|
|
3102
3418
|
|
|
3419
|
+
// lib/utils/does-trace-overlap-with-existing-traces.ts
|
|
3420
|
+
import { doSegmentsIntersect } from "@tscircuit/math-utils";
|
|
3421
|
+
function doesTraceOverlapWithExistingTraces(newTracePath, existingTraces) {
|
|
3422
|
+
for (let i = 0; i < newTracePath.length - 1; i++) {
|
|
3423
|
+
const newSegmentP1 = newTracePath[i];
|
|
3424
|
+
const newSegmentP2 = newTracePath[i + 1];
|
|
3425
|
+
for (const existingTrace of existingTraces) {
|
|
3426
|
+
for (let j = 0; j < existingTrace.tracePath.length - 1; j++) {
|
|
3427
|
+
const existingSegmentP1 = existingTrace.tracePath[j];
|
|
3428
|
+
const existingSegmentP2 = existingTrace.tracePath[j + 1];
|
|
3429
|
+
if (doSegmentsIntersect(
|
|
3430
|
+
newSegmentP1,
|
|
3431
|
+
newSegmentP2,
|
|
3432
|
+
existingSegmentP1,
|
|
3433
|
+
existingSegmentP2
|
|
3434
|
+
)) {
|
|
3435
|
+
return true;
|
|
3436
|
+
}
|
|
3437
|
+
}
|
|
3438
|
+
}
|
|
3439
|
+
}
|
|
3440
|
+
return false;
|
|
3441
|
+
}
|
|
3442
|
+
|
|
3443
|
+
// lib/solvers/LongDistancePairSolver/LongDistancePairSolver.ts
|
|
3444
|
+
var NEAREST_NEIGHBOR_COUNT = 3;
|
|
3445
|
+
var distance = (p1, p2) => {
|
|
3446
|
+
return Math.sqrt(Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2));
|
|
3447
|
+
};
|
|
3448
|
+
var LongDistancePairSolver = class extends BaseSolver {
|
|
3449
|
+
constructor(params) {
|
|
3450
|
+
super();
|
|
3451
|
+
this.params = params;
|
|
3452
|
+
const { inputProblem, primaryMspConnectionPairs, alreadySolvedTraces } = this.params;
|
|
3453
|
+
this.inputProblem = inputProblem;
|
|
3454
|
+
this.allSolvedTraces = [...alreadySolvedTraces];
|
|
3455
|
+
const primaryConnectedPinIds = /* @__PURE__ */ new Set();
|
|
3456
|
+
for (const pair of primaryMspConnectionPairs) {
|
|
3457
|
+
primaryConnectedPinIds.add(pair.pins[0].pinId);
|
|
3458
|
+
primaryConnectedPinIds.add(pair.pins[1].pinId);
|
|
3459
|
+
}
|
|
3460
|
+
const { netConnMap } = getConnectivityMapsFromInputProblem(inputProblem);
|
|
3461
|
+
this.netConnMap = netConnMap;
|
|
3462
|
+
const pinMap = /* @__PURE__ */ new Map();
|
|
3463
|
+
for (const chip of inputProblem.chips) {
|
|
3464
|
+
this.chipMap[chip.chipId] = chip;
|
|
3465
|
+
for (const pin of chip.pins) {
|
|
3466
|
+
pinMap.set(pin.pinId, { ...pin, chipId: chip.chipId });
|
|
3467
|
+
}
|
|
3468
|
+
}
|
|
3469
|
+
const candidatePairs = [];
|
|
3470
|
+
const addedPairKeys = /* @__PURE__ */ new Set();
|
|
3471
|
+
for (const netId of Object.keys(netConnMap.netMap)) {
|
|
3472
|
+
const allPinIdsInNet = netConnMap.getIdsConnectedToNet(netId);
|
|
3473
|
+
if (allPinIdsInNet.length < 2) continue;
|
|
3474
|
+
const unconnectedPinIds = allPinIdsInNet.filter(
|
|
3475
|
+
(pinId) => !primaryConnectedPinIds.has(pinId)
|
|
3476
|
+
);
|
|
3477
|
+
for (const unconnectedPinId of unconnectedPinIds) {
|
|
3478
|
+
const sourcePin = pinMap.get(unconnectedPinId);
|
|
3479
|
+
if (!sourcePin) continue;
|
|
3480
|
+
const neighbors = allPinIdsInNet.filter((otherPinId) => otherPinId !== unconnectedPinId).flatMap((otherPinId) => {
|
|
3481
|
+
const targetPin = pinMap.get(otherPinId);
|
|
3482
|
+
if (!targetPin) return [];
|
|
3483
|
+
return [
|
|
3484
|
+
{
|
|
3485
|
+
pin: targetPin,
|
|
3486
|
+
distance: distance(sourcePin, targetPin)
|
|
3487
|
+
}
|
|
3488
|
+
];
|
|
3489
|
+
}).sort((a, b) => a.distance - b.distance).slice(0, NEAREST_NEIGHBOR_COUNT);
|
|
3490
|
+
for (const neighbor of neighbors) {
|
|
3491
|
+
const pair = [sourcePin, neighbor.pin];
|
|
3492
|
+
const pairKey = pair.map((p) => p.pinId).sort().join("--");
|
|
3493
|
+
if (!addedPairKeys.has(pairKey)) {
|
|
3494
|
+
candidatePairs.push(pair);
|
|
3495
|
+
addedPairKeys.add(pairKey);
|
|
3496
|
+
}
|
|
3497
|
+
}
|
|
3498
|
+
}
|
|
3499
|
+
}
|
|
3500
|
+
this.queuedCandidatePairs = candidatePairs;
|
|
3501
|
+
}
|
|
3502
|
+
solvedLongDistanceTraces = [];
|
|
3503
|
+
queuedCandidatePairs = [];
|
|
3504
|
+
currentCandidatePair = null;
|
|
3505
|
+
subSolver = null;
|
|
3506
|
+
chipMap = {};
|
|
3507
|
+
inputProblem;
|
|
3508
|
+
netConnMap;
|
|
3509
|
+
newlyConnectedPinIds = /* @__PURE__ */ new Set();
|
|
3510
|
+
allSolvedTraces = [];
|
|
3511
|
+
getConstructorParams() {
|
|
3512
|
+
return this.params;
|
|
3513
|
+
}
|
|
3514
|
+
_step() {
|
|
3515
|
+
if (this.subSolver?.solved) {
|
|
3516
|
+
const newTracePath = this.subSolver.solvedTracePath;
|
|
3517
|
+
if (newTracePath && this.currentCandidatePair) {
|
|
3518
|
+
const isTraceClear = !doesTraceOverlapWithExistingTraces(
|
|
3519
|
+
newTracePath,
|
|
3520
|
+
this.allSolvedTraces
|
|
3521
|
+
);
|
|
3522
|
+
if (isTraceClear) {
|
|
3523
|
+
const [p1, p2] = this.currentCandidatePair;
|
|
3524
|
+
const globalConnNetId = this.netConnMap.getNetConnectedToId(p1.pinId);
|
|
3525
|
+
const mspPairId = `${p1.pinId}-${p2.pinId}`;
|
|
3526
|
+
const newSolvedTrace = {
|
|
3527
|
+
mspPairId,
|
|
3528
|
+
dcConnNetId: globalConnNetId,
|
|
3529
|
+
globalConnNetId,
|
|
3530
|
+
pins: [p1, p2],
|
|
3531
|
+
tracePath: newTracePath,
|
|
3532
|
+
mspConnectionPairIds: [mspPairId],
|
|
3533
|
+
pinIds: [p1.pinId, p2.pinId]
|
|
3534
|
+
};
|
|
3535
|
+
this.solvedLongDistanceTraces.push(newSolvedTrace);
|
|
3536
|
+
this.allSolvedTraces.push(newSolvedTrace);
|
|
3537
|
+
this.newlyConnectedPinIds.add(p1.pinId);
|
|
3538
|
+
this.newlyConnectedPinIds.add(p2.pinId);
|
|
3539
|
+
}
|
|
3540
|
+
}
|
|
3541
|
+
this.subSolver = null;
|
|
3542
|
+
this.currentCandidatePair = null;
|
|
3543
|
+
} else if (this.subSolver?.failed) {
|
|
3544
|
+
this.subSolver = null;
|
|
3545
|
+
this.currentCandidatePair = null;
|
|
3546
|
+
}
|
|
3547
|
+
if (this.subSolver) {
|
|
3548
|
+
this.subSolver.step();
|
|
3549
|
+
return;
|
|
3550
|
+
}
|
|
3551
|
+
while (this.queuedCandidatePairs.length > 0) {
|
|
3552
|
+
const nextPair = this.queuedCandidatePairs.shift();
|
|
3553
|
+
const [p1, p2] = nextPair;
|
|
3554
|
+
if (this.newlyConnectedPinIds.has(p1.pinId) || this.newlyConnectedPinIds.has(p2.pinId)) {
|
|
3555
|
+
continue;
|
|
3556
|
+
}
|
|
3557
|
+
this.currentCandidatePair = nextPair;
|
|
3558
|
+
this.subSolver = new SchematicTraceSingleLineSolver2({
|
|
3559
|
+
inputProblem: this.params.inputProblem,
|
|
3560
|
+
pins: this.currentCandidatePair,
|
|
3561
|
+
chipMap: this.chipMap
|
|
3562
|
+
});
|
|
3563
|
+
return;
|
|
3564
|
+
}
|
|
3565
|
+
this.solved = true;
|
|
3566
|
+
}
|
|
3567
|
+
visualize() {
|
|
3568
|
+
if (this.subSolver) {
|
|
3569
|
+
return this.subSolver.visualize();
|
|
3570
|
+
}
|
|
3571
|
+
const graphics = visualizeInputProblem(this.inputProblem);
|
|
3572
|
+
for (const trace of this.solvedLongDistanceTraces) {
|
|
3573
|
+
graphics.lines.push({
|
|
3574
|
+
points: trace.tracePath,
|
|
3575
|
+
strokeColor: "purple"
|
|
3576
|
+
});
|
|
3577
|
+
}
|
|
3578
|
+
for (const [p1, p2] of this.queuedCandidatePairs) {
|
|
3579
|
+
graphics.lines.push({
|
|
3580
|
+
points: [p1, p2],
|
|
3581
|
+
strokeColor: "gray",
|
|
3582
|
+
strokeDash: "4 4"
|
|
3583
|
+
});
|
|
3584
|
+
}
|
|
3585
|
+
return graphics;
|
|
3586
|
+
}
|
|
3587
|
+
getOutput() {
|
|
3588
|
+
if (!this.solved) {
|
|
3589
|
+
return { newTraces: [], allTracesMerged: this.params.alreadySolvedTraces };
|
|
3590
|
+
}
|
|
3591
|
+
return {
|
|
3592
|
+
newTraces: this.solvedLongDistanceTraces,
|
|
3593
|
+
allTracesMerged: [
|
|
3594
|
+
...this.params.alreadySolvedTraces,
|
|
3595
|
+
...this.solvedLongDistanceTraces
|
|
3596
|
+
]
|
|
3597
|
+
};
|
|
3598
|
+
}
|
|
3599
|
+
};
|
|
3600
|
+
|
|
3103
3601
|
// lib/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver.ts
|
|
3104
3602
|
function definePipelineStep(solverName, solverClass, getConstructorParams, opts = {}) {
|
|
3105
3603
|
return {
|
|
3106
3604
|
solverName,
|
|
3107
3605
|
solverClass,
|
|
3108
3606
|
getConstructorParams,
|
|
3109
|
-
onSolved: opts.onSolved
|
|
3607
|
+
onSolved: opts.onSolved,
|
|
3608
|
+
shouldSkip: opts.shouldSkip
|
|
3110
3609
|
};
|
|
3111
3610
|
}
|
|
3112
3611
|
var SchematicTracePipelineSolver = class extends BaseSolver {
|
|
3113
3612
|
mspConnectionPairSolver;
|
|
3114
3613
|
// guidelinesSolver?: GuidelinesSolver
|
|
3115
3614
|
schematicTraceLinesSolver;
|
|
3615
|
+
longDistancePairSolver;
|
|
3116
3616
|
traceOverlapShiftSolver;
|
|
3117
3617
|
netLabelPlacementSolver;
|
|
3618
|
+
labelMergingSolver;
|
|
3118
3619
|
traceLabelOverlapAvoidanceSolver;
|
|
3620
|
+
traceCleanupSolver;
|
|
3119
3621
|
startTimeOfPhase;
|
|
3120
3622
|
endTimeOfPhase;
|
|
3121
3623
|
timeSpentOnPhase;
|
|
@@ -3155,6 +3657,17 @@ var SchematicTracePipelineSolver = class extends BaseSolver {
|
|
|
3155
3657
|
// guidelines: this.guidelinesSolver!.guidelines,
|
|
3156
3658
|
chipMap: this.mspConnectionPairSolver.chipMap
|
|
3157
3659
|
}
|
|
3660
|
+
]
|
|
3661
|
+
),
|
|
3662
|
+
definePipelineStep(
|
|
3663
|
+
"longDistancePairSolver",
|
|
3664
|
+
LongDistancePairSolver,
|
|
3665
|
+
(instance) => [
|
|
3666
|
+
{
|
|
3667
|
+
inputProblem: instance.inputProblem,
|
|
3668
|
+
primaryMspConnectionPairs: instance.mspConnectionPairSolver.mspConnectionPairs,
|
|
3669
|
+
alreadySolvedTraces: instance.schematicTraceLinesSolver.solvedTracePaths
|
|
3670
|
+
}
|
|
3158
3671
|
],
|
|
3159
3672
|
{
|
|
3160
3673
|
onSolved: (schematicTraceLinesSolver) => {
|
|
@@ -3167,7 +3680,7 @@ var SchematicTracePipelineSolver = class extends BaseSolver {
|
|
|
3167
3680
|
() => [
|
|
3168
3681
|
{
|
|
3169
3682
|
inputProblem: this.inputProblem,
|
|
3170
|
-
inputTracePaths: this.
|
|
3683
|
+
inputTracePaths: this.longDistancePairSolver?.getOutput().allTracesMerged,
|
|
3171
3684
|
globalConnMap: this.mspConnectionPairSolver.globalConnMap
|
|
3172
3685
|
}
|
|
3173
3686
|
],
|
|
@@ -3183,10 +3696,9 @@ var SchematicTracePipelineSolver = class extends BaseSolver {
|
|
|
3183
3696
|
{
|
|
3184
3697
|
inputProblem: this.inputProblem,
|
|
3185
3698
|
inputTraceMap: this.traceOverlapShiftSolver?.correctedTraceMap ?? Object.fromEntries(
|
|
3186
|
-
this.
|
|
3187
|
-
p.mspPairId,
|
|
3188
|
-
|
|
3189
|
-
])
|
|
3699
|
+
this.longDistancePairSolver.getOutput().allTracesMerged.map(
|
|
3700
|
+
(p) => [p.mspPairId, p]
|
|
3701
|
+
)
|
|
3190
3702
|
)
|
|
3191
3703
|
}
|
|
3192
3704
|
],
|
|
@@ -3200,10 +3712,7 @@ var SchematicTracePipelineSolver = class extends BaseSolver {
|
|
|
3200
3712
|
TraceLabelOverlapAvoidanceSolver,
|
|
3201
3713
|
(instance) => {
|
|
3202
3714
|
const traceMap = instance.traceOverlapShiftSolver?.correctedTraceMap ?? Object.fromEntries(
|
|
3203
|
-
instance.
|
|
3204
|
-
p.mspPairId,
|
|
3205
|
-
p
|
|
3206
|
-
])
|
|
3715
|
+
instance.longDistancePairSolver.getOutput().allTracesMerged.map((p) => [p.mspPairId, p])
|
|
3207
3716
|
);
|
|
3208
3717
|
const traces = Object.values(traceMap);
|
|
3209
3718
|
const netLabelPlacements = instance.netLabelPlacementSolver.netLabelPlacements;
|
|
@@ -3214,14 +3723,21 @@ var SchematicTracePipelineSolver = class extends BaseSolver {
|
|
|
3214
3723
|
netLabelPlacements
|
|
3215
3724
|
}
|
|
3216
3725
|
];
|
|
3217
|
-
}
|
|
3218
|
-
|
|
3219
|
-
|
|
3220
|
-
|
|
3221
|
-
|
|
3222
|
-
|
|
3726
|
+
}
|
|
3727
|
+
),
|
|
3728
|
+
definePipelineStep(
|
|
3729
|
+
"netLabelPlacementSolver",
|
|
3730
|
+
NetLabelPlacementSolver,
|
|
3731
|
+
(instance) => {
|
|
3732
|
+
const traces = instance.traceCleanupSolver?.getOutput().traces ?? instance.traceLabelOverlapAvoidanceSolver.getOutput().traces;
|
|
3733
|
+
return [
|
|
3734
|
+
{
|
|
3735
|
+
inputProblem: instance.inputProblem,
|
|
3736
|
+
inputTraceMap: Object.fromEntries(
|
|
3737
|
+
traces.map((trace) => [trace.mspPairId, trace])
|
|
3738
|
+
)
|
|
3223
3739
|
}
|
|
3224
|
-
|
|
3740
|
+
];
|
|
3225
3741
|
}
|
|
3226
3742
|
)
|
|
3227
3743
|
];
|
|
@@ -3307,14 +3823,17 @@ var SchematicTracePipelineSolver = class extends BaseSolver {
|
|
|
3307
3823
|
return viz;
|
|
3308
3824
|
})
|
|
3309
3825
|
];
|
|
3310
|
-
if (visualizations.length === 1)
|
|
3311
|
-
|
|
3826
|
+
if (visualizations.length === 1) {
|
|
3827
|
+
return visualizations[0];
|
|
3828
|
+
}
|
|
3829
|
+
const finalGraphics = {
|
|
3312
3830
|
points: visualizations.flatMap((v) => v.points || []),
|
|
3313
3831
|
rects: visualizations.flatMap((v) => v.rects || []),
|
|
3314
3832
|
lines: visualizations.flatMap((v) => v.lines || []),
|
|
3315
3833
|
circles: visualizations.flatMap((v) => v.circles || []),
|
|
3316
3834
|
texts: visualizations.flatMap((v) => v.texts || [])
|
|
3317
3835
|
};
|
|
3836
|
+
return finalGraphics;
|
|
3318
3837
|
}
|
|
3319
3838
|
/**
|
|
3320
3839
|
* A lightweight version of the visualize method that can be used to stream
|