@tscircuit/schematic-trace-solver 0.0.105 → 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 +403 -166
- package/lib/solvers/TraceCleanupSolver/minimizeTurnsWithFilteredLabels.ts +78 -27
- package/lib/solvers/TraceCleanupSolver/sameNetRailAlignment/geometry.ts +40 -20
- 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/examples/__snapshots__/example13.snap.svg +3 -3
- package/tests/examples/__snapshots__/example29.snap.svg +23 -23
- package/tests/examples/example19.test.ts +4 -0
- package/tests/repros/__snapshots__/repro-example35-minimize-trace-crossing.snap.svg +256 -0
- 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-example35-minimize-trace-crossing.input.json +1561 -0
- package/tests/repros/assets/repro-tps61222-trace-intersection.input.json +200 -0
- package/tests/repros/repro-example35-minimize-trace-crossing.test.ts +22 -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(
|
|
@@ -4774,6 +4774,95 @@ var minimizeTurns = ({
|
|
|
4774
4774
|
return finalSimplifiedPath;
|
|
4775
4775
|
};
|
|
4776
4776
|
|
|
4777
|
+
// lib/solvers/TraceCleanupSolver/sameNetRailAlignment/geometry.ts
|
|
4778
|
+
var RAIL_ALIGNMENT_EPSILON = 2e-3;
|
|
4779
|
+
var nearlyEqual = (a, b) => Math.abs(a - b) < RAIL_ALIGNMENT_EPSILON;
|
|
4780
|
+
var isHorizontal2 = (a, b) => nearlyEqual(a.y, b.y);
|
|
4781
|
+
var isVertical2 = (a, b) => nearlyEqual(a.x, b.x);
|
|
4782
|
+
var isPositiveLength = (a, b) => Math.abs(a.x - b.x) >= RAIL_ALIGNMENT_EPSILON || Math.abs(a.y - b.y) >= RAIL_ALIGNMENT_EPSILON;
|
|
4783
|
+
var getRailOrientation = (a, b) => {
|
|
4784
|
+
if (!isPositiveLength(a, b)) return null;
|
|
4785
|
+
if (isVertical2(a, b)) return "vertical";
|
|
4786
|
+
if (isHorizontal2(a, b)) return "horizontal";
|
|
4787
|
+
return null;
|
|
4788
|
+
};
|
|
4789
|
+
var rangesTouchOrOverlap = (a, b) => Math.min(a.maxAlong, b.maxAlong) - Math.max(a.minAlong, b.minAlong) >= -RAIL_ALIGNMENT_EPSILON;
|
|
4790
|
+
var pointsEqual = (a, b) => nearlyEqual(a.x, b.x) && nearlyEqual(a.y, b.y);
|
|
4791
|
+
var getDistinctCoordinates = (coordinates) => {
|
|
4792
|
+
const distinct = [];
|
|
4793
|
+
for (const coordinate of coordinates) {
|
|
4794
|
+
if (!distinct.some((item) => nearlyEqual(item, coordinate))) {
|
|
4795
|
+
distinct.push(coordinate);
|
|
4796
|
+
}
|
|
4797
|
+
}
|
|
4798
|
+
return distinct;
|
|
4799
|
+
};
|
|
4800
|
+
var getMergedIntervalMetrics = (intervals) => {
|
|
4801
|
+
const groups = [];
|
|
4802
|
+
for (const interval of intervals) {
|
|
4803
|
+
const group = groups.find(
|
|
4804
|
+
(items) => nearlyEqual(items[0].coordinate, interval.coordinate)
|
|
4805
|
+
);
|
|
4806
|
+
if (group) group.push(interval);
|
|
4807
|
+
else groups.push([interval]);
|
|
4808
|
+
}
|
|
4809
|
+
return groups.reduce(
|
|
4810
|
+
(total, group) => {
|
|
4811
|
+
const sorted = [...group].sort((a, b) => a.min - b.min);
|
|
4812
|
+
let groupLength = 0;
|
|
4813
|
+
let segmentCount = 1;
|
|
4814
|
+
let currentMin = sorted[0].min;
|
|
4815
|
+
let currentMax = sorted[0].max;
|
|
4816
|
+
for (const interval of sorted.slice(1)) {
|
|
4817
|
+
if (interval.min <= currentMax + RAIL_ALIGNMENT_EPSILON) {
|
|
4818
|
+
currentMax = Math.max(currentMax, interval.max);
|
|
4819
|
+
} else {
|
|
4820
|
+
groupLength += currentMax - currentMin;
|
|
4821
|
+
segmentCount++;
|
|
4822
|
+
currentMin = interval.min;
|
|
4823
|
+
currentMax = interval.max;
|
|
4824
|
+
}
|
|
4825
|
+
}
|
|
4826
|
+
return {
|
|
4827
|
+
length: total.length + groupLength + currentMax - currentMin,
|
|
4828
|
+
segmentCount: total.segmentCount + segmentCount
|
|
4829
|
+
};
|
|
4830
|
+
},
|
|
4831
|
+
{ length: 0, segmentCount: 0 }
|
|
4832
|
+
);
|
|
4833
|
+
};
|
|
4834
|
+
var getVisibleTraceMetrics = (traces) => {
|
|
4835
|
+
const horizontal = [];
|
|
4836
|
+
const vertical = [];
|
|
4837
|
+
for (const trace of traces) {
|
|
4838
|
+
for (let index = 0; index < trace.tracePath.length - 1; index++) {
|
|
4839
|
+
const start = trace.tracePath[index];
|
|
4840
|
+
const end = trace.tracePath[index + 1];
|
|
4841
|
+
if (isHorizontal2(start, end)) {
|
|
4842
|
+
horizontal.push({
|
|
4843
|
+
coordinate: start.y,
|
|
4844
|
+
min: Math.min(start.x, end.x),
|
|
4845
|
+
max: Math.max(start.x, end.x)
|
|
4846
|
+
});
|
|
4847
|
+
} else if (isVertical2(start, end)) {
|
|
4848
|
+
vertical.push({
|
|
4849
|
+
coordinate: start.x,
|
|
4850
|
+
min: Math.min(start.y, end.y),
|
|
4851
|
+
max: Math.max(start.y, end.y)
|
|
4852
|
+
});
|
|
4853
|
+
}
|
|
4854
|
+
}
|
|
4855
|
+
}
|
|
4856
|
+
const horizontalMetrics = getMergedIntervalMetrics(horizontal);
|
|
4857
|
+
const verticalMetrics = getMergedIntervalMetrics(vertical);
|
|
4858
|
+
return {
|
|
4859
|
+
length: horizontalMetrics.length + verticalMetrics.length,
|
|
4860
|
+
segmentCount: horizontalMetrics.segmentCount + verticalMetrics.segmentCount
|
|
4861
|
+
};
|
|
4862
|
+
};
|
|
4863
|
+
var getVisibleTraceLength = (traces) => getVisibleTraceMetrics(traces).length;
|
|
4864
|
+
var getVisibleTraceSegmentCount = (traces) => getVisibleTraceMetrics(traces).segmentCount;
|
|
4865
|
+
|
|
4777
4866
|
// lib/solvers/TraceCleanupSolver/minimizeTurnsWithFilteredLabels.ts
|
|
4778
4867
|
var minimizeTurnsWithFilteredLabels = ({
|
|
4779
4868
|
targetMspConnectionPairId,
|
|
@@ -4789,11 +4878,16 @@ var minimizeTurnsWithFilteredLabels = ({
|
|
|
4789
4878
|
if (!targetTrace) {
|
|
4790
4879
|
throw new Error(`Target trace ${targetMspConnectionPairId} not found`);
|
|
4791
4880
|
}
|
|
4792
|
-
const
|
|
4793
|
-
|
|
4881
|
+
const targetPinIds = new Set(targetTrace.pinIds);
|
|
4882
|
+
const otherTraces = traces.filter(
|
|
4883
|
+
(trace) => trace.mspPairId !== targetMspConnectionPairId
|
|
4794
4884
|
);
|
|
4885
|
+
const relaxedObstacleTraces = otherTraces.filter((trace) => {
|
|
4886
|
+
const sharesEndpoint = trace.pinIds.some((pinId) => targetPinIds.has(pinId));
|
|
4887
|
+
return trace.globalConnNetId !== targetTrace.globalConnNetId || !sharesEndpoint;
|
|
4888
|
+
});
|
|
4795
4889
|
const TRACE_WIDTH = 0.01;
|
|
4796
|
-
const
|
|
4890
|
+
const getTraceObstacles2 = (obstacleTraces) => obstacleTraces.flatMap(
|
|
4797
4891
|
(trace, i) => trace.tracePath.slice(0, -1).map((p1, pi) => {
|
|
4798
4892
|
const p2 = trace.tracePath[pi + 1];
|
|
4799
4893
|
return {
|
|
@@ -4814,7 +4908,6 @@ var minimizeTurnsWithFilteredLabels = ({
|
|
|
4814
4908
|
maxX: obs.maxX + PADDING,
|
|
4815
4909
|
maxY: obs.maxY + PADDING
|
|
4816
4910
|
}));
|
|
4817
|
-
const combinedObstacles = [...staticObstacles, ...traceObstacles];
|
|
4818
4911
|
const originalPath = targetTrace.tracePath;
|
|
4819
4912
|
const filteredLabels = allLabelPlacements.filter((label) => {
|
|
4820
4913
|
const originalNetIds = mergedLabelNetIdMap[label.globalConnNetId];
|
|
@@ -4829,12 +4922,46 @@ var minimizeTurnsWithFilteredLabels = ({
|
|
|
4829
4922
|
minY: nl.center.y - nl.height / 2 - paddingBuffer,
|
|
4830
4923
|
maxY: nl.center.y + nl.height / 2 + paddingBuffer
|
|
4831
4924
|
}));
|
|
4832
|
-
const
|
|
4925
|
+
const strictPath = minimizeTurns({
|
|
4926
|
+
path: originalPath,
|
|
4927
|
+
obstacles: [...staticObstacles, ...getTraceObstacles2(otherTraces)],
|
|
4928
|
+
labelBounds,
|
|
4929
|
+
originalPath
|
|
4930
|
+
});
|
|
4931
|
+
const relaxedPath = minimizeTurns({
|
|
4833
4932
|
path: originalPath,
|
|
4834
|
-
obstacles:
|
|
4933
|
+
obstacles: [
|
|
4934
|
+
...staticObstacles,
|
|
4935
|
+
...getTraceObstacles2(relaxedObstacleTraces)
|
|
4936
|
+
],
|
|
4835
4937
|
labelBounds,
|
|
4836
4938
|
originalPath
|
|
4837
4939
|
});
|
|
4940
|
+
const sameNetTraces = otherTraces.filter(
|
|
4941
|
+
(trace) => trace.globalConnNetId === targetTrace.globalConnNetId
|
|
4942
|
+
);
|
|
4943
|
+
const getSameNetReadability = (tracePath) => {
|
|
4944
|
+
const tracesWithCandidate = [
|
|
4945
|
+
...sameNetTraces,
|
|
4946
|
+
{ ...targetTrace, tracePath }
|
|
4947
|
+
];
|
|
4948
|
+
return {
|
|
4949
|
+
segmentCount: getVisibleTraceSegmentCount(tracesWithCandidate),
|
|
4950
|
+
visibleLength: getVisibleTraceLength(tracesWithCandidate)
|
|
4951
|
+
};
|
|
4952
|
+
};
|
|
4953
|
+
const strictTurns = countTurns(strictPath);
|
|
4954
|
+
const relaxedTurns = countTurns(relaxedPath);
|
|
4955
|
+
let newPath = strictPath;
|
|
4956
|
+
if (relaxedTurns < strictTurns) {
|
|
4957
|
+
newPath = relaxedPath;
|
|
4958
|
+
} else if (relaxedTurns === strictTurns) {
|
|
4959
|
+
const strictReadability = getSameNetReadability(strictPath);
|
|
4960
|
+
const relaxedReadability = getSameNetReadability(relaxedPath);
|
|
4961
|
+
if (relaxedReadability.segmentCount < strictReadability.segmentCount || relaxedReadability.segmentCount === strictReadability.segmentCount && relaxedReadability.visibleLength < strictReadability.visibleLength - RAIL_ALIGNMENT_EPSILON) {
|
|
4962
|
+
newPath = relaxedPath;
|
|
4963
|
+
}
|
|
4964
|
+
}
|
|
4838
4965
|
return {
|
|
4839
4966
|
...targetTrace,
|
|
4840
4967
|
tracePath: newPath
|
|
@@ -4978,80 +5105,6 @@ var balanceZShapes = ({
|
|
|
4978
5105
|
};
|
|
4979
5106
|
};
|
|
4980
5107
|
|
|
4981
|
-
// lib/solvers/TraceCleanupSolver/sameNetRailAlignment/geometry.ts
|
|
4982
|
-
var RAIL_ALIGNMENT_EPSILON = 2e-3;
|
|
4983
|
-
var nearlyEqual = (a, b) => Math.abs(a - b) < RAIL_ALIGNMENT_EPSILON;
|
|
4984
|
-
var isHorizontal2 = (a, b) => nearlyEqual(a.y, b.y);
|
|
4985
|
-
var isVertical2 = (a, b) => nearlyEqual(a.x, b.x);
|
|
4986
|
-
var isPositiveLength = (a, b) => Math.abs(a.x - b.x) >= RAIL_ALIGNMENT_EPSILON || Math.abs(a.y - b.y) >= RAIL_ALIGNMENT_EPSILON;
|
|
4987
|
-
var getRailOrientation = (a, b) => {
|
|
4988
|
-
if (!isPositiveLength(a, b)) return null;
|
|
4989
|
-
if (isVertical2(a, b)) return "vertical";
|
|
4990
|
-
if (isHorizontal2(a, b)) return "horizontal";
|
|
4991
|
-
return null;
|
|
4992
|
-
};
|
|
4993
|
-
var rangesTouchOrOverlap = (a, b) => Math.min(a.maxAlong, b.maxAlong) - Math.max(a.minAlong, b.minAlong) >= -RAIL_ALIGNMENT_EPSILON;
|
|
4994
|
-
var pointsEqual = (a, b) => nearlyEqual(a.x, b.x) && nearlyEqual(a.y, b.y);
|
|
4995
|
-
var getDistinctCoordinates = (coordinates) => {
|
|
4996
|
-
const distinct = [];
|
|
4997
|
-
for (const coordinate of coordinates) {
|
|
4998
|
-
if (!distinct.some((item) => nearlyEqual(item, coordinate))) {
|
|
4999
|
-
distinct.push(coordinate);
|
|
5000
|
-
}
|
|
5001
|
-
}
|
|
5002
|
-
return distinct;
|
|
5003
|
-
};
|
|
5004
|
-
var getMergedIntervalLength = (intervals) => {
|
|
5005
|
-
const groups = [];
|
|
5006
|
-
for (const interval of intervals) {
|
|
5007
|
-
const group = groups.find(
|
|
5008
|
-
(items) => nearlyEqual(items[0].coordinate, interval.coordinate)
|
|
5009
|
-
);
|
|
5010
|
-
if (group) group.push(interval);
|
|
5011
|
-
else groups.push([interval]);
|
|
5012
|
-
}
|
|
5013
|
-
return groups.reduce((total, group) => {
|
|
5014
|
-
const sorted = [...group].sort((a, b) => a.min - b.min);
|
|
5015
|
-
let groupLength = 0;
|
|
5016
|
-
let currentMin = sorted[0].min;
|
|
5017
|
-
let currentMax = sorted[0].max;
|
|
5018
|
-
for (const interval of sorted.slice(1)) {
|
|
5019
|
-
if (interval.min <= currentMax + RAIL_ALIGNMENT_EPSILON) {
|
|
5020
|
-
currentMax = Math.max(currentMax, interval.max);
|
|
5021
|
-
} else {
|
|
5022
|
-
groupLength += currentMax - currentMin;
|
|
5023
|
-
currentMin = interval.min;
|
|
5024
|
-
currentMax = interval.max;
|
|
5025
|
-
}
|
|
5026
|
-
}
|
|
5027
|
-
return total + groupLength + currentMax - currentMin;
|
|
5028
|
-
}, 0);
|
|
5029
|
-
};
|
|
5030
|
-
var getVisibleTraceLength = (traces) => {
|
|
5031
|
-
const horizontal = [];
|
|
5032
|
-
const vertical = [];
|
|
5033
|
-
for (const trace of traces) {
|
|
5034
|
-
for (let index = 0; index < trace.tracePath.length - 1; index++) {
|
|
5035
|
-
const start = trace.tracePath[index];
|
|
5036
|
-
const end = trace.tracePath[index + 1];
|
|
5037
|
-
if (isHorizontal2(start, end)) {
|
|
5038
|
-
horizontal.push({
|
|
5039
|
-
coordinate: start.y,
|
|
5040
|
-
min: Math.min(start.x, end.x),
|
|
5041
|
-
max: Math.max(start.x, end.x)
|
|
5042
|
-
});
|
|
5043
|
-
} else if (isVertical2(start, end)) {
|
|
5044
|
-
vertical.push({
|
|
5045
|
-
coordinate: start.x,
|
|
5046
|
-
min: Math.min(start.y, end.y),
|
|
5047
|
-
max: Math.max(start.y, end.y)
|
|
5048
|
-
});
|
|
5049
|
-
}
|
|
5050
|
-
}
|
|
5051
|
-
}
|
|
5052
|
-
return getMergedIntervalLength(horizontal) + getMergedIntervalLength(vertical);
|
|
5053
|
-
};
|
|
5054
|
-
|
|
5055
5108
|
// lib/solvers/TraceCleanupSolver/sameNetRailAlignment/moveRailSegments.ts
|
|
5056
5109
|
var moveRailSegments = (trace, segments, coordinate) => {
|
|
5057
5110
|
const pointsToMove = /* @__PURE__ */ new Set();
|
|
@@ -5599,6 +5652,7 @@ var getTraceObstacles = (allTraces, excludeTraceId) => {
|
|
|
5599
5652
|
|
|
5600
5653
|
// lib/solvers/TraceCleanupSolver/sub-solver/findIntersectionsWithObstacles.ts
|
|
5601
5654
|
import { getSegmentIntersection } from "@tscircuit/math-utils/line-intersections";
|
|
5655
|
+
var EPS7 = 1e-6;
|
|
5602
5656
|
var findIntersectionsWithObstacles = (p1, p2, obstacles) => {
|
|
5603
5657
|
const intersections = [];
|
|
5604
5658
|
for (const obstacle of obstacles) {
|
|
@@ -5617,10 +5671,38 @@ var findIntersectionsWithObstacles = (p1, p2, obstacles) => {
|
|
|
5617
5671
|
}
|
|
5618
5672
|
return intersections;
|
|
5619
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
|
+
};
|
|
5620
5702
|
|
|
5621
5703
|
// lib/solvers/TraceCleanupSolver/sub-solver/generateLShapeRerouteCandidates.ts
|
|
5622
|
-
var
|
|
5623
|
-
var isVertical3 = (a, b, eps =
|
|
5704
|
+
var EPS8 = 1e-6;
|
|
5705
|
+
var isVertical3 = (a, b, eps = EPS8) => Math.abs(a.x - b.x) < eps;
|
|
5624
5706
|
var generateLShapeRerouteCandidates = ({
|
|
5625
5707
|
lShape,
|
|
5626
5708
|
rectangle,
|
|
@@ -5633,7 +5715,7 @@ var generateLShapeRerouteCandidates = ({
|
|
|
5633
5715
|
let c2;
|
|
5634
5716
|
let i1_padded = interactionPoint1;
|
|
5635
5717
|
let i2_padded = interactionPoint2;
|
|
5636
|
-
if (Math.abs(p2.x - x) <
|
|
5718
|
+
if (Math.abs(p2.x - x) < EPS8 && Math.abs(p2.y - (y + height)) < EPS8) {
|
|
5637
5719
|
c2 = { x: x + width + padding, y: y - padding };
|
|
5638
5720
|
if (isVertical3(p1, p2)) {
|
|
5639
5721
|
i1_padded = { x: interactionPoint1.x, y: interactionPoint1.y - padding };
|
|
@@ -5645,7 +5727,7 @@ var generateLShapeRerouteCandidates = ({
|
|
|
5645
5727
|
} else {
|
|
5646
5728
|
i2_padded = { x: interactionPoint2.x + padding, y: interactionPoint2.y };
|
|
5647
5729
|
}
|
|
5648
|
-
} 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) {
|
|
5649
5731
|
c2 = { x: x - padding, y: y - padding };
|
|
5650
5732
|
if (isVertical3(p1, p2)) {
|
|
5651
5733
|
i1_padded = { x: interactionPoint1.x, y: interactionPoint1.y - padding };
|
|
@@ -5657,7 +5739,7 @@ var generateLShapeRerouteCandidates = ({
|
|
|
5657
5739
|
} else {
|
|
5658
5740
|
i2_padded = { x: interactionPoint2.x - padding, y: interactionPoint2.y };
|
|
5659
5741
|
}
|
|
5660
|
-
} else if (Math.abs(p2.x - x) <
|
|
5742
|
+
} else if (Math.abs(p2.x - x) < EPS8 && Math.abs(p2.y - y) < EPS8) {
|
|
5661
5743
|
c2 = { x: x + width + padding, y: y + height + padding };
|
|
5662
5744
|
if (isVertical3(p1, p2)) {
|
|
5663
5745
|
i1_padded = { x: interactionPoint1.x, y: interactionPoint1.y + padding };
|
|
@@ -5669,7 +5751,7 @@ var generateLShapeRerouteCandidates = ({
|
|
|
5669
5751
|
} else {
|
|
5670
5752
|
i2_padded = { x: interactionPoint2.x + padding, y: interactionPoint2.y };
|
|
5671
5753
|
}
|
|
5672
|
-
} else if (Math.abs(p2.x - (x + width)) <
|
|
5754
|
+
} else if (Math.abs(p2.x - (x + width)) < EPS8 && Math.abs(p2.y - y) < EPS8) {
|
|
5673
5755
|
c2 = { x: x - padding, y: y + height + padding };
|
|
5674
5756
|
if (isVertical3(p1, p2)) {
|
|
5675
5757
|
i1_padded = { x: interactionPoint1.x, y: interactionPoint1.y + padding };
|
|
@@ -5686,6 +5768,48 @@ var generateLShapeRerouteCandidates = ({
|
|
|
5686
5768
|
}
|
|
5687
5769
|
return [[i1_padded, c2, i2_padded]];
|
|
5688
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
|
+
};
|
|
5689
5813
|
|
|
5690
5814
|
// lib/solvers/TraceCleanupSolver/sub-solver/isPathColliding.ts
|
|
5691
5815
|
import { getSegmentIntersection as getSegmentIntersection2 } from "@tscircuit/math-utils/line-intersections";
|
|
@@ -5860,6 +5984,9 @@ var UntangleTraceSubsolver = class extends BaseSolver {
|
|
|
5860
5984
|
input;
|
|
5861
5985
|
chipObstacleSpatialIndex;
|
|
5862
5986
|
lShapesToProcess = [];
|
|
5987
|
+
ignoredCrossings = /* @__PURE__ */ new Set();
|
|
5988
|
+
reroutedTraceIds = /* @__PURE__ */ new Set();
|
|
5989
|
+
processingCrossings = true;
|
|
5863
5990
|
visualizationMode = "l_shapes";
|
|
5864
5991
|
currentLShape = null;
|
|
5865
5992
|
intersectionPoints = [];
|
|
@@ -5883,18 +6010,24 @@ var UntangleTraceSubsolver = class extends BaseSolver {
|
|
|
5883
6010
|
if (!this.input.inputProblem._chipObstacleSpatialIndex) {
|
|
5884
6011
|
this.input.inputProblem._chipObstacleSpatialIndex = this.chipObstacleSpatialIndex;
|
|
5885
6012
|
}
|
|
5886
|
-
for (const trace of this.input.allTraces) {
|
|
5887
|
-
const lShapes = findAllLShapedTurns(trace.tracePath);
|
|
5888
|
-
this.lShapesToProcess.push(
|
|
5889
|
-
...lShapes.map((l) => ({ ...l, traceId: trace.mspPairId }))
|
|
5890
|
-
);
|
|
5891
|
-
}
|
|
5892
6013
|
}
|
|
5893
6014
|
_step() {
|
|
5894
6015
|
if (this.isInitialStep) {
|
|
5895
6016
|
this.isInitialStep = false;
|
|
5896
6017
|
return;
|
|
5897
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
|
+
}
|
|
5898
6031
|
if (this.lShapeJustProcessed) {
|
|
5899
6032
|
this._resetAfterLShapProcessing();
|
|
5900
6033
|
return;
|
|
@@ -5918,6 +6051,110 @@ var UntangleTraceSubsolver = class extends BaseSolver {
|
|
|
5918
6051
|
break;
|
|
5919
6052
|
}
|
|
5920
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
|
+
}
|
|
5921
6158
|
_resetAfterLShapProcessing() {
|
|
5922
6159
|
this.lShapeProcessingStep = "idle";
|
|
5923
6160
|
this.currentLShape = null;
|
|
@@ -6140,9 +6377,9 @@ var UntangleTraceSubsolver = class extends BaseSolver {
|
|
|
6140
6377
|
};
|
|
6141
6378
|
|
|
6142
6379
|
// lib/solvers/TraceCleanupSolver/is4PointRectangle.ts
|
|
6143
|
-
var
|
|
6144
|
-
var sameX = (a, b) => Math.abs(a.x - b.x) <=
|
|
6145
|
-
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;
|
|
6146
6383
|
var is4PointRectangle = (path) => {
|
|
6147
6384
|
if (path.length !== 4) return false;
|
|
6148
6385
|
const [p0, p1, p2, p3] = path;
|
|
@@ -7202,16 +7439,16 @@ var createPortOnlyLabelConnectorTrace = ({
|
|
|
7202
7439
|
// lib/solvers/AvailableNetOrientationSolver/constants.ts
|
|
7203
7440
|
var LABEL_SEARCH_STEP = 0.05;
|
|
7204
7441
|
var WICK_CLEARANCE = 1e-3;
|
|
7205
|
-
var
|
|
7206
|
-
var TRACE_BOUNDARY_TOLERANCE = WICK_CLEARANCE +
|
|
7442
|
+
var EPS10 = 1e-9;
|
|
7443
|
+
var TRACE_BOUNDARY_TOLERANCE = WICK_CLEARANCE + EPS10;
|
|
7207
7444
|
var CANDIDATE_SELECTED_COLOR2 = "blue";
|
|
7208
7445
|
var CANDIDATE_REJECTED_COLOR2 = "red";
|
|
7209
7446
|
|
|
7210
7447
|
// lib/solvers/AvailableNetOrientationSolver/geometry.ts
|
|
7211
7448
|
var isYOrientation = (orientation) => orientation === "y+" || orientation === "y-";
|
|
7212
7449
|
var isXOrientation = (orientation) => orientation === "x+" || orientation === "x-";
|
|
7213
|
-
var rectsOverlap2 = (a, b) => Math.min(a.maxX, b.maxX) - Math.max(a.minX, b.minX) >
|
|
7214
|
-
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;
|
|
7215
7452
|
var traceCrossesBoundsInterior = (bounds, traceMap) => {
|
|
7216
7453
|
for (const trace of Object.values(traceMap)) {
|
|
7217
7454
|
const points = trace.tracePath;
|
|
@@ -7234,7 +7471,7 @@ var segmentCrossesBoundsInterior = (p1, p2, bounds) => {
|
|
|
7234
7471
|
return false;
|
|
7235
7472
|
}
|
|
7236
7473
|
if (sameX2(p1, p2)) {
|
|
7237
|
-
if (p1.x <= interiorBounds.minX +
|
|
7474
|
+
if (p1.x <= interiorBounds.minX + EPS10 || p1.x >= interiorBounds.maxX - EPS10) {
|
|
7238
7475
|
return false;
|
|
7239
7476
|
}
|
|
7240
7477
|
return rangesOverlap(
|
|
@@ -7245,7 +7482,7 @@ var segmentCrossesBoundsInterior = (p1, p2, bounds) => {
|
|
|
7245
7482
|
);
|
|
7246
7483
|
}
|
|
7247
7484
|
if (sameY2(p1, p2)) {
|
|
7248
|
-
if (p1.y <= interiorBounds.minY +
|
|
7485
|
+
if (p1.y <= interiorBounds.minY + EPS10 || p1.y >= interiorBounds.maxY - EPS10) {
|
|
7249
7486
|
return false;
|
|
7250
7487
|
}
|
|
7251
7488
|
return rangesOverlap(
|
|
@@ -7301,8 +7538,8 @@ var simplifyOrthogonalPath = (path) => {
|
|
|
7301
7538
|
return simplified;
|
|
7302
7539
|
};
|
|
7303
7540
|
var pointsEqual2 = (a, b) => sameX2(a, b) && sameY2(a, b);
|
|
7304
|
-
var sameX2 = (a, b) => Math.abs(a.x - b.x) <=
|
|
7305
|
-
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;
|
|
7306
7543
|
var getMaxSearchDistance = (inputProblem) => {
|
|
7307
7544
|
const maxChipWidth = Math.max(
|
|
7308
7545
|
...inputProblem.chips.map((chip) => chip.width),
|
|
@@ -7557,11 +7794,11 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
7557
7794
|
if (trace.globalConnNetId !== label.globalConnNetId) return false;
|
|
7558
7795
|
const path = trace.tracePath;
|
|
7559
7796
|
return path.some((point, pointIndex) => {
|
|
7560
|
-
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) {
|
|
7561
7798
|
return false;
|
|
7562
7799
|
}
|
|
7563
7800
|
return [path[pointIndex - 1], path[pointIndex + 1]].some(
|
|
7564
|
-
(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
|
|
7565
7802
|
);
|
|
7566
7803
|
});
|
|
7567
7804
|
});
|
|
@@ -7640,7 +7877,7 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
7640
7877
|
);
|
|
7641
7878
|
const maxSearchDistance = this.getSearchDistanceLimit(label, orientation);
|
|
7642
7879
|
const maxOutwardDistance = outwardDirection.x === 0 && outwardDirection.y === 0 ? 0 : this.maxSearchDistance;
|
|
7643
|
-
for (let outwardDistance = 0; outwardDistance <= maxOutwardDistance +
|
|
7880
|
+
for (let outwardDistance = 0; outwardDistance <= maxOutwardDistance + EPS10; outwardDistance += LABEL_SEARCH_STEP) {
|
|
7644
7881
|
const baseAnchor = {
|
|
7645
7882
|
x: initialBaseAnchor.x + outwardDirection.x * outwardDistance,
|
|
7646
7883
|
y: initialBaseAnchor.y + outwardDirection.y * outwardDistance
|
|
@@ -7714,7 +7951,7 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
7714
7951
|
phase = "shift",
|
|
7715
7952
|
stopOnTraceCollision = true
|
|
7716
7953
|
} = params;
|
|
7717
|
-
for (let distance4 = LABEL_SEARCH_STEP; distance4 <= maxSearchDistance +
|
|
7954
|
+
for (let distance4 = LABEL_SEARCH_STEP; distance4 <= maxSearchDistance + EPS10; distance4 += LABEL_SEARCH_STEP) {
|
|
7718
7955
|
const anchorPoint = {
|
|
7719
7956
|
x: baseAnchor.x + direction.x * distance4,
|
|
7720
7957
|
y: baseAnchor.y + direction.y * distance4
|
|
@@ -7951,9 +8188,9 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
7951
8188
|
const { anchorPoint, orientation } = candidate;
|
|
7952
8189
|
const chipBounds = chip.bounds;
|
|
7953
8190
|
if (isYOrientation(orientation)) {
|
|
7954
|
-
return anchorPoint.x < chipBounds.minX -
|
|
8191
|
+
return anchorPoint.x < chipBounds.minX - EPS10 || anchorPoint.x > chipBounds.maxX + EPS10;
|
|
7955
8192
|
}
|
|
7956
|
-
return anchorPoint.y < chipBounds.minY -
|
|
8193
|
+
return anchorPoint.y < chipBounds.minY - EPS10 || anchorPoint.y > chipBounds.maxY + EPS10;
|
|
7957
8194
|
});
|
|
7958
8195
|
}
|
|
7959
8196
|
getBoundsStatus(candidateBoundsCheck) {
|
|
@@ -8027,8 +8264,8 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
8027
8264
|
sharesChipBoundary(bounds) {
|
|
8028
8265
|
for (const chip of this.chipObstacleSpatialIndex.chips) {
|
|
8029
8266
|
const chipBounds = chip.bounds;
|
|
8030
|
-
const adjacentToVerticalSide = Math.abs(bounds.minX - chipBounds.maxX) <= WICK_CLEARANCE +
|
|
8031
|
-
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;
|
|
8032
8269
|
if (adjacentToVerticalSide && rangesOverlap(
|
|
8033
8270
|
bounds.minY,
|
|
8034
8271
|
bounds.maxY,
|
|
@@ -8076,7 +8313,7 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
8076
8313
|
let nearestDistance = Number.POSITIVE_INFINITY;
|
|
8077
8314
|
for (const chip of this.chipObstacleSpatialIndex.chips) {
|
|
8078
8315
|
const bounds = chip.bounds;
|
|
8079
|
-
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) {
|
|
8080
8317
|
continue;
|
|
8081
8318
|
}
|
|
8082
8319
|
for (const [side, distance4] of getSideDistances(point, bounds)) {
|
|
@@ -8093,8 +8330,8 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
8093
8330
|
let nearestDistanceSq = Number.POSITIVE_INFINITY;
|
|
8094
8331
|
for (const chip of this.chipObstacleSpatialIndex.chips) {
|
|
8095
8332
|
const bounds = chip.bounds;
|
|
8096
|
-
const dx = point.x < bounds.minX -
|
|
8097
|
-
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;
|
|
8098
8335
|
if (dx === 0 && dy === 0) continue;
|
|
8099
8336
|
const distanceSq = dx ** 2 + dy ** 2;
|
|
8100
8337
|
if (distanceSq >= nearestDistanceSq) continue;
|
|
@@ -8472,11 +8709,11 @@ var getOrientationConstraint = (inputProblem, label) => {
|
|
|
8472
8709
|
};
|
|
8473
8710
|
|
|
8474
8711
|
// lib/solvers/TraceAnchoredNetLabelOverlapSolver/geometry.ts
|
|
8475
|
-
var
|
|
8712
|
+
var EPS11 = 1e-6;
|
|
8476
8713
|
var TRACE_BOUNDARY_TOLERANCE2 = 1e-6;
|
|
8477
8714
|
var getLabelBounds = (label) => getRectBounds(label.center, label.width, label.height);
|
|
8478
|
-
var rectsOverlap3 = (a, b) => Math.min(a.maxX, b.maxX) - Math.max(a.minX, b.minX) >
|
|
8479
|
-
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;
|
|
8480
8717
|
var traceCrossesBoundsInterior2 = (bounds, traces) => {
|
|
8481
8718
|
for (const trace of traces) {
|
|
8482
8719
|
const points = trace.tracePath;
|
|
@@ -8522,7 +8759,7 @@ var getPointAtTraceDistance = (trace, distance4) => {
|
|
|
8522
8759
|
const end = trace.tracePath[i + 1];
|
|
8523
8760
|
const segmentLength = getManhattanDistance(start, end);
|
|
8524
8761
|
const nextDistance = pathDistance + segmentLength;
|
|
8525
|
-
if (distance4 <= nextDistance +
|
|
8762
|
+
if (distance4 <= nextDistance + EPS11) {
|
|
8526
8763
|
const offset = Math.max(
|
|
8527
8764
|
0,
|
|
8528
8765
|
Math.min(segmentLength, distance4 - pathDistance)
|
|
@@ -8561,7 +8798,7 @@ var segmentCrossesBoundsInterior2 = (start, end, bounds) => {
|
|
|
8561
8798
|
return false;
|
|
8562
8799
|
}
|
|
8563
8800
|
if (isVertical4(start, end)) {
|
|
8564
|
-
if (start.x <= interior.minX +
|
|
8801
|
+
if (start.x <= interior.minX + EPS11 || start.x >= interior.maxX - EPS11) {
|
|
8565
8802
|
return false;
|
|
8566
8803
|
}
|
|
8567
8804
|
return rangesOverlap2(
|
|
@@ -8572,7 +8809,7 @@ var segmentCrossesBoundsInterior2 = (start, end, bounds) => {
|
|
|
8572
8809
|
);
|
|
8573
8810
|
}
|
|
8574
8811
|
if (isHorizontal3(start, end)) {
|
|
8575
|
-
if (start.y <= interior.minY +
|
|
8812
|
+
if (start.y <= interior.minY + EPS11 || start.y >= interior.maxY - EPS11) {
|
|
8576
8813
|
return false;
|
|
8577
8814
|
}
|
|
8578
8815
|
return rangesOverlap2(
|
|
@@ -8586,10 +8823,10 @@ var segmentCrossesBoundsInterior2 = (start, end, bounds) => {
|
|
|
8586
8823
|
};
|
|
8587
8824
|
var isPointOnSegment2 = (point, start, end) => {
|
|
8588
8825
|
if (isHorizontal3(start, end)) {
|
|
8589
|
-
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;
|
|
8590
8827
|
}
|
|
8591
8828
|
if (isVertical4(start, end)) {
|
|
8592
|
-
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;
|
|
8593
8830
|
}
|
|
8594
8831
|
return false;
|
|
8595
8832
|
};
|
|
@@ -8597,9 +8834,9 @@ var getSegmentDirection = (start, end) => ({
|
|
|
8597
8834
|
x: isVertical4(start, end) ? 0 : Math.sign(end.x - start.x),
|
|
8598
8835
|
y: isHorizontal3(start, end) ? 0 : Math.sign(end.y - start.y)
|
|
8599
8836
|
});
|
|
8600
|
-
var isHorizontal3 = (start, end) => Math.abs(start.y - end.y) <=
|
|
8601
|
-
var isVertical4 = (start, end) => Math.abs(start.x - end.x) <=
|
|
8602
|
-
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;
|
|
8603
8840
|
var getUniquePinCount2 = (pinIds) => new Set(pinIds).size;
|
|
8604
8841
|
|
|
8605
8842
|
// lib/solvers/TraceAnchoredNetLabelOverlapSolver/candidates.ts
|
|
@@ -8656,7 +8893,7 @@ var getCandidateDistances = (traceLength, vertexDistances) => {
|
|
|
8656
8893
|
for (const distance4 of vertexDistances) {
|
|
8657
8894
|
distances.add(roundDistance(distance4));
|
|
8658
8895
|
}
|
|
8659
|
-
return [...distances].filter((distance4) => distance4 >= -
|
|
8896
|
+
return [...distances].filter((distance4) => distance4 >= -EPS11 && distance4 <= traceLength + EPS11).sort((a, b) => a - b);
|
|
8660
8897
|
};
|
|
8661
8898
|
var getOrientationsForPoint = (params) => {
|
|
8662
8899
|
const { inputProblem, label, point, orientationConstraint } = params;
|
|
@@ -8745,13 +8982,13 @@ var getOutwardOrientationOptions = (point, chipBounds) => {
|
|
|
8745
8982
|
};
|
|
8746
8983
|
var getOutwardAxisOption = (params) => {
|
|
8747
8984
|
const { value, min, max, center, positiveOrientation, negativeOrientation } = params;
|
|
8748
|
-
if (value > max +
|
|
8985
|
+
if (value > max + EPS11) {
|
|
8749
8986
|
return {
|
|
8750
8987
|
orientation: positiveOrientation,
|
|
8751
8988
|
outwardScore: 1 + value - max
|
|
8752
8989
|
};
|
|
8753
8990
|
}
|
|
8754
|
-
if (value < min -
|
|
8991
|
+
if (value < min - EPS11) {
|
|
8755
8992
|
return {
|
|
8756
8993
|
orientation: negativeOrientation,
|
|
8757
8994
|
outwardScore: 1 + min - value
|
|
@@ -8762,7 +8999,7 @@ var getOutwardAxisOption = (params) => {
|
|
|
8762
8999
|
outwardScore: getNormalizedCenterDistance(value, center, max - min)
|
|
8763
9000
|
};
|
|
8764
9001
|
};
|
|
8765
|
-
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);
|
|
8766
9003
|
var ALL_ORIENTATIONS = ["x+", "x-", "y+", "y-"];
|
|
8767
9004
|
var getFlippedOrientation = (orientation) => {
|
|
8768
9005
|
switch (orientation) {
|
|
@@ -8835,7 +9072,7 @@ var getNetLabelHeight = (inputProblem, label) => {
|
|
|
8835
9072
|
)?.netLabelHeight;
|
|
8836
9073
|
};
|
|
8837
9074
|
var roundDistance = (distance4) => Number(distance4.toFixed(6));
|
|
8838
|
-
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;
|
|
8839
9076
|
|
|
8840
9077
|
// lib/solvers/TraceAnchoredNetLabelOverlapSolver/visualize.ts
|
|
8841
9078
|
var CANDIDATE_SELECTED_COLOR4 = "blue";
|