@tscircuit/schematic-trace-solver 0.0.137 → 0.0.141
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/.github/workflows/bun-pver-release.yml +7 -3
- package/dist/index.d.ts +6 -0
- package/dist/index.js +304 -36
- package/lib/solvers/AvailableNetOrientationSolver/AvailableNetOrientationObstacleIndex.ts +182 -0
- package/lib/solvers/AvailableNetOrientationSolver/AvailableNetOrientationSolver.ts +67 -25
- package/lib/solvers/AvailableNetOrientationSolver/constants.ts +2 -0
- package/lib/solvers/Example28Solver/labelMovement.ts +71 -0
- package/lib/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver.ts +12 -4
- package/lib/solvers/TraceOverlapShiftSolver/TraceOverlapShiftSolver.ts +60 -4
- package/package.json +5 -1
- package/tests/bug-reports/bug-report-20260819T091818Z/__snapshots__/bug-report-20260819T091818Z.snap.svg +237 -0
- package/tests/bug-reports/bug-report-20260819T091818Z/bug-report-20260819T091818Z.json +1052 -0
- package/tests/bug-reports/bug-report-20260819T091818Z/bug-report-20260819T091818Z.test.ts +33 -0
- package/tests/repros/__snapshots__/board-1273-trace-overlap-cycle.snap.svg +542 -0
- package/tests/repros/__snapshots__/repro-board-648-esp12f-section.snap.svg +124 -0
- package/tests/repros/assets/board-1273-trace-overlap-cycle.input.json +3519 -0
- package/tests/repros/assets/repro-board-648-esp12f-section.input.json +537 -0
- package/tests/repros/board-1273-trace-overlap-cycle.test.ts +30 -0
- package/tests/repros/repro-board-648-esp12f-section.test.ts +13 -0
- package/tests/repros/repro161-power-section-autolayout.test.ts +7 -0
- package/tests/solvers/AvailableNetOrientationSolver/AvailableNetOrientationObstacleIndex.test.ts +122 -0
|
@@ -7,6 +7,10 @@ on:
|
|
|
7
7
|
paths:
|
|
8
8
|
- 'lib/**'
|
|
9
9
|
workflow_dispatch:
|
|
10
|
+
permissions:
|
|
11
|
+
contents: write
|
|
12
|
+
id-token: write
|
|
13
|
+
pull-requests: write
|
|
10
14
|
jobs:
|
|
11
15
|
publish:
|
|
12
16
|
runs-on: ubuntu-latest
|
|
@@ -18,14 +22,14 @@ jobs:
|
|
|
18
22
|
uses: oven-sh/setup-bun@v2
|
|
19
23
|
with:
|
|
20
24
|
bun-version: 1.3.1
|
|
21
|
-
- uses: actions/setup-node@
|
|
25
|
+
- uses: actions/setup-node@v6
|
|
22
26
|
with:
|
|
23
|
-
node-version:
|
|
27
|
+
node-version: 24
|
|
24
28
|
registry-url: https://registry.npmjs.org/
|
|
29
|
+
package-manager-cache: false
|
|
25
30
|
- run: npm install -g pver
|
|
26
31
|
- run: bun install --frozen-lockfile
|
|
27
32
|
- run: bun run build
|
|
28
33
|
- run: pver release
|
|
29
34
|
env:
|
|
30
|
-
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
31
35
|
GITHUB_TOKEN: ${{ secrets.TSCIRCUIT_BOT_GITHUB_TOKEN }}
|
package/dist/index.d.ts
CHANGED
|
@@ -279,6 +279,7 @@ declare class TraceOverlapIssueSolver extends BaseSolver {
|
|
|
279
279
|
}
|
|
280
280
|
|
|
281
281
|
type ConnNetId = string;
|
|
282
|
+
type TraceState = Record<MspConnectionPairId, SolvedTracePath>;
|
|
282
283
|
/**
|
|
283
284
|
* This solver finds traces that overlap or meet collinearly and aren't
|
|
284
285
|
* connected via the globalConnMap, then shifts them apart in the direction
|
|
@@ -308,6 +309,7 @@ declare class TraceOverlapShiftSolver extends BaseSolver {
|
|
|
308
309
|
*/
|
|
309
310
|
traceNetIslands: Record<ConnNetId, Array<SolvedTracePath>>;
|
|
310
311
|
correctedTraceMap: Record<MspConnectionPairId, SolvedTracePath>;
|
|
312
|
+
recentTraceStates: TraceState[];
|
|
311
313
|
cleanupPhase: "diagonals" | "done" | null;
|
|
312
314
|
constructor(params: {
|
|
313
315
|
inputProblem: InputProblem;
|
|
@@ -324,6 +326,8 @@ declare class TraceOverlapShiftSolver extends BaseSolver {
|
|
|
324
326
|
private findNextDiagonalSegment;
|
|
325
327
|
private findAndFixNextDiagonalSegment;
|
|
326
328
|
_step(): void;
|
|
329
|
+
private rememberTraceState;
|
|
330
|
+
private returnsToPreviousTraceState;
|
|
327
331
|
visualize(): graphics_debug.GraphicsObject;
|
|
328
332
|
}
|
|
329
333
|
|
|
@@ -787,6 +791,7 @@ declare class AvailableNetOrientationSolver extends BaseSolver {
|
|
|
787
791
|
private chipObstacleSpatialIndex;
|
|
788
792
|
private maxSearchDistance;
|
|
789
793
|
private pinMap;
|
|
794
|
+
private obstacleIndex;
|
|
790
795
|
constructor(params: AvailableNetOrientationSolverParams);
|
|
791
796
|
getConstructorParams(): ConstructorParameters<typeof AvailableNetOrientationSolver>[0];
|
|
792
797
|
_step(): void;
|
|
@@ -824,6 +829,7 @@ declare class AvailableNetOrientationSolver extends BaseSolver {
|
|
|
824
829
|
private findValidLateralShiftedCandidate;
|
|
825
830
|
private findValidCandidateInShiftColumn;
|
|
826
831
|
private evaluateCandidate;
|
|
832
|
+
private recordCandidateResult;
|
|
827
833
|
private getCandidateConnectorTrace;
|
|
828
834
|
private isStandaloneSinglePinNetLabel;
|
|
829
835
|
private labelIntersectsDifferentNetTrace;
|
package/dist/index.js
CHANGED
|
@@ -2102,6 +2102,7 @@ var TraceOverlapIssueSolver = class extends BaseSolver {
|
|
|
2102
2102
|
};
|
|
2103
2103
|
|
|
2104
2104
|
// lib/solvers/TraceOverlapShiftSolver/TraceOverlapShiftSolver.ts
|
|
2105
|
+
var TRACE_STATE_POSITION_EPSILON = 1e-6;
|
|
2105
2106
|
var TraceOverlapShiftSolver = class extends BaseSolver {
|
|
2106
2107
|
inputProblem;
|
|
2107
2108
|
inputTracePaths;
|
|
@@ -2112,6 +2113,9 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
|
|
|
2112
2113
|
*/
|
|
2113
2114
|
traceNetIslands = {};
|
|
2114
2115
|
correctedTraceMap = {};
|
|
2116
|
+
// Keep only the current and previous layouts to detect a two-state cycle
|
|
2117
|
+
// without accumulating routing history for the whole solve.
|
|
2118
|
+
recentTraceStates = [];
|
|
2115
2119
|
cleanupPhase = null;
|
|
2116
2120
|
constructor(params) {
|
|
2117
2121
|
super();
|
|
@@ -2123,6 +2127,7 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
|
|
|
2123
2127
|
const { mspPairId } = tracePath;
|
|
2124
2128
|
this.correctedTraceMap[mspPairId] = tracePath;
|
|
2125
2129
|
}
|
|
2130
|
+
this.rememberTraceState(this.correctedTraceMap);
|
|
2126
2131
|
this.traceNetIslands = this.computeTraceNetIslands();
|
|
2127
2132
|
}
|
|
2128
2133
|
getConstructorParams() {
|
|
@@ -2337,11 +2342,17 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
|
|
|
2337
2342
|
}
|
|
2338
2343
|
_step() {
|
|
2339
2344
|
if (this.activeSubSolver?.solved) {
|
|
2340
|
-
|
|
2341
|
-
this.
|
|
2342
|
-
|
|
2343
|
-
|
|
2345
|
+
const nextTraceState = {
|
|
2346
|
+
...this.correctedTraceMap,
|
|
2347
|
+
...this.activeSubSolver.correctedTraceMap
|
|
2348
|
+
};
|
|
2349
|
+
if (this.returnsToPreviousTraceState(nextTraceState)) {
|
|
2350
|
+
this.activeSubSolver = null;
|
|
2351
|
+
this.solved = true;
|
|
2352
|
+
return;
|
|
2344
2353
|
}
|
|
2354
|
+
this.correctedTraceMap = nextTraceState;
|
|
2355
|
+
this.rememberTraceState(nextTraceState);
|
|
2345
2356
|
this.activeSubSolver = null;
|
|
2346
2357
|
this.traceNetIslands = this.computeTraceNetIslands();
|
|
2347
2358
|
}
|
|
@@ -2374,6 +2385,34 @@ var TraceOverlapShiftSolver = class extends BaseSolver {
|
|
|
2374
2385
|
traceIdsToShift: this.traceIdsToShift
|
|
2375
2386
|
});
|
|
2376
2387
|
}
|
|
2388
|
+
rememberTraceState(traceState) {
|
|
2389
|
+
this.recentTraceStates.push({ ...traceState });
|
|
2390
|
+
if (this.recentTraceStates.length > 2) {
|
|
2391
|
+
this.recentTraceStates.shift();
|
|
2392
|
+
}
|
|
2393
|
+
}
|
|
2394
|
+
returnsToPreviousTraceState(candidateTraceState) {
|
|
2395
|
+
if (this.recentTraceStates.length < 2) return false;
|
|
2396
|
+
const previousTraceState = this.recentTraceStates[0];
|
|
2397
|
+
const traceIds = Object.keys(candidateTraceState);
|
|
2398
|
+
if (traceIds.length !== Object.keys(previousTraceState).length) return false;
|
|
2399
|
+
for (const traceId of traceIds) {
|
|
2400
|
+
const candidatePath = candidateTraceState[traceId];
|
|
2401
|
+
const previousPath = previousTraceState[traceId];
|
|
2402
|
+
if (!candidatePath || !previousPath) return false;
|
|
2403
|
+
if (candidatePath.tracePath.length !== previousPath.tracePath.length) {
|
|
2404
|
+
return false;
|
|
2405
|
+
}
|
|
2406
|
+
for (let i = 0; i < candidatePath.tracePath.length; i++) {
|
|
2407
|
+
const candidatePoint = candidatePath.tracePath[i];
|
|
2408
|
+
const previousPoint = previousPath.tracePath[i];
|
|
2409
|
+
if (Math.abs(candidatePoint.x - previousPoint.x) > TRACE_STATE_POSITION_EPSILON || Math.abs(candidatePoint.y - previousPoint.y) > TRACE_STATE_POSITION_EPSILON) {
|
|
2410
|
+
return false;
|
|
2411
|
+
}
|
|
2412
|
+
}
|
|
2413
|
+
}
|
|
2414
|
+
return true;
|
|
2415
|
+
}
|
|
2377
2416
|
visualize() {
|
|
2378
2417
|
if (this.activeSubSolver) {
|
|
2379
2418
|
return this.activeSubSolver.visualize();
|
|
@@ -7159,6 +7198,65 @@ var moveAttachedLabelsToReroutedTrace = ({
|
|
|
7159
7198
|
}
|
|
7160
7199
|
};
|
|
7161
7200
|
});
|
|
7201
|
+
var moveNetLabelConnectorsToReroutedTraces = ({
|
|
7202
|
+
originalTraces,
|
|
7203
|
+
reroutedTraces,
|
|
7204
|
+
netLabelPlacements
|
|
7205
|
+
}) => {
|
|
7206
|
+
const traces = [...reroutedTraces];
|
|
7207
|
+
const reroutedTraceMap = new Map(
|
|
7208
|
+
reroutedTraces.map((trace) => [trace.mspPairId, trace])
|
|
7209
|
+
);
|
|
7210
|
+
const labels = netLabelPlacements.map((label) => {
|
|
7211
|
+
const originalHostTrace = originalTraces.find((trace) => {
|
|
7212
|
+
if (!label.mspConnectionPairIds.includes(trace.mspPairId)) return false;
|
|
7213
|
+
const reroutedTrace = reroutedTraceMap.get(trace.mspPairId);
|
|
7214
|
+
if (!reroutedTrace) return false;
|
|
7215
|
+
return reroutedTrace.tracePath !== trace.tracePath;
|
|
7216
|
+
});
|
|
7217
|
+
if (!originalHostTrace) return label;
|
|
7218
|
+
const reroutedHostTrace = reroutedTraceMap.get(originalHostTrace.mspPairId);
|
|
7219
|
+
const connectorIndex = originalTraces.findIndex((trace) => {
|
|
7220
|
+
if (trace.mspPairId === originalHostTrace.mspPairId) return false;
|
|
7221
|
+
if (trace.globalConnNetId !== label.globalConnNetId) return false;
|
|
7222
|
+
if (!tracePathContainsPoint(trace.tracePath, label.anchorPoint)) {
|
|
7223
|
+
return false;
|
|
7224
|
+
}
|
|
7225
|
+
return label.pinIds.every((pinId) => trace.pinIds.includes(pinId));
|
|
7226
|
+
});
|
|
7227
|
+
if (connectorIndex < 0) return label;
|
|
7228
|
+
const connector = originalTraces[connectorIndex];
|
|
7229
|
+
const originalJunction = connector.tracePath.find(
|
|
7230
|
+
(point) => tracePathContainsPoint(originalHostTrace.tracePath, point)
|
|
7231
|
+
);
|
|
7232
|
+
if (!originalJunction) return label;
|
|
7233
|
+
const reroutedJunction = getMovedAnchorPointForReroute(
|
|
7234
|
+
originalJunction,
|
|
7235
|
+
originalHostTrace.tracePath,
|
|
7236
|
+
reroutedHostTrace.tracePath
|
|
7237
|
+
);
|
|
7238
|
+
if (!reroutedJunction) return label;
|
|
7239
|
+
const delta = {
|
|
7240
|
+
x: reroutedJunction.x - originalJunction.x,
|
|
7241
|
+
y: reroutedJunction.y - originalJunction.y
|
|
7242
|
+
};
|
|
7243
|
+
const movedConnector = {
|
|
7244
|
+
...connector,
|
|
7245
|
+
tracePath: connector.tracePath.map((point) => ({
|
|
7246
|
+
x: point.x + delta.x,
|
|
7247
|
+
y: point.y + delta.y
|
|
7248
|
+
}))
|
|
7249
|
+
};
|
|
7250
|
+
traces[connectorIndex] = movedConnector;
|
|
7251
|
+
return moveAttachedLabelsToReroutedTrace({
|
|
7252
|
+
trace: connector,
|
|
7253
|
+
originalTracePath: connector.tracePath,
|
|
7254
|
+
reroutedTracePath: movedConnector.tracePath,
|
|
7255
|
+
netLabelPlacements: [label]
|
|
7256
|
+
})[0];
|
|
7257
|
+
});
|
|
7258
|
+
return { traces, netLabelPlacements: labels };
|
|
7259
|
+
};
|
|
7162
7260
|
|
|
7163
7261
|
// lib/solvers/Example28Solver/doesPathRunAlongChipBoundary.ts
|
|
7164
7262
|
var doesPathRunAlongChipBoundary = (path, chipObstacles) => {
|
|
@@ -7951,6 +8049,7 @@ var createPortOnlyLabelConnectorTrace = ({
|
|
|
7951
8049
|
|
|
7952
8050
|
// lib/solvers/AvailableNetOrientationSolver/constants.ts
|
|
7953
8051
|
var LABEL_SEARCH_STEP = 0.05;
|
|
8052
|
+
var MAX_RECORDED_CANDIDATES = 2e3;
|
|
7954
8053
|
var WICK_CLEARANCE = 1e-3;
|
|
7955
8054
|
var EPS12 = 1e-9;
|
|
7956
8055
|
var TRACE_BOUNDARY_TOLERANCE = WICK_CLEARANCE + EPS12;
|
|
@@ -8007,14 +8106,6 @@ var segmentCrossesBoundsInterior = (p1, p2, bounds) => {
|
|
|
8007
8106
|
}
|
|
8008
8107
|
return false;
|
|
8009
8108
|
};
|
|
8010
|
-
var tracePathCrossesAnyBounds = (tracePath, bounds) => {
|
|
8011
|
-
for (let i = 0; i < tracePath.length - 1; i++) {
|
|
8012
|
-
if (segmentCrossesBoundsInterior(tracePath[i], tracePath[i + 1], bounds)) {
|
|
8013
|
-
return true;
|
|
8014
|
-
}
|
|
8015
|
-
}
|
|
8016
|
-
return false;
|
|
8017
|
-
};
|
|
8018
8109
|
var tracePathIntersectsBounds = (tracePath, bounds) => {
|
|
8019
8110
|
for (let i = 0; i < tracePath.length - 1; i++) {
|
|
8020
8111
|
if (segmentIntersectsRect2(tracePath[i], tracePath[i + 1], bounds)) {
|
|
@@ -8184,6 +8275,145 @@ var ensureGraphicsArrays = (graphics) => {
|
|
|
8184
8275
|
if (!graphics.texts) graphics.texts = [];
|
|
8185
8276
|
};
|
|
8186
8277
|
|
|
8278
|
+
// lib/solvers/AvailableNetOrientationSolver/AvailableNetOrientationObstacleIndex.ts
|
|
8279
|
+
import Flatbush2 from "flatbush";
|
|
8280
|
+
var AvailableNetOrientationObstacleIndex = class {
|
|
8281
|
+
chipObstacleSpatialIndex;
|
|
8282
|
+
labelIndex = null;
|
|
8283
|
+
traceSegmentIndex = null;
|
|
8284
|
+
traceSegments = [];
|
|
8285
|
+
constructor(params) {
|
|
8286
|
+
this.chipObstacleSpatialIndex = params.chipObstacleSpatialIndex;
|
|
8287
|
+
this.rebuild(params);
|
|
8288
|
+
}
|
|
8289
|
+
rebuild(params) {
|
|
8290
|
+
this.labelIndex = this.buildLabelIndex(params.netLabelPlacements);
|
|
8291
|
+
this.traceSegments = this.getTraceSegments(params.traces);
|
|
8292
|
+
this.traceSegmentIndex = this.buildTraceSegmentIndex(this.traceSegments);
|
|
8293
|
+
}
|
|
8294
|
+
getLabelIndicesInBounds(bounds) {
|
|
8295
|
+
if (!this.labelIndex) return [];
|
|
8296
|
+
return this.labelIndex.search(
|
|
8297
|
+
bounds.minX,
|
|
8298
|
+
bounds.minY,
|
|
8299
|
+
bounds.maxX,
|
|
8300
|
+
bounds.maxY
|
|
8301
|
+
);
|
|
8302
|
+
}
|
|
8303
|
+
getTraceSegmentsInBounds(bounds) {
|
|
8304
|
+
if (!this.traceSegmentIndex) return [];
|
|
8305
|
+
const searchBounds = getPaddedBounds(bounds, EPS12);
|
|
8306
|
+
return this.traceSegmentIndex.search(
|
|
8307
|
+
searchBounds.minX,
|
|
8308
|
+
searchBounds.minY,
|
|
8309
|
+
searchBounds.maxX,
|
|
8310
|
+
searchBounds.maxY
|
|
8311
|
+
).map((segmentIndex) => this.traceSegments[segmentIndex]);
|
|
8312
|
+
}
|
|
8313
|
+
getLabelIndicesNearTracePath(tracePath) {
|
|
8314
|
+
const labelIndices = /* @__PURE__ */ new Set();
|
|
8315
|
+
for (let pointIndex = 0; pointIndex < tracePath.length - 1; pointIndex++) {
|
|
8316
|
+
const segmentBounds = getPaddedBounds(
|
|
8317
|
+
getSegmentBounds(tracePath[pointIndex], tracePath[pointIndex + 1]),
|
|
8318
|
+
EPS12
|
|
8319
|
+
);
|
|
8320
|
+
for (const labelIndex of this.getLabelIndicesInBounds(segmentBounds)) {
|
|
8321
|
+
labelIndices.add(labelIndex);
|
|
8322
|
+
}
|
|
8323
|
+
}
|
|
8324
|
+
return [...labelIndices].sort((a, b) => a - b);
|
|
8325
|
+
}
|
|
8326
|
+
doesTracePathCrossChip(tracePath) {
|
|
8327
|
+
for (let pointIndex = 0; pointIndex < tracePath.length - 1; pointIndex++) {
|
|
8328
|
+
const start = tracePath[pointIndex];
|
|
8329
|
+
const end = tracePath[pointIndex + 1];
|
|
8330
|
+
const nearbyChips = this.chipObstacleSpatialIndex.getChipsInBounds(
|
|
8331
|
+
getPaddedBounds(getSegmentBounds(start, end), EPS12)
|
|
8332
|
+
);
|
|
8333
|
+
for (const chip of nearbyChips) {
|
|
8334
|
+
if (segmentCrossesBoundsInterior(start, end, chip.bounds)) return true;
|
|
8335
|
+
}
|
|
8336
|
+
}
|
|
8337
|
+
return false;
|
|
8338
|
+
}
|
|
8339
|
+
doesTraceCrossBoundsInterior(bounds) {
|
|
8340
|
+
for (const segment of this.getTraceSegmentsInBounds(bounds)) {
|
|
8341
|
+
if (segmentCrossesBoundsInterior(segment.start, segment.end, bounds)) {
|
|
8342
|
+
return true;
|
|
8343
|
+
}
|
|
8344
|
+
}
|
|
8345
|
+
return false;
|
|
8346
|
+
}
|
|
8347
|
+
doesTraceIntersectBounds(params) {
|
|
8348
|
+
for (const segment of this.getTraceSegmentsInBounds(params.bounds)) {
|
|
8349
|
+
if (segment.trace.globalConnNetId === params.excludedGlobalConnNetId) {
|
|
8350
|
+
continue;
|
|
8351
|
+
}
|
|
8352
|
+
if (segmentIntersectsRect2(segment.start, segment.end, params.bounds)) {
|
|
8353
|
+
return true;
|
|
8354
|
+
}
|
|
8355
|
+
}
|
|
8356
|
+
return false;
|
|
8357
|
+
}
|
|
8358
|
+
buildLabelIndex(netLabelPlacements) {
|
|
8359
|
+
if (netLabelPlacements.length === 0) return null;
|
|
8360
|
+
const labelIndex = new Flatbush2(netLabelPlacements.length);
|
|
8361
|
+
for (const label of netLabelPlacements) {
|
|
8362
|
+
labelIndex.add(
|
|
8363
|
+
label.center.x - label.width / 2,
|
|
8364
|
+
label.center.y - label.height / 2,
|
|
8365
|
+
label.center.x + label.width / 2,
|
|
8366
|
+
label.center.y + label.height / 2
|
|
8367
|
+
);
|
|
8368
|
+
}
|
|
8369
|
+
labelIndex.finish();
|
|
8370
|
+
return labelIndex;
|
|
8371
|
+
}
|
|
8372
|
+
getTraceSegments(traces) {
|
|
8373
|
+
const traceSegments = [];
|
|
8374
|
+
for (const trace of traces) {
|
|
8375
|
+
for (let pointIndex = 0; pointIndex < trace.tracePath.length - 1; pointIndex++) {
|
|
8376
|
+
traceSegments.push({
|
|
8377
|
+
trace,
|
|
8378
|
+
start: trace.tracePath[pointIndex],
|
|
8379
|
+
end: trace.tracePath[pointIndex + 1]
|
|
8380
|
+
});
|
|
8381
|
+
}
|
|
8382
|
+
}
|
|
8383
|
+
return traceSegments;
|
|
8384
|
+
}
|
|
8385
|
+
buildTraceSegmentIndex(traceSegments) {
|
|
8386
|
+
if (traceSegments.length === 0) return null;
|
|
8387
|
+
const traceSegmentIndex = new Flatbush2(traceSegments.length);
|
|
8388
|
+
for (const segment of traceSegments) {
|
|
8389
|
+
traceSegmentIndex.add(
|
|
8390
|
+
Math.min(segment.start.x, segment.end.x),
|
|
8391
|
+
Math.min(segment.start.y, segment.end.y),
|
|
8392
|
+
Math.max(segment.start.x, segment.end.x),
|
|
8393
|
+
Math.max(segment.start.y, segment.end.y)
|
|
8394
|
+
);
|
|
8395
|
+
}
|
|
8396
|
+
traceSegmentIndex.finish();
|
|
8397
|
+
return traceSegmentIndex;
|
|
8398
|
+
}
|
|
8399
|
+
};
|
|
8400
|
+
function getSegmentBounds(start, end) {
|
|
8401
|
+
return {
|
|
8402
|
+
minX: Math.min(start.x, end.x),
|
|
8403
|
+
minY: Math.min(start.y, end.y),
|
|
8404
|
+
maxX: Math.max(start.x, end.x),
|
|
8405
|
+
maxY: Math.max(start.y, end.y)
|
|
8406
|
+
};
|
|
8407
|
+
}
|
|
8408
|
+
function getPaddedBounds(bounds, padding) {
|
|
8409
|
+
return {
|
|
8410
|
+
minX: bounds.minX - padding,
|
|
8411
|
+
minY: bounds.minY - padding,
|
|
8412
|
+
maxX: bounds.maxX + padding,
|
|
8413
|
+
maxY: bounds.maxY + padding
|
|
8414
|
+
};
|
|
8415
|
+
}
|
|
8416
|
+
|
|
8187
8417
|
// lib/solvers/AvailableNetOrientationSolver/AvailableNetOrientationSolver.ts
|
|
8188
8418
|
var LABEL_TRACE_CLEARANCE2 = 0.1;
|
|
8189
8419
|
var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
@@ -8202,6 +8432,7 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
8202
8432
|
chipObstacleSpatialIndex;
|
|
8203
8433
|
maxSearchDistance;
|
|
8204
8434
|
pinMap;
|
|
8435
|
+
obstacleIndex;
|
|
8205
8436
|
constructor(params) {
|
|
8206
8437
|
super();
|
|
8207
8438
|
this.inputProblem = params.inputProblem;
|
|
@@ -8214,6 +8445,11 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
8214
8445
|
this.pinMap = getPinMap(params.inputProblem);
|
|
8215
8446
|
this.chipObstacleSpatialIndex = params.inputProblem._chipObstacleSpatialIndex ?? new ChipObstacleSpatialIndex(params.inputProblem.chips);
|
|
8216
8447
|
this.maxSearchDistance = getMaxSearchDistance(params.inputProblem);
|
|
8448
|
+
this.obstacleIndex = new AvailableNetOrientationObstacleIndex({
|
|
8449
|
+
chipObstacleSpatialIndex: this.chipObstacleSpatialIndex,
|
|
8450
|
+
netLabelPlacements: this.outputNetLabelPlacements,
|
|
8451
|
+
traces: this.traces
|
|
8452
|
+
});
|
|
8217
8453
|
this.crowdedPortOnlyLabelIndices = this.getCrowdedPortOnlyLabelIndices();
|
|
8218
8454
|
this.queuedLabelIndices = this.getProcessableLabelIndices();
|
|
8219
8455
|
this.setCurrentLabel(this.queuedLabelIndices[0] ?? null);
|
|
@@ -8395,6 +8631,10 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
8395
8631
|
...toNetLabelPlacementPatch(candidate)
|
|
8396
8632
|
};
|
|
8397
8633
|
this.addConnectorTrace(label, candidate, labelIndex);
|
|
8634
|
+
this.obstacleIndex.rebuild({
|
|
8635
|
+
netLabelPlacements: this.outputNetLabelPlacements,
|
|
8636
|
+
traces: this.traces
|
|
8637
|
+
});
|
|
8398
8638
|
}
|
|
8399
8639
|
addConnectorTrace(label, candidate, labelIndex) {
|
|
8400
8640
|
if (candidate.phase === "trace-anchor") return;
|
|
@@ -8557,7 +8797,7 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
8557
8797
|
anchorY - label.anchorPoint.y,
|
|
8558
8798
|
anchorX - label.anchorPoint.x
|
|
8559
8799
|
);
|
|
8560
|
-
this.
|
|
8800
|
+
this.recordCandidateResult(result);
|
|
8561
8801
|
if (result.status !== "valid") continue;
|
|
8562
8802
|
result.selected = true;
|
|
8563
8803
|
return result;
|
|
@@ -8592,7 +8832,7 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
8592
8832
|
labelIndex,
|
|
8593
8833
|
"rotate"
|
|
8594
8834
|
);
|
|
8595
|
-
this.
|
|
8835
|
+
this.recordCandidateResult(result);
|
|
8596
8836
|
if (result.status === "valid") {
|
|
8597
8837
|
result.selected = true;
|
|
8598
8838
|
return result;
|
|
@@ -8617,7 +8857,7 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
8617
8857
|
labelIndex,
|
|
8618
8858
|
"trace-anchor"
|
|
8619
8859
|
);
|
|
8620
|
-
this.
|
|
8860
|
+
this.recordCandidateResult(result);
|
|
8621
8861
|
if (result.status === "valid") {
|
|
8622
8862
|
result.selected = true;
|
|
8623
8863
|
return result;
|
|
@@ -8654,7 +8894,7 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
8654
8894
|
labelIndex,
|
|
8655
8895
|
"outward-trace-anchor"
|
|
8656
8896
|
);
|
|
8657
|
-
this.
|
|
8897
|
+
this.recordCandidateResult(preservedColumnResult);
|
|
8658
8898
|
if (preservedColumnResult.status === "valid") {
|
|
8659
8899
|
preservedColumnResult.selected = true;
|
|
8660
8900
|
return preservedColumnResult;
|
|
@@ -8682,7 +8922,7 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
8682
8922
|
"outward-trace-anchor",
|
|
8683
8923
|
distance5
|
|
8684
8924
|
);
|
|
8685
|
-
this.
|
|
8925
|
+
this.recordCandidateResult(result);
|
|
8686
8926
|
if (result.status === "valid") {
|
|
8687
8927
|
result.selected = true;
|
|
8688
8928
|
return result;
|
|
@@ -8807,7 +9047,7 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
8807
9047
|
distance5,
|
|
8808
9048
|
outwardDistance
|
|
8809
9049
|
);
|
|
8810
|
-
this.
|
|
9050
|
+
this.recordCandidateResult(result);
|
|
8811
9051
|
if (result.status === "valid") {
|
|
8812
9052
|
result.selected = true;
|
|
8813
9053
|
return result;
|
|
@@ -8831,6 +9071,18 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
8831
9071
|
})
|
|
8832
9072
|
};
|
|
8833
9073
|
}
|
|
9074
|
+
recordCandidateResult(candidate) {
|
|
9075
|
+
this.stats.candidateEvaluations = (this.stats.candidateEvaluations ?? 0) + 1;
|
|
9076
|
+
if (this.currentCandidateResults.length < MAX_RECORDED_CANDIDATES) {
|
|
9077
|
+
this.currentCandidateResults.push(candidate);
|
|
9078
|
+
} else if (candidate.status === "valid") {
|
|
9079
|
+
this.currentCandidateResults[MAX_RECORDED_CANDIDATES - 1] = candidate;
|
|
9080
|
+
}
|
|
9081
|
+
this.stats.maxRecordedCandidates = Math.max(
|
|
9082
|
+
this.stats.maxRecordedCandidates ?? 0,
|
|
9083
|
+
this.currentCandidateResults.length
|
|
9084
|
+
);
|
|
9085
|
+
}
|
|
8834
9086
|
getCandidateConnectorTrace(label, candidate, labelIndex) {
|
|
8835
9087
|
if (this.crowdedPortOnlyLabelIndices.has(labelIndex) && this.getChipSideForPoint(label.anchorPoint) === "top" && isYOrientation(candidate.orientation)) {
|
|
8836
9088
|
return simplifyOrthogonalPath([
|
|
@@ -9070,12 +9322,12 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
9070
9322
|
},
|
|
9071
9323
|
labelIndex
|
|
9072
9324
|
);
|
|
9073
|
-
|
|
9074
|
-
|
|
9075
|
-
return "chip-collision";
|
|
9076
|
-
}
|
|
9325
|
+
if (this.obstacleIndex.doesTracePathCrossChip(connectorTrace)) {
|
|
9326
|
+
return "chip-collision";
|
|
9077
9327
|
}
|
|
9078
|
-
for (
|
|
9328
|
+
for (const i of this.obstacleIndex.getLabelIndicesNearTracePath(
|
|
9329
|
+
connectorTrace
|
|
9330
|
+
)) {
|
|
9079
9331
|
if (i === labelIndex) continue;
|
|
9080
9332
|
if (this.shouldIgnorePendingCrowdedLabel(labelIndex, i)) continue;
|
|
9081
9333
|
const otherLabel = this.outputNetLabelPlacements[i];
|
|
@@ -9117,7 +9369,7 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
9117
9369
|
if (rectIntersectsAnyTextBox(bounds, this.inputProblem)) {
|
|
9118
9370
|
return "text-collision";
|
|
9119
9371
|
}
|
|
9120
|
-
if (
|
|
9372
|
+
if (this.obstacleIndex.doesTraceCrossBoundsInterior(bounds)) {
|
|
9121
9373
|
return "trace-collision";
|
|
9122
9374
|
}
|
|
9123
9375
|
if (this.isTraceTooCloseToLabel(bounds, label)) {
|
|
@@ -9131,13 +9383,10 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
9131
9383
|
isTraceTooCloseToLabel(bounds, label) {
|
|
9132
9384
|
if (!this.shouldCheckTraceClearanceForLabel(label)) return false;
|
|
9133
9385
|
const clearanceBounds = this.getLabelTraceClearanceBounds(bounds);
|
|
9134
|
-
|
|
9135
|
-
|
|
9136
|
-
|
|
9137
|
-
|
|
9138
|
-
}
|
|
9139
|
-
}
|
|
9140
|
-
return false;
|
|
9386
|
+
return this.obstacleIndex.doesTraceIntersectBounds({
|
|
9387
|
+
bounds: clearanceBounds,
|
|
9388
|
+
excludedGlobalConnNetId: label.globalConnNetId
|
|
9389
|
+
});
|
|
9141
9390
|
}
|
|
9142
9391
|
getLabelTraceClearanceBounds(bounds) {
|
|
9143
9392
|
return {
|
|
@@ -9220,7 +9469,14 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
9220
9469
|
return this.crowdedPortOnlyLabelIndices.has(labelIndex) && this.crowdedPortOnlyLabelIndices.has(otherLabelIndex) && this.queuedLabelIndices.includes(otherLabelIndex);
|
|
9221
9470
|
}
|
|
9222
9471
|
intersectsAnyOtherNetLabel(bounds, labelIndex) {
|
|
9223
|
-
|
|
9472
|
+
const searchBounds = {
|
|
9473
|
+
minX: bounds.minX - LABEL_SEARCH_STEP,
|
|
9474
|
+
minY: bounds.minY - LABEL_SEARCH_STEP,
|
|
9475
|
+
maxX: bounds.maxX + LABEL_SEARCH_STEP,
|
|
9476
|
+
maxY: bounds.maxY + LABEL_SEARCH_STEP
|
|
9477
|
+
};
|
|
9478
|
+
const nearbyLabelIndices = this.obstacleIndex.getLabelIndicesInBounds(searchBounds).sort((a, b) => a - b);
|
|
9479
|
+
for (const i of nearbyLabelIndices) {
|
|
9224
9480
|
if (i === labelIndex) continue;
|
|
9225
9481
|
if (this.shouldIgnorePendingCrowdedLabel(labelIndex, i)) continue;
|
|
9226
9482
|
const label = this.outputNetLabelPlacements[i];
|
|
@@ -9234,7 +9490,14 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
9234
9490
|
return false;
|
|
9235
9491
|
}
|
|
9236
9492
|
sharesChipBoundary(bounds) {
|
|
9237
|
-
|
|
9493
|
+
const boundarySearchBounds = {
|
|
9494
|
+
minX: bounds.minX - WICK_CLEARANCE - EPS12,
|
|
9495
|
+
minY: bounds.minY - WICK_CLEARANCE - EPS12,
|
|
9496
|
+
maxX: bounds.maxX + WICK_CLEARANCE + EPS12,
|
|
9497
|
+
maxY: bounds.maxY + WICK_CLEARANCE + EPS12
|
|
9498
|
+
};
|
|
9499
|
+
const nearbyChips = this.chipObstacleSpatialIndex.getChipsInBounds(boundarySearchBounds);
|
|
9500
|
+
for (const chip of nearbyChips) {
|
|
9238
9501
|
const chipBounds = chip.bounds;
|
|
9239
9502
|
const adjacentToVerticalSide = Math.abs(bounds.minX - chipBounds.maxX) <= WICK_CLEARANCE + EPS12 || Math.abs(bounds.maxX - chipBounds.minX) <= WICK_CLEARANCE + EPS12;
|
|
9240
9503
|
const adjacentToHorizontalSide = Math.abs(bounds.minY - chipBounds.maxY) <= WICK_CLEARANCE + EPS12 || Math.abs(bounds.maxY - chipBounds.minY) <= WICK_CLEARANCE + EPS12;
|
|
@@ -12963,11 +13226,16 @@ var SchematicTracePipelineSolver = class extends BaseSolver {
|
|
|
12963
13226
|
(instance) => {
|
|
12964
13227
|
const previousOutput = instance.preAlignmentNetLabelTraceCollisionSolver.getOutput();
|
|
12965
13228
|
const alignmentOutput = instance.traceCleanupSolver2.getOutput();
|
|
13229
|
+
const connectorMovement = moveNetLabelConnectorsToReroutedTraces({
|
|
13230
|
+
originalTraces: previousOutput.traces,
|
|
13231
|
+
reroutedTraces: alignmentOutput.traces,
|
|
13232
|
+
netLabelPlacements: previousOutput.netLabelPlacements
|
|
13233
|
+
});
|
|
12966
13234
|
const previousTraceMap = new Map(
|
|
12967
13235
|
previousOutput.traces.map((trace) => [trace.mspPairId, trace])
|
|
12968
13236
|
);
|
|
12969
|
-
let netLabelPlacements =
|
|
12970
|
-
for (const trace of
|
|
13237
|
+
let netLabelPlacements = connectorMovement.netLabelPlacements;
|
|
13238
|
+
for (const trace of connectorMovement.traces) {
|
|
12971
13239
|
const previousTrace = previousTraceMap.get(trace.mspPairId);
|
|
12972
13240
|
if (!previousTrace || previousTrace.tracePath === trace.tracePath) {
|
|
12973
13241
|
continue;
|
|
@@ -12987,7 +13255,7 @@ var SchematicTracePipelineSolver = class extends BaseSolver {
|
|
|
12987
13255
|
return [
|
|
12988
13256
|
{
|
|
12989
13257
|
inputProblem: instance.inputProblem,
|
|
12990
|
-
traces:
|
|
13258
|
+
traces: connectorMovement.traces,
|
|
12991
13259
|
netLabelPlacements
|
|
12992
13260
|
}
|
|
12993
13261
|
];
|