@tscircuit/schematic-trace-solver 0.0.64 → 0.0.65
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 +4 -0
- package/dist/index.js +160 -108
- package/lib/solvers/TraceOverlapShiftSolver/TraceOverlapIssueSolver/TraceOverlapIssueSolver.ts +89 -6
- package/lib/solvers/TraceOverlapShiftSolver/TraceOverlapShiftSolver.ts +1 -0
- package/package.json +1 -1
- package/tests/repros/__snapshots__/trace-overlap-box-resistor.snap.svg +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -204,13 +204,17 @@ interface OverlappingTraceSegmentLocator {
|
|
|
204
204
|
declare class TraceOverlapIssueSolver extends BaseSolver {
|
|
205
205
|
overlappingTraceSegments: OverlappingTraceSegmentLocator[];
|
|
206
206
|
traceNetIslands: Record<ConnNetId$1, Array<SolvedTracePath>>;
|
|
207
|
+
obstacleRects: ReturnType<typeof getObstacleRects>;
|
|
207
208
|
SHIFT_DISTANCE: number;
|
|
208
209
|
correctedTraceMap: Record<MspConnectionPairId, SolvedTracePath>;
|
|
209
210
|
constructor(params: {
|
|
211
|
+
inputProblem: InputProblem;
|
|
210
212
|
overlappingTraceSegments: OverlappingTraceSegmentLocator[];
|
|
211
213
|
traceNetIslands: Record<ConnNetId$1, Array<SolvedTracePath>>;
|
|
212
214
|
});
|
|
213
215
|
_step(): void;
|
|
216
|
+
private getObstacleAwareOffset;
|
|
217
|
+
private getBlockingCollisions;
|
|
214
218
|
visualize(): GraphicsObject;
|
|
215
219
|
}
|
|
216
220
|
|
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,13 +1050,13 @@ 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
1062
|
if (si === 0) {
|
|
@@ -1103,15 +1103,18 @@ var applyJogToTerminalSegment = ({
|
|
|
1103
1103
|
};
|
|
1104
1104
|
|
|
1105
1105
|
// lib/solvers/TraceOverlapShiftSolver/TraceOverlapIssueSolver/TraceOverlapIssueSolver.ts
|
|
1106
|
+
var EPS4 = 1e-6;
|
|
1106
1107
|
var TraceOverlapIssueSolver = class extends BaseSolver {
|
|
1107
1108
|
overlappingTraceSegments;
|
|
1108
1109
|
traceNetIslands;
|
|
1110
|
+
obstacleRects;
|
|
1109
1111
|
SHIFT_DISTANCE = 0.1;
|
|
1110
1112
|
correctedTraceMap = {};
|
|
1111
1113
|
constructor(params) {
|
|
1112
1114
|
super();
|
|
1113
1115
|
this.overlappingTraceSegments = params.overlappingTraceSegments;
|
|
1114
1116
|
this.traceNetIslands = params.traceNetIslands;
|
|
1117
|
+
this.obstacleRects = getObstacleRects(params.inputProblem);
|
|
1115
1118
|
for (const { connNetId, pathsWithOverlap } of this.overlappingTraceSegments) {
|
|
1116
1119
|
for (const {
|
|
1117
1120
|
solvedTracePathIndex,
|
|
@@ -1123,13 +1126,15 @@ var TraceOverlapIssueSolver = class extends BaseSolver {
|
|
|
1123
1126
|
}
|
|
1124
1127
|
}
|
|
1125
1128
|
_step() {
|
|
1126
|
-
const
|
|
1127
|
-
const offsets = this.overlappingTraceSegments.map((_, idx) => {
|
|
1129
|
+
const offsets = this.overlappingTraceSegments.map((group, idx) => {
|
|
1128
1130
|
const n = Math.floor(idx / 2) + 1;
|
|
1129
1131
|
const signed = idx % 2 === 0 ? -n : n;
|
|
1130
|
-
return
|
|
1132
|
+
return this.getObstacleAwareOffset({
|
|
1133
|
+
group,
|
|
1134
|
+
offset: signed * this.SHIFT_DISTANCE
|
|
1135
|
+
});
|
|
1131
1136
|
});
|
|
1132
|
-
const eq = (a, b) => Math.abs(a - b) <
|
|
1137
|
+
const eq = (a, b) => Math.abs(a - b) < EPS4;
|
|
1133
1138
|
const samePoint = (p, q) => !!p && !!q && eq(p.x, q.x) && eq(p.y, q.y);
|
|
1134
1139
|
this.overlappingTraceSegments.forEach((group, gidx) => {
|
|
1135
1140
|
const offset = offsets[gidx];
|
|
@@ -1144,7 +1149,6 @@ var TraceOverlapIssueSolver = class extends BaseSolver {
|
|
|
1144
1149
|
const original = this.traceNetIslands[group.connNetId][pathIdx];
|
|
1145
1150
|
const current = this.correctedTraceMap[original.mspPairId] ?? original;
|
|
1146
1151
|
const pts = current.tracePath.map((p) => ({ ...p }));
|
|
1147
|
-
const segIdxs = Array.from(segIdxSet).sort((a, b) => a - b);
|
|
1148
1152
|
const segIdxsRev = Array.from(segIdxSet).sort((a, b) => a - b).reverse();
|
|
1149
1153
|
const JOG_SIZE = this.SHIFT_DISTANCE;
|
|
1150
1154
|
for (const si of segIdxsRev) {
|
|
@@ -1155,13 +1159,13 @@ var TraceOverlapIssueSolver = class extends BaseSolver {
|
|
|
1155
1159
|
segmentIndex: si,
|
|
1156
1160
|
offset,
|
|
1157
1161
|
JOG_SIZE,
|
|
1158
|
-
EPS:
|
|
1162
|
+
EPS: EPS4
|
|
1159
1163
|
});
|
|
1160
1164
|
} else {
|
|
1161
1165
|
const start = pts[si];
|
|
1162
1166
|
const end = pts[si + 1];
|
|
1163
|
-
const isVertical4 = Math.abs(start.x - end.x) <
|
|
1164
|
-
const isHorizontal3 = Math.abs(start.y - end.y) <
|
|
1167
|
+
const isVertical4 = Math.abs(start.x - end.x) < EPS4;
|
|
1168
|
+
const isHorizontal3 = Math.abs(start.y - end.y) < EPS4;
|
|
1165
1169
|
if (!isVertical4 && !isHorizontal3) continue;
|
|
1166
1170
|
if (isVertical4) {
|
|
1167
1171
|
start.x += offset;
|
|
@@ -1186,6 +1190,53 @@ var TraceOverlapIssueSolver = class extends BaseSolver {
|
|
|
1186
1190
|
});
|
|
1187
1191
|
this.solved = true;
|
|
1188
1192
|
}
|
|
1193
|
+
getObstacleAwareOffset({
|
|
1194
|
+
group,
|
|
1195
|
+
offset
|
|
1196
|
+
}) {
|
|
1197
|
+
const blockingCollisions = this.getBlockingCollisions({ group, offset });
|
|
1198
|
+
if (blockingCollisions.length === 0) return offset;
|
|
1199
|
+
return blockingCollisions.flatMap(({ start, isVertical: isVertical4, obstacle }) => [
|
|
1200
|
+
(isVertical4 ? obstacle.minX - start.x : obstacle.minY - start.y) - this.SHIFT_DISTANCE,
|
|
1201
|
+
(isVertical4 ? obstacle.maxX - start.x : obstacle.maxY - start.y) + this.SHIFT_DISTANCE
|
|
1202
|
+
]).filter(
|
|
1203
|
+
(candidateOffset) => this.getBlockingCollisions({ group, offset: candidateOffset }).length === 0
|
|
1204
|
+
).sort((a, b) => Math.abs(a - offset) - Math.abs(b - offset))[0] ?? offset;
|
|
1205
|
+
}
|
|
1206
|
+
getBlockingCollisions({
|
|
1207
|
+
group,
|
|
1208
|
+
offset
|
|
1209
|
+
}) {
|
|
1210
|
+
const blockingCollisions = [];
|
|
1211
|
+
for (const {
|
|
1212
|
+
solvedTracePathIndex,
|
|
1213
|
+
traceSegmentIndex
|
|
1214
|
+
} of group.pathsWithOverlap) {
|
|
1215
|
+
const trace = this.traceNetIslands[group.connNetId][solvedTracePathIndex];
|
|
1216
|
+
const start = trace.tracePath[traceSegmentIndex];
|
|
1217
|
+
const end = trace.tracePath[traceSegmentIndex + 1];
|
|
1218
|
+
if (!start || !end) continue;
|
|
1219
|
+
const isVertical4 = Math.abs(start.x - end.x) < EPS4;
|
|
1220
|
+
const isHorizontal3 = Math.abs(start.y - end.y) < EPS4;
|
|
1221
|
+
if (!isVertical4 && !isHorizontal3) continue;
|
|
1222
|
+
const shiftedSegment = isVertical4 ? [
|
|
1223
|
+
{ ...start, x: start.x + offset },
|
|
1224
|
+
{ ...end, x: end.x + offset }
|
|
1225
|
+
] : [
|
|
1226
|
+
{ ...start, y: start.y + offset },
|
|
1227
|
+
{ ...end, y: end.y + offset }
|
|
1228
|
+
];
|
|
1229
|
+
const collision = findFirstCollision(shiftedSegment, this.obstacleRects);
|
|
1230
|
+
if (collision) {
|
|
1231
|
+
blockingCollisions.push({
|
|
1232
|
+
start,
|
|
1233
|
+
isVertical: isVertical4,
|
|
1234
|
+
obstacle: collision.rect
|
|
1235
|
+
});
|
|
1236
|
+
}
|
|
1237
|
+
}
|
|
1238
|
+
return blockingCollisions;
|
|
1239
|
+
}
|
|
1189
1240
|
visualize() {
|
|
1190
1241
|
const graphics = {
|
|
1191
1242
|
lines: [],
|
|
@@ -1258,7 +1309,7 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
|
|
|
1258
1309
|
return islands;
|
|
1259
1310
|
}
|
|
1260
1311
|
findNextOverlapIssue() {
|
|
1261
|
-
const
|
|
1312
|
+
const EPS11 = 2e-3;
|
|
1262
1313
|
const netIds = Object.keys(this.traceNetIslands);
|
|
1263
1314
|
for (let i = 0; i < netIds.length; i++) {
|
|
1264
1315
|
for (let j = i + 1; j < netIds.length; j++) {
|
|
@@ -1276,7 +1327,7 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
|
|
|
1276
1327
|
const minB = Math.min(b1, b2);
|
|
1277
1328
|
const maxB = Math.max(b1, b2);
|
|
1278
1329
|
const overlap = Math.min(maxA, maxB) - Math.max(minA, minB);
|
|
1279
|
-
return overlap >
|
|
1330
|
+
return overlap > EPS11;
|
|
1280
1331
|
};
|
|
1281
1332
|
for (let pa = 0; pa < pathsA.length; pa++) {
|
|
1282
1333
|
const pathA = pathsA[pa];
|
|
@@ -1284,8 +1335,8 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
|
|
|
1284
1335
|
for (let sa = 0; sa < ptsA.length - 1; sa++) {
|
|
1285
1336
|
const a1 = ptsA[sa];
|
|
1286
1337
|
const a2 = ptsA[sa + 1];
|
|
1287
|
-
const aVert = Math.abs(a1.x - a2.x) <
|
|
1288
|
-
const aHorz = Math.abs(a1.y - a2.y) <
|
|
1338
|
+
const aVert = Math.abs(a1.x - a2.x) < EPS11;
|
|
1339
|
+
const aHorz = Math.abs(a1.y - a2.y) < EPS11;
|
|
1289
1340
|
if (!aVert && !aHorz) continue;
|
|
1290
1341
|
for (let pb = 0; pb < pathsB.length; pb++) {
|
|
1291
1342
|
const pathB = pathsB[pb];
|
|
@@ -1293,11 +1344,11 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
|
|
|
1293
1344
|
for (let sb = 0; sb < ptsB.length - 1; sb++) {
|
|
1294
1345
|
const b1 = ptsB[sb];
|
|
1295
1346
|
const b2 = ptsB[sb + 1];
|
|
1296
|
-
const bVert = Math.abs(b1.x - b2.x) <
|
|
1297
|
-
const bHorz = Math.abs(b1.y - b2.y) <
|
|
1347
|
+
const bVert = Math.abs(b1.x - b2.x) < EPS11;
|
|
1348
|
+
const bHorz = Math.abs(b1.y - b2.y) < EPS11;
|
|
1298
1349
|
if (!bVert && !bHorz) continue;
|
|
1299
1350
|
if (aVert && bVert) {
|
|
1300
|
-
if (Math.abs(a1.x - b1.x) <
|
|
1351
|
+
if (Math.abs(a1.x - b1.x) < EPS11) {
|
|
1301
1352
|
if (overlaps1D(a1.y, a2.y, b1.y, b2.y)) {
|
|
1302
1353
|
const keyA = `${pa}:${sa}`;
|
|
1303
1354
|
const keyB = `${pb}:${sb}`;
|
|
@@ -1318,7 +1369,7 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
|
|
|
1318
1369
|
}
|
|
1319
1370
|
}
|
|
1320
1371
|
} else if (aHorz && bHorz) {
|
|
1321
|
-
if (Math.abs(a1.y - b1.y) <
|
|
1372
|
+
if (Math.abs(a1.y - b1.y) < EPS11) {
|
|
1322
1373
|
if (overlaps1D(a1.x, a2.x, b1.x, b2.x)) {
|
|
1323
1374
|
const keyA = `${pa}:${sa}`;
|
|
1324
1375
|
const keyB = `${pb}:${sb}`;
|
|
@@ -1356,14 +1407,14 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
|
|
|
1356
1407
|
return null;
|
|
1357
1408
|
}
|
|
1358
1409
|
findNextDiagonalSegment() {
|
|
1359
|
-
const
|
|
1410
|
+
const EPS11 = 2e-3;
|
|
1360
1411
|
for (const mspPairId in this.correctedTraceMap) {
|
|
1361
1412
|
const tracePath = this.correctedTraceMap[mspPairId].tracePath;
|
|
1362
1413
|
for (let i = 0; i < tracePath.length - 1; i++) {
|
|
1363
1414
|
const p1 = tracePath[i];
|
|
1364
1415
|
const p2 = tracePath[i + 1];
|
|
1365
|
-
const isHorizontal3 = Math.abs(p1.y - p2.y) <
|
|
1366
|
-
const isVertical4 = Math.abs(p1.x - p2.x) <
|
|
1416
|
+
const isHorizontal3 = Math.abs(p1.y - p2.y) < EPS11;
|
|
1417
|
+
const isVertical4 = Math.abs(p1.x - p2.x) < EPS11;
|
|
1367
1418
|
if (!isHorizontal3 && !isVertical4) {
|
|
1368
1419
|
return { mspPairId, tracePath, i, p1, p2 };
|
|
1369
1420
|
}
|
|
@@ -1377,13 +1428,13 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
|
|
|
1377
1428
|
return false;
|
|
1378
1429
|
}
|
|
1379
1430
|
const { mspPairId, tracePath, i, p1, p2 } = diagonalInfo;
|
|
1380
|
-
const
|
|
1431
|
+
const EPS11 = 2e-3;
|
|
1381
1432
|
const p0 = i > 0 ? tracePath[i - 1] : null;
|
|
1382
1433
|
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) <
|
|
1434
|
+
const prevIsVertical = p0 ? Math.abs(p0.x - p1.x) < EPS11 : false;
|
|
1435
|
+
const prevIsHorizontal = p0 ? Math.abs(p0.y - p1.y) < EPS11 : false;
|
|
1436
|
+
const nextIsVertical = p3 ? Math.abs(p2.x - p3.x) < EPS11 : false;
|
|
1437
|
+
const nextIsHorizontal = p3 ? Math.abs(p2.y - p3.y) < EPS11 : false;
|
|
1387
1438
|
const elbow1 = { x: p1.x, y: p2.y };
|
|
1388
1439
|
const elbow2 = { x: p2.x, y: p1.y };
|
|
1389
1440
|
let score1 = 0;
|
|
@@ -1428,6 +1479,7 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
|
|
|
1428
1479
|
}
|
|
1429
1480
|
const { overlappingTraceSegments } = overlapIssue;
|
|
1430
1481
|
this.activeSubSolver = new TraceOverlapIssueSolver({
|
|
1482
|
+
inputProblem: this.inputProblem,
|
|
1431
1483
|
overlappingTraceSegments,
|
|
1432
1484
|
traceNetIslands: this.traceNetIslands
|
|
1433
1485
|
});
|
|
@@ -1548,24 +1600,24 @@ function getRectBounds(center, w, h) {
|
|
|
1548
1600
|
}
|
|
1549
1601
|
|
|
1550
1602
|
// 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) <
|
|
1603
|
+
function segmentIntersectsRect2(p1, p2, rect, EPS11 = 1e-9) {
|
|
1604
|
+
const isVert = Math.abs(p1.x - p2.x) < EPS11;
|
|
1605
|
+
const isHorz = Math.abs(p1.y - p2.y) < EPS11;
|
|
1554
1606
|
if (!isVert && !isHorz) return false;
|
|
1555
1607
|
if (isVert) {
|
|
1556
1608
|
const x = p1.x;
|
|
1557
|
-
if (x < rect.minX -
|
|
1609
|
+
if (x < rect.minX - EPS11 || x > rect.maxX + EPS11) return false;
|
|
1558
1610
|
const segMinY = Math.min(p1.y, p2.y);
|
|
1559
1611
|
const segMaxY = Math.max(p1.y, p2.y);
|
|
1560
1612
|
const overlap = Math.min(segMaxY, rect.maxY) - Math.max(segMinY, rect.minY);
|
|
1561
|
-
return overlap >
|
|
1613
|
+
return overlap > EPS11;
|
|
1562
1614
|
} else {
|
|
1563
1615
|
const y = p1.y;
|
|
1564
|
-
if (y < rect.minY -
|
|
1616
|
+
if (y < rect.minY - EPS11 || y > rect.maxY + EPS11) return false;
|
|
1565
1617
|
const segMinX = Math.min(p1.x, p2.x);
|
|
1566
1618
|
const segMaxX = Math.max(p1.x, p2.x);
|
|
1567
1619
|
const overlap = Math.min(segMaxX, rect.maxX) - Math.max(segMinX, rect.minX);
|
|
1568
|
-
return overlap >
|
|
1620
|
+
return overlap > EPS11;
|
|
1569
1621
|
}
|
|
1570
1622
|
}
|
|
1571
1623
|
function rectIntersectsAnyTrace(bounds, inputTraceMap, hostPathId, hostSegIndex) {
|
|
@@ -1949,14 +2001,14 @@ var SingleNetLabelPlacementSolver = class extends BaseSolver {
|
|
|
1949
2001
|
};
|
|
1950
2002
|
let bestCandidate = null;
|
|
1951
2003
|
let bestScore = -Infinity;
|
|
1952
|
-
const
|
|
2004
|
+
const EPS11 = 1e-6;
|
|
1953
2005
|
for (const curr of tracesToScan) {
|
|
1954
2006
|
const pts = curr.tracePath.slice();
|
|
1955
2007
|
for (let si = 0; si < pts.length - 1; si++) {
|
|
1956
2008
|
const a = pts[si];
|
|
1957
2009
|
const b = pts[si + 1];
|
|
1958
|
-
const isH = Math.abs(a.y - b.y) <
|
|
1959
|
-
const isV = Math.abs(a.x - b.x) <
|
|
2010
|
+
const isH = Math.abs(a.y - b.y) < EPS11;
|
|
2011
|
+
const isV = Math.abs(a.x - b.x) < EPS11;
|
|
1960
2012
|
if (!isH && !isV) continue;
|
|
1961
2013
|
const segmentAllowed = isH ? ["y+", "y-"] : ["x+", "x-"];
|
|
1962
2014
|
const candidateOrients = orientations.filter(
|
|
@@ -4172,8 +4224,8 @@ var findIntersectionsWithObstacles = (p1, p2, obstacles) => {
|
|
|
4172
4224
|
};
|
|
4173
4225
|
|
|
4174
4226
|
// lib/solvers/TraceCleanupSolver/sub-solver/generateLShapeRerouteCandidates.ts
|
|
4175
|
-
var
|
|
4176
|
-
var isVertical2 = (a, b, eps =
|
|
4227
|
+
var EPS5 = 1e-6;
|
|
4228
|
+
var isVertical2 = (a, b, eps = EPS5) => Math.abs(a.x - b.x) < eps;
|
|
4177
4229
|
var generateLShapeRerouteCandidates = ({
|
|
4178
4230
|
lShape,
|
|
4179
4231
|
rectangle,
|
|
@@ -4186,7 +4238,7 @@ var generateLShapeRerouteCandidates = ({
|
|
|
4186
4238
|
let c2;
|
|
4187
4239
|
let i1_padded = interactionPoint1;
|
|
4188
4240
|
let i2_padded = interactionPoint2;
|
|
4189
|
-
if (Math.abs(p2.x - x) <
|
|
4241
|
+
if (Math.abs(p2.x - x) < EPS5 && Math.abs(p2.y - (y + height)) < EPS5) {
|
|
4190
4242
|
c2 = { x: x + width + padding, y: y - padding };
|
|
4191
4243
|
if (isVertical2(p1, p2)) {
|
|
4192
4244
|
i1_padded = { x: interactionPoint1.x, y: interactionPoint1.y - padding };
|
|
@@ -4198,7 +4250,7 @@ var generateLShapeRerouteCandidates = ({
|
|
|
4198
4250
|
} else {
|
|
4199
4251
|
i2_padded = { x: interactionPoint2.x + padding, y: interactionPoint2.y };
|
|
4200
4252
|
}
|
|
4201
|
-
} else if (Math.abs(p2.x - (x + width)) <
|
|
4253
|
+
} else if (Math.abs(p2.x - (x + width)) < EPS5 && Math.abs(p2.y - (y + height)) < EPS5) {
|
|
4202
4254
|
c2 = { x: x - padding, y: y - padding };
|
|
4203
4255
|
if (isVertical2(p1, p2)) {
|
|
4204
4256
|
i1_padded = { x: interactionPoint1.x, y: interactionPoint1.y - padding };
|
|
@@ -4210,7 +4262,7 @@ var generateLShapeRerouteCandidates = ({
|
|
|
4210
4262
|
} else {
|
|
4211
4263
|
i2_padded = { x: interactionPoint2.x - padding, y: interactionPoint2.y };
|
|
4212
4264
|
}
|
|
4213
|
-
} else if (Math.abs(p2.x - x) <
|
|
4265
|
+
} else if (Math.abs(p2.x - x) < EPS5 && Math.abs(p2.y - y) < EPS5) {
|
|
4214
4266
|
c2 = { x: x + width + padding, y: y + height + padding };
|
|
4215
4267
|
if (isVertical2(p1, p2)) {
|
|
4216
4268
|
i1_padded = { x: interactionPoint1.x, y: interactionPoint1.y + padding };
|
|
@@ -4222,7 +4274,7 @@ var generateLShapeRerouteCandidates = ({
|
|
|
4222
4274
|
} else {
|
|
4223
4275
|
i2_padded = { x: interactionPoint2.x + padding, y: interactionPoint2.y };
|
|
4224
4276
|
}
|
|
4225
|
-
} else if (Math.abs(p2.x - (x + width)) <
|
|
4277
|
+
} else if (Math.abs(p2.x - (x + width)) < EPS5 && Math.abs(p2.y - y) < EPS5) {
|
|
4226
4278
|
c2 = { x: x - padding, y: y + height + padding };
|
|
4227
4279
|
if (isVertical2(p1, p2)) {
|
|
4228
4280
|
i1_padded = { x: interactionPoint1.x, y: interactionPoint1.y + padding };
|
|
@@ -4667,9 +4719,9 @@ var UntangleTraceSubsolver = class extends BaseSolver {
|
|
|
4667
4719
|
};
|
|
4668
4720
|
|
|
4669
4721
|
// 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) <=
|
|
4722
|
+
var EPS6 = 1e-6;
|
|
4723
|
+
var sameX = (a, b) => Math.abs(a.x - b.x) <= EPS6;
|
|
4724
|
+
var sameY = (a, b) => Math.abs(a.y - b.y) <= EPS6;
|
|
4673
4725
|
var is4PointRectangle = (path) => {
|
|
4674
4726
|
if (path.length !== 4) return false;
|
|
4675
4727
|
const [p0, p1, p2, p3] = path;
|
|
@@ -4803,7 +4855,7 @@ var TraceCleanupSolver = class extends BaseSolver {
|
|
|
4803
4855
|
};
|
|
4804
4856
|
|
|
4805
4857
|
// lib/solvers/Example28Solver/types.ts
|
|
4806
|
-
var
|
|
4858
|
+
var EPS7 = 1e-9;
|
|
4807
4859
|
|
|
4808
4860
|
// lib/solvers/Example28Solver/geometry.ts
|
|
4809
4861
|
var getPathKey = (path) => path.map((point) => `${point.x},${point.y}`).join(";");
|
|
@@ -4815,10 +4867,10 @@ var getPathLength = (path) => {
|
|
|
4815
4867
|
return length;
|
|
4816
4868
|
};
|
|
4817
4869
|
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) <
|
|
4870
|
+
var isAxisAlignedSegment = (start, end) => Math.abs(start.x - end.x) < EPS7 || Math.abs(start.y - end.y) < EPS7;
|
|
4871
|
+
var getSegmentOrientation = (start, end) => Math.abs(start.y - end.y) < EPS7 ? "horizontal" : "vertical";
|
|
4820
4872
|
var projectPointToSegment = (point, start, end) => {
|
|
4821
|
-
if (Math.abs(start.x - end.x) <
|
|
4873
|
+
if (Math.abs(start.x - end.x) < EPS7) {
|
|
4822
4874
|
return {
|
|
4823
4875
|
x: start.x,
|
|
4824
4876
|
y: Math.min(
|
|
@@ -4827,7 +4879,7 @@ var projectPointToSegment = (point, start, end) => {
|
|
|
4827
4879
|
)
|
|
4828
4880
|
};
|
|
4829
4881
|
}
|
|
4830
|
-
if (Math.abs(start.y - end.y) <
|
|
4882
|
+
if (Math.abs(start.y - end.y) < EPS7) {
|
|
4831
4883
|
return {
|
|
4832
4884
|
x: Math.min(
|
|
4833
4885
|
Math.max(point.x, Math.min(start.x, end.x)),
|
|
@@ -4870,9 +4922,9 @@ var findSegmentContainingPoint = (path, point) => {
|
|
|
4870
4922
|
};
|
|
4871
4923
|
var isPointWithinSegmentPrimaryRange = (point, segment) => {
|
|
4872
4924
|
if (segment.orientation === "horizontal") {
|
|
4873
|
-
return point.x >= Math.min(segment.start.x, segment.end.x) -
|
|
4925
|
+
return point.x >= Math.min(segment.start.x, segment.end.x) - EPS7 && point.x <= Math.max(segment.start.x, segment.end.x) + EPS7;
|
|
4874
4926
|
}
|
|
4875
|
-
return point.y >= Math.min(segment.start.y, segment.end.y) -
|
|
4927
|
+
return point.y >= Math.min(segment.start.y, segment.end.y) - EPS7 && point.y <= Math.max(segment.start.y, segment.end.y) + EPS7;
|
|
4876
4928
|
};
|
|
4877
4929
|
var findPreferredReroutedSegment = (path, originalSegmentIndex, originalSegmentCount, orientation, anchorPoint) => {
|
|
4878
4930
|
const matchingSegments = getSegments(path).filter(
|
|
@@ -4900,18 +4952,18 @@ var projectPointToPath = (point, path) => {
|
|
|
4900
4952
|
return bestPoint;
|
|
4901
4953
|
};
|
|
4902
4954
|
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) -
|
|
4955
|
+
const aVertical = Math.abs(a1.x - a2.x) < EPS7;
|
|
4956
|
+
const bVertical = Math.abs(b1.x - b2.x) < EPS7;
|
|
4957
|
+
const between = (value, p1, p2) => value >= Math.min(p1, p2) - EPS7 && value <= Math.max(p1, p2) + EPS7;
|
|
4906
4958
|
if (aVertical && bVertical) {
|
|
4907
|
-
if (Math.abs(a1.x - b1.x) >
|
|
4959
|
+
if (Math.abs(a1.x - b1.x) > EPS7) return false;
|
|
4908
4960
|
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 >
|
|
4961
|
+
return overlap > EPS7;
|
|
4910
4962
|
}
|
|
4911
4963
|
if (!aVertical && !bVertical) {
|
|
4912
|
-
if (Math.abs(a1.y - b1.y) >
|
|
4964
|
+
if (Math.abs(a1.y - b1.y) > EPS7) return false;
|
|
4913
4965
|
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 >
|
|
4966
|
+
return overlap > EPS7;
|
|
4915
4967
|
}
|
|
4916
4968
|
const verticalA = aVertical ? a1 : b1;
|
|
4917
4969
|
const verticalB = aVertical ? a2 : b2;
|
|
@@ -4943,13 +4995,13 @@ var isPathCollidingWithChipInterior = (path, chipObstacles) => {
|
|
|
4943
4995
|
return false;
|
|
4944
4996
|
};
|
|
4945
4997
|
var segmentRunsAlongRectBoundary = (start, end, rect) => {
|
|
4946
|
-
const isVertical4 = Math.abs(start.x - end.x) <
|
|
4947
|
-
const isHorizontal3 = Math.abs(start.y - end.y) <
|
|
4998
|
+
const isVertical4 = Math.abs(start.x - end.x) < EPS7;
|
|
4999
|
+
const isHorizontal3 = Math.abs(start.y - end.y) < EPS7;
|
|
4948
5000
|
if (isVertical4) {
|
|
4949
|
-
return Math.abs(start.x - rect.minX) <
|
|
5001
|
+
return Math.abs(start.x - rect.minX) < EPS7 || Math.abs(start.x - rect.maxX) < EPS7;
|
|
4950
5002
|
}
|
|
4951
5003
|
if (isHorizontal3) {
|
|
4952
|
-
return Math.abs(start.y - rect.minY) <
|
|
5004
|
+
return Math.abs(start.y - rect.minY) < EPS7 || Math.abs(start.y - rect.maxY) < EPS7;
|
|
4953
5005
|
}
|
|
4954
5006
|
return false;
|
|
4955
5007
|
};
|
|
@@ -5573,16 +5625,16 @@ var Example28Solver = class extends BaseSolver {
|
|
|
5573
5625
|
// lib/solvers/AvailableNetOrientationSolver/constants.ts
|
|
5574
5626
|
var LABEL_SEARCH_STEP = 0.05;
|
|
5575
5627
|
var WICK_CLEARANCE = 1e-3;
|
|
5576
|
-
var
|
|
5577
|
-
var TRACE_BOUNDARY_TOLERANCE = WICK_CLEARANCE +
|
|
5628
|
+
var EPS8 = 1e-9;
|
|
5629
|
+
var TRACE_BOUNDARY_TOLERANCE = WICK_CLEARANCE + EPS8;
|
|
5578
5630
|
var CANDIDATE_SELECTED_COLOR2 = "blue";
|
|
5579
5631
|
var CANDIDATE_REJECTED_COLOR2 = "red";
|
|
5580
5632
|
|
|
5581
5633
|
// lib/solvers/AvailableNetOrientationSolver/geometry.ts
|
|
5582
5634
|
var isYOrientation = (orientation) => orientation === "y+" || orientation === "y-";
|
|
5583
5635
|
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) >
|
|
5636
|
+
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;
|
|
5637
|
+
var rangesOverlap = (minA, maxA, minB, maxB) => Math.min(maxA, maxB) - Math.max(minA, minB) > EPS8;
|
|
5586
5638
|
var traceCrossesBoundsInterior = (bounds, traceMap) => {
|
|
5587
5639
|
for (const trace of Object.values(traceMap)) {
|
|
5588
5640
|
const points = trace.tracePath;
|
|
@@ -5605,7 +5657,7 @@ var segmentCrossesBoundsInterior = (p1, p2, bounds) => {
|
|
|
5605
5657
|
return false;
|
|
5606
5658
|
}
|
|
5607
5659
|
if (sameX2(p1, p2)) {
|
|
5608
|
-
if (p1.x <= interiorBounds.minX +
|
|
5660
|
+
if (p1.x <= interiorBounds.minX + EPS8 || p1.x >= interiorBounds.maxX - EPS8) {
|
|
5609
5661
|
return false;
|
|
5610
5662
|
}
|
|
5611
5663
|
return rangesOverlap(
|
|
@@ -5616,7 +5668,7 @@ var segmentCrossesBoundsInterior = (p1, p2, bounds) => {
|
|
|
5616
5668
|
);
|
|
5617
5669
|
}
|
|
5618
5670
|
if (sameY2(p1, p2)) {
|
|
5619
|
-
if (p1.y <= interiorBounds.minY +
|
|
5671
|
+
if (p1.y <= interiorBounds.minY + EPS8 || p1.y >= interiorBounds.maxY - EPS8) {
|
|
5620
5672
|
return false;
|
|
5621
5673
|
}
|
|
5622
5674
|
return rangesOverlap(
|
|
@@ -5664,10 +5716,10 @@ var tracePathCrossesAnyTrace = (tracePath, traceMap) => {
|
|
|
5664
5716
|
};
|
|
5665
5717
|
var segmentsStrictlyCross = (a1, a2, b1, b2) => {
|
|
5666
5718
|
if (sameX2(a1, a2) && sameY2(b1, b2)) {
|
|
5667
|
-
return a1.x > Math.min(b1.x, b2.x) +
|
|
5719
|
+
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
5720
|
}
|
|
5669
5721
|
if (sameY2(a1, a2) && sameX2(b1, b2)) {
|
|
5670
|
-
return b1.x > Math.min(a1.x, a2.x) +
|
|
5722
|
+
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
5723
|
}
|
|
5672
5724
|
return false;
|
|
5673
5725
|
};
|
|
@@ -5699,8 +5751,8 @@ var simplifyOrthogonalPath = (path) => {
|
|
|
5699
5751
|
return simplified;
|
|
5700
5752
|
};
|
|
5701
5753
|
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) <=
|
|
5754
|
+
var sameX2 = (a, b) => Math.abs(a.x - b.x) <= EPS8;
|
|
5755
|
+
var sameY2 = (a, b) => Math.abs(a.y - b.y) <= EPS8;
|
|
5704
5756
|
var getMaxSearchDistance = (inputProblem) => {
|
|
5705
5757
|
const maxChipWidth = Math.max(
|
|
5706
5758
|
...inputProblem.chips.map((chip) => chip.width),
|
|
@@ -5988,7 +6040,7 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
5988
6040
|
);
|
|
5989
6041
|
const maxSearchDistance = this.getSearchDistanceLimit(label, orientation);
|
|
5990
6042
|
const maxOutwardDistance = outwardDirection.x === 0 && outwardDirection.y === 0 ? 0 : this.maxSearchDistance;
|
|
5991
|
-
for (let outwardDistance = 0; outwardDistance <= maxOutwardDistance +
|
|
6043
|
+
for (let outwardDistance = 0; outwardDistance <= maxOutwardDistance + EPS8; outwardDistance += LABEL_SEARCH_STEP) {
|
|
5992
6044
|
const baseAnchor = {
|
|
5993
6045
|
x: initialBaseAnchor.x + outwardDirection.x * outwardDistance,
|
|
5994
6046
|
y: initialBaseAnchor.y + outwardDirection.y * outwardDistance
|
|
@@ -6061,7 +6113,7 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
6061
6113
|
outwardDistance,
|
|
6062
6114
|
phase = "shift"
|
|
6063
6115
|
} = params;
|
|
6064
|
-
for (let distance3 = LABEL_SEARCH_STEP; distance3 <= maxSearchDistance +
|
|
6116
|
+
for (let distance3 = LABEL_SEARCH_STEP; distance3 <= maxSearchDistance + EPS8; distance3 += LABEL_SEARCH_STEP) {
|
|
6065
6117
|
const anchorPoint = {
|
|
6066
6118
|
x: baseAnchor.x + direction.x * distance3,
|
|
6067
6119
|
y: baseAnchor.y + direction.y * distance3
|
|
@@ -6299,8 +6351,8 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
6299
6351
|
sharesChipBoundary(bounds) {
|
|
6300
6352
|
for (const chip of this.chipObstacleSpatialIndex.chips) {
|
|
6301
6353
|
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 +
|
|
6354
|
+
const adjacentToVerticalSide = Math.abs(bounds.minX - chipBounds.maxX) <= WICK_CLEARANCE + EPS8 || Math.abs(bounds.maxX - chipBounds.minX) <= WICK_CLEARANCE + EPS8;
|
|
6355
|
+
const adjacentToHorizontalSide = Math.abs(bounds.minY - chipBounds.maxY) <= WICK_CLEARANCE + EPS8 || Math.abs(bounds.maxY - chipBounds.minY) <= WICK_CLEARANCE + EPS8;
|
|
6304
6356
|
if (adjacentToVerticalSide && rangesOverlap(
|
|
6305
6357
|
bounds.minY,
|
|
6306
6358
|
bounds.maxY,
|
|
@@ -6348,7 +6400,7 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
6348
6400
|
let nearestDistance = Number.POSITIVE_INFINITY;
|
|
6349
6401
|
for (const chip of this.chipObstacleSpatialIndex.chips) {
|
|
6350
6402
|
const bounds = chip.bounds;
|
|
6351
|
-
if (point.x < bounds.minX -
|
|
6403
|
+
if (point.x < bounds.minX - EPS8 || point.x > bounds.maxX + EPS8 || point.y < bounds.minY - EPS8 || point.y > bounds.maxY + EPS8) {
|
|
6352
6404
|
continue;
|
|
6353
6405
|
}
|
|
6354
6406
|
for (const [side, distance3] of getSideDistances(point, bounds)) {
|
|
@@ -6365,8 +6417,8 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
6365
6417
|
let nearestDistanceSq = Number.POSITIVE_INFINITY;
|
|
6366
6418
|
for (const chip of this.chipObstacleSpatialIndex.chips) {
|
|
6367
6419
|
const bounds = chip.bounds;
|
|
6368
|
-
const dx = point.x < bounds.minX -
|
|
6369
|
-
const dy = point.y < bounds.minY -
|
|
6420
|
+
const dx = point.x < bounds.minX - EPS8 ? bounds.minX - point.x : point.x > bounds.maxX + EPS8 ? point.x - bounds.maxX : 0;
|
|
6421
|
+
const dy = point.y < bounds.minY - EPS8 ? bounds.minY - point.y : point.y > bounds.maxY + EPS8 ? point.y - bounds.maxY : 0;
|
|
6370
6422
|
if (dx === 0 && dy === 0) continue;
|
|
6371
6423
|
const distanceSq = dx ** 2 + dy ** 2;
|
|
6372
6424
|
if (distanceSq >= nearestDistanceSq) continue;
|
|
@@ -6405,9 +6457,9 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
6405
6457
|
};
|
|
6406
6458
|
|
|
6407
6459
|
// lib/solvers/VccNetLabelCornerPlacementSolver/geometry.ts
|
|
6408
|
-
var
|
|
6460
|
+
var EPS9 = 1e-6;
|
|
6409
6461
|
var isTraceLine = (trace) => getUniquePinCount(trace.pinIds) >= 2;
|
|
6410
|
-
var rectsOverlap2 = (a, b) => Math.min(a.maxX, b.maxX) - Math.max(a.minX, b.minX) >
|
|
6462
|
+
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
6463
|
var getTraceCorners = (path) => {
|
|
6412
6464
|
const corners = [];
|
|
6413
6465
|
for (let i = 1; i < path.length - 1; i++) {
|
|
@@ -6431,11 +6483,11 @@ var getUniquePinCount = (pinIds) => new Set(pinIds).size;
|
|
|
6431
6483
|
var isTraceCorner = (a, b, c) => getSegmentOrientation2(a, b) !== getSegmentOrientation2(b, c);
|
|
6432
6484
|
var isPointOnSegment = (point, start, end) => {
|
|
6433
6485
|
if (getSegmentOrientation2(start, end) === "horizontal") {
|
|
6434
|
-
return Math.abs(point.y - start.y) <=
|
|
6486
|
+
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
6487
|
}
|
|
6436
|
-
return Math.abs(point.x - start.x) <=
|
|
6488
|
+
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
6489
|
};
|
|
6438
|
-
var getSegmentOrientation2 = (a, b) => Math.abs(a.y - b.y) <=
|
|
6490
|
+
var getSegmentOrientation2 = (a, b) => Math.abs(a.y - b.y) <= EPS9 ? "horizontal" : "vertical";
|
|
6439
6491
|
|
|
6440
6492
|
// lib/solvers/VccNetLabelCornerPlacementSolver/visualize.ts
|
|
6441
6493
|
var CANDIDATE_SELECTED_COLOR3 = "blue";
|
|
@@ -6713,11 +6765,11 @@ var VccNetLabelCornerPlacementSolver = class extends BaseSolver {
|
|
|
6713
6765
|
};
|
|
6714
6766
|
|
|
6715
6767
|
// lib/solvers/TraceAnchoredNetLabelOverlapSolver/geometry.ts
|
|
6716
|
-
var
|
|
6768
|
+
var EPS10 = 1e-6;
|
|
6717
6769
|
var TRACE_BOUNDARY_TOLERANCE2 = 1e-6;
|
|
6718
6770
|
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) >= -
|
|
6771
|
+
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;
|
|
6772
|
+
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
6773
|
var traceCrossesBoundsInterior2 = (bounds, traces) => {
|
|
6722
6774
|
for (const trace of traces) {
|
|
6723
6775
|
const points = trace.tracePath;
|
|
@@ -6763,7 +6815,7 @@ var getPointAtTraceDistance = (trace, distance3) => {
|
|
|
6763
6815
|
const end = trace.tracePath[i + 1];
|
|
6764
6816
|
const segmentLength = getManhattanDistance(start, end);
|
|
6765
6817
|
const nextDistance = pathDistance + segmentLength;
|
|
6766
|
-
if (distance3 <= nextDistance +
|
|
6818
|
+
if (distance3 <= nextDistance + EPS10) {
|
|
6767
6819
|
const offset = Math.max(
|
|
6768
6820
|
0,
|
|
6769
6821
|
Math.min(segmentLength, distance3 - pathDistance)
|
|
@@ -6802,7 +6854,7 @@ var segmentCrossesBoundsInterior2 = (start, end, bounds) => {
|
|
|
6802
6854
|
return false;
|
|
6803
6855
|
}
|
|
6804
6856
|
if (isVertical3(start, end)) {
|
|
6805
|
-
if (start.x <= interior.minX +
|
|
6857
|
+
if (start.x <= interior.minX + EPS10 || start.x >= interior.maxX - EPS10) {
|
|
6806
6858
|
return false;
|
|
6807
6859
|
}
|
|
6808
6860
|
return rangesOverlap2(
|
|
@@ -6813,7 +6865,7 @@ var segmentCrossesBoundsInterior2 = (start, end, bounds) => {
|
|
|
6813
6865
|
);
|
|
6814
6866
|
}
|
|
6815
6867
|
if (isHorizontal2(start, end)) {
|
|
6816
|
-
if (start.y <= interior.minY +
|
|
6868
|
+
if (start.y <= interior.minY + EPS10 || start.y >= interior.maxY - EPS10) {
|
|
6817
6869
|
return false;
|
|
6818
6870
|
}
|
|
6819
6871
|
return rangesOverlap2(
|
|
@@ -6827,10 +6879,10 @@ var segmentCrossesBoundsInterior2 = (start, end, bounds) => {
|
|
|
6827
6879
|
};
|
|
6828
6880
|
var isPointOnSegment2 = (point, start, end) => {
|
|
6829
6881
|
if (isHorizontal2(start, end)) {
|
|
6830
|
-
return Math.abs(point.y - start.y) <=
|
|
6882
|
+
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
6883
|
}
|
|
6832
6884
|
if (isVertical3(start, end)) {
|
|
6833
|
-
return Math.abs(point.x - start.x) <=
|
|
6885
|
+
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
6886
|
}
|
|
6835
6887
|
return false;
|
|
6836
6888
|
};
|
|
@@ -6838,9 +6890,9 @@ var getSegmentDirection = (start, end) => ({
|
|
|
6838
6890
|
x: isVertical3(start, end) ? 0 : Math.sign(end.x - start.x),
|
|
6839
6891
|
y: isHorizontal2(start, end) ? 0 : Math.sign(end.y - start.y)
|
|
6840
6892
|
});
|
|
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) >
|
|
6893
|
+
var isHorizontal2 = (start, end) => Math.abs(start.y - end.y) <= EPS10;
|
|
6894
|
+
var isVertical3 = (start, end) => Math.abs(start.x - end.x) <= EPS10;
|
|
6895
|
+
var rangesOverlap2 = (minA, maxA, minB, maxB) => Math.min(maxA, maxB) - Math.max(minA, minB) > EPS10;
|
|
6844
6896
|
var getUniquePinCount2 = (pinIds) => new Set(pinIds).size;
|
|
6845
6897
|
|
|
6846
6898
|
// lib/solvers/TraceAnchoredNetLabelOverlapSolver/candidates.ts
|
|
@@ -6897,7 +6949,7 @@ var getCandidateDistances = (traceLength, vertexDistances) => {
|
|
|
6897
6949
|
for (const distance3 of vertexDistances) {
|
|
6898
6950
|
distances.add(roundDistance(distance3));
|
|
6899
6951
|
}
|
|
6900
|
-
return [...distances].filter((distance3) => distance3 >= -
|
|
6952
|
+
return [...distances].filter((distance3) => distance3 >= -EPS10 && distance3 <= traceLength + EPS10).sort((a, b) => a - b);
|
|
6901
6953
|
};
|
|
6902
6954
|
var getOrientationsForPoint = (params) => {
|
|
6903
6955
|
const { inputProblem, label, point, orientationConstraint } = params;
|
|
@@ -7006,13 +7058,13 @@ var getOutwardOrientationOptions = (point, chipBounds) => {
|
|
|
7006
7058
|
};
|
|
7007
7059
|
var getOutwardAxisOption = (params) => {
|
|
7008
7060
|
const { value, min, max, center, positiveOrientation, negativeOrientation } = params;
|
|
7009
|
-
if (value > max +
|
|
7061
|
+
if (value > max + EPS10) {
|
|
7010
7062
|
return {
|
|
7011
7063
|
orientation: positiveOrientation,
|
|
7012
7064
|
outwardScore: 1 + value - max
|
|
7013
7065
|
};
|
|
7014
7066
|
}
|
|
7015
|
-
if (value < min -
|
|
7067
|
+
if (value < min - EPS10) {
|
|
7016
7068
|
return {
|
|
7017
7069
|
orientation: negativeOrientation,
|
|
7018
7070
|
outwardScore: 1 + min - value
|
|
@@ -7023,7 +7075,7 @@ var getOutwardAxisOption = (params) => {
|
|
|
7023
7075
|
outwardScore: getNormalizedCenterDistance(value, center, max - min)
|
|
7024
7076
|
};
|
|
7025
7077
|
};
|
|
7026
|
-
var getNormalizedCenterDistance = (value, center, span) => Math.abs(value - center) / Math.max(
|
|
7078
|
+
var getNormalizedCenterDistance = (value, center, span) => Math.abs(value - center) / Math.max(EPS10, span / 2);
|
|
7027
7079
|
var ALL_ORIENTATIONS = ["x+", "x-", "y+", "y-"];
|
|
7028
7080
|
var getFlippedOrientation = (orientation) => {
|
|
7029
7081
|
switch (orientation) {
|
|
@@ -7118,7 +7170,7 @@ var normalizeFacingDirection = (value) => {
|
|
|
7118
7170
|
var dedupeStrings = (values) => [
|
|
7119
7171
|
...new Set(values.filter((value) => value !== void 0))
|
|
7120
7172
|
];
|
|
7121
|
-
var isSamePlacement = (label, point, orientation) => Math.abs(point.x - label.anchorPoint.x) <=
|
|
7173
|
+
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
7174
|
|
|
7123
7175
|
// lib/solvers/TraceAnchoredNetLabelOverlapSolver/visualize.ts
|
|
7124
7176
|
var CANDIDATE_SELECTED_COLOR4 = "blue";
|
package/lib/solvers/TraceOverlapShiftSolver/TraceOverlapIssueSolver/TraceOverlapIssueSolver.ts
CHANGED
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
import type { GraphicsObject } from "graphics-debug"
|
|
2
2
|
import { BaseSolver } from "lib/solvers/BaseSolver/BaseSolver"
|
|
3
3
|
import type { MspConnectionPairId } from "lib/solvers/MspConnectionPairSolver/MspConnectionPairSolver"
|
|
4
|
+
import { findFirstCollision } from "lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver2/collisions"
|
|
5
|
+
import { getObstacleRects } from "lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver2/rect"
|
|
4
6
|
import type { SolvedTracePath } from "lib/solvers/SchematicTraceLinesSolver/SchematicTraceLinesSolver"
|
|
7
|
+
import type { InputProblem } from "lib/types/InputProblem"
|
|
5
8
|
import { applyJogToTerminalSegment } from "./applyJogToTrace"
|
|
6
9
|
|
|
7
10
|
type ConnNetId = string
|
|
8
11
|
|
|
12
|
+
const EPS = 1e-6
|
|
13
|
+
|
|
9
14
|
export interface OverlappingTraceSegmentLocator {
|
|
10
15
|
connNetId: string
|
|
11
16
|
pathsWithOverlap: Array<{
|
|
@@ -17,18 +22,21 @@ export interface OverlappingTraceSegmentLocator {
|
|
|
17
22
|
export class TraceOverlapIssueSolver extends BaseSolver {
|
|
18
23
|
overlappingTraceSegments: OverlappingTraceSegmentLocator[]
|
|
19
24
|
traceNetIslands: Record<ConnNetId, Array<SolvedTracePath>>
|
|
25
|
+
obstacleRects: ReturnType<typeof getObstacleRects>
|
|
20
26
|
|
|
21
27
|
SHIFT_DISTANCE = 0.1
|
|
22
28
|
|
|
23
29
|
correctedTraceMap: Record<MspConnectionPairId, SolvedTracePath> = {}
|
|
24
30
|
|
|
25
31
|
constructor(params: {
|
|
32
|
+
inputProblem: InputProblem
|
|
26
33
|
overlappingTraceSegments: OverlappingTraceSegmentLocator[]
|
|
27
34
|
traceNetIslands: Record<ConnNetId, Array<SolvedTracePath>>
|
|
28
35
|
}) {
|
|
29
36
|
super()
|
|
30
37
|
this.overlappingTraceSegments = params.overlappingTraceSegments
|
|
31
38
|
this.traceNetIslands = params.traceNetIslands
|
|
39
|
+
this.obstacleRects = getObstacleRects(params.inputProblem)
|
|
32
40
|
|
|
33
41
|
// Only add the relevant traces to the correctedTraceMap
|
|
34
42
|
for (const { connNetId, pathsWithOverlap } of this
|
|
@@ -49,13 +57,14 @@ export class TraceOverlapIssueSolver extends BaseSolver {
|
|
|
49
57
|
// Shift only the overlapping segments, and move the shared endpoints
|
|
50
58
|
// (the last point of the previous segment and the first point of the next
|
|
51
59
|
// segment) so the polyline remains orthogonal without self-overlap.
|
|
52
|
-
const EPS = 1e-6
|
|
53
|
-
|
|
54
60
|
// Compute offsets for each island involved: alternate directions
|
|
55
|
-
const offsets = this.overlappingTraceSegments.map((
|
|
61
|
+
const offsets = this.overlappingTraceSegments.map((group, idx) => {
|
|
56
62
|
const n = Math.floor(idx / 2) + 1
|
|
57
63
|
const signed = idx % 2 === 0 ? -n : n
|
|
58
|
-
return
|
|
64
|
+
return this.getObstacleAwareOffset({
|
|
65
|
+
group,
|
|
66
|
+
offset: signed * this.SHIFT_DISTANCE,
|
|
67
|
+
})
|
|
59
68
|
})
|
|
60
69
|
|
|
61
70
|
const eq = (a: number, b: number) => Math.abs(a - b) < EPS
|
|
@@ -82,8 +91,6 @@ export class TraceOverlapIssueSolver extends BaseSolver {
|
|
|
82
91
|
const current = this.correctedTraceMap[original.mspPairId] ?? original
|
|
83
92
|
const pts = current.tracePath.map((p) => ({ ...p }))
|
|
84
93
|
|
|
85
|
-
const segIdxs = Array.from(segIdxSet).sort((a, b) => a - b)
|
|
86
|
-
|
|
87
94
|
const segIdxsRev = Array.from(segIdxSet)
|
|
88
95
|
.sort((a, b) => a - b)
|
|
89
96
|
.reverse()
|
|
@@ -142,6 +149,82 @@ export class TraceOverlapIssueSolver extends BaseSolver {
|
|
|
142
149
|
this.solved = true
|
|
143
150
|
}
|
|
144
151
|
|
|
152
|
+
private getObstacleAwareOffset({
|
|
153
|
+
group,
|
|
154
|
+
offset,
|
|
155
|
+
}: {
|
|
156
|
+
group: OverlappingTraceSegmentLocator
|
|
157
|
+
offset: number
|
|
158
|
+
}) {
|
|
159
|
+
const blockingCollisions = this.getBlockingCollisions({ group, offset })
|
|
160
|
+
if (blockingCollisions.length === 0) return offset
|
|
161
|
+
|
|
162
|
+
return (
|
|
163
|
+
blockingCollisions
|
|
164
|
+
.flatMap(({ start, isVertical, obstacle }) => [
|
|
165
|
+
(isVertical ? obstacle.minX - start.x : obstacle.minY - start.y) -
|
|
166
|
+
this.SHIFT_DISTANCE,
|
|
167
|
+
(isVertical ? obstacle.maxX - start.x : obstacle.maxY - start.y) +
|
|
168
|
+
this.SHIFT_DISTANCE,
|
|
169
|
+
])
|
|
170
|
+
.filter(
|
|
171
|
+
(candidateOffset) =>
|
|
172
|
+
this.getBlockingCollisions({ group, offset: candidateOffset })
|
|
173
|
+
.length === 0,
|
|
174
|
+
)
|
|
175
|
+
.sort((a, b) => Math.abs(a - offset) - Math.abs(b - offset))[0] ??
|
|
176
|
+
offset
|
|
177
|
+
)
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
private getBlockingCollisions({
|
|
181
|
+
group,
|
|
182
|
+
offset,
|
|
183
|
+
}: {
|
|
184
|
+
group: OverlappingTraceSegmentLocator
|
|
185
|
+
offset: number
|
|
186
|
+
}) {
|
|
187
|
+
const blockingCollisions: Array<{
|
|
188
|
+
start: SolvedTracePath["tracePath"][number]
|
|
189
|
+
isVertical: boolean
|
|
190
|
+
obstacle: ReturnType<typeof getObstacleRects>[number]
|
|
191
|
+
}> = []
|
|
192
|
+
|
|
193
|
+
for (const {
|
|
194
|
+
solvedTracePathIndex,
|
|
195
|
+
traceSegmentIndex,
|
|
196
|
+
} of group.pathsWithOverlap) {
|
|
197
|
+
const trace = this.traceNetIslands[group.connNetId][solvedTracePathIndex]!
|
|
198
|
+
const start = trace.tracePath[traceSegmentIndex]
|
|
199
|
+
const end = trace.tracePath[traceSegmentIndex + 1]
|
|
200
|
+
if (!start || !end) continue
|
|
201
|
+
|
|
202
|
+
const isVertical = Math.abs(start.x - end.x) < EPS
|
|
203
|
+
const isHorizontal = Math.abs(start.y - end.y) < EPS
|
|
204
|
+
if (!isVertical && !isHorizontal) continue
|
|
205
|
+
|
|
206
|
+
const shiftedSegment = isVertical
|
|
207
|
+
? [
|
|
208
|
+
{ ...start, x: start.x + offset },
|
|
209
|
+
{ ...end, x: end.x + offset },
|
|
210
|
+
]
|
|
211
|
+
: [
|
|
212
|
+
{ ...start, y: start.y + offset },
|
|
213
|
+
{ ...end, y: end.y + offset },
|
|
214
|
+
]
|
|
215
|
+
const collision = findFirstCollision(shiftedSegment, this.obstacleRects)
|
|
216
|
+
if (collision) {
|
|
217
|
+
blockingCollisions.push({
|
|
218
|
+
start,
|
|
219
|
+
isVertical,
|
|
220
|
+
obstacle: collision.rect,
|
|
221
|
+
})
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
return blockingCollisions
|
|
226
|
+
}
|
|
227
|
+
|
|
145
228
|
override visualize(): GraphicsObject {
|
|
146
229
|
// Visualize overlapped segments and proposed corrections
|
|
147
230
|
const graphics: GraphicsObject = {
|
|
@@ -309,6 +309,7 @@ export class TraceOverlapShiftSolver extends BaseSolver {
|
|
|
309
309
|
const { overlappingTraceSegments } = overlapIssue
|
|
310
310
|
|
|
311
311
|
this.activeSubSolver = new TraceOverlapIssueSolver({
|
|
312
|
+
inputProblem: this.inputProblem,
|
|
312
313
|
overlappingTraceSegments,
|
|
313
314
|
traceNetIslands: this.traceNetIslands,
|
|
314
315
|
})
|
package/package.json
CHANGED
|
@@ -18,7 +18,7 @@ y-" data-x="2.25" data-y="-2.6500000000000004" cx="500.642827694859" cy="536.849
|
|
|
18
18
|
</g>
|
|
19
19
|
<g>
|
|
20
20
|
<circle data-type="point" data-label="anchorPoint
|
|
21
|
-
orientation: y-" data-x="
|
|
21
|
+
orientation: y-" data-x="1.9902723250000003" data-y="-2.8500000000000005" cx="476.52218126036485" cy="555.4228855721392" r="3" fill="hsl(40, 100%, 50%, 0.9)" />
|
|
22
22
|
</g>
|
|
23
23
|
<g>
|
|
24
24
|
<circle data-type="point" data-label="anchorPoint
|
|
@@ -34,7 +34,7 @@ orientation: y+" data-x="1.9249999999999998" data-y="-0.32499999999999996" cx="4
|
|
|
34
34
|
<polyline data-points="1.7999999999999998,-0.32499999999999996 1.9249999999999998,-0.32499999999999996 1.9249999999999998,-1.1 2.25,-1.1 2.25,-0.9" data-type="line" data-label="" points="458.8517829187396,320.9286898839137 470.46040646766164,320.9286898839137 470.46040646766164,392.9021558872305 500.642827694859,392.9021558872305 500.642827694859,374.3283582089552" fill="none" stroke="purple" stroke-width="1" />
|
|
35
35
|
</g>
|
|
36
36
|
<g>
|
|
37
|
-
<polyline data-points="1.7999999999999998,-0.975
|
|
37
|
+
<polyline data-points="1.7999999999999998,-0.975 1.9902723250000003,-0.975 1.9902723250000003,-2.8500000000000005 2.25,-2.8500000000000005 2.25,-2.6500000000000004" data-type="line" data-label="" points="458.8517829187396,381.2935323383084 476.52218126036485,381.2935323383084 476.52218126036485,555.4228855721392 500.642827694859,555.4228855721392 500.642827694859,536.849087893864" fill="none" stroke="purple" stroke-width="1" />
|
|
38
38
|
</g>
|
|
39
39
|
<g>
|
|
40
40
|
<rect data-type="rect" data-label="schematic_component_0" data-x="0" data-y="0" x="124.52342470978448" y="40" width="334.32835820895514" height="501.49253731343276" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.010767857142857145" />
|
|
@@ -47,7 +47,7 @@ orientation: y+" data-x="1.9249999999999998" data-y="-0.32499999999999996" cx="4
|
|
|
47
47
|
</g>
|
|
48
48
|
<g>
|
|
49
49
|
<rect data-type="rect" data-label="netId: GND
|
|
50
|
-
globalConnNetId: connectivity_net1" data-x="
|
|
50
|
+
globalConnNetId: connectivity_net1" data-x="1.9902723250000003" data-y="-3.0900000000000007" x="467.2352824212272" y="555.4228855721392" width="18.573797678275298" height="44.577114427860806" fill="#00000066" stroke="#000000" stroke-width="0.010767857142857145" />
|
|
51
51
|
</g>
|
|
52
52
|
<g>
|
|
53
53
|
<rect data-type="rect" data-label="netId: U1.FB to R1.pin2
|