@tscircuit/schematic-trace-solver 0.0.64 → 0.0.66
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 +10 -0
- package/dist/index.js +254 -115
- package/lib/solvers/NetLabelPlacementSolver/NetLabelPlacementSolver.ts +8 -2
- package/lib/solvers/TraceLabelOverlapAvoidanceSolver/TraceLabelOverlapAvoidanceSolver.ts +6 -0
- package/lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/OverlapAvoidanceStepSolver/OverlapAvoidanceStepSolver.ts +6 -0
- package/lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/SingleOverlapSolver/SingleOverlapSolver.ts +68 -1
- package/lib/solvers/TraceOverlapShiftSolver/TraceOverlapIssueSolver/TraceOverlapIssueSolver.ts +109 -5
- package/lib/solvers/TraceOverlapShiftSolver/TraceOverlapIssueSolver/applyJogToTrace.ts +30 -0
- package/lib/solvers/TraceOverlapShiftSolver/TraceOverlapShiftSolver.ts +1 -0
- package/package.json +1 -1
- package/tests/examples/__snapshots__/example27.snap.svg +86 -78
- package/tests/examples/__snapshots__/example37.snap.svg +60 -156
- package/tests/examples/__snapshots__/example40.snap.svg +103 -63
- package/tests/repros/__snapshots__/repro130-bq27441-fuel-gauge-trace-through-c1.snap.svg +460 -0
- package/tests/repros/__snapshots__/trace-overlap-box-resistor.snap.svg +3 -3
- package/tests/repros/assets/repro130-bq27441-fuel-gauge.input.json +350 -0
- package/tests/repros/repro130-bq27441-fuel-gauge-trace-through-c1.test.ts +60 -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 EPS11 = 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) < -EPS11) 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) < -EPS11) 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) < EPS11 || Math.abs(p1.y - p2.y) < EPS11) {
|
|
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 EPS11 = 1e-9;
|
|
854
|
+
const samePoint = (p, q) => Math.abs(p.x - q.x) < EPS11 && Math.abs(p.y - q.y) < EPS11;
|
|
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,15 +1050,41 @@ var applyJogToTerminalSegment = ({
|
|
|
1050
1050
|
segmentIndex: si,
|
|
1051
1051
|
offset,
|
|
1052
1052
|
JOG_SIZE,
|
|
1053
|
-
EPS:
|
|
1053
|
+
EPS: EPS11 = 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) < EPS11;
|
|
1059
|
+
const isHorizontal3 = Math.abs(start.y - end.y) < EPS11;
|
|
1060
1060
|
if (!isVertical4 && !isHorizontal3) return;
|
|
1061
1061
|
const segDir = isVertical4 ? end.y > start.y ? 1 : -1 : end.x > start.x ? 1 : -1;
|
|
1062
|
+
if (pts.length === 2) {
|
|
1063
|
+
if (isVertical4) {
|
|
1064
|
+
const jogYNearStart = start.y + segDir * JOG_SIZE;
|
|
1065
|
+
const jogYNearEnd = end.y - segDir * JOG_SIZE;
|
|
1066
|
+
pts.splice(
|
|
1067
|
+
1,
|
|
1068
|
+
0,
|
|
1069
|
+
{ x: start.x, y: jogYNearStart },
|
|
1070
|
+
{ x: start.x + offset, y: jogYNearStart },
|
|
1071
|
+
{ x: end.x + offset, y: jogYNearEnd },
|
|
1072
|
+
{ x: end.x, y: jogYNearEnd }
|
|
1073
|
+
);
|
|
1074
|
+
} else {
|
|
1075
|
+
const jogXNearStart = start.x + segDir * JOG_SIZE;
|
|
1076
|
+
const jogXNearEnd = end.x - segDir * JOG_SIZE;
|
|
1077
|
+
pts.splice(
|
|
1078
|
+
1,
|
|
1079
|
+
0,
|
|
1080
|
+
{ x: jogXNearStart, y: start.y },
|
|
1081
|
+
{ x: jogXNearStart, y: start.y + offset },
|
|
1082
|
+
{ x: jogXNearEnd, y: end.y + offset },
|
|
1083
|
+
{ x: jogXNearEnd, y: end.y }
|
|
1084
|
+
);
|
|
1085
|
+
}
|
|
1086
|
+
return;
|
|
1087
|
+
}
|
|
1062
1088
|
if (si === 0) {
|
|
1063
1089
|
if (isVertical4) {
|
|
1064
1090
|
const jogY = start.y + segDir * JOG_SIZE;
|
|
@@ -1103,15 +1129,18 @@ var applyJogToTerminalSegment = ({
|
|
|
1103
1129
|
};
|
|
1104
1130
|
|
|
1105
1131
|
// lib/solvers/TraceOverlapShiftSolver/TraceOverlapIssueSolver/TraceOverlapIssueSolver.ts
|
|
1132
|
+
var EPS4 = 1e-6;
|
|
1106
1133
|
var TraceOverlapIssueSolver = class extends BaseSolver {
|
|
1107
1134
|
overlappingTraceSegments;
|
|
1108
1135
|
traceNetIslands;
|
|
1136
|
+
obstacleRects;
|
|
1109
1137
|
SHIFT_DISTANCE = 0.1;
|
|
1110
1138
|
correctedTraceMap = {};
|
|
1111
1139
|
constructor(params) {
|
|
1112
1140
|
super();
|
|
1113
1141
|
this.overlappingTraceSegments = params.overlappingTraceSegments;
|
|
1114
1142
|
this.traceNetIslands = params.traceNetIslands;
|
|
1143
|
+
this.obstacleRects = getObstacleRects(params.inputProblem);
|
|
1115
1144
|
for (const { connNetId, pathsWithOverlap } of this.overlappingTraceSegments) {
|
|
1116
1145
|
for (const {
|
|
1117
1146
|
solvedTracePathIndex,
|
|
@@ -1123,16 +1152,30 @@ var TraceOverlapIssueSolver = class extends BaseSolver {
|
|
|
1123
1152
|
}
|
|
1124
1153
|
}
|
|
1125
1154
|
_step() {
|
|
1126
|
-
const
|
|
1127
|
-
|
|
1155
|
+
const containsStraightPinToPinTrace = (group) => group.pathsWithOverlap.some(({ solvedTracePathIndex }) => {
|
|
1156
|
+
const path = this.traceNetIslands[group.connNetId][solvedTracePathIndex];
|
|
1157
|
+
return path.tracePath.length === 2;
|
|
1158
|
+
});
|
|
1159
|
+
const groupShouldStayInPlace = this.overlappingTraceSegments.map(
|
|
1160
|
+
containsStraightPinToPinTrace
|
|
1161
|
+
);
|
|
1162
|
+
const someGroupCanShift = groupShouldStayInPlace.some(
|
|
1163
|
+
(shouldStay) => !shouldStay
|
|
1164
|
+
);
|
|
1165
|
+
const offsets = this.overlappingTraceSegments.map((group, idx) => {
|
|
1166
|
+
if (someGroupCanShift && groupShouldStayInPlace[idx]) return 0;
|
|
1128
1167
|
const n = Math.floor(idx / 2) + 1;
|
|
1129
1168
|
const signed = idx % 2 === 0 ? -n : n;
|
|
1130
|
-
return
|
|
1169
|
+
return this.getObstacleAwareOffset({
|
|
1170
|
+
group,
|
|
1171
|
+
offset: signed * this.SHIFT_DISTANCE
|
|
1172
|
+
});
|
|
1131
1173
|
});
|
|
1132
|
-
const eq = (a, b) => Math.abs(a - b) <
|
|
1174
|
+
const eq = (a, b) => Math.abs(a - b) < EPS4;
|
|
1133
1175
|
const samePoint = (p, q) => !!p && !!q && eq(p.x, q.x) && eq(p.y, q.y);
|
|
1134
1176
|
this.overlappingTraceSegments.forEach((group, gidx) => {
|
|
1135
1177
|
const offset = offsets[gidx];
|
|
1178
|
+
if (offset === 0) return;
|
|
1136
1179
|
const byPath = /* @__PURE__ */ new Map();
|
|
1137
1180
|
for (const loc of group.pathsWithOverlap) {
|
|
1138
1181
|
if (!byPath.has(loc.solvedTracePathIndex)) {
|
|
@@ -1144,7 +1187,6 @@ var TraceOverlapIssueSolver = class extends BaseSolver {
|
|
|
1144
1187
|
const original = this.traceNetIslands[group.connNetId][pathIdx];
|
|
1145
1188
|
const current = this.correctedTraceMap[original.mspPairId] ?? original;
|
|
1146
1189
|
const pts = current.tracePath.map((p) => ({ ...p }));
|
|
1147
|
-
const segIdxs = Array.from(segIdxSet).sort((a, b) => a - b);
|
|
1148
1190
|
const segIdxsRev = Array.from(segIdxSet).sort((a, b) => a - b).reverse();
|
|
1149
1191
|
const JOG_SIZE = this.SHIFT_DISTANCE;
|
|
1150
1192
|
for (const si of segIdxsRev) {
|
|
@@ -1155,13 +1197,13 @@ var TraceOverlapIssueSolver = class extends BaseSolver {
|
|
|
1155
1197
|
segmentIndex: si,
|
|
1156
1198
|
offset,
|
|
1157
1199
|
JOG_SIZE,
|
|
1158
|
-
EPS:
|
|
1200
|
+
EPS: EPS4
|
|
1159
1201
|
});
|
|
1160
1202
|
} else {
|
|
1161
1203
|
const start = pts[si];
|
|
1162
1204
|
const end = pts[si + 1];
|
|
1163
|
-
const isVertical4 = Math.abs(start.x - end.x) <
|
|
1164
|
-
const isHorizontal3 = Math.abs(start.y - end.y) <
|
|
1205
|
+
const isVertical4 = Math.abs(start.x - end.x) < EPS4;
|
|
1206
|
+
const isHorizontal3 = Math.abs(start.y - end.y) < EPS4;
|
|
1165
1207
|
if (!isVertical4 && !isHorizontal3) continue;
|
|
1166
1208
|
if (isVertical4) {
|
|
1167
1209
|
start.x += offset;
|
|
@@ -1186,6 +1228,53 @@ var TraceOverlapIssueSolver = class extends BaseSolver {
|
|
|
1186
1228
|
});
|
|
1187
1229
|
this.solved = true;
|
|
1188
1230
|
}
|
|
1231
|
+
getObstacleAwareOffset({
|
|
1232
|
+
group,
|
|
1233
|
+
offset
|
|
1234
|
+
}) {
|
|
1235
|
+
const blockingCollisions = this.getBlockingCollisions({ group, offset });
|
|
1236
|
+
if (blockingCollisions.length === 0) return offset;
|
|
1237
|
+
return blockingCollisions.flatMap(({ start, isVertical: isVertical4, obstacle }) => [
|
|
1238
|
+
(isVertical4 ? obstacle.minX - start.x : obstacle.minY - start.y) - this.SHIFT_DISTANCE,
|
|
1239
|
+
(isVertical4 ? obstacle.maxX - start.x : obstacle.maxY - start.y) + this.SHIFT_DISTANCE
|
|
1240
|
+
]).filter(
|
|
1241
|
+
(candidateOffset) => this.getBlockingCollisions({ group, offset: candidateOffset }).length === 0
|
|
1242
|
+
).sort((a, b) => Math.abs(a - offset) - Math.abs(b - offset))[0] ?? offset;
|
|
1243
|
+
}
|
|
1244
|
+
getBlockingCollisions({
|
|
1245
|
+
group,
|
|
1246
|
+
offset
|
|
1247
|
+
}) {
|
|
1248
|
+
const blockingCollisions = [];
|
|
1249
|
+
for (const {
|
|
1250
|
+
solvedTracePathIndex,
|
|
1251
|
+
traceSegmentIndex
|
|
1252
|
+
} of group.pathsWithOverlap) {
|
|
1253
|
+
const trace = this.traceNetIslands[group.connNetId][solvedTracePathIndex];
|
|
1254
|
+
const start = trace.tracePath[traceSegmentIndex];
|
|
1255
|
+
const end = trace.tracePath[traceSegmentIndex + 1];
|
|
1256
|
+
if (!start || !end) continue;
|
|
1257
|
+
const isVertical4 = Math.abs(start.x - end.x) < EPS4;
|
|
1258
|
+
const isHorizontal3 = Math.abs(start.y - end.y) < EPS4;
|
|
1259
|
+
if (!isVertical4 && !isHorizontal3) continue;
|
|
1260
|
+
const shiftedSegment = isVertical4 ? [
|
|
1261
|
+
{ ...start, x: start.x + offset },
|
|
1262
|
+
{ ...end, x: end.x + offset }
|
|
1263
|
+
] : [
|
|
1264
|
+
{ ...start, y: start.y + offset },
|
|
1265
|
+
{ ...end, y: end.y + offset }
|
|
1266
|
+
];
|
|
1267
|
+
const collision = findFirstCollision(shiftedSegment, this.obstacleRects);
|
|
1268
|
+
if (collision) {
|
|
1269
|
+
blockingCollisions.push({
|
|
1270
|
+
start,
|
|
1271
|
+
isVertical: isVertical4,
|
|
1272
|
+
obstacle: collision.rect
|
|
1273
|
+
});
|
|
1274
|
+
}
|
|
1275
|
+
}
|
|
1276
|
+
return blockingCollisions;
|
|
1277
|
+
}
|
|
1189
1278
|
visualize() {
|
|
1190
1279
|
const graphics = {
|
|
1191
1280
|
lines: [],
|
|
@@ -1258,7 +1347,7 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
|
|
|
1258
1347
|
return islands;
|
|
1259
1348
|
}
|
|
1260
1349
|
findNextOverlapIssue() {
|
|
1261
|
-
const
|
|
1350
|
+
const EPS11 = 2e-3;
|
|
1262
1351
|
const netIds = Object.keys(this.traceNetIslands);
|
|
1263
1352
|
for (let i = 0; i < netIds.length; i++) {
|
|
1264
1353
|
for (let j = i + 1; j < netIds.length; j++) {
|
|
@@ -1276,7 +1365,7 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
|
|
|
1276
1365
|
const minB = Math.min(b1, b2);
|
|
1277
1366
|
const maxB = Math.max(b1, b2);
|
|
1278
1367
|
const overlap = Math.min(maxA, maxB) - Math.max(minA, minB);
|
|
1279
|
-
return overlap >
|
|
1368
|
+
return overlap > EPS11;
|
|
1280
1369
|
};
|
|
1281
1370
|
for (let pa = 0; pa < pathsA.length; pa++) {
|
|
1282
1371
|
const pathA = pathsA[pa];
|
|
@@ -1284,8 +1373,8 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
|
|
|
1284
1373
|
for (let sa = 0; sa < ptsA.length - 1; sa++) {
|
|
1285
1374
|
const a1 = ptsA[sa];
|
|
1286
1375
|
const a2 = ptsA[sa + 1];
|
|
1287
|
-
const aVert = Math.abs(a1.x - a2.x) <
|
|
1288
|
-
const aHorz = Math.abs(a1.y - a2.y) <
|
|
1376
|
+
const aVert = Math.abs(a1.x - a2.x) < EPS11;
|
|
1377
|
+
const aHorz = Math.abs(a1.y - a2.y) < EPS11;
|
|
1289
1378
|
if (!aVert && !aHorz) continue;
|
|
1290
1379
|
for (let pb = 0; pb < pathsB.length; pb++) {
|
|
1291
1380
|
const pathB = pathsB[pb];
|
|
@@ -1293,11 +1382,11 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
|
|
|
1293
1382
|
for (let sb = 0; sb < ptsB.length - 1; sb++) {
|
|
1294
1383
|
const b1 = ptsB[sb];
|
|
1295
1384
|
const b2 = ptsB[sb + 1];
|
|
1296
|
-
const bVert = Math.abs(b1.x - b2.x) <
|
|
1297
|
-
const bHorz = Math.abs(b1.y - b2.y) <
|
|
1385
|
+
const bVert = Math.abs(b1.x - b2.x) < EPS11;
|
|
1386
|
+
const bHorz = Math.abs(b1.y - b2.y) < EPS11;
|
|
1298
1387
|
if (!bVert && !bHorz) continue;
|
|
1299
1388
|
if (aVert && bVert) {
|
|
1300
|
-
if (Math.abs(a1.x - b1.x) <
|
|
1389
|
+
if (Math.abs(a1.x - b1.x) < EPS11) {
|
|
1301
1390
|
if (overlaps1D(a1.y, a2.y, b1.y, b2.y)) {
|
|
1302
1391
|
const keyA = `${pa}:${sa}`;
|
|
1303
1392
|
const keyB = `${pb}:${sb}`;
|
|
@@ -1318,7 +1407,7 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
|
|
|
1318
1407
|
}
|
|
1319
1408
|
}
|
|
1320
1409
|
} else if (aHorz && bHorz) {
|
|
1321
|
-
if (Math.abs(a1.y - b1.y) <
|
|
1410
|
+
if (Math.abs(a1.y - b1.y) < EPS11) {
|
|
1322
1411
|
if (overlaps1D(a1.x, a2.x, b1.x, b2.x)) {
|
|
1323
1412
|
const keyA = `${pa}:${sa}`;
|
|
1324
1413
|
const keyB = `${pb}:${sb}`;
|
|
@@ -1356,14 +1445,14 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
|
|
|
1356
1445
|
return null;
|
|
1357
1446
|
}
|
|
1358
1447
|
findNextDiagonalSegment() {
|
|
1359
|
-
const
|
|
1448
|
+
const EPS11 = 2e-3;
|
|
1360
1449
|
for (const mspPairId in this.correctedTraceMap) {
|
|
1361
1450
|
const tracePath = this.correctedTraceMap[mspPairId].tracePath;
|
|
1362
1451
|
for (let i = 0; i < tracePath.length - 1; i++) {
|
|
1363
1452
|
const p1 = tracePath[i];
|
|
1364
1453
|
const p2 = tracePath[i + 1];
|
|
1365
|
-
const isHorizontal3 = Math.abs(p1.y - p2.y) <
|
|
1366
|
-
const isVertical4 = Math.abs(p1.x - p2.x) <
|
|
1454
|
+
const isHorizontal3 = Math.abs(p1.y - p2.y) < EPS11;
|
|
1455
|
+
const isVertical4 = Math.abs(p1.x - p2.x) < EPS11;
|
|
1367
1456
|
if (!isHorizontal3 && !isVertical4) {
|
|
1368
1457
|
return { mspPairId, tracePath, i, p1, p2 };
|
|
1369
1458
|
}
|
|
@@ -1377,13 +1466,13 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
|
|
|
1377
1466
|
return false;
|
|
1378
1467
|
}
|
|
1379
1468
|
const { mspPairId, tracePath, i, p1, p2 } = diagonalInfo;
|
|
1380
|
-
const
|
|
1469
|
+
const EPS11 = 2e-3;
|
|
1381
1470
|
const p0 = i > 0 ? tracePath[i - 1] : null;
|
|
1382
1471
|
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) <
|
|
1472
|
+
const prevIsVertical = p0 ? Math.abs(p0.x - p1.x) < EPS11 : false;
|
|
1473
|
+
const prevIsHorizontal = p0 ? Math.abs(p0.y - p1.y) < EPS11 : false;
|
|
1474
|
+
const nextIsVertical = p3 ? Math.abs(p2.x - p3.x) < EPS11 : false;
|
|
1475
|
+
const nextIsHorizontal = p3 ? Math.abs(p2.y - p3.y) < EPS11 : false;
|
|
1387
1476
|
const elbow1 = { x: p1.x, y: p2.y };
|
|
1388
1477
|
const elbow2 = { x: p2.x, y: p1.y };
|
|
1389
1478
|
let score1 = 0;
|
|
@@ -1428,6 +1517,7 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
|
|
|
1428
1517
|
}
|
|
1429
1518
|
const { overlappingTraceSegments } = overlapIssue;
|
|
1430
1519
|
this.activeSubSolver = new TraceOverlapIssueSolver({
|
|
1520
|
+
inputProblem: this.inputProblem,
|
|
1431
1521
|
overlappingTraceSegments,
|
|
1432
1522
|
traceNetIslands: this.traceNetIslands
|
|
1433
1523
|
});
|
|
@@ -1548,24 +1638,24 @@ function getRectBounds(center, w, h) {
|
|
|
1548
1638
|
}
|
|
1549
1639
|
|
|
1550
1640
|
// lib/solvers/NetLabelPlacementSolver/SingleNetLabelPlacementSolver/collisions.ts
|
|
1551
|
-
function segmentIntersectsRect2(p1, p2, rect,
|
|
1552
|
-
const isVert = Math.abs(p1.x - p2.x) <
|
|
1553
|
-
const isHorz = Math.abs(p1.y - p2.y) <
|
|
1641
|
+
function segmentIntersectsRect2(p1, p2, rect, EPS11 = 1e-9) {
|
|
1642
|
+
const isVert = Math.abs(p1.x - p2.x) < EPS11;
|
|
1643
|
+
const isHorz = Math.abs(p1.y - p2.y) < EPS11;
|
|
1554
1644
|
if (!isVert && !isHorz) return false;
|
|
1555
1645
|
if (isVert) {
|
|
1556
1646
|
const x = p1.x;
|
|
1557
|
-
if (x < rect.minX -
|
|
1647
|
+
if (x < rect.minX - EPS11 || x > rect.maxX + EPS11) return false;
|
|
1558
1648
|
const segMinY = Math.min(p1.y, p2.y);
|
|
1559
1649
|
const segMaxY = Math.max(p1.y, p2.y);
|
|
1560
1650
|
const overlap = Math.min(segMaxY, rect.maxY) - Math.max(segMinY, rect.minY);
|
|
1561
|
-
return overlap >
|
|
1651
|
+
return overlap > EPS11;
|
|
1562
1652
|
} else {
|
|
1563
1653
|
const y = p1.y;
|
|
1564
|
-
if (y < rect.minY -
|
|
1654
|
+
if (y < rect.minY - EPS11 || y > rect.maxY + EPS11) return false;
|
|
1565
1655
|
const segMinX = Math.min(p1.x, p2.x);
|
|
1566
1656
|
const segMaxX = Math.max(p1.x, p2.x);
|
|
1567
1657
|
const overlap = Math.min(segMaxX, rect.maxX) - Math.max(segMinX, rect.minX);
|
|
1568
|
-
return overlap >
|
|
1658
|
+
return overlap > EPS11;
|
|
1569
1659
|
}
|
|
1570
1660
|
}
|
|
1571
1661
|
function rectIntersectsAnyTrace(bounds, inputTraceMap, hostPathId, hostSegIndex) {
|
|
@@ -1949,14 +2039,14 @@ var SingleNetLabelPlacementSolver = class extends BaseSolver {
|
|
|
1949
2039
|
};
|
|
1950
2040
|
let bestCandidate = null;
|
|
1951
2041
|
let bestScore = -Infinity;
|
|
1952
|
-
const
|
|
2042
|
+
const EPS11 = 1e-6;
|
|
1953
2043
|
for (const curr of tracesToScan) {
|
|
1954
2044
|
const pts = curr.tracePath.slice();
|
|
1955
2045
|
for (let si = 0; si < pts.length - 1; si++) {
|
|
1956
2046
|
const a = pts[si];
|
|
1957
2047
|
const b = pts[si + 1];
|
|
1958
|
-
const isH = Math.abs(a.y - b.y) <
|
|
1959
|
-
const isV = Math.abs(a.x - b.x) <
|
|
2048
|
+
const isH = Math.abs(a.y - b.y) < EPS11;
|
|
2049
|
+
const isV = Math.abs(a.x - b.x) < EPS11;
|
|
1960
2050
|
if (!isH && !isV) continue;
|
|
1961
2051
|
const segmentAllowed = isH ? ["y+", "y-"] : ["x+", "x-"];
|
|
1962
2052
|
const candidateOrients = orientations.filter(
|
|
@@ -2094,6 +2184,7 @@ var NetLabelPlacementSolver = class extends BaseSolver {
|
|
|
2094
2184
|
overlappingSameNetTraceGroups;
|
|
2095
2185
|
queuedOverlappingSameNetTraceGroups;
|
|
2096
2186
|
netLabelPlacements = [];
|
|
2187
|
+
failedGroups = [];
|
|
2097
2188
|
currentGroup = null;
|
|
2098
2189
|
triedAnyOrientationFallbackForCurrentGroup = false;
|
|
2099
2190
|
constructor(params) {
|
|
@@ -2299,8 +2390,12 @@ var NetLabelPlacementSolver = class extends BaseSolver {
|
|
|
2299
2390
|
});
|
|
2300
2391
|
return;
|
|
2301
2392
|
}
|
|
2302
|
-
this.
|
|
2303
|
-
|
|
2393
|
+
if (this.currentGroup) {
|
|
2394
|
+
this.failedGroups.push(this.currentGroup);
|
|
2395
|
+
}
|
|
2396
|
+
this.activeSubSolver = null;
|
|
2397
|
+
this.currentGroup = null;
|
|
2398
|
+
this.triedAnyOrientationFallbackForCurrentGroup = false;
|
|
2304
2399
|
return;
|
|
2305
2400
|
}
|
|
2306
2401
|
if (this.activeSubSolver) {
|
|
@@ -2961,6 +3056,38 @@ var generateRerouteCandidates = ({
|
|
|
2961
3056
|
|
|
2962
3057
|
// lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/SingleOverlapSolver/SingleOverlapSolver.ts
|
|
2963
3058
|
var MAX_TRIES = 5;
|
|
3059
|
+
var COINCIDENT_EPS = 2e-3;
|
|
3060
|
+
var doesPathCoincideWithTraces = (path, traces) => {
|
|
3061
|
+
const rangesOverlap1D = (a1, a2, b1, b2) => Math.min(Math.max(a1, a2), Math.max(b1, b2)) - Math.max(Math.min(a1, a2), Math.min(b1, b2)) > COINCIDENT_EPS;
|
|
3062
|
+
for (let i = 0; i < path.length - 1; i++) {
|
|
3063
|
+
const pathSegStart = path[i];
|
|
3064
|
+
const pathSegEnd = path[i + 1];
|
|
3065
|
+
const isVertical4 = Math.abs(pathSegStart.x - pathSegEnd.x) < COINCIDENT_EPS;
|
|
3066
|
+
const isHorizontal3 = Math.abs(pathSegStart.y - pathSegEnd.y) < COINCIDENT_EPS;
|
|
3067
|
+
if (!isVertical4 && !isHorizontal3) continue;
|
|
3068
|
+
const crossAxis = isVertical4 ? "x" : "y";
|
|
3069
|
+
const alongAxis = isVertical4 ? "y" : "x";
|
|
3070
|
+
for (const trace of traces) {
|
|
3071
|
+
for (let j = 0; j < trace.tracePath.length - 1; j++) {
|
|
3072
|
+
const traceSegStart = trace.tracePath[j];
|
|
3073
|
+
const traceSegEnd = trace.tracePath[j + 1];
|
|
3074
|
+
const isParallel = Math.abs(traceSegStart[crossAxis] - traceSegEnd[crossAxis]) < COINCIDENT_EPS;
|
|
3075
|
+
if (!isParallel) continue;
|
|
3076
|
+
const isCoincident = Math.abs(pathSegStart[crossAxis] - traceSegStart[crossAxis]) < COINCIDENT_EPS;
|
|
3077
|
+
if (!isCoincident) continue;
|
|
3078
|
+
if (rangesOverlap1D(
|
|
3079
|
+
pathSegStart[alongAxis],
|
|
3080
|
+
pathSegEnd[alongAxis],
|
|
3081
|
+
traceSegStart[alongAxis],
|
|
3082
|
+
traceSegEnd[alongAxis]
|
|
3083
|
+
)) {
|
|
3084
|
+
return true;
|
|
3085
|
+
}
|
|
3086
|
+
}
|
|
3087
|
+
}
|
|
3088
|
+
}
|
|
3089
|
+
return false;
|
|
3090
|
+
};
|
|
2964
3091
|
var SingleOverlapSolver = class extends BaseSolver {
|
|
2965
3092
|
queuedCandidatePaths;
|
|
2966
3093
|
solvedTracePath = null;
|
|
@@ -2968,12 +3095,14 @@ var SingleOverlapSolver = class extends BaseSolver {
|
|
|
2968
3095
|
problem;
|
|
2969
3096
|
obstacles;
|
|
2970
3097
|
label;
|
|
3098
|
+
tracesToAvoidOverlapping;
|
|
2971
3099
|
_tried = 0;
|
|
2972
3100
|
constructor(solverInput) {
|
|
2973
3101
|
super();
|
|
2974
3102
|
this.initialTrace = solverInput.trace;
|
|
2975
3103
|
this.problem = solverInput.problem;
|
|
2976
3104
|
this.label = solverInput.label;
|
|
3105
|
+
this.tracesToAvoidOverlapping = (solverInput.tracesToAvoidOverlapping ?? []).filter((t) => t.globalConnNetId !== solverInput.trace.globalConnNetId);
|
|
2977
3106
|
const effectivePadding = solverInput.paddingBuffer + solverInput.detourCount * solverInput.paddingBuffer;
|
|
2978
3107
|
const candidates = generateRerouteCandidates({
|
|
2979
3108
|
...solverInput,
|
|
@@ -3002,7 +3131,7 @@ var SingleOverlapSolver = class extends BaseSolver {
|
|
|
3002
3131
|
this._tried++;
|
|
3003
3132
|
const nextCandidatePath = this.queuedCandidatePaths.shift();
|
|
3004
3133
|
const simplifiedPath = simplifyPath(nextCandidatePath);
|
|
3005
|
-
if (!isPathCollidingWithObstacles(simplifiedPath, this.obstacles)) {
|
|
3134
|
+
if (!isPathCollidingWithObstacles(simplifiedPath, this.obstacles) && !doesPathCoincideWithTraces(simplifiedPath, this.tracesToAvoidOverlapping)) {
|
|
3006
3135
|
this.solvedTracePath = simplifiedPath;
|
|
3007
3136
|
this.solved = true;
|
|
3008
3137
|
}
|
|
@@ -3107,6 +3236,7 @@ var OverlapAvoidanceStepSolver = class extends BaseSolver {
|
|
|
3107
3236
|
mergedNetLabelPlacements;
|
|
3108
3237
|
mergedLabelNetIdMap;
|
|
3109
3238
|
allTraces;
|
|
3239
|
+
tracesToAvoidOverlapping;
|
|
3110
3240
|
modifiedTraces = [];
|
|
3111
3241
|
PADDING_BUFFER = 0.1;
|
|
3112
3242
|
detourCounts = /* @__PURE__ */ new Map();
|
|
@@ -3122,6 +3252,7 @@ var OverlapAvoidanceStepSolver = class extends BaseSolver {
|
|
|
3122
3252
|
this.mergedNetLabelPlacements = solverInput.mergedNetLabelPlacements;
|
|
3123
3253
|
this.mergedLabelNetIdMap = solverInput.mergedLabelNetIdMap;
|
|
3124
3254
|
this.allTraces = [...solverInput.traces];
|
|
3255
|
+
this.tracesToAvoidOverlapping = solverInput.tracesToAvoidOverlapping ?? [];
|
|
3125
3256
|
this.detourCounts = solverInput.detourCounts;
|
|
3126
3257
|
}
|
|
3127
3258
|
_step() {
|
|
@@ -3203,7 +3334,8 @@ var OverlapAvoidanceStepSolver = class extends BaseSolver {
|
|
|
3203
3334
|
label: actualOverlapLabel,
|
|
3204
3335
|
problem: this.inputProblem,
|
|
3205
3336
|
paddingBuffer: this.PADDING_BUFFER,
|
|
3206
|
-
detourCount: detourCount2
|
|
3337
|
+
detourCount: detourCount2,
|
|
3338
|
+
tracesToAvoidOverlapping: this.tracesToAvoidOverlapping
|
|
3207
3339
|
});
|
|
3208
3340
|
} else {
|
|
3209
3341
|
const overlapId = `${traceToFix.mspPairId}-${labelToAvoid.globalConnNetId}`;
|
|
@@ -3238,7 +3370,8 @@ var OverlapAvoidanceStepSolver = class extends BaseSolver {
|
|
|
3238
3370
|
label: actualOverlapLabel,
|
|
3239
3371
|
problem: this.inputProblem,
|
|
3240
3372
|
paddingBuffer: this.PADDING_BUFFER,
|
|
3241
|
-
detourCount: detourCount2
|
|
3373
|
+
detourCount: detourCount2,
|
|
3374
|
+
tracesToAvoidOverlapping: this.tracesToAvoidOverlapping
|
|
3242
3375
|
});
|
|
3243
3376
|
} else {
|
|
3244
3377
|
const overlapId = `${traceToFix.mspPairId}-${labelToAvoid.globalConnNetId}`;
|
|
@@ -3253,7 +3386,8 @@ var OverlapAvoidanceStepSolver = class extends BaseSolver {
|
|
|
3253
3386
|
label: labelToAvoid,
|
|
3254
3387
|
problem: this.inputProblem,
|
|
3255
3388
|
paddingBuffer: this.PADDING_BUFFER,
|
|
3256
|
-
detourCount
|
|
3389
|
+
detourCount,
|
|
3390
|
+
tracesToAvoidOverlapping: this.tracesToAvoidOverlapping
|
|
3257
3391
|
});
|
|
3258
3392
|
}
|
|
3259
3393
|
}
|
|
@@ -3321,10 +3455,12 @@ var TraceLabelOverlapAvoidanceSolver = class extends BaseSolver {
|
|
|
3321
3455
|
phase = "searching_for_overlaps";
|
|
3322
3456
|
detourCounts = /* @__PURE__ */ new Map();
|
|
3323
3457
|
labelMergingSolver;
|
|
3458
|
+
allInputTraces;
|
|
3324
3459
|
constructor(solverInput) {
|
|
3325
3460
|
super();
|
|
3326
3461
|
this.inputProblem = solverInput.inputProblem;
|
|
3327
3462
|
this.unprocessedTraces = [...solverInput.traces];
|
|
3463
|
+
this.allInputTraces = solverInput.traces;
|
|
3328
3464
|
this.netLabelPlacements = solverInput.netLabelPlacements;
|
|
3329
3465
|
this.cleanTraces = [];
|
|
3330
3466
|
this.subSolvers = [];
|
|
@@ -3360,7 +3496,10 @@ var TraceLabelOverlapAvoidanceSolver = class extends BaseSolver {
|
|
|
3360
3496
|
initialNetLabelPlacements: this.netLabelPlacements,
|
|
3361
3497
|
mergedNetLabelPlacements: mergingOutput.netLabelPlacements,
|
|
3362
3498
|
mergedLabelNetIdMap: mergingOutput.mergedLabelNetIdMap,
|
|
3363
|
-
detourCounts: this.detourCounts
|
|
3499
|
+
detourCounts: this.detourCounts,
|
|
3500
|
+
tracesToAvoidOverlapping: this.allInputTraces.filter(
|
|
3501
|
+
(t) => t.mspPairId !== currentTargetTrace.mspPairId
|
|
3502
|
+
)
|
|
3364
3503
|
});
|
|
3365
3504
|
this.subSolvers.push(subSolver);
|
|
3366
3505
|
}
|
|
@@ -4172,8 +4311,8 @@ var findIntersectionsWithObstacles = (p1, p2, obstacles) => {
|
|
|
4172
4311
|
};
|
|
4173
4312
|
|
|
4174
4313
|
// lib/solvers/TraceCleanupSolver/sub-solver/generateLShapeRerouteCandidates.ts
|
|
4175
|
-
var
|
|
4176
|
-
var isVertical2 = (a, b, eps =
|
|
4314
|
+
var EPS5 = 1e-6;
|
|
4315
|
+
var isVertical2 = (a, b, eps = EPS5) => Math.abs(a.x - b.x) < eps;
|
|
4177
4316
|
var generateLShapeRerouteCandidates = ({
|
|
4178
4317
|
lShape,
|
|
4179
4318
|
rectangle,
|
|
@@ -4186,7 +4325,7 @@ var generateLShapeRerouteCandidates = ({
|
|
|
4186
4325
|
let c2;
|
|
4187
4326
|
let i1_padded = interactionPoint1;
|
|
4188
4327
|
let i2_padded = interactionPoint2;
|
|
4189
|
-
if (Math.abs(p2.x - x) <
|
|
4328
|
+
if (Math.abs(p2.x - x) < EPS5 && Math.abs(p2.y - (y + height)) < EPS5) {
|
|
4190
4329
|
c2 = { x: x + width + padding, y: y - padding };
|
|
4191
4330
|
if (isVertical2(p1, p2)) {
|
|
4192
4331
|
i1_padded = { x: interactionPoint1.x, y: interactionPoint1.y - padding };
|
|
@@ -4198,7 +4337,7 @@ var generateLShapeRerouteCandidates = ({
|
|
|
4198
4337
|
} else {
|
|
4199
4338
|
i2_padded = { x: interactionPoint2.x + padding, y: interactionPoint2.y };
|
|
4200
4339
|
}
|
|
4201
|
-
} else if (Math.abs(p2.x - (x + width)) <
|
|
4340
|
+
} else if (Math.abs(p2.x - (x + width)) < EPS5 && Math.abs(p2.y - (y + height)) < EPS5) {
|
|
4202
4341
|
c2 = { x: x - padding, y: y - padding };
|
|
4203
4342
|
if (isVertical2(p1, p2)) {
|
|
4204
4343
|
i1_padded = { x: interactionPoint1.x, y: interactionPoint1.y - padding };
|
|
@@ -4210,7 +4349,7 @@ var generateLShapeRerouteCandidates = ({
|
|
|
4210
4349
|
} else {
|
|
4211
4350
|
i2_padded = { x: interactionPoint2.x - padding, y: interactionPoint2.y };
|
|
4212
4351
|
}
|
|
4213
|
-
} else if (Math.abs(p2.x - x) <
|
|
4352
|
+
} else if (Math.abs(p2.x - x) < EPS5 && Math.abs(p2.y - y) < EPS5) {
|
|
4214
4353
|
c2 = { x: x + width + padding, y: y + height + padding };
|
|
4215
4354
|
if (isVertical2(p1, p2)) {
|
|
4216
4355
|
i1_padded = { x: interactionPoint1.x, y: interactionPoint1.y + padding };
|
|
@@ -4222,7 +4361,7 @@ var generateLShapeRerouteCandidates = ({
|
|
|
4222
4361
|
} else {
|
|
4223
4362
|
i2_padded = { x: interactionPoint2.x + padding, y: interactionPoint2.y };
|
|
4224
4363
|
}
|
|
4225
|
-
} else if (Math.abs(p2.x - (x + width)) <
|
|
4364
|
+
} else if (Math.abs(p2.x - (x + width)) < EPS5 && Math.abs(p2.y - y) < EPS5) {
|
|
4226
4365
|
c2 = { x: x - padding, y: y + height + padding };
|
|
4227
4366
|
if (isVertical2(p1, p2)) {
|
|
4228
4367
|
i1_padded = { x: interactionPoint1.x, y: interactionPoint1.y + padding };
|
|
@@ -4667,9 +4806,9 @@ var UntangleTraceSubsolver = class extends BaseSolver {
|
|
|
4667
4806
|
};
|
|
4668
4807
|
|
|
4669
4808
|
// lib/solvers/TraceCleanupSolver/is4PointRectangle.ts
|
|
4670
|
-
var
|
|
4671
|
-
var sameX = (a, b) => Math.abs(a.x - b.x) <=
|
|
4672
|
-
var sameY = (a, b) => Math.abs(a.y - b.y) <=
|
|
4809
|
+
var EPS6 = 1e-6;
|
|
4810
|
+
var sameX = (a, b) => Math.abs(a.x - b.x) <= EPS6;
|
|
4811
|
+
var sameY = (a, b) => Math.abs(a.y - b.y) <= EPS6;
|
|
4673
4812
|
var is4PointRectangle = (path) => {
|
|
4674
4813
|
if (path.length !== 4) return false;
|
|
4675
4814
|
const [p0, p1, p2, p3] = path;
|
|
@@ -4803,7 +4942,7 @@ var TraceCleanupSolver = class extends BaseSolver {
|
|
|
4803
4942
|
};
|
|
4804
4943
|
|
|
4805
4944
|
// lib/solvers/Example28Solver/types.ts
|
|
4806
|
-
var
|
|
4945
|
+
var EPS7 = 1e-9;
|
|
4807
4946
|
|
|
4808
4947
|
// lib/solvers/Example28Solver/geometry.ts
|
|
4809
4948
|
var getPathKey = (path) => path.map((point) => `${point.x},${point.y}`).join(";");
|
|
@@ -4815,10 +4954,10 @@ var getPathLength = (path) => {
|
|
|
4815
4954
|
return length;
|
|
4816
4955
|
};
|
|
4817
4956
|
var getDistance = (a, b) => Math.abs(a.x - b.x) + Math.abs(a.y - b.y);
|
|
4818
|
-
var isAxisAlignedSegment = (start, end) => Math.abs(start.x - end.x) <
|
|
4819
|
-
var getSegmentOrientation = (start, end) => Math.abs(start.y - end.y) <
|
|
4957
|
+
var isAxisAlignedSegment = (start, end) => Math.abs(start.x - end.x) < EPS7 || Math.abs(start.y - end.y) < EPS7;
|
|
4958
|
+
var getSegmentOrientation = (start, end) => Math.abs(start.y - end.y) < EPS7 ? "horizontal" : "vertical";
|
|
4820
4959
|
var projectPointToSegment = (point, start, end) => {
|
|
4821
|
-
if (Math.abs(start.x - end.x) <
|
|
4960
|
+
if (Math.abs(start.x - end.x) < EPS7) {
|
|
4822
4961
|
return {
|
|
4823
4962
|
x: start.x,
|
|
4824
4963
|
y: Math.min(
|
|
@@ -4827,7 +4966,7 @@ var projectPointToSegment = (point, start, end) => {
|
|
|
4827
4966
|
)
|
|
4828
4967
|
};
|
|
4829
4968
|
}
|
|
4830
|
-
if (Math.abs(start.y - end.y) <
|
|
4969
|
+
if (Math.abs(start.y - end.y) < EPS7) {
|
|
4831
4970
|
return {
|
|
4832
4971
|
x: Math.min(
|
|
4833
4972
|
Math.max(point.x, Math.min(start.x, end.x)),
|
|
@@ -4870,9 +5009,9 @@ var findSegmentContainingPoint = (path, point) => {
|
|
|
4870
5009
|
};
|
|
4871
5010
|
var isPointWithinSegmentPrimaryRange = (point, segment) => {
|
|
4872
5011
|
if (segment.orientation === "horizontal") {
|
|
4873
|
-
return point.x >= Math.min(segment.start.x, segment.end.x) -
|
|
5012
|
+
return point.x >= Math.min(segment.start.x, segment.end.x) - EPS7 && point.x <= Math.max(segment.start.x, segment.end.x) + EPS7;
|
|
4874
5013
|
}
|
|
4875
|
-
return point.y >= Math.min(segment.start.y, segment.end.y) -
|
|
5014
|
+
return point.y >= Math.min(segment.start.y, segment.end.y) - EPS7 && point.y <= Math.max(segment.start.y, segment.end.y) + EPS7;
|
|
4876
5015
|
};
|
|
4877
5016
|
var findPreferredReroutedSegment = (path, originalSegmentIndex, originalSegmentCount, orientation, anchorPoint) => {
|
|
4878
5017
|
const matchingSegments = getSegments(path).filter(
|
|
@@ -4900,18 +5039,18 @@ var projectPointToPath = (point, path) => {
|
|
|
4900
5039
|
return bestPoint;
|
|
4901
5040
|
};
|
|
4902
5041
|
var segmentsIntersect = (a1, a2, b1, b2) => {
|
|
4903
|
-
const aVertical = Math.abs(a1.x - a2.x) <
|
|
4904
|
-
const bVertical = Math.abs(b1.x - b2.x) <
|
|
4905
|
-
const between = (value, p1, p2) => value >= Math.min(p1, p2) -
|
|
5042
|
+
const aVertical = Math.abs(a1.x - a2.x) < EPS7;
|
|
5043
|
+
const bVertical = Math.abs(b1.x - b2.x) < EPS7;
|
|
5044
|
+
const between = (value, p1, p2) => value >= Math.min(p1, p2) - EPS7 && value <= Math.max(p1, p2) + EPS7;
|
|
4906
5045
|
if (aVertical && bVertical) {
|
|
4907
|
-
if (Math.abs(a1.x - b1.x) >
|
|
5046
|
+
if (Math.abs(a1.x - b1.x) > EPS7) return false;
|
|
4908
5047
|
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));
|
|
4909
|
-
return overlap >
|
|
5048
|
+
return overlap > EPS7;
|
|
4910
5049
|
}
|
|
4911
5050
|
if (!aVertical && !bVertical) {
|
|
4912
|
-
if (Math.abs(a1.y - b1.y) >
|
|
5051
|
+
if (Math.abs(a1.y - b1.y) > EPS7) return false;
|
|
4913
5052
|
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));
|
|
4914
|
-
return overlap >
|
|
5053
|
+
return overlap > EPS7;
|
|
4915
5054
|
}
|
|
4916
5055
|
const verticalA = aVertical ? a1 : b1;
|
|
4917
5056
|
const verticalB = aVertical ? a2 : b2;
|
|
@@ -4943,13 +5082,13 @@ var isPathCollidingWithChipInterior = (path, chipObstacles) => {
|
|
|
4943
5082
|
return false;
|
|
4944
5083
|
};
|
|
4945
5084
|
var segmentRunsAlongRectBoundary = (start, end, rect) => {
|
|
4946
|
-
const isVertical4 = Math.abs(start.x - end.x) <
|
|
4947
|
-
const isHorizontal3 = Math.abs(start.y - end.y) <
|
|
5085
|
+
const isVertical4 = Math.abs(start.x - end.x) < EPS7;
|
|
5086
|
+
const isHorizontal3 = Math.abs(start.y - end.y) < EPS7;
|
|
4948
5087
|
if (isVertical4) {
|
|
4949
|
-
return Math.abs(start.x - rect.minX) <
|
|
5088
|
+
return Math.abs(start.x - rect.minX) < EPS7 || Math.abs(start.x - rect.maxX) < EPS7;
|
|
4950
5089
|
}
|
|
4951
5090
|
if (isHorizontal3) {
|
|
4952
|
-
return Math.abs(start.y - rect.minY) <
|
|
5091
|
+
return Math.abs(start.y - rect.minY) < EPS7 || Math.abs(start.y - rect.maxY) < EPS7;
|
|
4953
5092
|
}
|
|
4954
5093
|
return false;
|
|
4955
5094
|
};
|
|
@@ -5573,16 +5712,16 @@ var Example28Solver = class extends BaseSolver {
|
|
|
5573
5712
|
// lib/solvers/AvailableNetOrientationSolver/constants.ts
|
|
5574
5713
|
var LABEL_SEARCH_STEP = 0.05;
|
|
5575
5714
|
var WICK_CLEARANCE = 1e-3;
|
|
5576
|
-
var
|
|
5577
|
-
var TRACE_BOUNDARY_TOLERANCE = WICK_CLEARANCE +
|
|
5715
|
+
var EPS8 = 1e-9;
|
|
5716
|
+
var TRACE_BOUNDARY_TOLERANCE = WICK_CLEARANCE + EPS8;
|
|
5578
5717
|
var CANDIDATE_SELECTED_COLOR2 = "blue";
|
|
5579
5718
|
var CANDIDATE_REJECTED_COLOR2 = "red";
|
|
5580
5719
|
|
|
5581
5720
|
// lib/solvers/AvailableNetOrientationSolver/geometry.ts
|
|
5582
5721
|
var isYOrientation = (orientation) => orientation === "y+" || orientation === "y-";
|
|
5583
5722
|
var isXOrientation = (orientation) => orientation === "x+" || orientation === "x-";
|
|
5584
|
-
var rectsOverlap = (a, b) => Math.min(a.maxX, b.maxX) - Math.max(a.minX, b.minX) >
|
|
5585
|
-
var rangesOverlap = (minA, maxA, minB, maxB) => Math.min(maxA, maxB) - Math.max(minA, minB) >
|
|
5723
|
+
var rectsOverlap = (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;
|
|
5724
|
+
var rangesOverlap = (minA, maxA, minB, maxB) => Math.min(maxA, maxB) - Math.max(minA, minB) > EPS8;
|
|
5586
5725
|
var traceCrossesBoundsInterior = (bounds, traceMap) => {
|
|
5587
5726
|
for (const trace of Object.values(traceMap)) {
|
|
5588
5727
|
const points = trace.tracePath;
|
|
@@ -5605,7 +5744,7 @@ var segmentCrossesBoundsInterior = (p1, p2, bounds) => {
|
|
|
5605
5744
|
return false;
|
|
5606
5745
|
}
|
|
5607
5746
|
if (sameX2(p1, p2)) {
|
|
5608
|
-
if (p1.x <= interiorBounds.minX +
|
|
5747
|
+
if (p1.x <= interiorBounds.minX + EPS8 || p1.x >= interiorBounds.maxX - EPS8) {
|
|
5609
5748
|
return false;
|
|
5610
5749
|
}
|
|
5611
5750
|
return rangesOverlap(
|
|
@@ -5616,7 +5755,7 @@ var segmentCrossesBoundsInterior = (p1, p2, bounds) => {
|
|
|
5616
5755
|
);
|
|
5617
5756
|
}
|
|
5618
5757
|
if (sameY2(p1, p2)) {
|
|
5619
|
-
if (p1.y <= interiorBounds.minY +
|
|
5758
|
+
if (p1.y <= interiorBounds.minY + EPS8 || p1.y >= interiorBounds.maxY - EPS8) {
|
|
5620
5759
|
return false;
|
|
5621
5760
|
}
|
|
5622
5761
|
return rangesOverlap(
|
|
@@ -5664,10 +5803,10 @@ var tracePathCrossesAnyTrace = (tracePath, traceMap) => {
|
|
|
5664
5803
|
};
|
|
5665
5804
|
var segmentsStrictlyCross = (a1, a2, b1, b2) => {
|
|
5666
5805
|
if (sameX2(a1, a2) && sameY2(b1, b2)) {
|
|
5667
|
-
return a1.x > Math.min(b1.x, b2.x) +
|
|
5806
|
+
return a1.x > Math.min(b1.x, b2.x) + EPS8 && a1.x < Math.max(b1.x, b2.x) - EPS8 && b1.y > Math.min(a1.y, a2.y) + EPS8 && b1.y < Math.max(a1.y, a2.y) - EPS8;
|
|
5668
5807
|
}
|
|
5669
5808
|
if (sameY2(a1, a2) && sameX2(b1, b2)) {
|
|
5670
|
-
return b1.x > Math.min(a1.x, a2.x) +
|
|
5809
|
+
return b1.x > Math.min(a1.x, a2.x) + EPS8 && b1.x < Math.max(a1.x, a2.x) - EPS8 && a1.y > Math.min(b1.y, b2.y) + EPS8 && a1.y < Math.max(b1.y, b2.y) - EPS8;
|
|
5671
5810
|
}
|
|
5672
5811
|
return false;
|
|
5673
5812
|
};
|
|
@@ -5699,8 +5838,8 @@ var simplifyOrthogonalPath = (path) => {
|
|
|
5699
5838
|
return simplified;
|
|
5700
5839
|
};
|
|
5701
5840
|
var pointsEqual = (a, b) => sameX2(a, b) && sameY2(a, b);
|
|
5702
|
-
var sameX2 = (a, b) => Math.abs(a.x - b.x) <=
|
|
5703
|
-
var sameY2 = (a, b) => Math.abs(a.y - b.y) <=
|
|
5841
|
+
var sameX2 = (a, b) => Math.abs(a.x - b.x) <= EPS8;
|
|
5842
|
+
var sameY2 = (a, b) => Math.abs(a.y - b.y) <= EPS8;
|
|
5704
5843
|
var getMaxSearchDistance = (inputProblem) => {
|
|
5705
5844
|
const maxChipWidth = Math.max(
|
|
5706
5845
|
...inputProblem.chips.map((chip) => chip.width),
|
|
@@ -5988,7 +6127,7 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
5988
6127
|
);
|
|
5989
6128
|
const maxSearchDistance = this.getSearchDistanceLimit(label, orientation);
|
|
5990
6129
|
const maxOutwardDistance = outwardDirection.x === 0 && outwardDirection.y === 0 ? 0 : this.maxSearchDistance;
|
|
5991
|
-
for (let outwardDistance = 0; outwardDistance <= maxOutwardDistance +
|
|
6130
|
+
for (let outwardDistance = 0; outwardDistance <= maxOutwardDistance + EPS8; outwardDistance += LABEL_SEARCH_STEP) {
|
|
5992
6131
|
const baseAnchor = {
|
|
5993
6132
|
x: initialBaseAnchor.x + outwardDirection.x * outwardDistance,
|
|
5994
6133
|
y: initialBaseAnchor.y + outwardDirection.y * outwardDistance
|
|
@@ -6061,7 +6200,7 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
6061
6200
|
outwardDistance,
|
|
6062
6201
|
phase = "shift"
|
|
6063
6202
|
} = params;
|
|
6064
|
-
for (let distance3 = LABEL_SEARCH_STEP; distance3 <= maxSearchDistance +
|
|
6203
|
+
for (let distance3 = LABEL_SEARCH_STEP; distance3 <= maxSearchDistance + EPS8; distance3 += LABEL_SEARCH_STEP) {
|
|
6065
6204
|
const anchorPoint = {
|
|
6066
6205
|
x: baseAnchor.x + direction.x * distance3,
|
|
6067
6206
|
y: baseAnchor.y + direction.y * distance3
|
|
@@ -6299,8 +6438,8 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
6299
6438
|
sharesChipBoundary(bounds) {
|
|
6300
6439
|
for (const chip of this.chipObstacleSpatialIndex.chips) {
|
|
6301
6440
|
const chipBounds = chip.bounds;
|
|
6302
|
-
const adjacentToVerticalSide = Math.abs(bounds.minX - chipBounds.maxX) <= WICK_CLEARANCE +
|
|
6303
|
-
const adjacentToHorizontalSide = Math.abs(bounds.minY - chipBounds.maxY) <= WICK_CLEARANCE +
|
|
6441
|
+
const adjacentToVerticalSide = Math.abs(bounds.minX - chipBounds.maxX) <= WICK_CLEARANCE + EPS8 || Math.abs(bounds.maxX - chipBounds.minX) <= WICK_CLEARANCE + EPS8;
|
|
6442
|
+
const adjacentToHorizontalSide = Math.abs(bounds.minY - chipBounds.maxY) <= WICK_CLEARANCE + EPS8 || Math.abs(bounds.maxY - chipBounds.minY) <= WICK_CLEARANCE + EPS8;
|
|
6304
6443
|
if (adjacentToVerticalSide && rangesOverlap(
|
|
6305
6444
|
bounds.minY,
|
|
6306
6445
|
bounds.maxY,
|
|
@@ -6348,7 +6487,7 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
6348
6487
|
let nearestDistance = Number.POSITIVE_INFINITY;
|
|
6349
6488
|
for (const chip of this.chipObstacleSpatialIndex.chips) {
|
|
6350
6489
|
const bounds = chip.bounds;
|
|
6351
|
-
if (point.x < bounds.minX -
|
|
6490
|
+
if (point.x < bounds.minX - EPS8 || point.x > bounds.maxX + EPS8 || point.y < bounds.minY - EPS8 || point.y > bounds.maxY + EPS8) {
|
|
6352
6491
|
continue;
|
|
6353
6492
|
}
|
|
6354
6493
|
for (const [side, distance3] of getSideDistances(point, bounds)) {
|
|
@@ -6365,8 +6504,8 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
6365
6504
|
let nearestDistanceSq = Number.POSITIVE_INFINITY;
|
|
6366
6505
|
for (const chip of this.chipObstacleSpatialIndex.chips) {
|
|
6367
6506
|
const bounds = chip.bounds;
|
|
6368
|
-
const dx = point.x < bounds.minX -
|
|
6369
|
-
const dy = point.y < bounds.minY -
|
|
6507
|
+
const dx = point.x < bounds.minX - EPS8 ? bounds.minX - point.x : point.x > bounds.maxX + EPS8 ? point.x - bounds.maxX : 0;
|
|
6508
|
+
const dy = point.y < bounds.minY - EPS8 ? bounds.minY - point.y : point.y > bounds.maxY + EPS8 ? point.y - bounds.maxY : 0;
|
|
6370
6509
|
if (dx === 0 && dy === 0) continue;
|
|
6371
6510
|
const distanceSq = dx ** 2 + dy ** 2;
|
|
6372
6511
|
if (distanceSq >= nearestDistanceSq) continue;
|
|
@@ -6405,9 +6544,9 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
6405
6544
|
};
|
|
6406
6545
|
|
|
6407
6546
|
// lib/solvers/VccNetLabelCornerPlacementSolver/geometry.ts
|
|
6408
|
-
var
|
|
6547
|
+
var EPS9 = 1e-6;
|
|
6409
6548
|
var isTraceLine = (trace) => getUniquePinCount(trace.pinIds) >= 2;
|
|
6410
|
-
var rectsOverlap2 = (a, b) => Math.min(a.maxX, b.maxX) - Math.max(a.minX, b.minX) >
|
|
6549
|
+
var rectsOverlap2 = (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;
|
|
6411
6550
|
var getTraceCorners = (path) => {
|
|
6412
6551
|
const corners = [];
|
|
6413
6552
|
for (let i = 1; i < path.length - 1; i++) {
|
|
@@ -6431,11 +6570,11 @@ var getUniquePinCount = (pinIds) => new Set(pinIds).size;
|
|
|
6431
6570
|
var isTraceCorner = (a, b, c) => getSegmentOrientation2(a, b) !== getSegmentOrientation2(b, c);
|
|
6432
6571
|
var isPointOnSegment = (point, start, end) => {
|
|
6433
6572
|
if (getSegmentOrientation2(start, end) === "horizontal") {
|
|
6434
|
-
return Math.abs(point.y - start.y) <=
|
|
6573
|
+
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;
|
|
6435
6574
|
}
|
|
6436
|
-
return Math.abs(point.x - start.x) <=
|
|
6575
|
+
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;
|
|
6437
6576
|
};
|
|
6438
|
-
var getSegmentOrientation2 = (a, b) => Math.abs(a.y - b.y) <=
|
|
6577
|
+
var getSegmentOrientation2 = (a, b) => Math.abs(a.y - b.y) <= EPS9 ? "horizontal" : "vertical";
|
|
6439
6578
|
|
|
6440
6579
|
// lib/solvers/VccNetLabelCornerPlacementSolver/visualize.ts
|
|
6441
6580
|
var CANDIDATE_SELECTED_COLOR3 = "blue";
|
|
@@ -6713,11 +6852,11 @@ var VccNetLabelCornerPlacementSolver = class extends BaseSolver {
|
|
|
6713
6852
|
};
|
|
6714
6853
|
|
|
6715
6854
|
// lib/solvers/TraceAnchoredNetLabelOverlapSolver/geometry.ts
|
|
6716
|
-
var
|
|
6855
|
+
var EPS10 = 1e-6;
|
|
6717
6856
|
var TRACE_BOUNDARY_TOLERANCE2 = 1e-6;
|
|
6718
6857
|
var getLabelBounds = (label) => getRectBounds(label.center, label.width, label.height);
|
|
6719
|
-
var rectsOverlap3 = (a, b) => Math.min(a.maxX, b.maxX) - Math.max(a.minX, b.minX) >
|
|
6720
|
-
var rectsTouchOrOverlap = (a, b) => Math.min(a.maxX, b.maxX) - Math.max(a.minX, b.minX) >= -
|
|
6858
|
+
var rectsOverlap3 = (a, b) => Math.min(a.maxX, b.maxX) - Math.max(a.minX, b.minX) > EPS10 && Math.min(a.maxY, b.maxY) - Math.max(a.minY, b.minY) > EPS10;
|
|
6859
|
+
var rectsTouchOrOverlap = (a, b) => Math.min(a.maxX, b.maxX) - Math.max(a.minX, b.minX) >= -EPS10 && Math.min(a.maxY, b.maxY) - Math.max(a.minY, b.minY) >= -EPS10;
|
|
6721
6860
|
var traceCrossesBoundsInterior2 = (bounds, traces) => {
|
|
6722
6861
|
for (const trace of traces) {
|
|
6723
6862
|
const points = trace.tracePath;
|
|
@@ -6763,7 +6902,7 @@ var getPointAtTraceDistance = (trace, distance3) => {
|
|
|
6763
6902
|
const end = trace.tracePath[i + 1];
|
|
6764
6903
|
const segmentLength = getManhattanDistance(start, end);
|
|
6765
6904
|
const nextDistance = pathDistance + segmentLength;
|
|
6766
|
-
if (distance3 <= nextDistance +
|
|
6905
|
+
if (distance3 <= nextDistance + EPS10) {
|
|
6767
6906
|
const offset = Math.max(
|
|
6768
6907
|
0,
|
|
6769
6908
|
Math.min(segmentLength, distance3 - pathDistance)
|
|
@@ -6802,7 +6941,7 @@ var segmentCrossesBoundsInterior2 = (start, end, bounds) => {
|
|
|
6802
6941
|
return false;
|
|
6803
6942
|
}
|
|
6804
6943
|
if (isVertical3(start, end)) {
|
|
6805
|
-
if (start.x <= interior.minX +
|
|
6944
|
+
if (start.x <= interior.minX + EPS10 || start.x >= interior.maxX - EPS10) {
|
|
6806
6945
|
return false;
|
|
6807
6946
|
}
|
|
6808
6947
|
return rangesOverlap2(
|
|
@@ -6813,7 +6952,7 @@ var segmentCrossesBoundsInterior2 = (start, end, bounds) => {
|
|
|
6813
6952
|
);
|
|
6814
6953
|
}
|
|
6815
6954
|
if (isHorizontal2(start, end)) {
|
|
6816
|
-
if (start.y <= interior.minY +
|
|
6955
|
+
if (start.y <= interior.minY + EPS10 || start.y >= interior.maxY - EPS10) {
|
|
6817
6956
|
return false;
|
|
6818
6957
|
}
|
|
6819
6958
|
return rangesOverlap2(
|
|
@@ -6827,10 +6966,10 @@ var segmentCrossesBoundsInterior2 = (start, end, bounds) => {
|
|
|
6827
6966
|
};
|
|
6828
6967
|
var isPointOnSegment2 = (point, start, end) => {
|
|
6829
6968
|
if (isHorizontal2(start, end)) {
|
|
6830
|
-
return Math.abs(point.y - start.y) <=
|
|
6969
|
+
return Math.abs(point.y - start.y) <= EPS10 && point.x >= Math.min(start.x, end.x) - EPS10 && point.x <= Math.max(start.x, end.x) + EPS10;
|
|
6831
6970
|
}
|
|
6832
6971
|
if (isVertical3(start, end)) {
|
|
6833
|
-
return Math.abs(point.x - start.x) <=
|
|
6972
|
+
return Math.abs(point.x - start.x) <= EPS10 && point.y >= Math.min(start.y, end.y) - EPS10 && point.y <= Math.max(start.y, end.y) + EPS10;
|
|
6834
6973
|
}
|
|
6835
6974
|
return false;
|
|
6836
6975
|
};
|
|
@@ -6838,9 +6977,9 @@ var getSegmentDirection = (start, end) => ({
|
|
|
6838
6977
|
x: isVertical3(start, end) ? 0 : Math.sign(end.x - start.x),
|
|
6839
6978
|
y: isHorizontal2(start, end) ? 0 : Math.sign(end.y - start.y)
|
|
6840
6979
|
});
|
|
6841
|
-
var isHorizontal2 = (start, end) => Math.abs(start.y - end.y) <=
|
|
6842
|
-
var isVertical3 = (start, end) => Math.abs(start.x - end.x) <=
|
|
6843
|
-
var rangesOverlap2 = (minA, maxA, minB, maxB) => Math.min(maxA, maxB) - Math.max(minA, minB) >
|
|
6980
|
+
var isHorizontal2 = (start, end) => Math.abs(start.y - end.y) <= EPS10;
|
|
6981
|
+
var isVertical3 = (start, end) => Math.abs(start.x - end.x) <= EPS10;
|
|
6982
|
+
var rangesOverlap2 = (minA, maxA, minB, maxB) => Math.min(maxA, maxB) - Math.max(minA, minB) > EPS10;
|
|
6844
6983
|
var getUniquePinCount2 = (pinIds) => new Set(pinIds).size;
|
|
6845
6984
|
|
|
6846
6985
|
// lib/solvers/TraceAnchoredNetLabelOverlapSolver/candidates.ts
|
|
@@ -6897,7 +7036,7 @@ var getCandidateDistances = (traceLength, vertexDistances) => {
|
|
|
6897
7036
|
for (const distance3 of vertexDistances) {
|
|
6898
7037
|
distances.add(roundDistance(distance3));
|
|
6899
7038
|
}
|
|
6900
|
-
return [...distances].filter((distance3) => distance3 >= -
|
|
7039
|
+
return [...distances].filter((distance3) => distance3 >= -EPS10 && distance3 <= traceLength + EPS10).sort((a, b) => a - b);
|
|
6901
7040
|
};
|
|
6902
7041
|
var getOrientationsForPoint = (params) => {
|
|
6903
7042
|
const { inputProblem, label, point, orientationConstraint } = params;
|
|
@@ -7006,13 +7145,13 @@ var getOutwardOrientationOptions = (point, chipBounds) => {
|
|
|
7006
7145
|
};
|
|
7007
7146
|
var getOutwardAxisOption = (params) => {
|
|
7008
7147
|
const { value, min, max, center, positiveOrientation, negativeOrientation } = params;
|
|
7009
|
-
if (value > max +
|
|
7148
|
+
if (value > max + EPS10) {
|
|
7010
7149
|
return {
|
|
7011
7150
|
orientation: positiveOrientation,
|
|
7012
7151
|
outwardScore: 1 + value - max
|
|
7013
7152
|
};
|
|
7014
7153
|
}
|
|
7015
|
-
if (value < min -
|
|
7154
|
+
if (value < min - EPS10) {
|
|
7016
7155
|
return {
|
|
7017
7156
|
orientation: negativeOrientation,
|
|
7018
7157
|
outwardScore: 1 + min - value
|
|
@@ -7023,7 +7162,7 @@ var getOutwardAxisOption = (params) => {
|
|
|
7023
7162
|
outwardScore: getNormalizedCenterDistance(value, center, max - min)
|
|
7024
7163
|
};
|
|
7025
7164
|
};
|
|
7026
|
-
var getNormalizedCenterDistance = (value, center, span) => Math.abs(value - center) / Math.max(
|
|
7165
|
+
var getNormalizedCenterDistance = (value, center, span) => Math.abs(value - center) / Math.max(EPS10, span / 2);
|
|
7027
7166
|
var ALL_ORIENTATIONS = ["x+", "x-", "y+", "y-"];
|
|
7028
7167
|
var getFlippedOrientation = (orientation) => {
|
|
7029
7168
|
switch (orientation) {
|
|
@@ -7118,7 +7257,7 @@ var normalizeFacingDirection = (value) => {
|
|
|
7118
7257
|
var dedupeStrings = (values) => [
|
|
7119
7258
|
...new Set(values.filter((value) => value !== void 0))
|
|
7120
7259
|
];
|
|
7121
|
-
var isSamePlacement = (label, point, orientation) => Math.abs(point.x - label.anchorPoint.x) <=
|
|
7260
|
+
var isSamePlacement = (label, point, orientation) => Math.abs(point.x - label.anchorPoint.x) <= EPS10 && Math.abs(point.y - label.anchorPoint.y) <= EPS10 && orientation === label.orientation;
|
|
7122
7261
|
|
|
7123
7262
|
// lib/solvers/TraceAnchoredNetLabelOverlapSolver/visualize.ts
|
|
7124
7263
|
var CANDIDATE_SELECTED_COLOR4 = "blue";
|