@tscircuit/schematic-trace-solver 0.0.174 → 0.0.176
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 +5 -0
- package/dist/index.js +759 -91
- package/lib/solvers/AvailableNetOrientationSolver/AvailableNetOrientationSolver.ts +5 -1
- package/lib/solvers/InlineNetLabelSolver/InlineNetLabelSolver.ts +16 -1
- package/lib/solvers/InlineNetLabelSolver/restoreReroutesAroundSupersededLabels.ts +174 -0
- package/lib/solvers/NetLabelToTraceSolver/NetLabelToTraceSolver.ts +2 -30
- package/lib/solvers/SameNetJunctionAlignmentSolver/SameNetJunctionAlignmentSolver.ts +2 -0
- package/lib/solvers/SameNetJunctionAlignmentSolver/alignSameNetJunctions.ts +748 -15
- package/lib/solvers/SameNetJunctionAlignmentSolver/findNearestSharedPinExitRail.ts +140 -0
- package/lib/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver.ts +12 -5
- package/lib/utils/doesPathCoincideWithTraces.ts +17 -4
- package/lib/utils/pathIntersectsRenderedLabel.ts +33 -0
- package/package.json +1 -1
- package/site/bug-reports/bug-report-20260901T055358Z.page.tsx +4 -0
- package/site/bug-reports/bug-report-20260901T064117Z.page.tsx +4 -0
- package/site/bug-reports/bug-report-20260901T134241Z.page.tsx +4 -0
- package/tests/bug-reports/bug-report-20260707T134549Z/__snapshots__/bug-report-20260707T134549Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260707T134549Z/bug-report-20260707T134549Z.test.ts +9 -0
- package/tests/bug-reports/bug-report-20260707T230831Z/__snapshots__/bug-report-20260707T230831Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260717T042845Z/__snapshots__/bug-report-20260717T042845Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260721T221026Z/__snapshots__/bug-report-20260721T221026Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260730T061837Z/__snapshots__/bug-report-20260730T061837Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260730T061837Z/bug-report-20260730T061837Z.test.ts +8 -4
- package/tests/bug-reports/bug-report-20260804T171919Z/__snapshots__/bug-report-20260804T171919Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260805T061316Z/__snapshots__/bug-report-20260805T061316Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260806T061548Z/__snapshots__/bug-report-20260806T061548Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260825T045913Z/__snapshots__/bug-report-20260825T045913Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260826T072956Z/__snapshots__/bug-report-20260826T072956Z.snap.svg +6 -6
- package/tests/bug-reports/bug-report-20260901T055358Z/__snapshots__/bug-report-20260901T055358Z.snap.svg +676 -0
- package/tests/bug-reports/bug-report-20260901T055358Z/bug-report-20260901T055358Z.json +2467 -0
- package/tests/bug-reports/bug-report-20260901T055358Z/bug-report-20260901T055358Z.test.ts +59 -0
- package/tests/bug-reports/bug-report-20260901T064117Z/__snapshots__/bug-report-20260901T064117Z.snap.svg +134 -0
- package/tests/bug-reports/bug-report-20260901T064117Z/bug-report-20260901T064117Z.json +215 -0
- package/tests/bug-reports/bug-report-20260901T064117Z/bug-report-20260901T064117Z.test.ts +12 -0
- package/tests/bug-reports/bug-report-20260901T134241Z/__snapshots__/bug-report-20260901T134241Z.snap.svg +115 -0
- package/tests/bug-reports/bug-report-20260901T134241Z/bug-report-20260901T134241Z.json +359 -0
- package/tests/bug-reports/bug-report-20260901T134241Z/bug-report-20260901T134241Z.test.ts +60 -0
- package/tests/examples/__snapshots__/example51.snap.svg +2 -2
- package/tests/repros/__snapshots__/board-1273-trace-overlap-cycle.snap.svg +10 -10
- package/tests/repros/__snapshots__/board1096-usb-label-overlap-iteration.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-bq25895-cross-net-trace-overlap.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-core-ground-inline-label-fallback.snap.svg +10 -10
- package/tests/repros/__snapshots__/repro-example35-minimize-trace-crossing.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-isolated-rs485-isow7841.snap.svg +18 -18
- package/tests/repros/__snapshots__/repro-pga300-redundant-ground-traces.snap.svg +18 -18
- package/tests/repros/__snapshots__/repro-pmp11282-isolated-dcdc.snap.svg +10 -10
- package/tests/repros/__snapshots__/repro-powerbank-3v-system-power.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-ti-power-output-section.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-tida-01389-hbridge.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-tida010076-page02.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-trellis-core-gnd-net-label-overlap.snap.svg +134 -0
- package/tests/repros/__snapshots__/repro-wireless-mouse-charger-section.snap.svg +164 -0
- package/tests/repros/__snapshots__/repro161-power-section-autolayout.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro48-555-timer-vcc-rail-label.snap.svg +2 -2
- package/tests/repros/assets/repro-trellis-core-gnd-net-label-overlap.input.json +178 -0
- package/tests/repros/assets/repro-wireless-mouse-charger-section.input.json +591 -0
- package/tests/repros/repro-isolated-rs485-isow7841.test.ts +4 -1
- package/tests/repros/repro-powerbank-3v-system-power.test.ts +24 -0
- package/tests/repros/repro-tida-01389-hbridge.test.ts +24 -0
- package/tests/repros/repro-trellis-core-gnd-net-label-overlap.test.ts +73 -0
- package/tests/repros/repro-wireless-mouse-charger-section.test.ts +16 -0
- package/tests/solvers/InlineNetLabelSolver/restore-reroutes-around-superseded-labels.test.ts +186 -0
- package/tests/solvers/SameNetJunctionAlignmentSolver/parallel-load-rails.test.ts +1 -0
package/dist/index.js
CHANGED
|
@@ -325,19 +325,19 @@ var doesPairCrossRestrictedCenterLines = (params) => {
|
|
|
325
325
|
chipMap
|
|
326
326
|
});
|
|
327
327
|
if (restrictedCenterLines.size === 0) return false;
|
|
328
|
-
const
|
|
328
|
+
const EPS16 = 1e-9;
|
|
329
329
|
const crossesSegment = (a, b) => {
|
|
330
330
|
for (const [, rcl] of restrictedCenterLines) {
|
|
331
331
|
if (rcl.axes.has("x") && typeof rcl.x === "number") {
|
|
332
|
-
if ((a.x - rcl.x) * (b.x - rcl.x) < -
|
|
332
|
+
if ((a.x - rcl.x) * (b.x - rcl.x) < -EPS16) return true;
|
|
333
333
|
}
|
|
334
334
|
if (rcl.axes.has("y") && typeof rcl.y === "number") {
|
|
335
|
-
if ((a.y - rcl.y) * (b.y - rcl.y) < -
|
|
335
|
+
if ((a.y - rcl.y) * (b.y - rcl.y) < -EPS16) return true;
|
|
336
336
|
}
|
|
337
337
|
}
|
|
338
338
|
return false;
|
|
339
339
|
};
|
|
340
|
-
if (Math.abs(p1.x - p2.x) <
|
|
340
|
+
if (Math.abs(p1.x - p2.x) < EPS16 || Math.abs(p1.y - p2.y) < EPS16) {
|
|
341
341
|
return crossesSegment({ x: p1.x, y: p1.y }, { x: p2.x, y: p2.y });
|
|
342
342
|
}
|
|
343
343
|
const elbowHV = { x: p2.x, y: p1.y };
|
|
@@ -1575,8 +1575,8 @@ var SchematicTraceSingleLineSolver2 = class extends BaseSolver {
|
|
|
1575
1575
|
if (!collision) {
|
|
1576
1576
|
const first = path[0];
|
|
1577
1577
|
const last = path[path.length - 1];
|
|
1578
|
-
const
|
|
1579
|
-
const samePoint = (p, q) => Math.abs(p.x - q.x) <
|
|
1578
|
+
const EPS16 = 1e-9;
|
|
1579
|
+
const samePoint = (p, q) => Math.abs(p.x - q.x) < EPS16 && Math.abs(p.y - q.y) < EPS16;
|
|
1580
1580
|
if (samePoint(first, { x: PA.x, y: PA.y }) && samePoint(last, { x: PB.x, y: PB.y })) {
|
|
1581
1581
|
this.solvedTracePath = path;
|
|
1582
1582
|
this.solved = true;
|
|
@@ -1887,13 +1887,13 @@ var applyJogToTerminalSegment = ({
|
|
|
1887
1887
|
segmentIndex: si,
|
|
1888
1888
|
offset,
|
|
1889
1889
|
JOG_SIZE,
|
|
1890
|
-
EPS:
|
|
1890
|
+
EPS: EPS16 = 1e-6
|
|
1891
1891
|
}) => {
|
|
1892
1892
|
if (si !== 0 && si !== pts.length - 2) return;
|
|
1893
1893
|
const start = pts[si];
|
|
1894
1894
|
const end = pts[si + 1];
|
|
1895
|
-
const isVertical6 = Math.abs(start.x - end.x) <
|
|
1896
|
-
const isHorizontal5 = Math.abs(start.y - end.y) <
|
|
1895
|
+
const isVertical6 = Math.abs(start.x - end.x) < EPS16;
|
|
1896
|
+
const isHorizontal5 = Math.abs(start.y - end.y) < EPS16;
|
|
1897
1897
|
if (!isVertical6 && !isHorizontal5) return;
|
|
1898
1898
|
const segDir = isVertical6 ? end.y > start.y ? 1 : -1 : end.x > start.x ? 1 : -1;
|
|
1899
1899
|
if (pts.length === 2) {
|
|
@@ -2327,7 +2327,7 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
|
|
|
2327
2327
|
return islands;
|
|
2328
2328
|
}
|
|
2329
2329
|
findNextOverlapIssue() {
|
|
2330
|
-
const
|
|
2330
|
+
const EPS16 = 2e-3;
|
|
2331
2331
|
const netIds = Object.keys(this.traceNetIslands);
|
|
2332
2332
|
for (let i = 0; i < netIds.length; i++) {
|
|
2333
2333
|
for (let j = i + 1; j < netIds.length; j++) {
|
|
@@ -2354,7 +2354,7 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
|
|
|
2354
2354
|
segmentBIndex,
|
|
2355
2355
|
rangeOverlap
|
|
2356
2356
|
}) => {
|
|
2357
|
-
if (rangeOverlap >
|
|
2357
|
+
if (rangeOverlap > EPS16) {
|
|
2358
2358
|
const keyA = `${pathAIndex}:${segmentAIndex}`;
|
|
2359
2359
|
const keyB = `${pathBIndex}:${segmentBIndex}`;
|
|
2360
2360
|
if (!seenA.has(keyA)) {
|
|
@@ -2373,7 +2373,7 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
|
|
|
2373
2373
|
}
|
|
2374
2374
|
return;
|
|
2375
2375
|
}
|
|
2376
|
-
if (rangeOverlap < -
|
|
2376
|
+
if (rangeOverlap < -EPS16) return;
|
|
2377
2377
|
const pathA = pathsA[pathAIndex].tracePath;
|
|
2378
2378
|
const pathB = pathsB[pathBIndex].tracePath;
|
|
2379
2379
|
const segmentAStart = pathA[segmentAIndex];
|
|
@@ -2396,8 +2396,8 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
|
|
|
2396
2396
|
for (let sa = 0; sa < ptsA.length - 1; sa++) {
|
|
2397
2397
|
const a1 = ptsA[sa];
|
|
2398
2398
|
const a2 = ptsA[sa + 1];
|
|
2399
|
-
const aVert = Math.abs(a1.x - a2.x) <
|
|
2400
|
-
const aHorz = Math.abs(a1.y - a2.y) <
|
|
2399
|
+
const aVert = Math.abs(a1.x - a2.x) < EPS16;
|
|
2400
|
+
const aHorz = Math.abs(a1.y - a2.y) < EPS16;
|
|
2401
2401
|
if (!aVert && !aHorz) continue;
|
|
2402
2402
|
for (let pb = 0; pb < pathsB.length; pb++) {
|
|
2403
2403
|
const pathB = pathsB[pb];
|
|
@@ -2408,11 +2408,11 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
|
|
|
2408
2408
|
for (let sb = 0; sb < ptsB.length - 1; sb++) {
|
|
2409
2409
|
const b1 = ptsB[sb];
|
|
2410
2410
|
const b2 = ptsB[sb + 1];
|
|
2411
|
-
const bVert = Math.abs(b1.x - b2.x) <
|
|
2412
|
-
const bHorz = Math.abs(b1.y - b2.y) <
|
|
2411
|
+
const bVert = Math.abs(b1.x - b2.x) < EPS16;
|
|
2412
|
+
const bHorz = Math.abs(b1.y - b2.y) < EPS16;
|
|
2413
2413
|
if (!bVert && !bHorz) continue;
|
|
2414
2414
|
if (aVert && bVert) {
|
|
2415
|
-
if (Math.abs(a1.x - b1.x) <
|
|
2415
|
+
if (Math.abs(a1.x - b1.x) < EPS16) {
|
|
2416
2416
|
recordCollinearInteraction({
|
|
2417
2417
|
pathAIndex: pa,
|
|
2418
2418
|
segmentAIndex: sa,
|
|
@@ -2422,7 +2422,7 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
|
|
|
2422
2422
|
});
|
|
2423
2423
|
}
|
|
2424
2424
|
} else if (aHorz && bHorz) {
|
|
2425
|
-
if (Math.abs(a1.y - b1.y) <
|
|
2425
|
+
if (Math.abs(a1.y - b1.y) < EPS16) {
|
|
2426
2426
|
recordCollinearInteraction({
|
|
2427
2427
|
pathAIndex: pa,
|
|
2428
2428
|
segmentAIndex: sa,
|
|
@@ -2478,14 +2478,14 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
|
|
|
2478
2478
|
return null;
|
|
2479
2479
|
}
|
|
2480
2480
|
findNextDiagonalSegment() {
|
|
2481
|
-
const
|
|
2481
|
+
const EPS16 = 2e-3;
|
|
2482
2482
|
for (const mspPairId in this.correctedTraceMap) {
|
|
2483
2483
|
const tracePath = this.correctedTraceMap[mspPairId].tracePath;
|
|
2484
2484
|
for (let i = 0; i < tracePath.length - 1; i++) {
|
|
2485
2485
|
const p1 = tracePath[i];
|
|
2486
2486
|
const p2 = tracePath[i + 1];
|
|
2487
|
-
const isHorizontal5 = Math.abs(p1.y - p2.y) <
|
|
2488
|
-
const isVertical6 = Math.abs(p1.x - p2.x) <
|
|
2487
|
+
const isHorizontal5 = Math.abs(p1.y - p2.y) < EPS16;
|
|
2488
|
+
const isVertical6 = Math.abs(p1.x - p2.x) < EPS16;
|
|
2489
2489
|
if (!isHorizontal5 && !isVertical6) {
|
|
2490
2490
|
return { mspPairId, tracePath, i, p1, p2 };
|
|
2491
2491
|
}
|
|
@@ -2499,13 +2499,13 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
|
|
|
2499
2499
|
return false;
|
|
2500
2500
|
}
|
|
2501
2501
|
const { mspPairId, tracePath, i, p1, p2 } = diagonalInfo;
|
|
2502
|
-
const
|
|
2502
|
+
const EPS16 = 2e-3;
|
|
2503
2503
|
const p0 = i > 0 ? tracePath[i - 1] : null;
|
|
2504
2504
|
const p3 = i + 2 < tracePath.length ? tracePath[i + 2] : null;
|
|
2505
|
-
const prevIsVertical = p0 ? Math.abs(p0.x - p1.x) <
|
|
2506
|
-
const prevIsHorizontal = p0 ? Math.abs(p0.y - p1.y) <
|
|
2507
|
-
const nextIsVertical = p3 ? Math.abs(p2.x - p3.x) <
|
|
2508
|
-
const nextIsHorizontal = p3 ? Math.abs(p2.y - p3.y) <
|
|
2505
|
+
const prevIsVertical = p0 ? Math.abs(p0.x - p1.x) < EPS16 : false;
|
|
2506
|
+
const prevIsHorizontal = p0 ? Math.abs(p0.y - p1.y) < EPS16 : false;
|
|
2507
|
+
const nextIsVertical = p3 ? Math.abs(p2.x - p3.x) < EPS16 : false;
|
|
2508
|
+
const nextIsHorizontal = p3 ? Math.abs(p2.y - p3.y) < EPS16 : false;
|
|
2509
2509
|
const elbow1 = { x: p1.x, y: p2.y };
|
|
2510
2510
|
const elbow2 = { x: p2.x, y: p1.y };
|
|
2511
2511
|
let score1 = 0;
|
|
@@ -2667,24 +2667,24 @@ var ChipObstacleSpatialIndex = class {
|
|
|
2667
2667
|
};
|
|
2668
2668
|
|
|
2669
2669
|
// lib/solvers/NetLabelPlacementSolver/SingleNetLabelPlacementSolver/collisions.ts
|
|
2670
|
-
function segmentIntersectsRect2(p1, p2, rect,
|
|
2671
|
-
const isVert = Math.abs(p1.x - p2.x) <
|
|
2672
|
-
const isHorz = Math.abs(p1.y - p2.y) <
|
|
2670
|
+
function segmentIntersectsRect2(p1, p2, rect, EPS16 = 1e-9) {
|
|
2671
|
+
const isVert = Math.abs(p1.x - p2.x) < EPS16;
|
|
2672
|
+
const isHorz = Math.abs(p1.y - p2.y) < EPS16;
|
|
2673
2673
|
if (!isVert && !isHorz) return false;
|
|
2674
2674
|
if (isVert) {
|
|
2675
2675
|
const x = p1.x;
|
|
2676
|
-
if (x < rect.minX -
|
|
2676
|
+
if (x < rect.minX - EPS16 || x > rect.maxX + EPS16) return false;
|
|
2677
2677
|
const segMinY = Math.min(p1.y, p2.y);
|
|
2678
2678
|
const segMaxY = Math.max(p1.y, p2.y);
|
|
2679
2679
|
const overlap = Math.min(segMaxY, rect.maxY) - Math.max(segMinY, rect.minY);
|
|
2680
|
-
return overlap >
|
|
2680
|
+
return overlap > EPS16;
|
|
2681
2681
|
} else {
|
|
2682
2682
|
const y = p1.y;
|
|
2683
|
-
if (y < rect.minY -
|
|
2683
|
+
if (y < rect.minY - EPS16 || y > rect.maxY + EPS16) return false;
|
|
2684
2684
|
const segMinX = Math.min(p1.x, p2.x);
|
|
2685
2685
|
const segMaxX = Math.max(p1.x, p2.x);
|
|
2686
2686
|
const overlap = Math.min(segMaxX, rect.maxX) - Math.max(segMinX, rect.minX);
|
|
2687
|
-
return overlap >
|
|
2687
|
+
return overlap > EPS16;
|
|
2688
2688
|
}
|
|
2689
2689
|
}
|
|
2690
2690
|
function rectIntersectsAnyTrace(bounds, inputTraceMap, hostPathId, hostSegIndex) {
|
|
@@ -3083,14 +3083,14 @@ var SingleNetLabelPlacementSolver = class extends BaseSolver {
|
|
|
3083
3083
|
};
|
|
3084
3084
|
let bestCandidate = null;
|
|
3085
3085
|
let bestScore = -Infinity;
|
|
3086
|
-
const
|
|
3086
|
+
const EPS16 = 1e-6;
|
|
3087
3087
|
for (const curr of tracesToScan) {
|
|
3088
3088
|
const pts = curr.tracePath.slice();
|
|
3089
3089
|
for (let si = 0; si < pts.length - 1; si++) {
|
|
3090
3090
|
const a = pts[si];
|
|
3091
3091
|
const b = pts[si + 1];
|
|
3092
|
-
const isH = Math.abs(a.y - b.y) <
|
|
3093
|
-
const isV = Math.abs(a.x - b.x) <
|
|
3092
|
+
const isH = Math.abs(a.y - b.y) < EPS16;
|
|
3093
|
+
const isV = Math.abs(a.x - b.x) < EPS16;
|
|
3094
3094
|
if (!isH && !isV) continue;
|
|
3095
3095
|
const segmentAllowed = isH ? ["y+", "y-"] : ["x+", "x-"];
|
|
3096
3096
|
const candidateOrients = orientations.filter(
|
|
@@ -4171,7 +4171,11 @@ var GEOMETRY_EPS = 1e-6;
|
|
|
4171
4171
|
var SCHEMATIC_TRACE_STROKE_WIDTH = 0.02;
|
|
4172
4172
|
var SCHEMATIC_TRACE_MIN_CENTERLINE_CLEARANCE = SCHEMATIC_TRACE_STROKE_WIDTH + GEOMETRY_EPS;
|
|
4173
4173
|
var SCHEMATIC_TRACE_MIN_VISUAL_CENTERLINE_CLEARANCE = SCHEMATIC_TRACE_STROKE_WIDTH * 3;
|
|
4174
|
-
var doesPathCoincideWithTraces = (path, traces) =>
|
|
4174
|
+
var doesPathCoincideWithTraces = (path, traces) => doesPathCoincideWithPaths(
|
|
4175
|
+
path,
|
|
4176
|
+
traces.map((trace) => trace.tracePath)
|
|
4177
|
+
);
|
|
4178
|
+
var doesPathCoincideWithPaths = (path, otherPaths) => {
|
|
4175
4179
|
const rangesOverlap1D = (a1, a2, b1, b2) => Math.min(Math.max(a1, a2), Math.max(b1, b2)) - Math.max(Math.min(a1, a2), Math.min(b1, b2)) > COINCIDENT_EPS;
|
|
4176
4180
|
for (let i = 0; i < path.length - 1; i++) {
|
|
4177
4181
|
const pathSegStart = path[i];
|
|
@@ -4181,10 +4185,10 @@ var doesPathCoincideWithTraces = (path, traces) => {
|
|
|
4181
4185
|
if (!isVertical6 && !isHorizontal5) continue;
|
|
4182
4186
|
const crossAxis = isVertical6 ? "x" : "y";
|
|
4183
4187
|
const alongAxis = isVertical6 ? "y" : "x";
|
|
4184
|
-
for (const
|
|
4185
|
-
for (let j = 0; j <
|
|
4186
|
-
const traceSegStart =
|
|
4187
|
-
const traceSegEnd =
|
|
4188
|
+
for (const otherPath of otherPaths) {
|
|
4189
|
+
for (let j = 0; j < otherPath.length - 1; j++) {
|
|
4190
|
+
const traceSegStart = otherPath[j];
|
|
4191
|
+
const traceSegEnd = otherPath[j + 1];
|
|
4188
4192
|
const isParallel = Math.abs(traceSegStart[crossAxis] - traceSegEnd[crossAxis]) < COINCIDENT_EPS;
|
|
4189
4193
|
if (!isParallel) continue;
|
|
4190
4194
|
const isCoincident = Math.abs(pathSegStart[crossAxis] - traceSegStart[crossAxis]) < COINCIDENT_EPS;
|
|
@@ -8862,6 +8866,8 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
8862
8866
|
inputProblem;
|
|
8863
8867
|
traces;
|
|
8864
8868
|
netLabelPlacements;
|
|
8869
|
+
/** Exact provenance for connector traces created by this solver. */
|
|
8870
|
+
netLabelConnectorTraceIds = /* @__PURE__ */ new Set();
|
|
8865
8871
|
outputNetLabelPlacements;
|
|
8866
8872
|
queuedLabelIndices = [];
|
|
8867
8873
|
currentLabelIndex = null;
|
|
@@ -9112,6 +9118,7 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
9112
9118
|
};
|
|
9113
9119
|
this.traces.push(connectorTrace);
|
|
9114
9120
|
this.traceMap[mspPairId] = connectorTrace;
|
|
9121
|
+
this.netLabelConnectorTraceIds.add(mspPairId);
|
|
9115
9122
|
}
|
|
9116
9123
|
finish() {
|
|
9117
9124
|
this.currentLabelIndex = null;
|
|
@@ -9434,7 +9441,7 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
9434
9441
|
foundConnectedTrace = false;
|
|
9435
9442
|
for (const trace of Object.values(this.traceMap)) {
|
|
9436
9443
|
if (connectedTraceIds.has(trace.mspPairId)) continue;
|
|
9437
|
-
if (trace.mspPairId
|
|
9444
|
+
if (this.netLabelConnectorTraceIds.has(trace.mspPairId)) continue;
|
|
9438
9445
|
if (trace.globalConnNetId !== label.globalConnNetId) continue;
|
|
9439
9446
|
if (!trace.pinIds.some((pinId) => connectedPinIds.has(pinId)))
|
|
9440
9447
|
continue;
|
|
@@ -12669,11 +12676,99 @@ var pathEntersAnyNetLabel = ({
|
|
|
12669
12676
|
return false;
|
|
12670
12677
|
};
|
|
12671
12678
|
|
|
12679
|
+
// lib/solvers/SameNetJunctionAlignmentSolver/findNearestSharedPinExitRail.ts
|
|
12680
|
+
var getPinFacingAxis = (pin) => {
|
|
12681
|
+
if (!pin._facingDirection) return null;
|
|
12682
|
+
return dir(pin._facingDirection).x === 0 ? "y" : "x";
|
|
12683
|
+
};
|
|
12684
|
+
var isCoordinateOnPinFacingSide = ({
|
|
12685
|
+
coordinate,
|
|
12686
|
+
axis,
|
|
12687
|
+
pin
|
|
12688
|
+
}) => {
|
|
12689
|
+
if (!pin._facingDirection) return false;
|
|
12690
|
+
const facingVector = dir(pin._facingDirection);
|
|
12691
|
+
return (coordinate - pin[axis]) * facingVector[axis] > 0;
|
|
12692
|
+
};
|
|
12693
|
+
var getSegmentAxis2 = (start, end) => {
|
|
12694
|
+
if (isHorizontal2(start, end)) return "x";
|
|
12695
|
+
if (isVertical2(start, end)) return "y";
|
|
12696
|
+
return null;
|
|
12697
|
+
};
|
|
12698
|
+
var getAxisAlignedSegments = (path) => {
|
|
12699
|
+
const segments = [];
|
|
12700
|
+
for (let index = 0; index < path.length - 1; index++) {
|
|
12701
|
+
const start = path[index];
|
|
12702
|
+
const end = path[index + 1];
|
|
12703
|
+
const axis = getSegmentAxis2(start, end);
|
|
12704
|
+
if (!axis) continue;
|
|
12705
|
+
const coordinateAxis = axis === "x" ? "y" : "x";
|
|
12706
|
+
segments.push({ start, end, axis, coordinate: start[coordinateAxis] });
|
|
12707
|
+
}
|
|
12708
|
+
return segments;
|
|
12709
|
+
};
|
|
12710
|
+
var getPinExitPoint = ({
|
|
12711
|
+
pin,
|
|
12712
|
+
departureAxis,
|
|
12713
|
+
railCoordinate
|
|
12714
|
+
}) => departureAxis === "x" ? { x: railCoordinate, y: pin.y } : { x: pin.x, y: railCoordinate };
|
|
12715
|
+
var findNearestSharedPinExitRail = ({
|
|
12716
|
+
donorPath,
|
|
12717
|
+
branchDepartureSegment,
|
|
12718
|
+
sharedPin,
|
|
12719
|
+
adjacentPin
|
|
12720
|
+
}) => {
|
|
12721
|
+
const departureAxis = getPinFacingAxis(sharedPin);
|
|
12722
|
+
if (!departureAxis) return null;
|
|
12723
|
+
const railAxis = departureAxis === "x" ? "y" : "x";
|
|
12724
|
+
const branchDeparture = getAxisAlignedSegments(branchDepartureSegment)[0];
|
|
12725
|
+
if (!branchDeparture || branchDeparture.axis !== departureAxis) return null;
|
|
12726
|
+
let nearestRail = null;
|
|
12727
|
+
let nearestDistance = Number.POSITIVE_INFINITY;
|
|
12728
|
+
for (const segment of getAxisAlignedSegments(donorPath)) {
|
|
12729
|
+
if (segment.axis !== railAxis) continue;
|
|
12730
|
+
if (!isCoordinateOnPinFacingSide({
|
|
12731
|
+
coordinate: segment.coordinate,
|
|
12732
|
+
axis: departureAxis,
|
|
12733
|
+
pin: sharedPin
|
|
12734
|
+
})) {
|
|
12735
|
+
continue;
|
|
12736
|
+
}
|
|
12737
|
+
const sharedPinExit = getPinExitPoint({
|
|
12738
|
+
pin: sharedPin,
|
|
12739
|
+
departureAxis,
|
|
12740
|
+
railCoordinate: segment.coordinate
|
|
12741
|
+
});
|
|
12742
|
+
const adjacentPinExit = getPinExitPoint({
|
|
12743
|
+
pin: adjacentPin,
|
|
12744
|
+
departureAxis,
|
|
12745
|
+
railCoordinate: segment.coordinate
|
|
12746
|
+
});
|
|
12747
|
+
if (!tracePathContainsPoint([segment.start, segment.end], sharedPinExit) || !tracePathContainsPoint([segment.start, segment.end], adjacentPinExit) || !tracePathContainsPoint(
|
|
12748
|
+
[branchDeparture.start, branchDeparture.end],
|
|
12749
|
+
sharedPinExit
|
|
12750
|
+
)) {
|
|
12751
|
+
continue;
|
|
12752
|
+
}
|
|
12753
|
+
const distance7 = Math.abs(segment.coordinate - sharedPin[departureAxis]);
|
|
12754
|
+
if (distance7 >= nearestDistance) continue;
|
|
12755
|
+
nearestRail = { segment, sharedPinExit };
|
|
12756
|
+
nearestDistance = distance7;
|
|
12757
|
+
}
|
|
12758
|
+
return nearestRail;
|
|
12759
|
+
};
|
|
12760
|
+
|
|
12672
12761
|
// lib/solvers/SameNetJunctionAlignmentSolver/alignSameNetJunctions.ts
|
|
12673
12762
|
var MAX_ALIGNED_LOAD_PIN_OFFSET = 0.2;
|
|
12674
12763
|
var MAX_SAME_NET_LABEL_BOUNDARY_RAIL_OFFSET = 0.2;
|
|
12675
12764
|
var MAX_SHARED_PIN_RAIL_OFFSET = 0.05;
|
|
12765
|
+
var MAX_SHARED_ENDPOINT_RAIL_OFFSET = 0.8;
|
|
12676
12766
|
var MIN_RETURN_STEM_LENGTH = 0.05;
|
|
12767
|
+
var getSegmentAxis3 = (start, end) => {
|
|
12768
|
+
if (isHorizontal2(start, end)) return "x";
|
|
12769
|
+
if (isVertical2(start, end)) return "y";
|
|
12770
|
+
return null;
|
|
12771
|
+
};
|
|
12677
12772
|
var getSharedPin = ({
|
|
12678
12773
|
donorTrace,
|
|
12679
12774
|
branchTrace
|
|
@@ -12826,11 +12921,366 @@ var getAlignedBranchPath = ({
|
|
|
12826
12921
|
if (branchTrace.pins[0].pinId === sharedPin.pinId) return sharedToOther;
|
|
12827
12922
|
return [...sharedToOther].reverse();
|
|
12828
12923
|
};
|
|
12924
|
+
var getAlignedParallelPinExitPath = ({
|
|
12925
|
+
donorTrace,
|
|
12926
|
+
branchTrace
|
|
12927
|
+
}) => {
|
|
12928
|
+
const sharedPin = getSharedPin({ donorTrace, branchTrace });
|
|
12929
|
+
if (!sharedPin) return null;
|
|
12930
|
+
const adjacentPin = getOtherPin({ trace: donorTrace, sharedPin });
|
|
12931
|
+
const targetPin = getOtherPin({ trace: branchTrace, sharedPin });
|
|
12932
|
+
if (!adjacentPin || !targetPin) return null;
|
|
12933
|
+
const facing = sharedPin._facingDirection;
|
|
12934
|
+
const departureAxis = getPinFacingAxis(sharedPin);
|
|
12935
|
+
if (!facing || !departureAxis) return null;
|
|
12936
|
+
const stemAxis = departureAxis === "x" ? "y" : "x";
|
|
12937
|
+
if (adjacentPin.chipId !== sharedPin.chipId || adjacentPin._facingDirection !== facing || !nearlyEqual(adjacentPin[departureAxis], sharedPin[departureAxis]) || getPinFacingAxis(targetPin) !== stemAxis) {
|
|
12938
|
+
return null;
|
|
12939
|
+
}
|
|
12940
|
+
const adjacentPinOffset = Math.abs(
|
|
12941
|
+
adjacentPin[stemAxis] - sharedPin[stemAxis]
|
|
12942
|
+
);
|
|
12943
|
+
if (adjacentPinOffset > MAX_ALIGNED_LOAD_PIN_OFFSET && !nearlyEqual(adjacentPinOffset, MAX_ALIGNED_LOAD_PIN_OFFSET)) {
|
|
12944
|
+
return null;
|
|
12945
|
+
}
|
|
12946
|
+
const branchStartsAtSharedPin = branchTrace.pins[0].pinId === sharedPin.pinId;
|
|
12947
|
+
let sharedToTargetPath = simplifyPath(branchTrace.tracePath);
|
|
12948
|
+
if (!branchStartsAtSharedPin) sharedToTargetPath.reverse();
|
|
12949
|
+
if (sharedToTargetPath.length < 2) return null;
|
|
12950
|
+
const branchDepartureSegment = [
|
|
12951
|
+
sharedToTargetPath[0],
|
|
12952
|
+
sharedToTargetPath[1]
|
|
12953
|
+
];
|
|
12954
|
+
const sharedExitRail = findNearestSharedPinExitRail({
|
|
12955
|
+
donorPath: donorTrace.tracePath,
|
|
12956
|
+
branchDepartureSegment,
|
|
12957
|
+
sharedPin,
|
|
12958
|
+
adjacentPin
|
|
12959
|
+
});
|
|
12960
|
+
if (!sharedExitRail) return null;
|
|
12961
|
+
const alignedRailCoordinate = adjacentPin[stemAxis];
|
|
12962
|
+
if (!isCoordinateOnPinFacingSide({
|
|
12963
|
+
coordinate: alignedRailCoordinate,
|
|
12964
|
+
axis: stemAxis,
|
|
12965
|
+
pin: targetPin
|
|
12966
|
+
})) {
|
|
12967
|
+
return null;
|
|
12968
|
+
}
|
|
12969
|
+
const alignedStemExit = {
|
|
12970
|
+
...sharedExitRail.sharedPinExit,
|
|
12971
|
+
[stemAxis]: alignedRailCoordinate
|
|
12972
|
+
};
|
|
12973
|
+
const targetApproach = {
|
|
12974
|
+
x: targetPin.x,
|
|
12975
|
+
y: targetPin.y,
|
|
12976
|
+
[stemAxis]: alignedRailCoordinate
|
|
12977
|
+
};
|
|
12978
|
+
const candidate = simplifyPath([
|
|
12979
|
+
{ x: sharedPin.x, y: sharedPin.y },
|
|
12980
|
+
sharedExitRail.sharedPinExit,
|
|
12981
|
+
alignedStemExit,
|
|
12982
|
+
targetApproach,
|
|
12983
|
+
{ x: targetPin.x, y: targetPin.y }
|
|
12984
|
+
]);
|
|
12985
|
+
return branchStartsAtSharedPin ? candidate : candidate.reverse();
|
|
12986
|
+
};
|
|
12987
|
+
var getAlignedSharedEndpointRailPath = ({
|
|
12988
|
+
donorTrace,
|
|
12989
|
+
branchTrace,
|
|
12990
|
+
netLabelConnectorTraceIds
|
|
12991
|
+
}) => {
|
|
12992
|
+
if (netLabelConnectorTraceIds.has(donorTrace.mspPairId) || netLabelConnectorTraceIds.has(branchTrace.mspPairId)) {
|
|
12993
|
+
return null;
|
|
12994
|
+
}
|
|
12995
|
+
const sharedPin = getSharedPin({ donorTrace, branchTrace });
|
|
12996
|
+
if (!sharedPin) return null;
|
|
12997
|
+
const pathFromShared = (trace) => {
|
|
12998
|
+
const path = simplifyPath(trace.tracePath);
|
|
12999
|
+
return trace.pins[0].pinId === sharedPin.pinId ? path : [...path].reverse();
|
|
13000
|
+
};
|
|
13001
|
+
const donorPath = pathFromShared(donorTrace);
|
|
13002
|
+
const branchPath = pathFromShared(branchTrace);
|
|
13003
|
+
if (donorPath.length < 3 || branchPath.length < 4) return null;
|
|
13004
|
+
const donorDepartureAxis = getSegmentAxis3(donorPath[0], donorPath[1]);
|
|
13005
|
+
const branchDepartureAxis = getSegmentAxis3(branchPath[0], branchPath[1]);
|
|
13006
|
+
if (!donorDepartureAxis || donorDepartureAxis !== branchDepartureAxis) {
|
|
13007
|
+
return null;
|
|
13008
|
+
}
|
|
13009
|
+
const donorDeparture = donorPath[1][donorDepartureAxis] - donorPath[0][donorDepartureAxis];
|
|
13010
|
+
const branchDeparture = branchPath[1][branchDepartureAxis] - branchPath[0][branchDepartureAxis];
|
|
13011
|
+
if (Math.sign(donorDeparture) !== Math.sign(branchDeparture)) return null;
|
|
13012
|
+
const donorRailAxis = getSegmentAxis3(donorPath[1], donorPath[2]);
|
|
13013
|
+
const branchRailAxis = getSegmentAxis3(branchPath[1], branchPath[2]);
|
|
13014
|
+
if (!donorRailAxis || donorRailAxis !== branchRailAxis || donorRailAxis === donorDepartureAxis) {
|
|
13015
|
+
return null;
|
|
13016
|
+
}
|
|
13017
|
+
let branchParallelRailCount = 0;
|
|
13018
|
+
for (let index = 1; index < branchPath.length - 2; index++) {
|
|
13019
|
+
if (getSegmentAxis3(branchPath[index], branchPath[index + 1]) === branchRailAxis) {
|
|
13020
|
+
branchParallelRailCount++;
|
|
13021
|
+
}
|
|
13022
|
+
}
|
|
13023
|
+
if (branchParallelRailCount !== 1) return null;
|
|
13024
|
+
const railCoordinateAxis = donorRailAxis === "x" ? "y" : "x";
|
|
13025
|
+
const donorCoordinate = donorPath[1][railCoordinateAxis];
|
|
13026
|
+
const branchCoordinate = branchPath[1][railCoordinateAxis];
|
|
13027
|
+
const railOffset = Math.abs(donorCoordinate - branchCoordinate);
|
|
13028
|
+
if (nearlyEqual(donorCoordinate, branchCoordinate) || railOffset > MAX_SHARED_ENDPOINT_RAIL_OFFSET) {
|
|
13029
|
+
return null;
|
|
13030
|
+
}
|
|
13031
|
+
const donorRange = [
|
|
13032
|
+
donorPath[1][donorRailAxis],
|
|
13033
|
+
donorPath[2][donorRailAxis]
|
|
13034
|
+
].sort((a, b) => a - b);
|
|
13035
|
+
const branchRange = [
|
|
13036
|
+
branchPath[1][branchRailAxis],
|
|
13037
|
+
branchPath[2][branchRailAxis]
|
|
13038
|
+
].sort((a, b) => a - b);
|
|
13039
|
+
const railsTouchAfterAlignment = Math.min(donorRange[1], branchRange[1]) >= Math.max(donorRange[0], branchRange[0]) - 1e-6;
|
|
13040
|
+
if (!railsTouchAfterAlignment) return null;
|
|
13041
|
+
const candidateFromShared = simplifyPath(
|
|
13042
|
+
branchPath.map(
|
|
13043
|
+
(point, index) => index === 1 || index === 2 ? { ...point, [railCoordinateAxis]: donorCoordinate } : point
|
|
13044
|
+
)
|
|
13045
|
+
);
|
|
13046
|
+
return branchTrace.pins[0].pinId === sharedPin.pinId ? candidateFromShared : candidateFromShared.reverse();
|
|
13047
|
+
};
|
|
13048
|
+
var getAlignedAttachedLabelConnectorPath = ({
|
|
13049
|
+
donorTrace,
|
|
13050
|
+
connectorTrace,
|
|
13051
|
+
netLabelConnectorTraceIds
|
|
13052
|
+
}) => {
|
|
13053
|
+
if (netLabelConnectorTraceIds.has(donorTrace.mspPairId) || !netLabelConnectorTraceIds.has(connectorTrace.mspPairId)) {
|
|
13054
|
+
return null;
|
|
13055
|
+
}
|
|
13056
|
+
const findCandidate = (connectorPath) => {
|
|
13057
|
+
if (connectorPath.length < 3) return null;
|
|
13058
|
+
const junction = connectorPath[0];
|
|
13059
|
+
const turn = connectorPath[1];
|
|
13060
|
+
const railEnd = connectorPath[2];
|
|
13061
|
+
const departureAxis = getSegmentAxis3(junction, turn);
|
|
13062
|
+
const railAxis = getSegmentAxis3(turn, railEnd);
|
|
13063
|
+
if (!departureAxis || !railAxis || departureAxis === railAxis) return null;
|
|
13064
|
+
const donorSegmentIndex = donorTrace.tracePath.findIndex(
|
|
13065
|
+
(point, index, path) => {
|
|
13066
|
+
const next = path[index + 1];
|
|
13067
|
+
return next && getSegmentAxis3(point, next) === departureAxis && tracePathContainsPoint([point, next], junction) && tracePathContainsPoint([point, next], turn);
|
|
13068
|
+
}
|
|
13069
|
+
);
|
|
13070
|
+
if (donorSegmentIndex < 0) return null;
|
|
13071
|
+
const donorSegmentStart = donorTrace.tracePath[donorSegmentIndex];
|
|
13072
|
+
const donorSegmentEnd = donorTrace.tracePath[donorSegmentIndex + 1];
|
|
13073
|
+
if (nearlyEqual(junction.x, donorSegmentStart.x) && nearlyEqual(junction.y, donorSegmentStart.y) || nearlyEqual(junction.x, donorSegmentEnd.x) && nearlyEqual(junction.y, donorSegmentEnd.y)) {
|
|
13074
|
+
return null;
|
|
13075
|
+
}
|
|
13076
|
+
const adjacentDonorRails = [
|
|
13077
|
+
donorSegmentIndex > 0 ? [donorTrace.tracePath[donorSegmentIndex - 1], donorSegmentStart] : null,
|
|
13078
|
+
donorSegmentIndex + 2 < donorTrace.tracePath.length ? [donorSegmentEnd, donorTrace.tracePath[donorSegmentIndex + 2]] : null
|
|
13079
|
+
].flatMap(
|
|
13080
|
+
(segment) => segment && getSegmentAxis3(segment[0], segment[1]) === railAxis ? [segment] : []
|
|
13081
|
+
);
|
|
13082
|
+
if (adjacentDonorRails.length === 0) return null;
|
|
13083
|
+
const railCoordinateAxis = railAxis === "x" ? "y" : "x";
|
|
13084
|
+
const connectorRailCoordinate = turn[railCoordinateAxis];
|
|
13085
|
+
const connectorRange = [turn[railAxis], railEnd[railAxis]].sort(
|
|
13086
|
+
(a, b) => a - b
|
|
13087
|
+
);
|
|
13088
|
+
const donorRail = adjacentDonorRails.map((segment) => ({
|
|
13089
|
+
segment,
|
|
13090
|
+
coordinate: segment[0][railCoordinateAxis],
|
|
13091
|
+
offset: Math.abs(
|
|
13092
|
+
segment[0][railCoordinateAxis] - connectorRailCoordinate
|
|
13093
|
+
)
|
|
13094
|
+
})).filter(({ segment, offset }) => {
|
|
13095
|
+
if (offset > MAX_SHARED_ENDPOINT_RAIL_OFFSET) return false;
|
|
13096
|
+
const donorRange = [segment[0][railAxis], segment[1][railAxis]].sort(
|
|
13097
|
+
(a, b) => a - b
|
|
13098
|
+
);
|
|
13099
|
+
const overlapStart = Math.max(donorRange[0], connectorRange[0]);
|
|
13100
|
+
const overlapEnd = Math.min(donorRange[1], connectorRange[1]);
|
|
13101
|
+
return overlapEnd >= overlapStart - 1e-6 && Math.abs(overlapEnd - overlapStart) <= 1e-6;
|
|
13102
|
+
}).sort((a, b) => a.offset - b.offset)[0];
|
|
13103
|
+
if (!donorRail || nearlyEqual(donorRail.offset, 0)) return null;
|
|
13104
|
+
return simplifyPath(
|
|
13105
|
+
connectorPath.map(
|
|
13106
|
+
(point, index) => index === 1 || index === 2 ? { ...point, [railCoordinateAxis]: donorRail.coordinate } : point
|
|
13107
|
+
)
|
|
13108
|
+
);
|
|
13109
|
+
};
|
|
13110
|
+
const forwardPath = simplifyPath(connectorTrace.tracePath);
|
|
13111
|
+
const forwardCandidate = findCandidate(forwardPath);
|
|
13112
|
+
if (forwardCandidate) return forwardCandidate;
|
|
13113
|
+
const reverseCandidate = findCandidate([...forwardPath].reverse());
|
|
13114
|
+
return reverseCandidate ? reverseCandidate.reverse() : null;
|
|
13115
|
+
};
|
|
13116
|
+
var pathsIntersect = (firstPath, secondPath) => {
|
|
13117
|
+
if (firstPath.some((point) => tracePathContainsPoint(secondPath, point)) || secondPath.some((point) => tracePathContainsPoint(firstPath, point))) {
|
|
13118
|
+
return true;
|
|
13119
|
+
}
|
|
13120
|
+
for (let firstIndex = 1; firstIndex < firstPath.length; firstIndex++) {
|
|
13121
|
+
for (let secondIndex = 1; secondIndex < secondPath.length; secondIndex++) {
|
|
13122
|
+
if (getSegmentIntersection3(
|
|
13123
|
+
firstPath[firstIndex - 1],
|
|
13124
|
+
firstPath[firstIndex],
|
|
13125
|
+
secondPath[secondIndex - 1],
|
|
13126
|
+
secondPath[secondIndex]
|
|
13127
|
+
)) {
|
|
13128
|
+
return true;
|
|
13129
|
+
}
|
|
13130
|
+
}
|
|
13131
|
+
}
|
|
13132
|
+
return false;
|
|
13133
|
+
};
|
|
13134
|
+
var preserveAttachedLabelConnectorJunctions = ({
|
|
13135
|
+
originalTrace,
|
|
13136
|
+
candidateTrace,
|
|
13137
|
+
traces,
|
|
13138
|
+
netLabelConnectorTraceIds
|
|
13139
|
+
}) => {
|
|
13140
|
+
let outputTraces = traces.map(
|
|
13141
|
+
(trace) => trace.mspPairId === originalTrace.mspPairId ? candidateTrace : trace
|
|
13142
|
+
);
|
|
13143
|
+
for (const connector of traces) {
|
|
13144
|
+
if (connector.mspPairId === originalTrace.mspPairId || !netLabelConnectorTraceIds.has(connector.mspPairId) || connector.globalConnNetId !== originalTrace.globalConnNetId || !pathsIntersect(originalTrace.tracePath, connector.tracePath) || pathsIntersect(candidateTrace.tracePath, connector.tracePath)) {
|
|
13145
|
+
continue;
|
|
13146
|
+
}
|
|
13147
|
+
const endpointIndex = [0, connector.tracePath.length - 1].find(
|
|
13148
|
+
(index) => tracePathContainsPoint(
|
|
13149
|
+
originalTrace.tracePath,
|
|
13150
|
+
connector.tracePath[index]
|
|
13151
|
+
)
|
|
13152
|
+
);
|
|
13153
|
+
if (endpointIndex === void 0) return null;
|
|
13154
|
+
const originalJunction = connector.tracePath[endpointIndex];
|
|
13155
|
+
const movedJunction = getMovedAnchorPointForReroute(
|
|
13156
|
+
originalJunction,
|
|
13157
|
+
originalTrace.tracePath,
|
|
13158
|
+
candidateTrace.tracePath
|
|
13159
|
+
);
|
|
13160
|
+
if (!movedJunction) return null;
|
|
13161
|
+
const neighborIndex = endpointIndex === 0 ? 1 : endpointIndex - 1;
|
|
13162
|
+
const neighbor = connector.tracePath[neighborIndex];
|
|
13163
|
+
if (!neighbor || getSegmentAxis3(originalJunction, neighbor) !== getSegmentAxis3(movedJunction, neighbor)) {
|
|
13164
|
+
return null;
|
|
13165
|
+
}
|
|
13166
|
+
const movedConnector = {
|
|
13167
|
+
...connector,
|
|
13168
|
+
tracePath: connector.tracePath.map(
|
|
13169
|
+
(point, index) => index === endpointIndex ? movedJunction : point
|
|
13170
|
+
)
|
|
13171
|
+
};
|
|
13172
|
+
if (!pathsIntersect(candidateTrace.tracePath, movedConnector.tracePath)) {
|
|
13173
|
+
return null;
|
|
13174
|
+
}
|
|
13175
|
+
outputTraces = outputTraces.map(
|
|
13176
|
+
(trace) => trace.mspPairId === connector.mspPairId ? movedConnector : trace
|
|
13177
|
+
);
|
|
13178
|
+
}
|
|
13179
|
+
return outputTraces;
|
|
13180
|
+
};
|
|
13181
|
+
var getPerpendicularPinRail = ({
|
|
13182
|
+
trace,
|
|
13183
|
+
endpointPin
|
|
13184
|
+
}) => {
|
|
13185
|
+
const otherPin = getOtherPin({ trace, sharedPin: endpointPin });
|
|
13186
|
+
if (!otherPin) return null;
|
|
13187
|
+
const startsAtEndpoint = trace.pins[0].pinId === endpointPin.pinId;
|
|
13188
|
+
let endpointToOtherPath = simplifyPath(trace.tracePath);
|
|
13189
|
+
if (!startsAtEndpoint) endpointToOtherPath.reverse();
|
|
13190
|
+
if (endpointToOtherPath.length !== 3) return null;
|
|
13191
|
+
const [endpoint, railPoint, other] = endpointToOtherPath;
|
|
13192
|
+
const endpointFacing = endpointPin._facingDirection;
|
|
13193
|
+
if (endpointFacing === "y+" || endpointFacing === "y-") {
|
|
13194
|
+
if (otherPin._facingDirection !== "x+" && otherPin._facingDirection !== "x-") {
|
|
13195
|
+
return null;
|
|
13196
|
+
}
|
|
13197
|
+
if (!isVertical2(endpoint, railPoint) || !isHorizontal2(railPoint, other) || !railIsOnFacingSide({ railY: railPoint.y, pin: endpointPin })) {
|
|
13198
|
+
return null;
|
|
13199
|
+
}
|
|
13200
|
+
const approachesOtherFromFacingSide2 = otherPin._facingDirection === "x-" ? railPoint.x < otherPin.x : railPoint.x > otherPin.x;
|
|
13201
|
+
return approachesOtherFromFacingSide2 ? { railCoordinate: railPoint.y } : null;
|
|
13202
|
+
}
|
|
13203
|
+
if (endpointFacing !== "x+" && endpointFacing !== "x-") return null;
|
|
13204
|
+
if (otherPin._facingDirection !== "y+" && otherPin._facingDirection !== "y-") {
|
|
13205
|
+
return null;
|
|
13206
|
+
}
|
|
13207
|
+
if (!isHorizontal2(endpoint, railPoint) || !isVertical2(railPoint, other)) {
|
|
13208
|
+
return null;
|
|
13209
|
+
}
|
|
13210
|
+
const railIsOnEndpointFacingSide = endpointFacing === "x+" ? railPoint.x > endpointPin.x : railPoint.x < endpointPin.x;
|
|
13211
|
+
const approachesOtherFromFacingSide = otherPin._facingDirection === "y+" ? railPoint.y > otherPin.y : railPoint.y < otherPin.y;
|
|
13212
|
+
return railIsOnEndpointFacingSide && approachesOtherFromFacingSide ? { railCoordinate: railPoint.x } : null;
|
|
13213
|
+
};
|
|
13214
|
+
var getAlignedPerpendicularEndpointBusPath = ({
|
|
13215
|
+
donorTrace,
|
|
13216
|
+
branchTrace,
|
|
13217
|
+
traces
|
|
13218
|
+
}) => {
|
|
13219
|
+
const sharedPin = getSharedPin({ donorTrace, branchTrace });
|
|
13220
|
+
if (!sharedPin) return null;
|
|
13221
|
+
const returnPin = getOtherPin({ trace: branchTrace, sharedPin });
|
|
13222
|
+
if (!returnPin) return null;
|
|
13223
|
+
const getOtherSameNetTracesAtPin = (pin) => traces.filter(
|
|
13224
|
+
(trace) => trace.mspPairId !== branchTrace.mspPairId && trace.globalConnNetId === branchTrace.globalConnNetId && trace.pinIds.includes(pin.pinId)
|
|
13225
|
+
);
|
|
13226
|
+
const sharedDonorTraces = getOtherSameNetTracesAtPin(sharedPin);
|
|
13227
|
+
const returnDonorTraces = getOtherSameNetTracesAtPin(returnPin);
|
|
13228
|
+
if (sharedDonorTraces.length !== 1 || sharedDonorTraces[0].mspPairId !== donorTrace.mspPairId || returnDonorTraces.length !== 1) {
|
|
13229
|
+
return null;
|
|
13230
|
+
}
|
|
13231
|
+
const sharedRail = getPerpendicularPinRail({
|
|
13232
|
+
trace: donorTrace,
|
|
13233
|
+
endpointPin: sharedPin
|
|
13234
|
+
});
|
|
13235
|
+
if (!sharedRail) return null;
|
|
13236
|
+
const facing = sharedPin._facingDirection;
|
|
13237
|
+
const verticalEndpoints = facing === "y+" || facing === "y-";
|
|
13238
|
+
const horizontalEndpoints = facing === "x+" || facing === "x-";
|
|
13239
|
+
if (!verticalEndpoints && !horizontalEndpoints) return null;
|
|
13240
|
+
if (verticalEndpoints !== (returnPin._facingDirection === "y+" || returnPin._facingDirection === "y-")) {
|
|
13241
|
+
return null;
|
|
13242
|
+
}
|
|
13243
|
+
const branchStartsAtSharedPin = branchTrace.pins[0].pinId === sharedPin.pinId;
|
|
13244
|
+
let sharedToReturnPath = simplifyPath(branchTrace.tracePath);
|
|
13245
|
+
if (!branchStartsAtSharedPin) sharedToReturnPath.reverse();
|
|
13246
|
+
if (sharedToReturnPath.length !== 6) return null;
|
|
13247
|
+
const expectedSegmentOrientations = verticalEndpoints ? ["V", "H", "V", "H", "V"] : ["H", "V", "H", "V", "H"];
|
|
13248
|
+
const actualSegmentOrientations = sharedToReturnPath.slice(1).map(
|
|
13249
|
+
(point, index) => isHorizontal2(sharedToReturnPath[index], point) ? "H" : isVertical2(sharedToReturnPath[index], point) ? "V" : "D"
|
|
13250
|
+
);
|
|
13251
|
+
if (actualSegmentOrientations.some(
|
|
13252
|
+
(orientation, index) => orientation !== expectedSegmentOrientations[index]
|
|
13253
|
+
)) {
|
|
13254
|
+
return null;
|
|
13255
|
+
}
|
|
13256
|
+
const returnRail = getPerpendicularPinRail({
|
|
13257
|
+
trace: returnDonorTraces[0],
|
|
13258
|
+
endpointPin: returnPin
|
|
13259
|
+
});
|
|
13260
|
+
if (!returnRail) return null;
|
|
13261
|
+
const candidate = verticalEndpoints ? simplifyPath([
|
|
13262
|
+
{ x: sharedPin.x, y: sharedPin.y },
|
|
13263
|
+
{ x: sharedPin.x, y: sharedRail.railCoordinate },
|
|
13264
|
+
{ x: sharedToReturnPath[2].x, y: sharedRail.railCoordinate },
|
|
13265
|
+
{ x: sharedToReturnPath[3].x, y: returnRail.railCoordinate },
|
|
13266
|
+
{ x: returnPin.x, y: returnRail.railCoordinate },
|
|
13267
|
+
{ x: returnPin.x, y: returnPin.y }
|
|
13268
|
+
]) : simplifyPath([
|
|
13269
|
+
{ x: sharedPin.x, y: sharedPin.y },
|
|
13270
|
+
{ x: sharedRail.railCoordinate, y: sharedPin.y },
|
|
13271
|
+
{ x: sharedRail.railCoordinate, y: sharedToReturnPath[2].y },
|
|
13272
|
+
{ x: returnRail.railCoordinate, y: sharedToReturnPath[3].y },
|
|
13273
|
+
{ x: returnRail.railCoordinate, y: returnPin.y },
|
|
13274
|
+
{ x: returnPin.x, y: returnPin.y }
|
|
13275
|
+
]);
|
|
13276
|
+
return branchStartsAtSharedPin ? candidate : candidate.reverse();
|
|
13277
|
+
};
|
|
12829
13278
|
var candidateIsClear = ({
|
|
12830
13279
|
candidateTrace,
|
|
12831
13280
|
originalTrace,
|
|
12832
13281
|
traces,
|
|
12833
13282
|
inputProblem,
|
|
13283
|
+
originalNetLabelPlacements,
|
|
12834
13284
|
candidateNetLabelPlacements,
|
|
12835
13285
|
attachedLabelIndexes
|
|
12836
13286
|
}) => {
|
|
@@ -12873,6 +13323,53 @@ var candidateIsClear = ({
|
|
|
12873
13323
|
)) {
|
|
12874
13324
|
return false;
|
|
12875
13325
|
}
|
|
13326
|
+
const labelHitsTrace = (label, trace) => pathIntersectsAnyNetLabel({
|
|
13327
|
+
path: trace.tracePath,
|
|
13328
|
+
netLabelPlacements: [label]
|
|
13329
|
+
});
|
|
13330
|
+
for (const labelIndex of attachedLabelIndexes) {
|
|
13331
|
+
const originalLabel = originalNetLabelPlacements[labelIndex];
|
|
13332
|
+
const candidateLabel = candidateNetLabelPlacements[labelIndex];
|
|
13333
|
+
const originalBounds = getRectBounds(
|
|
13334
|
+
originalLabel.center,
|
|
13335
|
+
originalLabel.width,
|
|
13336
|
+
originalLabel.height
|
|
13337
|
+
);
|
|
13338
|
+
const candidateBounds = getRectBounds(
|
|
13339
|
+
candidateLabel.center,
|
|
13340
|
+
candidateLabel.width,
|
|
13341
|
+
candidateLabel.height
|
|
13342
|
+
);
|
|
13343
|
+
for (const trace of traces) {
|
|
13344
|
+
if (trace.globalConnNetId === candidateLabel.globalConnNetId) continue;
|
|
13345
|
+
if (labelHitsTrace(candidateLabel, trace) && !labelHitsTrace(originalLabel, trace)) {
|
|
13346
|
+
return false;
|
|
13347
|
+
}
|
|
13348
|
+
}
|
|
13349
|
+
for (const obstacle of obstacles) {
|
|
13350
|
+
if (rectsOverlap(candidateBounds, obstacle) && !rectsOverlap(originalBounds, obstacle)) {
|
|
13351
|
+
return false;
|
|
13352
|
+
}
|
|
13353
|
+
}
|
|
13354
|
+
for (let otherIndex = 0; otherIndex < candidateNetLabelPlacements.length; otherIndex++) {
|
|
13355
|
+
if (otherIndex === labelIndex) continue;
|
|
13356
|
+
const originalOther = originalNetLabelPlacements[otherIndex];
|
|
13357
|
+
const candidateOther = candidateNetLabelPlacements[otherIndex];
|
|
13358
|
+
const originalOtherBounds = getRectBounds(
|
|
13359
|
+
originalOther.center,
|
|
13360
|
+
originalOther.width,
|
|
13361
|
+
originalOther.height
|
|
13362
|
+
);
|
|
13363
|
+
const candidateOtherBounds = getRectBounds(
|
|
13364
|
+
candidateOther.center,
|
|
13365
|
+
candidateOther.width,
|
|
13366
|
+
candidateOther.height
|
|
13367
|
+
);
|
|
13368
|
+
if (rectsOverlap(candidateBounds, candidateOtherBounds) && !rectsOverlap(originalBounds, originalOtherBounds)) {
|
|
13369
|
+
return false;
|
|
13370
|
+
}
|
|
13371
|
+
}
|
|
13372
|
+
}
|
|
12876
13373
|
const otherNetLabelPlacements = candidateNetLabelPlacements.filter(
|
|
12877
13374
|
(label) => label.globalConnNetId !== candidateTrace.globalConnNetId
|
|
12878
13375
|
);
|
|
@@ -12956,13 +13453,14 @@ var getAlignedReturnBranchPath = ({
|
|
|
12956
13453
|
var alignSameNetJunctions = ({
|
|
12957
13454
|
inputProblem,
|
|
12958
13455
|
traces,
|
|
12959
|
-
netLabelPlacements
|
|
13456
|
+
netLabelPlacements,
|
|
13457
|
+
netLabelConnectorTraceIds
|
|
12960
13458
|
}) => {
|
|
12961
13459
|
let outputTraces = [...traces];
|
|
12962
13460
|
let outputNetLabelPlacements = [...netLabelPlacements];
|
|
12963
13461
|
let alignedJunctionCount = 0;
|
|
13462
|
+
const alignedBranchTraceIds = /* @__PURE__ */ new Set();
|
|
12964
13463
|
for (const alignReturnBranches of [false, true]) {
|
|
12965
|
-
const alignedBranchTraceIds = /* @__PURE__ */ new Set();
|
|
12966
13464
|
const donorTraceIds = traces.map((trace) => trace.mspPairId);
|
|
12967
13465
|
const pendingDonorTraceIds = new Set(donorTraceIds);
|
|
12968
13466
|
for (let donorIndex = 0; donorIndex < donorTraceIds.length; donorIndex++) {
|
|
@@ -12975,13 +13473,40 @@ var alignSameNetJunctions = ({
|
|
|
12975
13473
|
if (alignedBranchTraceIds.has(branchTrace.mspPairId)) continue;
|
|
12976
13474
|
if (donorTrace.mspPairId === branchTrace.mspPairId) continue;
|
|
12977
13475
|
if (donorTrace.globalConnNetId !== branchTrace.globalConnNetId) continue;
|
|
12978
|
-
const
|
|
12979
|
-
|
|
13476
|
+
const donorIsLabelConnector = netLabelConnectorTraceIds.has(
|
|
13477
|
+
donorTrace.mspPairId
|
|
13478
|
+
);
|
|
13479
|
+
const branchIsLabelConnector = netLabelConnectorTraceIds.has(
|
|
13480
|
+
branchTrace.mspPairId
|
|
13481
|
+
);
|
|
13482
|
+
const candidatePaths = branchIsLabelConnector ? alignReturnBranches && !donorIsLabelConnector ? [
|
|
13483
|
+
getAlignedAttachedLabelConnectorPath({
|
|
13484
|
+
donorTrace,
|
|
13485
|
+
connectorTrace: branchTrace,
|
|
13486
|
+
netLabelConnectorTraceIds
|
|
13487
|
+
})
|
|
13488
|
+
] : [] : donorIsLabelConnector ? [] : alignReturnBranches ? [
|
|
13489
|
+
...[1, 0.5, 0.25].map(
|
|
13490
|
+
(returnStemScale) => getAlignedReturnBranchPath({
|
|
13491
|
+
donorTrace,
|
|
13492
|
+
branchTrace,
|
|
13493
|
+
returnStemScale
|
|
13494
|
+
})
|
|
13495
|
+
),
|
|
13496
|
+
getAlignedPerpendicularEndpointBusPath({
|
|
13497
|
+
donorTrace,
|
|
13498
|
+
branchTrace,
|
|
13499
|
+
traces: outputTraces
|
|
13500
|
+
}),
|
|
13501
|
+
getAlignedSharedEndpointRailPath({
|
|
12980
13502
|
donorTrace,
|
|
12981
13503
|
branchTrace,
|
|
12982
|
-
|
|
13504
|
+
netLabelConnectorTraceIds
|
|
12983
13505
|
})
|
|
12984
|
-
|
|
13506
|
+
] : [
|
|
13507
|
+
getAlignedBranchPath({ donorTrace, branchTrace }),
|
|
13508
|
+
getAlignedParallelPinExitPath({ donorTrace, branchTrace })
|
|
13509
|
+
];
|
|
12985
13510
|
for (const candidatePath of candidatePaths) {
|
|
12986
13511
|
if (!candidatePath) continue;
|
|
12987
13512
|
const candidateTrace = { ...branchTrace, tracePath: candidatePath };
|
|
@@ -13005,20 +13530,47 @@ var alignSameNetJunctions = ({
|
|
|
13005
13530
|
netLabelPlacements: outputNetLabelPlacements,
|
|
13006
13531
|
attachedLabelIndexes
|
|
13007
13532
|
});
|
|
13533
|
+
const candidateTraces = preserveAttachedLabelConnectorJunctions({
|
|
13534
|
+
originalTrace: branchTrace,
|
|
13535
|
+
candidateTrace,
|
|
13536
|
+
traces: outputTraces,
|
|
13537
|
+
netLabelConnectorTraceIds
|
|
13538
|
+
});
|
|
13539
|
+
if (!candidateTraces) continue;
|
|
13008
13540
|
if (!candidateIsClear({
|
|
13009
13541
|
candidateTrace,
|
|
13010
13542
|
originalTrace: branchTrace,
|
|
13011
|
-
traces:
|
|
13543
|
+
traces: candidateTraces,
|
|
13012
13544
|
inputProblem,
|
|
13545
|
+
originalNetLabelPlacements: outputNetLabelPlacements,
|
|
13013
13546
|
candidateNetLabelPlacements,
|
|
13014
13547
|
attachedLabelIndexes
|
|
13015
13548
|
})) {
|
|
13016
13549
|
continue;
|
|
13017
13550
|
}
|
|
13018
|
-
|
|
13019
|
-
if (trace.mspPairId === branchTrace.mspPairId)
|
|
13020
|
-
|
|
13551
|
+
const movedConnectorsAreClear = candidateTraces.every((trace) => {
|
|
13552
|
+
if (trace.mspPairId === branchTrace.mspPairId || !netLabelConnectorTraceIds.has(trace.mspPairId)) {
|
|
13553
|
+
return true;
|
|
13554
|
+
}
|
|
13555
|
+
const originalConnector = outputTraces.find(
|
|
13556
|
+
(originalTrace) => originalTrace.mspPairId === trace.mspPairId
|
|
13557
|
+
);
|
|
13558
|
+
if (originalConnector.tracePath === trace.tracePath) return true;
|
|
13559
|
+
return candidateIsClear({
|
|
13560
|
+
candidateTrace: trace,
|
|
13561
|
+
originalTrace: originalConnector,
|
|
13562
|
+
traces: candidateTraces,
|
|
13563
|
+
inputProblem,
|
|
13564
|
+
originalNetLabelPlacements: outputNetLabelPlacements,
|
|
13565
|
+
candidateNetLabelPlacements,
|
|
13566
|
+
attachedLabelIndexes: getAttachedLabelIndexes(
|
|
13567
|
+
originalConnector,
|
|
13568
|
+
outputNetLabelPlacements
|
|
13569
|
+
)
|
|
13570
|
+
});
|
|
13021
13571
|
});
|
|
13572
|
+
if (!movedConnectorsAreClear) continue;
|
|
13573
|
+
outputTraces = candidateTraces;
|
|
13022
13574
|
outputNetLabelPlacements = candidateNetLabelPlacements;
|
|
13023
13575
|
alignedBranchTraceIds.add(branchTrace.mspPairId);
|
|
13024
13576
|
alignedJunctionCount++;
|
|
@@ -13830,7 +14382,7 @@ var alignPortOnlyInlineNetLabelStubs = ({
|
|
|
13830
14382
|
};
|
|
13831
14383
|
|
|
13832
14384
|
// lib/solvers/InlineNetLabelSolver/getAxisAlignedSegments.ts
|
|
13833
|
-
var
|
|
14385
|
+
var getAxisAlignedSegments2 = (path, epsilon = 1e-6) => {
|
|
13834
14386
|
const segments = [];
|
|
13835
14387
|
let runStart = null;
|
|
13836
14388
|
let runAxis = null;
|
|
@@ -14445,6 +14997,131 @@ var pushInlineTerminalLabelsAwayFromAnchoredLabels = ({
|
|
|
14445
14997
|
};
|
|
14446
14998
|
};
|
|
14447
14999
|
|
|
15000
|
+
// lib/solvers/InlineNetLabelSolver/restoreReroutesAroundSupersededLabels.ts
|
|
15001
|
+
import { getSegmentIntersection as getSegmentIntersection5 } from "@tscircuit/math-utils/line-intersections";
|
|
15002
|
+
|
|
15003
|
+
// lib/utils/pathIntersectsRenderedLabel.ts
|
|
15004
|
+
import {
|
|
15005
|
+
doesSegmentIntersectRect,
|
|
15006
|
+
getBoundFromCenteredRect
|
|
15007
|
+
} from "@tscircuit/math-utils";
|
|
15008
|
+
var pathIntersectsRenderedLabel = (path, label) => {
|
|
15009
|
+
let width = label.width;
|
|
15010
|
+
let height = label.height;
|
|
15011
|
+
if ("axis" in label && label.axis === "y") {
|
|
15012
|
+
width = label.height;
|
|
15013
|
+
height = label.width;
|
|
15014
|
+
}
|
|
15015
|
+
const bounds = getBoundFromCenteredRect({
|
|
15016
|
+
center: label.center,
|
|
15017
|
+
width,
|
|
15018
|
+
height
|
|
15019
|
+
});
|
|
15020
|
+
for (let pathIndex = 0; pathIndex < path.length - 1; pathIndex++) {
|
|
15021
|
+
if (doesSegmentIntersectRect(path[pathIndex], path[pathIndex + 1], bounds)) {
|
|
15022
|
+
return true;
|
|
15023
|
+
}
|
|
15024
|
+
}
|
|
15025
|
+
return false;
|
|
15026
|
+
};
|
|
15027
|
+
|
|
15028
|
+
// lib/solvers/InlineNetLabelSolver/restoreReroutesAroundSupersededLabels.ts
|
|
15029
|
+
var EPS14 = 1e-6;
|
|
15030
|
+
var getPathLength5 = (path) => path.slice(1).reduce((length, point, pointIndex) => {
|
|
15031
|
+
const previousPoint = path[pointIndex];
|
|
15032
|
+
return length + Math.abs(point.x - previousPoint.x) + Math.abs(point.y - previousPoint.y);
|
|
15033
|
+
}, 0);
|
|
15034
|
+
var pathsEqual = (first, second) => first.length === second.length && first.every(
|
|
15035
|
+
(point, index) => Math.abs(point.x - second[index].x) <= EPS14 && Math.abs(point.y - second[index].y) <= EPS14
|
|
15036
|
+
);
|
|
15037
|
+
var isStrictlySimpler = (candidate, current) => candidate.length < current.length && getPathLength5(candidate) <= getPathLength5(current) + EPS14;
|
|
15038
|
+
var getIntersectionKeys = (path, otherPath) => {
|
|
15039
|
+
const intersections = /* @__PURE__ */ new Set();
|
|
15040
|
+
for (let pathIndex = 0; pathIndex < path.length - 1; pathIndex++) {
|
|
15041
|
+
for (let otherPathIndex = 0; otherPathIndex < otherPath.length - 1; otherPathIndex++) {
|
|
15042
|
+
const point = getSegmentIntersection5(
|
|
15043
|
+
path[pathIndex],
|
|
15044
|
+
path[pathIndex + 1],
|
|
15045
|
+
otherPath[otherPathIndex],
|
|
15046
|
+
otherPath[otherPathIndex + 1]
|
|
15047
|
+
);
|
|
15048
|
+
if (point) {
|
|
15049
|
+
intersections.add(`${point.x.toFixed(6)},${point.y.toFixed(6)}`);
|
|
15050
|
+
}
|
|
15051
|
+
}
|
|
15052
|
+
}
|
|
15053
|
+
return intersections;
|
|
15054
|
+
};
|
|
15055
|
+
var introducesNewCrossings = (candidatePath, currentPath, otherPaths) => otherPaths.some((otherPath) => {
|
|
15056
|
+
const currentIntersections = getIntersectionKeys(currentPath, otherPath);
|
|
15057
|
+
const candidateIntersections = getIntersectionKeys(candidatePath, otherPath);
|
|
15058
|
+
return [...candidateIntersections].some(
|
|
15059
|
+
(intersection) => !currentIntersections.has(intersection)
|
|
15060
|
+
);
|
|
15061
|
+
});
|
|
15062
|
+
var restoreReroutesAroundSupersededLabels = ({
|
|
15063
|
+
inputProblem,
|
|
15064
|
+
traces,
|
|
15065
|
+
netLabelPlacements,
|
|
15066
|
+
inlineNetLabelPlacements,
|
|
15067
|
+
completedReroutes
|
|
15068
|
+
}) => {
|
|
15069
|
+
const outputTraces = [...traces];
|
|
15070
|
+
const supersededLabelGlobalConnNetIds = new Set(
|
|
15071
|
+
inlineNetLabelPlacements.map((placement) => placement.globalConnNetId)
|
|
15072
|
+
);
|
|
15073
|
+
const obstacles = getObstacleRects(inputProblem);
|
|
15074
|
+
let restoredTraceCount = 0;
|
|
15075
|
+
for (const reroute of [...completedReroutes].reverse()) {
|
|
15076
|
+
if (!supersededLabelGlobalConnNetIds.has(reroute.label.globalConnNetId)) {
|
|
15077
|
+
continue;
|
|
15078
|
+
}
|
|
15079
|
+
const traceIndex = outputTraces.findIndex(
|
|
15080
|
+
(trace) => trace.mspPairId === reroute.initialTrace.mspPairId
|
|
15081
|
+
);
|
|
15082
|
+
if (traceIndex < 0) continue;
|
|
15083
|
+
const currentTrace = outputTraces[traceIndex];
|
|
15084
|
+
const currentPath = simplifyPath(currentTrace.tracePath);
|
|
15085
|
+
const recordedReroutePath = simplifyPath(reroute.reroutedTracePath);
|
|
15086
|
+
if (!pathsEqual(currentPath, recordedReroutePath)) continue;
|
|
15087
|
+
const candidatePath = simplifyPath(reroute.initialTrace.tracePath);
|
|
15088
|
+
if (!isStrictlySimpler(candidatePath, currentPath)) continue;
|
|
15089
|
+
const candidateTrace = { ...currentTrace, tracePath: candidatePath };
|
|
15090
|
+
const otherNetTraces = outputTraces.filter(
|
|
15091
|
+
(trace) => trace.mspPairId !== currentTrace.mspPairId && trace.globalConnNetId !== currentTrace.globalConnNetId
|
|
15092
|
+
);
|
|
15093
|
+
const otherNetInlineLabels = inlineNetLabelPlacements.filter(
|
|
15094
|
+
(label) => label.globalConnNetId !== currentTrace.globalConnNetId
|
|
15095
|
+
);
|
|
15096
|
+
const otherNetInlineStubPaths = otherNetInlineLabels.flatMap(
|
|
15097
|
+
(label) => label.stubTracePath ? [[...label.stubTracePath]] : []
|
|
15098
|
+
);
|
|
15099
|
+
if (isPathCollidingWithObstacles(candidatePath, obstacles) || detectTraceLabelOverlap({
|
|
15100
|
+
traces: [candidateTrace],
|
|
15101
|
+
netLabels: netLabelPlacements
|
|
15102
|
+
}).length > 0 || otherNetInlineLabels.some(
|
|
15103
|
+
(label) => pathIntersectsRenderedLabel(candidatePath, label)
|
|
15104
|
+
) || doesPathCoincideWithTraces(candidatePath, otherNetTraces) || doesPathCoincideWithPaths(candidatePath, otherNetInlineStubPaths) || introducesNewCrossings(
|
|
15105
|
+
candidatePath,
|
|
15106
|
+
currentPath,
|
|
15107
|
+
otherNetTraces.map((trace) => trace.tracePath)
|
|
15108
|
+
) || introducesNewCrossings(
|
|
15109
|
+
candidatePath,
|
|
15110
|
+
currentPath,
|
|
15111
|
+
otherNetInlineStubPaths
|
|
15112
|
+
) || !preservesLabelAnchors(
|
|
15113
|
+
netLabelPlacements,
|
|
15114
|
+
[currentTrace],
|
|
15115
|
+
[candidateTrace]
|
|
15116
|
+
)) {
|
|
15117
|
+
continue;
|
|
15118
|
+
}
|
|
15119
|
+
outputTraces[traceIndex] = candidateTrace;
|
|
15120
|
+
restoredTraceCount++;
|
|
15121
|
+
}
|
|
15122
|
+
return { traces: outputTraces, restoredTraceCount };
|
|
15123
|
+
};
|
|
15124
|
+
|
|
14448
15125
|
// lib/solvers/InlineNetLabelSolver/InlineNetLabelSolver.ts
|
|
14449
15126
|
var DEFAULT_INLINE_NET_LABEL_HEIGHT = 0.18;
|
|
14450
15127
|
var INLINE_NET_LABEL_TRACE_MARGIN = 0.05;
|
|
@@ -14477,6 +15154,7 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
14477
15154
|
inputProblem;
|
|
14478
15155
|
traces;
|
|
14479
15156
|
inputNetLabelPlacements;
|
|
15157
|
+
completedReroutes;
|
|
14480
15158
|
inlineNetLabelPlacements = [];
|
|
14481
15159
|
/** Eligible connections still waiting to be processed. */
|
|
14482
15160
|
queuedConnections;
|
|
@@ -14490,6 +15168,7 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
14490
15168
|
this.inputProblem = input.inputProblem;
|
|
14491
15169
|
this.traces = input.traces;
|
|
14492
15170
|
this.inputNetLabelPlacements = input.netLabelPlacements;
|
|
15171
|
+
this.completedReroutes = input.completedReroutes ?? [];
|
|
14493
15172
|
this.globalConnMap = getConnectivityMapsFromInputProblem(
|
|
14494
15173
|
this.inputProblem
|
|
14495
15174
|
).netConnMap;
|
|
@@ -14524,7 +15203,8 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
14524
15203
|
{
|
|
14525
15204
|
inputProblem: this.inputProblem,
|
|
14526
15205
|
traces: this.traces,
|
|
14527
|
-
netLabelPlacements: this.inputNetLabelPlacements
|
|
15206
|
+
netLabelPlacements: this.inputNetLabelPlacements,
|
|
15207
|
+
completedReroutes: this.completedReroutes
|
|
14528
15208
|
}
|
|
14529
15209
|
];
|
|
14530
15210
|
}
|
|
@@ -14840,7 +15520,7 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
14840
15520
|
pinIds,
|
|
14841
15521
|
ignoredTraceIds = /* @__PURE__ */ new Set()
|
|
14842
15522
|
}) {
|
|
14843
|
-
const segments =
|
|
15523
|
+
const segments = getAxisAlignedSegments2(trace.tracePath);
|
|
14844
15524
|
if (segments.length === 0) return null;
|
|
14845
15525
|
const height = connection.inlineNetLabelHeight ?? DEFAULT_INLINE_NET_LABEL_HEIGHT;
|
|
14846
15526
|
const netLabelText = connection.netLabelText?.trim() || void 0;
|
|
@@ -15097,9 +15777,17 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
15097
15777
|
if (blockedGlobalConnNetIds.size === 0) {
|
|
15098
15778
|
this.inlineNetLabelPlacements = activeInlinePlacements;
|
|
15099
15779
|
this.stats.pushedAnchoredNetLabelCount = pushed.movedLabelCount;
|
|
15100
|
-
|
|
15780
|
+
const restored = restoreReroutesAroundSupersededLabels({
|
|
15781
|
+
inputProblem: this.inputProblem,
|
|
15101
15782
|
traces: pushed.traces,
|
|
15102
15783
|
netLabelPlacements: pushed.netLabelPlacements,
|
|
15784
|
+
inlineNetLabelPlacements: activeInlinePlacements,
|
|
15785
|
+
completedReroutes: this.completedReroutes
|
|
15786
|
+
});
|
|
15787
|
+
this.stats.restoredSupersededLabelRerouteCount = restored.restoredTraceCount;
|
|
15788
|
+
return {
|
|
15789
|
+
traces: restored.traces,
|
|
15790
|
+
netLabelPlacements: pushed.netLabelPlacements,
|
|
15103
15791
|
inlineNetLabelPlacements: activeInlinePlacements
|
|
15104
15792
|
};
|
|
15105
15793
|
}
|
|
@@ -15307,12 +15995,6 @@ var getCollisionLimitedTerminalStubEnd = ({
|
|
|
15307
15995
|
return isHorizontal5 ? { x: start.x + direction * availableLength, y: start.y } : { x: start.x, y: start.y + direction * availableLength };
|
|
15308
15996
|
};
|
|
15309
15997
|
|
|
15310
|
-
// lib/solvers/NetLabelToTraceSolver/NetLabelToTraceSolver.ts
|
|
15311
|
-
import {
|
|
15312
|
-
doesSegmentIntersectRect,
|
|
15313
|
-
getBoundFromCenteredRect
|
|
15314
|
-
} from "@tscircuit/math-utils";
|
|
15315
|
-
|
|
15316
15998
|
// lib/solvers/NetLabelTraceRecovery/doesTraceRecoveryPathConflict.ts
|
|
15317
15999
|
import { doSegmentsIntersect as doSegmentsIntersect4 } from "@tscircuit/math-utils";
|
|
15318
16000
|
var EPSILON = 1e-6;
|
|
@@ -15407,12 +16089,12 @@ var getTraceRecoveryConnectivityMaps = (inputProblem) => {
|
|
|
15407
16089
|
};
|
|
15408
16090
|
|
|
15409
16091
|
// lib/solvers/NetLabelToTraceSolver/reduceTraceCrossings.ts
|
|
15410
|
-
var
|
|
15411
|
-
var isHorizontal4 = (start, end) => Math.abs(start.y - end.y) <
|
|
15412
|
-
var isVertical5 = (start, end) => Math.abs(start.x - end.x) <
|
|
16092
|
+
var EPS15 = 1e-9;
|
|
16093
|
+
var isHorizontal4 = (start, end) => Math.abs(start.y - end.y) < EPS15;
|
|
16094
|
+
var isVertical5 = (start, end) => Math.abs(start.x - end.x) < EPS15;
|
|
15413
16095
|
var compactConsecutivePoints = (path) => path.filter((point, index) => {
|
|
15414
16096
|
const previousPoint = path[index - 1];
|
|
15415
|
-
return !previousPoint || Math.abs(point.x - previousPoint.x) >=
|
|
16097
|
+
return !previousPoint || Math.abs(point.x - previousPoint.x) >= EPS15 || Math.abs(point.y - previousPoint.y) >= EPS15;
|
|
15416
16098
|
});
|
|
15417
16099
|
var isValidOrthogonalPath = (path) => {
|
|
15418
16100
|
if (path.length < 2 || !path.every((point, index) => {
|
|
@@ -15450,7 +16132,7 @@ var getEndpointAlignedSegmentCandidates = (tracePath) => {
|
|
|
15450
16132
|
}
|
|
15451
16133
|
const alignedCoordinates = segmentIsVertical ? [previousPoint.x, nextPoint.x] : [previousPoint.y, nextPoint.y];
|
|
15452
16134
|
for (const alignedCoordinate of alignedCoordinates) {
|
|
15453
|
-
if (Math.abs(alignedCoordinate - (segmentIsVertical ? start.x : start.y)) <
|
|
16135
|
+
if (Math.abs(alignedCoordinate - (segmentIsVertical ? start.x : start.y)) < EPS15) {
|
|
15454
16136
|
continue;
|
|
15455
16137
|
}
|
|
15456
16138
|
const candidate = tracePath.map((point) => ({ ...point }));
|
|
@@ -15513,25 +16195,6 @@ var RECOVERED_TRACE_PREFIX = "net-label-to-trace-";
|
|
|
15513
16195
|
var MAX_NAMED_NET_RECOVERY_PERPENDICULAR_OFFSET = 0.05;
|
|
15514
16196
|
var MAX_ROUTED_COMPONENT_RECOVERY_PERPENDICULAR_OFFSET = 0.25;
|
|
15515
16197
|
var getCanonicalPairKey = (firstPinId, secondPinId) => [firstPinId, secondPinId].sort().join("--");
|
|
15516
|
-
var pathIntersectsRenderedLabel = (path, label) => {
|
|
15517
|
-
let width = label.width;
|
|
15518
|
-
let height = label.height;
|
|
15519
|
-
if ("axis" in label && label.axis === "y") {
|
|
15520
|
-
width = label.height;
|
|
15521
|
-
height = label.width;
|
|
15522
|
-
}
|
|
15523
|
-
const bounds = getBoundFromCenteredRect({
|
|
15524
|
-
center: label.center,
|
|
15525
|
-
width,
|
|
15526
|
-
height
|
|
15527
|
-
});
|
|
15528
|
-
for (let pathIndex = 0; pathIndex < path.length - 1; pathIndex++) {
|
|
15529
|
-
if (doesSegmentIntersectRect(path[pathIndex], path[pathIndex + 1], bounds)) {
|
|
15530
|
-
return true;
|
|
15531
|
-
}
|
|
15532
|
-
}
|
|
15533
|
-
return false;
|
|
15534
|
-
};
|
|
15535
16198
|
var getPerpendicularOffset = (firstPoint, secondPoint) => {
|
|
15536
16199
|
const xDistance = Math.abs(firstPoint.x - secondPoint.x);
|
|
15537
16200
|
const yDistance = Math.abs(firstPoint.y - secondPoint.y);
|
|
@@ -16174,9 +16837,7 @@ var SchematicTracePipelineSolver = class extends BaseSolver {
|
|
|
16174
16837
|
inputTracePaths: instance.availableNetOrientationSolver.traces,
|
|
16175
16838
|
globalConnMap: instance.mspConnectionPairSolver.globalConnMap,
|
|
16176
16839
|
traceIdsToShift: new Set(
|
|
16177
|
-
instance.availableNetOrientationSolver.
|
|
16178
|
-
(trace) => trace.mspPairId.startsWith("available-net-orientation-")
|
|
16179
|
-
).map((trace) => trace.mspPairId)
|
|
16840
|
+
instance.availableNetOrientationSolver.netLabelConnectorTraceIds
|
|
16180
16841
|
)
|
|
16181
16842
|
}
|
|
16182
16843
|
]
|
|
@@ -16335,7 +16996,8 @@ var SchematicTracePipelineSolver = class extends BaseSolver {
|
|
|
16335
16996
|
{
|
|
16336
16997
|
inputProblem: instance.inputProblem,
|
|
16337
16998
|
traces: instance.netLabelNetLabelCollisionSolver.traces,
|
|
16338
|
-
netLabelPlacements: collisionOutput.netLabelPlacements
|
|
16999
|
+
netLabelPlacements: collisionOutput.netLabelPlacements,
|
|
17000
|
+
netLabelConnectorTraceIds: instance.availableNetOrientationSolver.netLabelConnectorTraceIds
|
|
16339
17001
|
}
|
|
16340
17002
|
];
|
|
16341
17003
|
}
|
|
@@ -16345,11 +17007,17 @@ var SchematicTracePipelineSolver = class extends BaseSolver {
|
|
|
16345
17007
|
InlineNetLabelSolver,
|
|
16346
17008
|
(instance) => {
|
|
16347
17009
|
const junctionOutput = instance.sameNetJunctionAlignmentSolver.getOutput();
|
|
17010
|
+
const completedReroutes = [
|
|
17011
|
+
...instance.traceLabelOverlapAvoidanceSolver.getOutput().completedReroutes,
|
|
17012
|
+
...instance.preAlignmentNetLabelTraceCollisionSolver.getOutput().completedReroutes,
|
|
17013
|
+
...instance.netLabelTraceCollisionSolver.getOutput().completedReroutes
|
|
17014
|
+
];
|
|
16348
17015
|
return [
|
|
16349
17016
|
{
|
|
16350
17017
|
inputProblem: instance.inputProblem,
|
|
16351
17018
|
traces: junctionOutput.traces,
|
|
16352
|
-
netLabelPlacements: junctionOutput.netLabelPlacements
|
|
17019
|
+
netLabelPlacements: junctionOutput.netLabelPlacements,
|
|
17020
|
+
completedReroutes
|
|
16353
17021
|
}
|
|
16354
17022
|
];
|
|
16355
17023
|
}
|