@tscircuit/schematic-trace-solver 0.0.187 → 0.0.189
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 +42 -23
- package/dist/index.js +1053 -316
- package/lib/solvers/InlineNetLabelSolver/InlineNetLabelSolver.ts +612 -230
- package/lib/solvers/InlineNetLabelSolver/alignPortOnlyInlineNetLabelStubs.ts +2 -6
- package/lib/solvers/InlineNetLabelSolver/getAnchoredNetLabelRenderedBounds.ts +13 -0
- 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 +94 -16
- package/lib/solvers/NetLabelToTraceSolver/NetLabelToTraceSolver.ts +4 -3
- package/lib/solvers/SameNetJunctionAlignmentSolver/alignSameNetJunctions.ts +7 -7
- package/lib/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver.ts +3 -0
- package/lib/solvers/TraceCleanupSolver/sub-solver/generateLShapeRerouteCandidates.ts +5 -1
- package/lib/types/InputProblem.ts +2 -2
- package/package.json +1 -1
- package/site/SchematicTracePipelineSolver/repro-robot-controller-imu-tof.page.tsx +7 -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-20260730T061837Z/__snapshots__/bug-report-20260730T061837Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260806T093501Z/__snapshots__/bug-report-20260806T093501Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260811T075142Z/__snapshots__/bug-report-20260811T075142Z.snap.svg +18 -18
- package/tests/bug-reports/bug-report-20260819T091818Z/__snapshots__/bug-report-20260819T091818Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260819T091818Z/bug-report-20260819T091818Z.test.ts +21 -0
- package/tests/bug-reports/bug-report-20260825T103621Z/__snapshots__/bug-report-20260825T103621Z.snap.svg +5 -38
- package/tests/bug-reports/bug-report-20260826T072956Z/__snapshots__/bug-report-20260826T072956Z.snap.svg +3 -9
- package/tests/bug-reports/bug-report-20260901T055358Z/__snapshots__/bug-report-20260901T055358Z.snap.svg +18 -30
- package/tests/bug-reports/bug-report-20260901T055358Z/bug-report-20260901T055358Z.test.ts +33 -0
- package/tests/bug-reports/bug-report-20260907T110144Z/__snapshots__/bug-report-20260907T110144Z.snap.svg +282 -0
- package/tests/bug-reports/bug-report-20260907T110144Z/bug-report-20260907T110144Z.json +1073 -0
- package/tests/bug-reports/bug-report-20260907T110144Z/bug-report-20260907T110144Z.test.ts +12 -0
- package/tests/bug-reports/bug-report-20260907T145640Z/__snapshots__/bug-report-20260907T145640Z.snap.svg +1107 -0
- package/tests/bug-reports/bug-report-20260907T145640Z/bug-report-20260907T145640Z.json +3563 -0
- package/tests/bug-reports/bug-report-20260907T145640Z/bug-report-20260907T145640Z.test.ts +117 -0
- package/tests/repros/__snapshots__/repro-battery-management-bq24073.snap.svg +4 -4
- package/tests/repros/__snapshots__/repro-board-648-esp12f-section.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-core-tb67s579ftg-inline-label-routing.snap.svg +20 -20
- package/tests/repros/__snapshots__/repro-esp12f-section.snap.svg +37 -55
- package/tests/repros/__snapshots__/repro-hub-usb-sheet.snap.svg +44 -68
- package/tests/repros/__snapshots__/repro-mspm0l1306-capacitor-symmetry.snap.svg +3 -9
- package/tests/repros/__snapshots__/repro-robot-controller-imu-tof.snap.svg +199 -0
- package/tests/repros/__snapshots__/repro-robot-controller-imu-tof.source.svg +33 -0
- 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/__snapshots__/rp2040-robot-controller-disconnected-gnd.snap.svg +103 -0
- package/tests/repros/assets/repro-robot-controller-imu-tof.input.json +540 -0
- package/tests/repros/assets/rp2040-robot-controller.input.json +349 -0
- 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-robot-controller-imu-tof.test.ts +83 -0
- package/tests/repros/repro-usb-power-vbus-label-detour.test.ts +59 -13
- package/tests/repros/rp2040-robot-controller-disconnected-gnd.test.ts +59 -0
- package/tests/solvers/InlineNetLabelSolver/get-anchored-net-label-rendered-bounds.test.ts +24 -0
- 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/TraceCleanupSolver/perpendicular-detours-preserve-endpoints.test.ts +60 -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 = {}) => {
|
|
@@ -7005,13 +7005,15 @@ var generatePerpendicularTraceDetours = ({
|
|
|
7005
7005
|
bounds2[highBound] + clearance
|
|
7006
7006
|
])
|
|
7007
7007
|
].filter((coordinate) => coordinate !== void 0);
|
|
7008
|
+
const remainingPath = path.slice(index + 2);
|
|
7009
|
+
if (remainingPath.length === 0) remainingPath.push(end);
|
|
7008
7010
|
return [...new Set(detourCoordinates)].map(
|
|
7009
7011
|
(detour) => simplifyPath([
|
|
7010
7012
|
...path.slice(0, index + 1),
|
|
7011
7013
|
{ ...start, [movingAxis]: gate },
|
|
7012
7014
|
{ ...start, [movingAxis]: gate, [detourAxis]: detour },
|
|
7013
7015
|
{ ...end, [detourAxis]: detour },
|
|
7014
|
-
...
|
|
7016
|
+
...remainingPath
|
|
7015
7017
|
])
|
|
7016
7018
|
);
|
|
7017
7019
|
};
|
|
@@ -12400,6 +12402,33 @@ globalConnNetId: ${label.globalConnNetId}`
|
|
|
12400
12402
|
}
|
|
12401
12403
|
};
|
|
12402
12404
|
|
|
12405
|
+
// lib/solvers/InlineNetLabelSolver/getAnchoredNetLabelRenderedBounds.ts
|
|
12406
|
+
var getAnchoredNetLabelRenderedBounds = (placement) => {
|
|
12407
|
+
if (placement.orientation !== "x-" && placement.orientation !== "x+") {
|
|
12408
|
+
if (placement.netLabelText && placement.width > placement.height) {
|
|
12409
|
+
const width2 = placement.height;
|
|
12410
|
+
const height2 = placement.width;
|
|
12411
|
+
const center2 = getCenterFromAnchor(
|
|
12412
|
+
placement.anchorPoint,
|
|
12413
|
+
placement.orientation,
|
|
12414
|
+
width2,
|
|
12415
|
+
height2
|
|
12416
|
+
);
|
|
12417
|
+
return getRectBounds(center2, width2, height2);
|
|
12418
|
+
}
|
|
12419
|
+
return getRectBounds(placement.center, placement.width, placement.height);
|
|
12420
|
+
}
|
|
12421
|
+
const width = Math.max(placement.width, placement.height);
|
|
12422
|
+
const height = NET_LABEL_HORIZONTAL_HEIGHT;
|
|
12423
|
+
const center = getCenterFromAnchor(
|
|
12424
|
+
placement.anchorPoint,
|
|
12425
|
+
placement.orientation,
|
|
12426
|
+
width,
|
|
12427
|
+
height
|
|
12428
|
+
);
|
|
12429
|
+
return getRectBounds(center, width, height);
|
|
12430
|
+
};
|
|
12431
|
+
|
|
12403
12432
|
// lib/solvers/NetLabelNetLabelCollisionSolver/NetLabelNetLabelCollisionSolver.ts
|
|
12404
12433
|
var ANCHOR_TRACE_CLEARANCE = 1e-4;
|
|
12405
12434
|
var SEGMENT_PARALLEL_EPS = 1e-6;
|
|
@@ -12440,6 +12469,19 @@ function sampleAnchorsAlongSegment(a, b) {
|
|
|
12440
12469
|
return anchors;
|
|
12441
12470
|
}
|
|
12442
12471
|
var NetLabelNetLabelCollisionSolver = class extends BaseSolver {
|
|
12472
|
+
constructor(params) {
|
|
12473
|
+
super();
|
|
12474
|
+
this.params = params;
|
|
12475
|
+
this.inputProblem = params.inputProblem;
|
|
12476
|
+
this.traces = params.traces;
|
|
12477
|
+
this.netLabelPlacements = params.netLabelPlacements;
|
|
12478
|
+
this.outputNetLabelPlacements = [...params.netLabelPlacements];
|
|
12479
|
+
this.chipIndex = params.inputProblem._chipObstacleSpatialIndex ?? (params.inputProblem.chips.length > 0 ? new ChipObstacleSpatialIndex(params.inputProblem.chips) : void 0);
|
|
12480
|
+
this.traceMap = Object.fromEntries(
|
|
12481
|
+
params.traces.map((t) => [t.mspPairId, t])
|
|
12482
|
+
);
|
|
12483
|
+
}
|
|
12484
|
+
params;
|
|
12443
12485
|
inputProblem;
|
|
12444
12486
|
traces;
|
|
12445
12487
|
netLabelPlacements;
|
|
@@ -12453,40 +12495,37 @@ var NetLabelNetLabelCollisionSolver = class extends BaseSolver {
|
|
|
12453
12495
|
labelsToTry = [];
|
|
12454
12496
|
candidateQueue = [];
|
|
12455
12497
|
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
12498
|
getConstructorParams() {
|
|
12468
12499
|
return {
|
|
12469
12500
|
inputProblem: this.inputProblem,
|
|
12470
12501
|
traces: this.traces,
|
|
12471
|
-
netLabelPlacements: this.netLabelPlacements
|
|
12502
|
+
netLabelPlacements: this.netLabelPlacements,
|
|
12503
|
+
fixedNetLabelPlacements: this.params.fixedNetLabelPlacements,
|
|
12504
|
+
useRenderedLabelBounds: this.params.useRenderedLabelBounds
|
|
12472
12505
|
};
|
|
12473
12506
|
}
|
|
12474
12507
|
getOutput() {
|
|
12475
12508
|
return { netLabelPlacements: this.outputNetLabelPlacements };
|
|
12476
12509
|
}
|
|
12477
12510
|
labelBounds(label) {
|
|
12478
|
-
|
|
12511
|
+
if (!this.params.useRenderedLabelBounds || this.params.fixedNetLabelPlacements?.includes(label))
|
|
12512
|
+
return getRectBounds(label.center, label.width, label.height);
|
|
12513
|
+
return getAnchoredNetLabelRenderedBounds(label);
|
|
12479
12514
|
}
|
|
12480
12515
|
collisionKey(a, b) {
|
|
12481
12516
|
return [a.globalConnNetId, b.globalConnNetId].sort().join("::");
|
|
12482
12517
|
}
|
|
12483
12518
|
findNextCollidingPair() {
|
|
12484
|
-
const labels =
|
|
12485
|
-
|
|
12519
|
+
const labels = [
|
|
12520
|
+
...this.outputNetLabelPlacements,
|
|
12521
|
+
...this.params.fixedNetLabelPlacements ?? []
|
|
12522
|
+
];
|
|
12523
|
+
for (let i = 0; i < this.outputNetLabelPlacements.length; i++) {
|
|
12486
12524
|
for (let j = i + 1; j < labels.length; j++) {
|
|
12487
12525
|
const a = labels[i];
|
|
12488
12526
|
const b = labels[j];
|
|
12489
|
-
if (a.globalConnNetId === b.globalConnNetId)
|
|
12527
|
+
if (a.globalConnNetId === b.globalConnNetId && !this.params.fixedNetLabelPlacements?.includes(b))
|
|
12528
|
+
continue;
|
|
12490
12529
|
if (this.skippedCollisionKeys.has(this.collisionKey(a, b))) continue;
|
|
12491
12530
|
if (boundsOverlap2(this.labelBounds(a), this.labelBounds(b)))
|
|
12492
12531
|
return [a, b];
|
|
@@ -12526,14 +12565,23 @@ var NetLabelNetLabelCollisionSolver = class extends BaseSolver {
|
|
|
12526
12565
|
center,
|
|
12527
12566
|
width,
|
|
12528
12567
|
height,
|
|
12529
|
-
bounds:
|
|
12568
|
+
bounds: this.params.useRenderedLabelBounds ? getAnchoredNetLabelRenderedBounds({
|
|
12569
|
+
...label,
|
|
12570
|
+
orientation,
|
|
12571
|
+
anchorPoint: anchor,
|
|
12572
|
+
center,
|
|
12573
|
+
width,
|
|
12574
|
+
height
|
|
12575
|
+
}) : getRectBounds(center, width, height),
|
|
12530
12576
|
hostPairId,
|
|
12531
12577
|
hostSegIndex,
|
|
12532
12578
|
status: null
|
|
12533
12579
|
};
|
|
12534
12580
|
};
|
|
12535
|
-
const
|
|
12536
|
-
|
|
12581
|
+
const isAnchoredOnConnector = this.traces.some(
|
|
12582
|
+
(trace) => this.params.netLabelConnectorTraceIds?.has(trace.mspPairId) && trace.globalConnNetId === label.globalConnNetId && tracePathContainsPoint(trace.tracePath, label.anchorPoint)
|
|
12583
|
+
);
|
|
12584
|
+
if (label.mspConnectionPairIds.length === 0 || isAnchoredOnConnector) {
|
|
12537
12585
|
const allOrientations = ["x+", "x-", "y+", "y-"];
|
|
12538
12586
|
const orderedOrientations = [
|
|
12539
12587
|
label.orientation,
|
|
@@ -12578,7 +12626,7 @@ var NetLabelNetLabelCollisionSolver = class extends BaseSolver {
|
|
|
12578
12626
|
}
|
|
12579
12627
|
checkCandidate(candidate, movingLabelNetId, obstacleLabels) {
|
|
12580
12628
|
const { bounds, hostPairId, hostSegIndex } = candidate;
|
|
12581
|
-
if (this.chipIndex
|
|
12629
|
+
if ((this.chipIndex?.getChipsInBounds(bounds).length ?? 0) > 0)
|
|
12582
12630
|
return "chip-collision";
|
|
12583
12631
|
if (rectIntersectsAnyTextBox(bounds, this.inputProblem))
|
|
12584
12632
|
return "text-collision";
|
|
@@ -12586,7 +12634,8 @@ var NetLabelNetLabelCollisionSolver = class extends BaseSolver {
|
|
|
12586
12634
|
return "trace-collision";
|
|
12587
12635
|
}
|
|
12588
12636
|
for (const obstacle of obstacleLabels) {
|
|
12589
|
-
if (obstacle.globalConnNetId === movingLabelNetId)
|
|
12637
|
+
if (obstacle.globalConnNetId === movingLabelNetId && !this.params.fixedNetLabelPlacements?.includes(obstacle))
|
|
12638
|
+
continue;
|
|
12590
12639
|
if (boundsOverlap2(bounds, this.labelBounds(obstacle)))
|
|
12591
12640
|
return "label-collision";
|
|
12592
12641
|
}
|
|
@@ -12598,6 +12647,27 @@ var NetLabelNetLabelCollisionSolver = class extends BaseSolver {
|
|
|
12598
12647
|
this.candidateIndex = 0;
|
|
12599
12648
|
this.candidateResults = [];
|
|
12600
12649
|
}
|
|
12650
|
+
/** Reuse the normal anchor search for a local trace-clearance proposal. */
|
|
12651
|
+
getNearbyValidPlacements(label, maxDistance) {
|
|
12652
|
+
const distance7 = (candidate) => Math.hypot(
|
|
12653
|
+
candidate.anchor.x - label.anchorPoint.x,
|
|
12654
|
+
candidate.anchor.y - label.anchorPoint.y
|
|
12655
|
+
);
|
|
12656
|
+
const obstacles = [
|
|
12657
|
+
...this.outputNetLabelPlacements.filter((other) => other !== label),
|
|
12658
|
+
...this.params.fixedNetLabelPlacements ?? []
|
|
12659
|
+
];
|
|
12660
|
+
return this.buildCandidatesForLabel(label).filter(
|
|
12661
|
+
(candidate) => distance7(candidate) <= maxDistance && this.checkCandidate(candidate, label.globalConnNetId, obstacles) === "ok"
|
|
12662
|
+
).sort((a, b) => distance7(a) - distance7(b)).map((candidate) => ({
|
|
12663
|
+
...label,
|
|
12664
|
+
orientation: candidate.orientation,
|
|
12665
|
+
anchorPoint: candidate.anchor,
|
|
12666
|
+
center: candidate.center,
|
|
12667
|
+
width: candidate.width,
|
|
12668
|
+
height: candidate.height
|
|
12669
|
+
}));
|
|
12670
|
+
}
|
|
12601
12671
|
clearActiveSearch() {
|
|
12602
12672
|
this.currentCollision = null;
|
|
12603
12673
|
this.currentLabelToMove = null;
|
|
@@ -12614,7 +12684,9 @@ var NetLabelNetLabelCollisionSolver = class extends BaseSolver {
|
|
|
12614
12684
|
return;
|
|
12615
12685
|
}
|
|
12616
12686
|
this.currentCollision = pair;
|
|
12617
|
-
this.labelsToTry = [pair[1], pair[0]]
|
|
12687
|
+
this.labelsToTry = [pair[1], pair[0]].filter(
|
|
12688
|
+
(label) => !(this.params.fixedNetLabelPlacements ?? []).includes(label)
|
|
12689
|
+
);
|
|
12618
12690
|
this.beginSearchForLabel(this.labelsToTry.shift());
|
|
12619
12691
|
return;
|
|
12620
12692
|
}
|
|
@@ -12638,9 +12710,10 @@ var NetLabelNetLabelCollisionSolver = class extends BaseSolver {
|
|
|
12638
12710
|
fixedLabel = labelB;
|
|
12639
12711
|
}
|
|
12640
12712
|
const obstacleLabels = [
|
|
12641
|
-
...
|
|
12642
|
-
|
|
12643
|
-
|
|
12713
|
+
...[
|
|
12714
|
+
...this.outputNetLabelPlacements,
|
|
12715
|
+
...this.params.fixedNetLabelPlacements ?? []
|
|
12716
|
+
].filter((l) => l !== labelA && l !== labelB),
|
|
12644
12717
|
fixedLabel
|
|
12645
12718
|
];
|
|
12646
12719
|
const status = this.checkCandidate(
|
|
@@ -13601,8 +13674,10 @@ var getHorizontalPinApproachPoint = ({
|
|
|
13601
13674
|
return approachesFromFacingSide ? approachPoint : null;
|
|
13602
13675
|
};
|
|
13603
13676
|
var getAttachedLabelIndexes = (trace, netLabelPlacements) => netLabelPlacements.flatMap((label, index) => {
|
|
13604
|
-
|
|
13605
|
-
|
|
13677
|
+
if (isLabelAttachedToTrace(label, trace) && tracePathContainsPoint(trace.tracePath, label.anchorPoint)) {
|
|
13678
|
+
return [index];
|
|
13679
|
+
}
|
|
13680
|
+
return [];
|
|
13606
13681
|
});
|
|
13607
13682
|
var moveAttachedLabels = ({
|
|
13608
13683
|
trace,
|
|
@@ -14084,7 +14159,7 @@ var candidateIsClear = ({
|
|
|
14084
14159
|
}
|
|
14085
14160
|
for (const otherTrace of otherNetTraces) {
|
|
14086
14161
|
const countIntersections = (path) => {
|
|
14087
|
-
const
|
|
14162
|
+
const intersections2 = /* @__PURE__ */ new Set();
|
|
14088
14163
|
for (let i = 1; i < path.length; i++) {
|
|
14089
14164
|
for (let j = 1; j < otherTrace.tracePath.length; j++) {
|
|
14090
14165
|
const point = getSegmentIntersection3(
|
|
@@ -14094,10 +14169,10 @@ var candidateIsClear = ({
|
|
|
14094
14169
|
otherTrace.tracePath[j]
|
|
14095
14170
|
);
|
|
14096
14171
|
if (point)
|
|
14097
|
-
|
|
14172
|
+
intersections2.add(`${point.x.toFixed(6)},${point.y.toFixed(6)}`);
|
|
14098
14173
|
}
|
|
14099
14174
|
}
|
|
14100
|
-
return
|
|
14175
|
+
return intersections2.size;
|
|
14101
14176
|
};
|
|
14102
14177
|
if (countIntersections(candidateTrace.tracePath) > countIntersections(originalTrace.tracePath)) {
|
|
14103
14178
|
return false;
|
|
@@ -15027,6 +15102,422 @@ var TraceElbowTransitionSimplificationSolver = class extends BaseSolver {
|
|
|
15027
15102
|
}
|
|
15028
15103
|
};
|
|
15029
15104
|
|
|
15105
|
+
// lib/solvers/InlineNetLabelSolver/getLocalTraceLabelShifts.ts
|
|
15106
|
+
import { getSegmentIntersection as getSegmentIntersection5 } from "@tscircuit/math-utils/line-intersections";
|
|
15107
|
+
|
|
15108
|
+
// lib/solvers/InlineNetLabelSolver/getInlineLabelObstacles.ts
|
|
15109
|
+
var getInlineTerminalBounds = (label) => {
|
|
15110
|
+
if (!label.stubTracePath) return null;
|
|
15111
|
+
const epsilon = 1e-6;
|
|
15112
|
+
return {
|
|
15113
|
+
minX: Math.min(...label.stubTracePath.map((p) => p.x)) - epsilon,
|
|
15114
|
+
maxX: Math.max(...label.stubTracePath.map((p) => p.x)) + epsilon,
|
|
15115
|
+
minY: Math.min(...label.stubTracePath.map((p) => p.y)) - epsilon,
|
|
15116
|
+
maxY: Math.max(...label.stubTracePath.map((p) => p.y)) + epsilon
|
|
15117
|
+
};
|
|
15118
|
+
};
|
|
15119
|
+
var getInlineLabelObstacles = (inputProblem, placements) => {
|
|
15120
|
+
const fixedLabels = placements.map((label) => ({
|
|
15121
|
+
globalConnNetId: label.globalConnNetId,
|
|
15122
|
+
netId: label.netId,
|
|
15123
|
+
pinIds: label.pinIds,
|
|
15124
|
+
mspConnectionPairIds: [],
|
|
15125
|
+
anchorPoint: label.anchorPoint,
|
|
15126
|
+
orientation: "y+",
|
|
15127
|
+
center: label.center,
|
|
15128
|
+
width: label.axis === "x" ? label.width : label.height,
|
|
15129
|
+
height: label.axis === "x" ? label.height : label.width
|
|
15130
|
+
}));
|
|
15131
|
+
const terminalTraces = placements.flatMap((label) => {
|
|
15132
|
+
if (!label.stubTracePath) return [];
|
|
15133
|
+
const chip = inputProblem.chips.find(
|
|
15134
|
+
(chip2) => chip2.pins.some((pin2) => label.pinIds.includes(pin2.pinId))
|
|
15135
|
+
);
|
|
15136
|
+
const pin = chip?.pins.find((pin2) => label.pinIds.includes(pin2.pinId));
|
|
15137
|
+
if (!chip || !pin) return [];
|
|
15138
|
+
const id = JSON.stringify([
|
|
15139
|
+
"inline-terminal",
|
|
15140
|
+
label.globalConnNetId,
|
|
15141
|
+
[...label.pinIds].sort()
|
|
15142
|
+
]);
|
|
15143
|
+
return [
|
|
15144
|
+
{
|
|
15145
|
+
mspPairId: id,
|
|
15146
|
+
mspConnectionPairIds: [id],
|
|
15147
|
+
globalConnNetId: label.globalConnNetId,
|
|
15148
|
+
dcConnNetId: label.globalConnNetId,
|
|
15149
|
+
pinIds: label.pinIds,
|
|
15150
|
+
pins: [
|
|
15151
|
+
{ ...pin, chipId: chip.chipId },
|
|
15152
|
+
{ ...pin, ...label.stubTracePath[1], chipId: chip.chipId }
|
|
15153
|
+
],
|
|
15154
|
+
tracePath: label.stubTracePath
|
|
15155
|
+
}
|
|
15156
|
+
];
|
|
15157
|
+
});
|
|
15158
|
+
return { fixedLabels, terminalTraces };
|
|
15159
|
+
};
|
|
15160
|
+
|
|
15161
|
+
// lib/solvers/InlineNetLabelSolver/getLocalTraceLabelShifts.ts
|
|
15162
|
+
var EPS15 = 1e-6;
|
|
15163
|
+
var CLEARANCE = 0.05;
|
|
15164
|
+
var hits = (path, bounds) => path.slice(1).some((p, i) => segmentIntersectsRect(path[i], p, bounds));
|
|
15165
|
+
var same = (a, b) => Math.hypot(a.x - b.x, a.y - b.y) < EPS15;
|
|
15166
|
+
var translate = (p, axis, distance7) => ({
|
|
15167
|
+
...p,
|
|
15168
|
+
[axis]: p[axis] + distance7
|
|
15169
|
+
});
|
|
15170
|
+
var intersections = (a, b) => a.slice(1).flatMap(
|
|
15171
|
+
(p, i) => b.slice(1).flatMap((q, j) => {
|
|
15172
|
+
const point = getSegmentIntersection5(a[i], p, b[j], q);
|
|
15173
|
+
return point ? [point] : [];
|
|
15174
|
+
})
|
|
15175
|
+
);
|
|
15176
|
+
function* getLocalTraceLabelShifts(inputProblem, output, pendingInlinePlacements = []) {
|
|
15177
|
+
const placements = [
|
|
15178
|
+
...output.inlineNetLabelPlacements,
|
|
15179
|
+
...pendingInlinePlacements
|
|
15180
|
+
];
|
|
15181
|
+
const { fixedLabels, terminalTraces } = getInlineLabelObstacles(
|
|
15182
|
+
inputProblem,
|
|
15183
|
+
placements
|
|
15184
|
+
);
|
|
15185
|
+
const terminalBounds = placements.flatMap((label) => {
|
|
15186
|
+
const bounds = getInlineTerminalBounds(label);
|
|
15187
|
+
return bounds ? [{ label, bounds }] : [];
|
|
15188
|
+
});
|
|
15189
|
+
const obstacles = [
|
|
15190
|
+
...inputProblem.chips.map((chip) => ({
|
|
15191
|
+
minX: chip.center.x - chip.width / 2,
|
|
15192
|
+
maxX: chip.center.x + chip.width / 2,
|
|
15193
|
+
minY: chip.center.y - chip.height / 2,
|
|
15194
|
+
maxY: chip.center.y + chip.height / 2
|
|
15195
|
+
})),
|
|
15196
|
+
...(inputProblem.textBoxes ?? []).map((box) => getTextBoxBounds(box))
|
|
15197
|
+
];
|
|
15198
|
+
const inlineBounds = fixedLabels.map((label) => ({
|
|
15199
|
+
minX: label.center.x - label.width / 2,
|
|
15200
|
+
maxX: label.center.x + label.width / 2,
|
|
15201
|
+
minY: label.center.y - label.height / 2,
|
|
15202
|
+
maxY: label.center.y + label.height / 2
|
|
15203
|
+
}));
|
|
15204
|
+
const pinPositions = [
|
|
15205
|
+
...inputProblem.chips.flatMap((chip) => chip.pins),
|
|
15206
|
+
...output.traces.flatMap((trace) => trace.pins)
|
|
15207
|
+
];
|
|
15208
|
+
for (const trace of output.traces) {
|
|
15209
|
+
const path = simplifyPath(trace.tracePath);
|
|
15210
|
+
for (let i = 0; i < path.length - 1; i++) {
|
|
15211
|
+
const a = path[i], b = path[i + 1];
|
|
15212
|
+
const axis = Math.abs(a.x - b.x) < EPS15 ? "x" : "y";
|
|
15213
|
+
const along = axis === "x" ? "y" : "x";
|
|
15214
|
+
if (Math.abs(a[axis] - b[axis]) > EPS15 || same(a, b)) continue;
|
|
15215
|
+
const blocking = [
|
|
15216
|
+
...output.netLabelPlacements.filter((label) => label.globalConnNetId !== trace.globalConnNetId).map(getAnchoredNetLabelRenderedBounds),
|
|
15217
|
+
...inlineBounds,
|
|
15218
|
+
...terminalBounds.filter(
|
|
15219
|
+
({ label }) => !trace.pinIds.some((pinId) => label.pinIds.includes(pinId))
|
|
15220
|
+
).map(({ bounds }) => bounds)
|
|
15221
|
+
].filter((bounds) => segmentIntersectsRect(a, b, bounds));
|
|
15222
|
+
if (!blocking.length) continue;
|
|
15223
|
+
let low = Math.min(a[along], b[along]);
|
|
15224
|
+
let high = Math.max(a[along], b[along]);
|
|
15225
|
+
let expanded = true;
|
|
15226
|
+
while (expanded) {
|
|
15227
|
+
expanded = false;
|
|
15228
|
+
for (const other of output.traces) {
|
|
15229
|
+
if (other.globalConnNetId !== trace.globalConnNetId) continue;
|
|
15230
|
+
for (let j = 1; j < other.tracePath.length; j++) {
|
|
15231
|
+
const p = other.tracePath[j - 1], q = other.tracePath[j];
|
|
15232
|
+
if (Math.abs(p[axis] - a[axis]) > EPS15 || Math.abs(q[axis] - a[axis]) > EPS15)
|
|
15233
|
+
continue;
|
|
15234
|
+
const min = Math.min(p[along], q[along]), max = Math.max(p[along], q[along]);
|
|
15235
|
+
if (max < low - EPS15 || min > high + EPS15) continue;
|
|
15236
|
+
if (min < low || max > high) expanded = true;
|
|
15237
|
+
low = Math.min(low, min);
|
|
15238
|
+
high = Math.max(high, max);
|
|
15239
|
+
}
|
|
15240
|
+
}
|
|
15241
|
+
}
|
|
15242
|
+
const onRail = (p) => Math.abs(p[axis] - a[axis]) < EPS15 && p[along] >= low - EPS15 && p[along] <= high + EPS15;
|
|
15243
|
+
if (pinPositions.some(onRail)) continue;
|
|
15244
|
+
const minKey = axis === "x" ? "minX" : "minY";
|
|
15245
|
+
const maxKey = axis === "x" ? "maxX" : "maxY";
|
|
15246
|
+
const localWidth = Math.max(
|
|
15247
|
+
...blocking.map((bounds) => bounds[maxKey] - bounds[minKey])
|
|
15248
|
+
);
|
|
15249
|
+
const railLabelBounds = output.netLabelPlacements.filter(
|
|
15250
|
+
(label) => label.globalConnNetId === trace.globalConnNetId && onRail(label.anchorPoint)
|
|
15251
|
+
).map(getAnchoredNetLabelRenderedBounds);
|
|
15252
|
+
const coordinates = [
|
|
15253
|
+
...new Set(
|
|
15254
|
+
blocking.flatMap((bounds) => [
|
|
15255
|
+
bounds[minKey] - CLEARANCE,
|
|
15256
|
+
bounds[maxKey] + CLEARANCE,
|
|
15257
|
+
...railLabelBounds.filter((own) => boundsOverlap(own, bounds)).flatMap((own) => [
|
|
15258
|
+
a[axis] + bounds[minKey] - CLEARANCE - own[maxKey],
|
|
15259
|
+
a[axis] + bounds[maxKey] + CLEARANCE - own[minKey]
|
|
15260
|
+
])
|
|
15261
|
+
])
|
|
15262
|
+
)
|
|
15263
|
+
].sort((x, y) => Math.abs(x - a[axis]) - Math.abs(y - a[axis]));
|
|
15264
|
+
for (const coordinate of coordinates) {
|
|
15265
|
+
const distance7 = coordinate - a[axis];
|
|
15266
|
+
if (Math.abs(distance7) > localWidth + 2 * CLEARANCE) continue;
|
|
15267
|
+
const traces = output.traces.map((other) => {
|
|
15268
|
+
if (other.globalConnNetId !== trace.globalConnNetId || !other.tracePath.some(onRail))
|
|
15269
|
+
return other;
|
|
15270
|
+
return {
|
|
15271
|
+
...other,
|
|
15272
|
+
tracePath: other.tracePath.map(
|
|
15273
|
+
(p) => onRail(p) ? translate(p, axis, distance7) : p
|
|
15274
|
+
)
|
|
15275
|
+
};
|
|
15276
|
+
});
|
|
15277
|
+
const shiftedPaths = traces.filter((other, index) => other !== output.traces[index]).map((other) => other.tracePath);
|
|
15278
|
+
let labels = output.netLabelPlacements.map((label) => {
|
|
15279
|
+
if (label.globalConnNetId !== trace.globalConnNetId || !onRail(label.anchorPoint))
|
|
15280
|
+
return label;
|
|
15281
|
+
return {
|
|
15282
|
+
...label,
|
|
15283
|
+
anchorPoint: translate(label.anchorPoint, axis, distance7),
|
|
15284
|
+
center: translate(label.center, axis, distance7)
|
|
15285
|
+
};
|
|
15286
|
+
});
|
|
15287
|
+
let blocked = false;
|
|
15288
|
+
const movedOwnLabelBounds = labels.flatMap(
|
|
15289
|
+
(label, index) => label !== output.netLabelPlacements[index] ? [getAnchoredNetLabelRenderedBounds(label)] : []
|
|
15290
|
+
);
|
|
15291
|
+
for (const [labelIndex, label] of labels.entries()) {
|
|
15292
|
+
if (label.globalConnNetId === trace.globalConnNetId) continue;
|
|
15293
|
+
const bounds = getAnchoredNetLabelRenderedBounds(label);
|
|
15294
|
+
const clearanceEdges = movedOwnLabelBounds.filter((own) => boundsOverlap(own, bounds)).map((own) => own[distance7 > 0 ? maxKey : minKey]);
|
|
15295
|
+
if (shiftedPaths.some((p) => hits(p, bounds)) && !output.traces.some(
|
|
15296
|
+
(other) => other.globalConnNetId === trace.globalConnNetId && hits(other.tracePath, bounds)
|
|
15297
|
+
))
|
|
15298
|
+
clearanceEdges.push(coordinate);
|
|
15299
|
+
if (!clearanceEdges.length) continue;
|
|
15300
|
+
const connectorIndex = traces.findIndex(
|
|
15301
|
+
(candidate) => candidate.globalConnNetId === label.globalConnNetId && candidate.pinIds.length === 1 && candidate.tracePath.length === 3 && same(candidate.tracePath.at(-1), label.anchorPoint)
|
|
15302
|
+
);
|
|
15303
|
+
const connector = traces[connectorIndex];
|
|
15304
|
+
if (!connector) {
|
|
15305
|
+
const placementSolver = new NetLabelNetLabelCollisionSolver({
|
|
15306
|
+
inputProblem,
|
|
15307
|
+
traces: [...traces, ...terminalTraces],
|
|
15308
|
+
netLabelPlacements: labels,
|
|
15309
|
+
fixedNetLabelPlacements: fixedLabels,
|
|
15310
|
+
useRenderedLabelBounds: true
|
|
15311
|
+
});
|
|
15312
|
+
const nearby = placementSolver.getNearbyValidPlacements(
|
|
15313
|
+
label,
|
|
15314
|
+
localWidth + Math.max(label.width, label.height)
|
|
15315
|
+
)[0];
|
|
15316
|
+
if (!nearby) {
|
|
15317
|
+
blocked = true;
|
|
15318
|
+
break;
|
|
15319
|
+
}
|
|
15320
|
+
labels[labelIndex] = nearby;
|
|
15321
|
+
continue;
|
|
15322
|
+
}
|
|
15323
|
+
const [start, bend, end] = connector.tracePath;
|
|
15324
|
+
if (Math.abs(bend[axis] - end[axis]) > EPS15 || Math.abs(start[along] - bend[along]) > EPS15) {
|
|
15325
|
+
blocked = true;
|
|
15326
|
+
break;
|
|
15327
|
+
}
|
|
15328
|
+
const delta = distance7 > 0 ? Math.max(...clearanceEdges) + CLEARANCE - bounds[minKey] : Math.min(...clearanceEdges) - CLEARANCE - bounds[maxKey];
|
|
15329
|
+
if (Math.abs(delta) > localWidth + bounds[maxKey] - bounds[minKey] + 2 * CLEARANCE) {
|
|
15330
|
+
blocked = true;
|
|
15331
|
+
break;
|
|
15332
|
+
}
|
|
15333
|
+
const moved = {
|
|
15334
|
+
...label,
|
|
15335
|
+
anchorPoint: translate(label.anchorPoint, axis, delta),
|
|
15336
|
+
center: translate(label.center, axis, delta)
|
|
15337
|
+
};
|
|
15338
|
+
labels[labelIndex] = moved;
|
|
15339
|
+
traces[connectorIndex] = {
|
|
15340
|
+
...connector,
|
|
15341
|
+
tracePath: [start, translate(bend, axis, delta), moved.anchorPoint]
|
|
15342
|
+
};
|
|
15343
|
+
}
|
|
15344
|
+
if (blocked) continue;
|
|
15345
|
+
for (const [index, proposed] of traces.entries()) {
|
|
15346
|
+
const original = output.traces[index];
|
|
15347
|
+
if (proposed === original) continue;
|
|
15348
|
+
const candidate = proposed.tracePath;
|
|
15349
|
+
const previous = original.tracePath;
|
|
15350
|
+
if (candidate.slice(1).some(
|
|
15351
|
+
(p, index2) => Math.abs(p.x - candidate[index2].x) > EPS15 && Math.abs(p.y - candidate[index2].y) > EPS15
|
|
15352
|
+
)) {
|
|
15353
|
+
blocked = true;
|
|
15354
|
+
break;
|
|
15355
|
+
}
|
|
15356
|
+
const dot = (a2, b2, c, d) => (b2.x - a2.x) * (d.x - c.x) + (b2.y - a2.y) * (d.y - c.y);
|
|
15357
|
+
if (dot(previous[0], previous[1], candidate[0], candidate[1]) <= EPS15 || dot(
|
|
15358
|
+
previous.at(-1),
|
|
15359
|
+
previous.at(-2),
|
|
15360
|
+
candidate.at(-1),
|
|
15361
|
+
candidate.at(-2)
|
|
15362
|
+
) <= EPS15) {
|
|
15363
|
+
blocked = true;
|
|
15364
|
+
break;
|
|
15365
|
+
}
|
|
15366
|
+
const junctions = output.traces.filter(
|
|
15367
|
+
(other) => other !== original && other.globalConnNetId === original.globalConnNetId
|
|
15368
|
+
).flatMap((other) => [
|
|
15369
|
+
...other.tracePath,
|
|
15370
|
+
...intersections(previous, other.tracePath)
|
|
15371
|
+
]).filter((p) => tracePathContainsPoint(previous, p)).map(
|
|
15372
|
+
(p) => original.globalConnNetId === trace.globalConnNetId && onRail(p) ? translate(p, axis, distance7) : p
|
|
15373
|
+
);
|
|
15374
|
+
const protectedPoints = [
|
|
15375
|
+
...pinPositions.filter((p) => tracePathContainsPoint(previous, p)),
|
|
15376
|
+
...junctions
|
|
15377
|
+
];
|
|
15378
|
+
if (protectedPoints.some(
|
|
15379
|
+
(p) => !tracePathContainsPoint(candidate, p)
|
|
15380
|
+
) || pinPositions.some((p) => {
|
|
15381
|
+
const clearance = {
|
|
15382
|
+
minX: p.x - CLEARANCE,
|
|
15383
|
+
maxX: p.x + CLEARANCE,
|
|
15384
|
+
minY: p.y - CLEARANCE,
|
|
15385
|
+
maxY: p.y + CLEARANCE
|
|
15386
|
+
};
|
|
15387
|
+
return hits(candidate, clearance) && !hits(previous, clearance);
|
|
15388
|
+
}) || obstacles.some(
|
|
15389
|
+
(bounds) => hits(candidate, bounds) && !hits(previous, bounds)
|
|
15390
|
+
)) {
|
|
15391
|
+
blocked = true;
|
|
15392
|
+
break;
|
|
15393
|
+
}
|
|
15394
|
+
for (const other of [...traces, ...terminalTraces]) {
|
|
15395
|
+
if (other.mspPairId === proposed.mspPairId || other.globalConnNetId === proposed.globalConnNetId)
|
|
15396
|
+
continue;
|
|
15397
|
+
const originalOther = output.traces.find((t) => t.mspPairId === other.mspPairId) ?? other;
|
|
15398
|
+
if (doesPathCoincideWithTraces(candidate, [other]) || intersections(candidate, other.tracePath).length > intersections(previous, originalOther.tracePath).length) {
|
|
15399
|
+
blocked = true;
|
|
15400
|
+
break;
|
|
15401
|
+
}
|
|
15402
|
+
}
|
|
15403
|
+
if (blocked) break;
|
|
15404
|
+
}
|
|
15405
|
+
if (blocked) continue;
|
|
15406
|
+
for (const [index, label] of labels.entries()) {
|
|
15407
|
+
if (label === output.netLabelPlacements[index]) continue;
|
|
15408
|
+
const bounds = getAnchoredNetLabelRenderedBounds(label);
|
|
15409
|
+
if (obstacles.some((obstacle) => boundsOverlap(bounds, obstacle)) || inlineBounds.some((other) => boundsOverlap(bounds, other))) {
|
|
15410
|
+
blocked = true;
|
|
15411
|
+
break;
|
|
15412
|
+
}
|
|
15413
|
+
if (labels.some(
|
|
15414
|
+
(other, j) => index !== j && boundsOverlap(bounds, getAnchoredNetLabelRenderedBounds(other))
|
|
15415
|
+
)) {
|
|
15416
|
+
blocked = true;
|
|
15417
|
+
break;
|
|
15418
|
+
}
|
|
15419
|
+
if ([...traces, ...terminalTraces].some(
|
|
15420
|
+
(other) => other.globalConnNetId !== label.globalConnNetId && hits(other.tracePath, bounds)
|
|
15421
|
+
)) {
|
|
15422
|
+
blocked = true;
|
|
15423
|
+
break;
|
|
15424
|
+
}
|
|
15425
|
+
}
|
|
15426
|
+
if (!blocked) yield { ...output, traces, netLabelPlacements: labels };
|
|
15427
|
+
}
|
|
15428
|
+
}
|
|
15429
|
+
}
|
|
15430
|
+
}
|
|
15431
|
+
|
|
15432
|
+
// lib/solvers/InlineNetLabelSolver/getOutputLabelCollisions.ts
|
|
15433
|
+
var sameLabel = (a, b) => {
|
|
15434
|
+
const first = [...a.pinIds].sort();
|
|
15435
|
+
const second = [...b.pinIds].sort();
|
|
15436
|
+
return a.globalConnNetId === b.globalConnNetId && first.length === second.length && first.every((pinId, index) => pinId === second[index]);
|
|
15437
|
+
};
|
|
15438
|
+
var sameOutputLabelCollision = (a, b) => {
|
|
15439
|
+
if (a.kind === "label-label" && b.kind === "label-label")
|
|
15440
|
+
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]);
|
|
15441
|
+
if (a.kind !== "trace-label" || b.kind !== "trace-label") return false;
|
|
15442
|
+
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);
|
|
15443
|
+
return sameTrace && a.target === b.target && sameLabel(a.label, b.label);
|
|
15444
|
+
};
|
|
15445
|
+
var getOutputLabelCollisions = (output) => {
|
|
15446
|
+
const labels = [
|
|
15447
|
+
...output.netLabelPlacements,
|
|
15448
|
+
...output.inlineNetLabelPlacements
|
|
15449
|
+
].map((label) => ({
|
|
15450
|
+
label,
|
|
15451
|
+
bounds: "axis" in label ? {
|
|
15452
|
+
minX: label.center.x - (label.axis === "x" ? label.width : label.height) / 2,
|
|
15453
|
+
maxX: label.center.x + (label.axis === "x" ? label.width : label.height) / 2,
|
|
15454
|
+
minY: label.center.y - (label.axis === "x" ? label.height : label.width) / 2,
|
|
15455
|
+
maxY: label.center.y + (label.axis === "x" ? label.height : label.width) / 2
|
|
15456
|
+
} : getAnchoredNetLabelRenderedBounds(label)
|
|
15457
|
+
}));
|
|
15458
|
+
const collisions = [];
|
|
15459
|
+
const add = (collision) => {
|
|
15460
|
+
if (!collisions.some((other) => sameOutputLabelCollision(collision, other)))
|
|
15461
|
+
collisions.push(collision);
|
|
15462
|
+
};
|
|
15463
|
+
for (let i = 0; i < labels.length; i++)
|
|
15464
|
+
for (const other of labels.slice(i + 1)) {
|
|
15465
|
+
if (boundsOverlap(labels[i].bounds, other.bounds))
|
|
15466
|
+
add({ kind: "label-label", labels: [labels[i].label, other.label] });
|
|
15467
|
+
}
|
|
15468
|
+
const traces = [
|
|
15469
|
+
...output.traces.map((trace) => ({
|
|
15470
|
+
...trace,
|
|
15471
|
+
identity: { kind: "routed", id: trace.mspPairId }
|
|
15472
|
+
})),
|
|
15473
|
+
...output.inlineNetLabelPlacements.flatMap(
|
|
15474
|
+
(label) => label.stubTracePath ? [
|
|
15475
|
+
{
|
|
15476
|
+
identity: { kind: "terminal", label },
|
|
15477
|
+
globalConnNetId: label.globalConnNetId,
|
|
15478
|
+
tracePath: label.stubTracePath
|
|
15479
|
+
}
|
|
15480
|
+
] : []
|
|
15481
|
+
)
|
|
15482
|
+
];
|
|
15483
|
+
for (const trace of traces)
|
|
15484
|
+
for (const { label, bounds } of labels) {
|
|
15485
|
+
if (("axis" in label || label.globalConnNetId !== trace.globalConnNetId) && trace.tracePath.slice(1).some(
|
|
15486
|
+
(end, index) => segmentIntersectsRect(trace.tracePath[index], end, bounds)
|
|
15487
|
+
))
|
|
15488
|
+
add({
|
|
15489
|
+
kind: "trace-label",
|
|
15490
|
+
trace: trace.identity,
|
|
15491
|
+
label,
|
|
15492
|
+
target: "text"
|
|
15493
|
+
});
|
|
15494
|
+
}
|
|
15495
|
+
for (const label of output.inlineNetLabelPlacements) {
|
|
15496
|
+
const bounds = getInlineTerminalBounds(label);
|
|
15497
|
+
if (!bounds) continue;
|
|
15498
|
+
for (const trace of output.traces) {
|
|
15499
|
+
if (trace.pinIds.some((pinId) => label.pinIds.includes(pinId))) continue;
|
|
15500
|
+
if (trace.tracePath.slice(1).some(
|
|
15501
|
+
(end, index) => segmentIntersectsRect(trace.tracePath[index], end, bounds)
|
|
15502
|
+
))
|
|
15503
|
+
add({
|
|
15504
|
+
kind: "trace-label",
|
|
15505
|
+
trace: { kind: "routed", id: trace.mspPairId },
|
|
15506
|
+
label,
|
|
15507
|
+
target: "terminal"
|
|
15508
|
+
});
|
|
15509
|
+
}
|
|
15510
|
+
}
|
|
15511
|
+
return collisions;
|
|
15512
|
+
};
|
|
15513
|
+
|
|
15514
|
+
// lib/solvers/InlineNetLabelSolver/isLabelRepresentedInline.ts
|
|
15515
|
+
var isLabelRepresentedInline = (label, inlinePlacements) => label.pinIds.length > 0 && label.pinIds.every(
|
|
15516
|
+
(pinId) => inlinePlacements.some(
|
|
15517
|
+
(inline) => inline.globalConnNetId === label.globalConnNetId && inline.pinIds.includes(pinId)
|
|
15518
|
+
)
|
|
15519
|
+
);
|
|
15520
|
+
|
|
15030
15521
|
// lib/solvers/InlineNetLabelSolver/alignPortOnlyInlineNetLabelStubs.ts
|
|
15031
15522
|
var getStubDirection = (path) => {
|
|
15032
15523
|
const [start, end] = path;
|
|
@@ -15102,12 +15593,7 @@ var alignPortOnlyInlineNetLabelStubs = ({
|
|
|
15102
15593
|
groups.set(groupKey, group);
|
|
15103
15594
|
}
|
|
15104
15595
|
const alignedPlacements = [...placements];
|
|
15105
|
-
const
|
|
15106
|
-
placements.map((placement) => placement.globalConnNetId)
|
|
15107
|
-
);
|
|
15108
|
-
const retainedAnchoredLabelBounds = netLabelPlacements.filter(
|
|
15109
|
-
(placement) => !supersededGlobalNetIds.has(placement.globalConnNetId)
|
|
15110
|
-
).map(getLabelBounds2);
|
|
15596
|
+
const retainedAnchoredLabelBounds = netLabelPlacements.filter((placement) => !isLabelRepresentedInline(placement, placements)).map(getLabelBounds2);
|
|
15111
15597
|
for (const group of groups.values()) {
|
|
15112
15598
|
if (group.length < 2) continue;
|
|
15113
15599
|
const targetLength = Math.max(
|
|
@@ -15216,22 +15702,6 @@ var getAxisAlignedSegments2 = (path, epsilon = 1e-6) => {
|
|
|
15216
15702
|
return segments.sort((a, b) => b.length - a.length);
|
|
15217
15703
|
};
|
|
15218
15704
|
|
|
15219
|
-
// lib/solvers/InlineNetLabelSolver/getAnchoredNetLabelRenderedBounds.ts
|
|
15220
|
-
var getAnchoredNetLabelRenderedBounds = (placement) => {
|
|
15221
|
-
if (placement.orientation !== "x-" && placement.orientation !== "x+") {
|
|
15222
|
-
return getRectBounds(placement.center, placement.width, placement.height);
|
|
15223
|
-
}
|
|
15224
|
-
const width = Math.max(placement.width, placement.height);
|
|
15225
|
-
const height = NET_LABEL_HORIZONTAL_HEIGHT;
|
|
15226
|
-
const center = getCenterFromAnchor(
|
|
15227
|
-
placement.anchorPoint,
|
|
15228
|
-
placement.orientation,
|
|
15229
|
-
width,
|
|
15230
|
-
height
|
|
15231
|
-
);
|
|
15232
|
-
return getRectBounds(center, width, height);
|
|
15233
|
-
};
|
|
15234
|
-
|
|
15235
15705
|
// lib/solvers/InlineNetLabelSolver/pushAnchoredNetLabelsAwayFromInlineLabels.ts
|
|
15236
15706
|
var LABEL_CLEARANCE2 = 0.05;
|
|
15237
15707
|
var POINT_EPSILON = 1e-6;
|
|
@@ -15279,29 +15749,37 @@ var isPointOnPath2 = (point, path) => {
|
|
|
15279
15749
|
return false;
|
|
15280
15750
|
};
|
|
15281
15751
|
var getRequiredOutwardDistance = (label, inlineBounds) => {
|
|
15282
|
-
|
|
15283
|
-
|
|
15284
|
-
const
|
|
15285
|
-
(
|
|
15752
|
+
let distance7 = 0;
|
|
15753
|
+
for (let iteration = 0; iteration < inlineBounds.length; iteration++) {
|
|
15754
|
+
const labelBounds = getAnchoredNetLabelRenderedBounds(
|
|
15755
|
+
moveLabel(label, label.orientation, distance7)
|
|
15286
15756
|
);
|
|
15287
|
-
|
|
15288
|
-
|
|
15289
|
-
|
|
15290
|
-
|
|
15757
|
+
const horizontal = label.orientation === "x-" || label.orientation === "x+";
|
|
15758
|
+
const overlapping = inlineBounds.filter(
|
|
15759
|
+
(bounds) => boundsOverlap(labelBounds, {
|
|
15760
|
+
minX: bounds.minX - (horizontal ? LABEL_CLEARANCE2 : 0),
|
|
15761
|
+
maxX: bounds.maxX + (horizontal ? LABEL_CLEARANCE2 : 0),
|
|
15762
|
+
minY: bounds.minY - (horizontal ? 0 : LABEL_CLEARANCE2),
|
|
15763
|
+
maxY: bounds.maxY + (horizontal ? 0 : LABEL_CLEARANCE2)
|
|
15764
|
+
})
|
|
15765
|
+
);
|
|
15766
|
+
if (overlapping.length === 0) break;
|
|
15767
|
+
switch (label.orientation) {
|
|
15768
|
+
case "x-":
|
|
15769
|
+
distance7 += labelBounds.maxX - Math.min(...overlapping.map((b) => b.minX)) + LABEL_CLEARANCE2;
|
|
15770
|
+
break;
|
|
15771
|
+
case "x+":
|
|
15772
|
+
distance7 += Math.max(...overlapping.map((b) => b.maxX)) - labelBounds.minX + LABEL_CLEARANCE2;
|
|
15773
|
+
break;
|
|
15774
|
+
case "y-":
|
|
15775
|
+
distance7 += labelBounds.maxY - Math.min(...overlapping.map((b) => b.minY)) + LABEL_CLEARANCE2;
|
|
15776
|
+
break;
|
|
15777
|
+
case "y+":
|
|
15778
|
+
distance7 += Math.max(...overlapping.map((b) => b.maxY)) - labelBounds.minY + LABEL_CLEARANCE2;
|
|
15779
|
+
break;
|
|
15291
15780
|
}
|
|
15292
|
-
const targetMinX = Math.max(...nearby2.map((bounds) => bounds.maxX));
|
|
15293
|
-
return Math.max(0, targetMinX - labelBounds.minX + LABEL_CLEARANCE2);
|
|
15294
15781
|
}
|
|
15295
|
-
|
|
15296
|
-
(bounds) => labelBounds.minX < bounds.maxX && labelBounds.maxX > bounds.minX
|
|
15297
|
-
);
|
|
15298
|
-
if (nearby.length === 0) return 0;
|
|
15299
|
-
if (label.orientation === "y-") {
|
|
15300
|
-
const targetMaxY = Math.min(...nearby.map((bounds) => bounds.minY));
|
|
15301
|
-
return Math.max(0, labelBounds.maxY - targetMaxY + LABEL_CLEARANCE2);
|
|
15302
|
-
}
|
|
15303
|
-
const targetMinY = Math.max(...nearby.map((bounds) => bounds.maxY));
|
|
15304
|
-
return Math.max(0, targetMinY - labelBounds.minY + LABEL_CLEARANCE2);
|
|
15782
|
+
return distance7;
|
|
15305
15783
|
};
|
|
15306
15784
|
var moveLabel = (label, orientation, distance7) => {
|
|
15307
15785
|
const direction = dir(orientation);
|
|
@@ -15336,10 +15814,9 @@ var boundsGapOnPerpendicularAxis = (a, b, orientation) => {
|
|
|
15336
15814
|
return Math.max(0, a.minX - b.maxX, b.minX - a.maxX);
|
|
15337
15815
|
};
|
|
15338
15816
|
var sharesOwnerChip = (label, ownerChipIds, chipIdByPinId) => label.pinIds.some((pinId) => ownerChipIds.has(chipIdByPinId.get(pinId) ?? ""));
|
|
15339
|
-
var
|
|
15340
|
-
var findConnectorTraceIndex = (label, traces) => traces.findIndex((trace) => {
|
|
15817
|
+
var findConnectorTraceIndex = (label, traces, connectorTraceIds) => traces.findIndex((trace) => {
|
|
15341
15818
|
if (trace.globalConnNetId !== label.globalConnNetId) return false;
|
|
15342
|
-
if (!
|
|
15819
|
+
if (!connectorTraceIds.has(trace.mspPairId)) return false;
|
|
15343
15820
|
const first = trace.tracePath[0];
|
|
15344
15821
|
const last = trace.tracePath.at(-1);
|
|
15345
15822
|
return Boolean(
|
|
@@ -15422,8 +15899,10 @@ var pushAnchoredNetLabelsAwayFromInlineLabels = ({
|
|
|
15422
15899
|
inputProblem,
|
|
15423
15900
|
traces,
|
|
15424
15901
|
netLabelPlacements,
|
|
15425
|
-
inlineNetLabelPlacements
|
|
15902
|
+
inlineNetLabelPlacements,
|
|
15903
|
+
netLabelConnectorTraceIds = /* @__PURE__ */ new Set()
|
|
15426
15904
|
}) => {
|
|
15905
|
+
const connectorTraceIds = new Set(netLabelConnectorTraceIds);
|
|
15427
15906
|
const outputTraces = traces.map((trace) => ({
|
|
15428
15907
|
...trace,
|
|
15429
15908
|
tracePath: trace.tracePath.map((point) => ({ ...point }))
|
|
@@ -15467,7 +15946,11 @@ var pushAnchoredNetLabelsAwayFromInlineLabels = ({
|
|
|
15467
15946
|
moveLabel(obstacle, trigger.orientation, existingObstacleDistance)
|
|
15468
15947
|
);
|
|
15469
15948
|
if (!boundsOverlap(movingBounds, obstacleBounds)) continue;
|
|
15470
|
-
if (!sharesOwnerChip(obstacle, ownerChipIds, chipIdByPinId) || findConnectorTraceIndex(
|
|
15949
|
+
if (!sharesOwnerChip(obstacle, ownerChipIds, chipIdByPinId) || findConnectorTraceIndex(
|
|
15950
|
+
obstacle,
|
|
15951
|
+
outputTraces,
|
|
15952
|
+
connectorTraceIds
|
|
15953
|
+
) === -1 && !canAddConnectorAtAnchor(obstacle, outputTraces, pinMap)) {
|
|
15471
15954
|
failed = true;
|
|
15472
15955
|
break;
|
|
15473
15956
|
}
|
|
@@ -15539,7 +16022,11 @@ var pushAnchoredNetLabelsAwayFromInlineLabels = ({
|
|
|
15539
16022
|
const connectorUpdates = [];
|
|
15540
16023
|
for (const [labelIndex, movedLabel] of proposals) {
|
|
15541
16024
|
const label = outputLabels[labelIndex];
|
|
15542
|
-
const connectorIndex = findConnectorTraceIndex(
|
|
16025
|
+
const connectorIndex = findConnectorTraceIndex(
|
|
16026
|
+
label,
|
|
16027
|
+
outputTraces,
|
|
16028
|
+
connectorTraceIds
|
|
16029
|
+
);
|
|
15543
16030
|
if (connectorIndex === -1 && !canAddConnectorAtAnchor(label, outputTraces, pinMap)) {
|
|
15544
16031
|
failed = true;
|
|
15545
16032
|
break;
|
|
@@ -15589,6 +16076,7 @@ var pushAnchoredNetLabelsAwayFromInlineLabels = ({
|
|
|
15589
16076
|
movedLabelIndices.add(labelIndex);
|
|
15590
16077
|
}
|
|
15591
16078
|
for (const update of connectorUpdates) {
|
|
16079
|
+
connectorTraceIds.add(update.trace.mspPairId);
|
|
15592
16080
|
if (update.connectorIndex === -1) outputTraces.push(update.trace);
|
|
15593
16081
|
else outputTraces[update.connectorIndex] = update.trace;
|
|
15594
16082
|
}
|
|
@@ -15596,7 +16084,8 @@ var pushAnchoredNetLabelsAwayFromInlineLabels = ({
|
|
|
15596
16084
|
return {
|
|
15597
16085
|
traces: outputTraces,
|
|
15598
16086
|
netLabelPlacements: outputLabels,
|
|
15599
|
-
movedLabelCount: movedLabelIndices.size
|
|
16087
|
+
movedLabelCount: movedLabelIndices.size,
|
|
16088
|
+
netLabelConnectorTraceIds: connectorTraceIds
|
|
15600
16089
|
};
|
|
15601
16090
|
};
|
|
15602
16091
|
|
|
@@ -15798,7 +16287,7 @@ var pushInlineTerminalLabelsAwayFromAnchoredLabels = ({
|
|
|
15798
16287
|
};
|
|
15799
16288
|
|
|
15800
16289
|
// lib/solvers/InlineNetLabelSolver/restoreReroutesAroundSupersededLabels.ts
|
|
15801
|
-
import { getSegmentIntersection as
|
|
16290
|
+
import { getSegmentIntersection as getSegmentIntersection6 } from "@tscircuit/math-utils/line-intersections";
|
|
15802
16291
|
|
|
15803
16292
|
// lib/utils/pathIntersectsRenderedLabel.ts
|
|
15804
16293
|
import {
|
|
@@ -15826,31 +16315,31 @@ var pathIntersectsRenderedLabel = (path, label) => {
|
|
|
15826
16315
|
};
|
|
15827
16316
|
|
|
15828
16317
|
// lib/solvers/InlineNetLabelSolver/restoreReroutesAroundSupersededLabels.ts
|
|
15829
|
-
var
|
|
16318
|
+
var EPS16 = 1e-6;
|
|
15830
16319
|
var getPathLength7 = (path) => path.slice(1).reduce((length, point, pointIndex) => {
|
|
15831
16320
|
const previousPoint = path[pointIndex];
|
|
15832
16321
|
return length + Math.abs(point.x - previousPoint.x) + Math.abs(point.y - previousPoint.y);
|
|
15833
16322
|
}, 0);
|
|
15834
16323
|
var pathsEqual = (first, second) => first.length === second.length && first.every(
|
|
15835
|
-
(point, index) => Math.abs(point.x - second[index].x) <=
|
|
16324
|
+
(point, index) => Math.abs(point.x - second[index].x) <= EPS16 && Math.abs(point.y - second[index].y) <= EPS16
|
|
15836
16325
|
);
|
|
15837
|
-
var isStrictlySimpler = (candidate, current) => candidate.length < current.length && getPathLength7(candidate) <= getPathLength7(current) +
|
|
16326
|
+
var isStrictlySimpler = (candidate, current) => candidate.length < current.length && getPathLength7(candidate) <= getPathLength7(current) + EPS16;
|
|
15838
16327
|
var getIntersectionKeys = (path, otherPath) => {
|
|
15839
|
-
const
|
|
16328
|
+
const intersections2 = /* @__PURE__ */ new Set();
|
|
15840
16329
|
for (let pathIndex = 0; pathIndex < path.length - 1; pathIndex++) {
|
|
15841
16330
|
for (let otherPathIndex = 0; otherPathIndex < otherPath.length - 1; otherPathIndex++) {
|
|
15842
|
-
const point =
|
|
16331
|
+
const point = getSegmentIntersection6(
|
|
15843
16332
|
path[pathIndex],
|
|
15844
16333
|
path[pathIndex + 1],
|
|
15845
16334
|
otherPath[otherPathIndex],
|
|
15846
16335
|
otherPath[otherPathIndex + 1]
|
|
15847
16336
|
);
|
|
15848
16337
|
if (point) {
|
|
15849
|
-
|
|
16338
|
+
intersections2.add(`${point.x.toFixed(6)},${point.y.toFixed(6)}`);
|
|
15850
16339
|
}
|
|
15851
16340
|
}
|
|
15852
16341
|
}
|
|
15853
|
-
return
|
|
16342
|
+
return intersections2;
|
|
15854
16343
|
};
|
|
15855
16344
|
var introducesNewCrossings = (candidatePath, currentPath, otherPaths) => otherPaths.some((otherPath) => {
|
|
15856
16345
|
const currentIntersections = getIntersectionKeys(currentPath, otherPath);
|
|
@@ -15927,9 +16416,7 @@ var DEFAULT_INLINE_NET_LABEL_HEIGHT = 0.18;
|
|
|
15927
16416
|
var INLINE_NET_LABEL_TRACE_MARGIN = 0.05;
|
|
15928
16417
|
var INLINE_NET_LABEL_STUB_TRACE_CLEARANCE = 0.05;
|
|
15929
16418
|
var INLINE_NET_LABEL_MAX_SPAN_JOG = 0.4;
|
|
15930
|
-
var
|
|
15931
|
-
var isGeneratedAnchoredLabelConnector = (trace) => trace.mspPairId.startsWith(AVAILABLE_NET_ORIENTATION_TRACE_PREFIX);
|
|
15932
|
-
var getPinPairKey2 = (pinIds) => [...pinIds].sort().join("::");
|
|
16419
|
+
var getPinPairKey2 = (pinIds) => JSON.stringify([...pinIds].sort());
|
|
15933
16420
|
var getTraceLength2 = (trace) => {
|
|
15934
16421
|
let length = 0;
|
|
15935
16422
|
for (let index = 0; index < trace.tracePath.length - 1; index++) {
|
|
@@ -15950,21 +16437,26 @@ var getInlinePlacementBounds = (placement) => {
|
|
|
15950
16437
|
maxY: placement.center.y + renderedHeight / 2
|
|
15951
16438
|
};
|
|
15952
16439
|
};
|
|
15953
|
-
var
|
|
15954
|
-
|
|
15955
|
-
|
|
15956
|
-
|
|
15957
|
-
|
|
15958
|
-
|
|
15959
|
-
|
|
15960
|
-
|
|
15961
|
-
|
|
15962
|
-
|
|
15963
|
-
|
|
15964
|
-
|
|
15965
|
-
|
|
16440
|
+
var getInlinePlacementKey = (placement) => JSON.stringify([
|
|
16441
|
+
placement.globalConnNetId,
|
|
16442
|
+
[...placement.pinIds].sort(),
|
|
16443
|
+
placement.mspPairId ?? null
|
|
16444
|
+
]);
|
|
16445
|
+
var terminalStubIntersectsTrace = (path, trace) => {
|
|
16446
|
+
const clearance = INLINE_NET_LABEL_STUB_TRACE_CLEARANCE - GEOMETRY_EPSILON;
|
|
16447
|
+
const bounds = {
|
|
16448
|
+
minX: Math.min(path[0].x, path[1].x) - clearance,
|
|
16449
|
+
maxX: Math.max(path[0].x, path[1].x) + clearance,
|
|
16450
|
+
minY: Math.min(path[0].y, path[1].y) - clearance,
|
|
16451
|
+
maxY: Math.max(path[0].y, path[1].y) + clearance
|
|
16452
|
+
};
|
|
16453
|
+
return doesPathIntersectBounds3(trace.tracePath, bounds);
|
|
16454
|
+
};
|
|
16455
|
+
var InlineNetLabelSolver = class _InlineNetLabelSolver extends BaseSolver {
|
|
15966
16456
|
constructor(input) {
|
|
15967
16457
|
super();
|
|
16458
|
+
this.input = input;
|
|
16459
|
+
this.netLabelConnectorTraceIds = input.netLabelConnectorTraceIds ?? /* @__PURE__ */ new Set();
|
|
15968
16460
|
this.inputProblem = input.inputProblem;
|
|
15969
16461
|
this.traces = input.traces;
|
|
15970
16462
|
this.inputNetLabelPlacements = input.netLabelPlacements;
|
|
@@ -15974,7 +16466,11 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
15974
16466
|
).netConnMap;
|
|
15975
16467
|
this.queuedConnections = [
|
|
15976
16468
|
...this.inputProblem.directConnections.filter(
|
|
15977
|
-
(connection) => connection.allowInlineNetLabel && connection.netId
|
|
16469
|
+
(connection) => connection.allowInlineNetLabel && connection.netId && // An opted-in named net owns all of its connected components.
|
|
16470
|
+
// Do not plan the same pair again through its direct connection.
|
|
16471
|
+
!this.inputProblem.netConnections.some(
|
|
16472
|
+
(net) => net.allowInlineNetLabel && net.netId && connection.pinIds.every((pin) => net.pinIds.includes(pin))
|
|
16473
|
+
)
|
|
15978
16474
|
).map((connection) => ({
|
|
15979
16475
|
kind: "direct_connection",
|
|
15980
16476
|
connection
|
|
@@ -15988,7 +16484,7 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
15988
16484
|
];
|
|
15989
16485
|
this.tracesByPinPairKey = /* @__PURE__ */ new Map();
|
|
15990
16486
|
for (const trace of this.traces) {
|
|
15991
|
-
if (
|
|
16487
|
+
if (this.netLabelConnectorTraceIds.has(trace.mspPairId)) continue;
|
|
15992
16488
|
const key = getPinPairKey2(trace.pins.map((p) => p.pinId));
|
|
15993
16489
|
const existing = this.tracesByPinPairKey.get(key);
|
|
15994
16490
|
if (existing) {
|
|
@@ -15998,13 +16494,32 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
15998
16494
|
}
|
|
15999
16495
|
}
|
|
16000
16496
|
}
|
|
16497
|
+
input;
|
|
16498
|
+
inputProblem;
|
|
16499
|
+
traces;
|
|
16500
|
+
inputNetLabelPlacements;
|
|
16501
|
+
completedReroutes;
|
|
16502
|
+
inlineNetLabelPlacements = [];
|
|
16503
|
+
/** Eligible connections still waiting to be processed. */
|
|
16504
|
+
queuedConnections;
|
|
16505
|
+
netLabelConnectorTraceIds;
|
|
16506
|
+
tracesByPinPairKey;
|
|
16507
|
+
globalConnMap;
|
|
16508
|
+
inlineConversions = [];
|
|
16509
|
+
hasAlignedPortOnlyStubs = false;
|
|
16510
|
+
postProcessedOutput;
|
|
16511
|
+
refinementComplete = false;
|
|
16512
|
+
refinement;
|
|
16513
|
+
currentProposal;
|
|
16001
16514
|
getConstructorParams() {
|
|
16002
16515
|
return [
|
|
16003
16516
|
{
|
|
16004
16517
|
inputProblem: this.inputProblem,
|
|
16005
16518
|
traces: this.traces,
|
|
16006
16519
|
netLabelPlacements: this.inputNetLabelPlacements,
|
|
16007
|
-
completedReroutes: this.completedReroutes
|
|
16520
|
+
completedReroutes: this.completedReroutes,
|
|
16521
|
+
resolveTraceCollisions: this.input.resolveTraceCollisions,
|
|
16522
|
+
netLabelConnectorTraceIds: this.netLabelConnectorTraceIds
|
|
16008
16523
|
}
|
|
16009
16524
|
];
|
|
16010
16525
|
}
|
|
@@ -16025,16 +16540,7 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
16025
16540
|
netConnections
|
|
16026
16541
|
)) {
|
|
16027
16542
|
this.inlineNetLabelPlacements.push(...conversion.placements);
|
|
16028
|
-
|
|
16029
|
-
conversion.globalConnNetId
|
|
16030
|
-
) ?? /* @__PURE__ */ new Set();
|
|
16031
|
-
for (const traceId of conversion.supersededTraceIds) {
|
|
16032
|
-
supersededTraceIds.add(traceId);
|
|
16033
|
-
}
|
|
16034
|
-
this.supersededTraceIdsByGlobalConnNetId.set(
|
|
16035
|
-
conversion.globalConnNetId,
|
|
16036
|
-
supersededTraceIds
|
|
16037
|
-
);
|
|
16543
|
+
this.inlineConversions.push(conversion);
|
|
16038
16544
|
}
|
|
16039
16545
|
return;
|
|
16040
16546
|
}
|
|
@@ -16048,11 +16554,12 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
16048
16554
|
});
|
|
16049
16555
|
if (placement) this.inlineNetLabelPlacements.push(placement);
|
|
16050
16556
|
} else {
|
|
16051
|
-
const
|
|
16052
|
-
|
|
16053
|
-
|
|
16054
|
-
|
|
16055
|
-
|
|
16557
|
+
for (const pinId of connection.pinIds) {
|
|
16558
|
+
const placement = this.computeTerminalInlinePlacement(
|
|
16559
|
+
connection,
|
|
16560
|
+
pinId
|
|
16561
|
+
);
|
|
16562
|
+
if (placement) this.inlineNetLabelPlacements.push(placement);
|
|
16056
16563
|
}
|
|
16057
16564
|
}
|
|
16058
16565
|
return;
|
|
@@ -16071,13 +16578,17 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
16071
16578
|
this.postProcessedOutput = this.buildPostProcessedOutput();
|
|
16072
16579
|
return;
|
|
16073
16580
|
}
|
|
16581
|
+
if (this.input.resolveTraceCollisions && !this.refinementComplete) {
|
|
16582
|
+
this.stepTraceRefinement();
|
|
16583
|
+
return;
|
|
16584
|
+
}
|
|
16074
16585
|
this.solved = true;
|
|
16075
16586
|
this.stats.inlineNetLabelCount = this.inlineNetLabelPlacements.length;
|
|
16076
16587
|
}
|
|
16077
16588
|
/**
|
|
16078
16589
|
* Plans all opted-in multi-pin nets together. Short routed components can
|
|
16079
16590
|
* mutually block the outward endpoint stubs that replace them, so tentative
|
|
16080
|
-
* replacements are ignored as obstacles only while their
|
|
16591
|
+
* replacements are ignored as obstacles only while their connected component still
|
|
16081
16592
|
* converts successfully. Failed conversions retain both their traces and
|
|
16082
16593
|
* their conventional labels, and the remaining conversions are retried.
|
|
16083
16594
|
*/
|
|
@@ -16118,13 +16629,11 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
16118
16629
|
}));
|
|
16119
16630
|
const nextIgnoredTraceIds = new Set(
|
|
16120
16631
|
conversions.flatMap(
|
|
16121
|
-
({ conversion }) => conversion
|
|
16632
|
+
({ conversion }) => conversion.flatMap((component) => [...component.supersededTraceIds])
|
|
16122
16633
|
)
|
|
16123
16634
|
);
|
|
16124
16635
|
if (setsEqual(ignoredTraceIds, nextIgnoredTraceIds)) {
|
|
16125
|
-
return conversions.flatMap(
|
|
16126
|
-
({ conversion }) => conversion ? [conversion] : []
|
|
16127
|
-
);
|
|
16636
|
+
return conversions.flatMap(({ conversion }) => conversion);
|
|
16128
16637
|
}
|
|
16129
16638
|
ignoredTraceIds = nextIgnoredTraceIds;
|
|
16130
16639
|
}
|
|
@@ -16154,7 +16663,7 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
16154
16663
|
// anchored label. They are removed when that label becomes inline, so
|
|
16155
16664
|
// treating them as routed circuitry would leave text on a deleted wire.
|
|
16156
16665
|
traces: this.traces.filter(
|
|
16157
|
-
(trace) => !
|
|
16666
|
+
(trace) => !this.netLabelConnectorTraceIds.has(trace.mspPairId)
|
|
16158
16667
|
)
|
|
16159
16668
|
}).map((component) => ({
|
|
16160
16669
|
pinIds: component.pinIds,
|
|
@@ -16180,14 +16689,14 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
16180
16689
|
* Converts every conventional label representation for an opted-in named
|
|
16181
16690
|
* net. Routed connected components become labels on their representative
|
|
16182
16691
|
* trace; disconnected pins become outward terminal stubs. The conversion is
|
|
16183
|
-
* atomic
|
|
16692
|
+
* atomic within each routed component, so replacing its traces cannot strand
|
|
16693
|
+
* a pin. Disconnected components can keep their own label style.
|
|
16184
16694
|
*/
|
|
16185
16695
|
computeNetConnectionInlinePlacements(connection, ignoredTraceIds, forcedTerminalTraceIds) {
|
|
16186
16696
|
const components = this.getNetConnectionComponents(connection);
|
|
16187
16697
|
const globalConnNetId = this.getGlobalConnNetId(connection);
|
|
16188
|
-
if (!globalConnNetId) return
|
|
16189
|
-
const
|
|
16190
|
-
const supersededTraceIds = /* @__PURE__ */ new Set();
|
|
16698
|
+
if (!globalConnNetId) return [];
|
|
16699
|
+
const conversions = [];
|
|
16191
16700
|
for (const component of components) {
|
|
16192
16701
|
const shouldUseTerminalStubs = component.traces.some(
|
|
16193
16702
|
(trace) => forcedTerminalTraceIds.has(trace.mspPairId)
|
|
@@ -16205,14 +16714,18 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
16205
16714
|
}
|
|
16206
16715
|
}
|
|
16207
16716
|
if (inlinePlacement) {
|
|
16208
|
-
|
|
16717
|
+
conversions.push({
|
|
16718
|
+
globalConnNetId,
|
|
16719
|
+
placements: [inlinePlacement],
|
|
16720
|
+
supersededTraceIds: /* @__PURE__ */ new Set()
|
|
16721
|
+
});
|
|
16209
16722
|
continue;
|
|
16210
16723
|
}
|
|
16211
16724
|
if (component.traces.length > 0 && !shouldUseTerminalStubs) {
|
|
16212
|
-
|
|
16725
|
+
continue;
|
|
16213
16726
|
}
|
|
16214
16727
|
if (component.labeledPinIds.length !== component.pinIds.length) {
|
|
16215
|
-
|
|
16728
|
+
continue;
|
|
16216
16729
|
}
|
|
16217
16730
|
const terminalPlacements = component.pinIds.map(
|
|
16218
16731
|
(pinId) => this.computeTerminalInlinePlacement(
|
|
@@ -16223,26 +16736,41 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
16223
16736
|
)
|
|
16224
16737
|
);
|
|
16225
16738
|
if (terminalPlacements.some((placement) => placement === null)) {
|
|
16226
|
-
|
|
16739
|
+
continue;
|
|
16227
16740
|
}
|
|
16228
|
-
|
|
16229
|
-
|
|
16230
|
-
|
|
16741
|
+
conversions.push({
|
|
16742
|
+
globalConnNetId,
|
|
16743
|
+
placements: terminalPlacements,
|
|
16744
|
+
supersededTraceIds: new Set(
|
|
16745
|
+
component.traces.map((trace) => trace.mspPairId)
|
|
16231
16746
|
)
|
|
16232
|
-
);
|
|
16233
|
-
|
|
16234
|
-
|
|
16747
|
+
});
|
|
16748
|
+
}
|
|
16749
|
+
return conversions;
|
|
16750
|
+
}
|
|
16751
|
+
/** Prefer the normal gap, then center text in a tighter parallel-wire slot. */
|
|
16752
|
+
getInlineOffsets(anchor, axis, side, width, height, traces, ignoredTraceIds) {
|
|
16753
|
+
const normal = height / 2 + INLINE_NET_LABEL_TRACE_MARGIN;
|
|
16754
|
+
const across = axis === "x" ? "y" : "x";
|
|
16755
|
+
const sign = side === "x+" || side === "y+" ? 1 : -1;
|
|
16756
|
+
let gap = Infinity;
|
|
16757
|
+
for (const trace of traces) {
|
|
16758
|
+
if (ignoredTraceIds.has(trace.mspPairId)) continue;
|
|
16759
|
+
for (const segment of getAxisAlignedSegments2(trace.tracePath)) {
|
|
16760
|
+
if (segment.axis !== axis) continue;
|
|
16761
|
+
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)
|
|
16762
|
+
continue;
|
|
16763
|
+
const distance7 = sign * (segment.start[across] - anchor[across]);
|
|
16764
|
+
if (distance7 > GEOMETRY_EPSILON) gap = Math.min(gap, distance7);
|
|
16235
16765
|
}
|
|
16236
16766
|
}
|
|
16237
|
-
return
|
|
16767
|
+
return gap > height + GEOMETRY_EPSILON && gap / 2 < normal - GEOMETRY_EPSILON ? [normal, gap / 2] : [normal];
|
|
16238
16768
|
}
|
|
16239
16769
|
/**
|
|
16240
|
-
* Converts one conventional endpoint placement into an inline label on
|
|
16241
|
-
*
|
|
16242
|
-
* an anchored label may finish in another direction after an elbow, which is
|
|
16243
|
-
* not the direction a terminal stub should leave the pin.
|
|
16770
|
+
* Converts one conventional endpoint placement into an inline label on an
|
|
16771
|
+
* outward stub that follows the pin's true facing direction.
|
|
16244
16772
|
*/
|
|
16245
|
-
computeTerminalInlinePlacement(connection, pinId, knownGlobalConnNetId, ignoredTraceIds = /* @__PURE__ */ new Set()) {
|
|
16773
|
+
computeTerminalInlinePlacement(connection, pinId, knownGlobalConnNetId, ignoredTraceIds = /* @__PURE__ */ new Set(), obstacles) {
|
|
16246
16774
|
if (!connection.netId) return null;
|
|
16247
16775
|
const anchoredPlacement = this.inputNetLabelPlacements.find(
|
|
16248
16776
|
(placement) => placement.netId === connection.netId && placement.pinIds.length === 1 && placement.pinIds[0] === pinId
|
|
@@ -16265,7 +16793,7 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
16265
16793
|
start,
|
|
16266
16794
|
intendedEnd,
|
|
16267
16795
|
minimumLength: width + 2 * INLINE_NET_LABEL_TRACE_MARGIN,
|
|
16268
|
-
traces: this.traces,
|
|
16796
|
+
traces: obstacles?.traces ?? this.traces,
|
|
16269
16797
|
ownGlobalConnNetId: globalConnNetId,
|
|
16270
16798
|
ignoredTraceIds
|
|
16271
16799
|
});
|
|
@@ -16275,42 +16803,52 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
16275
16803
|
x: (start.x + end.x) / 2,
|
|
16276
16804
|
y: (start.y + end.y) / 2
|
|
16277
16805
|
};
|
|
16278
|
-
const offset = height / 2 + INLINE_NET_LABEL_TRACE_MARGIN;
|
|
16279
16806
|
const sides = axis === "x" ? ["y+", "y-"] : ["x-", "x+"];
|
|
16280
16807
|
for (const side of sides) {
|
|
16281
|
-
const
|
|
16282
|
-
const halfAlong = width / 2;
|
|
16283
|
-
const halfAcross = height / 2;
|
|
16284
|
-
const bounds = axis === "x" ? {
|
|
16285
|
-
minX: center.x - halfAlong,
|
|
16286
|
-
maxX: center.x + halfAlong,
|
|
16287
|
-
minY: center.y - halfAcross,
|
|
16288
|
-
maxY: center.y + halfAcross
|
|
16289
|
-
} : {
|
|
16290
|
-
minX: center.x - halfAcross,
|
|
16291
|
-
maxX: center.x + halfAcross,
|
|
16292
|
-
minY: center.y - halfAlong,
|
|
16293
|
-
maxY: center.y + halfAlong
|
|
16294
|
-
};
|
|
16295
|
-
if (this.isObstructed(bounds, {
|
|
16296
|
-
ownGlobalConnNetId: globalConnNetId,
|
|
16297
|
-
ignoredTraceIds
|
|
16298
|
-
})) {
|
|
16299
|
-
continue;
|
|
16300
|
-
}
|
|
16301
|
-
return {
|
|
16302
|
-
globalConnNetId,
|
|
16303
|
-
netId: connection.netId,
|
|
16304
|
-
netLabelText,
|
|
16305
|
-
pinIds: [pinId],
|
|
16306
|
-
stubTracePath: [start, end],
|
|
16307
|
-
axis,
|
|
16808
|
+
for (const offset of this.getInlineOffsets(
|
|
16308
16809
|
anchorPoint,
|
|
16309
|
-
|
|
16810
|
+
axis,
|
|
16811
|
+
side,
|
|
16310
16812
|
width,
|
|
16311
16813
|
height,
|
|
16312
|
-
|
|
16313
|
-
|
|
16814
|
+
obstacles?.traces ?? this.traces,
|
|
16815
|
+
ignoredTraceIds
|
|
16816
|
+
)) {
|
|
16817
|
+
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 };
|
|
16818
|
+
const halfAlong = width / 2;
|
|
16819
|
+
const halfAcross = height / 2;
|
|
16820
|
+
const bounds = axis === "x" ? {
|
|
16821
|
+
minX: center.x - halfAlong,
|
|
16822
|
+
maxX: center.x + halfAlong,
|
|
16823
|
+
minY: center.y - halfAcross,
|
|
16824
|
+
maxY: center.y + halfAcross
|
|
16825
|
+
} : {
|
|
16826
|
+
minX: center.x - halfAcross,
|
|
16827
|
+
maxX: center.x + halfAcross,
|
|
16828
|
+
minY: center.y - halfAlong,
|
|
16829
|
+
maxY: center.y + halfAlong
|
|
16830
|
+
};
|
|
16831
|
+
if (this.isObstructed(bounds, {
|
|
16832
|
+
ownGlobalConnNetId: globalConnNetId,
|
|
16833
|
+
ignoredTraceIds,
|
|
16834
|
+
obstacles
|
|
16835
|
+
})) {
|
|
16836
|
+
continue;
|
|
16837
|
+
}
|
|
16838
|
+
return {
|
|
16839
|
+
globalConnNetId,
|
|
16840
|
+
netId: connection.netId,
|
|
16841
|
+
netLabelText,
|
|
16842
|
+
pinIds: [pinId],
|
|
16843
|
+
stubTracePath: [start, end],
|
|
16844
|
+
axis,
|
|
16845
|
+
anchorPoint,
|
|
16846
|
+
center,
|
|
16847
|
+
width,
|
|
16848
|
+
height,
|
|
16849
|
+
side
|
|
16850
|
+
};
|
|
16851
|
+
}
|
|
16314
16852
|
}
|
|
16315
16853
|
return null;
|
|
16316
16854
|
}
|
|
@@ -16331,39 +16869,49 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
16331
16869
|
const sides = segment.axis === "x" ? ["y+", "y-"] : ["x-", "x+"];
|
|
16332
16870
|
for (const side of sides) {
|
|
16333
16871
|
for (const anchorPoint of getAnchorCandidates(segment, width)) {
|
|
16334
|
-
const
|
|
16335
|
-
const halfAlong = width / 2;
|
|
16336
|
-
const halfAcross = height / 2;
|
|
16337
|
-
const bounds = segment.axis === "x" ? {
|
|
16338
|
-
minX: center.x - halfAlong,
|
|
16339
|
-
maxX: center.x + halfAlong,
|
|
16340
|
-
minY: center.y - halfAcross,
|
|
16341
|
-
maxY: center.y + halfAcross
|
|
16342
|
-
} : {
|
|
16343
|
-
minX: center.x - halfAcross,
|
|
16344
|
-
maxX: center.x + halfAcross,
|
|
16345
|
-
minY: center.y - halfAlong,
|
|
16346
|
-
maxY: center.y + halfAlong
|
|
16347
|
-
};
|
|
16348
|
-
if (this.isObstructed(bounds, {
|
|
16349
|
-
ownTrace: trace,
|
|
16350
|
-
ownGlobalConnNetId: trace.globalConnNetId,
|
|
16351
|
-
ignoredTraceIds
|
|
16352
|
-
}))
|
|
16353
|
-
continue;
|
|
16354
|
-
return {
|
|
16355
|
-
globalConnNetId: trace.globalConnNetId,
|
|
16356
|
-
netId: connection.netId,
|
|
16357
|
-
netLabelText,
|
|
16358
|
-
mspPairId: trace.mspPairId,
|
|
16359
|
-
pinIds: [...pinIds],
|
|
16360
|
-
axis: segment.axis,
|
|
16872
|
+
for (const offset2 of this.getInlineOffsets(
|
|
16361
16873
|
anchorPoint,
|
|
16362
|
-
|
|
16874
|
+
segment.axis,
|
|
16875
|
+
side,
|
|
16363
16876
|
width,
|
|
16364
16877
|
height,
|
|
16365
|
-
|
|
16366
|
-
|
|
16878
|
+
this.traces,
|
|
16879
|
+
ignoredTraceIds
|
|
16880
|
+
)) {
|
|
16881
|
+
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 };
|
|
16882
|
+
const halfAlong = width / 2;
|
|
16883
|
+
const halfAcross = height / 2;
|
|
16884
|
+
const bounds = segment.axis === "x" ? {
|
|
16885
|
+
minX: center.x - halfAlong,
|
|
16886
|
+
maxX: center.x + halfAlong,
|
|
16887
|
+
minY: center.y - halfAcross,
|
|
16888
|
+
maxY: center.y + halfAcross
|
|
16889
|
+
} : {
|
|
16890
|
+
minX: center.x - halfAcross,
|
|
16891
|
+
maxX: center.x + halfAcross,
|
|
16892
|
+
minY: center.y - halfAlong,
|
|
16893
|
+
maxY: center.y + halfAlong
|
|
16894
|
+
};
|
|
16895
|
+
if (this.isObstructed(bounds, {
|
|
16896
|
+
ownTrace: trace,
|
|
16897
|
+
ownGlobalConnNetId: trace.globalConnNetId,
|
|
16898
|
+
ignoredTraceIds
|
|
16899
|
+
}))
|
|
16900
|
+
continue;
|
|
16901
|
+
return {
|
|
16902
|
+
globalConnNetId: trace.globalConnNetId,
|
|
16903
|
+
netId: connection.netId,
|
|
16904
|
+
netLabelText,
|
|
16905
|
+
mspPairId: trace.mspPairId,
|
|
16906
|
+
pinIds: [...pinIds],
|
|
16907
|
+
axis: segment.axis,
|
|
16908
|
+
anchorPoint,
|
|
16909
|
+
center,
|
|
16910
|
+
width,
|
|
16911
|
+
height,
|
|
16912
|
+
side
|
|
16913
|
+
};
|
|
16914
|
+
}
|
|
16367
16915
|
}
|
|
16368
16916
|
}
|
|
16369
16917
|
}
|
|
@@ -16473,7 +17021,8 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
16473
17021
|
isObstructed(bounds, {
|
|
16474
17022
|
ownTrace,
|
|
16475
17023
|
ownGlobalConnNetId,
|
|
16476
|
-
ignoredTraceIds = /* @__PURE__ */ new Set()
|
|
17024
|
+
ignoredTraceIds = /* @__PURE__ */ new Set(),
|
|
17025
|
+
obstacles
|
|
16477
17026
|
}) {
|
|
16478
17027
|
for (const chip of this.inputProblem.chips) {
|
|
16479
17028
|
const chipBounds = {
|
|
@@ -16487,82 +17036,102 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
16487
17036
|
for (const textBox of this.inputProblem.textBoxes ?? []) {
|
|
16488
17037
|
if (boundsOverlap(bounds, getTextBoxBounds(textBox))) return true;
|
|
16489
17038
|
}
|
|
16490
|
-
for (const trace of this.traces) {
|
|
17039
|
+
for (const trace of obstacles?.traces ?? this.traces) {
|
|
16491
17040
|
if (ignoredTraceIds.has(trace.mspPairId)) continue;
|
|
16492
17041
|
if (ownTrace && trace.mspPairId === ownTrace.mspPairId) continue;
|
|
16493
17042
|
if (trace.globalConnNetId === ownGlobalConnNetId) continue;
|
|
16494
17043
|
if (doesPathIntersectBounds3(trace.tracePath, bounds)) return true;
|
|
16495
17044
|
}
|
|
17045
|
+
if (obstacles?.anchored.some(
|
|
17046
|
+
(label) => boundsOverlap(bounds, getAnchoredNetLabelRenderedBounds(label))
|
|
17047
|
+
))
|
|
17048
|
+
return true;
|
|
17049
|
+
if (obstacles?.inline.some(
|
|
17050
|
+
(label) => boundsOverlap(bounds, getInlinePlacementBounds(label)) || label.stubTracePath && label.globalConnNetId !== ownGlobalConnNetId && doesPathIntersectBounds3(label.stubTracePath, bounds)
|
|
17051
|
+
))
|
|
17052
|
+
return true;
|
|
16496
17053
|
return false;
|
|
16497
17054
|
}
|
|
16498
|
-
|
|
16499
|
-
|
|
16500
|
-
|
|
16501
|
-
|
|
16502
|
-
|
|
16503
|
-
|
|
16504
|
-
|
|
16505
|
-
|
|
16506
|
-
|
|
16507
|
-
return keys;
|
|
16508
|
-
}
|
|
16509
|
-
getOutputTraces(supersededNetLabelKeys, supersededTraceIds) {
|
|
17055
|
+
getOutputTraces(placements) {
|
|
17056
|
+
const activeKeys = new Set(placements.map(getInlinePlacementKey));
|
|
17057
|
+
const supersededTraceIds = new Set(
|
|
17058
|
+
this.inlineConversions.filter(
|
|
17059
|
+
(conversion) => conversion.placements.every(
|
|
17060
|
+
(placement) => activeKeys.has(getInlinePlacementKey(placement))
|
|
17061
|
+
)
|
|
17062
|
+
).flatMap((conversion) => [...conversion.supersededTraceIds])
|
|
17063
|
+
);
|
|
16510
17064
|
return this.traces.filter(
|
|
16511
|
-
(trace) => !supersededTraceIds.has(trace.mspPairId) && !(
|
|
17065
|
+
(trace) => !supersededTraceIds.has(trace.mspPairId) && !(this.netLabelConnectorTraceIds.has(trace.mspPairId) && isLabelRepresentedInline(trace, placements))
|
|
16512
17066
|
);
|
|
16513
17067
|
}
|
|
16514
|
-
|
|
17068
|
+
getBlockedInlinePlacements({
|
|
16515
17069
|
inlineNetLabelPlacements,
|
|
16516
|
-
anchoredNetLabelPlacements
|
|
17070
|
+
anchoredNetLabelPlacements,
|
|
17071
|
+
traces
|
|
16517
17072
|
}) {
|
|
16518
|
-
const
|
|
16519
|
-
for (const
|
|
16520
|
-
const
|
|
16521
|
-
|
|
16522
|
-
|
|
16523
|
-
|
|
16524
|
-
|
|
16525
|
-
|
|
16526
|
-
|
|
16527
|
-
|
|
16528
|
-
|
|
16529
|
-
))
|
|
16530
|
-
|
|
16531
|
-
|
|
16532
|
-
|
|
17073
|
+
const blockedKeys = /* @__PURE__ */ new Set();
|
|
17074
|
+
for (const inline of inlineNetLabelPlacements) {
|
|
17075
|
+
const bounds = getInlinePlacementBounds(inline);
|
|
17076
|
+
const blockedByLabel = anchoredNetLabelPlacements.some((anchored) => {
|
|
17077
|
+
const anchoredBounds = getAnchoredNetLabelRenderedBounds(anchored);
|
|
17078
|
+
return boundsOverlap(bounds, anchoredBounds) || inline.stubTracePath && doesPathIntersectBounds3(inline.stubTracePath, anchoredBounds);
|
|
17079
|
+
});
|
|
17080
|
+
const blockedByTrace = traces.some(
|
|
17081
|
+
(trace) => trace.globalConnNetId !== inline.globalConnNetId && (doesPathIntersectBounds3(trace.tracePath, bounds) || inline.stubTracePath && terminalStubIntersectsTrace(inline.stubTracePath, trace))
|
|
17082
|
+
);
|
|
17083
|
+
const blockedByInlineWire = inlineNetLabelPlacements.some(
|
|
17084
|
+
(other) => other !== inline && other.globalConnNetId !== inline.globalConnNetId && other.stubTracePath && doesPathIntersectBounds3(other.stubTracePath, bounds)
|
|
17085
|
+
);
|
|
17086
|
+
const blockedByInlineText = inlineNetLabelPlacements.some(
|
|
17087
|
+
(other) => other !== inline && boundsOverlap(bounds, getInlinePlacementBounds(other))
|
|
17088
|
+
);
|
|
17089
|
+
if (blockedByLabel || blockedByTrace || blockedByInlineWire || blockedByInlineText)
|
|
17090
|
+
blockedKeys.add(getInlinePlacementKey(inline));
|
|
17091
|
+
}
|
|
17092
|
+
for (const conversion of this.inlineConversions) {
|
|
17093
|
+
if (conversion.placements.some(
|
|
17094
|
+
(placement) => blockedKeys.has(getInlinePlacementKey(placement))
|
|
17095
|
+
)) {
|
|
17096
|
+
for (const placement of conversion.placements)
|
|
17097
|
+
blockedKeys.add(getInlinePlacementKey(placement));
|
|
16533
17098
|
}
|
|
16534
17099
|
}
|
|
16535
|
-
return
|
|
17100
|
+
return blockedKeys;
|
|
16536
17101
|
}
|
|
16537
17102
|
buildPostProcessedOutput() {
|
|
16538
17103
|
let activeInlinePlacements = this.inlineNetLabelPlacements;
|
|
16539
17104
|
while (true) {
|
|
16540
|
-
const supersededNetLabelKeys = this.getSupersededNetLabelKeys(
|
|
16541
|
-
activeInlinePlacements
|
|
16542
|
-
);
|
|
16543
|
-
const supersededTraceIds = new Set(
|
|
16544
|
-
[...supersededNetLabelKeys].flatMap((globalConnNetId) => [
|
|
16545
|
-
...this.supersededTraceIdsByGlobalConnNetId.get(globalConnNetId) ?? []
|
|
16546
|
-
])
|
|
16547
|
-
);
|
|
16548
17105
|
const retainedNetLabelPlacements = this.inputNetLabelPlacements.filter(
|
|
16549
|
-
(placement) => !
|
|
17106
|
+
(placement) => !isLabelRepresentedInline(placement, activeInlinePlacements)
|
|
16550
17107
|
);
|
|
16551
|
-
const outputTraces = this.getOutputTraces(
|
|
16552
|
-
|
|
16553
|
-
|
|
17108
|
+
const outputTraces = this.getOutputTraces(activeInlinePlacements);
|
|
17109
|
+
const { fixedLabels, terminalTraces } = getInlineLabelObstacles(
|
|
17110
|
+
this.inputProblem,
|
|
17111
|
+
activeInlinePlacements
|
|
16554
17112
|
);
|
|
17113
|
+
const labelCollisionSolver = new NetLabelNetLabelCollisionSolver({
|
|
17114
|
+
inputProblem: this.inputProblem,
|
|
17115
|
+
traces: [...outputTraces, ...terminalTraces],
|
|
17116
|
+
netLabelPlacements: retainedNetLabelPlacements,
|
|
17117
|
+
fixedNetLabelPlacements: fixedLabels,
|
|
17118
|
+
netLabelConnectorTraceIds: this.netLabelConnectorTraceIds,
|
|
17119
|
+
useRenderedLabelBounds: activeInlinePlacements.length > 0
|
|
17120
|
+
});
|
|
17121
|
+
if (activeInlinePlacements.length > 0) labelCollisionSolver.solve();
|
|
16555
17122
|
const pushed = pushAnchoredNetLabelsAwayFromInlineLabels({
|
|
16556
17123
|
inputProblem: this.inputProblem,
|
|
16557
17124
|
traces: outputTraces,
|
|
16558
|
-
netLabelPlacements: retainedNetLabelPlacements,
|
|
16559
|
-
inlineNetLabelPlacements: activeInlinePlacements
|
|
17125
|
+
netLabelPlacements: labelCollisionSolver.solved && !labelCollisionSolver.failed ? labelCollisionSolver.getOutput().netLabelPlacements : retainedNetLabelPlacements,
|
|
17126
|
+
inlineNetLabelPlacements: activeInlinePlacements,
|
|
17127
|
+
netLabelConnectorTraceIds: this.netLabelConnectorTraceIds
|
|
16560
17128
|
});
|
|
16561
|
-
|
|
17129
|
+
let blockedPlacementKeys = this.getBlockedInlinePlacements({
|
|
16562
17130
|
inlineNetLabelPlacements: activeInlinePlacements,
|
|
16563
|
-
anchoredNetLabelPlacements: pushed.netLabelPlacements
|
|
17131
|
+
anchoredNetLabelPlacements: pushed.netLabelPlacements,
|
|
17132
|
+
traces: pushed.traces
|
|
16564
17133
|
});
|
|
16565
|
-
if (
|
|
17134
|
+
if (blockedPlacementKeys.size > 0) {
|
|
16566
17135
|
const shiftedInlineTerminalLabels = pushInlineTerminalLabelsAwayFromAnchoredLabels({
|
|
16567
17136
|
inputProblem: this.inputProblem,
|
|
16568
17137
|
traces: pushed.traces,
|
|
@@ -16573,8 +17142,49 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
16573
17142
|
activeInlinePlacements = shiftedInlineTerminalLabels.inlineNetLabelPlacements;
|
|
16574
17143
|
continue;
|
|
16575
17144
|
}
|
|
17145
|
+
const { terminalTraces: terminalTraces2 } = getInlineLabelObstacles(
|
|
17146
|
+
this.inputProblem,
|
|
17147
|
+
activeInlinePlacements
|
|
17148
|
+
);
|
|
17149
|
+
const replanned = activeInlinePlacements.filter(
|
|
17150
|
+
(label) => !label.stubTracePath
|
|
17151
|
+
);
|
|
17152
|
+
const terminals = activeInlinePlacements.filter((label) => label.stubTracePath).sort(
|
|
17153
|
+
(a, b) => Number(blockedPlacementKeys.has(getInlinePlacementKey(b))) - Number(blockedPlacementKeys.has(getInlinePlacementKey(a)))
|
|
17154
|
+
);
|
|
17155
|
+
for (const placement of terminals) {
|
|
17156
|
+
const connection = [
|
|
17157
|
+
...this.inputProblem.netConnections,
|
|
17158
|
+
...this.inputProblem.directConnections
|
|
17159
|
+
].find(
|
|
17160
|
+
(connection2) => connection2.netId === placement.netId && connection2.allowInlineNetLabel
|
|
17161
|
+
);
|
|
17162
|
+
const candidate = connection ? this.computeTerminalInlinePlacement(
|
|
17163
|
+
connection,
|
|
17164
|
+
placement.pinIds[0],
|
|
17165
|
+
placement.globalConnNetId,
|
|
17166
|
+
/* @__PURE__ */ new Set(),
|
|
17167
|
+
{
|
|
17168
|
+
traces: [...pushed.traces, ...terminalTraces2],
|
|
17169
|
+
anchored: pushed.netLabelPlacements,
|
|
17170
|
+
inline: replanned
|
|
17171
|
+
}
|
|
17172
|
+
) : null;
|
|
17173
|
+
replanned.push(candidate ?? placement);
|
|
17174
|
+
}
|
|
17175
|
+
const byKey = new Map(
|
|
17176
|
+
replanned.map((label) => [getInlinePlacementKey(label), label])
|
|
17177
|
+
);
|
|
17178
|
+
activeInlinePlacements = activeInlinePlacements.map(
|
|
17179
|
+
(label) => byKey.get(getInlinePlacementKey(label)) ?? label
|
|
17180
|
+
);
|
|
17181
|
+
blockedPlacementKeys = this.getBlockedInlinePlacements({
|
|
17182
|
+
inlineNetLabelPlacements: activeInlinePlacements,
|
|
17183
|
+
anchoredNetLabelPlacements: pushed.netLabelPlacements,
|
|
17184
|
+
traces: pushed.traces
|
|
17185
|
+
});
|
|
16576
17186
|
}
|
|
16577
|
-
if (
|
|
17187
|
+
if (blockedPlacementKeys.size === 0) {
|
|
16578
17188
|
this.inlineNetLabelPlacements = activeInlinePlacements;
|
|
16579
17189
|
this.stats.pushedAnchoredNetLabelCount = pushed.movedLabelCount;
|
|
16580
17190
|
const restored = restoreReroutesAroundSupersededLabels({
|
|
@@ -16585,17 +17195,141 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
16585
17195
|
completedReroutes: this.completedReroutes
|
|
16586
17196
|
});
|
|
16587
17197
|
this.stats.restoredSupersededLabelRerouteCount = restored.restoredTraceCount;
|
|
16588
|
-
|
|
17198
|
+
const output = {
|
|
16589
17199
|
traces: restored.traces,
|
|
17200
|
+
netLabelConnectorTraceIds: pushed.netLabelConnectorTraceIds,
|
|
16590
17201
|
netLabelPlacements: pushed.netLabelPlacements,
|
|
16591
17202
|
inlineNetLabelPlacements: activeInlinePlacements
|
|
16592
17203
|
};
|
|
17204
|
+
this.inlineNetLabelPlacements = output.inlineNetLabelPlacements;
|
|
17205
|
+
return output;
|
|
16593
17206
|
}
|
|
16594
17207
|
activeInlinePlacements = activeInlinePlacements.filter(
|
|
16595
|
-
(placement) => !
|
|
17208
|
+
(placement) => !blockedPlacementKeys.has(getInlinePlacementKey(placement))
|
|
17209
|
+
);
|
|
17210
|
+
}
|
|
17211
|
+
}
|
|
17212
|
+
/** Enumerate nearby moves in the existing order; collect one proposal per step. */
|
|
17213
|
+
*getTraceRefinementProposals(current) {
|
|
17214
|
+
yield* getLocalTraceLabelShifts(this.inputProblem, current);
|
|
17215
|
+
for (const label of current.netLabelPlacements) {
|
|
17216
|
+
if (label.pinIds.length !== 1) continue;
|
|
17217
|
+
const connection = [
|
|
17218
|
+
...this.inputProblem.netConnections,
|
|
17219
|
+
...this.inputProblem.directConnections
|
|
17220
|
+
].find(
|
|
17221
|
+
(connection2) => connection2.allowInlineNetLabel && connection2.netId === label.netId && connection2.pinIds.includes(label.pinIds[0])
|
|
17222
|
+
);
|
|
17223
|
+
if (!connection) continue;
|
|
17224
|
+
const placement = this.computeTerminalInlinePlacement(
|
|
17225
|
+
connection,
|
|
17226
|
+
label.pinIds[0],
|
|
17227
|
+
label.globalConnNetId,
|
|
17228
|
+
/* @__PURE__ */ new Set(),
|
|
17229
|
+
{ traces: [], anchored: [], inline: [] }
|
|
16596
17230
|
);
|
|
17231
|
+
if (placement)
|
|
17232
|
+
yield* getLocalTraceLabelShifts(this.inputProblem, current, [placement]);
|
|
16597
17233
|
}
|
|
16598
17234
|
}
|
|
17235
|
+
createRefinementCandidate(proposal) {
|
|
17236
|
+
const traceMap = new Map(
|
|
17237
|
+
proposal.traces.map((trace) => [trace.mspPairId, trace])
|
|
17238
|
+
);
|
|
17239
|
+
const labelKey = (label) => JSON.stringify([label.globalConnNetId, [...label.pinIds].sort()]);
|
|
17240
|
+
const labelMap = new Map(
|
|
17241
|
+
proposal.netLabelPlacements.map((label) => [labelKey(label), label])
|
|
17242
|
+
);
|
|
17243
|
+
const originalTraceIds = new Set(
|
|
17244
|
+
this.traces.map((trace) => trace.mspPairId)
|
|
17245
|
+
);
|
|
17246
|
+
return new _InlineNetLabelSolver({
|
|
17247
|
+
inputProblem: this.inputProblem,
|
|
17248
|
+
traces: [
|
|
17249
|
+
...this.traces.map((trace) => traceMap.get(trace.mspPairId) ?? trace),
|
|
17250
|
+
...proposal.traces.filter(
|
|
17251
|
+
(trace) => !originalTraceIds.has(trace.mspPairId)
|
|
17252
|
+
)
|
|
17253
|
+
],
|
|
17254
|
+
netLabelPlacements: this.inputNetLabelPlacements.map(
|
|
17255
|
+
(label) => labelMap.get(labelKey(label)) ?? label
|
|
17256
|
+
),
|
|
17257
|
+
completedReroutes: this.completedReroutes,
|
|
17258
|
+
netLabelConnectorTraceIds: proposal.netLabelConnectorTraceIds
|
|
17259
|
+
});
|
|
17260
|
+
}
|
|
17261
|
+
acceptRefinementCandidate(proposal, result) {
|
|
17262
|
+
const current = this.postProcessedOutput;
|
|
17263
|
+
const before = this.refinement.before;
|
|
17264
|
+
const after = getOutputLabelCollisions(result);
|
|
17265
|
+
if (after.some(
|
|
17266
|
+
(collision) => !before.some(
|
|
17267
|
+
(previous) => sameOutputLabelCollision(collision, previous)
|
|
17268
|
+
)
|
|
17269
|
+
))
|
|
17270
|
+
return false;
|
|
17271
|
+
const movedTraceIds = new Set(
|
|
17272
|
+
proposal.traces.filter((trace, index) => trace !== current.traces[index]).map((trace) => trace.mspPairId)
|
|
17273
|
+
);
|
|
17274
|
+
if (after.some(
|
|
17275
|
+
(collision) => collision.kind === "trace-label" && collision.trace.kind === "routed" && movedTraceIds.has(collision.trace.id)
|
|
17276
|
+
))
|
|
17277
|
+
return false;
|
|
17278
|
+
if (after.length >= before.length && result.inlineNetLabelPlacements.length <= current.inlineNetLabelPlacements.length)
|
|
17279
|
+
return false;
|
|
17280
|
+
this.postProcessedOutput = result;
|
|
17281
|
+
this.inlineNetLabelPlacements = result.inlineNetLabelPlacements;
|
|
17282
|
+
return true;
|
|
17283
|
+
}
|
|
17284
|
+
stepTraceRefinement() {
|
|
17285
|
+
if (this.activeSubSolver) {
|
|
17286
|
+
this.activeSubSolver.step();
|
|
17287
|
+
if (!this.activeSubSolver.solved && !this.activeSubSolver.failed) return;
|
|
17288
|
+
if (this.activeSubSolver.solved && !this.activeSubSolver.failed && this.acceptRefinementCandidate(
|
|
17289
|
+
this.currentProposal,
|
|
17290
|
+
this.activeSubSolver.getOutput()
|
|
17291
|
+
)) {
|
|
17292
|
+
this.refinement = void 0;
|
|
17293
|
+
}
|
|
17294
|
+
this.activeSubSolver = null;
|
|
17295
|
+
this.currentProposal = void 0;
|
|
17296
|
+
return;
|
|
17297
|
+
}
|
|
17298
|
+
const current = this.postProcessedOutput;
|
|
17299
|
+
if (!this.refinement) {
|
|
17300
|
+
this.refinement = {
|
|
17301
|
+
proposals: this.getTraceRefinementProposals(current),
|
|
17302
|
+
queue: [],
|
|
17303
|
+
collecting: true,
|
|
17304
|
+
before: getOutputLabelCollisions(current)
|
|
17305
|
+
};
|
|
17306
|
+
}
|
|
17307
|
+
const refinement = this.refinement;
|
|
17308
|
+
if (refinement.collecting) {
|
|
17309
|
+
const next2 = refinement.proposals.next();
|
|
17310
|
+
if (!next2.done) {
|
|
17311
|
+
const distance7 = next2.value.traces.reduce(
|
|
17312
|
+
(sum, trace, index) => sum + trace.tracePath.reduce((distance8, point, pointIndex) => {
|
|
17313
|
+
const previous = current.traces[index].tracePath[pointIndex];
|
|
17314
|
+
return distance8 + Math.abs(point.x - previous.x) + Math.abs(point.y - previous.y);
|
|
17315
|
+
}, 0),
|
|
17316
|
+
0
|
|
17317
|
+
);
|
|
17318
|
+
refinement.queue.push({ output: next2.value, distance: distance7 });
|
|
17319
|
+
} else {
|
|
17320
|
+
refinement.queue.sort((a, b) => a.distance - b.distance);
|
|
17321
|
+
refinement.collecting = false;
|
|
17322
|
+
}
|
|
17323
|
+
return;
|
|
17324
|
+
}
|
|
17325
|
+
const next = refinement.queue.shift();
|
|
17326
|
+
if (!next) {
|
|
17327
|
+
this.refinementComplete = true;
|
|
17328
|
+
return;
|
|
17329
|
+
}
|
|
17330
|
+
this.currentProposal = next.output;
|
|
17331
|
+
this.activeSubSolver = this.createRefinementCandidate(next.output);
|
|
17332
|
+
}
|
|
16599
17333
|
getOutput() {
|
|
16600
17334
|
if (this.postProcessedOutput) return this.postProcessedOutput;
|
|
16601
17335
|
return this.buildPostProcessedOutput();
|
|
@@ -16774,12 +17508,12 @@ var getCollisionLimitedTerminalStubEnd = ({
|
|
|
16774
17508
|
const maxAcross = Math.max(startAcross, endAcross);
|
|
16775
17509
|
let collisionDistance;
|
|
16776
17510
|
const isCollinear = Math.abs(startAcross) <= GEOMETRY_EPSILON && Math.abs(endAcross) <= GEOMETRY_EPSILON;
|
|
16777
|
-
if (isCollinear && maxAlong >= -GEOMETRY_EPSILON && minAlong <= intendedLength + GEOMETRY_EPSILON) {
|
|
17511
|
+
if (isCollinear && maxAlong >= -GEOMETRY_EPSILON && minAlong <= intendedLength + INLINE_NET_LABEL_STUB_TRACE_CLEARANCE + GEOMETRY_EPSILON) {
|
|
16778
17512
|
collisionDistance = Math.max(0, minAlong);
|
|
16779
17513
|
} else {
|
|
16780
17514
|
const crossesStubAxis = minAcross <= GEOMETRY_EPSILON && maxAcross >= -GEOMETRY_EPSILON;
|
|
16781
17515
|
const perpendicularAlong = (startAlong + endAlong) / 2;
|
|
16782
|
-
if (crossesStubAxis && Math.abs(startAlong - endAlong) <= GEOMETRY_EPSILON && perpendicularAlong >= -GEOMETRY_EPSILON && perpendicularAlong <= intendedLength + GEOMETRY_EPSILON) {
|
|
17516
|
+
if (crossesStubAxis && Math.abs(startAlong - endAlong) <= GEOMETRY_EPSILON && perpendicularAlong >= -GEOMETRY_EPSILON && perpendicularAlong <= intendedLength + INLINE_NET_LABEL_STUB_TRACE_CLEARANCE + GEOMETRY_EPSILON) {
|
|
16783
17517
|
collisionDistance = Math.max(0, perpendicularAlong);
|
|
16784
17518
|
}
|
|
16785
17519
|
}
|
|
@@ -16889,12 +17623,12 @@ var getTraceRecoveryConnectivityMaps = (inputProblem) => {
|
|
|
16889
17623
|
};
|
|
16890
17624
|
|
|
16891
17625
|
// lib/solvers/NetLabelToTraceSolver/reduceTraceCrossings.ts
|
|
16892
|
-
var
|
|
16893
|
-
var isHorizontal4 = (start, end) => Math.abs(start.y - end.y) <
|
|
16894
|
-
var isVertical5 = (start, end) => Math.abs(start.x - end.x) <
|
|
17626
|
+
var EPS17 = 1e-9;
|
|
17627
|
+
var isHorizontal4 = (start, end) => Math.abs(start.y - end.y) < EPS17;
|
|
17628
|
+
var isVertical5 = (start, end) => Math.abs(start.x - end.x) < EPS17;
|
|
16895
17629
|
var compactConsecutivePoints = (path) => path.filter((point, index) => {
|
|
16896
17630
|
const previousPoint = path[index - 1];
|
|
16897
|
-
return !previousPoint || Math.abs(point.x - previousPoint.x) >=
|
|
17631
|
+
return !previousPoint || Math.abs(point.x - previousPoint.x) >= EPS17 || Math.abs(point.y - previousPoint.y) >= EPS17;
|
|
16898
17632
|
});
|
|
16899
17633
|
var isValidOrthogonalPath = (path) => {
|
|
16900
17634
|
if (path.length < 2 || !path.every((point, index) => {
|
|
@@ -16932,7 +17666,7 @@ var getEndpointAlignedSegmentCandidates = (tracePath) => {
|
|
|
16932
17666
|
}
|
|
16933
17667
|
const alignedCoordinates = segmentIsVertical ? [previousPoint.x, nextPoint.x] : [previousPoint.y, nextPoint.y];
|
|
16934
17668
|
for (const alignedCoordinate of alignedCoordinates) {
|
|
16935
|
-
if (Math.abs(alignedCoordinate - (segmentIsVertical ? start.x : start.y)) <
|
|
17669
|
+
if (Math.abs(alignedCoordinate - (segmentIsVertical ? start.x : start.y)) < EPS17) {
|
|
16936
17670
|
continue;
|
|
16937
17671
|
}
|
|
16938
17672
|
const candidate = tracePath.map((point) => ({ ...point }));
|
|
@@ -16990,7 +17724,6 @@ var reduceTraceCrossings = ({
|
|
|
16990
17724
|
};
|
|
16991
17725
|
|
|
16992
17726
|
// lib/solvers/NetLabelToTraceSolver/NetLabelToTraceSolver.ts
|
|
16993
|
-
var AVAILABLE_NET_ORIENTATION_PREFIX = "available-net-orientation-";
|
|
16994
17727
|
var RECOVERED_TRACE_PREFIX = "net-label-to-trace-";
|
|
16995
17728
|
var MAX_NAMED_NET_RECOVERY_PERPENDICULAR_OFFSET = 0.05;
|
|
16996
17729
|
var MAX_ROUTED_COMPONENT_RECOVERY_PERPENDICULAR_OFFSET = 0.25;
|
|
@@ -17030,6 +17763,7 @@ var NetLabelToTraceSolver = class extends BaseSolver {
|
|
|
17030
17763
|
inputProblem;
|
|
17031
17764
|
outputTraces;
|
|
17032
17765
|
outputNetLabelPlacements;
|
|
17766
|
+
recoveredTraceIds = /* @__PURE__ */ new Set();
|
|
17033
17767
|
chipMap;
|
|
17034
17768
|
pinMap;
|
|
17035
17769
|
queuedCandidates;
|
|
@@ -17246,7 +17980,7 @@ var NetLabelToTraceSolver = class extends BaseSolver {
|
|
|
17246
17980
|
return candidates;
|
|
17247
17981
|
}
|
|
17248
17982
|
isSupersededConnectorTrace(trace, candidate) {
|
|
17249
|
-
if (!trace.mspPairId
|
|
17983
|
+
if (!this.input.netLabelConnectorTraceIds?.has(trace.mspPairId)) {
|
|
17250
17984
|
return false;
|
|
17251
17985
|
}
|
|
17252
17986
|
if (trace.pinIds.length !== 1) return false;
|
|
@@ -17296,6 +18030,7 @@ var NetLabelToTraceSolver = class extends BaseSolver {
|
|
|
17296
18030
|
mspConnectionPairIds: [mspPairId],
|
|
17297
18031
|
pinIds: [firstPin.pinId, secondPin.pinId]
|
|
17298
18032
|
};
|
|
18033
|
+
this.recoveredTraceIds.add(mspPairId);
|
|
17299
18034
|
this.outputTraces = [...retainedTraces, recoveredTrace];
|
|
17300
18035
|
if (candidate.recoveryMode !== "routed_components") {
|
|
17301
18036
|
this.outputNetLabelPlacements = this.outputNetLabelPlacements.filter(
|
|
@@ -17355,7 +18090,7 @@ var NetLabelToTraceSolver = class extends BaseSolver {
|
|
|
17355
18090
|
...this.getOutput()
|
|
17356
18091
|
});
|
|
17357
18092
|
for (const trace of this.outputTraces) {
|
|
17358
|
-
if (!trace.mspPairId
|
|
18093
|
+
if (!this.recoveredTraceIds.has(trace.mspPairId)) continue;
|
|
17359
18094
|
graphics.lines.push({
|
|
17360
18095
|
points: trace.tracePath,
|
|
17361
18096
|
strokeColor: "green",
|
|
@@ -17821,7 +18556,9 @@ var SchematicTracePipelineSolver = class extends BaseSolver {
|
|
|
17821
18556
|
inputProblem: instance.inputProblem,
|
|
17822
18557
|
traces: junctionOutput.traces,
|
|
17823
18558
|
netLabelPlacements: junctionOutput.netLabelPlacements,
|
|
17824
|
-
completedReroutes
|
|
18559
|
+
completedReroutes,
|
|
18560
|
+
resolveTraceCollisions: true,
|
|
18561
|
+
netLabelConnectorTraceIds: instance.availableNetOrientationSolver.netLabelConnectorTraceIds
|
|
17825
18562
|
}
|
|
17826
18563
|
];
|
|
17827
18564
|
}
|