@tscircuit/schematic-trace-solver 0.0.106 → 0.0.107
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.js +270 -86
- package/lib/solvers/TraceCleanupSolver/sub-solver/UntangleTraceSubsolver.ts +178 -9
- package/lib/solvers/TraceCleanupSolver/sub-solver/findIntersectionsWithObstacles.ts +59 -0
- package/lib/solvers/TraceCleanupSolver/sub-solver/generateLShapeRerouteCandidates.ts +64 -1
- package/package.json +1 -1
- package/tests/bug-reports/bug-report-20260707T140410Z/__snapshots__/bug-report-20260707T140410Z.snap.svg +3 -3
- package/tests/bug-reports/bug-report-20260721T221026Z/__snapshots__/bug-report-20260721T221026Z.snap.svg +1 -1
- package/tests/repros/__snapshots__/repro-tps61222-trace-intersection.snap.svg +221 -0
- package/tests/repros/__snapshots__/repro47-endpoint-obstacle-detour.snap.svg +1 -1
- package/tests/repros/assets/repro-tps61222-trace-intersection.input.json +200 -0
- package/tests/repros/repro-tps61222-trace-intersection.test.ts +14 -0
- package/tests/repros/repro47-endpoint-obstacle-detour.test.ts +6 -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 EPS12 = 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) < -EPS12) 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) < -EPS12) 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) < EPS12 || Math.abs(p1.y - p2.y) < EPS12) {
|
|
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 };
|
|
@@ -1299,8 +1299,8 @@ var SchematicTraceSingleLineSolver2 = class extends BaseSolver {
|
|
|
1299
1299
|
if (!collision) {
|
|
1300
1300
|
const first = path[0];
|
|
1301
1301
|
const last = path[path.length - 1];
|
|
1302
|
-
const
|
|
1303
|
-
const samePoint = (p, q) => Math.abs(p.x - q.x) <
|
|
1302
|
+
const EPS12 = 1e-9;
|
|
1303
|
+
const samePoint = (p, q) => Math.abs(p.x - q.x) < EPS12 && Math.abs(p.y - q.y) < EPS12;
|
|
1304
1304
|
if (samePoint(first, { x: PA.x, y: PA.y }) && samePoint(last, { x: PB.x, y: PB.y })) {
|
|
1305
1305
|
this.solvedTracePath = path;
|
|
1306
1306
|
this.solved = true;
|
|
@@ -1573,13 +1573,13 @@ var applyJogToTerminalSegment = ({
|
|
|
1573
1573
|
segmentIndex: si,
|
|
1574
1574
|
offset,
|
|
1575
1575
|
JOG_SIZE,
|
|
1576
|
-
EPS:
|
|
1576
|
+
EPS: EPS12 = 1e-6
|
|
1577
1577
|
}) => {
|
|
1578
1578
|
if (si !== 0 && si !== pts.length - 2) return;
|
|
1579
1579
|
const start = pts[si];
|
|
1580
1580
|
const end = pts[si + 1];
|
|
1581
|
-
const isVertical5 = Math.abs(start.x - end.x) <
|
|
1582
|
-
const isHorizontal4 = Math.abs(start.y - end.y) <
|
|
1581
|
+
const isVertical5 = Math.abs(start.x - end.x) < EPS12;
|
|
1582
|
+
const isHorizontal4 = Math.abs(start.y - end.y) < EPS12;
|
|
1583
1583
|
if (!isVertical5 && !isHorizontal4) return;
|
|
1584
1584
|
const segDir = isVertical5 ? end.y > start.y ? 1 : -1 : end.x > start.x ? 1 : -1;
|
|
1585
1585
|
if (pts.length === 2) {
|
|
@@ -1997,7 +1997,7 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
|
|
|
1997
1997
|
return islands;
|
|
1998
1998
|
}
|
|
1999
1999
|
findNextOverlapIssue() {
|
|
2000
|
-
const
|
|
2000
|
+
const EPS12 = 2e-3;
|
|
2001
2001
|
const netIds = Object.keys(this.traceNetIslands);
|
|
2002
2002
|
for (let i = 0; i < netIds.length; i++) {
|
|
2003
2003
|
for (let j = i + 1; j < netIds.length; j++) {
|
|
@@ -2024,7 +2024,7 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
|
|
|
2024
2024
|
segmentBIndex,
|
|
2025
2025
|
rangeOverlap
|
|
2026
2026
|
}) => {
|
|
2027
|
-
if (rangeOverlap >
|
|
2027
|
+
if (rangeOverlap > EPS12) {
|
|
2028
2028
|
const keyA = `${pathAIndex}:${segmentAIndex}`;
|
|
2029
2029
|
const keyB = `${pathBIndex}:${segmentBIndex}`;
|
|
2030
2030
|
if (!seenA.has(keyA)) {
|
|
@@ -2043,7 +2043,7 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
|
|
|
2043
2043
|
}
|
|
2044
2044
|
return;
|
|
2045
2045
|
}
|
|
2046
|
-
if (rangeOverlap < -
|
|
2046
|
+
if (rangeOverlap < -EPS12) return;
|
|
2047
2047
|
const pathA = pathsA[pathAIndex].tracePath;
|
|
2048
2048
|
const pathB = pathsB[pathBIndex].tracePath;
|
|
2049
2049
|
const segmentAStart = pathA[segmentAIndex];
|
|
@@ -2066,8 +2066,8 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
|
|
|
2066
2066
|
for (let sa = 0; sa < ptsA.length - 1; sa++) {
|
|
2067
2067
|
const a1 = ptsA[sa];
|
|
2068
2068
|
const a2 = ptsA[sa + 1];
|
|
2069
|
-
const aVert = Math.abs(a1.x - a2.x) <
|
|
2070
|
-
const aHorz = Math.abs(a1.y - a2.y) <
|
|
2069
|
+
const aVert = Math.abs(a1.x - a2.x) < EPS12;
|
|
2070
|
+
const aHorz = Math.abs(a1.y - a2.y) < EPS12;
|
|
2071
2071
|
if (!aVert && !aHorz) continue;
|
|
2072
2072
|
for (let pb = 0; pb < pathsB.length; pb++) {
|
|
2073
2073
|
const pathB = pathsB[pb];
|
|
@@ -2075,11 +2075,11 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
|
|
|
2075
2075
|
for (let sb = 0; sb < ptsB.length - 1; sb++) {
|
|
2076
2076
|
const b1 = ptsB[sb];
|
|
2077
2077
|
const b2 = ptsB[sb + 1];
|
|
2078
|
-
const bVert = Math.abs(b1.x - b2.x) <
|
|
2079
|
-
const bHorz = Math.abs(b1.y - b2.y) <
|
|
2078
|
+
const bVert = Math.abs(b1.x - b2.x) < EPS12;
|
|
2079
|
+
const bHorz = Math.abs(b1.y - b2.y) < EPS12;
|
|
2080
2080
|
if (!bVert && !bHorz) continue;
|
|
2081
2081
|
if (aVert && bVert) {
|
|
2082
|
-
if (Math.abs(a1.x - b1.x) <
|
|
2082
|
+
if (Math.abs(a1.x - b1.x) < EPS12) {
|
|
2083
2083
|
recordCollinearInteraction({
|
|
2084
2084
|
pathAIndex: pa,
|
|
2085
2085
|
segmentAIndex: sa,
|
|
@@ -2089,7 +2089,7 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
|
|
|
2089
2089
|
});
|
|
2090
2090
|
}
|
|
2091
2091
|
} else if (aHorz && bHorz) {
|
|
2092
|
-
if (Math.abs(a1.y - b1.y) <
|
|
2092
|
+
if (Math.abs(a1.y - b1.y) < EPS12) {
|
|
2093
2093
|
recordCollinearInteraction({
|
|
2094
2094
|
pathAIndex: pa,
|
|
2095
2095
|
segmentAIndex: sa,
|
|
@@ -2145,14 +2145,14 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
|
|
|
2145
2145
|
return null;
|
|
2146
2146
|
}
|
|
2147
2147
|
findNextDiagonalSegment() {
|
|
2148
|
-
const
|
|
2148
|
+
const EPS12 = 2e-3;
|
|
2149
2149
|
for (const mspPairId in this.correctedTraceMap) {
|
|
2150
2150
|
const tracePath = this.correctedTraceMap[mspPairId].tracePath;
|
|
2151
2151
|
for (let i = 0; i < tracePath.length - 1; i++) {
|
|
2152
2152
|
const p1 = tracePath[i];
|
|
2153
2153
|
const p2 = tracePath[i + 1];
|
|
2154
|
-
const isHorizontal4 = Math.abs(p1.y - p2.y) <
|
|
2155
|
-
const isVertical5 = Math.abs(p1.x - p2.x) <
|
|
2154
|
+
const isHorizontal4 = Math.abs(p1.y - p2.y) < EPS12;
|
|
2155
|
+
const isVertical5 = Math.abs(p1.x - p2.x) < EPS12;
|
|
2156
2156
|
if (!isHorizontal4 && !isVertical5) {
|
|
2157
2157
|
return { mspPairId, tracePath, i, p1, p2 };
|
|
2158
2158
|
}
|
|
@@ -2166,13 +2166,13 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
|
|
|
2166
2166
|
return false;
|
|
2167
2167
|
}
|
|
2168
2168
|
const { mspPairId, tracePath, i, p1, p2 } = diagonalInfo;
|
|
2169
|
-
const
|
|
2169
|
+
const EPS12 = 2e-3;
|
|
2170
2170
|
const p0 = i > 0 ? tracePath[i - 1] : null;
|
|
2171
2171
|
const p3 = i + 2 < tracePath.length ? tracePath[i + 2] : null;
|
|
2172
|
-
const prevIsVertical = p0 ? Math.abs(p0.x - p1.x) <
|
|
2173
|
-
const prevIsHorizontal = p0 ? Math.abs(p0.y - p1.y) <
|
|
2174
|
-
const nextIsVertical = p3 ? Math.abs(p2.x - p3.x) <
|
|
2175
|
-
const nextIsHorizontal = p3 ? Math.abs(p2.y - p3.y) <
|
|
2172
|
+
const prevIsVertical = p0 ? Math.abs(p0.x - p1.x) < EPS12 : false;
|
|
2173
|
+
const prevIsHorizontal = p0 ? Math.abs(p0.y - p1.y) < EPS12 : false;
|
|
2174
|
+
const nextIsVertical = p3 ? Math.abs(p2.x - p3.x) < EPS12 : false;
|
|
2175
|
+
const nextIsHorizontal = p3 ? Math.abs(p2.y - p3.y) < EPS12 : false;
|
|
2176
2176
|
const elbow1 = { x: p1.x, y: p2.y };
|
|
2177
2177
|
const elbow2 = { x: p2.x, y: p1.y };
|
|
2178
2178
|
let score1 = 0;
|
|
@@ -2299,24 +2299,24 @@ var ChipObstacleSpatialIndex = class {
|
|
|
2299
2299
|
};
|
|
2300
2300
|
|
|
2301
2301
|
// lib/solvers/NetLabelPlacementSolver/SingleNetLabelPlacementSolver/collisions.ts
|
|
2302
|
-
function segmentIntersectsRect2(p1, p2, rect,
|
|
2303
|
-
const isVert = Math.abs(p1.x - p2.x) <
|
|
2304
|
-
const isHorz = Math.abs(p1.y - p2.y) <
|
|
2302
|
+
function segmentIntersectsRect2(p1, p2, rect, EPS12 = 1e-9) {
|
|
2303
|
+
const isVert = Math.abs(p1.x - p2.x) < EPS12;
|
|
2304
|
+
const isHorz = Math.abs(p1.y - p2.y) < EPS12;
|
|
2305
2305
|
if (!isVert && !isHorz) return false;
|
|
2306
2306
|
if (isVert) {
|
|
2307
2307
|
const x = p1.x;
|
|
2308
|
-
if (x < rect.minX -
|
|
2308
|
+
if (x < rect.minX - EPS12 || x > rect.maxX + EPS12) return false;
|
|
2309
2309
|
const segMinY = Math.min(p1.y, p2.y);
|
|
2310
2310
|
const segMaxY = Math.max(p1.y, p2.y);
|
|
2311
2311
|
const overlap = Math.min(segMaxY, rect.maxY) - Math.max(segMinY, rect.minY);
|
|
2312
|
-
return overlap >
|
|
2312
|
+
return overlap > EPS12;
|
|
2313
2313
|
} else {
|
|
2314
2314
|
const y = p1.y;
|
|
2315
|
-
if (y < rect.minY -
|
|
2315
|
+
if (y < rect.minY - EPS12 || y > rect.maxY + EPS12) return false;
|
|
2316
2316
|
const segMinX = Math.min(p1.x, p2.x);
|
|
2317
2317
|
const segMaxX = Math.max(p1.x, p2.x);
|
|
2318
2318
|
const overlap = Math.min(segMaxX, rect.maxX) - Math.max(segMinX, rect.minX);
|
|
2319
|
-
return overlap >
|
|
2319
|
+
return overlap > EPS12;
|
|
2320
2320
|
}
|
|
2321
2321
|
}
|
|
2322
2322
|
function rectIntersectsAnyTrace(bounds, inputTraceMap, hostPathId, hostSegIndex) {
|
|
@@ -2713,14 +2713,14 @@ var SingleNetLabelPlacementSolver = class extends BaseSolver {
|
|
|
2713
2713
|
};
|
|
2714
2714
|
let bestCandidate = null;
|
|
2715
2715
|
let bestScore = -Infinity;
|
|
2716
|
-
const
|
|
2716
|
+
const EPS12 = 1e-6;
|
|
2717
2717
|
for (const curr of tracesToScan) {
|
|
2718
2718
|
const pts = curr.tracePath.slice();
|
|
2719
2719
|
for (let si = 0; si < pts.length - 1; si++) {
|
|
2720
2720
|
const a = pts[si];
|
|
2721
2721
|
const b = pts[si + 1];
|
|
2722
|
-
const isH = Math.abs(a.y - b.y) <
|
|
2723
|
-
const isV = Math.abs(a.x - b.x) <
|
|
2722
|
+
const isH = Math.abs(a.y - b.y) < EPS12;
|
|
2723
|
+
const isV = Math.abs(a.x - b.x) < EPS12;
|
|
2724
2724
|
if (!isH && !isV) continue;
|
|
2725
2725
|
const segmentAllowed = isH ? ["y+", "y-"] : ["x+", "x-"];
|
|
2726
2726
|
const candidateOrients = orientations.filter(
|
|
@@ -5652,6 +5652,7 @@ var getTraceObstacles = (allTraces, excludeTraceId) => {
|
|
|
5652
5652
|
|
|
5653
5653
|
// lib/solvers/TraceCleanupSolver/sub-solver/findIntersectionsWithObstacles.ts
|
|
5654
5654
|
import { getSegmentIntersection } from "@tscircuit/math-utils/line-intersections";
|
|
5655
|
+
var EPS7 = 1e-6;
|
|
5655
5656
|
var findIntersectionsWithObstacles = (p1, p2, obstacles) => {
|
|
5656
5657
|
const intersections = [];
|
|
5657
5658
|
for (const obstacle of obstacles) {
|
|
@@ -5670,10 +5671,38 @@ var findIntersectionsWithObstacles = (p1, p2, obstacles) => {
|
|
|
5670
5671
|
}
|
|
5671
5672
|
return intersections;
|
|
5672
5673
|
};
|
|
5674
|
+
var isSamePoint = (first, second) => Math.abs(first.x - second.x) < EPS7 && Math.abs(first.y - second.y) < EPS7;
|
|
5675
|
+
var findPerpendicularPathCrossings = (path, otherPath) => {
|
|
5676
|
+
const crossings = [];
|
|
5677
|
+
for (let pathSegmentIndex = 1; pathSegmentIndex < path.length - 2; pathSegmentIndex++) {
|
|
5678
|
+
const start = path[pathSegmentIndex];
|
|
5679
|
+
const end = path[pathSegmentIndex + 1];
|
|
5680
|
+
const isVertical5 = Math.abs(start.x - end.x) < EPS7;
|
|
5681
|
+
for (let otherPathSegmentIndex = 1; otherPathSegmentIndex < otherPath.length - 2; otherPathSegmentIndex++) {
|
|
5682
|
+
const otherStart = otherPath[otherPathSegmentIndex];
|
|
5683
|
+
const otherEnd = otherPath[otherPathSegmentIndex + 1];
|
|
5684
|
+
const otherIsVertical = Math.abs(otherStart.x - otherEnd.x) < EPS7;
|
|
5685
|
+
if (isVertical5 === otherIsVertical) continue;
|
|
5686
|
+
const intersection = getSegmentIntersection(
|
|
5687
|
+
start,
|
|
5688
|
+
end,
|
|
5689
|
+
otherStart,
|
|
5690
|
+
otherEnd
|
|
5691
|
+
);
|
|
5692
|
+
if (!intersection || [start, end, otherStart, otherEnd].some(
|
|
5693
|
+
(point) => isSamePoint(point, intersection)
|
|
5694
|
+
)) {
|
|
5695
|
+
continue;
|
|
5696
|
+
}
|
|
5697
|
+
crossings.push({ pathSegmentIndex, otherPathSegmentIndex });
|
|
5698
|
+
}
|
|
5699
|
+
}
|
|
5700
|
+
return crossings;
|
|
5701
|
+
};
|
|
5673
5702
|
|
|
5674
5703
|
// lib/solvers/TraceCleanupSolver/sub-solver/generateLShapeRerouteCandidates.ts
|
|
5675
|
-
var
|
|
5676
|
-
var isVertical3 = (a, b, eps =
|
|
5704
|
+
var EPS8 = 1e-6;
|
|
5705
|
+
var isVertical3 = (a, b, eps = EPS8) => Math.abs(a.x - b.x) < eps;
|
|
5677
5706
|
var generateLShapeRerouteCandidates = ({
|
|
5678
5707
|
lShape,
|
|
5679
5708
|
rectangle,
|
|
@@ -5686,7 +5715,7 @@ var generateLShapeRerouteCandidates = ({
|
|
|
5686
5715
|
let c2;
|
|
5687
5716
|
let i1_padded = interactionPoint1;
|
|
5688
5717
|
let i2_padded = interactionPoint2;
|
|
5689
|
-
if (Math.abs(p2.x - x) <
|
|
5718
|
+
if (Math.abs(p2.x - x) < EPS8 && Math.abs(p2.y - (y + height)) < EPS8) {
|
|
5690
5719
|
c2 = { x: x + width + padding, y: y - padding };
|
|
5691
5720
|
if (isVertical3(p1, p2)) {
|
|
5692
5721
|
i1_padded = { x: interactionPoint1.x, y: interactionPoint1.y - padding };
|
|
@@ -5698,7 +5727,7 @@ var generateLShapeRerouteCandidates = ({
|
|
|
5698
5727
|
} else {
|
|
5699
5728
|
i2_padded = { x: interactionPoint2.x + padding, y: interactionPoint2.y };
|
|
5700
5729
|
}
|
|
5701
|
-
} else if (Math.abs(p2.x - (x + width)) <
|
|
5730
|
+
} else if (Math.abs(p2.x - (x + width)) < EPS8 && Math.abs(p2.y - (y + height)) < EPS8) {
|
|
5702
5731
|
c2 = { x: x - padding, y: y - padding };
|
|
5703
5732
|
if (isVertical3(p1, p2)) {
|
|
5704
5733
|
i1_padded = { x: interactionPoint1.x, y: interactionPoint1.y - padding };
|
|
@@ -5710,7 +5739,7 @@ var generateLShapeRerouteCandidates = ({
|
|
|
5710
5739
|
} else {
|
|
5711
5740
|
i2_padded = { x: interactionPoint2.x - padding, y: interactionPoint2.y };
|
|
5712
5741
|
}
|
|
5713
|
-
} else if (Math.abs(p2.x - x) <
|
|
5742
|
+
} else if (Math.abs(p2.x - x) < EPS8 && Math.abs(p2.y - y) < EPS8) {
|
|
5714
5743
|
c2 = { x: x + width + padding, y: y + height + padding };
|
|
5715
5744
|
if (isVertical3(p1, p2)) {
|
|
5716
5745
|
i1_padded = { x: interactionPoint1.x, y: interactionPoint1.y + padding };
|
|
@@ -5722,7 +5751,7 @@ var generateLShapeRerouteCandidates = ({
|
|
|
5722
5751
|
} else {
|
|
5723
5752
|
i2_padded = { x: interactionPoint2.x + padding, y: interactionPoint2.y };
|
|
5724
5753
|
}
|
|
5725
|
-
} else if (Math.abs(p2.x - (x + width)) <
|
|
5754
|
+
} else if (Math.abs(p2.x - (x + width)) < EPS8 && Math.abs(p2.y - y) < EPS8) {
|
|
5726
5755
|
c2 = { x: x - padding, y: y + height + padding };
|
|
5727
5756
|
if (isVertical3(p1, p2)) {
|
|
5728
5757
|
i1_padded = { x: interactionPoint1.x, y: interactionPoint1.y + padding };
|
|
@@ -5739,6 +5768,48 @@ var generateLShapeRerouteCandidates = ({
|
|
|
5739
5768
|
}
|
|
5740
5769
|
return [[i1_padded, c2, i2_padded]];
|
|
5741
5770
|
};
|
|
5771
|
+
var generatePerpendicularTraceDetours = ({
|
|
5772
|
+
trace,
|
|
5773
|
+
segmentIndex,
|
|
5774
|
+
obstacleStart,
|
|
5775
|
+
obstacleEnd,
|
|
5776
|
+
chipBounds,
|
|
5777
|
+
clearance
|
|
5778
|
+
}) => {
|
|
5779
|
+
const buildDetours = (path, index) => {
|
|
5780
|
+
const start = path[index];
|
|
5781
|
+
const end = path[index + 1];
|
|
5782
|
+
const movingAxis = Math.abs(start.x - end.x) < EPS8 ? "y" : "x";
|
|
5783
|
+
const detourAxis = movingAxis === "x" ? "y" : "x";
|
|
5784
|
+
const gate = obstacleStart[movingAxis] + Math.sign(start[movingAxis] - obstacleStart[movingAxis]) * clearance;
|
|
5785
|
+
const obstacleRange = [obstacleStart[detourAxis], obstacleEnd[detourAxis]];
|
|
5786
|
+
const lowBound = detourAxis === "x" ? "minX" : "minY";
|
|
5787
|
+
const highBound = detourAxis === "x" ? "maxX" : "maxY";
|
|
5788
|
+
const detourCoordinates = [
|
|
5789
|
+
Math.min(...obstacleRange) - clearance,
|
|
5790
|
+
Math.max(...obstacleRange) + clearance,
|
|
5791
|
+
...chipBounds.flatMap((bounds) => [
|
|
5792
|
+
bounds[lowBound] - clearance,
|
|
5793
|
+
bounds[highBound] + clearance
|
|
5794
|
+
])
|
|
5795
|
+
];
|
|
5796
|
+
return [...new Set(detourCoordinates)].map(
|
|
5797
|
+
(detour) => simplifyPath([
|
|
5798
|
+
...path.slice(0, index + 1),
|
|
5799
|
+
{ ...start, [movingAxis]: gate },
|
|
5800
|
+
{ ...start, [movingAxis]: gate, [detourAxis]: detour },
|
|
5801
|
+
{ ...end, [detourAxis]: detour },
|
|
5802
|
+
...path.slice(index + 2)
|
|
5803
|
+
])
|
|
5804
|
+
);
|
|
5805
|
+
};
|
|
5806
|
+
const reversedPath = [...trace.tracePath].reverse();
|
|
5807
|
+
const reversedIndex = trace.tracePath.length - 2 - segmentIndex;
|
|
5808
|
+
return [
|
|
5809
|
+
...buildDetours(trace.tracePath, segmentIndex),
|
|
5810
|
+
...buildDetours(reversedPath, reversedIndex).map((path) => path.reverse())
|
|
5811
|
+
].map((path) => ({ traceId: trace.mspPairId, path }));
|
|
5812
|
+
};
|
|
5742
5813
|
|
|
5743
5814
|
// lib/solvers/TraceCleanupSolver/sub-solver/isPathColliding.ts
|
|
5744
5815
|
import { getSegmentIntersection as getSegmentIntersection2 } from "@tscircuit/math-utils/line-intersections";
|
|
@@ -5913,6 +5984,9 @@ var UntangleTraceSubsolver = class extends BaseSolver {
|
|
|
5913
5984
|
input;
|
|
5914
5985
|
chipObstacleSpatialIndex;
|
|
5915
5986
|
lShapesToProcess = [];
|
|
5987
|
+
ignoredCrossings = /* @__PURE__ */ new Set();
|
|
5988
|
+
reroutedTraceIds = /* @__PURE__ */ new Set();
|
|
5989
|
+
processingCrossings = true;
|
|
5916
5990
|
visualizationMode = "l_shapes";
|
|
5917
5991
|
currentLShape = null;
|
|
5918
5992
|
intersectionPoints = [];
|
|
@@ -5936,18 +6010,24 @@ var UntangleTraceSubsolver = class extends BaseSolver {
|
|
|
5936
6010
|
if (!this.input.inputProblem._chipObstacleSpatialIndex) {
|
|
5937
6011
|
this.input.inputProblem._chipObstacleSpatialIndex = this.chipObstacleSpatialIndex;
|
|
5938
6012
|
}
|
|
5939
|
-
for (const trace of this.input.allTraces) {
|
|
5940
|
-
const lShapes = findAllLShapedTurns(trace.tracePath);
|
|
5941
|
-
this.lShapesToProcess.push(
|
|
5942
|
-
...lShapes.map((l) => ({ ...l, traceId: trace.mspPairId }))
|
|
5943
|
-
);
|
|
5944
|
-
}
|
|
5945
6013
|
}
|
|
5946
6014
|
_step() {
|
|
5947
6015
|
if (this.isInitialStep) {
|
|
5948
6016
|
this.isInitialStep = false;
|
|
5949
6017
|
return;
|
|
5950
6018
|
}
|
|
6019
|
+
if (this.processingCrossings) {
|
|
6020
|
+
const crossing = this._findCrossing();
|
|
6021
|
+
if (crossing) {
|
|
6022
|
+
if (!this._resolveCrossing(crossing)) {
|
|
6023
|
+
this.ignoredCrossings.add(this._crossingKey(crossing));
|
|
6024
|
+
}
|
|
6025
|
+
return;
|
|
6026
|
+
}
|
|
6027
|
+
this.processingCrossings = false;
|
|
6028
|
+
this._initializeLShapes();
|
|
6029
|
+
return;
|
|
6030
|
+
}
|
|
5951
6031
|
if (this.lShapeJustProcessed) {
|
|
5952
6032
|
this._resetAfterLShapProcessing();
|
|
5953
6033
|
return;
|
|
@@ -5971,6 +6051,110 @@ var UntangleTraceSubsolver = class extends BaseSolver {
|
|
|
5971
6051
|
break;
|
|
5972
6052
|
}
|
|
5973
6053
|
}
|
|
6054
|
+
_initializeLShapes() {
|
|
6055
|
+
for (const trace of this.input.allTraces) {
|
|
6056
|
+
this.lShapesToProcess.push(
|
|
6057
|
+
...findAllLShapedTurns(trace.tracePath).map((lShape) => ({
|
|
6058
|
+
...lShape,
|
|
6059
|
+
traceId: trace.mspPairId
|
|
6060
|
+
}))
|
|
6061
|
+
);
|
|
6062
|
+
}
|
|
6063
|
+
}
|
|
6064
|
+
_crossingKey(crossing) {
|
|
6065
|
+
return `${crossing.trace.mspPairId}:${crossing.segmentIndex}:${crossing.otherTrace.mspPairId}:${crossing.otherSegmentIndex}`;
|
|
6066
|
+
}
|
|
6067
|
+
_isTraceBundle(first, second) {
|
|
6068
|
+
const componentPair = (trace) => trace.pins.map((pin) => pin.chipId).sort().join(":");
|
|
6069
|
+
if (componentPair(first) !== componentPair(second)) return false;
|
|
6070
|
+
return Object.values(this.input.mergedLabelNetIdMap).some(
|
|
6071
|
+
(netIds) => netIds.has(first.globalConnNetId) && netIds.has(second.globalConnNetId)
|
|
6072
|
+
);
|
|
6073
|
+
}
|
|
6074
|
+
_findCrossing() {
|
|
6075
|
+
const traces = this.input.allTraces;
|
|
6076
|
+
for (let firstIndex = 0; firstIndex < traces.length; firstIndex++) {
|
|
6077
|
+
const trace = traces[firstIndex];
|
|
6078
|
+
for (let secondIndex = firstIndex + 1; secondIndex < traces.length; secondIndex++) {
|
|
6079
|
+
const otherTrace = traces[secondIndex];
|
|
6080
|
+
if (trace.globalConnNetId === otherTrace.globalConnNetId) continue;
|
|
6081
|
+
const isInitialBundleCrossing = this._isTraceBundle(trace, otherTrace);
|
|
6082
|
+
if (!isInitialBundleCrossing && !this.reroutedTraceIds.has(trace.mspPairId) && !this.reroutedTraceIds.has(otherTrace.mspPairId)) {
|
|
6083
|
+
continue;
|
|
6084
|
+
}
|
|
6085
|
+
const crossings = findPerpendicularPathCrossings(
|
|
6086
|
+
trace.tracePath,
|
|
6087
|
+
otherTrace.tracePath
|
|
6088
|
+
);
|
|
6089
|
+
for (const { pathSegmentIndex, otherPathSegmentIndex } of crossings) {
|
|
6090
|
+
const crossing = {
|
|
6091
|
+
trace,
|
|
6092
|
+
segmentIndex: pathSegmentIndex,
|
|
6093
|
+
otherTrace,
|
|
6094
|
+
otherSegmentIndex: otherPathSegmentIndex,
|
|
6095
|
+
isInitialBundleCrossing
|
|
6096
|
+
};
|
|
6097
|
+
if (!this.ignoredCrossings.has(this._crossingKey(crossing))) {
|
|
6098
|
+
return crossing;
|
|
6099
|
+
}
|
|
6100
|
+
}
|
|
6101
|
+
}
|
|
6102
|
+
}
|
|
6103
|
+
return null;
|
|
6104
|
+
}
|
|
6105
|
+
_resolveCrossing(crossing) {
|
|
6106
|
+
const chipBounds = this.chipObstacleSpatialIndex.chips.map(
|
|
6107
|
+
(chip) => chip.bounds
|
|
6108
|
+
);
|
|
6109
|
+
const candidates = [
|
|
6110
|
+
...generatePerpendicularTraceDetours({
|
|
6111
|
+
trace: crossing.trace,
|
|
6112
|
+
segmentIndex: crossing.segmentIndex,
|
|
6113
|
+
obstacleStart: crossing.otherTrace.tracePath[crossing.otherSegmentIndex],
|
|
6114
|
+
obstacleEnd: crossing.otherTrace.tracePath[crossing.otherSegmentIndex + 1],
|
|
6115
|
+
chipBounds,
|
|
6116
|
+
clearance: this.input.paddingBuffer
|
|
6117
|
+
}),
|
|
6118
|
+
...generatePerpendicularTraceDetours({
|
|
6119
|
+
trace: crossing.otherTrace,
|
|
6120
|
+
segmentIndex: crossing.otherSegmentIndex,
|
|
6121
|
+
obstacleStart: crossing.trace.tracePath[crossing.segmentIndex],
|
|
6122
|
+
obstacleEnd: crossing.trace.tracePath[crossing.segmentIndex + 1],
|
|
6123
|
+
chipBounds,
|
|
6124
|
+
clearance: this.input.paddingBuffer
|
|
6125
|
+
})
|
|
6126
|
+
];
|
|
6127
|
+
const chipObstacles = getObstacleRects(this.input.inputProblem).filter(
|
|
6128
|
+
(obstacle) => obstacle.kind === "chip"
|
|
6129
|
+
);
|
|
6130
|
+
const validCandidates = candidates.map((candidate) => ({
|
|
6131
|
+
...candidate,
|
|
6132
|
+
collision: isPathColliding(
|
|
6133
|
+
candidate.path,
|
|
6134
|
+
this.input.allTraces,
|
|
6135
|
+
candidate.traceId
|
|
6136
|
+
)
|
|
6137
|
+
})).filter(
|
|
6138
|
+
(candidate) => !isPathCollidingWithChipInterior(candidate.path, chipObstacles) && !isPathColliding(
|
|
6139
|
+
candidate.path,
|
|
6140
|
+
[crossing.trace, crossing.otherTrace],
|
|
6141
|
+
candidate.traceId
|
|
6142
|
+
).isColliding && (crossing.isInitialBundleCrossing || !candidate.collision.isColliding)
|
|
6143
|
+
).sort(
|
|
6144
|
+
(first, second) => Number(first.collision.isColliding) - Number(second.collision.isColliding) || getPathLength(first.path) - getPathLength(second.path)
|
|
6145
|
+
);
|
|
6146
|
+
const bestCandidate = validCandidates[0];
|
|
6147
|
+
if (!bestCandidate) return false;
|
|
6148
|
+
const traceIndex = this.input.allTraces.findIndex(
|
|
6149
|
+
(trace) => trace.mspPairId === bestCandidate.traceId
|
|
6150
|
+
);
|
|
6151
|
+
this.input.allTraces[traceIndex] = {
|
|
6152
|
+
...this.input.allTraces[traceIndex],
|
|
6153
|
+
tracePath: bestCandidate.path
|
|
6154
|
+
};
|
|
6155
|
+
this.reroutedTraceIds.add(bestCandidate.traceId);
|
|
6156
|
+
return true;
|
|
6157
|
+
}
|
|
5974
6158
|
_resetAfterLShapProcessing() {
|
|
5975
6159
|
this.lShapeProcessingStep = "idle";
|
|
5976
6160
|
this.currentLShape = null;
|
|
@@ -6193,9 +6377,9 @@ var UntangleTraceSubsolver = class extends BaseSolver {
|
|
|
6193
6377
|
};
|
|
6194
6378
|
|
|
6195
6379
|
// lib/solvers/TraceCleanupSolver/is4PointRectangle.ts
|
|
6196
|
-
var
|
|
6197
|
-
var sameX = (a, b) => Math.abs(a.x - b.x) <=
|
|
6198
|
-
var sameY = (a, b) => Math.abs(a.y - b.y) <=
|
|
6380
|
+
var EPS9 = 1e-6;
|
|
6381
|
+
var sameX = (a, b) => Math.abs(a.x - b.x) <= EPS9;
|
|
6382
|
+
var sameY = (a, b) => Math.abs(a.y - b.y) <= EPS9;
|
|
6199
6383
|
var is4PointRectangle = (path) => {
|
|
6200
6384
|
if (path.length !== 4) return false;
|
|
6201
6385
|
const [p0, p1, p2, p3] = path;
|
|
@@ -7255,16 +7439,16 @@ var createPortOnlyLabelConnectorTrace = ({
|
|
|
7255
7439
|
// lib/solvers/AvailableNetOrientationSolver/constants.ts
|
|
7256
7440
|
var LABEL_SEARCH_STEP = 0.05;
|
|
7257
7441
|
var WICK_CLEARANCE = 1e-3;
|
|
7258
|
-
var
|
|
7259
|
-
var TRACE_BOUNDARY_TOLERANCE = WICK_CLEARANCE +
|
|
7442
|
+
var EPS10 = 1e-9;
|
|
7443
|
+
var TRACE_BOUNDARY_TOLERANCE = WICK_CLEARANCE + EPS10;
|
|
7260
7444
|
var CANDIDATE_SELECTED_COLOR2 = "blue";
|
|
7261
7445
|
var CANDIDATE_REJECTED_COLOR2 = "red";
|
|
7262
7446
|
|
|
7263
7447
|
// lib/solvers/AvailableNetOrientationSolver/geometry.ts
|
|
7264
7448
|
var isYOrientation = (orientation) => orientation === "y+" || orientation === "y-";
|
|
7265
7449
|
var isXOrientation = (orientation) => orientation === "x+" || orientation === "x-";
|
|
7266
|
-
var rectsOverlap2 = (a, b) => Math.min(a.maxX, b.maxX) - Math.max(a.minX, b.minX) >
|
|
7267
|
-
var rangesOverlap = (minA, maxA, minB, maxB) => Math.min(maxA, maxB) - Math.max(minA, minB) >
|
|
7450
|
+
var rectsOverlap2 = (a, b) => Math.min(a.maxX, b.maxX) - Math.max(a.minX, b.minX) > EPS10 && Math.min(a.maxY, b.maxY) - Math.max(a.minY, b.minY) > EPS10;
|
|
7451
|
+
var rangesOverlap = (minA, maxA, minB, maxB) => Math.min(maxA, maxB) - Math.max(minA, minB) > EPS10;
|
|
7268
7452
|
var traceCrossesBoundsInterior = (bounds, traceMap) => {
|
|
7269
7453
|
for (const trace of Object.values(traceMap)) {
|
|
7270
7454
|
const points = trace.tracePath;
|
|
@@ -7287,7 +7471,7 @@ var segmentCrossesBoundsInterior = (p1, p2, bounds) => {
|
|
|
7287
7471
|
return false;
|
|
7288
7472
|
}
|
|
7289
7473
|
if (sameX2(p1, p2)) {
|
|
7290
|
-
if (p1.x <= interiorBounds.minX +
|
|
7474
|
+
if (p1.x <= interiorBounds.minX + EPS10 || p1.x >= interiorBounds.maxX - EPS10) {
|
|
7291
7475
|
return false;
|
|
7292
7476
|
}
|
|
7293
7477
|
return rangesOverlap(
|
|
@@ -7298,7 +7482,7 @@ var segmentCrossesBoundsInterior = (p1, p2, bounds) => {
|
|
|
7298
7482
|
);
|
|
7299
7483
|
}
|
|
7300
7484
|
if (sameY2(p1, p2)) {
|
|
7301
|
-
if (p1.y <= interiorBounds.minY +
|
|
7485
|
+
if (p1.y <= interiorBounds.minY + EPS10 || p1.y >= interiorBounds.maxY - EPS10) {
|
|
7302
7486
|
return false;
|
|
7303
7487
|
}
|
|
7304
7488
|
return rangesOverlap(
|
|
@@ -7354,8 +7538,8 @@ var simplifyOrthogonalPath = (path) => {
|
|
|
7354
7538
|
return simplified;
|
|
7355
7539
|
};
|
|
7356
7540
|
var pointsEqual2 = (a, b) => sameX2(a, b) && sameY2(a, b);
|
|
7357
|
-
var sameX2 = (a, b) => Math.abs(a.x - b.x) <=
|
|
7358
|
-
var sameY2 = (a, b) => Math.abs(a.y - b.y) <=
|
|
7541
|
+
var sameX2 = (a, b) => Math.abs(a.x - b.x) <= EPS10;
|
|
7542
|
+
var sameY2 = (a, b) => Math.abs(a.y - b.y) <= EPS10;
|
|
7359
7543
|
var getMaxSearchDistance = (inputProblem) => {
|
|
7360
7544
|
const maxChipWidth = Math.max(
|
|
7361
7545
|
...inputProblem.chips.map((chip) => chip.width),
|
|
@@ -7610,11 +7794,11 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
7610
7794
|
if (trace.globalConnNetId !== label.globalConnNetId) return false;
|
|
7611
7795
|
const path = trace.tracePath;
|
|
7612
7796
|
return path.some((point, pointIndex) => {
|
|
7613
|
-
if (Math.abs(point.x - label.anchorPoint.x) >
|
|
7797
|
+
if (Math.abs(point.x - label.anchorPoint.x) > EPS10 || Math.abs(point.y - label.anchorPoint.y) > EPS10) {
|
|
7614
7798
|
return false;
|
|
7615
7799
|
}
|
|
7616
7800
|
return [path[pointIndex - 1], path[pointIndex + 1]].some(
|
|
7617
|
-
(neighbor) => neighbor && Math.abs(neighbor.x - point.x) <=
|
|
7801
|
+
(neighbor) => neighbor && Math.abs(neighbor.x - point.x) <= EPS10 && (neighbor.y - point.y) * direction.y > EPS10
|
|
7618
7802
|
);
|
|
7619
7803
|
});
|
|
7620
7804
|
});
|
|
@@ -7693,7 +7877,7 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
7693
7877
|
);
|
|
7694
7878
|
const maxSearchDistance = this.getSearchDistanceLimit(label, orientation);
|
|
7695
7879
|
const maxOutwardDistance = outwardDirection.x === 0 && outwardDirection.y === 0 ? 0 : this.maxSearchDistance;
|
|
7696
|
-
for (let outwardDistance = 0; outwardDistance <= maxOutwardDistance +
|
|
7880
|
+
for (let outwardDistance = 0; outwardDistance <= maxOutwardDistance + EPS10; outwardDistance += LABEL_SEARCH_STEP) {
|
|
7697
7881
|
const baseAnchor = {
|
|
7698
7882
|
x: initialBaseAnchor.x + outwardDirection.x * outwardDistance,
|
|
7699
7883
|
y: initialBaseAnchor.y + outwardDirection.y * outwardDistance
|
|
@@ -7767,7 +7951,7 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
7767
7951
|
phase = "shift",
|
|
7768
7952
|
stopOnTraceCollision = true
|
|
7769
7953
|
} = params;
|
|
7770
|
-
for (let distance4 = LABEL_SEARCH_STEP; distance4 <= maxSearchDistance +
|
|
7954
|
+
for (let distance4 = LABEL_SEARCH_STEP; distance4 <= maxSearchDistance + EPS10; distance4 += LABEL_SEARCH_STEP) {
|
|
7771
7955
|
const anchorPoint = {
|
|
7772
7956
|
x: baseAnchor.x + direction.x * distance4,
|
|
7773
7957
|
y: baseAnchor.y + direction.y * distance4
|
|
@@ -8004,9 +8188,9 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
8004
8188
|
const { anchorPoint, orientation } = candidate;
|
|
8005
8189
|
const chipBounds = chip.bounds;
|
|
8006
8190
|
if (isYOrientation(orientation)) {
|
|
8007
|
-
return anchorPoint.x < chipBounds.minX -
|
|
8191
|
+
return anchorPoint.x < chipBounds.minX - EPS10 || anchorPoint.x > chipBounds.maxX + EPS10;
|
|
8008
8192
|
}
|
|
8009
|
-
return anchorPoint.y < chipBounds.minY -
|
|
8193
|
+
return anchorPoint.y < chipBounds.minY - EPS10 || anchorPoint.y > chipBounds.maxY + EPS10;
|
|
8010
8194
|
});
|
|
8011
8195
|
}
|
|
8012
8196
|
getBoundsStatus(candidateBoundsCheck) {
|
|
@@ -8080,8 +8264,8 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
8080
8264
|
sharesChipBoundary(bounds) {
|
|
8081
8265
|
for (const chip of this.chipObstacleSpatialIndex.chips) {
|
|
8082
8266
|
const chipBounds = chip.bounds;
|
|
8083
|
-
const adjacentToVerticalSide = Math.abs(bounds.minX - chipBounds.maxX) <= WICK_CLEARANCE +
|
|
8084
|
-
const adjacentToHorizontalSide = Math.abs(bounds.minY - chipBounds.maxY) <= WICK_CLEARANCE +
|
|
8267
|
+
const adjacentToVerticalSide = Math.abs(bounds.minX - chipBounds.maxX) <= WICK_CLEARANCE + EPS10 || Math.abs(bounds.maxX - chipBounds.minX) <= WICK_CLEARANCE + EPS10;
|
|
8268
|
+
const adjacentToHorizontalSide = Math.abs(bounds.minY - chipBounds.maxY) <= WICK_CLEARANCE + EPS10 || Math.abs(bounds.maxY - chipBounds.minY) <= WICK_CLEARANCE + EPS10;
|
|
8085
8269
|
if (adjacentToVerticalSide && rangesOverlap(
|
|
8086
8270
|
bounds.minY,
|
|
8087
8271
|
bounds.maxY,
|
|
@@ -8129,7 +8313,7 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
8129
8313
|
let nearestDistance = Number.POSITIVE_INFINITY;
|
|
8130
8314
|
for (const chip of this.chipObstacleSpatialIndex.chips) {
|
|
8131
8315
|
const bounds = chip.bounds;
|
|
8132
|
-
if (point.x < bounds.minX -
|
|
8316
|
+
if (point.x < bounds.minX - EPS10 || point.x > bounds.maxX + EPS10 || point.y < bounds.minY - EPS10 || point.y > bounds.maxY + EPS10) {
|
|
8133
8317
|
continue;
|
|
8134
8318
|
}
|
|
8135
8319
|
for (const [side, distance4] of getSideDistances(point, bounds)) {
|
|
@@ -8146,8 +8330,8 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
8146
8330
|
let nearestDistanceSq = Number.POSITIVE_INFINITY;
|
|
8147
8331
|
for (const chip of this.chipObstacleSpatialIndex.chips) {
|
|
8148
8332
|
const bounds = chip.bounds;
|
|
8149
|
-
const dx = point.x < bounds.minX -
|
|
8150
|
-
const dy = point.y < bounds.minY -
|
|
8333
|
+
const dx = point.x < bounds.minX - EPS10 ? bounds.minX - point.x : point.x > bounds.maxX + EPS10 ? point.x - bounds.maxX : 0;
|
|
8334
|
+
const dy = point.y < bounds.minY - EPS10 ? bounds.minY - point.y : point.y > bounds.maxY + EPS10 ? point.y - bounds.maxY : 0;
|
|
8151
8335
|
if (dx === 0 && dy === 0) continue;
|
|
8152
8336
|
const distanceSq = dx ** 2 + dy ** 2;
|
|
8153
8337
|
if (distanceSq >= nearestDistanceSq) continue;
|
|
@@ -8525,11 +8709,11 @@ var getOrientationConstraint = (inputProblem, label) => {
|
|
|
8525
8709
|
};
|
|
8526
8710
|
|
|
8527
8711
|
// lib/solvers/TraceAnchoredNetLabelOverlapSolver/geometry.ts
|
|
8528
|
-
var
|
|
8712
|
+
var EPS11 = 1e-6;
|
|
8529
8713
|
var TRACE_BOUNDARY_TOLERANCE2 = 1e-6;
|
|
8530
8714
|
var getLabelBounds = (label) => getRectBounds(label.center, label.width, label.height);
|
|
8531
|
-
var rectsOverlap3 = (a, b) => Math.min(a.maxX, b.maxX) - Math.max(a.minX, b.minX) >
|
|
8532
|
-
var rectsTouchOrOverlap = (a, b) => Math.min(a.maxX, b.maxX) - Math.max(a.minX, b.minX) >= -
|
|
8715
|
+
var rectsOverlap3 = (a, b) => Math.min(a.maxX, b.maxX) - Math.max(a.minX, b.minX) > EPS11 && Math.min(a.maxY, b.maxY) - Math.max(a.minY, b.minY) > EPS11;
|
|
8716
|
+
var rectsTouchOrOverlap = (a, b) => Math.min(a.maxX, b.maxX) - Math.max(a.minX, b.minX) >= -EPS11 && Math.min(a.maxY, b.maxY) - Math.max(a.minY, b.minY) >= -EPS11;
|
|
8533
8717
|
var traceCrossesBoundsInterior2 = (bounds, traces) => {
|
|
8534
8718
|
for (const trace of traces) {
|
|
8535
8719
|
const points = trace.tracePath;
|
|
@@ -8575,7 +8759,7 @@ var getPointAtTraceDistance = (trace, distance4) => {
|
|
|
8575
8759
|
const end = trace.tracePath[i + 1];
|
|
8576
8760
|
const segmentLength = getManhattanDistance(start, end);
|
|
8577
8761
|
const nextDistance = pathDistance + segmentLength;
|
|
8578
|
-
if (distance4 <= nextDistance +
|
|
8762
|
+
if (distance4 <= nextDistance + EPS11) {
|
|
8579
8763
|
const offset = Math.max(
|
|
8580
8764
|
0,
|
|
8581
8765
|
Math.min(segmentLength, distance4 - pathDistance)
|
|
@@ -8614,7 +8798,7 @@ var segmentCrossesBoundsInterior2 = (start, end, bounds) => {
|
|
|
8614
8798
|
return false;
|
|
8615
8799
|
}
|
|
8616
8800
|
if (isVertical4(start, end)) {
|
|
8617
|
-
if (start.x <= interior.minX +
|
|
8801
|
+
if (start.x <= interior.minX + EPS11 || start.x >= interior.maxX - EPS11) {
|
|
8618
8802
|
return false;
|
|
8619
8803
|
}
|
|
8620
8804
|
return rangesOverlap2(
|
|
@@ -8625,7 +8809,7 @@ var segmentCrossesBoundsInterior2 = (start, end, bounds) => {
|
|
|
8625
8809
|
);
|
|
8626
8810
|
}
|
|
8627
8811
|
if (isHorizontal3(start, end)) {
|
|
8628
|
-
if (start.y <= interior.minY +
|
|
8812
|
+
if (start.y <= interior.minY + EPS11 || start.y >= interior.maxY - EPS11) {
|
|
8629
8813
|
return false;
|
|
8630
8814
|
}
|
|
8631
8815
|
return rangesOverlap2(
|
|
@@ -8639,10 +8823,10 @@ var segmentCrossesBoundsInterior2 = (start, end, bounds) => {
|
|
|
8639
8823
|
};
|
|
8640
8824
|
var isPointOnSegment2 = (point, start, end) => {
|
|
8641
8825
|
if (isHorizontal3(start, end)) {
|
|
8642
|
-
return Math.abs(point.y - start.y) <=
|
|
8826
|
+
return Math.abs(point.y - start.y) <= EPS11 && point.x >= Math.min(start.x, end.x) - EPS11 && point.x <= Math.max(start.x, end.x) + EPS11;
|
|
8643
8827
|
}
|
|
8644
8828
|
if (isVertical4(start, end)) {
|
|
8645
|
-
return Math.abs(point.x - start.x) <=
|
|
8829
|
+
return Math.abs(point.x - start.x) <= EPS11 && point.y >= Math.min(start.y, end.y) - EPS11 && point.y <= Math.max(start.y, end.y) + EPS11;
|
|
8646
8830
|
}
|
|
8647
8831
|
return false;
|
|
8648
8832
|
};
|
|
@@ -8650,9 +8834,9 @@ var getSegmentDirection = (start, end) => ({
|
|
|
8650
8834
|
x: isVertical4(start, end) ? 0 : Math.sign(end.x - start.x),
|
|
8651
8835
|
y: isHorizontal3(start, end) ? 0 : Math.sign(end.y - start.y)
|
|
8652
8836
|
});
|
|
8653
|
-
var isHorizontal3 = (start, end) => Math.abs(start.y - end.y) <=
|
|
8654
|
-
var isVertical4 = (start, end) => Math.abs(start.x - end.x) <=
|
|
8655
|
-
var rangesOverlap2 = (minA, maxA, minB, maxB) => Math.min(maxA, maxB) - Math.max(minA, minB) >
|
|
8837
|
+
var isHorizontal3 = (start, end) => Math.abs(start.y - end.y) <= EPS11;
|
|
8838
|
+
var isVertical4 = (start, end) => Math.abs(start.x - end.x) <= EPS11;
|
|
8839
|
+
var rangesOverlap2 = (minA, maxA, minB, maxB) => Math.min(maxA, maxB) - Math.max(minA, minB) > EPS11;
|
|
8656
8840
|
var getUniquePinCount2 = (pinIds) => new Set(pinIds).size;
|
|
8657
8841
|
|
|
8658
8842
|
// lib/solvers/TraceAnchoredNetLabelOverlapSolver/candidates.ts
|
|
@@ -8709,7 +8893,7 @@ var getCandidateDistances = (traceLength, vertexDistances) => {
|
|
|
8709
8893
|
for (const distance4 of vertexDistances) {
|
|
8710
8894
|
distances.add(roundDistance(distance4));
|
|
8711
8895
|
}
|
|
8712
|
-
return [...distances].filter((distance4) => distance4 >= -
|
|
8896
|
+
return [...distances].filter((distance4) => distance4 >= -EPS11 && distance4 <= traceLength + EPS11).sort((a, b) => a - b);
|
|
8713
8897
|
};
|
|
8714
8898
|
var getOrientationsForPoint = (params) => {
|
|
8715
8899
|
const { inputProblem, label, point, orientationConstraint } = params;
|
|
@@ -8798,13 +8982,13 @@ var getOutwardOrientationOptions = (point, chipBounds) => {
|
|
|
8798
8982
|
};
|
|
8799
8983
|
var getOutwardAxisOption = (params) => {
|
|
8800
8984
|
const { value, min, max, center, positiveOrientation, negativeOrientation } = params;
|
|
8801
|
-
if (value > max +
|
|
8985
|
+
if (value > max + EPS11) {
|
|
8802
8986
|
return {
|
|
8803
8987
|
orientation: positiveOrientation,
|
|
8804
8988
|
outwardScore: 1 + value - max
|
|
8805
8989
|
};
|
|
8806
8990
|
}
|
|
8807
|
-
if (value < min -
|
|
8991
|
+
if (value < min - EPS11) {
|
|
8808
8992
|
return {
|
|
8809
8993
|
orientation: negativeOrientation,
|
|
8810
8994
|
outwardScore: 1 + min - value
|
|
@@ -8815,7 +8999,7 @@ var getOutwardAxisOption = (params) => {
|
|
|
8815
8999
|
outwardScore: getNormalizedCenterDistance(value, center, max - min)
|
|
8816
9000
|
};
|
|
8817
9001
|
};
|
|
8818
|
-
var getNormalizedCenterDistance = (value, center, span) => Math.abs(value - center) / Math.max(
|
|
9002
|
+
var getNormalizedCenterDistance = (value, center, span) => Math.abs(value - center) / Math.max(EPS11, span / 2);
|
|
8819
9003
|
var ALL_ORIENTATIONS = ["x+", "x-", "y+", "y-"];
|
|
8820
9004
|
var getFlippedOrientation = (orientation) => {
|
|
8821
9005
|
switch (orientation) {
|
|
@@ -8888,7 +9072,7 @@ var getNetLabelHeight = (inputProblem, label) => {
|
|
|
8888
9072
|
)?.netLabelHeight;
|
|
8889
9073
|
};
|
|
8890
9074
|
var roundDistance = (distance4) => Number(distance4.toFixed(6));
|
|
8891
|
-
var isSamePlacement = (label, point, orientation) => Math.abs(point.x - label.anchorPoint.x) <=
|
|
9075
|
+
var isSamePlacement = (label, point, orientation) => Math.abs(point.x - label.anchorPoint.x) <= EPS11 && Math.abs(point.y - label.anchorPoint.y) <= EPS11 && orientation === label.orientation;
|
|
8892
9076
|
|
|
8893
9077
|
// lib/solvers/TraceAnchoredNetLabelOverlapSolver/visualize.ts
|
|
8894
9078
|
var CANDIDATE_SELECTED_COLOR4 = "blue";
|