@tscircuit/schematic-trace-solver 0.0.186 → 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 +1041 -319
- 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/SameNetJunctionAlignmentSolver/alignSameNetJunctions.ts +14 -11
- 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-20260907T083336Z.page.tsx +4 -0
- 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-20260907T083336Z/__snapshots__/bug-report-20260907T083336Z.snap.svg +520 -0
- package/tests/bug-reports/bug-report-20260907T083336Z/bug-report-20260907T083336Z.json +2031 -0
- package/tests/bug-reports/bug-report-20260907T083336Z/bug-report-20260907T083336Z.test.ts +27 -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__/board-1273-trace-overlap-cycle.snap.svg +2 -2
- 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/tests/solvers/SameNetJunctionAlignmentSolver/parallel-load-rails.test.ts +24 -0
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(
|
|
@@ -13915,17 +13973,16 @@ var pathsIntersect = (firstPath, secondPath) => {
|
|
|
13915
13973
|
}
|
|
13916
13974
|
return false;
|
|
13917
13975
|
};
|
|
13918
|
-
var
|
|
13976
|
+
var preserveAttachedTraceJunctions = ({
|
|
13919
13977
|
originalTrace,
|
|
13920
13978
|
candidateTrace,
|
|
13921
|
-
traces
|
|
13922
|
-
netLabelConnectorTraceIds
|
|
13979
|
+
traces
|
|
13923
13980
|
}) => {
|
|
13924
13981
|
let outputTraces = traces.map(
|
|
13925
13982
|
(trace) => trace.mspPairId === originalTrace.mspPairId ? candidateTrace : trace
|
|
13926
13983
|
);
|
|
13927
13984
|
for (const connector of traces) {
|
|
13928
|
-
if (connector.mspPairId === originalTrace.mspPairId ||
|
|
13985
|
+
if (connector.mspPairId === originalTrace.mspPairId || connector.globalConnNetId !== originalTrace.globalConnNetId || !pathsIntersect(originalTrace.tracePath, connector.tracePath) || pathsIntersect(candidateTrace.tracePath, connector.tracePath)) {
|
|
13929
13986
|
continue;
|
|
13930
13987
|
}
|
|
13931
13988
|
const endpointIndex = [0, connector.tracePath.length - 1].find(
|
|
@@ -13936,6 +13993,11 @@ var preserveAttachedLabelConnectorJunctions = ({
|
|
|
13936
13993
|
);
|
|
13937
13994
|
if (endpointIndex === void 0) return null;
|
|
13938
13995
|
const originalJunction = connector.tracePath[endpointIndex];
|
|
13996
|
+
if (connector.pins.some(
|
|
13997
|
+
(pin) => nearlyEqual(pin.x, originalJunction.x) && nearlyEqual(pin.y, originalJunction.y)
|
|
13998
|
+
)) {
|
|
13999
|
+
return null;
|
|
14000
|
+
}
|
|
13939
14001
|
const movedJunction = getMovedAnchorPointForReroute(
|
|
13940
14002
|
originalJunction,
|
|
13941
14003
|
originalTrace.tracePath,
|
|
@@ -14080,7 +14142,7 @@ var candidateIsClear = ({
|
|
|
14080
14142
|
}
|
|
14081
14143
|
for (const otherTrace of otherNetTraces) {
|
|
14082
14144
|
const countIntersections = (path) => {
|
|
14083
|
-
const
|
|
14145
|
+
const intersections2 = /* @__PURE__ */ new Set();
|
|
14084
14146
|
for (let i = 1; i < path.length; i++) {
|
|
14085
14147
|
for (let j = 1; j < otherTrace.tracePath.length; j++) {
|
|
14086
14148
|
const point = getSegmentIntersection3(
|
|
@@ -14090,10 +14152,10 @@ var candidateIsClear = ({
|
|
|
14090
14152
|
otherTrace.tracePath[j]
|
|
14091
14153
|
);
|
|
14092
14154
|
if (point)
|
|
14093
|
-
|
|
14155
|
+
intersections2.add(`${point.x.toFixed(6)},${point.y.toFixed(6)}`);
|
|
14094
14156
|
}
|
|
14095
14157
|
}
|
|
14096
|
-
return
|
|
14158
|
+
return intersections2.size;
|
|
14097
14159
|
};
|
|
14098
14160
|
if (countIntersections(candidateTrace.tracePath) > countIntersections(originalTrace.tracePath)) {
|
|
14099
14161
|
return false;
|
|
@@ -14314,11 +14376,10 @@ var alignSameNetJunctions = ({
|
|
|
14314
14376
|
netLabelPlacements: outputNetLabelPlacements,
|
|
14315
14377
|
attachedLabelIndexes
|
|
14316
14378
|
});
|
|
14317
|
-
const candidateTraces =
|
|
14379
|
+
const candidateTraces = preserveAttachedTraceJunctions({
|
|
14318
14380
|
originalTrace: branchTrace,
|
|
14319
14381
|
candidateTrace,
|
|
14320
|
-
traces: outputTraces
|
|
14321
|
-
netLabelConnectorTraceIds
|
|
14382
|
+
traces: outputTraces
|
|
14322
14383
|
});
|
|
14323
14384
|
if (!candidateTraces) continue;
|
|
14324
14385
|
if (!candidateIsClear({
|
|
@@ -14333,7 +14394,7 @@ var alignSameNetJunctions = ({
|
|
|
14333
14394
|
continue;
|
|
14334
14395
|
}
|
|
14335
14396
|
const movedConnectorsAreClear = candidateTraces.every((trace) => {
|
|
14336
|
-
if (trace.mspPairId === branchTrace.mspPairId
|
|
14397
|
+
if (trace.mspPairId === branchTrace.mspPairId) {
|
|
14337
14398
|
return true;
|
|
14338
14399
|
}
|
|
14339
14400
|
const originalConnector = outputTraces.find(
|
|
@@ -15024,6 +15085,422 @@ var TraceElbowTransitionSimplificationSolver = class extends BaseSolver {
|
|
|
15024
15085
|
}
|
|
15025
15086
|
};
|
|
15026
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
|
+
|
|
15027
15504
|
// lib/solvers/InlineNetLabelSolver/alignPortOnlyInlineNetLabelStubs.ts
|
|
15028
15505
|
var getStubDirection = (path) => {
|
|
15029
15506
|
const [start, end] = path;
|
|
@@ -15099,12 +15576,7 @@ var alignPortOnlyInlineNetLabelStubs = ({
|
|
|
15099
15576
|
groups.set(groupKey, group);
|
|
15100
15577
|
}
|
|
15101
15578
|
const alignedPlacements = [...placements];
|
|
15102
|
-
const
|
|
15103
|
-
placements.map((placement) => placement.globalConnNetId)
|
|
15104
|
-
);
|
|
15105
|
-
const retainedAnchoredLabelBounds = netLabelPlacements.filter(
|
|
15106
|
-
(placement) => !supersededGlobalNetIds.has(placement.globalConnNetId)
|
|
15107
|
-
).map(getLabelBounds2);
|
|
15579
|
+
const retainedAnchoredLabelBounds = netLabelPlacements.filter((placement) => !isLabelRepresentedInline(placement, placements)).map(getLabelBounds2);
|
|
15108
15580
|
for (const group of groups.values()) {
|
|
15109
15581
|
if (group.length < 2) continue;
|
|
15110
15582
|
const targetLength = Math.max(
|
|
@@ -15213,22 +15685,6 @@ var getAxisAlignedSegments2 = (path, epsilon = 1e-6) => {
|
|
|
15213
15685
|
return segments.sort((a, b) => b.length - a.length);
|
|
15214
15686
|
};
|
|
15215
15687
|
|
|
15216
|
-
// lib/solvers/InlineNetLabelSolver/getAnchoredNetLabelRenderedBounds.ts
|
|
15217
|
-
var getAnchoredNetLabelRenderedBounds = (placement) => {
|
|
15218
|
-
if (placement.orientation !== "x-" && placement.orientation !== "x+") {
|
|
15219
|
-
return getRectBounds(placement.center, placement.width, placement.height);
|
|
15220
|
-
}
|
|
15221
|
-
const width = Math.max(placement.width, placement.height);
|
|
15222
|
-
const height = NET_LABEL_HORIZONTAL_HEIGHT;
|
|
15223
|
-
const center = getCenterFromAnchor(
|
|
15224
|
-
placement.anchorPoint,
|
|
15225
|
-
placement.orientation,
|
|
15226
|
-
width,
|
|
15227
|
-
height
|
|
15228
|
-
);
|
|
15229
|
-
return getRectBounds(center, width, height);
|
|
15230
|
-
};
|
|
15231
|
-
|
|
15232
15688
|
// lib/solvers/InlineNetLabelSolver/pushAnchoredNetLabelsAwayFromInlineLabels.ts
|
|
15233
15689
|
var LABEL_CLEARANCE2 = 0.05;
|
|
15234
15690
|
var POINT_EPSILON = 1e-6;
|
|
@@ -15276,29 +15732,37 @@ var isPointOnPath2 = (point, path) => {
|
|
|
15276
15732
|
return false;
|
|
15277
15733
|
};
|
|
15278
15734
|
var getRequiredOutwardDistance = (label, inlineBounds) => {
|
|
15279
|
-
|
|
15280
|
-
|
|
15281
|
-
const
|
|
15282
|
-
(
|
|
15735
|
+
let distance7 = 0;
|
|
15736
|
+
for (let iteration = 0; iteration < inlineBounds.length; iteration++) {
|
|
15737
|
+
const labelBounds = getAnchoredNetLabelRenderedBounds(
|
|
15738
|
+
moveLabel(label, label.orientation, distance7)
|
|
15283
15739
|
);
|
|
15284
|
-
|
|
15285
|
-
|
|
15286
|
-
|
|
15287
|
-
|
|
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
|
+
})
|
|
15748
|
+
);
|
|
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;
|
|
15288
15763
|
}
|
|
15289
|
-
const targetMinX = Math.max(...nearby2.map((bounds) => bounds.maxX));
|
|
15290
|
-
return Math.max(0, targetMinX - labelBounds.minX + LABEL_CLEARANCE2);
|
|
15291
15764
|
}
|
|
15292
|
-
|
|
15293
|
-
(bounds) => labelBounds.minX < bounds.maxX && labelBounds.maxX > bounds.minX
|
|
15294
|
-
);
|
|
15295
|
-
if (nearby.length === 0) return 0;
|
|
15296
|
-
if (label.orientation === "y-") {
|
|
15297
|
-
const targetMaxY = Math.min(...nearby.map((bounds) => bounds.minY));
|
|
15298
|
-
return Math.max(0, labelBounds.maxY - targetMaxY + LABEL_CLEARANCE2);
|
|
15299
|
-
}
|
|
15300
|
-
const targetMinY = Math.max(...nearby.map((bounds) => bounds.maxY));
|
|
15301
|
-
return Math.max(0, targetMinY - labelBounds.minY + LABEL_CLEARANCE2);
|
|
15765
|
+
return distance7;
|
|
15302
15766
|
};
|
|
15303
15767
|
var moveLabel = (label, orientation, distance7) => {
|
|
15304
15768
|
const direction = dir(orientation);
|
|
@@ -15333,10 +15797,9 @@ var boundsGapOnPerpendicularAxis = (a, b, orientation) => {
|
|
|
15333
15797
|
return Math.max(0, a.minX - b.maxX, b.minX - a.maxX);
|
|
15334
15798
|
};
|
|
15335
15799
|
var sharesOwnerChip = (label, ownerChipIds, chipIdByPinId) => label.pinIds.some((pinId) => ownerChipIds.has(chipIdByPinId.get(pinId) ?? ""));
|
|
15336
|
-
var
|
|
15337
|
-
var findConnectorTraceIndex = (label, traces) => traces.findIndex((trace) => {
|
|
15800
|
+
var findConnectorTraceIndex = (label, traces, connectorTraceIds) => traces.findIndex((trace) => {
|
|
15338
15801
|
if (trace.globalConnNetId !== label.globalConnNetId) return false;
|
|
15339
|
-
if (!
|
|
15802
|
+
if (!connectorTraceIds.has(trace.mspPairId)) return false;
|
|
15340
15803
|
const first = trace.tracePath[0];
|
|
15341
15804
|
const last = trace.tracePath.at(-1);
|
|
15342
15805
|
return Boolean(
|
|
@@ -15419,8 +15882,10 @@ var pushAnchoredNetLabelsAwayFromInlineLabels = ({
|
|
|
15419
15882
|
inputProblem,
|
|
15420
15883
|
traces,
|
|
15421
15884
|
netLabelPlacements,
|
|
15422
|
-
inlineNetLabelPlacements
|
|
15885
|
+
inlineNetLabelPlacements,
|
|
15886
|
+
netLabelConnectorTraceIds = /* @__PURE__ */ new Set()
|
|
15423
15887
|
}) => {
|
|
15888
|
+
const connectorTraceIds = new Set(netLabelConnectorTraceIds);
|
|
15424
15889
|
const outputTraces = traces.map((trace) => ({
|
|
15425
15890
|
...trace,
|
|
15426
15891
|
tracePath: trace.tracePath.map((point) => ({ ...point }))
|
|
@@ -15464,7 +15929,11 @@ var pushAnchoredNetLabelsAwayFromInlineLabels = ({
|
|
|
15464
15929
|
moveLabel(obstacle, trigger.orientation, existingObstacleDistance)
|
|
15465
15930
|
);
|
|
15466
15931
|
if (!boundsOverlap(movingBounds, obstacleBounds)) continue;
|
|
15467
|
-
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)) {
|
|
15468
15937
|
failed = true;
|
|
15469
15938
|
break;
|
|
15470
15939
|
}
|
|
@@ -15536,7 +16005,11 @@ var pushAnchoredNetLabelsAwayFromInlineLabels = ({
|
|
|
15536
16005
|
const connectorUpdates = [];
|
|
15537
16006
|
for (const [labelIndex, movedLabel] of proposals) {
|
|
15538
16007
|
const label = outputLabels[labelIndex];
|
|
15539
|
-
const connectorIndex = findConnectorTraceIndex(
|
|
16008
|
+
const connectorIndex = findConnectorTraceIndex(
|
|
16009
|
+
label,
|
|
16010
|
+
outputTraces,
|
|
16011
|
+
connectorTraceIds
|
|
16012
|
+
);
|
|
15540
16013
|
if (connectorIndex === -1 && !canAddConnectorAtAnchor(label, outputTraces, pinMap)) {
|
|
15541
16014
|
failed = true;
|
|
15542
16015
|
break;
|
|
@@ -15586,6 +16059,7 @@ var pushAnchoredNetLabelsAwayFromInlineLabels = ({
|
|
|
15586
16059
|
movedLabelIndices.add(labelIndex);
|
|
15587
16060
|
}
|
|
15588
16061
|
for (const update of connectorUpdates) {
|
|
16062
|
+
connectorTraceIds.add(update.trace.mspPairId);
|
|
15589
16063
|
if (update.connectorIndex === -1) outputTraces.push(update.trace);
|
|
15590
16064
|
else outputTraces[update.connectorIndex] = update.trace;
|
|
15591
16065
|
}
|
|
@@ -15593,7 +16067,8 @@ var pushAnchoredNetLabelsAwayFromInlineLabels = ({
|
|
|
15593
16067
|
return {
|
|
15594
16068
|
traces: outputTraces,
|
|
15595
16069
|
netLabelPlacements: outputLabels,
|
|
15596
|
-
movedLabelCount: movedLabelIndices.size
|
|
16070
|
+
movedLabelCount: movedLabelIndices.size,
|
|
16071
|
+
netLabelConnectorTraceIds: connectorTraceIds
|
|
15597
16072
|
};
|
|
15598
16073
|
};
|
|
15599
16074
|
|
|
@@ -15795,7 +16270,7 @@ var pushInlineTerminalLabelsAwayFromAnchoredLabels = ({
|
|
|
15795
16270
|
};
|
|
15796
16271
|
|
|
15797
16272
|
// lib/solvers/InlineNetLabelSolver/restoreReroutesAroundSupersededLabels.ts
|
|
15798
|
-
import { getSegmentIntersection as
|
|
16273
|
+
import { getSegmentIntersection as getSegmentIntersection6 } from "@tscircuit/math-utils/line-intersections";
|
|
15799
16274
|
|
|
15800
16275
|
// lib/utils/pathIntersectsRenderedLabel.ts
|
|
15801
16276
|
import {
|
|
@@ -15823,31 +16298,31 @@ var pathIntersectsRenderedLabel = (path, label) => {
|
|
|
15823
16298
|
};
|
|
15824
16299
|
|
|
15825
16300
|
// lib/solvers/InlineNetLabelSolver/restoreReroutesAroundSupersededLabels.ts
|
|
15826
|
-
var
|
|
16301
|
+
var EPS16 = 1e-6;
|
|
15827
16302
|
var getPathLength7 = (path) => path.slice(1).reduce((length, point, pointIndex) => {
|
|
15828
16303
|
const previousPoint = path[pointIndex];
|
|
15829
16304
|
return length + Math.abs(point.x - previousPoint.x) + Math.abs(point.y - previousPoint.y);
|
|
15830
16305
|
}, 0);
|
|
15831
16306
|
var pathsEqual = (first, second) => first.length === second.length && first.every(
|
|
15832
|
-
(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
|
|
15833
16308
|
);
|
|
15834
|
-
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;
|
|
15835
16310
|
var getIntersectionKeys = (path, otherPath) => {
|
|
15836
|
-
const
|
|
16311
|
+
const intersections2 = /* @__PURE__ */ new Set();
|
|
15837
16312
|
for (let pathIndex = 0; pathIndex < path.length - 1; pathIndex++) {
|
|
15838
16313
|
for (let otherPathIndex = 0; otherPathIndex < otherPath.length - 1; otherPathIndex++) {
|
|
15839
|
-
const point =
|
|
16314
|
+
const point = getSegmentIntersection6(
|
|
15840
16315
|
path[pathIndex],
|
|
15841
16316
|
path[pathIndex + 1],
|
|
15842
16317
|
otherPath[otherPathIndex],
|
|
15843
16318
|
otherPath[otherPathIndex + 1]
|
|
15844
16319
|
);
|
|
15845
16320
|
if (point) {
|
|
15846
|
-
|
|
16321
|
+
intersections2.add(`${point.x.toFixed(6)},${point.y.toFixed(6)}`);
|
|
15847
16322
|
}
|
|
15848
16323
|
}
|
|
15849
16324
|
}
|
|
15850
|
-
return
|
|
16325
|
+
return intersections2;
|
|
15851
16326
|
};
|
|
15852
16327
|
var introducesNewCrossings = (candidatePath, currentPath, otherPaths) => otherPaths.some((otherPath) => {
|
|
15853
16328
|
const currentIntersections = getIntersectionKeys(currentPath, otherPath);
|
|
@@ -15924,9 +16399,7 @@ var DEFAULT_INLINE_NET_LABEL_HEIGHT = 0.18;
|
|
|
15924
16399
|
var INLINE_NET_LABEL_TRACE_MARGIN = 0.05;
|
|
15925
16400
|
var INLINE_NET_LABEL_STUB_TRACE_CLEARANCE = 0.05;
|
|
15926
16401
|
var INLINE_NET_LABEL_MAX_SPAN_JOG = 0.4;
|
|
15927
|
-
var
|
|
15928
|
-
var isGeneratedAnchoredLabelConnector = (trace) => trace.mspPairId.startsWith(AVAILABLE_NET_ORIENTATION_TRACE_PREFIX);
|
|
15929
|
-
var getPinPairKey2 = (pinIds) => [...pinIds].sort().join("::");
|
|
16402
|
+
var getPinPairKey2 = (pinIds) => JSON.stringify([...pinIds].sort());
|
|
15930
16403
|
var getTraceLength2 = (trace) => {
|
|
15931
16404
|
let length = 0;
|
|
15932
16405
|
for (let index = 0; index < trace.tracePath.length - 1; index++) {
|
|
@@ -15947,21 +16420,26 @@ var getInlinePlacementBounds = (placement) => {
|
|
|
15947
16420
|
maxY: placement.center.y + renderedHeight / 2
|
|
15948
16421
|
};
|
|
15949
16422
|
};
|
|
15950
|
-
var
|
|
15951
|
-
|
|
15952
|
-
|
|
15953
|
-
|
|
15954
|
-
|
|
15955
|
-
|
|
15956
|
-
|
|
15957
|
-
|
|
15958
|
-
|
|
15959
|
-
|
|
15960
|
-
|
|
15961
|
-
|
|
15962
|
-
|
|
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 {
|
|
15963
16439
|
constructor(input) {
|
|
15964
16440
|
super();
|
|
16441
|
+
this.input = input;
|
|
16442
|
+
this.netLabelConnectorTraceIds = input.netLabelConnectorTraceIds ?? /* @__PURE__ */ new Set();
|
|
15965
16443
|
this.inputProblem = input.inputProblem;
|
|
15966
16444
|
this.traces = input.traces;
|
|
15967
16445
|
this.inputNetLabelPlacements = input.netLabelPlacements;
|
|
@@ -15971,7 +16449,11 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
15971
16449
|
).netConnMap;
|
|
15972
16450
|
this.queuedConnections = [
|
|
15973
16451
|
...this.inputProblem.directConnections.filter(
|
|
15974
|
-
(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
|
+
)
|
|
15975
16457
|
).map((connection) => ({
|
|
15976
16458
|
kind: "direct_connection",
|
|
15977
16459
|
connection
|
|
@@ -15985,7 +16467,7 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
15985
16467
|
];
|
|
15986
16468
|
this.tracesByPinPairKey = /* @__PURE__ */ new Map();
|
|
15987
16469
|
for (const trace of this.traces) {
|
|
15988
|
-
if (
|
|
16470
|
+
if (this.netLabelConnectorTraceIds.has(trace.mspPairId)) continue;
|
|
15989
16471
|
const key = getPinPairKey2(trace.pins.map((p) => p.pinId));
|
|
15990
16472
|
const existing = this.tracesByPinPairKey.get(key);
|
|
15991
16473
|
if (existing) {
|
|
@@ -15995,13 +16477,32 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
15995
16477
|
}
|
|
15996
16478
|
}
|
|
15997
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;
|
|
15998
16497
|
getConstructorParams() {
|
|
15999
16498
|
return [
|
|
16000
16499
|
{
|
|
16001
16500
|
inputProblem: this.inputProblem,
|
|
16002
16501
|
traces: this.traces,
|
|
16003
16502
|
netLabelPlacements: this.inputNetLabelPlacements,
|
|
16004
|
-
completedReroutes: this.completedReroutes
|
|
16503
|
+
completedReroutes: this.completedReroutes,
|
|
16504
|
+
resolveTraceCollisions: this.input.resolveTraceCollisions,
|
|
16505
|
+
netLabelConnectorTraceIds: this.netLabelConnectorTraceIds
|
|
16005
16506
|
}
|
|
16006
16507
|
];
|
|
16007
16508
|
}
|
|
@@ -16022,16 +16523,7 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
16022
16523
|
netConnections
|
|
16023
16524
|
)) {
|
|
16024
16525
|
this.inlineNetLabelPlacements.push(...conversion.placements);
|
|
16025
|
-
|
|
16026
|
-
conversion.globalConnNetId
|
|
16027
|
-
) ?? /* @__PURE__ */ new Set();
|
|
16028
|
-
for (const traceId of conversion.supersededTraceIds) {
|
|
16029
|
-
supersededTraceIds.add(traceId);
|
|
16030
|
-
}
|
|
16031
|
-
this.supersededTraceIdsByGlobalConnNetId.set(
|
|
16032
|
-
conversion.globalConnNetId,
|
|
16033
|
-
supersededTraceIds
|
|
16034
|
-
);
|
|
16526
|
+
this.inlineConversions.push(conversion);
|
|
16035
16527
|
}
|
|
16036
16528
|
return;
|
|
16037
16529
|
}
|
|
@@ -16045,11 +16537,12 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
16045
16537
|
});
|
|
16046
16538
|
if (placement) this.inlineNetLabelPlacements.push(placement);
|
|
16047
16539
|
} else {
|
|
16048
|
-
const
|
|
16049
|
-
|
|
16050
|
-
|
|
16051
|
-
|
|
16052
|
-
|
|
16540
|
+
for (const pinId of connection.pinIds) {
|
|
16541
|
+
const placement = this.computeTerminalInlinePlacement(
|
|
16542
|
+
connection,
|
|
16543
|
+
pinId
|
|
16544
|
+
);
|
|
16545
|
+
if (placement) this.inlineNetLabelPlacements.push(placement);
|
|
16053
16546
|
}
|
|
16054
16547
|
}
|
|
16055
16548
|
return;
|
|
@@ -16068,13 +16561,17 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
16068
16561
|
this.postProcessedOutput = this.buildPostProcessedOutput();
|
|
16069
16562
|
return;
|
|
16070
16563
|
}
|
|
16564
|
+
if (this.input.resolveTraceCollisions && !this.refinementComplete) {
|
|
16565
|
+
this.stepTraceRefinement();
|
|
16566
|
+
return;
|
|
16567
|
+
}
|
|
16071
16568
|
this.solved = true;
|
|
16072
16569
|
this.stats.inlineNetLabelCount = this.inlineNetLabelPlacements.length;
|
|
16073
16570
|
}
|
|
16074
16571
|
/**
|
|
16075
16572
|
* Plans all opted-in multi-pin nets together. Short routed components can
|
|
16076
16573
|
* mutually block the outward endpoint stubs that replace them, so tentative
|
|
16077
|
-
* replacements are ignored as obstacles only while their
|
|
16574
|
+
* replacements are ignored as obstacles only while their connected component still
|
|
16078
16575
|
* converts successfully. Failed conversions retain both their traces and
|
|
16079
16576
|
* their conventional labels, and the remaining conversions are retried.
|
|
16080
16577
|
*/
|
|
@@ -16115,13 +16612,11 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
16115
16612
|
}));
|
|
16116
16613
|
const nextIgnoredTraceIds = new Set(
|
|
16117
16614
|
conversions.flatMap(
|
|
16118
|
-
({ conversion }) => conversion
|
|
16615
|
+
({ conversion }) => conversion.flatMap((component) => [...component.supersededTraceIds])
|
|
16119
16616
|
)
|
|
16120
16617
|
);
|
|
16121
16618
|
if (setsEqual(ignoredTraceIds, nextIgnoredTraceIds)) {
|
|
16122
|
-
return conversions.flatMap(
|
|
16123
|
-
({ conversion }) => conversion ? [conversion] : []
|
|
16124
|
-
);
|
|
16619
|
+
return conversions.flatMap(({ conversion }) => conversion);
|
|
16125
16620
|
}
|
|
16126
16621
|
ignoredTraceIds = nextIgnoredTraceIds;
|
|
16127
16622
|
}
|
|
@@ -16151,7 +16646,7 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
16151
16646
|
// anchored label. They are removed when that label becomes inline, so
|
|
16152
16647
|
// treating them as routed circuitry would leave text on a deleted wire.
|
|
16153
16648
|
traces: this.traces.filter(
|
|
16154
|
-
(trace) => !
|
|
16649
|
+
(trace) => !this.netLabelConnectorTraceIds.has(trace.mspPairId)
|
|
16155
16650
|
)
|
|
16156
16651
|
}).map((component) => ({
|
|
16157
16652
|
pinIds: component.pinIds,
|
|
@@ -16177,14 +16672,14 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
16177
16672
|
* Converts every conventional label representation for an opted-in named
|
|
16178
16673
|
* net. Routed connected components become labels on their representative
|
|
16179
16674
|
* trace; disconnected pins become outward terminal stubs. The conversion is
|
|
16180
|
-
* atomic
|
|
16675
|
+
* atomic within each routed component, so replacing its traces cannot strand
|
|
16676
|
+
* a pin. Disconnected components can keep their own label style.
|
|
16181
16677
|
*/
|
|
16182
16678
|
computeNetConnectionInlinePlacements(connection, ignoredTraceIds, forcedTerminalTraceIds) {
|
|
16183
16679
|
const components = this.getNetConnectionComponents(connection);
|
|
16184
16680
|
const globalConnNetId = this.getGlobalConnNetId(connection);
|
|
16185
|
-
if (!globalConnNetId) return
|
|
16186
|
-
const
|
|
16187
|
-
const supersededTraceIds = /* @__PURE__ */ new Set();
|
|
16681
|
+
if (!globalConnNetId) return [];
|
|
16682
|
+
const conversions = [];
|
|
16188
16683
|
for (const component of components) {
|
|
16189
16684
|
const shouldUseTerminalStubs = component.traces.some(
|
|
16190
16685
|
(trace) => forcedTerminalTraceIds.has(trace.mspPairId)
|
|
@@ -16202,14 +16697,18 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
16202
16697
|
}
|
|
16203
16698
|
}
|
|
16204
16699
|
if (inlinePlacement) {
|
|
16205
|
-
|
|
16700
|
+
conversions.push({
|
|
16701
|
+
globalConnNetId,
|
|
16702
|
+
placements: [inlinePlacement],
|
|
16703
|
+
supersededTraceIds: /* @__PURE__ */ new Set()
|
|
16704
|
+
});
|
|
16206
16705
|
continue;
|
|
16207
16706
|
}
|
|
16208
16707
|
if (component.traces.length > 0 && !shouldUseTerminalStubs) {
|
|
16209
|
-
|
|
16708
|
+
continue;
|
|
16210
16709
|
}
|
|
16211
16710
|
if (component.labeledPinIds.length !== component.pinIds.length) {
|
|
16212
|
-
|
|
16711
|
+
continue;
|
|
16213
16712
|
}
|
|
16214
16713
|
const terminalPlacements = component.pinIds.map(
|
|
16215
16714
|
(pinId) => this.computeTerminalInlinePlacement(
|
|
@@ -16220,26 +16719,41 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
16220
16719
|
)
|
|
16221
16720
|
);
|
|
16222
16721
|
if (terminalPlacements.some((placement) => placement === null)) {
|
|
16223
|
-
|
|
16722
|
+
continue;
|
|
16224
16723
|
}
|
|
16225
|
-
|
|
16226
|
-
|
|
16227
|
-
|
|
16724
|
+
conversions.push({
|
|
16725
|
+
globalConnNetId,
|
|
16726
|
+
placements: terminalPlacements,
|
|
16727
|
+
supersededTraceIds: new Set(
|
|
16728
|
+
component.traces.map((trace) => trace.mspPairId)
|
|
16228
16729
|
)
|
|
16229
|
-
);
|
|
16230
|
-
|
|
16231
|
-
|
|
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);
|
|
16232
16748
|
}
|
|
16233
16749
|
}
|
|
16234
|
-
return
|
|
16750
|
+
return gap > height + GEOMETRY_EPSILON && gap / 2 < normal - GEOMETRY_EPSILON ? [normal, gap / 2] : [normal];
|
|
16235
16751
|
}
|
|
16236
16752
|
/**
|
|
16237
|
-
* Converts one conventional endpoint placement into an inline label on
|
|
16238
|
-
*
|
|
16239
|
-
* an anchored label may finish in another direction after an elbow, which is
|
|
16240
|
-
* 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.
|
|
16241
16755
|
*/
|
|
16242
|
-
computeTerminalInlinePlacement(connection, pinId, knownGlobalConnNetId, ignoredTraceIds = /* @__PURE__ */ new Set()) {
|
|
16756
|
+
computeTerminalInlinePlacement(connection, pinId, knownGlobalConnNetId, ignoredTraceIds = /* @__PURE__ */ new Set(), obstacles) {
|
|
16243
16757
|
if (!connection.netId) return null;
|
|
16244
16758
|
const anchoredPlacement = this.inputNetLabelPlacements.find(
|
|
16245
16759
|
(placement) => placement.netId === connection.netId && placement.pinIds.length === 1 && placement.pinIds[0] === pinId
|
|
@@ -16262,7 +16776,7 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
16262
16776
|
start,
|
|
16263
16777
|
intendedEnd,
|
|
16264
16778
|
minimumLength: width + 2 * INLINE_NET_LABEL_TRACE_MARGIN,
|
|
16265
|
-
traces: this.traces,
|
|
16779
|
+
traces: obstacles?.traces ?? this.traces,
|
|
16266
16780
|
ownGlobalConnNetId: globalConnNetId,
|
|
16267
16781
|
ignoredTraceIds
|
|
16268
16782
|
});
|
|
@@ -16272,42 +16786,52 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
16272
16786
|
x: (start.x + end.x) / 2,
|
|
16273
16787
|
y: (start.y + end.y) / 2
|
|
16274
16788
|
};
|
|
16275
|
-
const offset = height / 2 + INLINE_NET_LABEL_TRACE_MARGIN;
|
|
16276
16789
|
const sides = axis === "x" ? ["y+", "y-"] : ["x-", "x+"];
|
|
16277
16790
|
for (const side of sides) {
|
|
16278
|
-
const
|
|
16279
|
-
const halfAlong = width / 2;
|
|
16280
|
-
const halfAcross = height / 2;
|
|
16281
|
-
const bounds = axis === "x" ? {
|
|
16282
|
-
minX: center.x - halfAlong,
|
|
16283
|
-
maxX: center.x + halfAlong,
|
|
16284
|
-
minY: center.y - halfAcross,
|
|
16285
|
-
maxY: center.y + halfAcross
|
|
16286
|
-
} : {
|
|
16287
|
-
minX: center.x - halfAcross,
|
|
16288
|
-
maxX: center.x + halfAcross,
|
|
16289
|
-
minY: center.y - halfAlong,
|
|
16290
|
-
maxY: center.y + halfAlong
|
|
16291
|
-
};
|
|
16292
|
-
if (this.isObstructed(bounds, {
|
|
16293
|
-
ownGlobalConnNetId: globalConnNetId,
|
|
16294
|
-
ignoredTraceIds
|
|
16295
|
-
})) {
|
|
16296
|
-
continue;
|
|
16297
|
-
}
|
|
16298
|
-
return {
|
|
16299
|
-
globalConnNetId,
|
|
16300
|
-
netId: connection.netId,
|
|
16301
|
-
netLabelText,
|
|
16302
|
-
pinIds: [pinId],
|
|
16303
|
-
stubTracePath: [start, end],
|
|
16304
|
-
axis,
|
|
16791
|
+
for (const offset of this.getInlineOffsets(
|
|
16305
16792
|
anchorPoint,
|
|
16306
|
-
|
|
16793
|
+
axis,
|
|
16794
|
+
side,
|
|
16307
16795
|
width,
|
|
16308
16796
|
height,
|
|
16309
|
-
|
|
16310
|
-
|
|
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
|
+
}
|
|
16311
16835
|
}
|
|
16312
16836
|
return null;
|
|
16313
16837
|
}
|
|
@@ -16328,39 +16852,49 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
16328
16852
|
const sides = segment.axis === "x" ? ["y+", "y-"] : ["x-", "x+"];
|
|
16329
16853
|
for (const side of sides) {
|
|
16330
16854
|
for (const anchorPoint of getAnchorCandidates(segment, width)) {
|
|
16331
|
-
const
|
|
16332
|
-
const halfAlong = width / 2;
|
|
16333
|
-
const halfAcross = height / 2;
|
|
16334
|
-
const bounds = segment.axis === "x" ? {
|
|
16335
|
-
minX: center.x - halfAlong,
|
|
16336
|
-
maxX: center.x + halfAlong,
|
|
16337
|
-
minY: center.y - halfAcross,
|
|
16338
|
-
maxY: center.y + halfAcross
|
|
16339
|
-
} : {
|
|
16340
|
-
minX: center.x - halfAcross,
|
|
16341
|
-
maxX: center.x + halfAcross,
|
|
16342
|
-
minY: center.y - halfAlong,
|
|
16343
|
-
maxY: center.y + halfAlong
|
|
16344
|
-
};
|
|
16345
|
-
if (this.isObstructed(bounds, {
|
|
16346
|
-
ownTrace: trace,
|
|
16347
|
-
ownGlobalConnNetId: trace.globalConnNetId,
|
|
16348
|
-
ignoredTraceIds
|
|
16349
|
-
}))
|
|
16350
|
-
continue;
|
|
16351
|
-
return {
|
|
16352
|
-
globalConnNetId: trace.globalConnNetId,
|
|
16353
|
-
netId: connection.netId,
|
|
16354
|
-
netLabelText,
|
|
16355
|
-
mspPairId: trace.mspPairId,
|
|
16356
|
-
pinIds: [...pinIds],
|
|
16357
|
-
axis: segment.axis,
|
|
16855
|
+
for (const offset2 of this.getInlineOffsets(
|
|
16358
16856
|
anchorPoint,
|
|
16359
|
-
|
|
16857
|
+
segment.axis,
|
|
16858
|
+
side,
|
|
16360
16859
|
width,
|
|
16361
16860
|
height,
|
|
16362
|
-
|
|
16363
|
-
|
|
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
|
+
}
|
|
16364
16898
|
}
|
|
16365
16899
|
}
|
|
16366
16900
|
}
|
|
@@ -16470,7 +17004,8 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
16470
17004
|
isObstructed(bounds, {
|
|
16471
17005
|
ownTrace,
|
|
16472
17006
|
ownGlobalConnNetId,
|
|
16473
|
-
ignoredTraceIds = /* @__PURE__ */ new Set()
|
|
17007
|
+
ignoredTraceIds = /* @__PURE__ */ new Set(),
|
|
17008
|
+
obstacles
|
|
16474
17009
|
}) {
|
|
16475
17010
|
for (const chip of this.inputProblem.chips) {
|
|
16476
17011
|
const chipBounds = {
|
|
@@ -16484,82 +17019,101 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
16484
17019
|
for (const textBox of this.inputProblem.textBoxes ?? []) {
|
|
16485
17020
|
if (boundsOverlap(bounds, getTextBoxBounds(textBox))) return true;
|
|
16486
17021
|
}
|
|
16487
|
-
for (const trace of this.traces) {
|
|
17022
|
+
for (const trace of obstacles?.traces ?? this.traces) {
|
|
16488
17023
|
if (ignoredTraceIds.has(trace.mspPairId)) continue;
|
|
16489
17024
|
if (ownTrace && trace.mspPairId === ownTrace.mspPairId) continue;
|
|
16490
17025
|
if (trace.globalConnNetId === ownGlobalConnNetId) continue;
|
|
16491
17026
|
if (doesPathIntersectBounds3(trace.tracePath, bounds)) return true;
|
|
16492
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;
|
|
16493
17036
|
return false;
|
|
16494
17037
|
}
|
|
16495
|
-
|
|
16496
|
-
|
|
16497
|
-
|
|
16498
|
-
|
|
16499
|
-
|
|
16500
|
-
|
|
16501
|
-
|
|
16502
|
-
|
|
16503
|
-
|
|
16504
|
-
return keys;
|
|
16505
|
-
}
|
|
16506
|
-
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
|
+
);
|
|
16507
17047
|
return this.traces.filter(
|
|
16508
|
-
(trace) => !supersededTraceIds.has(trace.mspPairId) && !(
|
|
17048
|
+
(trace) => !supersededTraceIds.has(trace.mspPairId) && !(this.netLabelConnectorTraceIds.has(trace.mspPairId) && isLabelRepresentedInline(trace, placements))
|
|
16509
17049
|
);
|
|
16510
17050
|
}
|
|
16511
|
-
|
|
17051
|
+
getBlockedInlinePlacements({
|
|
16512
17052
|
inlineNetLabelPlacements,
|
|
16513
|
-
anchoredNetLabelPlacements
|
|
17053
|
+
anchoredNetLabelPlacements,
|
|
17054
|
+
traces
|
|
16514
17055
|
}) {
|
|
16515
|
-
const
|
|
16516
|
-
for (const
|
|
16517
|
-
const
|
|
16518
|
-
|
|
16519
|
-
|
|
16520
|
-
|
|
16521
|
-
|
|
16522
|
-
|
|
16523
|
-
|
|
16524
|
-
|
|
16525
|
-
|
|
16526
|
-
))
|
|
16527
|
-
|
|
16528
|
-
|
|
16529
|
-
|
|
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));
|
|
16530
17081
|
}
|
|
16531
17082
|
}
|
|
16532
|
-
return
|
|
17083
|
+
return blockedKeys;
|
|
16533
17084
|
}
|
|
16534
17085
|
buildPostProcessedOutput() {
|
|
16535
17086
|
let activeInlinePlacements = this.inlineNetLabelPlacements;
|
|
16536
17087
|
while (true) {
|
|
16537
|
-
const supersededNetLabelKeys = this.getSupersededNetLabelKeys(
|
|
16538
|
-
activeInlinePlacements
|
|
16539
|
-
);
|
|
16540
|
-
const supersededTraceIds = new Set(
|
|
16541
|
-
[...supersededNetLabelKeys].flatMap((globalConnNetId) => [
|
|
16542
|
-
...this.supersededTraceIdsByGlobalConnNetId.get(globalConnNetId) ?? []
|
|
16543
|
-
])
|
|
16544
|
-
);
|
|
16545
17088
|
const retainedNetLabelPlacements = this.inputNetLabelPlacements.filter(
|
|
16546
|
-
(placement) => !
|
|
17089
|
+
(placement) => !isLabelRepresentedInline(placement, activeInlinePlacements)
|
|
16547
17090
|
);
|
|
16548
|
-
const outputTraces = this.getOutputTraces(
|
|
16549
|
-
|
|
16550
|
-
|
|
17091
|
+
const outputTraces = this.getOutputTraces(activeInlinePlacements);
|
|
17092
|
+
const { fixedLabels, terminalTraces } = getInlineLabelObstacles(
|
|
17093
|
+
this.inputProblem,
|
|
17094
|
+
activeInlinePlacements
|
|
16551
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();
|
|
16552
17104
|
const pushed = pushAnchoredNetLabelsAwayFromInlineLabels({
|
|
16553
17105
|
inputProblem: this.inputProblem,
|
|
16554
17106
|
traces: outputTraces,
|
|
16555
|
-
netLabelPlacements: retainedNetLabelPlacements,
|
|
16556
|
-
inlineNetLabelPlacements: activeInlinePlacements
|
|
17107
|
+
netLabelPlacements: labelCollisionSolver.solved && !labelCollisionSolver.failed ? labelCollisionSolver.getOutput().netLabelPlacements : retainedNetLabelPlacements,
|
|
17108
|
+
inlineNetLabelPlacements: activeInlinePlacements,
|
|
17109
|
+
netLabelConnectorTraceIds: this.netLabelConnectorTraceIds
|
|
16557
17110
|
});
|
|
16558
|
-
|
|
17111
|
+
let blockedPlacementKeys = this.getBlockedInlinePlacements({
|
|
16559
17112
|
inlineNetLabelPlacements: activeInlinePlacements,
|
|
16560
|
-
anchoredNetLabelPlacements: pushed.netLabelPlacements
|
|
17113
|
+
anchoredNetLabelPlacements: pushed.netLabelPlacements,
|
|
17114
|
+
traces: pushed.traces
|
|
16561
17115
|
});
|
|
16562
|
-
if (
|
|
17116
|
+
if (blockedPlacementKeys.size > 0) {
|
|
16563
17117
|
const shiftedInlineTerminalLabels = pushInlineTerminalLabelsAwayFromAnchoredLabels({
|
|
16564
17118
|
inputProblem: this.inputProblem,
|
|
16565
17119
|
traces: pushed.traces,
|
|
@@ -16570,8 +17124,49 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
16570
17124
|
activeInlinePlacements = shiftedInlineTerminalLabels.inlineNetLabelPlacements;
|
|
16571
17125
|
continue;
|
|
16572
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
|
+
});
|
|
16573
17168
|
}
|
|
16574
|
-
if (
|
|
17169
|
+
if (blockedPlacementKeys.size === 0) {
|
|
16575
17170
|
this.inlineNetLabelPlacements = activeInlinePlacements;
|
|
16576
17171
|
this.stats.pushedAnchoredNetLabelCount = pushed.movedLabelCount;
|
|
16577
17172
|
const restored = restoreReroutesAroundSupersededLabels({
|
|
@@ -16582,17 +17177,141 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
16582
17177
|
completedReroutes: this.completedReroutes
|
|
16583
17178
|
});
|
|
16584
17179
|
this.stats.restoredSupersededLabelRerouteCount = restored.restoredTraceCount;
|
|
16585
|
-
|
|
17180
|
+
const output = {
|
|
16586
17181
|
traces: restored.traces,
|
|
17182
|
+
netLabelConnectorTraceIds: pushed.netLabelConnectorTraceIds,
|
|
16587
17183
|
netLabelPlacements: pushed.netLabelPlacements,
|
|
16588
17184
|
inlineNetLabelPlacements: activeInlinePlacements
|
|
16589
17185
|
};
|
|
17186
|
+
this.inlineNetLabelPlacements = output.inlineNetLabelPlacements;
|
|
17187
|
+
return output;
|
|
16590
17188
|
}
|
|
16591
17189
|
activeInlinePlacements = activeInlinePlacements.filter(
|
|
16592
|
-
(placement) => !
|
|
17190
|
+
(placement) => !blockedPlacementKeys.has(getInlinePlacementKey(placement))
|
|
17191
|
+
);
|
|
17192
|
+
}
|
|
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: [] }
|
|
16593
17212
|
);
|
|
17213
|
+
if (placement)
|
|
17214
|
+
yield* getLocalTraceLabelShifts(this.inputProblem, current, [placement]);
|
|
16594
17215
|
}
|
|
16595
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
|
+
}
|
|
16596
17315
|
getOutput() {
|
|
16597
17316
|
if (this.postProcessedOutput) return this.postProcessedOutput;
|
|
16598
17317
|
return this.buildPostProcessedOutput();
|
|
@@ -16771,12 +17490,12 @@ var getCollisionLimitedTerminalStubEnd = ({
|
|
|
16771
17490
|
const maxAcross = Math.max(startAcross, endAcross);
|
|
16772
17491
|
let collisionDistance;
|
|
16773
17492
|
const isCollinear = Math.abs(startAcross) <= GEOMETRY_EPSILON && Math.abs(endAcross) <= GEOMETRY_EPSILON;
|
|
16774
|
-
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) {
|
|
16775
17494
|
collisionDistance = Math.max(0, minAlong);
|
|
16776
17495
|
} else {
|
|
16777
17496
|
const crossesStubAxis = minAcross <= GEOMETRY_EPSILON && maxAcross >= -GEOMETRY_EPSILON;
|
|
16778
17497
|
const perpendicularAlong = (startAlong + endAlong) / 2;
|
|
16779
|
-
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) {
|
|
16780
17499
|
collisionDistance = Math.max(0, perpendicularAlong);
|
|
16781
17500
|
}
|
|
16782
17501
|
}
|
|
@@ -16886,12 +17605,12 @@ var getTraceRecoveryConnectivityMaps = (inputProblem) => {
|
|
|
16886
17605
|
};
|
|
16887
17606
|
|
|
16888
17607
|
// lib/solvers/NetLabelToTraceSolver/reduceTraceCrossings.ts
|
|
16889
|
-
var
|
|
16890
|
-
var isHorizontal4 = (start, end) => Math.abs(start.y - end.y) <
|
|
16891
|
-
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;
|
|
16892
17611
|
var compactConsecutivePoints = (path) => path.filter((point, index) => {
|
|
16893
17612
|
const previousPoint = path[index - 1];
|
|
16894
|
-
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;
|
|
16895
17614
|
});
|
|
16896
17615
|
var isValidOrthogonalPath = (path) => {
|
|
16897
17616
|
if (path.length < 2 || !path.every((point, index) => {
|
|
@@ -16929,7 +17648,7 @@ var getEndpointAlignedSegmentCandidates = (tracePath) => {
|
|
|
16929
17648
|
}
|
|
16930
17649
|
const alignedCoordinates = segmentIsVertical ? [previousPoint.x, nextPoint.x] : [previousPoint.y, nextPoint.y];
|
|
16931
17650
|
for (const alignedCoordinate of alignedCoordinates) {
|
|
16932
|
-
if (Math.abs(alignedCoordinate - (segmentIsVertical ? start.x : start.y)) <
|
|
17651
|
+
if (Math.abs(alignedCoordinate - (segmentIsVertical ? start.x : start.y)) < EPS17) {
|
|
16933
17652
|
continue;
|
|
16934
17653
|
}
|
|
16935
17654
|
const candidate = tracePath.map((point) => ({ ...point }));
|
|
@@ -16987,7 +17706,6 @@ var reduceTraceCrossings = ({
|
|
|
16987
17706
|
};
|
|
16988
17707
|
|
|
16989
17708
|
// lib/solvers/NetLabelToTraceSolver/NetLabelToTraceSolver.ts
|
|
16990
|
-
var AVAILABLE_NET_ORIENTATION_PREFIX = "available-net-orientation-";
|
|
16991
17709
|
var RECOVERED_TRACE_PREFIX = "net-label-to-trace-";
|
|
16992
17710
|
var MAX_NAMED_NET_RECOVERY_PERPENDICULAR_OFFSET = 0.05;
|
|
16993
17711
|
var MAX_ROUTED_COMPONENT_RECOVERY_PERPENDICULAR_OFFSET = 0.25;
|
|
@@ -17027,6 +17745,7 @@ var NetLabelToTraceSolver = class extends BaseSolver {
|
|
|
17027
17745
|
inputProblem;
|
|
17028
17746
|
outputTraces;
|
|
17029
17747
|
outputNetLabelPlacements;
|
|
17748
|
+
recoveredTraceIds = /* @__PURE__ */ new Set();
|
|
17030
17749
|
chipMap;
|
|
17031
17750
|
pinMap;
|
|
17032
17751
|
queuedCandidates;
|
|
@@ -17243,7 +17962,7 @@ var NetLabelToTraceSolver = class extends BaseSolver {
|
|
|
17243
17962
|
return candidates;
|
|
17244
17963
|
}
|
|
17245
17964
|
isSupersededConnectorTrace(trace, candidate) {
|
|
17246
|
-
if (!trace.mspPairId
|
|
17965
|
+
if (!this.input.netLabelConnectorTraceIds?.has(trace.mspPairId)) {
|
|
17247
17966
|
return false;
|
|
17248
17967
|
}
|
|
17249
17968
|
if (trace.pinIds.length !== 1) return false;
|
|
@@ -17293,6 +18012,7 @@ var NetLabelToTraceSolver = class extends BaseSolver {
|
|
|
17293
18012
|
mspConnectionPairIds: [mspPairId],
|
|
17294
18013
|
pinIds: [firstPin.pinId, secondPin.pinId]
|
|
17295
18014
|
};
|
|
18015
|
+
this.recoveredTraceIds.add(mspPairId);
|
|
17296
18016
|
this.outputTraces = [...retainedTraces, recoveredTrace];
|
|
17297
18017
|
if (candidate.recoveryMode !== "routed_components") {
|
|
17298
18018
|
this.outputNetLabelPlacements = this.outputNetLabelPlacements.filter(
|
|
@@ -17352,7 +18072,7 @@ var NetLabelToTraceSolver = class extends BaseSolver {
|
|
|
17352
18072
|
...this.getOutput()
|
|
17353
18073
|
});
|
|
17354
18074
|
for (const trace of this.outputTraces) {
|
|
17355
|
-
if (!trace.mspPairId
|
|
18075
|
+
if (!this.recoveredTraceIds.has(trace.mspPairId)) continue;
|
|
17356
18076
|
graphics.lines.push({
|
|
17357
18077
|
points: trace.tracePath,
|
|
17358
18078
|
strokeColor: "green",
|
|
@@ -17818,7 +18538,9 @@ var SchematicTracePipelineSolver = class extends BaseSolver {
|
|
|
17818
18538
|
inputProblem: instance.inputProblem,
|
|
17819
18539
|
traces: junctionOutput.traces,
|
|
17820
18540
|
netLabelPlacements: junctionOutput.netLabelPlacements,
|
|
17821
|
-
completedReroutes
|
|
18541
|
+
completedReroutes,
|
|
18542
|
+
resolveTraceCollisions: true,
|
|
18543
|
+
netLabelConnectorTraceIds: instance.availableNetOrientationSolver.netLabelConnectorTraceIds
|
|
17822
18544
|
}
|
|
17823
18545
|
];
|
|
17824
18546
|
}
|