@tscircuit/schematic-trace-solver 0.0.56 → 0.0.60
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +3 -0
- package/dist/index.js +290 -136
- package/lib/solvers/AvailableNetOrientationSolver/AvailableNetOrientationSolver.ts +40 -13
- package/lib/solvers/AvailableNetOrientationSolver/geometry.ts +14 -0
- package/lib/solvers/Example28Solver/reroute.ts +137 -17
- package/lib/solvers/Example28Solver/types.ts +1 -0
- package/lib/solvers/NetLabelPlacementSolver/NetLabelPlacementSolver.ts +32 -10
- package/lib/solvers/TraceAnchoredNetLabelOverlapSolver/candidates.ts +17 -5
- package/lib/solvers/TraceCleanupSolver/is4PointRectangle.ts +7 -2
- package/lib/types/InputProblem.ts +1 -0
- package/package.json +1 -1
- package/site/examples/example34.page.tsx +4 -0
- package/site/examples/example35.page.tsx +4 -0
- package/site/examples/example36.page.tsx +4 -0
- package/tests/assets/example34.json +61 -0
- package/tests/assets/example35.json +127 -0
- package/tests/assets/example36.json +124 -0
- package/tests/examples/__snapshots__/example34.snap.svg +113 -0
- package/tests/examples/__snapshots__/example35.snap.svg +177 -0
- package/tests/examples/__snapshots__/example36.snap.svg +160 -0
- package/tests/examples/example34.test.ts +12 -0
- package/tests/examples/example35.test.ts +12 -0
- package/tests/examples/example36.test.ts +12 -0
package/dist/index.js
CHANGED
|
@@ -271,19 +271,19 @@ var doesPairCrossRestrictedCenterLines = (params) => {
|
|
|
271
271
|
chipMap
|
|
272
272
|
});
|
|
273
273
|
if (restrictedCenterLines.size === 0) return false;
|
|
274
|
-
const
|
|
274
|
+
const EPS10 = 1e-9;
|
|
275
275
|
const crossesSegment = (a, b) => {
|
|
276
276
|
for (const [, rcl] of restrictedCenterLines) {
|
|
277
277
|
if (rcl.axes.has("x") && typeof rcl.x === "number") {
|
|
278
|
-
if ((a.x - rcl.x) * (b.x - rcl.x) < -
|
|
278
|
+
if ((a.x - rcl.x) * (b.x - rcl.x) < -EPS10) return true;
|
|
279
279
|
}
|
|
280
280
|
if (rcl.axes.has("y") && typeof rcl.y === "number") {
|
|
281
|
-
if ((a.y - rcl.y) * (b.y - rcl.y) < -
|
|
281
|
+
if ((a.y - rcl.y) * (b.y - rcl.y) < -EPS10) return true;
|
|
282
282
|
}
|
|
283
283
|
}
|
|
284
284
|
return false;
|
|
285
285
|
};
|
|
286
|
-
if (Math.abs(p1.x - p2.x) <
|
|
286
|
+
if (Math.abs(p1.x - p2.x) < EPS10 || Math.abs(p1.y - p2.y) < EPS10) {
|
|
287
287
|
return crossesSegment({ x: p1.x, y: p1.y }, { x: p2.x, y: p2.y });
|
|
288
288
|
}
|
|
289
289
|
const elbowHV = { x: p2.x, y: p1.y };
|
|
@@ -850,8 +850,8 @@ var SchematicTraceSingleLineSolver2 = class extends BaseSolver {
|
|
|
850
850
|
if (!collision) {
|
|
851
851
|
const first = path[0];
|
|
852
852
|
const last = path[path.length - 1];
|
|
853
|
-
const
|
|
854
|
-
const samePoint = (p, q) => Math.abs(p.x - q.x) <
|
|
853
|
+
const EPS10 = 1e-9;
|
|
854
|
+
const samePoint = (p, q) => Math.abs(p.x - q.x) < EPS10 && Math.abs(p.y - q.y) < EPS10;
|
|
855
855
|
if (samePoint(first, { x: PA.x, y: PA.y }) && samePoint(last, { x: PB.x, y: PB.y })) {
|
|
856
856
|
this.solvedTracePath = path;
|
|
857
857
|
this.solved = true;
|
|
@@ -1050,13 +1050,13 @@ var applyJogToTerminalSegment = ({
|
|
|
1050
1050
|
segmentIndex: si,
|
|
1051
1051
|
offset,
|
|
1052
1052
|
JOG_SIZE,
|
|
1053
|
-
EPS:
|
|
1053
|
+
EPS: EPS10 = 1e-6
|
|
1054
1054
|
}) => {
|
|
1055
1055
|
if (si !== 0 && si !== pts.length - 2) return;
|
|
1056
1056
|
const start = pts[si];
|
|
1057
1057
|
const end = pts[si + 1];
|
|
1058
|
-
const isVertical4 = Math.abs(start.x - end.x) <
|
|
1059
|
-
const isHorizontal3 = Math.abs(start.y - end.y) <
|
|
1058
|
+
const isVertical4 = Math.abs(start.x - end.x) < EPS10;
|
|
1059
|
+
const isHorizontal3 = Math.abs(start.y - end.y) < EPS10;
|
|
1060
1060
|
if (!isVertical4 && !isHorizontal3) return;
|
|
1061
1061
|
const segDir = isVertical4 ? end.y > start.y ? 1 : -1 : end.x > start.x ? 1 : -1;
|
|
1062
1062
|
if (si === 0) {
|
|
@@ -1123,13 +1123,13 @@ var TraceOverlapIssueSolver = class extends BaseSolver {
|
|
|
1123
1123
|
}
|
|
1124
1124
|
}
|
|
1125
1125
|
_step() {
|
|
1126
|
-
const
|
|
1126
|
+
const EPS10 = 1e-6;
|
|
1127
1127
|
const offsets = this.overlappingTraceSegments.map((_, idx) => {
|
|
1128
1128
|
const n = Math.floor(idx / 2) + 1;
|
|
1129
1129
|
const signed = idx % 2 === 0 ? -n : n;
|
|
1130
1130
|
return signed * this.SHIFT_DISTANCE;
|
|
1131
1131
|
});
|
|
1132
|
-
const eq = (a, b) => Math.abs(a - b) <
|
|
1132
|
+
const eq = (a, b) => Math.abs(a - b) < EPS10;
|
|
1133
1133
|
const samePoint = (p, q) => !!p && !!q && eq(p.x, q.x) && eq(p.y, q.y);
|
|
1134
1134
|
this.overlappingTraceSegments.forEach((group, gidx) => {
|
|
1135
1135
|
const offset = offsets[gidx];
|
|
@@ -1155,13 +1155,13 @@ var TraceOverlapIssueSolver = class extends BaseSolver {
|
|
|
1155
1155
|
segmentIndex: si,
|
|
1156
1156
|
offset,
|
|
1157
1157
|
JOG_SIZE,
|
|
1158
|
-
EPS:
|
|
1158
|
+
EPS: EPS10
|
|
1159
1159
|
});
|
|
1160
1160
|
} else {
|
|
1161
1161
|
const start = pts[si];
|
|
1162
1162
|
const end = pts[si + 1];
|
|
1163
|
-
const isVertical4 = Math.abs(start.x - end.x) <
|
|
1164
|
-
const isHorizontal3 = Math.abs(start.y - end.y) <
|
|
1163
|
+
const isVertical4 = Math.abs(start.x - end.x) < EPS10;
|
|
1164
|
+
const isHorizontal3 = Math.abs(start.y - end.y) < EPS10;
|
|
1165
1165
|
if (!isVertical4 && !isHorizontal3) continue;
|
|
1166
1166
|
if (isVertical4) {
|
|
1167
1167
|
start.x += offset;
|
|
@@ -1258,7 +1258,7 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
|
|
|
1258
1258
|
return islands;
|
|
1259
1259
|
}
|
|
1260
1260
|
findNextOverlapIssue() {
|
|
1261
|
-
const
|
|
1261
|
+
const EPS10 = 2e-3;
|
|
1262
1262
|
const netIds = Object.keys(this.traceNetIslands);
|
|
1263
1263
|
for (let i = 0; i < netIds.length; i++) {
|
|
1264
1264
|
for (let j = i + 1; j < netIds.length; j++) {
|
|
@@ -1276,7 +1276,7 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
|
|
|
1276
1276
|
const minB = Math.min(b1, b2);
|
|
1277
1277
|
const maxB = Math.max(b1, b2);
|
|
1278
1278
|
const overlap = Math.min(maxA, maxB) - Math.max(minA, minB);
|
|
1279
|
-
return overlap >
|
|
1279
|
+
return overlap > EPS10;
|
|
1280
1280
|
};
|
|
1281
1281
|
for (let pa = 0; pa < pathsA.length; pa++) {
|
|
1282
1282
|
const pathA = pathsA[pa];
|
|
@@ -1284,8 +1284,8 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
|
|
|
1284
1284
|
for (let sa = 0; sa < ptsA.length - 1; sa++) {
|
|
1285
1285
|
const a1 = ptsA[sa];
|
|
1286
1286
|
const a2 = ptsA[sa + 1];
|
|
1287
|
-
const aVert = Math.abs(a1.x - a2.x) <
|
|
1288
|
-
const aHorz = Math.abs(a1.y - a2.y) <
|
|
1287
|
+
const aVert = Math.abs(a1.x - a2.x) < EPS10;
|
|
1288
|
+
const aHorz = Math.abs(a1.y - a2.y) < EPS10;
|
|
1289
1289
|
if (!aVert && !aHorz) continue;
|
|
1290
1290
|
for (let pb = 0; pb < pathsB.length; pb++) {
|
|
1291
1291
|
const pathB = pathsB[pb];
|
|
@@ -1293,11 +1293,11 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
|
|
|
1293
1293
|
for (let sb = 0; sb < ptsB.length - 1; sb++) {
|
|
1294
1294
|
const b1 = ptsB[sb];
|
|
1295
1295
|
const b2 = ptsB[sb + 1];
|
|
1296
|
-
const bVert = Math.abs(b1.x - b2.x) <
|
|
1297
|
-
const bHorz = Math.abs(b1.y - b2.y) <
|
|
1296
|
+
const bVert = Math.abs(b1.x - b2.x) < EPS10;
|
|
1297
|
+
const bHorz = Math.abs(b1.y - b2.y) < EPS10;
|
|
1298
1298
|
if (!bVert && !bHorz) continue;
|
|
1299
1299
|
if (aVert && bVert) {
|
|
1300
|
-
if (Math.abs(a1.x - b1.x) <
|
|
1300
|
+
if (Math.abs(a1.x - b1.x) < EPS10) {
|
|
1301
1301
|
if (overlaps1D(a1.y, a2.y, b1.y, b2.y)) {
|
|
1302
1302
|
const keyA = `${pa}:${sa}`;
|
|
1303
1303
|
const keyB = `${pb}:${sb}`;
|
|
@@ -1318,7 +1318,7 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
|
|
|
1318
1318
|
}
|
|
1319
1319
|
}
|
|
1320
1320
|
} else if (aHorz && bHorz) {
|
|
1321
|
-
if (Math.abs(a1.y - b1.y) <
|
|
1321
|
+
if (Math.abs(a1.y - b1.y) < EPS10) {
|
|
1322
1322
|
if (overlaps1D(a1.x, a2.x, b1.x, b2.x)) {
|
|
1323
1323
|
const keyA = `${pa}:${sa}`;
|
|
1324
1324
|
const keyB = `${pb}:${sb}`;
|
|
@@ -1356,14 +1356,14 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
|
|
|
1356
1356
|
return null;
|
|
1357
1357
|
}
|
|
1358
1358
|
findNextDiagonalSegment() {
|
|
1359
|
-
const
|
|
1359
|
+
const EPS10 = 2e-3;
|
|
1360
1360
|
for (const mspPairId in this.correctedTraceMap) {
|
|
1361
1361
|
const tracePath = this.correctedTraceMap[mspPairId].tracePath;
|
|
1362
1362
|
for (let i = 0; i < tracePath.length - 1; i++) {
|
|
1363
1363
|
const p1 = tracePath[i];
|
|
1364
1364
|
const p2 = tracePath[i + 1];
|
|
1365
|
-
const isHorizontal3 = Math.abs(p1.y - p2.y) <
|
|
1366
|
-
const isVertical4 = Math.abs(p1.x - p2.x) <
|
|
1365
|
+
const isHorizontal3 = Math.abs(p1.y - p2.y) < EPS10;
|
|
1366
|
+
const isVertical4 = Math.abs(p1.x - p2.x) < EPS10;
|
|
1367
1367
|
if (!isHorizontal3 && !isVertical4) {
|
|
1368
1368
|
return { mspPairId, tracePath, i, p1, p2 };
|
|
1369
1369
|
}
|
|
@@ -1377,13 +1377,13 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
|
|
|
1377
1377
|
return false;
|
|
1378
1378
|
}
|
|
1379
1379
|
const { mspPairId, tracePath, i, p1, p2 } = diagonalInfo;
|
|
1380
|
-
const
|
|
1380
|
+
const EPS10 = 2e-3;
|
|
1381
1381
|
const p0 = i > 0 ? tracePath[i - 1] : null;
|
|
1382
1382
|
const p3 = i + 2 < tracePath.length ? tracePath[i + 2] : null;
|
|
1383
|
-
const prevIsVertical = p0 ? Math.abs(p0.x - p1.x) <
|
|
1384
|
-
const prevIsHorizontal = p0 ? Math.abs(p0.y - p1.y) <
|
|
1385
|
-
const nextIsVertical = p3 ? Math.abs(p2.x - p3.x) <
|
|
1386
|
-
const nextIsHorizontal = p3 ? Math.abs(p2.y - p3.y) <
|
|
1383
|
+
const prevIsVertical = p0 ? Math.abs(p0.x - p1.x) < EPS10 : false;
|
|
1384
|
+
const prevIsHorizontal = p0 ? Math.abs(p0.y - p1.y) < EPS10 : false;
|
|
1385
|
+
const nextIsVertical = p3 ? Math.abs(p2.x - p3.x) < EPS10 : false;
|
|
1386
|
+
const nextIsHorizontal = p3 ? Math.abs(p2.y - p3.y) < EPS10 : false;
|
|
1387
1387
|
const elbow1 = { x: p1.x, y: p2.y };
|
|
1388
1388
|
const elbow2 = { x: p2.x, y: p1.y };
|
|
1389
1389
|
let score1 = 0;
|
|
@@ -1547,24 +1547,24 @@ function getRectBounds(center, w, h) {
|
|
|
1547
1547
|
}
|
|
1548
1548
|
|
|
1549
1549
|
// lib/solvers/NetLabelPlacementSolver/SingleNetLabelPlacementSolver/collisions.ts
|
|
1550
|
-
function segmentIntersectsRect2(p1, p2, rect,
|
|
1551
|
-
const isVert = Math.abs(p1.x - p2.x) <
|
|
1552
|
-
const isHorz = Math.abs(p1.y - p2.y) <
|
|
1550
|
+
function segmentIntersectsRect2(p1, p2, rect, EPS10 = 1e-9) {
|
|
1551
|
+
const isVert = Math.abs(p1.x - p2.x) < EPS10;
|
|
1552
|
+
const isHorz = Math.abs(p1.y - p2.y) < EPS10;
|
|
1553
1553
|
if (!isVert && !isHorz) return false;
|
|
1554
1554
|
if (isVert) {
|
|
1555
1555
|
const x = p1.x;
|
|
1556
|
-
if (x < rect.minX -
|
|
1556
|
+
if (x < rect.minX - EPS10 || x > rect.maxX + EPS10) return false;
|
|
1557
1557
|
const segMinY = Math.min(p1.y, p2.y);
|
|
1558
1558
|
const segMaxY = Math.max(p1.y, p2.y);
|
|
1559
1559
|
const overlap = Math.min(segMaxY, rect.maxY) - Math.max(segMinY, rect.minY);
|
|
1560
|
-
return overlap >
|
|
1560
|
+
return overlap > EPS10;
|
|
1561
1561
|
} else {
|
|
1562
1562
|
const y = p1.y;
|
|
1563
|
-
if (y < rect.minY -
|
|
1563
|
+
if (y < rect.minY - EPS10 || y > rect.maxY + EPS10) return false;
|
|
1564
1564
|
const segMinX = Math.min(p1.x, p2.x);
|
|
1565
1565
|
const segMaxX = Math.max(p1.x, p2.x);
|
|
1566
1566
|
const overlap = Math.min(segMaxX, rect.maxX) - Math.max(segMinX, rect.minX);
|
|
1567
|
-
return overlap >
|
|
1567
|
+
return overlap > EPS10;
|
|
1568
1568
|
}
|
|
1569
1569
|
}
|
|
1570
1570
|
function rectIntersectsAnyTrace(bounds, inputTraceMap, hostPathId, hostSegIndex) {
|
|
@@ -1942,14 +1942,14 @@ var SingleNetLabelPlacementSolver = class extends BaseSolver {
|
|
|
1942
1942
|
};
|
|
1943
1943
|
let bestCandidate = null;
|
|
1944
1944
|
let bestScore = -Infinity;
|
|
1945
|
-
const
|
|
1945
|
+
const EPS10 = 1e-6;
|
|
1946
1946
|
for (const curr of tracesToScan) {
|
|
1947
1947
|
const pts = curr.tracePath.slice();
|
|
1948
1948
|
for (let si = 0; si < pts.length - 1; si++) {
|
|
1949
1949
|
const a = pts[si];
|
|
1950
1950
|
const b = pts[si + 1];
|
|
1951
|
-
const isH = Math.abs(a.y - b.y) <
|
|
1952
|
-
const isV = Math.abs(a.x - b.x) <
|
|
1951
|
+
const isH = Math.abs(a.y - b.y) < EPS10;
|
|
1952
|
+
const isV = Math.abs(a.x - b.x) < EPS10;
|
|
1953
1953
|
if (!isH && !isV) continue;
|
|
1954
1954
|
const segmentAllowed = isH ? ["y+", "y-"] : ["x+", "x-"];
|
|
1955
1955
|
const candidateOrients = orientations.filter(
|
|
@@ -2227,6 +2227,29 @@ var NetLabelPlacementSolver = class extends BaseSolver {
|
|
|
2227
2227
|
}
|
|
2228
2228
|
return groups;
|
|
2229
2229
|
}
|
|
2230
|
+
getNetLabelWidthForGroup(group) {
|
|
2231
|
+
if (group.netId) {
|
|
2232
|
+
const ncWidth = this.inputProblem.netConnections.find(
|
|
2233
|
+
(nc) => nc.netId === group.netId
|
|
2234
|
+
)?.netLabelWidth;
|
|
2235
|
+
if (ncWidth !== void 0) return ncWidth;
|
|
2236
|
+
const dcWidthByNetId = this.inputProblem.directConnections.find(
|
|
2237
|
+
(dc) => dc.netId === group.netId
|
|
2238
|
+
)?.netLabelWidth;
|
|
2239
|
+
if (dcWidthByNetId !== void 0) return dcWidthByNetId;
|
|
2240
|
+
}
|
|
2241
|
+
const pinIds = group.overlappingTraces?.pins.map((p) => p.pinId) ?? [];
|
|
2242
|
+
if (group.portOnlyPinId) {
|
|
2243
|
+
pinIds.push(group.portOnlyPinId);
|
|
2244
|
+
}
|
|
2245
|
+
const dcWidthByPinId = this.inputProblem.directConnections.find(
|
|
2246
|
+
(dc) => dc.pinIds.some((pid) => pinIds.includes(pid))
|
|
2247
|
+
)?.netLabelWidth;
|
|
2248
|
+
if (dcWidthByPinId !== void 0) return dcWidthByPinId;
|
|
2249
|
+
return this.inputProblem.netConnections.find(
|
|
2250
|
+
(nc) => nc.pinIds.some((pid) => pinIds.includes(pid))
|
|
2251
|
+
)?.netLabelWidth;
|
|
2252
|
+
}
|
|
2230
2253
|
_step() {
|
|
2231
2254
|
if (this.activeSubSolver?.solved) {
|
|
2232
2255
|
this.netLabelPlacements.push(this.activeSubSolver.netLabelPlacement);
|
|
@@ -2241,9 +2264,7 @@ var NetLabelPlacementSolver = class extends BaseSolver {
|
|
|
2241
2264
|
const isAlreadyFull = currOrients.length === 4 && fullOrients.every((o) => currOrients.includes(o));
|
|
2242
2265
|
if (!this.triedAnyOrientationFallbackForCurrentGroup && !isAlreadyFull && this.currentGroup) {
|
|
2243
2266
|
this.triedAnyOrientationFallbackForCurrentGroup = true;
|
|
2244
|
-
const netLabelWidth2 = this.
|
|
2245
|
-
(nc) => nc.netId === this.currentGroup.netId
|
|
2246
|
-
)?.netLabelWidth : void 0;
|
|
2267
|
+
const netLabelWidth2 = this.getNetLabelWidthForGroup(this.currentGroup);
|
|
2247
2268
|
this.activeSubSolver = new SingleNetLabelPlacementSolver({
|
|
2248
2269
|
inputProblem: this.inputProblem,
|
|
2249
2270
|
inputTraceMap: this.inputTraceMap,
|
|
@@ -2269,9 +2290,7 @@ var NetLabelPlacementSolver = class extends BaseSolver {
|
|
|
2269
2290
|
const netId = nextOverlappingSameNetTraceGroup.netId ?? nextOverlappingSameNetTraceGroup.globalConnNetId;
|
|
2270
2291
|
this.currentGroup = nextOverlappingSameNetTraceGroup;
|
|
2271
2292
|
this.triedAnyOrientationFallbackForCurrentGroup = false;
|
|
2272
|
-
const netLabelWidth = this.
|
|
2273
|
-
(nc) => nc.netId === this.currentGroup.netId
|
|
2274
|
-
)?.netLabelWidth : void 0;
|
|
2293
|
+
const netLabelWidth = this.getNetLabelWidthForGroup(this.currentGroup);
|
|
2275
2294
|
this.activeSubSolver = new SingleNetLabelPlacementSolver({
|
|
2276
2295
|
inputProblem: this.inputProblem,
|
|
2277
2296
|
inputTraceMap: this.inputTraceMap,
|
|
@@ -4621,11 +4640,14 @@ var UntangleTraceSubsolver = class extends BaseSolver {
|
|
|
4621
4640
|
};
|
|
4622
4641
|
|
|
4623
4642
|
// lib/solvers/TraceCleanupSolver/is4PointRectangle.ts
|
|
4643
|
+
var EPS5 = 1e-6;
|
|
4644
|
+
var sameX = (a, b) => Math.abs(a.x - b.x) <= EPS5;
|
|
4645
|
+
var sameY = (a, b) => Math.abs(a.y - b.y) <= EPS5;
|
|
4624
4646
|
var is4PointRectangle = (path) => {
|
|
4625
4647
|
if (path.length !== 4) return false;
|
|
4626
4648
|
const [p0, p1, p2, p3] = path;
|
|
4627
|
-
const isHVHC = p0
|
|
4628
|
-
const isVHVC = p0
|
|
4649
|
+
const isHVHC = sameY(p0, p1) && sameX(p1, p2) && sameY(p2, p3) && sameX(p0, p3);
|
|
4650
|
+
const isVHVC = sameX(p0, p1) && sameY(p1, p2) && sameX(p2, p3) && sameY(p0, p3);
|
|
4629
4651
|
return isHVHC || isVHVC;
|
|
4630
4652
|
};
|
|
4631
4653
|
|
|
@@ -4754,7 +4776,7 @@ var TraceCleanupSolver = class extends BaseSolver {
|
|
|
4754
4776
|
};
|
|
4755
4777
|
|
|
4756
4778
|
// lib/solvers/Example28Solver/types.ts
|
|
4757
|
-
var
|
|
4779
|
+
var EPS6 = 1e-9;
|
|
4758
4780
|
|
|
4759
4781
|
// lib/solvers/Example28Solver/geometry.ts
|
|
4760
4782
|
var getPathKey = (path) => path.map((point) => `${point.x},${point.y}`).join(";");
|
|
@@ -4766,10 +4788,10 @@ var getPathLength = (path) => {
|
|
|
4766
4788
|
return length;
|
|
4767
4789
|
};
|
|
4768
4790
|
var getDistance = (a, b) => Math.abs(a.x - b.x) + Math.abs(a.y - b.y);
|
|
4769
|
-
var isAxisAlignedSegment = (start, end) => Math.abs(start.x - end.x) <
|
|
4770
|
-
var getSegmentOrientation = (start, end) => Math.abs(start.y - end.y) <
|
|
4791
|
+
var isAxisAlignedSegment = (start, end) => Math.abs(start.x - end.x) < EPS6 || Math.abs(start.y - end.y) < EPS6;
|
|
4792
|
+
var getSegmentOrientation = (start, end) => Math.abs(start.y - end.y) < EPS6 ? "horizontal" : "vertical";
|
|
4771
4793
|
var projectPointToSegment = (point, start, end) => {
|
|
4772
|
-
if (Math.abs(start.x - end.x) <
|
|
4794
|
+
if (Math.abs(start.x - end.x) < EPS6) {
|
|
4773
4795
|
return {
|
|
4774
4796
|
x: start.x,
|
|
4775
4797
|
y: Math.min(
|
|
@@ -4778,7 +4800,7 @@ var projectPointToSegment = (point, start, end) => {
|
|
|
4778
4800
|
)
|
|
4779
4801
|
};
|
|
4780
4802
|
}
|
|
4781
|
-
if (Math.abs(start.y - end.y) <
|
|
4803
|
+
if (Math.abs(start.y - end.y) < EPS6) {
|
|
4782
4804
|
return {
|
|
4783
4805
|
x: Math.min(
|
|
4784
4806
|
Math.max(point.x, Math.min(start.x, end.x)),
|
|
@@ -4821,9 +4843,9 @@ var findSegmentContainingPoint = (path, point) => {
|
|
|
4821
4843
|
};
|
|
4822
4844
|
var isPointWithinSegmentPrimaryRange = (point, segment) => {
|
|
4823
4845
|
if (segment.orientation === "horizontal") {
|
|
4824
|
-
return point.x >= Math.min(segment.start.x, segment.end.x) -
|
|
4846
|
+
return point.x >= Math.min(segment.start.x, segment.end.x) - EPS6 && point.x <= Math.max(segment.start.x, segment.end.x) + EPS6;
|
|
4825
4847
|
}
|
|
4826
|
-
return point.y >= Math.min(segment.start.y, segment.end.y) -
|
|
4848
|
+
return point.y >= Math.min(segment.start.y, segment.end.y) - EPS6 && point.y <= Math.max(segment.start.y, segment.end.y) + EPS6;
|
|
4827
4849
|
};
|
|
4828
4850
|
var findPreferredReroutedSegment = (path, originalSegmentIndex, originalSegmentCount, orientation, anchorPoint) => {
|
|
4829
4851
|
const matchingSegments = getSegments(path).filter(
|
|
@@ -4851,18 +4873,18 @@ var projectPointToPath = (point, path) => {
|
|
|
4851
4873
|
return bestPoint;
|
|
4852
4874
|
};
|
|
4853
4875
|
var segmentsIntersect = (a1, a2, b1, b2) => {
|
|
4854
|
-
const aVertical = Math.abs(a1.x - a2.x) <
|
|
4855
|
-
const bVertical = Math.abs(b1.x - b2.x) <
|
|
4856
|
-
const between = (value, p1, p2) => value >= Math.min(p1, p2) -
|
|
4876
|
+
const aVertical = Math.abs(a1.x - a2.x) < EPS6;
|
|
4877
|
+
const bVertical = Math.abs(b1.x - b2.x) < EPS6;
|
|
4878
|
+
const between = (value, p1, p2) => value >= Math.min(p1, p2) - EPS6 && value <= Math.max(p1, p2) + EPS6;
|
|
4857
4879
|
if (aVertical && bVertical) {
|
|
4858
|
-
if (Math.abs(a1.x - b1.x) >
|
|
4880
|
+
if (Math.abs(a1.x - b1.x) > EPS6) return false;
|
|
4859
4881
|
const overlap = Math.min(Math.max(a1.y, a2.y), Math.max(b1.y, b2.y)) - Math.max(Math.min(a1.y, a2.y), Math.min(b1.y, b2.y));
|
|
4860
|
-
return overlap >
|
|
4882
|
+
return overlap > EPS6;
|
|
4861
4883
|
}
|
|
4862
4884
|
if (!aVertical && !bVertical) {
|
|
4863
|
-
if (Math.abs(a1.y - b1.y) >
|
|
4885
|
+
if (Math.abs(a1.y - b1.y) > EPS6) return false;
|
|
4864
4886
|
const overlap = Math.min(Math.max(a1.x, a2.x), Math.max(b1.x, b2.x)) - Math.max(Math.min(a1.x, a2.x), Math.min(b1.x, b2.x));
|
|
4865
|
-
return overlap >
|
|
4887
|
+
return overlap > EPS6;
|
|
4866
4888
|
}
|
|
4867
4889
|
const verticalA = aVertical ? a1 : b1;
|
|
4868
4890
|
const verticalB = aVertical ? a2 : b2;
|
|
@@ -4894,13 +4916,13 @@ var isPathCollidingWithChipInterior = (path, chipObstacles) => {
|
|
|
4894
4916
|
return false;
|
|
4895
4917
|
};
|
|
4896
4918
|
var segmentRunsAlongRectBoundary = (start, end, rect) => {
|
|
4897
|
-
const isVertical4 = Math.abs(start.x - end.x) <
|
|
4898
|
-
const isHorizontal3 = Math.abs(start.y - end.y) <
|
|
4919
|
+
const isVertical4 = Math.abs(start.x - end.x) < EPS6;
|
|
4920
|
+
const isHorizontal3 = Math.abs(start.y - end.y) < EPS6;
|
|
4899
4921
|
if (isVertical4) {
|
|
4900
|
-
return Math.abs(start.x - rect.minX) <
|
|
4922
|
+
return Math.abs(start.x - rect.minX) < EPS6 || Math.abs(start.x - rect.maxX) < EPS6;
|
|
4901
4923
|
}
|
|
4902
4924
|
if (isHorizontal3) {
|
|
4903
|
-
return Math.abs(start.y - rect.minY) <
|
|
4925
|
+
return Math.abs(start.y - rect.minY) < EPS6 || Math.abs(start.y - rect.maxY) < EPS6;
|
|
4904
4926
|
}
|
|
4905
4927
|
return false;
|
|
4906
4928
|
};
|
|
@@ -5008,9 +5030,37 @@ var generateRerouteCandidateResults = ({
|
|
|
5008
5030
|
outputNetLabelPlacements,
|
|
5009
5031
|
chipObstacles
|
|
5010
5032
|
}) => {
|
|
5011
|
-
const rawCandidates = generateCandidatePaths(trace, label, inputProblem);
|
|
5012
5033
|
const seen = /* @__PURE__ */ new Set();
|
|
5013
5034
|
const candidateResults = [];
|
|
5035
|
+
const horizontalSegmentPushCandidate = generateHorizontalSegmentPushCandidate(
|
|
5036
|
+
trace,
|
|
5037
|
+
label
|
|
5038
|
+
);
|
|
5039
|
+
if (horizontalSegmentPushCandidate) {
|
|
5040
|
+
candidateResults.push(
|
|
5041
|
+
createCandidateResult({
|
|
5042
|
+
trace,
|
|
5043
|
+
obstacleLabel: label,
|
|
5044
|
+
path: horizontalSegmentPushCandidate,
|
|
5045
|
+
seen,
|
|
5046
|
+
outputTraces,
|
|
5047
|
+
outputNetLabelPlacements,
|
|
5048
|
+
chipObstacles,
|
|
5049
|
+
usesHorizontalSegmentPush: true
|
|
5050
|
+
})
|
|
5051
|
+
);
|
|
5052
|
+
}
|
|
5053
|
+
const rawCandidates = [
|
|
5054
|
+
...generateLabelHugCandidates(trace, label),
|
|
5055
|
+
...generateRerouteCandidates({
|
|
5056
|
+
trace,
|
|
5057
|
+
label,
|
|
5058
|
+
problem: inputProblem,
|
|
5059
|
+
paddingBuffer: LABEL_SIDE_CLEARANCE,
|
|
5060
|
+
detourCount: 0
|
|
5061
|
+
}),
|
|
5062
|
+
...generateEndpointDetourCandidates(trace, label)
|
|
5063
|
+
];
|
|
5014
5064
|
for (const rawCandidate of rawCandidates) {
|
|
5015
5065
|
candidateResults.push(
|
|
5016
5066
|
createCandidateResult({
|
|
@@ -5026,17 +5076,6 @@ var generateRerouteCandidateResults = ({
|
|
|
5026
5076
|
}
|
|
5027
5077
|
return candidateResults;
|
|
5028
5078
|
};
|
|
5029
|
-
var generateCandidatePaths = (trace, label, inputProblem) => [
|
|
5030
|
-
...generateLabelHugCandidates(trace, label),
|
|
5031
|
-
...generateRerouteCandidates({
|
|
5032
|
-
trace,
|
|
5033
|
-
label,
|
|
5034
|
-
problem: inputProblem,
|
|
5035
|
-
paddingBuffer: LABEL_SIDE_CLEARANCE,
|
|
5036
|
-
detourCount: 0
|
|
5037
|
-
}),
|
|
5038
|
-
...generateEndpointDetourCandidates(trace, label)
|
|
5039
|
-
];
|
|
5040
5079
|
var createCandidateResult = ({
|
|
5041
5080
|
trace,
|
|
5042
5081
|
obstacleLabel,
|
|
@@ -5044,13 +5083,15 @@ var createCandidateResult = ({
|
|
|
5044
5083
|
seen,
|
|
5045
5084
|
outputTraces,
|
|
5046
5085
|
outputNetLabelPlacements,
|
|
5047
|
-
chipObstacles
|
|
5086
|
+
chipObstacles,
|
|
5087
|
+
usesHorizontalSegmentPush
|
|
5048
5088
|
}) => {
|
|
5049
5089
|
const key = getPathKey(path);
|
|
5050
5090
|
if (seen.has(key)) {
|
|
5051
5091
|
return {
|
|
5052
5092
|
path,
|
|
5053
5093
|
status: "duplicate",
|
|
5094
|
+
usesHorizontalSegmentPush,
|
|
5054
5095
|
selected: false
|
|
5055
5096
|
};
|
|
5056
5097
|
}
|
|
@@ -5059,6 +5100,7 @@ var createCandidateResult = ({
|
|
|
5059
5100
|
return {
|
|
5060
5101
|
path,
|
|
5061
5102
|
status: "chip-collision",
|
|
5103
|
+
usesHorizontalSegmentPush,
|
|
5062
5104
|
selected: false
|
|
5063
5105
|
};
|
|
5064
5106
|
}
|
|
@@ -5072,6 +5114,7 @@ var createCandidateResult = ({
|
|
|
5072
5114
|
outputNetLabelPlacements
|
|
5073
5115
|
}),
|
|
5074
5116
|
status: "valid",
|
|
5117
|
+
usesHorizontalSegmentPush,
|
|
5075
5118
|
selected: false
|
|
5076
5119
|
};
|
|
5077
5120
|
};
|
|
@@ -5148,6 +5191,12 @@ var selectBestReroutePath = ({
|
|
|
5148
5191
|
outputNetLabelPlacements,
|
|
5149
5192
|
candidateResults
|
|
5150
5193
|
}) => {
|
|
5194
|
+
for (const candidate of candidateResults) {
|
|
5195
|
+
if (!candidate.usesHorizontalSegmentPush) continue;
|
|
5196
|
+
if (candidate.status !== "valid") continue;
|
|
5197
|
+
if (!candidate.score) continue;
|
|
5198
|
+
return candidate.path;
|
|
5199
|
+
}
|
|
5151
5200
|
let bestPath = null;
|
|
5152
5201
|
let bestScore = scoreTracePath({
|
|
5153
5202
|
trace,
|
|
@@ -5164,6 +5213,71 @@ var selectBestReroutePath = ({
|
|
|
5164
5213
|
}
|
|
5165
5214
|
return bestPath;
|
|
5166
5215
|
};
|
|
5216
|
+
var generateHorizontalSegmentPushCandidate = (trace, label) => {
|
|
5217
|
+
const labelDirection = dir(label.orientation);
|
|
5218
|
+
if (labelDirection.x === 0) return null;
|
|
5219
|
+
const path = trace.tracePath;
|
|
5220
|
+
const bounds = getRectBounds(label.center, label.width, label.height);
|
|
5221
|
+
const collidingVerticalSegmentIndex = path.findIndex((start, index) => {
|
|
5222
|
+
const end = path[index + 1];
|
|
5223
|
+
if (!end) return false;
|
|
5224
|
+
if (Math.abs(start.x - end.x) >= 1e-9) return false;
|
|
5225
|
+
return segmentIntersectsRect2(start, end, bounds);
|
|
5226
|
+
});
|
|
5227
|
+
if (collidingVerticalSegmentIndex <= 0 || collidingVerticalSegmentIndex >= path.length - 2) {
|
|
5228
|
+
return null;
|
|
5229
|
+
}
|
|
5230
|
+
const previousAnchor = path[collidingVerticalSegmentIndex - 1];
|
|
5231
|
+
const verticalStart = path[collidingVerticalSegmentIndex];
|
|
5232
|
+
const verticalEnd = path[collidingVerticalSegmentIndex + 1];
|
|
5233
|
+
const nextAnchor = path[collidingVerticalSegmentIndex + 2];
|
|
5234
|
+
if (Math.abs(previousAnchor.y - verticalStart.y) >= 1e-9 || Math.abs(verticalEnd.y - nextAnchor.y) >= 1e-9) {
|
|
5235
|
+
return null;
|
|
5236
|
+
}
|
|
5237
|
+
let segmentPushX = bounds.minX - LABEL_SIDE_CLEARANCE;
|
|
5238
|
+
if (labelDirection.x > 0) {
|
|
5239
|
+
segmentPushX = bounds.maxX + LABEL_SIDE_CLEARANCE;
|
|
5240
|
+
}
|
|
5241
|
+
const segmentPushStartY = getClearedHorizontalY({
|
|
5242
|
+
start: previousAnchor,
|
|
5243
|
+
end: { x: segmentPushX, y: verticalStart.y },
|
|
5244
|
+
labelBounds: bounds
|
|
5245
|
+
});
|
|
5246
|
+
const segmentPushEndY = getClearedHorizontalY({
|
|
5247
|
+
start: { x: segmentPushX, y: verticalEnd.y },
|
|
5248
|
+
end: nextAnchor,
|
|
5249
|
+
labelBounds: bounds
|
|
5250
|
+
});
|
|
5251
|
+
const segmentPushPath = [
|
|
5252
|
+
...path.slice(0, collidingVerticalSegmentIndex - 1),
|
|
5253
|
+
previousAnchor
|
|
5254
|
+
];
|
|
5255
|
+
if (Math.abs(previousAnchor.y - segmentPushStartY) >= 1e-9) {
|
|
5256
|
+
segmentPushPath.push({ x: previousAnchor.x, y: segmentPushStartY });
|
|
5257
|
+
}
|
|
5258
|
+
segmentPushPath.push({ x: segmentPushX, y: segmentPushStartY });
|
|
5259
|
+
segmentPushPath.push({ x: segmentPushX, y: segmentPushEndY });
|
|
5260
|
+
if (Math.abs(nextAnchor.y - segmentPushEndY) >= 1e-9) {
|
|
5261
|
+
segmentPushPath.push({ x: nextAnchor.x, y: segmentPushEndY });
|
|
5262
|
+
}
|
|
5263
|
+
segmentPushPath.push(
|
|
5264
|
+
nextAnchor,
|
|
5265
|
+
...path.slice(collidingVerticalSegmentIndex + 3)
|
|
5266
|
+
);
|
|
5267
|
+
return simplifyPath(segmentPushPath);
|
|
5268
|
+
};
|
|
5269
|
+
var getClearedHorizontalY = ({
|
|
5270
|
+
start,
|
|
5271
|
+
end,
|
|
5272
|
+
labelBounds
|
|
5273
|
+
}) => {
|
|
5274
|
+
if (!segmentIntersectsRect2(start, end, labelBounds)) return start.y;
|
|
5275
|
+
const labelCenterY = (labelBounds.minY + labelBounds.maxY) / 2;
|
|
5276
|
+
if (start.y >= labelCenterY) {
|
|
5277
|
+
return labelBounds.maxY + LABEL_HUG_CLEARANCE;
|
|
5278
|
+
}
|
|
5279
|
+
return labelBounds.minY - LABEL_HUG_CLEARANCE;
|
|
5280
|
+
};
|
|
5167
5281
|
var markSelectedCandidate = (candidateResults, bestPath) => {
|
|
5168
5282
|
if (!bestPath) return;
|
|
5169
5283
|
for (const candidate of candidateResults) {
|
|
@@ -5432,16 +5546,16 @@ var Example28Solver = class extends BaseSolver {
|
|
|
5432
5546
|
// lib/solvers/AvailableNetOrientationSolver/constants.ts
|
|
5433
5547
|
var LABEL_SEARCH_STEP = 0.05;
|
|
5434
5548
|
var WICK_CLEARANCE = 1e-3;
|
|
5435
|
-
var
|
|
5436
|
-
var TRACE_BOUNDARY_TOLERANCE = WICK_CLEARANCE +
|
|
5549
|
+
var EPS7 = 1e-9;
|
|
5550
|
+
var TRACE_BOUNDARY_TOLERANCE = WICK_CLEARANCE + EPS7;
|
|
5437
5551
|
var CANDIDATE_SELECTED_COLOR2 = "blue";
|
|
5438
5552
|
var CANDIDATE_REJECTED_COLOR2 = "red";
|
|
5439
5553
|
|
|
5440
5554
|
// lib/solvers/AvailableNetOrientationSolver/geometry.ts
|
|
5441
5555
|
var isYOrientation = (orientation) => orientation === "y+" || orientation === "y-";
|
|
5442
5556
|
var isXOrientation = (orientation) => orientation === "x+" || orientation === "x-";
|
|
5443
|
-
var rectsOverlap = (a, b) => Math.min(a.maxX, b.maxX) - Math.max(a.minX, b.minX) >
|
|
5444
|
-
var rangesOverlap = (minA, maxA, minB, maxB) => Math.min(maxA, maxB) - Math.max(minA, minB) >
|
|
5557
|
+
var rectsOverlap = (a, b) => Math.min(a.maxX, b.maxX) - Math.max(a.minX, b.minX) > EPS7 && Math.min(a.maxY, b.maxY) - Math.max(a.minY, b.minY) > EPS7;
|
|
5558
|
+
var rangesOverlap = (minA, maxA, minB, maxB) => Math.min(maxA, maxB) - Math.max(minA, minB) > EPS7;
|
|
5445
5559
|
var traceCrossesBoundsInterior = (bounds, traceMap) => {
|
|
5446
5560
|
for (const trace of Object.values(traceMap)) {
|
|
5447
5561
|
const points = trace.tracePath;
|
|
@@ -5463,8 +5577,8 @@ var segmentCrossesBoundsInterior = (p1, p2, bounds) => {
|
|
|
5463
5577
|
if (interiorBounds.minX >= interiorBounds.maxX || interiorBounds.minY >= interiorBounds.maxY) {
|
|
5464
5578
|
return false;
|
|
5465
5579
|
}
|
|
5466
|
-
if (
|
|
5467
|
-
if (p1.x <= interiorBounds.minX +
|
|
5580
|
+
if (sameX2(p1, p2)) {
|
|
5581
|
+
if (p1.x <= interiorBounds.minX + EPS7 || p1.x >= interiorBounds.maxX - EPS7) {
|
|
5468
5582
|
return false;
|
|
5469
5583
|
}
|
|
5470
5584
|
return rangesOverlap(
|
|
@@ -5474,8 +5588,8 @@ var segmentCrossesBoundsInterior = (p1, p2, bounds) => {
|
|
|
5474
5588
|
interiorBounds.maxY
|
|
5475
5589
|
);
|
|
5476
5590
|
}
|
|
5477
|
-
if (
|
|
5478
|
-
if (p1.y <= interiorBounds.minY +
|
|
5591
|
+
if (sameY2(p1, p2)) {
|
|
5592
|
+
if (p1.y <= interiorBounds.minY + EPS7 || p1.y >= interiorBounds.maxY - EPS7) {
|
|
5479
5593
|
return false;
|
|
5480
5594
|
}
|
|
5481
5595
|
return rangesOverlap(
|
|
@@ -5487,6 +5601,14 @@ var segmentCrossesBoundsInterior = (p1, p2, bounds) => {
|
|
|
5487
5601
|
}
|
|
5488
5602
|
return false;
|
|
5489
5603
|
};
|
|
5604
|
+
var tracePathCrossesAnyBounds = (tracePath, bounds) => {
|
|
5605
|
+
for (let i = 0; i < tracePath.length - 1; i++) {
|
|
5606
|
+
if (segmentCrossesBoundsInterior(tracePath[i], tracePath[i + 1], bounds)) {
|
|
5607
|
+
return true;
|
|
5608
|
+
}
|
|
5609
|
+
}
|
|
5610
|
+
return false;
|
|
5611
|
+
};
|
|
5490
5612
|
var tracePathCrossesAnyTrace = (tracePath, traceMap) => {
|
|
5491
5613
|
for (const trace of Object.values(traceMap)) {
|
|
5492
5614
|
const points = trace.tracePath;
|
|
@@ -5506,11 +5628,11 @@ var tracePathCrossesAnyTrace = (tracePath, traceMap) => {
|
|
|
5506
5628
|
return false;
|
|
5507
5629
|
};
|
|
5508
5630
|
var segmentsStrictlyCross = (a1, a2, b1, b2) => {
|
|
5509
|
-
if (
|
|
5510
|
-
return a1.x > Math.min(b1.x, b2.x) +
|
|
5631
|
+
if (sameX2(a1, a2) && sameY2(b1, b2)) {
|
|
5632
|
+
return a1.x > Math.min(b1.x, b2.x) + EPS7 && a1.x < Math.max(b1.x, b2.x) - EPS7 && b1.y > Math.min(a1.y, a2.y) + EPS7 && b1.y < Math.max(a1.y, a2.y) - EPS7;
|
|
5511
5633
|
}
|
|
5512
|
-
if (
|
|
5513
|
-
return b1.x > Math.min(a1.x, a2.x) +
|
|
5634
|
+
if (sameY2(a1, a2) && sameX2(b1, b2)) {
|
|
5635
|
+
return b1.x > Math.min(a1.x, a2.x) + EPS7 && b1.x < Math.max(a1.x, a2.x) - EPS7 && a1.y > Math.min(b1.y, b2.y) + EPS7 && a1.y < Math.max(b1.y, b2.y) - EPS7;
|
|
5514
5636
|
}
|
|
5515
5637
|
return false;
|
|
5516
5638
|
};
|
|
@@ -5533,7 +5655,7 @@ var simplifyOrthogonalPath = (path) => {
|
|
|
5533
5655
|
const prev = simplified[simplified.length - 1];
|
|
5534
5656
|
const point = deduped[i];
|
|
5535
5657
|
const next = deduped[i + 1];
|
|
5536
|
-
if (
|
|
5658
|
+
if (sameX2(prev, point) && sameX2(point, next) || sameY2(prev, point) && sameY2(point, next)) {
|
|
5537
5659
|
continue;
|
|
5538
5660
|
}
|
|
5539
5661
|
simplified.push(point);
|
|
@@ -5541,9 +5663,9 @@ var simplifyOrthogonalPath = (path) => {
|
|
|
5541
5663
|
simplified.push(deduped[deduped.length - 1]);
|
|
5542
5664
|
return simplified;
|
|
5543
5665
|
};
|
|
5544
|
-
var pointsEqual = (a, b) =>
|
|
5545
|
-
var
|
|
5546
|
-
var
|
|
5666
|
+
var pointsEqual = (a, b) => sameX2(a, b) && sameY2(a, b);
|
|
5667
|
+
var sameX2 = (a, b) => Math.abs(a.x - b.x) <= EPS7;
|
|
5668
|
+
var sameY2 = (a, b) => Math.abs(a.y - b.y) <= EPS7;
|
|
5547
5669
|
var getMaxSearchDistance = (inputProblem) => {
|
|
5548
5670
|
const maxChipWidth = Math.max(
|
|
5549
5671
|
...inputProblem.chips.map((chip) => chip.width),
|
|
@@ -5824,7 +5946,7 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
5824
5946
|
);
|
|
5825
5947
|
const maxSearchDistance = this.getSearchDistanceLimit(label, orientation);
|
|
5826
5948
|
const maxOutwardDistance = outwardDirection.x === 0 && outwardDirection.y === 0 ? 0 : this.maxSearchDistance;
|
|
5827
|
-
for (let outwardDistance = 0; outwardDistance <= maxOutwardDistance +
|
|
5949
|
+
for (let outwardDistance = 0; outwardDistance <= maxOutwardDistance + EPS7; outwardDistance += LABEL_SEARCH_STEP) {
|
|
5828
5950
|
const baseAnchor = {
|
|
5829
5951
|
x: initialBaseAnchor.x + outwardDirection.x * outwardDistance,
|
|
5830
5952
|
y: initialBaseAnchor.y + outwardDirection.y * outwardDistance
|
|
@@ -5852,7 +5974,7 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
5852
5974
|
maxSearchDistance,
|
|
5853
5975
|
outwardDistance
|
|
5854
5976
|
} = params;
|
|
5855
|
-
for (let distance3 = LABEL_SEARCH_STEP; distance3 <= maxSearchDistance +
|
|
5977
|
+
for (let distance3 = LABEL_SEARCH_STEP; distance3 <= maxSearchDistance + EPS7; distance3 += LABEL_SEARCH_STEP) {
|
|
5856
5978
|
const anchorPoint = {
|
|
5857
5979
|
x: baseAnchor.x + direction.x * distance3,
|
|
5858
5980
|
y: baseAnchor.y + direction.y * distance3
|
|
@@ -5957,9 +6079,22 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
5957
6079
|
};
|
|
5958
6080
|
}
|
|
5959
6081
|
getNetLabelWidth(label) {
|
|
5960
|
-
if (
|
|
6082
|
+
if (label.netId) {
|
|
6083
|
+
const ncWidth = this.inputProblem.netConnections.find(
|
|
6084
|
+
(connection) => connection.netId === label.netId
|
|
6085
|
+
)?.netLabelWidth;
|
|
6086
|
+
if (ncWidth !== void 0) return ncWidth;
|
|
6087
|
+
const dcWidthByNetId = this.inputProblem.directConnections.find(
|
|
6088
|
+
(dc) => dc.netId === label.netId
|
|
6089
|
+
)?.netLabelWidth;
|
|
6090
|
+
if (dcWidthByNetId !== void 0) return dcWidthByNetId;
|
|
6091
|
+
}
|
|
6092
|
+
const dcWidthByPinId = this.inputProblem.directConnections.find(
|
|
6093
|
+
(dc) => dc.pinIds.some((pid) => label.pinIds.includes(pid))
|
|
6094
|
+
)?.netLabelWidth;
|
|
6095
|
+
if (dcWidthByPinId !== void 0) return dcWidthByPinId;
|
|
5961
6096
|
return this.inputProblem.netConnections.find(
|
|
5962
|
-
(
|
|
6097
|
+
(nc) => nc.pinIds.some((pid) => label.pinIds.includes(pid))
|
|
5963
6098
|
)?.netLabelWidth;
|
|
5964
6099
|
}
|
|
5965
6100
|
getCandidateStatus(candidate, label, labelIndex) {
|
|
@@ -5968,16 +6103,24 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
5968
6103
|
labelIndex
|
|
5969
6104
|
);
|
|
5970
6105
|
if (boundsStatus !== "valid") return boundsStatus;
|
|
5971
|
-
|
|
5972
|
-
|
|
5973
|
-
|
|
5974
|
-
|
|
5975
|
-
|
|
5976
|
-
|
|
5977
|
-
this.traceMap
|
|
5978
|
-
)) {
|
|
6106
|
+
const connectorTrace = getConnectorTracePath(
|
|
6107
|
+
label.anchorPoint,
|
|
6108
|
+
candidate.anchorPoint,
|
|
6109
|
+
candidate.orientation
|
|
6110
|
+
);
|
|
6111
|
+
if (tracePathCrossesAnyTrace(connectorTrace, this.traceMap)) {
|
|
5979
6112
|
return "trace-collision";
|
|
5980
6113
|
}
|
|
6114
|
+
for (let i = 0; i < this.outputNetLabelPlacements.length; i++) {
|
|
6115
|
+
if (i === labelIndex) continue;
|
|
6116
|
+
const otherLabel = this.outputNetLabelPlacements[i];
|
|
6117
|
+
if (tracePathCrossesAnyBounds(
|
|
6118
|
+
connectorTrace,
|
|
6119
|
+
getRectBounds(otherLabel.center, otherLabel.width, otherLabel.height)
|
|
6120
|
+
)) {
|
|
6121
|
+
return "netlabel-collision";
|
|
6122
|
+
}
|
|
6123
|
+
}
|
|
5981
6124
|
return "valid";
|
|
5982
6125
|
}
|
|
5983
6126
|
getBoundsStatus(bounds, labelIndex) {
|
|
@@ -6007,8 +6150,8 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
6007
6150
|
sharesChipBoundary(bounds) {
|
|
6008
6151
|
for (const chip of this.chipObstacleSpatialIndex.chips) {
|
|
6009
6152
|
const chipBounds = chip.bounds;
|
|
6010
|
-
const adjacentToVerticalSide = Math.abs(bounds.minX - chipBounds.maxX) <= WICK_CLEARANCE +
|
|
6011
|
-
const adjacentToHorizontalSide = Math.abs(bounds.minY - chipBounds.maxY) <= WICK_CLEARANCE +
|
|
6153
|
+
const adjacentToVerticalSide = Math.abs(bounds.minX - chipBounds.maxX) <= WICK_CLEARANCE + EPS7 || Math.abs(bounds.maxX - chipBounds.minX) <= WICK_CLEARANCE + EPS7;
|
|
6154
|
+
const adjacentToHorizontalSide = Math.abs(bounds.minY - chipBounds.maxY) <= WICK_CLEARANCE + EPS7 || Math.abs(bounds.maxY - chipBounds.minY) <= WICK_CLEARANCE + EPS7;
|
|
6012
6155
|
if (adjacentToVerticalSide && rangesOverlap(
|
|
6013
6156
|
bounds.minY,
|
|
6014
6157
|
bounds.maxY,
|
|
@@ -6056,7 +6199,7 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
6056
6199
|
let nearestDistance = Number.POSITIVE_INFINITY;
|
|
6057
6200
|
for (const chip of this.chipObstacleSpatialIndex.chips) {
|
|
6058
6201
|
const bounds = chip.bounds;
|
|
6059
|
-
if (point.x < bounds.minX -
|
|
6202
|
+
if (point.x < bounds.minX - EPS7 || point.x > bounds.maxX + EPS7 || point.y < bounds.minY - EPS7 || point.y > bounds.maxY + EPS7) {
|
|
6060
6203
|
continue;
|
|
6061
6204
|
}
|
|
6062
6205
|
for (const [side, distance3] of getSideDistances(point, bounds)) {
|
|
@@ -6073,8 +6216,8 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
6073
6216
|
let nearestDistanceSq = Number.POSITIVE_INFINITY;
|
|
6074
6217
|
for (const chip of this.chipObstacleSpatialIndex.chips) {
|
|
6075
6218
|
const bounds = chip.bounds;
|
|
6076
|
-
const dx = point.x < bounds.minX -
|
|
6077
|
-
const dy = point.y < bounds.minY -
|
|
6219
|
+
const dx = point.x < bounds.minX - EPS7 ? bounds.minX - point.x : point.x > bounds.maxX + EPS7 ? point.x - bounds.maxX : 0;
|
|
6220
|
+
const dy = point.y < bounds.minY - EPS7 ? bounds.minY - point.y : point.y > bounds.maxY + EPS7 ? point.y - bounds.maxY : 0;
|
|
6078
6221
|
if (dx === 0 && dy === 0) continue;
|
|
6079
6222
|
const distanceSq = dx ** 2 + dy ** 2;
|
|
6080
6223
|
if (distanceSq >= nearestDistanceSq) continue;
|
|
@@ -6113,9 +6256,9 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
6113
6256
|
};
|
|
6114
6257
|
|
|
6115
6258
|
// lib/solvers/VccNetLabelCornerPlacementSolver/geometry.ts
|
|
6116
|
-
var
|
|
6259
|
+
var EPS8 = 1e-6;
|
|
6117
6260
|
var isTraceLine = (trace) => getUniquePinCount(trace.pinIds) >= 2;
|
|
6118
|
-
var rectsOverlap2 = (a, b) => Math.min(a.maxX, b.maxX) - Math.max(a.minX, b.minX) >
|
|
6261
|
+
var rectsOverlap2 = (a, b) => Math.min(a.maxX, b.maxX) - Math.max(a.minX, b.minX) > EPS8 && Math.min(a.maxY, b.maxY) - Math.max(a.minY, b.minY) > EPS8;
|
|
6119
6262
|
var getTraceCorners = (path) => {
|
|
6120
6263
|
const corners = [];
|
|
6121
6264
|
for (let i = 1; i < path.length - 1; i++) {
|
|
@@ -6139,11 +6282,11 @@ var getUniquePinCount = (pinIds) => new Set(pinIds).size;
|
|
|
6139
6282
|
var isTraceCorner = (a, b, c) => getSegmentOrientation2(a, b) !== getSegmentOrientation2(b, c);
|
|
6140
6283
|
var isPointOnSegment = (point, start, end) => {
|
|
6141
6284
|
if (getSegmentOrientation2(start, end) === "horizontal") {
|
|
6142
|
-
return Math.abs(point.y - start.y) <=
|
|
6285
|
+
return Math.abs(point.y - start.y) <= EPS8 && point.x >= Math.min(start.x, end.x) - EPS8 && point.x <= Math.max(start.x, end.x) + EPS8;
|
|
6143
6286
|
}
|
|
6144
|
-
return Math.abs(point.x - start.x) <=
|
|
6287
|
+
return Math.abs(point.x - start.x) <= EPS8 && point.y >= Math.min(start.y, end.y) - EPS8 && point.y <= Math.max(start.y, end.y) + EPS8;
|
|
6145
6288
|
};
|
|
6146
|
-
var getSegmentOrientation2 = (a, b) => Math.abs(a.y - b.y) <=
|
|
6289
|
+
var getSegmentOrientation2 = (a, b) => Math.abs(a.y - b.y) <= EPS8 ? "horizontal" : "vertical";
|
|
6147
6290
|
|
|
6148
6291
|
// lib/solvers/VccNetLabelCornerPlacementSolver/visualize.ts
|
|
6149
6292
|
var CANDIDATE_SELECTED_COLOR3 = "blue";
|
|
@@ -6421,11 +6564,11 @@ var VccNetLabelCornerPlacementSolver = class extends BaseSolver {
|
|
|
6421
6564
|
};
|
|
6422
6565
|
|
|
6423
6566
|
// lib/solvers/TraceAnchoredNetLabelOverlapSolver/geometry.ts
|
|
6424
|
-
var
|
|
6567
|
+
var EPS9 = 1e-6;
|
|
6425
6568
|
var TRACE_BOUNDARY_TOLERANCE2 = 1e-6;
|
|
6426
6569
|
var getLabelBounds = (label) => getRectBounds(label.center, label.width, label.height);
|
|
6427
|
-
var rectsOverlap3 = (a, b) => Math.min(a.maxX, b.maxX) - Math.max(a.minX, b.minX) >
|
|
6428
|
-
var rectsTouchOrOverlap = (a, b) => Math.min(a.maxX, b.maxX) - Math.max(a.minX, b.minX) >= -
|
|
6570
|
+
var rectsOverlap3 = (a, b) => Math.min(a.maxX, b.maxX) - Math.max(a.minX, b.minX) > EPS9 && Math.min(a.maxY, b.maxY) - Math.max(a.minY, b.minY) > EPS9;
|
|
6571
|
+
var rectsTouchOrOverlap = (a, b) => Math.min(a.maxX, b.maxX) - Math.max(a.minX, b.minX) >= -EPS9 && Math.min(a.maxY, b.maxY) - Math.max(a.minY, b.minY) >= -EPS9;
|
|
6429
6572
|
var traceCrossesBoundsInterior2 = (bounds, traces) => {
|
|
6430
6573
|
for (const trace of traces) {
|
|
6431
6574
|
const points = trace.tracePath;
|
|
@@ -6471,7 +6614,7 @@ var getPointAtTraceDistance = (trace, distance3) => {
|
|
|
6471
6614
|
const end = trace.tracePath[i + 1];
|
|
6472
6615
|
const segmentLength = getManhattanDistance(start, end);
|
|
6473
6616
|
const nextDistance = pathDistance + segmentLength;
|
|
6474
|
-
if (distance3 <= nextDistance +
|
|
6617
|
+
if (distance3 <= nextDistance + EPS9) {
|
|
6475
6618
|
const offset = Math.max(
|
|
6476
6619
|
0,
|
|
6477
6620
|
Math.min(segmentLength, distance3 - pathDistance)
|
|
@@ -6510,7 +6653,7 @@ var segmentCrossesBoundsInterior2 = (start, end, bounds) => {
|
|
|
6510
6653
|
return false;
|
|
6511
6654
|
}
|
|
6512
6655
|
if (isVertical3(start, end)) {
|
|
6513
|
-
if (start.x <= interior.minX +
|
|
6656
|
+
if (start.x <= interior.minX + EPS9 || start.x >= interior.maxX - EPS9) {
|
|
6514
6657
|
return false;
|
|
6515
6658
|
}
|
|
6516
6659
|
return rangesOverlap2(
|
|
@@ -6521,7 +6664,7 @@ var segmentCrossesBoundsInterior2 = (start, end, bounds) => {
|
|
|
6521
6664
|
);
|
|
6522
6665
|
}
|
|
6523
6666
|
if (isHorizontal2(start, end)) {
|
|
6524
|
-
if (start.y <= interior.minY +
|
|
6667
|
+
if (start.y <= interior.minY + EPS9 || start.y >= interior.maxY - EPS9) {
|
|
6525
6668
|
return false;
|
|
6526
6669
|
}
|
|
6527
6670
|
return rangesOverlap2(
|
|
@@ -6535,10 +6678,10 @@ var segmentCrossesBoundsInterior2 = (start, end, bounds) => {
|
|
|
6535
6678
|
};
|
|
6536
6679
|
var isPointOnSegment2 = (point, start, end) => {
|
|
6537
6680
|
if (isHorizontal2(start, end)) {
|
|
6538
|
-
return Math.abs(point.y - start.y) <=
|
|
6681
|
+
return Math.abs(point.y - start.y) <= EPS9 && point.x >= Math.min(start.x, end.x) - EPS9 && point.x <= Math.max(start.x, end.x) + EPS9;
|
|
6539
6682
|
}
|
|
6540
6683
|
if (isVertical3(start, end)) {
|
|
6541
|
-
return Math.abs(point.x - start.x) <=
|
|
6684
|
+
return Math.abs(point.x - start.x) <= EPS9 && point.y >= Math.min(start.y, end.y) - EPS9 && point.y <= Math.max(start.y, end.y) + EPS9;
|
|
6542
6685
|
}
|
|
6543
6686
|
return false;
|
|
6544
6687
|
};
|
|
@@ -6546,9 +6689,9 @@ var getSegmentDirection = (start, end) => ({
|
|
|
6546
6689
|
x: isVertical3(start, end) ? 0 : Math.sign(end.x - start.x),
|
|
6547
6690
|
y: isHorizontal2(start, end) ? 0 : Math.sign(end.y - start.y)
|
|
6548
6691
|
});
|
|
6549
|
-
var isHorizontal2 = (start, end) => Math.abs(start.y - end.y) <=
|
|
6550
|
-
var isVertical3 = (start, end) => Math.abs(start.x - end.x) <=
|
|
6551
|
-
var rangesOverlap2 = (minA, maxA, minB, maxB) => Math.min(maxA, maxB) - Math.max(minA, minB) >
|
|
6692
|
+
var isHorizontal2 = (start, end) => Math.abs(start.y - end.y) <= EPS9;
|
|
6693
|
+
var isVertical3 = (start, end) => Math.abs(start.x - end.x) <= EPS9;
|
|
6694
|
+
var rangesOverlap2 = (minA, maxA, minB, maxB) => Math.min(maxA, maxB) - Math.max(minA, minB) > EPS9;
|
|
6552
6695
|
var getUniquePinCount2 = (pinIds) => new Set(pinIds).size;
|
|
6553
6696
|
|
|
6554
6697
|
// lib/solvers/TraceAnchoredNetLabelOverlapSolver/candidates.ts
|
|
@@ -6603,7 +6746,7 @@ var getCandidateDistances = (traceLength, vertexDistances) => {
|
|
|
6603
6746
|
for (const distance3 of vertexDistances) {
|
|
6604
6747
|
distances.add(roundDistance(distance3));
|
|
6605
6748
|
}
|
|
6606
|
-
return [...distances].filter((distance3) => distance3 >= -
|
|
6749
|
+
return [...distances].filter((distance3) => distance3 >= -EPS9 && distance3 <= traceLength + EPS9).sort((a, b) => a - b);
|
|
6607
6750
|
};
|
|
6608
6751
|
var getOrientationsForPoint = (params) => {
|
|
6609
6752
|
const { inputProblem, label, point, orientationConstraint } = params;
|
|
@@ -6710,13 +6853,13 @@ var getOutwardOrientationOptions = (point, chipBounds) => {
|
|
|
6710
6853
|
};
|
|
6711
6854
|
var getOutwardAxisOption = (params) => {
|
|
6712
6855
|
const { value, min, max, center, positiveOrientation, negativeOrientation } = params;
|
|
6713
|
-
if (value > max +
|
|
6856
|
+
if (value > max + EPS9) {
|
|
6714
6857
|
return {
|
|
6715
6858
|
orientation: positiveOrientation,
|
|
6716
6859
|
outwardScore: 1 + value - max
|
|
6717
6860
|
};
|
|
6718
6861
|
}
|
|
6719
|
-
if (value < min -
|
|
6862
|
+
if (value < min - EPS9) {
|
|
6720
6863
|
return {
|
|
6721
6864
|
orientation: negativeOrientation,
|
|
6722
6865
|
outwardScore: 1 + min - value
|
|
@@ -6727,7 +6870,7 @@ var getOutwardAxisOption = (params) => {
|
|
|
6727
6870
|
outwardScore: getNormalizedCenterDistance(value, center, max - min)
|
|
6728
6871
|
};
|
|
6729
6872
|
};
|
|
6730
|
-
var getNormalizedCenterDistance = (value, center, span) => Math.abs(value - center) / Math.max(
|
|
6873
|
+
var getNormalizedCenterDistance = (value, center, span) => Math.abs(value - center) / Math.max(EPS9, span / 2);
|
|
6731
6874
|
var ALL_ORIENTATIONS = ["x+", "x-", "y+", "y-"];
|
|
6732
6875
|
var getFlippedOrientation = (orientation) => {
|
|
6733
6876
|
switch (orientation) {
|
|
@@ -6773,11 +6916,22 @@ var getChipBounds = (inputProblem) => {
|
|
|
6773
6916
|
};
|
|
6774
6917
|
};
|
|
6775
6918
|
var getNetLabelWidth = (inputProblem, label) => {
|
|
6776
|
-
const
|
|
6919
|
+
const ncWidthByNetId = inputProblem.netConnections.find(
|
|
6777
6920
|
(connection) => connection.netId === label.netId
|
|
6778
6921
|
)?.netLabelWidth;
|
|
6779
|
-
if (
|
|
6780
|
-
|
|
6922
|
+
if (ncWidthByNetId !== void 0) return ncWidthByNetId;
|
|
6923
|
+
const dcWidth = inputProblem.directConnections.find(
|
|
6924
|
+
(dc) => dc.pinIds.some((pid) => label.pinIds.includes(pid))
|
|
6925
|
+
)?.netLabelWidth;
|
|
6926
|
+
if (dcWidth !== void 0) return dcWidth;
|
|
6927
|
+
const ncWidthByPinId = inputProblem.netConnections.find(
|
|
6928
|
+
(nc) => nc.pinIds.some((pid) => label.pinIds.includes(pid))
|
|
6929
|
+
)?.netLabelWidth;
|
|
6930
|
+
if (ncWidthByPinId !== void 0) return ncWidthByPinId;
|
|
6931
|
+
if (label.orientation === "y+" || label.orientation === "y-") {
|
|
6932
|
+
return label.height;
|
|
6933
|
+
}
|
|
6934
|
+
return label.width;
|
|
6781
6935
|
};
|
|
6782
6936
|
var roundDistance = (distance3) => Number(distance3.toFixed(6));
|
|
6783
6937
|
var dedupeOrientations = (orientations) => [
|
|
@@ -6802,7 +6956,7 @@ var normalizeFacingDirection = (value) => {
|
|
|
6802
6956
|
var dedupeStrings = (values) => [
|
|
6803
6957
|
...new Set(values.filter((value) => value !== void 0))
|
|
6804
6958
|
];
|
|
6805
|
-
var isSamePlacement = (label, point, orientation) => Math.abs(point.x - label.anchorPoint.x) <=
|
|
6959
|
+
var isSamePlacement = (label, point, orientation) => Math.abs(point.x - label.anchorPoint.x) <= EPS9 && Math.abs(point.y - label.anchorPoint.y) <= EPS9 && orientation === label.orientation;
|
|
6806
6960
|
|
|
6807
6961
|
// lib/solvers/TraceAnchoredNetLabelOverlapSolver/visualize.ts
|
|
6808
6962
|
var CANDIDATE_SELECTED_COLOR4 = "blue";
|