@tscircuit/schematic-trace-solver 0.0.174 → 0.0.175
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 +2 -0
- package/dist/index.js +195 -74
- 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/SchematicTracePipelineSolver/SchematicTracePipelineSolver.ts +9 -0
- 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-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 +12 -0
- 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/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-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/dist/index.d.ts
CHANGED
|
@@ -1286,6 +1286,7 @@ interface InlineNetLabelSolverInput {
|
|
|
1286
1286
|
inputProblem: InputProblem;
|
|
1287
1287
|
traces: SolvedTracePath[];
|
|
1288
1288
|
netLabelPlacements: NetLabelPlacement[];
|
|
1289
|
+
completedReroutes?: CompletedTraceReroute[];
|
|
1289
1290
|
}
|
|
1290
1291
|
interface InlineNetLabelOutput {
|
|
1291
1292
|
inputProblem: InputProblem;
|
|
@@ -1311,6 +1312,7 @@ declare class InlineNetLabelSolver extends BaseSolver {
|
|
|
1311
1312
|
inputProblem: InputProblem;
|
|
1312
1313
|
traces: SolvedTracePath[];
|
|
1313
1314
|
inputNetLabelPlacements: NetLabelPlacement[];
|
|
1315
|
+
completedReroutes: CompletedTraceReroute[];
|
|
1314
1316
|
inlineNetLabelPlacements: InlineNetLabelPlacement[];
|
|
1315
1317
|
/** Eligible connections still waiting to be processed. */
|
|
1316
1318
|
queuedConnections: QueuedInlineConnection[];
|
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;
|
|
@@ -14445,6 +14449,131 @@ var pushInlineTerminalLabelsAwayFromAnchoredLabels = ({
|
|
|
14445
14449
|
};
|
|
14446
14450
|
};
|
|
14447
14451
|
|
|
14452
|
+
// lib/solvers/InlineNetLabelSolver/restoreReroutesAroundSupersededLabels.ts
|
|
14453
|
+
import { getSegmentIntersection as getSegmentIntersection5 } from "@tscircuit/math-utils/line-intersections";
|
|
14454
|
+
|
|
14455
|
+
// lib/utils/pathIntersectsRenderedLabel.ts
|
|
14456
|
+
import {
|
|
14457
|
+
doesSegmentIntersectRect,
|
|
14458
|
+
getBoundFromCenteredRect
|
|
14459
|
+
} from "@tscircuit/math-utils";
|
|
14460
|
+
var pathIntersectsRenderedLabel = (path, label) => {
|
|
14461
|
+
let width = label.width;
|
|
14462
|
+
let height = label.height;
|
|
14463
|
+
if ("axis" in label && label.axis === "y") {
|
|
14464
|
+
width = label.height;
|
|
14465
|
+
height = label.width;
|
|
14466
|
+
}
|
|
14467
|
+
const bounds = getBoundFromCenteredRect({
|
|
14468
|
+
center: label.center,
|
|
14469
|
+
width,
|
|
14470
|
+
height
|
|
14471
|
+
});
|
|
14472
|
+
for (let pathIndex = 0; pathIndex < path.length - 1; pathIndex++) {
|
|
14473
|
+
if (doesSegmentIntersectRect(path[pathIndex], path[pathIndex + 1], bounds)) {
|
|
14474
|
+
return true;
|
|
14475
|
+
}
|
|
14476
|
+
}
|
|
14477
|
+
return false;
|
|
14478
|
+
};
|
|
14479
|
+
|
|
14480
|
+
// lib/solvers/InlineNetLabelSolver/restoreReroutesAroundSupersededLabels.ts
|
|
14481
|
+
var EPS14 = 1e-6;
|
|
14482
|
+
var getPathLength5 = (path) => path.slice(1).reduce((length, point, pointIndex) => {
|
|
14483
|
+
const previousPoint = path[pointIndex];
|
|
14484
|
+
return length + Math.abs(point.x - previousPoint.x) + Math.abs(point.y - previousPoint.y);
|
|
14485
|
+
}, 0);
|
|
14486
|
+
var pathsEqual = (first, second) => first.length === second.length && first.every(
|
|
14487
|
+
(point, index) => Math.abs(point.x - second[index].x) <= EPS14 && Math.abs(point.y - second[index].y) <= EPS14
|
|
14488
|
+
);
|
|
14489
|
+
var isStrictlySimpler = (candidate, current) => candidate.length < current.length && getPathLength5(candidate) <= getPathLength5(current) + EPS14;
|
|
14490
|
+
var getIntersectionKeys = (path, otherPath) => {
|
|
14491
|
+
const intersections = /* @__PURE__ */ new Set();
|
|
14492
|
+
for (let pathIndex = 0; pathIndex < path.length - 1; pathIndex++) {
|
|
14493
|
+
for (let otherPathIndex = 0; otherPathIndex < otherPath.length - 1; otherPathIndex++) {
|
|
14494
|
+
const point = getSegmentIntersection5(
|
|
14495
|
+
path[pathIndex],
|
|
14496
|
+
path[pathIndex + 1],
|
|
14497
|
+
otherPath[otherPathIndex],
|
|
14498
|
+
otherPath[otherPathIndex + 1]
|
|
14499
|
+
);
|
|
14500
|
+
if (point) {
|
|
14501
|
+
intersections.add(`${point.x.toFixed(6)},${point.y.toFixed(6)}`);
|
|
14502
|
+
}
|
|
14503
|
+
}
|
|
14504
|
+
}
|
|
14505
|
+
return intersections;
|
|
14506
|
+
};
|
|
14507
|
+
var introducesNewCrossings = (candidatePath, currentPath, otherPaths) => otherPaths.some((otherPath) => {
|
|
14508
|
+
const currentIntersections = getIntersectionKeys(currentPath, otherPath);
|
|
14509
|
+
const candidateIntersections = getIntersectionKeys(candidatePath, otherPath);
|
|
14510
|
+
return [...candidateIntersections].some(
|
|
14511
|
+
(intersection) => !currentIntersections.has(intersection)
|
|
14512
|
+
);
|
|
14513
|
+
});
|
|
14514
|
+
var restoreReroutesAroundSupersededLabels = ({
|
|
14515
|
+
inputProblem,
|
|
14516
|
+
traces,
|
|
14517
|
+
netLabelPlacements,
|
|
14518
|
+
inlineNetLabelPlacements,
|
|
14519
|
+
completedReroutes
|
|
14520
|
+
}) => {
|
|
14521
|
+
const outputTraces = [...traces];
|
|
14522
|
+
const supersededLabelGlobalConnNetIds = new Set(
|
|
14523
|
+
inlineNetLabelPlacements.map((placement) => placement.globalConnNetId)
|
|
14524
|
+
);
|
|
14525
|
+
const obstacles = getObstacleRects(inputProblem);
|
|
14526
|
+
let restoredTraceCount = 0;
|
|
14527
|
+
for (const reroute of [...completedReroutes].reverse()) {
|
|
14528
|
+
if (!supersededLabelGlobalConnNetIds.has(reroute.label.globalConnNetId)) {
|
|
14529
|
+
continue;
|
|
14530
|
+
}
|
|
14531
|
+
const traceIndex = outputTraces.findIndex(
|
|
14532
|
+
(trace) => trace.mspPairId === reroute.initialTrace.mspPairId
|
|
14533
|
+
);
|
|
14534
|
+
if (traceIndex < 0) continue;
|
|
14535
|
+
const currentTrace = outputTraces[traceIndex];
|
|
14536
|
+
const currentPath = simplifyPath(currentTrace.tracePath);
|
|
14537
|
+
const recordedReroutePath = simplifyPath(reroute.reroutedTracePath);
|
|
14538
|
+
if (!pathsEqual(currentPath, recordedReroutePath)) continue;
|
|
14539
|
+
const candidatePath = simplifyPath(reroute.initialTrace.tracePath);
|
|
14540
|
+
if (!isStrictlySimpler(candidatePath, currentPath)) continue;
|
|
14541
|
+
const candidateTrace = { ...currentTrace, tracePath: candidatePath };
|
|
14542
|
+
const otherNetTraces = outputTraces.filter(
|
|
14543
|
+
(trace) => trace.mspPairId !== currentTrace.mspPairId && trace.globalConnNetId !== currentTrace.globalConnNetId
|
|
14544
|
+
);
|
|
14545
|
+
const otherNetInlineLabels = inlineNetLabelPlacements.filter(
|
|
14546
|
+
(label) => label.globalConnNetId !== currentTrace.globalConnNetId
|
|
14547
|
+
);
|
|
14548
|
+
const otherNetInlineStubPaths = otherNetInlineLabels.flatMap(
|
|
14549
|
+
(label) => label.stubTracePath ? [[...label.stubTracePath]] : []
|
|
14550
|
+
);
|
|
14551
|
+
if (isPathCollidingWithObstacles(candidatePath, obstacles) || detectTraceLabelOverlap({
|
|
14552
|
+
traces: [candidateTrace],
|
|
14553
|
+
netLabels: netLabelPlacements
|
|
14554
|
+
}).length > 0 || otherNetInlineLabels.some(
|
|
14555
|
+
(label) => pathIntersectsRenderedLabel(candidatePath, label)
|
|
14556
|
+
) || doesPathCoincideWithTraces(candidatePath, otherNetTraces) || doesPathCoincideWithPaths(candidatePath, otherNetInlineStubPaths) || introducesNewCrossings(
|
|
14557
|
+
candidatePath,
|
|
14558
|
+
currentPath,
|
|
14559
|
+
otherNetTraces.map((trace) => trace.tracePath)
|
|
14560
|
+
) || introducesNewCrossings(
|
|
14561
|
+
candidatePath,
|
|
14562
|
+
currentPath,
|
|
14563
|
+
otherNetInlineStubPaths
|
|
14564
|
+
) || !preservesLabelAnchors(
|
|
14565
|
+
netLabelPlacements,
|
|
14566
|
+
[currentTrace],
|
|
14567
|
+
[candidateTrace]
|
|
14568
|
+
)) {
|
|
14569
|
+
continue;
|
|
14570
|
+
}
|
|
14571
|
+
outputTraces[traceIndex] = candidateTrace;
|
|
14572
|
+
restoredTraceCount++;
|
|
14573
|
+
}
|
|
14574
|
+
return { traces: outputTraces, restoredTraceCount };
|
|
14575
|
+
};
|
|
14576
|
+
|
|
14448
14577
|
// lib/solvers/InlineNetLabelSolver/InlineNetLabelSolver.ts
|
|
14449
14578
|
var DEFAULT_INLINE_NET_LABEL_HEIGHT = 0.18;
|
|
14450
14579
|
var INLINE_NET_LABEL_TRACE_MARGIN = 0.05;
|
|
@@ -14477,6 +14606,7 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
14477
14606
|
inputProblem;
|
|
14478
14607
|
traces;
|
|
14479
14608
|
inputNetLabelPlacements;
|
|
14609
|
+
completedReroutes;
|
|
14480
14610
|
inlineNetLabelPlacements = [];
|
|
14481
14611
|
/** Eligible connections still waiting to be processed. */
|
|
14482
14612
|
queuedConnections;
|
|
@@ -14490,6 +14620,7 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
14490
14620
|
this.inputProblem = input.inputProblem;
|
|
14491
14621
|
this.traces = input.traces;
|
|
14492
14622
|
this.inputNetLabelPlacements = input.netLabelPlacements;
|
|
14623
|
+
this.completedReroutes = input.completedReroutes ?? [];
|
|
14493
14624
|
this.globalConnMap = getConnectivityMapsFromInputProblem(
|
|
14494
14625
|
this.inputProblem
|
|
14495
14626
|
).netConnMap;
|
|
@@ -14524,7 +14655,8 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
14524
14655
|
{
|
|
14525
14656
|
inputProblem: this.inputProblem,
|
|
14526
14657
|
traces: this.traces,
|
|
14527
|
-
netLabelPlacements: this.inputNetLabelPlacements
|
|
14658
|
+
netLabelPlacements: this.inputNetLabelPlacements,
|
|
14659
|
+
completedReroutes: this.completedReroutes
|
|
14528
14660
|
}
|
|
14529
14661
|
];
|
|
14530
14662
|
}
|
|
@@ -15097,9 +15229,17 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
15097
15229
|
if (blockedGlobalConnNetIds.size === 0) {
|
|
15098
15230
|
this.inlineNetLabelPlacements = activeInlinePlacements;
|
|
15099
15231
|
this.stats.pushedAnchoredNetLabelCount = pushed.movedLabelCount;
|
|
15100
|
-
|
|
15232
|
+
const restored = restoreReroutesAroundSupersededLabels({
|
|
15233
|
+
inputProblem: this.inputProblem,
|
|
15101
15234
|
traces: pushed.traces,
|
|
15102
15235
|
netLabelPlacements: pushed.netLabelPlacements,
|
|
15236
|
+
inlineNetLabelPlacements: activeInlinePlacements,
|
|
15237
|
+
completedReroutes: this.completedReroutes
|
|
15238
|
+
});
|
|
15239
|
+
this.stats.restoredSupersededLabelRerouteCount = restored.restoredTraceCount;
|
|
15240
|
+
return {
|
|
15241
|
+
traces: restored.traces,
|
|
15242
|
+
netLabelPlacements: pushed.netLabelPlacements,
|
|
15103
15243
|
inlineNetLabelPlacements: activeInlinePlacements
|
|
15104
15244
|
};
|
|
15105
15245
|
}
|
|
@@ -15307,12 +15447,6 @@ var getCollisionLimitedTerminalStubEnd = ({
|
|
|
15307
15447
|
return isHorizontal5 ? { x: start.x + direction * availableLength, y: start.y } : { x: start.x, y: start.y + direction * availableLength };
|
|
15308
15448
|
};
|
|
15309
15449
|
|
|
15310
|
-
// lib/solvers/NetLabelToTraceSolver/NetLabelToTraceSolver.ts
|
|
15311
|
-
import {
|
|
15312
|
-
doesSegmentIntersectRect,
|
|
15313
|
-
getBoundFromCenteredRect
|
|
15314
|
-
} from "@tscircuit/math-utils";
|
|
15315
|
-
|
|
15316
15450
|
// lib/solvers/NetLabelTraceRecovery/doesTraceRecoveryPathConflict.ts
|
|
15317
15451
|
import { doSegmentsIntersect as doSegmentsIntersect4 } from "@tscircuit/math-utils";
|
|
15318
15452
|
var EPSILON = 1e-6;
|
|
@@ -15407,12 +15541,12 @@ var getTraceRecoveryConnectivityMaps = (inputProblem) => {
|
|
|
15407
15541
|
};
|
|
15408
15542
|
|
|
15409
15543
|
// 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) <
|
|
15544
|
+
var EPS15 = 1e-9;
|
|
15545
|
+
var isHorizontal4 = (start, end) => Math.abs(start.y - end.y) < EPS15;
|
|
15546
|
+
var isVertical5 = (start, end) => Math.abs(start.x - end.x) < EPS15;
|
|
15413
15547
|
var compactConsecutivePoints = (path) => path.filter((point, index) => {
|
|
15414
15548
|
const previousPoint = path[index - 1];
|
|
15415
|
-
return !previousPoint || Math.abs(point.x - previousPoint.x) >=
|
|
15549
|
+
return !previousPoint || Math.abs(point.x - previousPoint.x) >= EPS15 || Math.abs(point.y - previousPoint.y) >= EPS15;
|
|
15416
15550
|
});
|
|
15417
15551
|
var isValidOrthogonalPath = (path) => {
|
|
15418
15552
|
if (path.length < 2 || !path.every((point, index) => {
|
|
@@ -15450,7 +15584,7 @@ var getEndpointAlignedSegmentCandidates = (tracePath) => {
|
|
|
15450
15584
|
}
|
|
15451
15585
|
const alignedCoordinates = segmentIsVertical ? [previousPoint.x, nextPoint.x] : [previousPoint.y, nextPoint.y];
|
|
15452
15586
|
for (const alignedCoordinate of alignedCoordinates) {
|
|
15453
|
-
if (Math.abs(alignedCoordinate - (segmentIsVertical ? start.x : start.y)) <
|
|
15587
|
+
if (Math.abs(alignedCoordinate - (segmentIsVertical ? start.x : start.y)) < EPS15) {
|
|
15454
15588
|
continue;
|
|
15455
15589
|
}
|
|
15456
15590
|
const candidate = tracePath.map((point) => ({ ...point }));
|
|
@@ -15513,25 +15647,6 @@ var RECOVERED_TRACE_PREFIX = "net-label-to-trace-";
|
|
|
15513
15647
|
var MAX_NAMED_NET_RECOVERY_PERPENDICULAR_OFFSET = 0.05;
|
|
15514
15648
|
var MAX_ROUTED_COMPONENT_RECOVERY_PERPENDICULAR_OFFSET = 0.25;
|
|
15515
15649
|
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
15650
|
var getPerpendicularOffset = (firstPoint, secondPoint) => {
|
|
15536
15651
|
const xDistance = Math.abs(firstPoint.x - secondPoint.x);
|
|
15537
15652
|
const yDistance = Math.abs(firstPoint.y - secondPoint.y);
|
|
@@ -16345,11 +16460,17 @@ var SchematicTracePipelineSolver = class extends BaseSolver {
|
|
|
16345
16460
|
InlineNetLabelSolver,
|
|
16346
16461
|
(instance) => {
|
|
16347
16462
|
const junctionOutput = instance.sameNetJunctionAlignmentSolver.getOutput();
|
|
16463
|
+
const completedReroutes = [
|
|
16464
|
+
...instance.traceLabelOverlapAvoidanceSolver.getOutput().completedReroutes,
|
|
16465
|
+
...instance.preAlignmentNetLabelTraceCollisionSolver.getOutput().completedReroutes,
|
|
16466
|
+
...instance.netLabelTraceCollisionSolver.getOutput().completedReroutes
|
|
16467
|
+
];
|
|
16348
16468
|
return [
|
|
16349
16469
|
{
|
|
16350
16470
|
inputProblem: instance.inputProblem,
|
|
16351
16471
|
traces: junctionOutput.traces,
|
|
16352
|
-
netLabelPlacements: junctionOutput.netLabelPlacements
|
|
16472
|
+
netLabelPlacements: junctionOutput.netLabelPlacements,
|
|
16473
|
+
completedReroutes
|
|
16353
16474
|
}
|
|
16354
16475
|
];
|
|
16355
16476
|
}
|
|
@@ -8,6 +8,7 @@ import { getTraceConnectedPinComponents } from "lib/solvers/SchematicTraceLinesS
|
|
|
8
8
|
import type { SolvedTracePath } from "lib/solvers/SchematicTraceLinesSolver/SchematicTraceLinesSolver"
|
|
9
9
|
import { getPinDirection } from "lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver/getPinDirection"
|
|
10
10
|
import { visualizeInputProblem } from "lib/solvers/SchematicTracePipelineSolver/visualizeInputProblem"
|
|
11
|
+
import type { CompletedTraceReroute } from "lib/solvers/TraceElbowTransitionSimplificationSolver/types"
|
|
11
12
|
import type {
|
|
12
13
|
InputDirectConnection,
|
|
13
14
|
InputNetConnection,
|
|
@@ -24,6 +25,7 @@ import {
|
|
|
24
25
|
import { getAnchoredNetLabelRenderedBounds } from "./getAnchoredNetLabelRenderedBounds"
|
|
25
26
|
import { pushAnchoredNetLabelsAwayFromInlineLabels } from "./pushAnchoredNetLabelsAwayFromInlineLabels"
|
|
26
27
|
import { pushInlineTerminalLabelsAwayFromAnchoredLabels } from "./pushInlineTerminalLabelsAwayFromAnchoredLabels"
|
|
28
|
+
import { restoreReroutesAroundSupersededLabels } from "./restoreReroutesAroundSupersededLabels"
|
|
27
29
|
|
|
28
30
|
export const DEFAULT_INLINE_NET_LABEL_HEIGHT = 0.18
|
|
29
31
|
|
|
@@ -95,6 +97,7 @@ interface InlineNetLabelSolverInput {
|
|
|
95
97
|
inputProblem: InputProblem
|
|
96
98
|
traces: SolvedTracePath[]
|
|
97
99
|
netLabelPlacements: NetLabelPlacement[]
|
|
100
|
+
completedReroutes?: CompletedTraceReroute[]
|
|
98
101
|
}
|
|
99
102
|
|
|
100
103
|
export interface InlineNetLabelOutput {
|
|
@@ -169,6 +172,7 @@ export class InlineNetLabelSolver extends BaseSolver {
|
|
|
169
172
|
inputProblem: InputProblem
|
|
170
173
|
traces: SolvedTracePath[]
|
|
171
174
|
inputNetLabelPlacements: NetLabelPlacement[]
|
|
175
|
+
completedReroutes: CompletedTraceReroute[]
|
|
172
176
|
|
|
173
177
|
inlineNetLabelPlacements: InlineNetLabelPlacement[] = []
|
|
174
178
|
|
|
@@ -190,6 +194,7 @@ export class InlineNetLabelSolver extends BaseSolver {
|
|
|
190
194
|
this.inputProblem = input.inputProblem
|
|
191
195
|
this.traces = input.traces
|
|
192
196
|
this.inputNetLabelPlacements = input.netLabelPlacements
|
|
197
|
+
this.completedReroutes = input.completedReroutes ?? []
|
|
193
198
|
this.globalConnMap = getConnectivityMapsFromInputProblem(
|
|
194
199
|
this.inputProblem,
|
|
195
200
|
).netConnMap
|
|
@@ -235,6 +240,7 @@ export class InlineNetLabelSolver extends BaseSolver {
|
|
|
235
240
|
inputProblem: this.inputProblem,
|
|
236
241
|
traces: this.traces,
|
|
237
242
|
netLabelPlacements: this.inputNetLabelPlacements,
|
|
243
|
+
completedReroutes: this.completedReroutes,
|
|
238
244
|
},
|
|
239
245
|
]
|
|
240
246
|
}
|
|
@@ -1066,10 +1072,19 @@ export class InlineNetLabelSolver extends BaseSolver {
|
|
|
1066
1072
|
if (blockedGlobalConnNetIds.size === 0) {
|
|
1067
1073
|
this.inlineNetLabelPlacements = activeInlinePlacements
|
|
1068
1074
|
this.stats.pushedAnchoredNetLabelCount = pushed.movedLabelCount
|
|
1069
|
-
|
|
1075
|
+
const restored = restoreReroutesAroundSupersededLabels({
|
|
1076
|
+
inputProblem: this.inputProblem,
|
|
1070
1077
|
traces: pushed.traces,
|
|
1071
1078
|
netLabelPlacements: pushed.netLabelPlacements,
|
|
1072
1079
|
inlineNetLabelPlacements: activeInlinePlacements,
|
|
1080
|
+
completedReroutes: this.completedReroutes,
|
|
1081
|
+
})
|
|
1082
|
+
this.stats.restoredSupersededLabelRerouteCount =
|
|
1083
|
+
restored.restoredTraceCount
|
|
1084
|
+
return {
|
|
1085
|
+
traces: restored.traces,
|
|
1086
|
+
netLabelPlacements: pushed.netLabelPlacements,
|
|
1087
|
+
inlineNetLabelPlacements: activeInlinePlacements,
|
|
1073
1088
|
}
|
|
1074
1089
|
}
|
|
1075
1090
|
activeInlinePlacements = activeInlinePlacements.filter(
|