@tscircuit/schematic-trace-solver 0.0.57 → 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 +266 -128
- package/lib/solvers/AvailableNetOrientationSolver/AvailableNetOrientationSolver.ts +19 -3
- 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/example35.page.tsx +4 -0
- package/site/examples/example36.page.tsx +4 -0
- package/tests/assets/example35.json +127 -0
- package/tests/assets/example36.json +124 -0
- package/tests/examples/__snapshots__/example35.snap.svg +177 -0
- package/tests/examples/__snapshots__/example36.snap.svg +160 -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(
|
|
@@ -5514,11 +5628,11 @@ var tracePathCrossesAnyTrace = (tracePath, traceMap) => {
|
|
|
5514
5628
|
return false;
|
|
5515
5629
|
};
|
|
5516
5630
|
var segmentsStrictlyCross = (a1, a2, b1, b2) => {
|
|
5517
|
-
if (
|
|
5518
|
-
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;
|
|
5519
5633
|
}
|
|
5520
|
-
if (
|
|
5521
|
-
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;
|
|
5522
5636
|
}
|
|
5523
5637
|
return false;
|
|
5524
5638
|
};
|
|
@@ -5541,7 +5655,7 @@ var simplifyOrthogonalPath = (path) => {
|
|
|
5541
5655
|
const prev = simplified[simplified.length - 1];
|
|
5542
5656
|
const point = deduped[i];
|
|
5543
5657
|
const next = deduped[i + 1];
|
|
5544
|
-
if (
|
|
5658
|
+
if (sameX2(prev, point) && sameX2(point, next) || sameY2(prev, point) && sameY2(point, next)) {
|
|
5545
5659
|
continue;
|
|
5546
5660
|
}
|
|
5547
5661
|
simplified.push(point);
|
|
@@ -5549,9 +5663,9 @@ var simplifyOrthogonalPath = (path) => {
|
|
|
5549
5663
|
simplified.push(deduped[deduped.length - 1]);
|
|
5550
5664
|
return simplified;
|
|
5551
5665
|
};
|
|
5552
|
-
var pointsEqual = (a, b) =>
|
|
5553
|
-
var
|
|
5554
|
-
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;
|
|
5555
5669
|
var getMaxSearchDistance = (inputProblem) => {
|
|
5556
5670
|
const maxChipWidth = Math.max(
|
|
5557
5671
|
...inputProblem.chips.map((chip) => chip.width),
|
|
@@ -5832,7 +5946,7 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
5832
5946
|
);
|
|
5833
5947
|
const maxSearchDistance = this.getSearchDistanceLimit(label, orientation);
|
|
5834
5948
|
const maxOutwardDistance = outwardDirection.x === 0 && outwardDirection.y === 0 ? 0 : this.maxSearchDistance;
|
|
5835
|
-
for (let outwardDistance = 0; outwardDistance <= maxOutwardDistance +
|
|
5949
|
+
for (let outwardDistance = 0; outwardDistance <= maxOutwardDistance + EPS7; outwardDistance += LABEL_SEARCH_STEP) {
|
|
5836
5950
|
const baseAnchor = {
|
|
5837
5951
|
x: initialBaseAnchor.x + outwardDirection.x * outwardDistance,
|
|
5838
5952
|
y: initialBaseAnchor.y + outwardDirection.y * outwardDistance
|
|
@@ -5860,7 +5974,7 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
5860
5974
|
maxSearchDistance,
|
|
5861
5975
|
outwardDistance
|
|
5862
5976
|
} = params;
|
|
5863
|
-
for (let distance3 = LABEL_SEARCH_STEP; distance3 <= maxSearchDistance +
|
|
5977
|
+
for (let distance3 = LABEL_SEARCH_STEP; distance3 <= maxSearchDistance + EPS7; distance3 += LABEL_SEARCH_STEP) {
|
|
5864
5978
|
const anchorPoint = {
|
|
5865
5979
|
x: baseAnchor.x + direction.x * distance3,
|
|
5866
5980
|
y: baseAnchor.y + direction.y * distance3
|
|
@@ -5965,9 +6079,22 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
5965
6079
|
};
|
|
5966
6080
|
}
|
|
5967
6081
|
getNetLabelWidth(label) {
|
|
5968
|
-
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;
|
|
5969
6096
|
return this.inputProblem.netConnections.find(
|
|
5970
|
-
(
|
|
6097
|
+
(nc) => nc.pinIds.some((pid) => label.pinIds.includes(pid))
|
|
5971
6098
|
)?.netLabelWidth;
|
|
5972
6099
|
}
|
|
5973
6100
|
getCandidateStatus(candidate, label, labelIndex) {
|
|
@@ -6023,8 +6150,8 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
6023
6150
|
sharesChipBoundary(bounds) {
|
|
6024
6151
|
for (const chip of this.chipObstacleSpatialIndex.chips) {
|
|
6025
6152
|
const chipBounds = chip.bounds;
|
|
6026
|
-
const adjacentToVerticalSide = Math.abs(bounds.minX - chipBounds.maxX) <= WICK_CLEARANCE +
|
|
6027
|
-
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;
|
|
6028
6155
|
if (adjacentToVerticalSide && rangesOverlap(
|
|
6029
6156
|
bounds.minY,
|
|
6030
6157
|
bounds.maxY,
|
|
@@ -6072,7 +6199,7 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
6072
6199
|
let nearestDistance = Number.POSITIVE_INFINITY;
|
|
6073
6200
|
for (const chip of this.chipObstacleSpatialIndex.chips) {
|
|
6074
6201
|
const bounds = chip.bounds;
|
|
6075
|
-
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) {
|
|
6076
6203
|
continue;
|
|
6077
6204
|
}
|
|
6078
6205
|
for (const [side, distance3] of getSideDistances(point, bounds)) {
|
|
@@ -6089,8 +6216,8 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
6089
6216
|
let nearestDistanceSq = Number.POSITIVE_INFINITY;
|
|
6090
6217
|
for (const chip of this.chipObstacleSpatialIndex.chips) {
|
|
6091
6218
|
const bounds = chip.bounds;
|
|
6092
|
-
const dx = point.x < bounds.minX -
|
|
6093
|
-
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;
|
|
6094
6221
|
if (dx === 0 && dy === 0) continue;
|
|
6095
6222
|
const distanceSq = dx ** 2 + dy ** 2;
|
|
6096
6223
|
if (distanceSq >= nearestDistanceSq) continue;
|
|
@@ -6129,9 +6256,9 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
6129
6256
|
};
|
|
6130
6257
|
|
|
6131
6258
|
// lib/solvers/VccNetLabelCornerPlacementSolver/geometry.ts
|
|
6132
|
-
var
|
|
6259
|
+
var EPS8 = 1e-6;
|
|
6133
6260
|
var isTraceLine = (trace) => getUniquePinCount(trace.pinIds) >= 2;
|
|
6134
|
-
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;
|
|
6135
6262
|
var getTraceCorners = (path) => {
|
|
6136
6263
|
const corners = [];
|
|
6137
6264
|
for (let i = 1; i < path.length - 1; i++) {
|
|
@@ -6155,11 +6282,11 @@ var getUniquePinCount = (pinIds) => new Set(pinIds).size;
|
|
|
6155
6282
|
var isTraceCorner = (a, b, c) => getSegmentOrientation2(a, b) !== getSegmentOrientation2(b, c);
|
|
6156
6283
|
var isPointOnSegment = (point, start, end) => {
|
|
6157
6284
|
if (getSegmentOrientation2(start, end) === "horizontal") {
|
|
6158
|
-
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;
|
|
6159
6286
|
}
|
|
6160
|
-
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;
|
|
6161
6288
|
};
|
|
6162
|
-
var getSegmentOrientation2 = (a, b) => Math.abs(a.y - b.y) <=
|
|
6289
|
+
var getSegmentOrientation2 = (a, b) => Math.abs(a.y - b.y) <= EPS8 ? "horizontal" : "vertical";
|
|
6163
6290
|
|
|
6164
6291
|
// lib/solvers/VccNetLabelCornerPlacementSolver/visualize.ts
|
|
6165
6292
|
var CANDIDATE_SELECTED_COLOR3 = "blue";
|
|
@@ -6437,11 +6564,11 @@ var VccNetLabelCornerPlacementSolver = class extends BaseSolver {
|
|
|
6437
6564
|
};
|
|
6438
6565
|
|
|
6439
6566
|
// lib/solvers/TraceAnchoredNetLabelOverlapSolver/geometry.ts
|
|
6440
|
-
var
|
|
6567
|
+
var EPS9 = 1e-6;
|
|
6441
6568
|
var TRACE_BOUNDARY_TOLERANCE2 = 1e-6;
|
|
6442
6569
|
var getLabelBounds = (label) => getRectBounds(label.center, label.width, label.height);
|
|
6443
|
-
var rectsOverlap3 = (a, b) => Math.min(a.maxX, b.maxX) - Math.max(a.minX, b.minX) >
|
|
6444
|
-
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;
|
|
6445
6572
|
var traceCrossesBoundsInterior2 = (bounds, traces) => {
|
|
6446
6573
|
for (const trace of traces) {
|
|
6447
6574
|
const points = trace.tracePath;
|
|
@@ -6487,7 +6614,7 @@ var getPointAtTraceDistance = (trace, distance3) => {
|
|
|
6487
6614
|
const end = trace.tracePath[i + 1];
|
|
6488
6615
|
const segmentLength = getManhattanDistance(start, end);
|
|
6489
6616
|
const nextDistance = pathDistance + segmentLength;
|
|
6490
|
-
if (distance3 <= nextDistance +
|
|
6617
|
+
if (distance3 <= nextDistance + EPS9) {
|
|
6491
6618
|
const offset = Math.max(
|
|
6492
6619
|
0,
|
|
6493
6620
|
Math.min(segmentLength, distance3 - pathDistance)
|
|
@@ -6526,7 +6653,7 @@ var segmentCrossesBoundsInterior2 = (start, end, bounds) => {
|
|
|
6526
6653
|
return false;
|
|
6527
6654
|
}
|
|
6528
6655
|
if (isVertical3(start, end)) {
|
|
6529
|
-
if (start.x <= interior.minX +
|
|
6656
|
+
if (start.x <= interior.minX + EPS9 || start.x >= interior.maxX - EPS9) {
|
|
6530
6657
|
return false;
|
|
6531
6658
|
}
|
|
6532
6659
|
return rangesOverlap2(
|
|
@@ -6537,7 +6664,7 @@ var segmentCrossesBoundsInterior2 = (start, end, bounds) => {
|
|
|
6537
6664
|
);
|
|
6538
6665
|
}
|
|
6539
6666
|
if (isHorizontal2(start, end)) {
|
|
6540
|
-
if (start.y <= interior.minY +
|
|
6667
|
+
if (start.y <= interior.minY + EPS9 || start.y >= interior.maxY - EPS9) {
|
|
6541
6668
|
return false;
|
|
6542
6669
|
}
|
|
6543
6670
|
return rangesOverlap2(
|
|
@@ -6551,10 +6678,10 @@ var segmentCrossesBoundsInterior2 = (start, end, bounds) => {
|
|
|
6551
6678
|
};
|
|
6552
6679
|
var isPointOnSegment2 = (point, start, end) => {
|
|
6553
6680
|
if (isHorizontal2(start, end)) {
|
|
6554
|
-
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;
|
|
6555
6682
|
}
|
|
6556
6683
|
if (isVertical3(start, end)) {
|
|
6557
|
-
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;
|
|
6558
6685
|
}
|
|
6559
6686
|
return false;
|
|
6560
6687
|
};
|
|
@@ -6562,9 +6689,9 @@ var getSegmentDirection = (start, end) => ({
|
|
|
6562
6689
|
x: isVertical3(start, end) ? 0 : Math.sign(end.x - start.x),
|
|
6563
6690
|
y: isHorizontal2(start, end) ? 0 : Math.sign(end.y - start.y)
|
|
6564
6691
|
});
|
|
6565
|
-
var isHorizontal2 = (start, end) => Math.abs(start.y - end.y) <=
|
|
6566
|
-
var isVertical3 = (start, end) => Math.abs(start.x - end.x) <=
|
|
6567
|
-
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;
|
|
6568
6695
|
var getUniquePinCount2 = (pinIds) => new Set(pinIds).size;
|
|
6569
6696
|
|
|
6570
6697
|
// lib/solvers/TraceAnchoredNetLabelOverlapSolver/candidates.ts
|
|
@@ -6619,7 +6746,7 @@ var getCandidateDistances = (traceLength, vertexDistances) => {
|
|
|
6619
6746
|
for (const distance3 of vertexDistances) {
|
|
6620
6747
|
distances.add(roundDistance(distance3));
|
|
6621
6748
|
}
|
|
6622
|
-
return [...distances].filter((distance3) => distance3 >= -
|
|
6749
|
+
return [...distances].filter((distance3) => distance3 >= -EPS9 && distance3 <= traceLength + EPS9).sort((a, b) => a - b);
|
|
6623
6750
|
};
|
|
6624
6751
|
var getOrientationsForPoint = (params) => {
|
|
6625
6752
|
const { inputProblem, label, point, orientationConstraint } = params;
|
|
@@ -6726,13 +6853,13 @@ var getOutwardOrientationOptions = (point, chipBounds) => {
|
|
|
6726
6853
|
};
|
|
6727
6854
|
var getOutwardAxisOption = (params) => {
|
|
6728
6855
|
const { value, min, max, center, positiveOrientation, negativeOrientation } = params;
|
|
6729
|
-
if (value > max +
|
|
6856
|
+
if (value > max + EPS9) {
|
|
6730
6857
|
return {
|
|
6731
6858
|
orientation: positiveOrientation,
|
|
6732
6859
|
outwardScore: 1 + value - max
|
|
6733
6860
|
};
|
|
6734
6861
|
}
|
|
6735
|
-
if (value < min -
|
|
6862
|
+
if (value < min - EPS9) {
|
|
6736
6863
|
return {
|
|
6737
6864
|
orientation: negativeOrientation,
|
|
6738
6865
|
outwardScore: 1 + min - value
|
|
@@ -6743,7 +6870,7 @@ var getOutwardAxisOption = (params) => {
|
|
|
6743
6870
|
outwardScore: getNormalizedCenterDistance(value, center, max - min)
|
|
6744
6871
|
};
|
|
6745
6872
|
};
|
|
6746
|
-
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);
|
|
6747
6874
|
var ALL_ORIENTATIONS = ["x+", "x-", "y+", "y-"];
|
|
6748
6875
|
var getFlippedOrientation = (orientation) => {
|
|
6749
6876
|
switch (orientation) {
|
|
@@ -6789,11 +6916,22 @@ var getChipBounds = (inputProblem) => {
|
|
|
6789
6916
|
};
|
|
6790
6917
|
};
|
|
6791
6918
|
var getNetLabelWidth = (inputProblem, label) => {
|
|
6792
|
-
const
|
|
6919
|
+
const ncWidthByNetId = inputProblem.netConnections.find(
|
|
6793
6920
|
(connection) => connection.netId === label.netId
|
|
6794
6921
|
)?.netLabelWidth;
|
|
6795
|
-
if (
|
|
6796
|
-
|
|
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;
|
|
6797
6935
|
};
|
|
6798
6936
|
var roundDistance = (distance3) => Number(distance3.toFixed(6));
|
|
6799
6937
|
var dedupeOrientations = (orientations) => [
|
|
@@ -6818,7 +6956,7 @@ var normalizeFacingDirection = (value) => {
|
|
|
6818
6956
|
var dedupeStrings = (values) => [
|
|
6819
6957
|
...new Set(values.filter((value) => value !== void 0))
|
|
6820
6958
|
];
|
|
6821
|
-
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;
|
|
6822
6960
|
|
|
6823
6961
|
// lib/solvers/TraceAnchoredNetLabelOverlapSolver/visualize.ts
|
|
6824
6962
|
var CANDIDATE_SELECTED_COLOR4 = "blue";
|