@tscircuit/schematic-trace-solver 0.0.187 → 0.0.188
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 +40 -23
- package/dist/index.js +1030 -311
- package/lib/solvers/InlineNetLabelSolver/InlineNetLabelSolver.ts +611 -230
- package/lib/solvers/InlineNetLabelSolver/alignPortOnlyInlineNetLabelStubs.ts +2 -6
- package/lib/solvers/InlineNetLabelSolver/getInlineLabelObstacles.ts +64 -0
- package/lib/solvers/InlineNetLabelSolver/getLocalTraceLabelShifts.ts +407 -0
- package/lib/solvers/InlineNetLabelSolver/getOutputLabelCollisions.ts +145 -0
- package/lib/solvers/InlineNetLabelSolver/isLabelRepresentedInline.ts +15 -0
- package/lib/solvers/InlineNetLabelSolver/pushAnchoredNetLabelsAwayFromInlineLabels.ts +61 -31
- package/lib/solvers/NetLabelNetLabelCollisionSolver/NetLabelNetLabelCollisionSolver.ts +83 -14
- package/lib/solvers/NetLabelToTraceSolver/NetLabelToTraceSolver.ts +4 -3
- package/lib/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver.ts +3 -0
- package/lib/types/InputProblem.ts +2 -2
- package/package.json +1 -1
- package/site/bug-reports/bug-report-20260907T110144Z.page.tsx +4 -0
- package/site/bug-reports/bug-report-20260907T145640Z.page.tsx +4 -0
- package/tests/bug-reports/bug-report-20260806T093501Z/__snapshots__/bug-report-20260806T093501Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260811T075142Z/__snapshots__/bug-report-20260811T075142Z.snap.svg +18 -18
- package/tests/bug-reports/bug-report-20260819T091818Z/__snapshots__/bug-report-20260819T091818Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260819T091818Z/bug-report-20260819T091818Z.test.ts +21 -0
- package/tests/bug-reports/bug-report-20260825T103621Z/__snapshots__/bug-report-20260825T103621Z.snap.svg +5 -38
- package/tests/bug-reports/bug-report-20260826T072956Z/__snapshots__/bug-report-20260826T072956Z.snap.svg +3 -9
- package/tests/bug-reports/bug-report-20260901T055358Z/__snapshots__/bug-report-20260901T055358Z.snap.svg +18 -30
- package/tests/bug-reports/bug-report-20260901T055358Z/bug-report-20260901T055358Z.test.ts +33 -0
- package/tests/bug-reports/bug-report-20260907T110144Z/__snapshots__/bug-report-20260907T110144Z.snap.svg +282 -0
- package/tests/bug-reports/bug-report-20260907T110144Z/bug-report-20260907T110144Z.json +1073 -0
- package/tests/bug-reports/bug-report-20260907T110144Z/bug-report-20260907T110144Z.test.ts +12 -0
- package/tests/bug-reports/bug-report-20260907T145640Z/__snapshots__/bug-report-20260907T145640Z.snap.svg +1107 -0
- package/tests/bug-reports/bug-report-20260907T145640Z/bug-report-20260907T145640Z.json +3563 -0
- package/tests/bug-reports/bug-report-20260907T145640Z/bug-report-20260907T145640Z.test.ts +117 -0
- package/tests/repros/__snapshots__/repro-battery-management-bq24073.snap.svg +4 -4
- package/tests/repros/__snapshots__/repro-board-648-esp12f-section.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-core-tb67s579ftg-inline-label-routing.snap.svg +20 -20
- package/tests/repros/__snapshots__/repro-esp12f-section.snap.svg +37 -55
- package/tests/repros/__snapshots__/repro-hub-usb-sheet.snap.svg +44 -68
- package/tests/repros/__snapshots__/repro-mspm0l1306-capacitor-symmetry.snap.svg +3 -9
- package/tests/repros/__snapshots__/repro-usb-power-vbus-label-detour.snap.svg +50 -74
- package/tests/repros/__snapshots__/repro48-555-timer-vcc-rail-label.snap.svg +2 -2
- package/tests/repros/repro-battery-management-bq24073.test.ts +13 -1
- package/tests/repros/repro-hub-usb-sheet.test.ts +25 -0
- package/tests/repros/repro-usb-power-vbus-label-detour.test.ts +59 -13
- package/tests/solvers/InlineNetLabelSolver/local-trace-label-shifts.test.ts +296 -0
- package/tests/solvers/InlineNetLabelSolver/multi-pin-connected-components.test.ts +7 -4
- package/tests/solvers/InlineNetLabelSolver/push-anchored-net-labels-away.test.ts +2 -1
- package/tests/solvers/InlineNetLabelSolver/shared-direct-and-named-connection.test.ts +62 -0
- package/tests/solvers/InlineNetLabelSolver/two-pin-terminal-stubs-atomic.test.ts +9 -3
package/dist/index.js
CHANGED
|
@@ -342,19 +342,19 @@ var doesPairCrossRestrictedCenterLines = (params) => {
|
|
|
342
342
|
chipMap
|
|
343
343
|
});
|
|
344
344
|
if (restrictedCenterLines.size === 0) return false;
|
|
345
|
-
const
|
|
345
|
+
const EPS18 = 1e-9;
|
|
346
346
|
const crossesSegment = (a, b) => {
|
|
347
347
|
for (const [, rcl] of restrictedCenterLines) {
|
|
348
348
|
if (rcl.axes.has("x") && typeof rcl.x === "number") {
|
|
349
|
-
if ((a.x - rcl.x) * (b.x - rcl.x) < -
|
|
349
|
+
if ((a.x - rcl.x) * (b.x - rcl.x) < -EPS18) return true;
|
|
350
350
|
}
|
|
351
351
|
if (rcl.axes.has("y") && typeof rcl.y === "number") {
|
|
352
|
-
if ((a.y - rcl.y) * (b.y - rcl.y) < -
|
|
352
|
+
if ((a.y - rcl.y) * (b.y - rcl.y) < -EPS18) return true;
|
|
353
353
|
}
|
|
354
354
|
}
|
|
355
355
|
return false;
|
|
356
356
|
};
|
|
357
|
-
if (Math.abs(p1.x - p2.x) <
|
|
357
|
+
if (Math.abs(p1.x - p2.x) < EPS18 || Math.abs(p1.y - p2.y) < EPS18) {
|
|
358
358
|
return crossesSegment({ x: p1.x, y: p1.y }, { x: p2.x, y: p2.y });
|
|
359
359
|
}
|
|
360
360
|
const elbowHV = { x: p2.x, y: p1.y };
|
|
@@ -1657,8 +1657,8 @@ var SchematicTraceSingleLineSolver2 = class extends BaseSolver {
|
|
|
1657
1657
|
if (!collision) {
|
|
1658
1658
|
const first = path[0];
|
|
1659
1659
|
const last = path[path.length - 1];
|
|
1660
|
-
const
|
|
1661
|
-
const samePoint = (p, q) => Math.abs(p.x - q.x) <
|
|
1660
|
+
const EPS18 = 1e-9;
|
|
1661
|
+
const samePoint = (p, q) => Math.abs(p.x - q.x) < EPS18 && Math.abs(p.y - q.y) < EPS18;
|
|
1662
1662
|
if (samePoint(first, { x: PA.x, y: PA.y }) && samePoint(last, { x: PB.x, y: PB.y }) && (!this.hasAmbiguousPinDirections || pathMatchesPinDirections({
|
|
1663
1663
|
path,
|
|
1664
1664
|
pin1: { ...PA, _facingDirection: directions[0] },
|
|
@@ -2013,13 +2013,13 @@ var applyJogToTerminalSegment = ({
|
|
|
2013
2013
|
segmentIndex: si,
|
|
2014
2014
|
offset,
|
|
2015
2015
|
JOG_SIZE,
|
|
2016
|
-
EPS:
|
|
2016
|
+
EPS: EPS18 = 1e-6
|
|
2017
2017
|
}) => {
|
|
2018
2018
|
if (si !== 0 && si !== pts.length - 2) return;
|
|
2019
2019
|
const start = pts[si];
|
|
2020
2020
|
const end = pts[si + 1];
|
|
2021
|
-
const isVertical6 = Math.abs(start.x - end.x) <
|
|
2022
|
-
const isHorizontal5 = Math.abs(start.y - end.y) <
|
|
2021
|
+
const isVertical6 = Math.abs(start.x - end.x) < EPS18;
|
|
2022
|
+
const isHorizontal5 = Math.abs(start.y - end.y) < EPS18;
|
|
2023
2023
|
if (!isVertical6 && !isHorizontal5) return;
|
|
2024
2024
|
const segDir = isVertical6 ? end.y > start.y ? 1 : -1 : end.x > start.x ? 1 : -1;
|
|
2025
2025
|
if (pts.length === 2) {
|
|
@@ -2453,7 +2453,7 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
|
|
|
2453
2453
|
return islands;
|
|
2454
2454
|
}
|
|
2455
2455
|
findNextOverlapIssue() {
|
|
2456
|
-
const
|
|
2456
|
+
const EPS18 = 2e-3;
|
|
2457
2457
|
const netIds = Object.keys(this.traceNetIslands);
|
|
2458
2458
|
for (let i = 0; i < netIds.length; i++) {
|
|
2459
2459
|
for (let j = i + 1; j < netIds.length; j++) {
|
|
@@ -2480,7 +2480,7 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
|
|
|
2480
2480
|
segmentBIndex,
|
|
2481
2481
|
rangeOverlap
|
|
2482
2482
|
}) => {
|
|
2483
|
-
if (rangeOverlap >
|
|
2483
|
+
if (rangeOverlap > EPS18) {
|
|
2484
2484
|
const keyA = `${pathAIndex}:${segmentAIndex}`;
|
|
2485
2485
|
const keyB = `${pathBIndex}:${segmentBIndex}`;
|
|
2486
2486
|
if (!seenA.has(keyA)) {
|
|
@@ -2499,7 +2499,7 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
|
|
|
2499
2499
|
}
|
|
2500
2500
|
return;
|
|
2501
2501
|
}
|
|
2502
|
-
if (rangeOverlap < -
|
|
2502
|
+
if (rangeOverlap < -EPS18) return;
|
|
2503
2503
|
const pathA = pathsA[pathAIndex].tracePath;
|
|
2504
2504
|
const pathB = pathsB[pathBIndex].tracePath;
|
|
2505
2505
|
const segmentAStart = pathA[segmentAIndex];
|
|
@@ -2522,8 +2522,8 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
|
|
|
2522
2522
|
for (let sa = 0; sa < ptsA.length - 1; sa++) {
|
|
2523
2523
|
const a1 = ptsA[sa];
|
|
2524
2524
|
const a2 = ptsA[sa + 1];
|
|
2525
|
-
const aVert = Math.abs(a1.x - a2.x) <
|
|
2526
|
-
const aHorz = Math.abs(a1.y - a2.y) <
|
|
2525
|
+
const aVert = Math.abs(a1.x - a2.x) < EPS18;
|
|
2526
|
+
const aHorz = Math.abs(a1.y - a2.y) < EPS18;
|
|
2527
2527
|
if (!aVert && !aHorz) continue;
|
|
2528
2528
|
for (let pb = 0; pb < pathsB.length; pb++) {
|
|
2529
2529
|
const pathB = pathsB[pb];
|
|
@@ -2534,11 +2534,11 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
|
|
|
2534
2534
|
for (let sb = 0; sb < ptsB.length - 1; sb++) {
|
|
2535
2535
|
const b1 = ptsB[sb];
|
|
2536
2536
|
const b2 = ptsB[sb + 1];
|
|
2537
|
-
const bVert = Math.abs(b1.x - b2.x) <
|
|
2538
|
-
const bHorz = Math.abs(b1.y - b2.y) <
|
|
2537
|
+
const bVert = Math.abs(b1.x - b2.x) < EPS18;
|
|
2538
|
+
const bHorz = Math.abs(b1.y - b2.y) < EPS18;
|
|
2539
2539
|
if (!bVert && !bHorz) continue;
|
|
2540
2540
|
if (aVert && bVert) {
|
|
2541
|
-
if (Math.abs(a1.x - b1.x) <
|
|
2541
|
+
if (Math.abs(a1.x - b1.x) < EPS18) {
|
|
2542
2542
|
recordCollinearInteraction({
|
|
2543
2543
|
pathAIndex: pa,
|
|
2544
2544
|
segmentAIndex: sa,
|
|
@@ -2548,7 +2548,7 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
|
|
|
2548
2548
|
});
|
|
2549
2549
|
}
|
|
2550
2550
|
} else if (aHorz && bHorz) {
|
|
2551
|
-
if (Math.abs(a1.y - b1.y) <
|
|
2551
|
+
if (Math.abs(a1.y - b1.y) < EPS18) {
|
|
2552
2552
|
recordCollinearInteraction({
|
|
2553
2553
|
pathAIndex: pa,
|
|
2554
2554
|
segmentAIndex: sa,
|
|
@@ -2604,14 +2604,14 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
|
|
|
2604
2604
|
return null;
|
|
2605
2605
|
}
|
|
2606
2606
|
findNextDiagonalSegment() {
|
|
2607
|
-
const
|
|
2607
|
+
const EPS18 = 2e-3;
|
|
2608
2608
|
for (const mspPairId in this.correctedTraceMap) {
|
|
2609
2609
|
const tracePath = this.correctedTraceMap[mspPairId].tracePath;
|
|
2610
2610
|
for (let i = 0; i < tracePath.length - 1; i++) {
|
|
2611
2611
|
const p1 = tracePath[i];
|
|
2612
2612
|
const p2 = tracePath[i + 1];
|
|
2613
|
-
const isHorizontal5 = Math.abs(p1.y - p2.y) <
|
|
2614
|
-
const isVertical6 = Math.abs(p1.x - p2.x) <
|
|
2613
|
+
const isHorizontal5 = Math.abs(p1.y - p2.y) < EPS18;
|
|
2614
|
+
const isVertical6 = Math.abs(p1.x - p2.x) < EPS18;
|
|
2615
2615
|
if (!isHorizontal5 && !isVertical6) {
|
|
2616
2616
|
return { mspPairId, tracePath, i, p1, p2 };
|
|
2617
2617
|
}
|
|
@@ -2625,13 +2625,13 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
|
|
|
2625
2625
|
return false;
|
|
2626
2626
|
}
|
|
2627
2627
|
const { mspPairId, tracePath, i, p1, p2 } = diagonalInfo;
|
|
2628
|
-
const
|
|
2628
|
+
const EPS18 = 2e-3;
|
|
2629
2629
|
const p0 = i > 0 ? tracePath[i - 1] : null;
|
|
2630
2630
|
const p3 = i + 2 < tracePath.length ? tracePath[i + 2] : null;
|
|
2631
|
-
const prevIsVertical = p0 ? Math.abs(p0.x - p1.x) <
|
|
2632
|
-
const prevIsHorizontal = p0 ? Math.abs(p0.y - p1.y) <
|
|
2633
|
-
const nextIsVertical = p3 ? Math.abs(p2.x - p3.x) <
|
|
2634
|
-
const nextIsHorizontal = p3 ? Math.abs(p2.y - p3.y) <
|
|
2631
|
+
const prevIsVertical = p0 ? Math.abs(p0.x - p1.x) < EPS18 : false;
|
|
2632
|
+
const prevIsHorizontal = p0 ? Math.abs(p0.y - p1.y) < EPS18 : false;
|
|
2633
|
+
const nextIsVertical = p3 ? Math.abs(p2.x - p3.x) < EPS18 : false;
|
|
2634
|
+
const nextIsHorizontal = p3 ? Math.abs(p2.y - p3.y) < EPS18 : false;
|
|
2635
2635
|
const elbow1 = { x: p1.x, y: p2.y };
|
|
2636
2636
|
const elbow2 = { x: p2.x, y: p1.y };
|
|
2637
2637
|
let score1 = 0;
|
|
@@ -2793,24 +2793,24 @@ var ChipObstacleSpatialIndex = class {
|
|
|
2793
2793
|
};
|
|
2794
2794
|
|
|
2795
2795
|
// lib/solvers/NetLabelPlacementSolver/SingleNetLabelPlacementSolver/collisions.ts
|
|
2796
|
-
function segmentIntersectsRect2(p1, p2, rect,
|
|
2797
|
-
const isVert = Math.abs(p1.x - p2.x) <
|
|
2798
|
-
const isHorz = Math.abs(p1.y - p2.y) <
|
|
2796
|
+
function segmentIntersectsRect2(p1, p2, rect, EPS18 = 1e-9) {
|
|
2797
|
+
const isVert = Math.abs(p1.x - p2.x) < EPS18;
|
|
2798
|
+
const isHorz = Math.abs(p1.y - p2.y) < EPS18;
|
|
2799
2799
|
if (!isVert && !isHorz) return false;
|
|
2800
2800
|
if (isVert) {
|
|
2801
2801
|
const x = p1.x;
|
|
2802
|
-
if (x < rect.minX -
|
|
2802
|
+
if (x < rect.minX - EPS18 || x > rect.maxX + EPS18) return false;
|
|
2803
2803
|
const segMinY = Math.min(p1.y, p2.y);
|
|
2804
2804
|
const segMaxY = Math.max(p1.y, p2.y);
|
|
2805
2805
|
const overlap = Math.min(segMaxY, rect.maxY) - Math.max(segMinY, rect.minY);
|
|
2806
|
-
return overlap >
|
|
2806
|
+
return overlap > EPS18;
|
|
2807
2807
|
} else {
|
|
2808
2808
|
const y = p1.y;
|
|
2809
|
-
if (y < rect.minY -
|
|
2809
|
+
if (y < rect.minY - EPS18 || y > rect.maxY + EPS18) return false;
|
|
2810
2810
|
const segMinX = Math.min(p1.x, p2.x);
|
|
2811
2811
|
const segMaxX = Math.max(p1.x, p2.x);
|
|
2812
2812
|
const overlap = Math.min(segMaxX, rect.maxX) - Math.max(segMinX, rect.minX);
|
|
2813
|
-
return overlap >
|
|
2813
|
+
return overlap > EPS18;
|
|
2814
2814
|
}
|
|
2815
2815
|
}
|
|
2816
2816
|
function rectIntersectsAnyTrace(bounds, inputTraceMap, hostPathId, hostSegIndex) {
|
|
@@ -3209,14 +3209,14 @@ var SingleNetLabelPlacementSolver = class extends BaseSolver {
|
|
|
3209
3209
|
};
|
|
3210
3210
|
let bestCandidate = null;
|
|
3211
3211
|
let bestScore = -Infinity;
|
|
3212
|
-
const
|
|
3212
|
+
const EPS18 = 1e-6;
|
|
3213
3213
|
for (const curr of tracesToScan) {
|
|
3214
3214
|
const pts = curr.tracePath.slice();
|
|
3215
3215
|
for (let si = 0; si < pts.length - 1; si++) {
|
|
3216
3216
|
const a = pts[si];
|
|
3217
3217
|
const b = pts[si + 1];
|
|
3218
|
-
const isH = Math.abs(a.y - b.y) <
|
|
3219
|
-
const isV = Math.abs(a.x - b.x) <
|
|
3218
|
+
const isH = Math.abs(a.y - b.y) < EPS18;
|
|
3219
|
+
const isV = Math.abs(a.x - b.x) < EPS18;
|
|
3220
3220
|
if (!isH && !isV) continue;
|
|
3221
3221
|
const segmentAllowed = isH ? ["y+", "y-"] : ["x+", "x-"];
|
|
3222
3222
|
const candidateOrients = orientations.filter(
|
|
@@ -5049,7 +5049,7 @@ var clipPathAtFirstIntersection = (tracePath, existingTraces) => {
|
|
|
5049
5049
|
for (let pathIndex = 0; pathIndex < tracePath.length - 1; pathIndex++) {
|
|
5050
5050
|
const pathStart = tracePath[pathIndex];
|
|
5051
5051
|
const pathEnd = tracePath[pathIndex + 1];
|
|
5052
|
-
const
|
|
5052
|
+
const intersections2 = existingTraces.flatMap(
|
|
5053
5053
|
(trace) => trace.tracePath.slice(0, -1).flatMap((traceStart, traceIndex) => {
|
|
5054
5054
|
const intersection2 = getAxisAlignedIntersection(
|
|
5055
5055
|
pathStart,
|
|
@@ -5060,10 +5060,10 @@ var clipPathAtFirstIntersection = (tracePath, existingTraces) => {
|
|
|
5060
5060
|
return intersection2 ? [intersection2] : [];
|
|
5061
5061
|
})
|
|
5062
5062
|
);
|
|
5063
|
-
|
|
5063
|
+
intersections2.sort(
|
|
5064
5064
|
(first, second) => distance3(pathStart, first) - distance3(pathStart, second)
|
|
5065
5065
|
);
|
|
5066
|
-
const intersection =
|
|
5066
|
+
const intersection = intersections2[0];
|
|
5067
5067
|
if (!intersection) continue;
|
|
5068
5068
|
const clippedPath = tracePath.slice(0, pathIndex + 1);
|
|
5069
5069
|
if (distance3(clippedPath.at(-1), intersection) > EPS6) {
|
|
@@ -6800,7 +6800,7 @@ var getTraceObstacles = (allTraces, excludeTraceId) => {
|
|
|
6800
6800
|
import { getSegmentIntersection } from "@tscircuit/math-utils/line-intersections";
|
|
6801
6801
|
var EPS9 = 1e-6;
|
|
6802
6802
|
var findIntersectionsWithObstacles = (p1, p2, obstacles) => {
|
|
6803
|
-
const
|
|
6803
|
+
const intersections2 = [];
|
|
6804
6804
|
for (const obstacle of obstacles) {
|
|
6805
6805
|
const obstaclePath = obstacle.points;
|
|
6806
6806
|
for (let i = 0; i < obstaclePath.length - 1; i++) {
|
|
@@ -6811,11 +6811,11 @@ var findIntersectionsWithObstacles = (p1, p2, obstacles) => {
|
|
|
6811
6811
|
}
|
|
6812
6812
|
const intersection = getSegmentIntersection(p1, p2, o1, o2);
|
|
6813
6813
|
if (intersection) {
|
|
6814
|
-
|
|
6814
|
+
intersections2.push(intersection);
|
|
6815
6815
|
}
|
|
6816
6816
|
}
|
|
6817
6817
|
}
|
|
6818
|
-
return
|
|
6818
|
+
return intersections2;
|
|
6819
6819
|
};
|
|
6820
6820
|
var isSamePoint = (first, second) => Math.abs(first.x - second.x) < EPS9 && Math.abs(first.y - second.y) < EPS9;
|
|
6821
6821
|
var findPerpendicularPathCrossings = (path, otherPath, options = {}) => {
|
|
@@ -12400,6 +12400,22 @@ globalConnNetId: ${label.globalConnNetId}`
|
|
|
12400
12400
|
}
|
|
12401
12401
|
};
|
|
12402
12402
|
|
|
12403
|
+
// lib/solvers/InlineNetLabelSolver/getAnchoredNetLabelRenderedBounds.ts
|
|
12404
|
+
var getAnchoredNetLabelRenderedBounds = (placement) => {
|
|
12405
|
+
if (placement.orientation !== "x-" && placement.orientation !== "x+") {
|
|
12406
|
+
return getRectBounds(placement.center, placement.width, placement.height);
|
|
12407
|
+
}
|
|
12408
|
+
const width = Math.max(placement.width, placement.height);
|
|
12409
|
+
const height = NET_LABEL_HORIZONTAL_HEIGHT;
|
|
12410
|
+
const center = getCenterFromAnchor(
|
|
12411
|
+
placement.anchorPoint,
|
|
12412
|
+
placement.orientation,
|
|
12413
|
+
width,
|
|
12414
|
+
height
|
|
12415
|
+
);
|
|
12416
|
+
return getRectBounds(center, width, height);
|
|
12417
|
+
};
|
|
12418
|
+
|
|
12403
12419
|
// lib/solvers/NetLabelNetLabelCollisionSolver/NetLabelNetLabelCollisionSolver.ts
|
|
12404
12420
|
var ANCHOR_TRACE_CLEARANCE = 1e-4;
|
|
12405
12421
|
var SEGMENT_PARALLEL_EPS = 1e-6;
|
|
@@ -12440,6 +12456,19 @@ function sampleAnchorsAlongSegment(a, b) {
|
|
|
12440
12456
|
return anchors;
|
|
12441
12457
|
}
|
|
12442
12458
|
var NetLabelNetLabelCollisionSolver = class extends BaseSolver {
|
|
12459
|
+
constructor(params) {
|
|
12460
|
+
super();
|
|
12461
|
+
this.params = params;
|
|
12462
|
+
this.inputProblem = params.inputProblem;
|
|
12463
|
+
this.traces = params.traces;
|
|
12464
|
+
this.netLabelPlacements = params.netLabelPlacements;
|
|
12465
|
+
this.outputNetLabelPlacements = [...params.netLabelPlacements];
|
|
12466
|
+
this.chipIndex = params.inputProblem._chipObstacleSpatialIndex ?? (params.inputProblem.chips.length > 0 ? new ChipObstacleSpatialIndex(params.inputProblem.chips) : void 0);
|
|
12467
|
+
this.traceMap = Object.fromEntries(
|
|
12468
|
+
params.traces.map((t) => [t.mspPairId, t])
|
|
12469
|
+
);
|
|
12470
|
+
}
|
|
12471
|
+
params;
|
|
12443
12472
|
inputProblem;
|
|
12444
12473
|
traces;
|
|
12445
12474
|
netLabelPlacements;
|
|
@@ -12453,40 +12482,37 @@ var NetLabelNetLabelCollisionSolver = class extends BaseSolver {
|
|
|
12453
12482
|
labelsToTry = [];
|
|
12454
12483
|
candidateQueue = [];
|
|
12455
12484
|
candidateIndex = 0;
|
|
12456
|
-
constructor(params) {
|
|
12457
|
-
super();
|
|
12458
|
-
this.inputProblem = params.inputProblem;
|
|
12459
|
-
this.traces = params.traces;
|
|
12460
|
-
this.netLabelPlacements = params.netLabelPlacements;
|
|
12461
|
-
this.outputNetLabelPlacements = [...params.netLabelPlacements];
|
|
12462
|
-
this.chipIndex = params.inputProblem._chipObstacleSpatialIndex ?? new ChipObstacleSpatialIndex(params.inputProblem.chips);
|
|
12463
|
-
this.traceMap = Object.fromEntries(
|
|
12464
|
-
params.traces.map((t) => [t.mspPairId, t])
|
|
12465
|
-
);
|
|
12466
|
-
}
|
|
12467
12485
|
getConstructorParams() {
|
|
12468
12486
|
return {
|
|
12469
12487
|
inputProblem: this.inputProblem,
|
|
12470
12488
|
traces: this.traces,
|
|
12471
|
-
netLabelPlacements: this.netLabelPlacements
|
|
12489
|
+
netLabelPlacements: this.netLabelPlacements,
|
|
12490
|
+
fixedNetLabelPlacements: this.params.fixedNetLabelPlacements,
|
|
12491
|
+
useRenderedLabelBounds: this.params.useRenderedLabelBounds
|
|
12472
12492
|
};
|
|
12473
12493
|
}
|
|
12474
12494
|
getOutput() {
|
|
12475
12495
|
return { netLabelPlacements: this.outputNetLabelPlacements };
|
|
12476
12496
|
}
|
|
12477
12497
|
labelBounds(label) {
|
|
12478
|
-
|
|
12498
|
+
if (!this.params.useRenderedLabelBounds || this.params.fixedNetLabelPlacements?.includes(label))
|
|
12499
|
+
return getRectBounds(label.center, label.width, label.height);
|
|
12500
|
+
return getAnchoredNetLabelRenderedBounds(label);
|
|
12479
12501
|
}
|
|
12480
12502
|
collisionKey(a, b) {
|
|
12481
12503
|
return [a.globalConnNetId, b.globalConnNetId].sort().join("::");
|
|
12482
12504
|
}
|
|
12483
12505
|
findNextCollidingPair() {
|
|
12484
|
-
const labels =
|
|
12485
|
-
|
|
12506
|
+
const labels = [
|
|
12507
|
+
...this.outputNetLabelPlacements,
|
|
12508
|
+
...this.params.fixedNetLabelPlacements ?? []
|
|
12509
|
+
];
|
|
12510
|
+
for (let i = 0; i < this.outputNetLabelPlacements.length; i++) {
|
|
12486
12511
|
for (let j = i + 1; j < labels.length; j++) {
|
|
12487
12512
|
const a = labels[i];
|
|
12488
12513
|
const b = labels[j];
|
|
12489
|
-
if (a.globalConnNetId === b.globalConnNetId)
|
|
12514
|
+
if (a.globalConnNetId === b.globalConnNetId && !this.params.fixedNetLabelPlacements?.includes(b))
|
|
12515
|
+
continue;
|
|
12490
12516
|
if (this.skippedCollisionKeys.has(this.collisionKey(a, b))) continue;
|
|
12491
12517
|
if (boundsOverlap2(this.labelBounds(a), this.labelBounds(b)))
|
|
12492
12518
|
return [a, b];
|
|
@@ -12526,7 +12552,14 @@ var NetLabelNetLabelCollisionSolver = class extends BaseSolver {
|
|
|
12526
12552
|
center,
|
|
12527
12553
|
width,
|
|
12528
12554
|
height,
|
|
12529
|
-
bounds:
|
|
12555
|
+
bounds: this.params.useRenderedLabelBounds ? getAnchoredNetLabelRenderedBounds({
|
|
12556
|
+
...label,
|
|
12557
|
+
orientation,
|
|
12558
|
+
anchorPoint: anchor,
|
|
12559
|
+
center,
|
|
12560
|
+
width,
|
|
12561
|
+
height
|
|
12562
|
+
}) : getRectBounds(center, width, height),
|
|
12530
12563
|
hostPairId,
|
|
12531
12564
|
hostSegIndex,
|
|
12532
12565
|
status: null
|
|
@@ -12578,7 +12611,7 @@ var NetLabelNetLabelCollisionSolver = class extends BaseSolver {
|
|
|
12578
12611
|
}
|
|
12579
12612
|
checkCandidate(candidate, movingLabelNetId, obstacleLabels) {
|
|
12580
12613
|
const { bounds, hostPairId, hostSegIndex } = candidate;
|
|
12581
|
-
if (this.chipIndex
|
|
12614
|
+
if ((this.chipIndex?.getChipsInBounds(bounds).length ?? 0) > 0)
|
|
12582
12615
|
return "chip-collision";
|
|
12583
12616
|
if (rectIntersectsAnyTextBox(bounds, this.inputProblem))
|
|
12584
12617
|
return "text-collision";
|
|
@@ -12586,7 +12619,8 @@ var NetLabelNetLabelCollisionSolver = class extends BaseSolver {
|
|
|
12586
12619
|
return "trace-collision";
|
|
12587
12620
|
}
|
|
12588
12621
|
for (const obstacle of obstacleLabels) {
|
|
12589
|
-
if (obstacle.globalConnNetId === movingLabelNetId)
|
|
12622
|
+
if (obstacle.globalConnNetId === movingLabelNetId && !this.params.fixedNetLabelPlacements?.includes(obstacle))
|
|
12623
|
+
continue;
|
|
12590
12624
|
if (boundsOverlap2(bounds, this.labelBounds(obstacle)))
|
|
12591
12625
|
return "label-collision";
|
|
12592
12626
|
}
|
|
@@ -12598,6 +12632,27 @@ var NetLabelNetLabelCollisionSolver = class extends BaseSolver {
|
|
|
12598
12632
|
this.candidateIndex = 0;
|
|
12599
12633
|
this.candidateResults = [];
|
|
12600
12634
|
}
|
|
12635
|
+
/** Reuse the normal anchor search for a local trace-clearance proposal. */
|
|
12636
|
+
getNearbyValidPlacements(label, maxDistance) {
|
|
12637
|
+
const distance7 = (candidate) => Math.hypot(
|
|
12638
|
+
candidate.anchor.x - label.anchorPoint.x,
|
|
12639
|
+
candidate.anchor.y - label.anchorPoint.y
|
|
12640
|
+
);
|
|
12641
|
+
const obstacles = [
|
|
12642
|
+
...this.outputNetLabelPlacements.filter((other) => other !== label),
|
|
12643
|
+
...this.params.fixedNetLabelPlacements ?? []
|
|
12644
|
+
];
|
|
12645
|
+
return this.buildCandidatesForLabel(label).filter(
|
|
12646
|
+
(candidate) => distance7(candidate) <= maxDistance && this.checkCandidate(candidate, label.globalConnNetId, obstacles) === "ok"
|
|
12647
|
+
).sort((a, b) => distance7(a) - distance7(b)).map((candidate) => ({
|
|
12648
|
+
...label,
|
|
12649
|
+
orientation: candidate.orientation,
|
|
12650
|
+
anchorPoint: candidate.anchor,
|
|
12651
|
+
center: candidate.center,
|
|
12652
|
+
width: candidate.width,
|
|
12653
|
+
height: candidate.height
|
|
12654
|
+
}));
|
|
12655
|
+
}
|
|
12601
12656
|
clearActiveSearch() {
|
|
12602
12657
|
this.currentCollision = null;
|
|
12603
12658
|
this.currentLabelToMove = null;
|
|
@@ -12614,7 +12669,9 @@ var NetLabelNetLabelCollisionSolver = class extends BaseSolver {
|
|
|
12614
12669
|
return;
|
|
12615
12670
|
}
|
|
12616
12671
|
this.currentCollision = pair;
|
|
12617
|
-
this.labelsToTry = [pair[1], pair[0]]
|
|
12672
|
+
this.labelsToTry = [pair[1], pair[0]].filter(
|
|
12673
|
+
(label) => !(this.params.fixedNetLabelPlacements ?? []).includes(label)
|
|
12674
|
+
);
|
|
12618
12675
|
this.beginSearchForLabel(this.labelsToTry.shift());
|
|
12619
12676
|
return;
|
|
12620
12677
|
}
|
|
@@ -12638,9 +12695,10 @@ var NetLabelNetLabelCollisionSolver = class extends BaseSolver {
|
|
|
12638
12695
|
fixedLabel = labelB;
|
|
12639
12696
|
}
|
|
12640
12697
|
const obstacleLabels = [
|
|
12641
|
-
...
|
|
12642
|
-
|
|
12643
|
-
|
|
12698
|
+
...[
|
|
12699
|
+
...this.outputNetLabelPlacements,
|
|
12700
|
+
...this.params.fixedNetLabelPlacements ?? []
|
|
12701
|
+
].filter((l) => l !== labelA && l !== labelB),
|
|
12644
12702
|
fixedLabel
|
|
12645
12703
|
];
|
|
12646
12704
|
const status = this.checkCandidate(
|
|
@@ -14084,7 +14142,7 @@ var candidateIsClear = ({
|
|
|
14084
14142
|
}
|
|
14085
14143
|
for (const otherTrace of otherNetTraces) {
|
|
14086
14144
|
const countIntersections = (path) => {
|
|
14087
|
-
const
|
|
14145
|
+
const intersections2 = /* @__PURE__ */ new Set();
|
|
14088
14146
|
for (let i = 1; i < path.length; i++) {
|
|
14089
14147
|
for (let j = 1; j < otherTrace.tracePath.length; j++) {
|
|
14090
14148
|
const point = getSegmentIntersection3(
|
|
@@ -14094,10 +14152,10 @@ var candidateIsClear = ({
|
|
|
14094
14152
|
otherTrace.tracePath[j]
|
|
14095
14153
|
);
|
|
14096
14154
|
if (point)
|
|
14097
|
-
|
|
14155
|
+
intersections2.add(`${point.x.toFixed(6)},${point.y.toFixed(6)}`);
|
|
14098
14156
|
}
|
|
14099
14157
|
}
|
|
14100
|
-
return
|
|
14158
|
+
return intersections2.size;
|
|
14101
14159
|
};
|
|
14102
14160
|
if (countIntersections(candidateTrace.tracePath) > countIntersections(originalTrace.tracePath)) {
|
|
14103
14161
|
return false;
|
|
@@ -15027,6 +15085,422 @@ var TraceElbowTransitionSimplificationSolver = class extends BaseSolver {
|
|
|
15027
15085
|
}
|
|
15028
15086
|
};
|
|
15029
15087
|
|
|
15088
|
+
// lib/solvers/InlineNetLabelSolver/getLocalTraceLabelShifts.ts
|
|
15089
|
+
import { getSegmentIntersection as getSegmentIntersection5 } from "@tscircuit/math-utils/line-intersections";
|
|
15090
|
+
|
|
15091
|
+
// lib/solvers/InlineNetLabelSolver/getInlineLabelObstacles.ts
|
|
15092
|
+
var getInlineTerminalBounds = (label) => {
|
|
15093
|
+
if (!label.stubTracePath) return null;
|
|
15094
|
+
const epsilon = 1e-6;
|
|
15095
|
+
return {
|
|
15096
|
+
minX: Math.min(...label.stubTracePath.map((p) => p.x)) - epsilon,
|
|
15097
|
+
maxX: Math.max(...label.stubTracePath.map((p) => p.x)) + epsilon,
|
|
15098
|
+
minY: Math.min(...label.stubTracePath.map((p) => p.y)) - epsilon,
|
|
15099
|
+
maxY: Math.max(...label.stubTracePath.map((p) => p.y)) + epsilon
|
|
15100
|
+
};
|
|
15101
|
+
};
|
|
15102
|
+
var getInlineLabelObstacles = (inputProblem, placements) => {
|
|
15103
|
+
const fixedLabels = placements.map((label) => ({
|
|
15104
|
+
globalConnNetId: label.globalConnNetId,
|
|
15105
|
+
netId: label.netId,
|
|
15106
|
+
pinIds: label.pinIds,
|
|
15107
|
+
mspConnectionPairIds: [],
|
|
15108
|
+
anchorPoint: label.anchorPoint,
|
|
15109
|
+
orientation: "y+",
|
|
15110
|
+
center: label.center,
|
|
15111
|
+
width: label.axis === "x" ? label.width : label.height,
|
|
15112
|
+
height: label.axis === "x" ? label.height : label.width
|
|
15113
|
+
}));
|
|
15114
|
+
const terminalTraces = placements.flatMap((label) => {
|
|
15115
|
+
if (!label.stubTracePath) return [];
|
|
15116
|
+
const chip = inputProblem.chips.find(
|
|
15117
|
+
(chip2) => chip2.pins.some((pin2) => label.pinIds.includes(pin2.pinId))
|
|
15118
|
+
);
|
|
15119
|
+
const pin = chip?.pins.find((pin2) => label.pinIds.includes(pin2.pinId));
|
|
15120
|
+
if (!chip || !pin) return [];
|
|
15121
|
+
const id = JSON.stringify([
|
|
15122
|
+
"inline-terminal",
|
|
15123
|
+
label.globalConnNetId,
|
|
15124
|
+
[...label.pinIds].sort()
|
|
15125
|
+
]);
|
|
15126
|
+
return [
|
|
15127
|
+
{
|
|
15128
|
+
mspPairId: id,
|
|
15129
|
+
mspConnectionPairIds: [id],
|
|
15130
|
+
globalConnNetId: label.globalConnNetId,
|
|
15131
|
+
dcConnNetId: label.globalConnNetId,
|
|
15132
|
+
pinIds: label.pinIds,
|
|
15133
|
+
pins: [
|
|
15134
|
+
{ ...pin, chipId: chip.chipId },
|
|
15135
|
+
{ ...pin, ...label.stubTracePath[1], chipId: chip.chipId }
|
|
15136
|
+
],
|
|
15137
|
+
tracePath: label.stubTracePath
|
|
15138
|
+
}
|
|
15139
|
+
];
|
|
15140
|
+
});
|
|
15141
|
+
return { fixedLabels, terminalTraces };
|
|
15142
|
+
};
|
|
15143
|
+
|
|
15144
|
+
// lib/solvers/InlineNetLabelSolver/getLocalTraceLabelShifts.ts
|
|
15145
|
+
var EPS15 = 1e-6;
|
|
15146
|
+
var CLEARANCE = 0.05;
|
|
15147
|
+
var hits = (path, bounds) => path.slice(1).some((p, i) => segmentIntersectsRect(path[i], p, bounds));
|
|
15148
|
+
var same = (a, b) => Math.hypot(a.x - b.x, a.y - b.y) < EPS15;
|
|
15149
|
+
var translate = (p, axis, distance7) => ({
|
|
15150
|
+
...p,
|
|
15151
|
+
[axis]: p[axis] + distance7
|
|
15152
|
+
});
|
|
15153
|
+
var intersections = (a, b) => a.slice(1).flatMap(
|
|
15154
|
+
(p, i) => b.slice(1).flatMap((q, j) => {
|
|
15155
|
+
const point = getSegmentIntersection5(a[i], p, b[j], q);
|
|
15156
|
+
return point ? [point] : [];
|
|
15157
|
+
})
|
|
15158
|
+
);
|
|
15159
|
+
function* getLocalTraceLabelShifts(inputProblem, output, pendingInlinePlacements = []) {
|
|
15160
|
+
const placements = [
|
|
15161
|
+
...output.inlineNetLabelPlacements,
|
|
15162
|
+
...pendingInlinePlacements
|
|
15163
|
+
];
|
|
15164
|
+
const { fixedLabels, terminalTraces } = getInlineLabelObstacles(
|
|
15165
|
+
inputProblem,
|
|
15166
|
+
placements
|
|
15167
|
+
);
|
|
15168
|
+
const terminalBounds = placements.flatMap((label) => {
|
|
15169
|
+
const bounds = getInlineTerminalBounds(label);
|
|
15170
|
+
return bounds ? [{ label, bounds }] : [];
|
|
15171
|
+
});
|
|
15172
|
+
const obstacles = [
|
|
15173
|
+
...inputProblem.chips.map((chip) => ({
|
|
15174
|
+
minX: chip.center.x - chip.width / 2,
|
|
15175
|
+
maxX: chip.center.x + chip.width / 2,
|
|
15176
|
+
minY: chip.center.y - chip.height / 2,
|
|
15177
|
+
maxY: chip.center.y + chip.height / 2
|
|
15178
|
+
})),
|
|
15179
|
+
...(inputProblem.textBoxes ?? []).map((box) => getTextBoxBounds(box))
|
|
15180
|
+
];
|
|
15181
|
+
const inlineBounds = fixedLabels.map((label) => ({
|
|
15182
|
+
minX: label.center.x - label.width / 2,
|
|
15183
|
+
maxX: label.center.x + label.width / 2,
|
|
15184
|
+
minY: label.center.y - label.height / 2,
|
|
15185
|
+
maxY: label.center.y + label.height / 2
|
|
15186
|
+
}));
|
|
15187
|
+
const pinPositions = [
|
|
15188
|
+
...inputProblem.chips.flatMap((chip) => chip.pins),
|
|
15189
|
+
...output.traces.flatMap((trace) => trace.pins)
|
|
15190
|
+
];
|
|
15191
|
+
for (const trace of output.traces) {
|
|
15192
|
+
const path = simplifyPath(trace.tracePath);
|
|
15193
|
+
for (let i = 0; i < path.length - 1; i++) {
|
|
15194
|
+
const a = path[i], b = path[i + 1];
|
|
15195
|
+
const axis = Math.abs(a.x - b.x) < EPS15 ? "x" : "y";
|
|
15196
|
+
const along = axis === "x" ? "y" : "x";
|
|
15197
|
+
if (Math.abs(a[axis] - b[axis]) > EPS15 || same(a, b)) continue;
|
|
15198
|
+
const blocking = [
|
|
15199
|
+
...output.netLabelPlacements.filter((label) => label.globalConnNetId !== trace.globalConnNetId).map(getAnchoredNetLabelRenderedBounds),
|
|
15200
|
+
...inlineBounds,
|
|
15201
|
+
...terminalBounds.filter(
|
|
15202
|
+
({ label }) => !trace.pinIds.some((pinId) => label.pinIds.includes(pinId))
|
|
15203
|
+
).map(({ bounds }) => bounds)
|
|
15204
|
+
].filter((bounds) => segmentIntersectsRect(a, b, bounds));
|
|
15205
|
+
if (!blocking.length) continue;
|
|
15206
|
+
let low = Math.min(a[along], b[along]);
|
|
15207
|
+
let high = Math.max(a[along], b[along]);
|
|
15208
|
+
let expanded = true;
|
|
15209
|
+
while (expanded) {
|
|
15210
|
+
expanded = false;
|
|
15211
|
+
for (const other of output.traces) {
|
|
15212
|
+
if (other.globalConnNetId !== trace.globalConnNetId) continue;
|
|
15213
|
+
for (let j = 1; j < other.tracePath.length; j++) {
|
|
15214
|
+
const p = other.tracePath[j - 1], q = other.tracePath[j];
|
|
15215
|
+
if (Math.abs(p[axis] - a[axis]) > EPS15 || Math.abs(q[axis] - a[axis]) > EPS15)
|
|
15216
|
+
continue;
|
|
15217
|
+
const min = Math.min(p[along], q[along]), max = Math.max(p[along], q[along]);
|
|
15218
|
+
if (max < low - EPS15 || min > high + EPS15) continue;
|
|
15219
|
+
if (min < low || max > high) expanded = true;
|
|
15220
|
+
low = Math.min(low, min);
|
|
15221
|
+
high = Math.max(high, max);
|
|
15222
|
+
}
|
|
15223
|
+
}
|
|
15224
|
+
}
|
|
15225
|
+
const onRail = (p) => Math.abs(p[axis] - a[axis]) < EPS15 && p[along] >= low - EPS15 && p[along] <= high + EPS15;
|
|
15226
|
+
if (pinPositions.some(onRail)) continue;
|
|
15227
|
+
const minKey = axis === "x" ? "minX" : "minY";
|
|
15228
|
+
const maxKey = axis === "x" ? "maxX" : "maxY";
|
|
15229
|
+
const localWidth = Math.max(
|
|
15230
|
+
...blocking.map((bounds) => bounds[maxKey] - bounds[minKey])
|
|
15231
|
+
);
|
|
15232
|
+
const railLabelBounds = output.netLabelPlacements.filter(
|
|
15233
|
+
(label) => label.globalConnNetId === trace.globalConnNetId && onRail(label.anchorPoint)
|
|
15234
|
+
).map(getAnchoredNetLabelRenderedBounds);
|
|
15235
|
+
const coordinates = [
|
|
15236
|
+
...new Set(
|
|
15237
|
+
blocking.flatMap((bounds) => [
|
|
15238
|
+
bounds[minKey] - CLEARANCE,
|
|
15239
|
+
bounds[maxKey] + CLEARANCE,
|
|
15240
|
+
...railLabelBounds.filter((own) => boundsOverlap(own, bounds)).flatMap((own) => [
|
|
15241
|
+
a[axis] + bounds[minKey] - CLEARANCE - own[maxKey],
|
|
15242
|
+
a[axis] + bounds[maxKey] + CLEARANCE - own[minKey]
|
|
15243
|
+
])
|
|
15244
|
+
])
|
|
15245
|
+
)
|
|
15246
|
+
].sort((x, y) => Math.abs(x - a[axis]) - Math.abs(y - a[axis]));
|
|
15247
|
+
for (const coordinate of coordinates) {
|
|
15248
|
+
const distance7 = coordinate - a[axis];
|
|
15249
|
+
if (Math.abs(distance7) > localWidth + 2 * CLEARANCE) continue;
|
|
15250
|
+
const traces = output.traces.map((other) => {
|
|
15251
|
+
if (other.globalConnNetId !== trace.globalConnNetId || !other.tracePath.some(onRail))
|
|
15252
|
+
return other;
|
|
15253
|
+
return {
|
|
15254
|
+
...other,
|
|
15255
|
+
tracePath: other.tracePath.map(
|
|
15256
|
+
(p) => onRail(p) ? translate(p, axis, distance7) : p
|
|
15257
|
+
)
|
|
15258
|
+
};
|
|
15259
|
+
});
|
|
15260
|
+
const shiftedPaths = traces.filter((other, index) => other !== output.traces[index]).map((other) => other.tracePath);
|
|
15261
|
+
let labels = output.netLabelPlacements.map((label) => {
|
|
15262
|
+
if (label.globalConnNetId !== trace.globalConnNetId || !onRail(label.anchorPoint))
|
|
15263
|
+
return label;
|
|
15264
|
+
return {
|
|
15265
|
+
...label,
|
|
15266
|
+
anchorPoint: translate(label.anchorPoint, axis, distance7),
|
|
15267
|
+
center: translate(label.center, axis, distance7)
|
|
15268
|
+
};
|
|
15269
|
+
});
|
|
15270
|
+
let blocked = false;
|
|
15271
|
+
const movedOwnLabelBounds = labels.flatMap(
|
|
15272
|
+
(label, index) => label !== output.netLabelPlacements[index] ? [getAnchoredNetLabelRenderedBounds(label)] : []
|
|
15273
|
+
);
|
|
15274
|
+
for (const [labelIndex, label] of labels.entries()) {
|
|
15275
|
+
if (label.globalConnNetId === trace.globalConnNetId) continue;
|
|
15276
|
+
const bounds = getAnchoredNetLabelRenderedBounds(label);
|
|
15277
|
+
const clearanceEdges = movedOwnLabelBounds.filter((own) => boundsOverlap(own, bounds)).map((own) => own[distance7 > 0 ? maxKey : minKey]);
|
|
15278
|
+
if (shiftedPaths.some((p) => hits(p, bounds)) && !output.traces.some(
|
|
15279
|
+
(other) => other.globalConnNetId === trace.globalConnNetId && hits(other.tracePath, bounds)
|
|
15280
|
+
))
|
|
15281
|
+
clearanceEdges.push(coordinate);
|
|
15282
|
+
if (!clearanceEdges.length) continue;
|
|
15283
|
+
const connectorIndex = traces.findIndex(
|
|
15284
|
+
(candidate) => candidate.globalConnNetId === label.globalConnNetId && candidate.pinIds.length === 1 && candidate.tracePath.length === 3 && same(candidate.tracePath.at(-1), label.anchorPoint)
|
|
15285
|
+
);
|
|
15286
|
+
const connector = traces[connectorIndex];
|
|
15287
|
+
if (!connector) {
|
|
15288
|
+
const placementSolver = new NetLabelNetLabelCollisionSolver({
|
|
15289
|
+
inputProblem,
|
|
15290
|
+
traces: [...traces, ...terminalTraces],
|
|
15291
|
+
netLabelPlacements: labels,
|
|
15292
|
+
fixedNetLabelPlacements: fixedLabels,
|
|
15293
|
+
useRenderedLabelBounds: true
|
|
15294
|
+
});
|
|
15295
|
+
const nearby = placementSolver.getNearbyValidPlacements(
|
|
15296
|
+
label,
|
|
15297
|
+
localWidth + Math.max(label.width, label.height)
|
|
15298
|
+
)[0];
|
|
15299
|
+
if (!nearby) {
|
|
15300
|
+
blocked = true;
|
|
15301
|
+
break;
|
|
15302
|
+
}
|
|
15303
|
+
labels[labelIndex] = nearby;
|
|
15304
|
+
continue;
|
|
15305
|
+
}
|
|
15306
|
+
const [start, bend, end] = connector.tracePath;
|
|
15307
|
+
if (Math.abs(bend[axis] - end[axis]) > EPS15 || Math.abs(start[along] - bend[along]) > EPS15) {
|
|
15308
|
+
blocked = true;
|
|
15309
|
+
break;
|
|
15310
|
+
}
|
|
15311
|
+
const delta = distance7 > 0 ? Math.max(...clearanceEdges) + CLEARANCE - bounds[minKey] : Math.min(...clearanceEdges) - CLEARANCE - bounds[maxKey];
|
|
15312
|
+
if (Math.abs(delta) > localWidth + bounds[maxKey] - bounds[minKey] + 2 * CLEARANCE) {
|
|
15313
|
+
blocked = true;
|
|
15314
|
+
break;
|
|
15315
|
+
}
|
|
15316
|
+
const moved = {
|
|
15317
|
+
...label,
|
|
15318
|
+
anchorPoint: translate(label.anchorPoint, axis, delta),
|
|
15319
|
+
center: translate(label.center, axis, delta)
|
|
15320
|
+
};
|
|
15321
|
+
labels[labelIndex] = moved;
|
|
15322
|
+
traces[connectorIndex] = {
|
|
15323
|
+
...connector,
|
|
15324
|
+
tracePath: [start, translate(bend, axis, delta), moved.anchorPoint]
|
|
15325
|
+
};
|
|
15326
|
+
}
|
|
15327
|
+
if (blocked) continue;
|
|
15328
|
+
for (const [index, proposed] of traces.entries()) {
|
|
15329
|
+
const original = output.traces[index];
|
|
15330
|
+
if (proposed === original) continue;
|
|
15331
|
+
const candidate = proposed.tracePath;
|
|
15332
|
+
const previous = original.tracePath;
|
|
15333
|
+
if (candidate.slice(1).some(
|
|
15334
|
+
(p, index2) => Math.abs(p.x - candidate[index2].x) > EPS15 && Math.abs(p.y - candidate[index2].y) > EPS15
|
|
15335
|
+
)) {
|
|
15336
|
+
blocked = true;
|
|
15337
|
+
break;
|
|
15338
|
+
}
|
|
15339
|
+
const dot = (a2, b2, c, d) => (b2.x - a2.x) * (d.x - c.x) + (b2.y - a2.y) * (d.y - c.y);
|
|
15340
|
+
if (dot(previous[0], previous[1], candidate[0], candidate[1]) <= EPS15 || dot(
|
|
15341
|
+
previous.at(-1),
|
|
15342
|
+
previous.at(-2),
|
|
15343
|
+
candidate.at(-1),
|
|
15344
|
+
candidate.at(-2)
|
|
15345
|
+
) <= EPS15) {
|
|
15346
|
+
blocked = true;
|
|
15347
|
+
break;
|
|
15348
|
+
}
|
|
15349
|
+
const junctions = output.traces.filter(
|
|
15350
|
+
(other) => other !== original && other.globalConnNetId === original.globalConnNetId
|
|
15351
|
+
).flatMap((other) => [
|
|
15352
|
+
...other.tracePath,
|
|
15353
|
+
...intersections(previous, other.tracePath)
|
|
15354
|
+
]).filter((p) => tracePathContainsPoint(previous, p)).map(
|
|
15355
|
+
(p) => original.globalConnNetId === trace.globalConnNetId && onRail(p) ? translate(p, axis, distance7) : p
|
|
15356
|
+
);
|
|
15357
|
+
const protectedPoints = [
|
|
15358
|
+
...pinPositions.filter((p) => tracePathContainsPoint(previous, p)),
|
|
15359
|
+
...junctions
|
|
15360
|
+
];
|
|
15361
|
+
if (protectedPoints.some(
|
|
15362
|
+
(p) => !tracePathContainsPoint(candidate, p)
|
|
15363
|
+
) || pinPositions.some((p) => {
|
|
15364
|
+
const clearance = {
|
|
15365
|
+
minX: p.x - CLEARANCE,
|
|
15366
|
+
maxX: p.x + CLEARANCE,
|
|
15367
|
+
minY: p.y - CLEARANCE,
|
|
15368
|
+
maxY: p.y + CLEARANCE
|
|
15369
|
+
};
|
|
15370
|
+
return hits(candidate, clearance) && !hits(previous, clearance);
|
|
15371
|
+
}) || obstacles.some(
|
|
15372
|
+
(bounds) => hits(candidate, bounds) && !hits(previous, bounds)
|
|
15373
|
+
)) {
|
|
15374
|
+
blocked = true;
|
|
15375
|
+
break;
|
|
15376
|
+
}
|
|
15377
|
+
for (const other of [...traces, ...terminalTraces]) {
|
|
15378
|
+
if (other.mspPairId === proposed.mspPairId || other.globalConnNetId === proposed.globalConnNetId)
|
|
15379
|
+
continue;
|
|
15380
|
+
const originalOther = output.traces.find((t) => t.mspPairId === other.mspPairId) ?? other;
|
|
15381
|
+
if (doesPathCoincideWithTraces(candidate, [other]) || intersections(candidate, other.tracePath).length > intersections(previous, originalOther.tracePath).length) {
|
|
15382
|
+
blocked = true;
|
|
15383
|
+
break;
|
|
15384
|
+
}
|
|
15385
|
+
}
|
|
15386
|
+
if (blocked) break;
|
|
15387
|
+
}
|
|
15388
|
+
if (blocked) continue;
|
|
15389
|
+
for (const [index, label] of labels.entries()) {
|
|
15390
|
+
if (label === output.netLabelPlacements[index]) continue;
|
|
15391
|
+
const bounds = getAnchoredNetLabelRenderedBounds(label);
|
|
15392
|
+
if (obstacles.some((obstacle) => boundsOverlap(bounds, obstacle)) || inlineBounds.some((other) => boundsOverlap(bounds, other))) {
|
|
15393
|
+
blocked = true;
|
|
15394
|
+
break;
|
|
15395
|
+
}
|
|
15396
|
+
if (labels.some(
|
|
15397
|
+
(other, j) => index !== j && boundsOverlap(bounds, getAnchoredNetLabelRenderedBounds(other))
|
|
15398
|
+
)) {
|
|
15399
|
+
blocked = true;
|
|
15400
|
+
break;
|
|
15401
|
+
}
|
|
15402
|
+
if ([...traces, ...terminalTraces].some(
|
|
15403
|
+
(other) => other.globalConnNetId !== label.globalConnNetId && hits(other.tracePath, bounds)
|
|
15404
|
+
)) {
|
|
15405
|
+
blocked = true;
|
|
15406
|
+
break;
|
|
15407
|
+
}
|
|
15408
|
+
}
|
|
15409
|
+
if (!blocked) yield { ...output, traces, netLabelPlacements: labels };
|
|
15410
|
+
}
|
|
15411
|
+
}
|
|
15412
|
+
}
|
|
15413
|
+
}
|
|
15414
|
+
|
|
15415
|
+
// lib/solvers/InlineNetLabelSolver/getOutputLabelCollisions.ts
|
|
15416
|
+
var sameLabel = (a, b) => {
|
|
15417
|
+
const first = [...a.pinIds].sort();
|
|
15418
|
+
const second = [...b.pinIds].sort();
|
|
15419
|
+
return a.globalConnNetId === b.globalConnNetId && first.length === second.length && first.every((pinId, index) => pinId === second[index]);
|
|
15420
|
+
};
|
|
15421
|
+
var sameOutputLabelCollision = (a, b) => {
|
|
15422
|
+
if (a.kind === "label-label" && b.kind === "label-label")
|
|
15423
|
+
return sameLabel(a.labels[0], b.labels[0]) && sameLabel(a.labels[1], b.labels[1]) || sameLabel(a.labels[0], b.labels[1]) && sameLabel(a.labels[1], b.labels[0]);
|
|
15424
|
+
if (a.kind !== "trace-label" || b.kind !== "trace-label") return false;
|
|
15425
|
+
const sameTrace = a.trace.kind === "routed" && b.trace.kind === "routed" ? a.trace.id === b.trace.id : a.trace.kind === "terminal" && b.trace.kind === "terminal" && sameLabel(a.trace.label, b.trace.label);
|
|
15426
|
+
return sameTrace && a.target === b.target && sameLabel(a.label, b.label);
|
|
15427
|
+
};
|
|
15428
|
+
var getOutputLabelCollisions = (output) => {
|
|
15429
|
+
const labels = [
|
|
15430
|
+
...output.netLabelPlacements,
|
|
15431
|
+
...output.inlineNetLabelPlacements
|
|
15432
|
+
].map((label) => ({
|
|
15433
|
+
label,
|
|
15434
|
+
bounds: "axis" in label ? {
|
|
15435
|
+
minX: label.center.x - (label.axis === "x" ? label.width : label.height) / 2,
|
|
15436
|
+
maxX: label.center.x + (label.axis === "x" ? label.width : label.height) / 2,
|
|
15437
|
+
minY: label.center.y - (label.axis === "x" ? label.height : label.width) / 2,
|
|
15438
|
+
maxY: label.center.y + (label.axis === "x" ? label.height : label.width) / 2
|
|
15439
|
+
} : getAnchoredNetLabelRenderedBounds(label)
|
|
15440
|
+
}));
|
|
15441
|
+
const collisions = [];
|
|
15442
|
+
const add = (collision) => {
|
|
15443
|
+
if (!collisions.some((other) => sameOutputLabelCollision(collision, other)))
|
|
15444
|
+
collisions.push(collision);
|
|
15445
|
+
};
|
|
15446
|
+
for (let i = 0; i < labels.length; i++)
|
|
15447
|
+
for (const other of labels.slice(i + 1)) {
|
|
15448
|
+
if (boundsOverlap(labels[i].bounds, other.bounds))
|
|
15449
|
+
add({ kind: "label-label", labels: [labels[i].label, other.label] });
|
|
15450
|
+
}
|
|
15451
|
+
const traces = [
|
|
15452
|
+
...output.traces.map((trace) => ({
|
|
15453
|
+
...trace,
|
|
15454
|
+
identity: { kind: "routed", id: trace.mspPairId }
|
|
15455
|
+
})),
|
|
15456
|
+
...output.inlineNetLabelPlacements.flatMap(
|
|
15457
|
+
(label) => label.stubTracePath ? [
|
|
15458
|
+
{
|
|
15459
|
+
identity: { kind: "terminal", label },
|
|
15460
|
+
globalConnNetId: label.globalConnNetId,
|
|
15461
|
+
tracePath: label.stubTracePath
|
|
15462
|
+
}
|
|
15463
|
+
] : []
|
|
15464
|
+
)
|
|
15465
|
+
];
|
|
15466
|
+
for (const trace of traces)
|
|
15467
|
+
for (const { label, bounds } of labels) {
|
|
15468
|
+
if (("axis" in label || label.globalConnNetId !== trace.globalConnNetId) && trace.tracePath.slice(1).some(
|
|
15469
|
+
(end, index) => segmentIntersectsRect(trace.tracePath[index], end, bounds)
|
|
15470
|
+
))
|
|
15471
|
+
add({
|
|
15472
|
+
kind: "trace-label",
|
|
15473
|
+
trace: trace.identity,
|
|
15474
|
+
label,
|
|
15475
|
+
target: "text"
|
|
15476
|
+
});
|
|
15477
|
+
}
|
|
15478
|
+
for (const label of output.inlineNetLabelPlacements) {
|
|
15479
|
+
const bounds = getInlineTerminalBounds(label);
|
|
15480
|
+
if (!bounds) continue;
|
|
15481
|
+
for (const trace of output.traces) {
|
|
15482
|
+
if (trace.pinIds.some((pinId) => label.pinIds.includes(pinId))) continue;
|
|
15483
|
+
if (trace.tracePath.slice(1).some(
|
|
15484
|
+
(end, index) => segmentIntersectsRect(trace.tracePath[index], end, bounds)
|
|
15485
|
+
))
|
|
15486
|
+
add({
|
|
15487
|
+
kind: "trace-label",
|
|
15488
|
+
trace: { kind: "routed", id: trace.mspPairId },
|
|
15489
|
+
label,
|
|
15490
|
+
target: "terminal"
|
|
15491
|
+
});
|
|
15492
|
+
}
|
|
15493
|
+
}
|
|
15494
|
+
return collisions;
|
|
15495
|
+
};
|
|
15496
|
+
|
|
15497
|
+
// lib/solvers/InlineNetLabelSolver/isLabelRepresentedInline.ts
|
|
15498
|
+
var isLabelRepresentedInline = (label, inlinePlacements) => label.pinIds.length > 0 && label.pinIds.every(
|
|
15499
|
+
(pinId) => inlinePlacements.some(
|
|
15500
|
+
(inline) => inline.globalConnNetId === label.globalConnNetId && inline.pinIds.includes(pinId)
|
|
15501
|
+
)
|
|
15502
|
+
);
|
|
15503
|
+
|
|
15030
15504
|
// lib/solvers/InlineNetLabelSolver/alignPortOnlyInlineNetLabelStubs.ts
|
|
15031
15505
|
var getStubDirection = (path) => {
|
|
15032
15506
|
const [start, end] = path;
|
|
@@ -15102,12 +15576,7 @@ var alignPortOnlyInlineNetLabelStubs = ({
|
|
|
15102
15576
|
groups.set(groupKey, group);
|
|
15103
15577
|
}
|
|
15104
15578
|
const alignedPlacements = [...placements];
|
|
15105
|
-
const
|
|
15106
|
-
placements.map((placement) => placement.globalConnNetId)
|
|
15107
|
-
);
|
|
15108
|
-
const retainedAnchoredLabelBounds = netLabelPlacements.filter(
|
|
15109
|
-
(placement) => !supersededGlobalNetIds.has(placement.globalConnNetId)
|
|
15110
|
-
).map(getLabelBounds2);
|
|
15579
|
+
const retainedAnchoredLabelBounds = netLabelPlacements.filter((placement) => !isLabelRepresentedInline(placement, placements)).map(getLabelBounds2);
|
|
15111
15580
|
for (const group of groups.values()) {
|
|
15112
15581
|
if (group.length < 2) continue;
|
|
15113
15582
|
const targetLength = Math.max(
|
|
@@ -15216,22 +15685,6 @@ var getAxisAlignedSegments2 = (path, epsilon = 1e-6) => {
|
|
|
15216
15685
|
return segments.sort((a, b) => b.length - a.length);
|
|
15217
15686
|
};
|
|
15218
15687
|
|
|
15219
|
-
// lib/solvers/InlineNetLabelSolver/getAnchoredNetLabelRenderedBounds.ts
|
|
15220
|
-
var getAnchoredNetLabelRenderedBounds = (placement) => {
|
|
15221
|
-
if (placement.orientation !== "x-" && placement.orientation !== "x+") {
|
|
15222
|
-
return getRectBounds(placement.center, placement.width, placement.height);
|
|
15223
|
-
}
|
|
15224
|
-
const width = Math.max(placement.width, placement.height);
|
|
15225
|
-
const height = NET_LABEL_HORIZONTAL_HEIGHT;
|
|
15226
|
-
const center = getCenterFromAnchor(
|
|
15227
|
-
placement.anchorPoint,
|
|
15228
|
-
placement.orientation,
|
|
15229
|
-
width,
|
|
15230
|
-
height
|
|
15231
|
-
);
|
|
15232
|
-
return getRectBounds(center, width, height);
|
|
15233
|
-
};
|
|
15234
|
-
|
|
15235
15688
|
// lib/solvers/InlineNetLabelSolver/pushAnchoredNetLabelsAwayFromInlineLabels.ts
|
|
15236
15689
|
var LABEL_CLEARANCE2 = 0.05;
|
|
15237
15690
|
var POINT_EPSILON = 1e-6;
|
|
@@ -15279,29 +15732,37 @@ var isPointOnPath2 = (point, path) => {
|
|
|
15279
15732
|
return false;
|
|
15280
15733
|
};
|
|
15281
15734
|
var getRequiredOutwardDistance = (label, inlineBounds) => {
|
|
15282
|
-
|
|
15283
|
-
|
|
15284
|
-
const
|
|
15285
|
-
(
|
|
15735
|
+
let distance7 = 0;
|
|
15736
|
+
for (let iteration = 0; iteration < inlineBounds.length; iteration++) {
|
|
15737
|
+
const labelBounds = getAnchoredNetLabelRenderedBounds(
|
|
15738
|
+
moveLabel(label, label.orientation, distance7)
|
|
15739
|
+
);
|
|
15740
|
+
const horizontal = label.orientation === "x-" || label.orientation === "x+";
|
|
15741
|
+
const overlapping = inlineBounds.filter(
|
|
15742
|
+
(bounds) => boundsOverlap(labelBounds, {
|
|
15743
|
+
minX: bounds.minX - (horizontal ? LABEL_CLEARANCE2 : 0),
|
|
15744
|
+
maxX: bounds.maxX + (horizontal ? LABEL_CLEARANCE2 : 0),
|
|
15745
|
+
minY: bounds.minY - (horizontal ? 0 : LABEL_CLEARANCE2),
|
|
15746
|
+
maxY: bounds.maxY + (horizontal ? 0 : LABEL_CLEARANCE2)
|
|
15747
|
+
})
|
|
15286
15748
|
);
|
|
15287
|
-
if (
|
|
15288
|
-
|
|
15289
|
-
|
|
15290
|
-
|
|
15749
|
+
if (overlapping.length === 0) break;
|
|
15750
|
+
switch (label.orientation) {
|
|
15751
|
+
case "x-":
|
|
15752
|
+
distance7 += labelBounds.maxX - Math.min(...overlapping.map((b) => b.minX)) + LABEL_CLEARANCE2;
|
|
15753
|
+
break;
|
|
15754
|
+
case "x+":
|
|
15755
|
+
distance7 += Math.max(...overlapping.map((b) => b.maxX)) - labelBounds.minX + LABEL_CLEARANCE2;
|
|
15756
|
+
break;
|
|
15757
|
+
case "y-":
|
|
15758
|
+
distance7 += labelBounds.maxY - Math.min(...overlapping.map((b) => b.minY)) + LABEL_CLEARANCE2;
|
|
15759
|
+
break;
|
|
15760
|
+
case "y+":
|
|
15761
|
+
distance7 += Math.max(...overlapping.map((b) => b.maxY)) - labelBounds.minY + LABEL_CLEARANCE2;
|
|
15762
|
+
break;
|
|
15291
15763
|
}
|
|
15292
|
-
const targetMinX = Math.max(...nearby2.map((bounds) => bounds.maxX));
|
|
15293
|
-
return Math.max(0, targetMinX - labelBounds.minX + LABEL_CLEARANCE2);
|
|
15294
|
-
}
|
|
15295
|
-
const nearby = inlineBounds.filter(
|
|
15296
|
-
(bounds) => labelBounds.minX < bounds.maxX && labelBounds.maxX > bounds.minX
|
|
15297
|
-
);
|
|
15298
|
-
if (nearby.length === 0) return 0;
|
|
15299
|
-
if (label.orientation === "y-") {
|
|
15300
|
-
const targetMaxY = Math.min(...nearby.map((bounds) => bounds.minY));
|
|
15301
|
-
return Math.max(0, labelBounds.maxY - targetMaxY + LABEL_CLEARANCE2);
|
|
15302
15764
|
}
|
|
15303
|
-
|
|
15304
|
-
return Math.max(0, targetMinY - labelBounds.minY + LABEL_CLEARANCE2);
|
|
15765
|
+
return distance7;
|
|
15305
15766
|
};
|
|
15306
15767
|
var moveLabel = (label, orientation, distance7) => {
|
|
15307
15768
|
const direction = dir(orientation);
|
|
@@ -15336,10 +15797,9 @@ var boundsGapOnPerpendicularAxis = (a, b, orientation) => {
|
|
|
15336
15797
|
return Math.max(0, a.minX - b.maxX, b.minX - a.maxX);
|
|
15337
15798
|
};
|
|
15338
15799
|
var sharesOwnerChip = (label, ownerChipIds, chipIdByPinId) => label.pinIds.some((pinId) => ownerChipIds.has(chipIdByPinId.get(pinId) ?? ""));
|
|
15339
|
-
var
|
|
15340
|
-
var findConnectorTraceIndex = (label, traces) => traces.findIndex((trace) => {
|
|
15800
|
+
var findConnectorTraceIndex = (label, traces, connectorTraceIds) => traces.findIndex((trace) => {
|
|
15341
15801
|
if (trace.globalConnNetId !== label.globalConnNetId) return false;
|
|
15342
|
-
if (!
|
|
15802
|
+
if (!connectorTraceIds.has(trace.mspPairId)) return false;
|
|
15343
15803
|
const first = trace.tracePath[0];
|
|
15344
15804
|
const last = trace.tracePath.at(-1);
|
|
15345
15805
|
return Boolean(
|
|
@@ -15422,8 +15882,10 @@ var pushAnchoredNetLabelsAwayFromInlineLabels = ({
|
|
|
15422
15882
|
inputProblem,
|
|
15423
15883
|
traces,
|
|
15424
15884
|
netLabelPlacements,
|
|
15425
|
-
inlineNetLabelPlacements
|
|
15885
|
+
inlineNetLabelPlacements,
|
|
15886
|
+
netLabelConnectorTraceIds = /* @__PURE__ */ new Set()
|
|
15426
15887
|
}) => {
|
|
15888
|
+
const connectorTraceIds = new Set(netLabelConnectorTraceIds);
|
|
15427
15889
|
const outputTraces = traces.map((trace) => ({
|
|
15428
15890
|
...trace,
|
|
15429
15891
|
tracePath: trace.tracePath.map((point) => ({ ...point }))
|
|
@@ -15467,7 +15929,11 @@ var pushAnchoredNetLabelsAwayFromInlineLabels = ({
|
|
|
15467
15929
|
moveLabel(obstacle, trigger.orientation, existingObstacleDistance)
|
|
15468
15930
|
);
|
|
15469
15931
|
if (!boundsOverlap(movingBounds, obstacleBounds)) continue;
|
|
15470
|
-
if (!sharesOwnerChip(obstacle, ownerChipIds, chipIdByPinId) || findConnectorTraceIndex(
|
|
15932
|
+
if (!sharesOwnerChip(obstacle, ownerChipIds, chipIdByPinId) || findConnectorTraceIndex(
|
|
15933
|
+
obstacle,
|
|
15934
|
+
outputTraces,
|
|
15935
|
+
connectorTraceIds
|
|
15936
|
+
) === -1 && !canAddConnectorAtAnchor(obstacle, outputTraces, pinMap)) {
|
|
15471
15937
|
failed = true;
|
|
15472
15938
|
break;
|
|
15473
15939
|
}
|
|
@@ -15539,7 +16005,11 @@ var pushAnchoredNetLabelsAwayFromInlineLabels = ({
|
|
|
15539
16005
|
const connectorUpdates = [];
|
|
15540
16006
|
for (const [labelIndex, movedLabel] of proposals) {
|
|
15541
16007
|
const label = outputLabels[labelIndex];
|
|
15542
|
-
const connectorIndex = findConnectorTraceIndex(
|
|
16008
|
+
const connectorIndex = findConnectorTraceIndex(
|
|
16009
|
+
label,
|
|
16010
|
+
outputTraces,
|
|
16011
|
+
connectorTraceIds
|
|
16012
|
+
);
|
|
15543
16013
|
if (connectorIndex === -1 && !canAddConnectorAtAnchor(label, outputTraces, pinMap)) {
|
|
15544
16014
|
failed = true;
|
|
15545
16015
|
break;
|
|
@@ -15589,6 +16059,7 @@ var pushAnchoredNetLabelsAwayFromInlineLabels = ({
|
|
|
15589
16059
|
movedLabelIndices.add(labelIndex);
|
|
15590
16060
|
}
|
|
15591
16061
|
for (const update of connectorUpdates) {
|
|
16062
|
+
connectorTraceIds.add(update.trace.mspPairId);
|
|
15592
16063
|
if (update.connectorIndex === -1) outputTraces.push(update.trace);
|
|
15593
16064
|
else outputTraces[update.connectorIndex] = update.trace;
|
|
15594
16065
|
}
|
|
@@ -15596,7 +16067,8 @@ var pushAnchoredNetLabelsAwayFromInlineLabels = ({
|
|
|
15596
16067
|
return {
|
|
15597
16068
|
traces: outputTraces,
|
|
15598
16069
|
netLabelPlacements: outputLabels,
|
|
15599
|
-
movedLabelCount: movedLabelIndices.size
|
|
16070
|
+
movedLabelCount: movedLabelIndices.size,
|
|
16071
|
+
netLabelConnectorTraceIds: connectorTraceIds
|
|
15600
16072
|
};
|
|
15601
16073
|
};
|
|
15602
16074
|
|
|
@@ -15798,7 +16270,7 @@ var pushInlineTerminalLabelsAwayFromAnchoredLabels = ({
|
|
|
15798
16270
|
};
|
|
15799
16271
|
|
|
15800
16272
|
// lib/solvers/InlineNetLabelSolver/restoreReroutesAroundSupersededLabels.ts
|
|
15801
|
-
import { getSegmentIntersection as
|
|
16273
|
+
import { getSegmentIntersection as getSegmentIntersection6 } from "@tscircuit/math-utils/line-intersections";
|
|
15802
16274
|
|
|
15803
16275
|
// lib/utils/pathIntersectsRenderedLabel.ts
|
|
15804
16276
|
import {
|
|
@@ -15826,31 +16298,31 @@ var pathIntersectsRenderedLabel = (path, label) => {
|
|
|
15826
16298
|
};
|
|
15827
16299
|
|
|
15828
16300
|
// lib/solvers/InlineNetLabelSolver/restoreReroutesAroundSupersededLabels.ts
|
|
15829
|
-
var
|
|
16301
|
+
var EPS16 = 1e-6;
|
|
15830
16302
|
var getPathLength7 = (path) => path.slice(1).reduce((length, point, pointIndex) => {
|
|
15831
16303
|
const previousPoint = path[pointIndex];
|
|
15832
16304
|
return length + Math.abs(point.x - previousPoint.x) + Math.abs(point.y - previousPoint.y);
|
|
15833
16305
|
}, 0);
|
|
15834
16306
|
var pathsEqual = (first, second) => first.length === second.length && first.every(
|
|
15835
|
-
(point, index) => Math.abs(point.x - second[index].x) <=
|
|
16307
|
+
(point, index) => Math.abs(point.x - second[index].x) <= EPS16 && Math.abs(point.y - second[index].y) <= EPS16
|
|
15836
16308
|
);
|
|
15837
|
-
var isStrictlySimpler = (candidate, current) => candidate.length < current.length && getPathLength7(candidate) <= getPathLength7(current) +
|
|
16309
|
+
var isStrictlySimpler = (candidate, current) => candidate.length < current.length && getPathLength7(candidate) <= getPathLength7(current) + EPS16;
|
|
15838
16310
|
var getIntersectionKeys = (path, otherPath) => {
|
|
15839
|
-
const
|
|
16311
|
+
const intersections2 = /* @__PURE__ */ new Set();
|
|
15840
16312
|
for (let pathIndex = 0; pathIndex < path.length - 1; pathIndex++) {
|
|
15841
16313
|
for (let otherPathIndex = 0; otherPathIndex < otherPath.length - 1; otherPathIndex++) {
|
|
15842
|
-
const point =
|
|
16314
|
+
const point = getSegmentIntersection6(
|
|
15843
16315
|
path[pathIndex],
|
|
15844
16316
|
path[pathIndex + 1],
|
|
15845
16317
|
otherPath[otherPathIndex],
|
|
15846
16318
|
otherPath[otherPathIndex + 1]
|
|
15847
16319
|
);
|
|
15848
16320
|
if (point) {
|
|
15849
|
-
|
|
16321
|
+
intersections2.add(`${point.x.toFixed(6)},${point.y.toFixed(6)}`);
|
|
15850
16322
|
}
|
|
15851
16323
|
}
|
|
15852
16324
|
}
|
|
15853
|
-
return
|
|
16325
|
+
return intersections2;
|
|
15854
16326
|
};
|
|
15855
16327
|
var introducesNewCrossings = (candidatePath, currentPath, otherPaths) => otherPaths.some((otherPath) => {
|
|
15856
16328
|
const currentIntersections = getIntersectionKeys(currentPath, otherPath);
|
|
@@ -15927,9 +16399,7 @@ var DEFAULT_INLINE_NET_LABEL_HEIGHT = 0.18;
|
|
|
15927
16399
|
var INLINE_NET_LABEL_TRACE_MARGIN = 0.05;
|
|
15928
16400
|
var INLINE_NET_LABEL_STUB_TRACE_CLEARANCE = 0.05;
|
|
15929
16401
|
var INLINE_NET_LABEL_MAX_SPAN_JOG = 0.4;
|
|
15930
|
-
var
|
|
15931
|
-
var isGeneratedAnchoredLabelConnector = (trace) => trace.mspPairId.startsWith(AVAILABLE_NET_ORIENTATION_TRACE_PREFIX);
|
|
15932
|
-
var getPinPairKey2 = (pinIds) => [...pinIds].sort().join("::");
|
|
16402
|
+
var getPinPairKey2 = (pinIds) => JSON.stringify([...pinIds].sort());
|
|
15933
16403
|
var getTraceLength2 = (trace) => {
|
|
15934
16404
|
let length = 0;
|
|
15935
16405
|
for (let index = 0; index < trace.tracePath.length - 1; index++) {
|
|
@@ -15950,21 +16420,26 @@ var getInlinePlacementBounds = (placement) => {
|
|
|
15950
16420
|
maxY: placement.center.y + renderedHeight / 2
|
|
15951
16421
|
};
|
|
15952
16422
|
};
|
|
15953
|
-
var
|
|
15954
|
-
|
|
15955
|
-
|
|
15956
|
-
|
|
15957
|
-
|
|
15958
|
-
|
|
15959
|
-
|
|
15960
|
-
|
|
15961
|
-
|
|
15962
|
-
|
|
15963
|
-
|
|
15964
|
-
|
|
15965
|
-
|
|
16423
|
+
var getInlinePlacementKey = (placement) => JSON.stringify([
|
|
16424
|
+
placement.globalConnNetId,
|
|
16425
|
+
[...placement.pinIds].sort(),
|
|
16426
|
+
placement.mspPairId ?? null
|
|
16427
|
+
]);
|
|
16428
|
+
var terminalStubIntersectsTrace = (path, trace) => {
|
|
16429
|
+
const clearance = INLINE_NET_LABEL_STUB_TRACE_CLEARANCE - GEOMETRY_EPSILON;
|
|
16430
|
+
const bounds = {
|
|
16431
|
+
minX: Math.min(path[0].x, path[1].x) - clearance,
|
|
16432
|
+
maxX: Math.max(path[0].x, path[1].x) + clearance,
|
|
16433
|
+
minY: Math.min(path[0].y, path[1].y) - clearance,
|
|
16434
|
+
maxY: Math.max(path[0].y, path[1].y) + clearance
|
|
16435
|
+
};
|
|
16436
|
+
return doesPathIntersectBounds3(trace.tracePath, bounds);
|
|
16437
|
+
};
|
|
16438
|
+
var InlineNetLabelSolver = class _InlineNetLabelSolver extends BaseSolver {
|
|
15966
16439
|
constructor(input) {
|
|
15967
16440
|
super();
|
|
16441
|
+
this.input = input;
|
|
16442
|
+
this.netLabelConnectorTraceIds = input.netLabelConnectorTraceIds ?? /* @__PURE__ */ new Set();
|
|
15968
16443
|
this.inputProblem = input.inputProblem;
|
|
15969
16444
|
this.traces = input.traces;
|
|
15970
16445
|
this.inputNetLabelPlacements = input.netLabelPlacements;
|
|
@@ -15974,7 +16449,11 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
15974
16449
|
).netConnMap;
|
|
15975
16450
|
this.queuedConnections = [
|
|
15976
16451
|
...this.inputProblem.directConnections.filter(
|
|
15977
|
-
(connection) => connection.allowInlineNetLabel && connection.netId
|
|
16452
|
+
(connection) => connection.allowInlineNetLabel && connection.netId && // An opted-in named net owns all of its connected components.
|
|
16453
|
+
// Do not plan the same pair again through its direct connection.
|
|
16454
|
+
!this.inputProblem.netConnections.some(
|
|
16455
|
+
(net) => net.allowInlineNetLabel && net.netId && connection.pinIds.every((pin) => net.pinIds.includes(pin))
|
|
16456
|
+
)
|
|
15978
16457
|
).map((connection) => ({
|
|
15979
16458
|
kind: "direct_connection",
|
|
15980
16459
|
connection
|
|
@@ -15988,7 +16467,7 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
15988
16467
|
];
|
|
15989
16468
|
this.tracesByPinPairKey = /* @__PURE__ */ new Map();
|
|
15990
16469
|
for (const trace of this.traces) {
|
|
15991
|
-
if (
|
|
16470
|
+
if (this.netLabelConnectorTraceIds.has(trace.mspPairId)) continue;
|
|
15992
16471
|
const key = getPinPairKey2(trace.pins.map((p) => p.pinId));
|
|
15993
16472
|
const existing = this.tracesByPinPairKey.get(key);
|
|
15994
16473
|
if (existing) {
|
|
@@ -15998,13 +16477,32 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
15998
16477
|
}
|
|
15999
16478
|
}
|
|
16000
16479
|
}
|
|
16480
|
+
input;
|
|
16481
|
+
inputProblem;
|
|
16482
|
+
traces;
|
|
16483
|
+
inputNetLabelPlacements;
|
|
16484
|
+
completedReroutes;
|
|
16485
|
+
inlineNetLabelPlacements = [];
|
|
16486
|
+
/** Eligible connections still waiting to be processed. */
|
|
16487
|
+
queuedConnections;
|
|
16488
|
+
netLabelConnectorTraceIds;
|
|
16489
|
+
tracesByPinPairKey;
|
|
16490
|
+
globalConnMap;
|
|
16491
|
+
inlineConversions = [];
|
|
16492
|
+
hasAlignedPortOnlyStubs = false;
|
|
16493
|
+
postProcessedOutput;
|
|
16494
|
+
refinementComplete = false;
|
|
16495
|
+
refinement;
|
|
16496
|
+
currentProposal;
|
|
16001
16497
|
getConstructorParams() {
|
|
16002
16498
|
return [
|
|
16003
16499
|
{
|
|
16004
16500
|
inputProblem: this.inputProblem,
|
|
16005
16501
|
traces: this.traces,
|
|
16006
16502
|
netLabelPlacements: this.inputNetLabelPlacements,
|
|
16007
|
-
completedReroutes: this.completedReroutes
|
|
16503
|
+
completedReroutes: this.completedReroutes,
|
|
16504
|
+
resolveTraceCollisions: this.input.resolveTraceCollisions,
|
|
16505
|
+
netLabelConnectorTraceIds: this.netLabelConnectorTraceIds
|
|
16008
16506
|
}
|
|
16009
16507
|
];
|
|
16010
16508
|
}
|
|
@@ -16025,16 +16523,7 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
16025
16523
|
netConnections
|
|
16026
16524
|
)) {
|
|
16027
16525
|
this.inlineNetLabelPlacements.push(...conversion.placements);
|
|
16028
|
-
|
|
16029
|
-
conversion.globalConnNetId
|
|
16030
|
-
) ?? /* @__PURE__ */ new Set();
|
|
16031
|
-
for (const traceId of conversion.supersededTraceIds) {
|
|
16032
|
-
supersededTraceIds.add(traceId);
|
|
16033
|
-
}
|
|
16034
|
-
this.supersededTraceIdsByGlobalConnNetId.set(
|
|
16035
|
-
conversion.globalConnNetId,
|
|
16036
|
-
supersededTraceIds
|
|
16037
|
-
);
|
|
16526
|
+
this.inlineConversions.push(conversion);
|
|
16038
16527
|
}
|
|
16039
16528
|
return;
|
|
16040
16529
|
}
|
|
@@ -16048,11 +16537,12 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
16048
16537
|
});
|
|
16049
16538
|
if (placement) this.inlineNetLabelPlacements.push(placement);
|
|
16050
16539
|
} else {
|
|
16051
|
-
const
|
|
16052
|
-
|
|
16053
|
-
|
|
16054
|
-
|
|
16055
|
-
|
|
16540
|
+
for (const pinId of connection.pinIds) {
|
|
16541
|
+
const placement = this.computeTerminalInlinePlacement(
|
|
16542
|
+
connection,
|
|
16543
|
+
pinId
|
|
16544
|
+
);
|
|
16545
|
+
if (placement) this.inlineNetLabelPlacements.push(placement);
|
|
16056
16546
|
}
|
|
16057
16547
|
}
|
|
16058
16548
|
return;
|
|
@@ -16071,13 +16561,17 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
16071
16561
|
this.postProcessedOutput = this.buildPostProcessedOutput();
|
|
16072
16562
|
return;
|
|
16073
16563
|
}
|
|
16564
|
+
if (this.input.resolveTraceCollisions && !this.refinementComplete) {
|
|
16565
|
+
this.stepTraceRefinement();
|
|
16566
|
+
return;
|
|
16567
|
+
}
|
|
16074
16568
|
this.solved = true;
|
|
16075
16569
|
this.stats.inlineNetLabelCount = this.inlineNetLabelPlacements.length;
|
|
16076
16570
|
}
|
|
16077
16571
|
/**
|
|
16078
16572
|
* Plans all opted-in multi-pin nets together. Short routed components can
|
|
16079
16573
|
* mutually block the outward endpoint stubs that replace them, so tentative
|
|
16080
|
-
* replacements are ignored as obstacles only while their
|
|
16574
|
+
* replacements are ignored as obstacles only while their connected component still
|
|
16081
16575
|
* converts successfully. Failed conversions retain both their traces and
|
|
16082
16576
|
* their conventional labels, and the remaining conversions are retried.
|
|
16083
16577
|
*/
|
|
@@ -16118,13 +16612,11 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
16118
16612
|
}));
|
|
16119
16613
|
const nextIgnoredTraceIds = new Set(
|
|
16120
16614
|
conversions.flatMap(
|
|
16121
|
-
({ conversion }) => conversion
|
|
16615
|
+
({ conversion }) => conversion.flatMap((component) => [...component.supersededTraceIds])
|
|
16122
16616
|
)
|
|
16123
16617
|
);
|
|
16124
16618
|
if (setsEqual(ignoredTraceIds, nextIgnoredTraceIds)) {
|
|
16125
|
-
return conversions.flatMap(
|
|
16126
|
-
({ conversion }) => conversion ? [conversion] : []
|
|
16127
|
-
);
|
|
16619
|
+
return conversions.flatMap(({ conversion }) => conversion);
|
|
16128
16620
|
}
|
|
16129
16621
|
ignoredTraceIds = nextIgnoredTraceIds;
|
|
16130
16622
|
}
|
|
@@ -16154,7 +16646,7 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
16154
16646
|
// anchored label. They are removed when that label becomes inline, so
|
|
16155
16647
|
// treating them as routed circuitry would leave text on a deleted wire.
|
|
16156
16648
|
traces: this.traces.filter(
|
|
16157
|
-
(trace) => !
|
|
16649
|
+
(trace) => !this.netLabelConnectorTraceIds.has(trace.mspPairId)
|
|
16158
16650
|
)
|
|
16159
16651
|
}).map((component) => ({
|
|
16160
16652
|
pinIds: component.pinIds,
|
|
@@ -16180,14 +16672,14 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
16180
16672
|
* Converts every conventional label representation for an opted-in named
|
|
16181
16673
|
* net. Routed connected components become labels on their representative
|
|
16182
16674
|
* trace; disconnected pins become outward terminal stubs. The conversion is
|
|
16183
|
-
* atomic
|
|
16675
|
+
* atomic within each routed component, so replacing its traces cannot strand
|
|
16676
|
+
* a pin. Disconnected components can keep their own label style.
|
|
16184
16677
|
*/
|
|
16185
16678
|
computeNetConnectionInlinePlacements(connection, ignoredTraceIds, forcedTerminalTraceIds) {
|
|
16186
16679
|
const components = this.getNetConnectionComponents(connection);
|
|
16187
16680
|
const globalConnNetId = this.getGlobalConnNetId(connection);
|
|
16188
|
-
if (!globalConnNetId) return
|
|
16189
|
-
const
|
|
16190
|
-
const supersededTraceIds = /* @__PURE__ */ new Set();
|
|
16681
|
+
if (!globalConnNetId) return [];
|
|
16682
|
+
const conversions = [];
|
|
16191
16683
|
for (const component of components) {
|
|
16192
16684
|
const shouldUseTerminalStubs = component.traces.some(
|
|
16193
16685
|
(trace) => forcedTerminalTraceIds.has(trace.mspPairId)
|
|
@@ -16205,14 +16697,18 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
16205
16697
|
}
|
|
16206
16698
|
}
|
|
16207
16699
|
if (inlinePlacement) {
|
|
16208
|
-
|
|
16700
|
+
conversions.push({
|
|
16701
|
+
globalConnNetId,
|
|
16702
|
+
placements: [inlinePlacement],
|
|
16703
|
+
supersededTraceIds: /* @__PURE__ */ new Set()
|
|
16704
|
+
});
|
|
16209
16705
|
continue;
|
|
16210
16706
|
}
|
|
16211
16707
|
if (component.traces.length > 0 && !shouldUseTerminalStubs) {
|
|
16212
|
-
|
|
16708
|
+
continue;
|
|
16213
16709
|
}
|
|
16214
16710
|
if (component.labeledPinIds.length !== component.pinIds.length) {
|
|
16215
|
-
|
|
16711
|
+
continue;
|
|
16216
16712
|
}
|
|
16217
16713
|
const terminalPlacements = component.pinIds.map(
|
|
16218
16714
|
(pinId) => this.computeTerminalInlinePlacement(
|
|
@@ -16223,26 +16719,41 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
16223
16719
|
)
|
|
16224
16720
|
);
|
|
16225
16721
|
if (terminalPlacements.some((placement) => placement === null)) {
|
|
16226
|
-
|
|
16722
|
+
continue;
|
|
16227
16723
|
}
|
|
16228
|
-
|
|
16229
|
-
|
|
16230
|
-
|
|
16724
|
+
conversions.push({
|
|
16725
|
+
globalConnNetId,
|
|
16726
|
+
placements: terminalPlacements,
|
|
16727
|
+
supersededTraceIds: new Set(
|
|
16728
|
+
component.traces.map((trace) => trace.mspPairId)
|
|
16231
16729
|
)
|
|
16232
|
-
);
|
|
16233
|
-
|
|
16234
|
-
|
|
16730
|
+
});
|
|
16731
|
+
}
|
|
16732
|
+
return conversions;
|
|
16733
|
+
}
|
|
16734
|
+
/** Prefer the normal gap, then center text in a tighter parallel-wire slot. */
|
|
16735
|
+
getInlineOffsets(anchor, axis, side, width, height, traces, ignoredTraceIds) {
|
|
16736
|
+
const normal = height / 2 + INLINE_NET_LABEL_TRACE_MARGIN;
|
|
16737
|
+
const across = axis === "x" ? "y" : "x";
|
|
16738
|
+
const sign = side === "x+" || side === "y+" ? 1 : -1;
|
|
16739
|
+
let gap = Infinity;
|
|
16740
|
+
for (const trace of traces) {
|
|
16741
|
+
if (ignoredTraceIds.has(trace.mspPairId)) continue;
|
|
16742
|
+
for (const segment of getAxisAlignedSegments2(trace.tracePath)) {
|
|
16743
|
+
if (segment.axis !== axis) continue;
|
|
16744
|
+
if (Math.max(segment.start[axis], segment.end[axis]) <= anchor[axis] - width / 2 || Math.min(segment.start[axis], segment.end[axis]) >= anchor[axis] + width / 2)
|
|
16745
|
+
continue;
|
|
16746
|
+
const distance7 = sign * (segment.start[across] - anchor[across]);
|
|
16747
|
+
if (distance7 > GEOMETRY_EPSILON) gap = Math.min(gap, distance7);
|
|
16235
16748
|
}
|
|
16236
16749
|
}
|
|
16237
|
-
return
|
|
16750
|
+
return gap > height + GEOMETRY_EPSILON && gap / 2 < normal - GEOMETRY_EPSILON ? [normal, gap / 2] : [normal];
|
|
16238
16751
|
}
|
|
16239
16752
|
/**
|
|
16240
|
-
* Converts one conventional endpoint placement into an inline label on
|
|
16241
|
-
*
|
|
16242
|
-
* an anchored label may finish in another direction after an elbow, which is
|
|
16243
|
-
* not the direction a terminal stub should leave the pin.
|
|
16753
|
+
* Converts one conventional endpoint placement into an inline label on an
|
|
16754
|
+
* outward stub that follows the pin's true facing direction.
|
|
16244
16755
|
*/
|
|
16245
|
-
computeTerminalInlinePlacement(connection, pinId, knownGlobalConnNetId, ignoredTraceIds = /* @__PURE__ */ new Set()) {
|
|
16756
|
+
computeTerminalInlinePlacement(connection, pinId, knownGlobalConnNetId, ignoredTraceIds = /* @__PURE__ */ new Set(), obstacles) {
|
|
16246
16757
|
if (!connection.netId) return null;
|
|
16247
16758
|
const anchoredPlacement = this.inputNetLabelPlacements.find(
|
|
16248
16759
|
(placement) => placement.netId === connection.netId && placement.pinIds.length === 1 && placement.pinIds[0] === pinId
|
|
@@ -16265,7 +16776,7 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
16265
16776
|
start,
|
|
16266
16777
|
intendedEnd,
|
|
16267
16778
|
minimumLength: width + 2 * INLINE_NET_LABEL_TRACE_MARGIN,
|
|
16268
|
-
traces: this.traces,
|
|
16779
|
+
traces: obstacles?.traces ?? this.traces,
|
|
16269
16780
|
ownGlobalConnNetId: globalConnNetId,
|
|
16270
16781
|
ignoredTraceIds
|
|
16271
16782
|
});
|
|
@@ -16275,42 +16786,52 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
16275
16786
|
x: (start.x + end.x) / 2,
|
|
16276
16787
|
y: (start.y + end.y) / 2
|
|
16277
16788
|
};
|
|
16278
|
-
const offset = height / 2 + INLINE_NET_LABEL_TRACE_MARGIN;
|
|
16279
16789
|
const sides = axis === "x" ? ["y+", "y-"] : ["x-", "x+"];
|
|
16280
16790
|
for (const side of sides) {
|
|
16281
|
-
const
|
|
16282
|
-
const halfAlong = width / 2;
|
|
16283
|
-
const halfAcross = height / 2;
|
|
16284
|
-
const bounds = axis === "x" ? {
|
|
16285
|
-
minX: center.x - halfAlong,
|
|
16286
|
-
maxX: center.x + halfAlong,
|
|
16287
|
-
minY: center.y - halfAcross,
|
|
16288
|
-
maxY: center.y + halfAcross
|
|
16289
|
-
} : {
|
|
16290
|
-
minX: center.x - halfAcross,
|
|
16291
|
-
maxX: center.x + halfAcross,
|
|
16292
|
-
minY: center.y - halfAlong,
|
|
16293
|
-
maxY: center.y + halfAlong
|
|
16294
|
-
};
|
|
16295
|
-
if (this.isObstructed(bounds, {
|
|
16296
|
-
ownGlobalConnNetId: globalConnNetId,
|
|
16297
|
-
ignoredTraceIds
|
|
16298
|
-
})) {
|
|
16299
|
-
continue;
|
|
16300
|
-
}
|
|
16301
|
-
return {
|
|
16302
|
-
globalConnNetId,
|
|
16303
|
-
netId: connection.netId,
|
|
16304
|
-
netLabelText,
|
|
16305
|
-
pinIds: [pinId],
|
|
16306
|
-
stubTracePath: [start, end],
|
|
16307
|
-
axis,
|
|
16791
|
+
for (const offset of this.getInlineOffsets(
|
|
16308
16792
|
anchorPoint,
|
|
16309
|
-
|
|
16793
|
+
axis,
|
|
16794
|
+
side,
|
|
16310
16795
|
width,
|
|
16311
16796
|
height,
|
|
16312
|
-
|
|
16313
|
-
|
|
16797
|
+
obstacles?.traces ?? this.traces,
|
|
16798
|
+
ignoredTraceIds
|
|
16799
|
+
)) {
|
|
16800
|
+
const center = side === "y+" ? { x: anchorPoint.x, y: anchorPoint.y + offset } : side === "y-" ? { x: anchorPoint.x, y: anchorPoint.y - offset } : side === "x-" ? { x: anchorPoint.x - offset, y: anchorPoint.y } : { x: anchorPoint.x + offset, y: anchorPoint.y };
|
|
16801
|
+
const halfAlong = width / 2;
|
|
16802
|
+
const halfAcross = height / 2;
|
|
16803
|
+
const bounds = axis === "x" ? {
|
|
16804
|
+
minX: center.x - halfAlong,
|
|
16805
|
+
maxX: center.x + halfAlong,
|
|
16806
|
+
minY: center.y - halfAcross,
|
|
16807
|
+
maxY: center.y + halfAcross
|
|
16808
|
+
} : {
|
|
16809
|
+
minX: center.x - halfAcross,
|
|
16810
|
+
maxX: center.x + halfAcross,
|
|
16811
|
+
minY: center.y - halfAlong,
|
|
16812
|
+
maxY: center.y + halfAlong
|
|
16813
|
+
};
|
|
16814
|
+
if (this.isObstructed(bounds, {
|
|
16815
|
+
ownGlobalConnNetId: globalConnNetId,
|
|
16816
|
+
ignoredTraceIds,
|
|
16817
|
+
obstacles
|
|
16818
|
+
})) {
|
|
16819
|
+
continue;
|
|
16820
|
+
}
|
|
16821
|
+
return {
|
|
16822
|
+
globalConnNetId,
|
|
16823
|
+
netId: connection.netId,
|
|
16824
|
+
netLabelText,
|
|
16825
|
+
pinIds: [pinId],
|
|
16826
|
+
stubTracePath: [start, end],
|
|
16827
|
+
axis,
|
|
16828
|
+
anchorPoint,
|
|
16829
|
+
center,
|
|
16830
|
+
width,
|
|
16831
|
+
height,
|
|
16832
|
+
side
|
|
16833
|
+
};
|
|
16834
|
+
}
|
|
16314
16835
|
}
|
|
16315
16836
|
return null;
|
|
16316
16837
|
}
|
|
@@ -16331,39 +16852,49 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
16331
16852
|
const sides = segment.axis === "x" ? ["y+", "y-"] : ["x-", "x+"];
|
|
16332
16853
|
for (const side of sides) {
|
|
16333
16854
|
for (const anchorPoint of getAnchorCandidates(segment, width)) {
|
|
16334
|
-
const
|
|
16335
|
-
const halfAlong = width / 2;
|
|
16336
|
-
const halfAcross = height / 2;
|
|
16337
|
-
const bounds = segment.axis === "x" ? {
|
|
16338
|
-
minX: center.x - halfAlong,
|
|
16339
|
-
maxX: center.x + halfAlong,
|
|
16340
|
-
minY: center.y - halfAcross,
|
|
16341
|
-
maxY: center.y + halfAcross
|
|
16342
|
-
} : {
|
|
16343
|
-
minX: center.x - halfAcross,
|
|
16344
|
-
maxX: center.x + halfAcross,
|
|
16345
|
-
minY: center.y - halfAlong,
|
|
16346
|
-
maxY: center.y + halfAlong
|
|
16347
|
-
};
|
|
16348
|
-
if (this.isObstructed(bounds, {
|
|
16349
|
-
ownTrace: trace,
|
|
16350
|
-
ownGlobalConnNetId: trace.globalConnNetId,
|
|
16351
|
-
ignoredTraceIds
|
|
16352
|
-
}))
|
|
16353
|
-
continue;
|
|
16354
|
-
return {
|
|
16355
|
-
globalConnNetId: trace.globalConnNetId,
|
|
16356
|
-
netId: connection.netId,
|
|
16357
|
-
netLabelText,
|
|
16358
|
-
mspPairId: trace.mspPairId,
|
|
16359
|
-
pinIds: [...pinIds],
|
|
16360
|
-
axis: segment.axis,
|
|
16855
|
+
for (const offset2 of this.getInlineOffsets(
|
|
16361
16856
|
anchorPoint,
|
|
16362
|
-
|
|
16857
|
+
segment.axis,
|
|
16858
|
+
side,
|
|
16363
16859
|
width,
|
|
16364
16860
|
height,
|
|
16365
|
-
|
|
16366
|
-
|
|
16861
|
+
this.traces,
|
|
16862
|
+
ignoredTraceIds
|
|
16863
|
+
)) {
|
|
16864
|
+
const center = side === "y+" ? { x: anchorPoint.x, y: anchorPoint.y + offset2 } : side === "y-" ? { x: anchorPoint.x, y: anchorPoint.y - offset2 } : side === "x-" ? { x: anchorPoint.x - offset2, y: anchorPoint.y } : { x: anchorPoint.x + offset2, y: anchorPoint.y };
|
|
16865
|
+
const halfAlong = width / 2;
|
|
16866
|
+
const halfAcross = height / 2;
|
|
16867
|
+
const bounds = segment.axis === "x" ? {
|
|
16868
|
+
minX: center.x - halfAlong,
|
|
16869
|
+
maxX: center.x + halfAlong,
|
|
16870
|
+
minY: center.y - halfAcross,
|
|
16871
|
+
maxY: center.y + halfAcross
|
|
16872
|
+
} : {
|
|
16873
|
+
minX: center.x - halfAcross,
|
|
16874
|
+
maxX: center.x + halfAcross,
|
|
16875
|
+
minY: center.y - halfAlong,
|
|
16876
|
+
maxY: center.y + halfAlong
|
|
16877
|
+
};
|
|
16878
|
+
if (this.isObstructed(bounds, {
|
|
16879
|
+
ownTrace: trace,
|
|
16880
|
+
ownGlobalConnNetId: trace.globalConnNetId,
|
|
16881
|
+
ignoredTraceIds
|
|
16882
|
+
}))
|
|
16883
|
+
continue;
|
|
16884
|
+
return {
|
|
16885
|
+
globalConnNetId: trace.globalConnNetId,
|
|
16886
|
+
netId: connection.netId,
|
|
16887
|
+
netLabelText,
|
|
16888
|
+
mspPairId: trace.mspPairId,
|
|
16889
|
+
pinIds: [...pinIds],
|
|
16890
|
+
axis: segment.axis,
|
|
16891
|
+
anchorPoint,
|
|
16892
|
+
center,
|
|
16893
|
+
width,
|
|
16894
|
+
height,
|
|
16895
|
+
side
|
|
16896
|
+
};
|
|
16897
|
+
}
|
|
16367
16898
|
}
|
|
16368
16899
|
}
|
|
16369
16900
|
}
|
|
@@ -16473,7 +17004,8 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
16473
17004
|
isObstructed(bounds, {
|
|
16474
17005
|
ownTrace,
|
|
16475
17006
|
ownGlobalConnNetId,
|
|
16476
|
-
ignoredTraceIds = /* @__PURE__ */ new Set()
|
|
17007
|
+
ignoredTraceIds = /* @__PURE__ */ new Set(),
|
|
17008
|
+
obstacles
|
|
16477
17009
|
}) {
|
|
16478
17010
|
for (const chip of this.inputProblem.chips) {
|
|
16479
17011
|
const chipBounds = {
|
|
@@ -16487,82 +17019,101 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
16487
17019
|
for (const textBox of this.inputProblem.textBoxes ?? []) {
|
|
16488
17020
|
if (boundsOverlap(bounds, getTextBoxBounds(textBox))) return true;
|
|
16489
17021
|
}
|
|
16490
|
-
for (const trace of this.traces) {
|
|
17022
|
+
for (const trace of obstacles?.traces ?? this.traces) {
|
|
16491
17023
|
if (ignoredTraceIds.has(trace.mspPairId)) continue;
|
|
16492
17024
|
if (ownTrace && trace.mspPairId === ownTrace.mspPairId) continue;
|
|
16493
17025
|
if (trace.globalConnNetId === ownGlobalConnNetId) continue;
|
|
16494
17026
|
if (doesPathIntersectBounds3(trace.tracePath, bounds)) return true;
|
|
16495
17027
|
}
|
|
17028
|
+
if (obstacles?.anchored.some(
|
|
17029
|
+
(label) => boundsOverlap(bounds, getAnchoredNetLabelRenderedBounds(label))
|
|
17030
|
+
))
|
|
17031
|
+
return true;
|
|
17032
|
+
if (obstacles?.inline.some(
|
|
17033
|
+
(label) => boundsOverlap(bounds, getInlinePlacementBounds(label)) || label.stubTracePath && label.globalConnNetId !== ownGlobalConnNetId && doesPathIntersectBounds3(label.stubTracePath, bounds)
|
|
17034
|
+
))
|
|
17035
|
+
return true;
|
|
16496
17036
|
return false;
|
|
16497
17037
|
}
|
|
16498
|
-
|
|
16499
|
-
|
|
16500
|
-
|
|
16501
|
-
|
|
16502
|
-
|
|
16503
|
-
|
|
16504
|
-
|
|
16505
|
-
|
|
16506
|
-
|
|
16507
|
-
return keys;
|
|
16508
|
-
}
|
|
16509
|
-
getOutputTraces(supersededNetLabelKeys, supersededTraceIds) {
|
|
17038
|
+
getOutputTraces(placements) {
|
|
17039
|
+
const activeKeys = new Set(placements.map(getInlinePlacementKey));
|
|
17040
|
+
const supersededTraceIds = new Set(
|
|
17041
|
+
this.inlineConversions.filter(
|
|
17042
|
+
(conversion) => conversion.placements.every(
|
|
17043
|
+
(placement) => activeKeys.has(getInlinePlacementKey(placement))
|
|
17044
|
+
)
|
|
17045
|
+
).flatMap((conversion) => [...conversion.supersededTraceIds])
|
|
17046
|
+
);
|
|
16510
17047
|
return this.traces.filter(
|
|
16511
|
-
(trace) => !supersededTraceIds.has(trace.mspPairId) && !(
|
|
17048
|
+
(trace) => !supersededTraceIds.has(trace.mspPairId) && !(this.netLabelConnectorTraceIds.has(trace.mspPairId) && isLabelRepresentedInline(trace, placements))
|
|
16512
17049
|
);
|
|
16513
17050
|
}
|
|
16514
|
-
|
|
17051
|
+
getBlockedInlinePlacements({
|
|
16515
17052
|
inlineNetLabelPlacements,
|
|
16516
|
-
anchoredNetLabelPlacements
|
|
17053
|
+
anchoredNetLabelPlacements,
|
|
17054
|
+
traces
|
|
16517
17055
|
}) {
|
|
16518
|
-
const
|
|
16519
|
-
for (const
|
|
16520
|
-
const
|
|
16521
|
-
|
|
16522
|
-
|
|
16523
|
-
|
|
16524
|
-
|
|
16525
|
-
|
|
16526
|
-
|
|
16527
|
-
|
|
16528
|
-
|
|
16529
|
-
))
|
|
16530
|
-
|
|
16531
|
-
|
|
16532
|
-
|
|
17056
|
+
const blockedKeys = /* @__PURE__ */ new Set();
|
|
17057
|
+
for (const inline of inlineNetLabelPlacements) {
|
|
17058
|
+
const bounds = getInlinePlacementBounds(inline);
|
|
17059
|
+
const blockedByLabel = anchoredNetLabelPlacements.some((anchored) => {
|
|
17060
|
+
const anchoredBounds = getAnchoredNetLabelRenderedBounds(anchored);
|
|
17061
|
+
return boundsOverlap(bounds, anchoredBounds) || inline.stubTracePath && doesPathIntersectBounds3(inline.stubTracePath, anchoredBounds);
|
|
17062
|
+
});
|
|
17063
|
+
const blockedByTrace = traces.some(
|
|
17064
|
+
(trace) => trace.globalConnNetId !== inline.globalConnNetId && (doesPathIntersectBounds3(trace.tracePath, bounds) || inline.stubTracePath && terminalStubIntersectsTrace(inline.stubTracePath, trace))
|
|
17065
|
+
);
|
|
17066
|
+
const blockedByInlineWire = inlineNetLabelPlacements.some(
|
|
17067
|
+
(other) => other !== inline && other.globalConnNetId !== inline.globalConnNetId && other.stubTracePath && doesPathIntersectBounds3(other.stubTracePath, bounds)
|
|
17068
|
+
);
|
|
17069
|
+
const blockedByInlineText = inlineNetLabelPlacements.some(
|
|
17070
|
+
(other) => other !== inline && boundsOverlap(bounds, getInlinePlacementBounds(other))
|
|
17071
|
+
);
|
|
17072
|
+
if (blockedByLabel || blockedByTrace || blockedByInlineWire || blockedByInlineText)
|
|
17073
|
+
blockedKeys.add(getInlinePlacementKey(inline));
|
|
17074
|
+
}
|
|
17075
|
+
for (const conversion of this.inlineConversions) {
|
|
17076
|
+
if (conversion.placements.some(
|
|
17077
|
+
(placement) => blockedKeys.has(getInlinePlacementKey(placement))
|
|
17078
|
+
)) {
|
|
17079
|
+
for (const placement of conversion.placements)
|
|
17080
|
+
blockedKeys.add(getInlinePlacementKey(placement));
|
|
16533
17081
|
}
|
|
16534
17082
|
}
|
|
16535
|
-
return
|
|
17083
|
+
return blockedKeys;
|
|
16536
17084
|
}
|
|
16537
17085
|
buildPostProcessedOutput() {
|
|
16538
17086
|
let activeInlinePlacements = this.inlineNetLabelPlacements;
|
|
16539
17087
|
while (true) {
|
|
16540
|
-
const supersededNetLabelKeys = this.getSupersededNetLabelKeys(
|
|
16541
|
-
activeInlinePlacements
|
|
16542
|
-
);
|
|
16543
|
-
const supersededTraceIds = new Set(
|
|
16544
|
-
[...supersededNetLabelKeys].flatMap((globalConnNetId) => [
|
|
16545
|
-
...this.supersededTraceIdsByGlobalConnNetId.get(globalConnNetId) ?? []
|
|
16546
|
-
])
|
|
16547
|
-
);
|
|
16548
17088
|
const retainedNetLabelPlacements = this.inputNetLabelPlacements.filter(
|
|
16549
|
-
(placement) => !
|
|
17089
|
+
(placement) => !isLabelRepresentedInline(placement, activeInlinePlacements)
|
|
16550
17090
|
);
|
|
16551
|
-
const outputTraces = this.getOutputTraces(
|
|
16552
|
-
|
|
16553
|
-
|
|
17091
|
+
const outputTraces = this.getOutputTraces(activeInlinePlacements);
|
|
17092
|
+
const { fixedLabels, terminalTraces } = getInlineLabelObstacles(
|
|
17093
|
+
this.inputProblem,
|
|
17094
|
+
activeInlinePlacements
|
|
16554
17095
|
);
|
|
17096
|
+
const labelCollisionSolver = new NetLabelNetLabelCollisionSolver({
|
|
17097
|
+
inputProblem: this.inputProblem,
|
|
17098
|
+
traces: [...outputTraces, ...terminalTraces],
|
|
17099
|
+
netLabelPlacements: retainedNetLabelPlacements,
|
|
17100
|
+
fixedNetLabelPlacements: fixedLabels,
|
|
17101
|
+
useRenderedLabelBounds: activeInlinePlacements.length > 0
|
|
17102
|
+
});
|
|
17103
|
+
if (activeInlinePlacements.length > 0) labelCollisionSolver.solve();
|
|
16555
17104
|
const pushed = pushAnchoredNetLabelsAwayFromInlineLabels({
|
|
16556
17105
|
inputProblem: this.inputProblem,
|
|
16557
17106
|
traces: outputTraces,
|
|
16558
|
-
netLabelPlacements: retainedNetLabelPlacements,
|
|
16559
|
-
inlineNetLabelPlacements: activeInlinePlacements
|
|
17107
|
+
netLabelPlacements: labelCollisionSolver.solved && !labelCollisionSolver.failed ? labelCollisionSolver.getOutput().netLabelPlacements : retainedNetLabelPlacements,
|
|
17108
|
+
inlineNetLabelPlacements: activeInlinePlacements,
|
|
17109
|
+
netLabelConnectorTraceIds: this.netLabelConnectorTraceIds
|
|
16560
17110
|
});
|
|
16561
|
-
|
|
17111
|
+
let blockedPlacementKeys = this.getBlockedInlinePlacements({
|
|
16562
17112
|
inlineNetLabelPlacements: activeInlinePlacements,
|
|
16563
|
-
anchoredNetLabelPlacements: pushed.netLabelPlacements
|
|
17113
|
+
anchoredNetLabelPlacements: pushed.netLabelPlacements,
|
|
17114
|
+
traces: pushed.traces
|
|
16564
17115
|
});
|
|
16565
|
-
if (
|
|
17116
|
+
if (blockedPlacementKeys.size > 0) {
|
|
16566
17117
|
const shiftedInlineTerminalLabels = pushInlineTerminalLabelsAwayFromAnchoredLabels({
|
|
16567
17118
|
inputProblem: this.inputProblem,
|
|
16568
17119
|
traces: pushed.traces,
|
|
@@ -16573,8 +17124,49 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
16573
17124
|
activeInlinePlacements = shiftedInlineTerminalLabels.inlineNetLabelPlacements;
|
|
16574
17125
|
continue;
|
|
16575
17126
|
}
|
|
17127
|
+
const { terminalTraces: terminalTraces2 } = getInlineLabelObstacles(
|
|
17128
|
+
this.inputProblem,
|
|
17129
|
+
activeInlinePlacements
|
|
17130
|
+
);
|
|
17131
|
+
const replanned = activeInlinePlacements.filter(
|
|
17132
|
+
(label) => !label.stubTracePath
|
|
17133
|
+
);
|
|
17134
|
+
const terminals = activeInlinePlacements.filter((label) => label.stubTracePath).sort(
|
|
17135
|
+
(a, b) => Number(blockedPlacementKeys.has(getInlinePlacementKey(b))) - Number(blockedPlacementKeys.has(getInlinePlacementKey(a)))
|
|
17136
|
+
);
|
|
17137
|
+
for (const placement of terminals) {
|
|
17138
|
+
const connection = [
|
|
17139
|
+
...this.inputProblem.netConnections,
|
|
17140
|
+
...this.inputProblem.directConnections
|
|
17141
|
+
].find(
|
|
17142
|
+
(connection2) => connection2.netId === placement.netId && connection2.allowInlineNetLabel
|
|
17143
|
+
);
|
|
17144
|
+
const candidate = connection ? this.computeTerminalInlinePlacement(
|
|
17145
|
+
connection,
|
|
17146
|
+
placement.pinIds[0],
|
|
17147
|
+
placement.globalConnNetId,
|
|
17148
|
+
/* @__PURE__ */ new Set(),
|
|
17149
|
+
{
|
|
17150
|
+
traces: [...pushed.traces, ...terminalTraces2],
|
|
17151
|
+
anchored: pushed.netLabelPlacements,
|
|
17152
|
+
inline: replanned
|
|
17153
|
+
}
|
|
17154
|
+
) : null;
|
|
17155
|
+
replanned.push(candidate ?? placement);
|
|
17156
|
+
}
|
|
17157
|
+
const byKey = new Map(
|
|
17158
|
+
replanned.map((label) => [getInlinePlacementKey(label), label])
|
|
17159
|
+
);
|
|
17160
|
+
activeInlinePlacements = activeInlinePlacements.map(
|
|
17161
|
+
(label) => byKey.get(getInlinePlacementKey(label)) ?? label
|
|
17162
|
+
);
|
|
17163
|
+
blockedPlacementKeys = this.getBlockedInlinePlacements({
|
|
17164
|
+
inlineNetLabelPlacements: activeInlinePlacements,
|
|
17165
|
+
anchoredNetLabelPlacements: pushed.netLabelPlacements,
|
|
17166
|
+
traces: pushed.traces
|
|
17167
|
+
});
|
|
16576
17168
|
}
|
|
16577
|
-
if (
|
|
17169
|
+
if (blockedPlacementKeys.size === 0) {
|
|
16578
17170
|
this.inlineNetLabelPlacements = activeInlinePlacements;
|
|
16579
17171
|
this.stats.pushedAnchoredNetLabelCount = pushed.movedLabelCount;
|
|
16580
17172
|
const restored = restoreReroutesAroundSupersededLabels({
|
|
@@ -16585,17 +17177,141 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
16585
17177
|
completedReroutes: this.completedReroutes
|
|
16586
17178
|
});
|
|
16587
17179
|
this.stats.restoredSupersededLabelRerouteCount = restored.restoredTraceCount;
|
|
16588
|
-
|
|
17180
|
+
const output = {
|
|
16589
17181
|
traces: restored.traces,
|
|
17182
|
+
netLabelConnectorTraceIds: pushed.netLabelConnectorTraceIds,
|
|
16590
17183
|
netLabelPlacements: pushed.netLabelPlacements,
|
|
16591
17184
|
inlineNetLabelPlacements: activeInlinePlacements
|
|
16592
17185
|
};
|
|
17186
|
+
this.inlineNetLabelPlacements = output.inlineNetLabelPlacements;
|
|
17187
|
+
return output;
|
|
16593
17188
|
}
|
|
16594
17189
|
activeInlinePlacements = activeInlinePlacements.filter(
|
|
16595
|
-
(placement) => !
|
|
17190
|
+
(placement) => !blockedPlacementKeys.has(getInlinePlacementKey(placement))
|
|
16596
17191
|
);
|
|
16597
17192
|
}
|
|
16598
17193
|
}
|
|
17194
|
+
/** Enumerate nearby moves in the existing order; collect one proposal per step. */
|
|
17195
|
+
*getTraceRefinementProposals(current) {
|
|
17196
|
+
yield* getLocalTraceLabelShifts(this.inputProblem, current);
|
|
17197
|
+
for (const label of current.netLabelPlacements) {
|
|
17198
|
+
if (label.pinIds.length !== 1) continue;
|
|
17199
|
+
const connection = [
|
|
17200
|
+
...this.inputProblem.netConnections,
|
|
17201
|
+
...this.inputProblem.directConnections
|
|
17202
|
+
].find(
|
|
17203
|
+
(connection2) => connection2.allowInlineNetLabel && connection2.netId === label.netId && connection2.pinIds.includes(label.pinIds[0])
|
|
17204
|
+
);
|
|
17205
|
+
if (!connection) continue;
|
|
17206
|
+
const placement = this.computeTerminalInlinePlacement(
|
|
17207
|
+
connection,
|
|
17208
|
+
label.pinIds[0],
|
|
17209
|
+
label.globalConnNetId,
|
|
17210
|
+
/* @__PURE__ */ new Set(),
|
|
17211
|
+
{ traces: [], anchored: [], inline: [] }
|
|
17212
|
+
);
|
|
17213
|
+
if (placement)
|
|
17214
|
+
yield* getLocalTraceLabelShifts(this.inputProblem, current, [placement]);
|
|
17215
|
+
}
|
|
17216
|
+
}
|
|
17217
|
+
createRefinementCandidate(proposal) {
|
|
17218
|
+
const traceMap = new Map(
|
|
17219
|
+
proposal.traces.map((trace) => [trace.mspPairId, trace])
|
|
17220
|
+
);
|
|
17221
|
+
const labelKey = (label) => JSON.stringify([label.globalConnNetId, [...label.pinIds].sort()]);
|
|
17222
|
+
const labelMap = new Map(
|
|
17223
|
+
proposal.netLabelPlacements.map((label) => [labelKey(label), label])
|
|
17224
|
+
);
|
|
17225
|
+
const originalTraceIds = new Set(
|
|
17226
|
+
this.traces.map((trace) => trace.mspPairId)
|
|
17227
|
+
);
|
|
17228
|
+
return new _InlineNetLabelSolver({
|
|
17229
|
+
inputProblem: this.inputProblem,
|
|
17230
|
+
traces: [
|
|
17231
|
+
...this.traces.map((trace) => traceMap.get(trace.mspPairId) ?? trace),
|
|
17232
|
+
...proposal.traces.filter(
|
|
17233
|
+
(trace) => !originalTraceIds.has(trace.mspPairId)
|
|
17234
|
+
)
|
|
17235
|
+
],
|
|
17236
|
+
netLabelPlacements: this.inputNetLabelPlacements.map(
|
|
17237
|
+
(label) => labelMap.get(labelKey(label)) ?? label
|
|
17238
|
+
),
|
|
17239
|
+
completedReroutes: this.completedReroutes,
|
|
17240
|
+
netLabelConnectorTraceIds: proposal.netLabelConnectorTraceIds
|
|
17241
|
+
});
|
|
17242
|
+
}
|
|
17243
|
+
acceptRefinementCandidate(proposal, result) {
|
|
17244
|
+
const current = this.postProcessedOutput;
|
|
17245
|
+
const before = this.refinement.before;
|
|
17246
|
+
const after = getOutputLabelCollisions(result);
|
|
17247
|
+
if (after.some(
|
|
17248
|
+
(collision) => !before.some(
|
|
17249
|
+
(previous) => sameOutputLabelCollision(collision, previous)
|
|
17250
|
+
)
|
|
17251
|
+
))
|
|
17252
|
+
return false;
|
|
17253
|
+
const movedTraceIds = new Set(
|
|
17254
|
+
proposal.traces.filter((trace, index) => trace !== current.traces[index]).map((trace) => trace.mspPairId)
|
|
17255
|
+
);
|
|
17256
|
+
if (after.some(
|
|
17257
|
+
(collision) => collision.kind === "trace-label" && collision.trace.kind === "routed" && movedTraceIds.has(collision.trace.id)
|
|
17258
|
+
))
|
|
17259
|
+
return false;
|
|
17260
|
+
if (after.length >= before.length && result.inlineNetLabelPlacements.length <= current.inlineNetLabelPlacements.length)
|
|
17261
|
+
return false;
|
|
17262
|
+
this.postProcessedOutput = result;
|
|
17263
|
+
this.inlineNetLabelPlacements = result.inlineNetLabelPlacements;
|
|
17264
|
+
return true;
|
|
17265
|
+
}
|
|
17266
|
+
stepTraceRefinement() {
|
|
17267
|
+
if (this.activeSubSolver) {
|
|
17268
|
+
this.activeSubSolver.step();
|
|
17269
|
+
if (!this.activeSubSolver.solved && !this.activeSubSolver.failed) return;
|
|
17270
|
+
if (this.activeSubSolver.solved && !this.activeSubSolver.failed && this.acceptRefinementCandidate(
|
|
17271
|
+
this.currentProposal,
|
|
17272
|
+
this.activeSubSolver.getOutput()
|
|
17273
|
+
)) {
|
|
17274
|
+
this.refinement = void 0;
|
|
17275
|
+
}
|
|
17276
|
+
this.activeSubSolver = null;
|
|
17277
|
+
this.currentProposal = void 0;
|
|
17278
|
+
return;
|
|
17279
|
+
}
|
|
17280
|
+
const current = this.postProcessedOutput;
|
|
17281
|
+
if (!this.refinement) {
|
|
17282
|
+
this.refinement = {
|
|
17283
|
+
proposals: this.getTraceRefinementProposals(current),
|
|
17284
|
+
queue: [],
|
|
17285
|
+
collecting: true,
|
|
17286
|
+
before: getOutputLabelCollisions(current)
|
|
17287
|
+
};
|
|
17288
|
+
}
|
|
17289
|
+
const refinement = this.refinement;
|
|
17290
|
+
if (refinement.collecting) {
|
|
17291
|
+
const next2 = refinement.proposals.next();
|
|
17292
|
+
if (!next2.done) {
|
|
17293
|
+
const distance7 = next2.value.traces.reduce(
|
|
17294
|
+
(sum, trace, index) => sum + trace.tracePath.reduce((distance8, point, pointIndex) => {
|
|
17295
|
+
const previous = current.traces[index].tracePath[pointIndex];
|
|
17296
|
+
return distance8 + Math.abs(point.x - previous.x) + Math.abs(point.y - previous.y);
|
|
17297
|
+
}, 0),
|
|
17298
|
+
0
|
|
17299
|
+
);
|
|
17300
|
+
refinement.queue.push({ output: next2.value, distance: distance7 });
|
|
17301
|
+
} else {
|
|
17302
|
+
refinement.queue.sort((a, b) => a.distance - b.distance);
|
|
17303
|
+
refinement.collecting = false;
|
|
17304
|
+
}
|
|
17305
|
+
return;
|
|
17306
|
+
}
|
|
17307
|
+
const next = refinement.queue.shift();
|
|
17308
|
+
if (!next) {
|
|
17309
|
+
this.refinementComplete = true;
|
|
17310
|
+
return;
|
|
17311
|
+
}
|
|
17312
|
+
this.currentProposal = next.output;
|
|
17313
|
+
this.activeSubSolver = this.createRefinementCandidate(next.output);
|
|
17314
|
+
}
|
|
16599
17315
|
getOutput() {
|
|
16600
17316
|
if (this.postProcessedOutput) return this.postProcessedOutput;
|
|
16601
17317
|
return this.buildPostProcessedOutput();
|
|
@@ -16774,12 +17490,12 @@ var getCollisionLimitedTerminalStubEnd = ({
|
|
|
16774
17490
|
const maxAcross = Math.max(startAcross, endAcross);
|
|
16775
17491
|
let collisionDistance;
|
|
16776
17492
|
const isCollinear = Math.abs(startAcross) <= GEOMETRY_EPSILON && Math.abs(endAcross) <= GEOMETRY_EPSILON;
|
|
16777
|
-
if (isCollinear && maxAlong >= -GEOMETRY_EPSILON && minAlong <= intendedLength + GEOMETRY_EPSILON) {
|
|
17493
|
+
if (isCollinear && maxAlong >= -GEOMETRY_EPSILON && minAlong <= intendedLength + INLINE_NET_LABEL_STUB_TRACE_CLEARANCE + GEOMETRY_EPSILON) {
|
|
16778
17494
|
collisionDistance = Math.max(0, minAlong);
|
|
16779
17495
|
} else {
|
|
16780
17496
|
const crossesStubAxis = minAcross <= GEOMETRY_EPSILON && maxAcross >= -GEOMETRY_EPSILON;
|
|
16781
17497
|
const perpendicularAlong = (startAlong + endAlong) / 2;
|
|
16782
|
-
if (crossesStubAxis && Math.abs(startAlong - endAlong) <= GEOMETRY_EPSILON && perpendicularAlong >= -GEOMETRY_EPSILON && perpendicularAlong <= intendedLength + GEOMETRY_EPSILON) {
|
|
17498
|
+
if (crossesStubAxis && Math.abs(startAlong - endAlong) <= GEOMETRY_EPSILON && perpendicularAlong >= -GEOMETRY_EPSILON && perpendicularAlong <= intendedLength + INLINE_NET_LABEL_STUB_TRACE_CLEARANCE + GEOMETRY_EPSILON) {
|
|
16783
17499
|
collisionDistance = Math.max(0, perpendicularAlong);
|
|
16784
17500
|
}
|
|
16785
17501
|
}
|
|
@@ -16889,12 +17605,12 @@ var getTraceRecoveryConnectivityMaps = (inputProblem) => {
|
|
|
16889
17605
|
};
|
|
16890
17606
|
|
|
16891
17607
|
// lib/solvers/NetLabelToTraceSolver/reduceTraceCrossings.ts
|
|
16892
|
-
var
|
|
16893
|
-
var isHorizontal4 = (start, end) => Math.abs(start.y - end.y) <
|
|
16894
|
-
var isVertical5 = (start, end) => Math.abs(start.x - end.x) <
|
|
17608
|
+
var EPS17 = 1e-9;
|
|
17609
|
+
var isHorizontal4 = (start, end) => Math.abs(start.y - end.y) < EPS17;
|
|
17610
|
+
var isVertical5 = (start, end) => Math.abs(start.x - end.x) < EPS17;
|
|
16895
17611
|
var compactConsecutivePoints = (path) => path.filter((point, index) => {
|
|
16896
17612
|
const previousPoint = path[index - 1];
|
|
16897
|
-
return !previousPoint || Math.abs(point.x - previousPoint.x) >=
|
|
17613
|
+
return !previousPoint || Math.abs(point.x - previousPoint.x) >= EPS17 || Math.abs(point.y - previousPoint.y) >= EPS17;
|
|
16898
17614
|
});
|
|
16899
17615
|
var isValidOrthogonalPath = (path) => {
|
|
16900
17616
|
if (path.length < 2 || !path.every((point, index) => {
|
|
@@ -16932,7 +17648,7 @@ var getEndpointAlignedSegmentCandidates = (tracePath) => {
|
|
|
16932
17648
|
}
|
|
16933
17649
|
const alignedCoordinates = segmentIsVertical ? [previousPoint.x, nextPoint.x] : [previousPoint.y, nextPoint.y];
|
|
16934
17650
|
for (const alignedCoordinate of alignedCoordinates) {
|
|
16935
|
-
if (Math.abs(alignedCoordinate - (segmentIsVertical ? start.x : start.y)) <
|
|
17651
|
+
if (Math.abs(alignedCoordinate - (segmentIsVertical ? start.x : start.y)) < EPS17) {
|
|
16936
17652
|
continue;
|
|
16937
17653
|
}
|
|
16938
17654
|
const candidate = tracePath.map((point) => ({ ...point }));
|
|
@@ -16990,7 +17706,6 @@ var reduceTraceCrossings = ({
|
|
|
16990
17706
|
};
|
|
16991
17707
|
|
|
16992
17708
|
// lib/solvers/NetLabelToTraceSolver/NetLabelToTraceSolver.ts
|
|
16993
|
-
var AVAILABLE_NET_ORIENTATION_PREFIX = "available-net-orientation-";
|
|
16994
17709
|
var RECOVERED_TRACE_PREFIX = "net-label-to-trace-";
|
|
16995
17710
|
var MAX_NAMED_NET_RECOVERY_PERPENDICULAR_OFFSET = 0.05;
|
|
16996
17711
|
var MAX_ROUTED_COMPONENT_RECOVERY_PERPENDICULAR_OFFSET = 0.25;
|
|
@@ -17030,6 +17745,7 @@ var NetLabelToTraceSolver = class extends BaseSolver {
|
|
|
17030
17745
|
inputProblem;
|
|
17031
17746
|
outputTraces;
|
|
17032
17747
|
outputNetLabelPlacements;
|
|
17748
|
+
recoveredTraceIds = /* @__PURE__ */ new Set();
|
|
17033
17749
|
chipMap;
|
|
17034
17750
|
pinMap;
|
|
17035
17751
|
queuedCandidates;
|
|
@@ -17246,7 +17962,7 @@ var NetLabelToTraceSolver = class extends BaseSolver {
|
|
|
17246
17962
|
return candidates;
|
|
17247
17963
|
}
|
|
17248
17964
|
isSupersededConnectorTrace(trace, candidate) {
|
|
17249
|
-
if (!trace.mspPairId
|
|
17965
|
+
if (!this.input.netLabelConnectorTraceIds?.has(trace.mspPairId)) {
|
|
17250
17966
|
return false;
|
|
17251
17967
|
}
|
|
17252
17968
|
if (trace.pinIds.length !== 1) return false;
|
|
@@ -17296,6 +18012,7 @@ var NetLabelToTraceSolver = class extends BaseSolver {
|
|
|
17296
18012
|
mspConnectionPairIds: [mspPairId],
|
|
17297
18013
|
pinIds: [firstPin.pinId, secondPin.pinId]
|
|
17298
18014
|
};
|
|
18015
|
+
this.recoveredTraceIds.add(mspPairId);
|
|
17299
18016
|
this.outputTraces = [...retainedTraces, recoveredTrace];
|
|
17300
18017
|
if (candidate.recoveryMode !== "routed_components") {
|
|
17301
18018
|
this.outputNetLabelPlacements = this.outputNetLabelPlacements.filter(
|
|
@@ -17355,7 +18072,7 @@ var NetLabelToTraceSolver = class extends BaseSolver {
|
|
|
17355
18072
|
...this.getOutput()
|
|
17356
18073
|
});
|
|
17357
18074
|
for (const trace of this.outputTraces) {
|
|
17358
|
-
if (!trace.mspPairId
|
|
18075
|
+
if (!this.recoveredTraceIds.has(trace.mspPairId)) continue;
|
|
17359
18076
|
graphics.lines.push({
|
|
17360
18077
|
points: trace.tracePath,
|
|
17361
18078
|
strokeColor: "green",
|
|
@@ -17821,7 +18538,9 @@ var SchematicTracePipelineSolver = class extends BaseSolver {
|
|
|
17821
18538
|
inputProblem: instance.inputProblem,
|
|
17822
18539
|
traces: junctionOutput.traces,
|
|
17823
18540
|
netLabelPlacements: junctionOutput.netLabelPlacements,
|
|
17824
|
-
completedReroutes
|
|
18541
|
+
completedReroutes,
|
|
18542
|
+
resolveTraceCollisions: true,
|
|
18543
|
+
netLabelConnectorTraceIds: instance.availableNetOrientationSolver.netLabelConnectorTraceIds
|
|
17825
18544
|
}
|
|
17826
18545
|
];
|
|
17827
18546
|
}
|