@tscircuit/schematic-trace-solver 0.0.54 → 0.0.56
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 +31 -2
- package/dist/index.js +268 -2
- package/lib/solvers/LongDistancePairSolver/LongDistancePairSolver.ts +10 -1
- package/lib/solvers/MspConnectionPairSolver/MspConnectionPairSolver.ts +14 -0
- package/lib/solvers/NetLabelTraceCollisionSolver/NetLabelTraceCollisionSolver.ts +294 -0
- package/lib/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver.ts +15 -0
- package/lib/solvers/SchematicTracePipelineSolver/visualizeInputProblem.ts +7 -0
- package/lib/types/InputProblem.ts +2 -0
- package/lib/utils/arePinsInDifferentSchematicSections.ts +39 -0
- package/package.json +1 -1
- package/site/examples/example32.page.tsx +4 -0
- package/site/examples/example33.page.tsx +4 -0
- package/tests/assets/example32.json +148 -0
- package/tests/assets/example33.json +132 -0
- package/tests/examples/__snapshots__/example32.snap.svg +391 -0
- package/tests/examples/__snapshots__/example33.snap.svg +181 -0
- package/tests/examples/example32.test.ts +12 -0
- package/tests/examples/example33.test.ts +12 -0
- package/tests/solvers/MspConnectionPairSolver/MspConnectionPairSolver_schematicSections.test.ts +70 -0
package/dist/index.d.ts
CHANGED
|
@@ -56,6 +56,7 @@ type FacingDirection = "x+" | "x-" | "y+" | "y-";
|
|
|
56
56
|
type ChipId = string;
|
|
57
57
|
type PinId = string;
|
|
58
58
|
type NetId = string;
|
|
59
|
+
type SectionId = string;
|
|
59
60
|
interface InputPin {
|
|
60
61
|
pinId: PinId;
|
|
61
62
|
x: number;
|
|
@@ -71,6 +72,7 @@ interface InputChip {
|
|
|
71
72
|
width: number;
|
|
72
73
|
height: number;
|
|
73
74
|
pins: Array<InputPin>;
|
|
75
|
+
sectionId?: SectionId;
|
|
74
76
|
}
|
|
75
77
|
interface InputDirectConnection {
|
|
76
78
|
pinIds: [PinId, PinId];
|
|
@@ -818,6 +820,32 @@ declare class TraceAnchoredNetLabelOverlapSolver extends BaseSolver {
|
|
|
818
820
|
visualize(): GraphicsObject;
|
|
819
821
|
}
|
|
820
822
|
|
|
823
|
+
interface NetLabelTraceCollisionSolverParams {
|
|
824
|
+
inputProblem: InputProblem;
|
|
825
|
+
traces: SolvedTracePath[];
|
|
826
|
+
netLabelPlacements: NetLabelPlacement[];
|
|
827
|
+
}
|
|
828
|
+
declare class NetLabelTraceCollisionSolver extends BaseSolver {
|
|
829
|
+
inputProblem: InputProblem;
|
|
830
|
+
traces: SolvedTracePath[];
|
|
831
|
+
netLabelPlacements: NetLabelPlacement[];
|
|
832
|
+
outputTraces: SolvedTracePath[];
|
|
833
|
+
outputNetLabelPlacements: NetLabelPlacement[];
|
|
834
|
+
activeSubSolver: SingleOverlapSolver | null;
|
|
835
|
+
private recentlyFailed;
|
|
836
|
+
private detourCounts;
|
|
837
|
+
private currentOverlap;
|
|
838
|
+
constructor(params: NetLabelTraceCollisionSolverParams);
|
|
839
|
+
getConstructorParams(): ConstructorParameters<typeof NetLabelTraceCollisionSolver>[0];
|
|
840
|
+
_step(): void;
|
|
841
|
+
getOutput(): {
|
|
842
|
+
traces: SolvedTracePath[];
|
|
843
|
+
netLabelPlacements: NetLabelPlacement[];
|
|
844
|
+
};
|
|
845
|
+
private getOverlapKey;
|
|
846
|
+
visualize(): GraphicsObject;
|
|
847
|
+
}
|
|
848
|
+
|
|
821
849
|
/**
|
|
822
850
|
* Pipeline solver that runs a series of solvers to find the best schematic layout.
|
|
823
851
|
* Coordinates the entire layout process from chip partitioning through final packing.
|
|
@@ -847,12 +875,13 @@ declare class SchematicTracePipelineSolver extends BaseSolver {
|
|
|
847
875
|
availableNetOrientationSolver?: AvailableNetOrientationSolver;
|
|
848
876
|
vccNetLabelCornerPlacementSolver?: VccNetLabelCornerPlacementSolver;
|
|
849
877
|
traceAnchoredNetLabelOverlapSolver?: TraceAnchoredNetLabelOverlapSolver;
|
|
878
|
+
netLabelTraceCollisionSolver?: NetLabelTraceCollisionSolver;
|
|
850
879
|
startTimeOfPhase: Record<string, number>;
|
|
851
880
|
endTimeOfPhase: Record<string, number>;
|
|
852
881
|
timeSpentOnPhase: Record<string, number>;
|
|
853
882
|
firstIterationOfPhase: Record<string, number>;
|
|
854
883
|
inputProblem: InputProblem;
|
|
855
|
-
pipelineDef: (PipelineStep<typeof MspConnectionPairSolver> | PipelineStep<typeof SchematicTraceLinesSolver> | PipelineStep<typeof LongDistancePairSolver> | PipelineStep<typeof TraceOverlapShiftSolver> | PipelineStep<typeof NetLabelPlacementSolver> | PipelineStep<typeof TraceLabelOverlapAvoidanceSolver> | PipelineStep<typeof TraceCleanupSolver> | PipelineStep<typeof Example28Solver> | PipelineStep<typeof AvailableNetOrientationSolver> | PipelineStep<typeof VccNetLabelCornerPlacementSolver> | PipelineStep<typeof TraceAnchoredNetLabelOverlapSolver>)[];
|
|
884
|
+
pipelineDef: (PipelineStep<typeof MspConnectionPairSolver> | PipelineStep<typeof SchematicTraceLinesSolver> | PipelineStep<typeof LongDistancePairSolver> | PipelineStep<typeof TraceOverlapShiftSolver> | PipelineStep<typeof NetLabelPlacementSolver> | PipelineStep<typeof TraceLabelOverlapAvoidanceSolver> | PipelineStep<typeof TraceCleanupSolver> | PipelineStep<typeof Example28Solver> | PipelineStep<typeof AvailableNetOrientationSolver> | PipelineStep<typeof VccNetLabelCornerPlacementSolver> | PipelineStep<typeof TraceAnchoredNetLabelOverlapSolver> | PipelineStep<typeof NetLabelTraceCollisionSolver>)[];
|
|
856
885
|
constructor(inputProblem: InputProblem);
|
|
857
886
|
getConstructorParams(): ConstructorParameters<typeof SchematicTracePipelineSolver>[0];
|
|
858
887
|
currentPipelineStepIndex: number;
|
|
@@ -868,4 +897,4 @@ declare class SchematicTracePipelineSolver extends BaseSolver {
|
|
|
868
897
|
preview(): GraphicsObject;
|
|
869
898
|
}
|
|
870
899
|
|
|
871
|
-
export { type ChipId, type InputChip, type InputDirectConnection, type InputNetConnection, type InputPin, type InputProblem, type NetId, type PinId, SchematicTracePipelineSolver, type SchematicTracePipelineSolverParams, SchematicTraceSingleLineSolver2 };
|
|
900
|
+
export { type ChipId, type InputChip, type InputDirectConnection, type InputNetConnection, type InputPin, type InputProblem, type NetId, type PinId, SchematicTracePipelineSolver, type SchematicTracePipelineSolverParams, SchematicTraceSingleLineSolver2, type SectionId };
|
package/dist/index.js
CHANGED
|
@@ -301,6 +301,30 @@ var getColorFromString = (string, alpha = 1) => {
|
|
|
301
301
|
return `hsl(${hash % 360}, 100%, 50%, ${alpha})`;
|
|
302
302
|
};
|
|
303
303
|
|
|
304
|
+
// lib/utils/arePinsInDifferentSchematicSections.ts
|
|
305
|
+
var getSectionNameForPin = (sectionByChipId, sectionByPinId, pin) => {
|
|
306
|
+
if (pin.chipId) {
|
|
307
|
+
const chipSection = sectionByChipId.get(pin.chipId);
|
|
308
|
+
if (chipSection) return chipSection;
|
|
309
|
+
}
|
|
310
|
+
return sectionByPinId.get(pin.pinId);
|
|
311
|
+
};
|
|
312
|
+
var arePinsInDifferentSchematicSections = (inputProblem, p1, p2) => {
|
|
313
|
+
const sectionByChipId = /* @__PURE__ */ new Map();
|
|
314
|
+
const sectionByPinId = /* @__PURE__ */ new Map();
|
|
315
|
+
for (const chip of inputProblem.chips) {
|
|
316
|
+
if (!chip.sectionId) continue;
|
|
317
|
+
sectionByChipId.set(chip.chipId, chip.sectionId);
|
|
318
|
+
for (const pin of chip.pins) {
|
|
319
|
+
sectionByPinId.set(pin.pinId, chip.sectionId);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
if (sectionByChipId.size === 0) return false;
|
|
323
|
+
const s1 = getSectionNameForPin(sectionByChipId, sectionByPinId, p1);
|
|
324
|
+
const s2 = getSectionNameForPin(sectionByChipId, sectionByPinId, p2);
|
|
325
|
+
return !!s1 && !!s2 && s1 !== s2;
|
|
326
|
+
};
|
|
327
|
+
|
|
304
328
|
// lib/solvers/SchematicTracePipelineSolver/visualizeInputProblem.ts
|
|
305
329
|
var visualizeInputProblem = (inputProblem, opts = {}) => {
|
|
306
330
|
const { connectionAlpha = 0.8, chipAlpha = 0.8 } = opts;
|
|
@@ -337,6 +361,9 @@ ${pin._facingDirection ?? getPinDirection(pin, chip)}`,
|
|
|
337
361
|
const [pinId1, pinId2] = directConn.pinIds;
|
|
338
362
|
const pin1 = pinIdMap.get(pinId1);
|
|
339
363
|
const pin2 = pinIdMap.get(pinId2);
|
|
364
|
+
if (arePinsInDifferentSchematicSections(inputProblem, pin1, pin2)) {
|
|
365
|
+
continue;
|
|
366
|
+
}
|
|
340
367
|
graphics.lines.push({
|
|
341
368
|
points: [
|
|
342
369
|
{
|
|
@@ -360,6 +387,9 @@ ${pin._facingDirection ?? getPinDirection(pin, chip)}`,
|
|
|
360
387
|
for (let j = i + 1; j < pins.length; j++) {
|
|
361
388
|
const pin1 = pins[i];
|
|
362
389
|
const pin2 = pins[j];
|
|
390
|
+
if (arePinsInDifferentSchematicSections(inputProblem, pin1, pin2)) {
|
|
391
|
+
continue;
|
|
392
|
+
}
|
|
363
393
|
graphics.lines.push({
|
|
364
394
|
points: [
|
|
365
395
|
{ x: pin1.x, y: pin1.y },
|
|
@@ -441,6 +471,9 @@ var MspConnectionPairSolver = class extends BaseSolver {
|
|
|
441
471
|
if (manhattanDist > this.maxMspPairDistance) {
|
|
442
472
|
return;
|
|
443
473
|
}
|
|
474
|
+
if (arePinsInDifferentSchematicSections(this.inputProblem, p1, p2)) {
|
|
475
|
+
return;
|
|
476
|
+
}
|
|
444
477
|
const pinIdMap2 = new Map(Object.entries(this.pinMap));
|
|
445
478
|
if (doesPairCrossRestrictedCenterLines({
|
|
446
479
|
inputProblem: this.inputProblem,
|
|
@@ -467,7 +500,11 @@ var MspConnectionPairSolver = class extends BaseSolver {
|
|
|
467
500
|
directlyConnectedPins.map((p) => this.pinMap[p]).filter(Boolean),
|
|
468
501
|
{
|
|
469
502
|
maxDistance: this.maxMspPairDistance,
|
|
470
|
-
forbidEdge: (a, b) =>
|
|
503
|
+
forbidEdge: (a, b) => arePinsInDifferentSchematicSections(
|
|
504
|
+
this.inputProblem,
|
|
505
|
+
a,
|
|
506
|
+
b
|
|
507
|
+
) || doesPairCrossRestrictedCenterLines({
|
|
471
508
|
inputProblem: this.inputProblem,
|
|
472
509
|
chipMap: this.chipMap,
|
|
473
510
|
pinIdMap,
|
|
@@ -479,6 +516,9 @@ var MspConnectionPairSolver = class extends BaseSolver {
|
|
|
479
516
|
for (const [pin1, pin2] of msp) {
|
|
480
517
|
const p1Obj = this.pinMap[pin1];
|
|
481
518
|
const p2Obj = this.pinMap[pin2];
|
|
519
|
+
if (arePinsInDifferentSchematicSections(this.inputProblem, p1Obj, p2Obj)) {
|
|
520
|
+
continue;
|
|
521
|
+
}
|
|
482
522
|
if (doesPairCrossRestrictedCenterLines({
|
|
483
523
|
inputProblem: this.inputProblem,
|
|
484
524
|
chipMap: this.chipMap,
|
|
@@ -3461,6 +3501,9 @@ var LongDistancePairSolver = class extends BaseSolver {
|
|
|
3461
3501
|
}).sort((a, b) => a.distance - b.distance).slice(0, NEAREST_NEIGHBOR_COUNT);
|
|
3462
3502
|
for (const neighbor of neighbors) {
|
|
3463
3503
|
const pair = [sourcePin, neighbor.pin];
|
|
3504
|
+
if (arePinsInDifferentSchematicSections(inputProblem, pair[0], pair[1])) {
|
|
3505
|
+
continue;
|
|
3506
|
+
}
|
|
3464
3507
|
const pairKey = pair.map((p) => p.pinId).sort().join("--");
|
|
3465
3508
|
if (!addedPairKeys.has(pairKey)) {
|
|
3466
3509
|
candidatePairs.push(pair);
|
|
@@ -3559,7 +3602,10 @@ var LongDistancePairSolver = class extends BaseSolver {
|
|
|
3559
3602
|
}
|
|
3560
3603
|
getOutput() {
|
|
3561
3604
|
if (!this.solved) {
|
|
3562
|
-
return {
|
|
3605
|
+
return {
|
|
3606
|
+
newTraces: [],
|
|
3607
|
+
allTracesMerged: this.params.alreadySolvedTraces
|
|
3608
|
+
};
|
|
3563
3609
|
}
|
|
3564
3610
|
return {
|
|
3565
3611
|
newTraces: this.solvedLongDistanceTraces,
|
|
@@ -7104,6 +7150,214 @@ var TraceAnchoredNetLabelOverlapSolver = class extends BaseSolver {
|
|
|
7104
7150
|
}
|
|
7105
7151
|
};
|
|
7106
7152
|
|
|
7153
|
+
// lib/solvers/NetLabelTraceCollisionSolver/NetLabelTraceCollisionSolver.ts
|
|
7154
|
+
function buildMergedObstacleLabel(seedLabel, allLabels) {
|
|
7155
|
+
const TOUCH_MARGIN = 0.01;
|
|
7156
|
+
const getBounds3 = (l) => getRectBounds(l.center, l.width, l.height);
|
|
7157
|
+
const touches = (a, b) => {
|
|
7158
|
+
const ba = getBounds3(a);
|
|
7159
|
+
const bb = getBounds3(b);
|
|
7160
|
+
return ba.minX <= bb.maxX + TOUCH_MARGIN && ba.maxX >= bb.minX - TOUCH_MARGIN && ba.minY <= bb.maxY + TOUCH_MARGIN && ba.maxY >= bb.minY - TOUCH_MARGIN;
|
|
7161
|
+
};
|
|
7162
|
+
const group = /* @__PURE__ */ new Set([seedLabel]);
|
|
7163
|
+
let changed = true;
|
|
7164
|
+
while (changed) {
|
|
7165
|
+
changed = false;
|
|
7166
|
+
for (const l of allLabels) {
|
|
7167
|
+
if (group.has(l)) continue;
|
|
7168
|
+
if ([...group].some((g) => touches(g, l))) {
|
|
7169
|
+
group.add(l);
|
|
7170
|
+
changed = true;
|
|
7171
|
+
}
|
|
7172
|
+
}
|
|
7173
|
+
}
|
|
7174
|
+
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
7175
|
+
for (const l of group) {
|
|
7176
|
+
const b = getBounds3(l);
|
|
7177
|
+
if (b.minX < minX) minX = b.minX;
|
|
7178
|
+
if (b.minY < minY) minY = b.minY;
|
|
7179
|
+
if (b.maxX > maxX) maxX = b.maxX;
|
|
7180
|
+
if (b.maxY > maxY) maxY = b.maxY;
|
|
7181
|
+
}
|
|
7182
|
+
const cx = (minX + maxX) / 2;
|
|
7183
|
+
const cy = (minY + maxY) / 2;
|
|
7184
|
+
const w = maxX - minX;
|
|
7185
|
+
const h = maxY - minY;
|
|
7186
|
+
return {
|
|
7187
|
+
...seedLabel,
|
|
7188
|
+
center: { x: cx, y: cy },
|
|
7189
|
+
width: w,
|
|
7190
|
+
height: h
|
|
7191
|
+
};
|
|
7192
|
+
}
|
|
7193
|
+
function detectInnerTraceLabelOverlaps(traces, labels) {
|
|
7194
|
+
const overlaps = [];
|
|
7195
|
+
for (const trace of traces) {
|
|
7196
|
+
for (const label of labels) {
|
|
7197
|
+
if (trace.globalConnNetId === label.globalConnNetId) continue;
|
|
7198
|
+
const bounds = getRectBounds(label.center, label.width, label.height);
|
|
7199
|
+
const path = trace.tracePath;
|
|
7200
|
+
const innerStart = 1;
|
|
7201
|
+
const innerEnd = path.length - 2;
|
|
7202
|
+
for (let i = innerStart; i < innerEnd; i++) {
|
|
7203
|
+
if (segmentIntersectsRect2(path[i], path[i + 1], bounds)) {
|
|
7204
|
+
overlaps.push({ trace, label });
|
|
7205
|
+
break;
|
|
7206
|
+
}
|
|
7207
|
+
}
|
|
7208
|
+
}
|
|
7209
|
+
}
|
|
7210
|
+
return overlaps;
|
|
7211
|
+
}
|
|
7212
|
+
var PADDING_BUFFER = 0.1;
|
|
7213
|
+
var MAX_DETOUR_ATTEMPTS = 3;
|
|
7214
|
+
var NetLabelTraceCollisionSolver = class extends BaseSolver {
|
|
7215
|
+
inputProblem;
|
|
7216
|
+
traces;
|
|
7217
|
+
netLabelPlacements;
|
|
7218
|
+
outputTraces;
|
|
7219
|
+
outputNetLabelPlacements;
|
|
7220
|
+
activeSubSolver = null;
|
|
7221
|
+
recentlyFailed = /* @__PURE__ */ new Set();
|
|
7222
|
+
detourCounts = /* @__PURE__ */ new Map();
|
|
7223
|
+
currentOverlap = null;
|
|
7224
|
+
constructor(params) {
|
|
7225
|
+
super();
|
|
7226
|
+
this.inputProblem = params.inputProblem;
|
|
7227
|
+
this.traces = params.traces;
|
|
7228
|
+
this.netLabelPlacements = params.netLabelPlacements;
|
|
7229
|
+
this.outputTraces = [...params.traces];
|
|
7230
|
+
this.outputNetLabelPlacements = [...params.netLabelPlacements];
|
|
7231
|
+
}
|
|
7232
|
+
getConstructorParams() {
|
|
7233
|
+
return {
|
|
7234
|
+
inputProblem: this.inputProblem,
|
|
7235
|
+
traces: this.traces,
|
|
7236
|
+
netLabelPlacements: this.netLabelPlacements
|
|
7237
|
+
};
|
|
7238
|
+
}
|
|
7239
|
+
_step() {
|
|
7240
|
+
if (this.activeSubSolver) {
|
|
7241
|
+
this.activeSubSolver.step();
|
|
7242
|
+
if (this.activeSubSolver.solved) {
|
|
7243
|
+
const solvedPath = this.activeSubSolver.solvedTracePath;
|
|
7244
|
+
if (solvedPath) {
|
|
7245
|
+
const idx = this.outputTraces.findIndex(
|
|
7246
|
+
(t) => t.mspPairId === this.activeSubSolver.initialTrace.mspPairId
|
|
7247
|
+
);
|
|
7248
|
+
if (idx !== -1) {
|
|
7249
|
+
this.outputTraces[idx] = {
|
|
7250
|
+
...this.outputTraces[idx],
|
|
7251
|
+
tracePath: solvedPath
|
|
7252
|
+
};
|
|
7253
|
+
}
|
|
7254
|
+
}
|
|
7255
|
+
this.activeSubSolver = null;
|
|
7256
|
+
this.currentOverlap = null;
|
|
7257
|
+
} else if (this.activeSubSolver.failed) {
|
|
7258
|
+
const key = this.getOverlapKey(
|
|
7259
|
+
this.activeSubSolver.initialTrace,
|
|
7260
|
+
this.activeSubSolver.label
|
|
7261
|
+
);
|
|
7262
|
+
this.recentlyFailed.add(key);
|
|
7263
|
+
this.activeSubSolver = null;
|
|
7264
|
+
this.currentOverlap = null;
|
|
7265
|
+
}
|
|
7266
|
+
return;
|
|
7267
|
+
}
|
|
7268
|
+
const overlaps = detectInnerTraceLabelOverlaps(
|
|
7269
|
+
this.outputTraces,
|
|
7270
|
+
this.outputNetLabelPlacements
|
|
7271
|
+
);
|
|
7272
|
+
const actionable = overlaps.filter((o) => {
|
|
7273
|
+
const key = this.getOverlapKey(o.trace, o.label);
|
|
7274
|
+
return !this.recentlyFailed.has(key);
|
|
7275
|
+
});
|
|
7276
|
+
if (actionable.length === 0) {
|
|
7277
|
+
this.solved = true;
|
|
7278
|
+
return;
|
|
7279
|
+
}
|
|
7280
|
+
const next = actionable[0];
|
|
7281
|
+
const traceToFix = this.outputTraces.find(
|
|
7282
|
+
(t) => t.mspPairId === next.trace.mspPairId
|
|
7283
|
+
);
|
|
7284
|
+
this.currentOverlap = next;
|
|
7285
|
+
const mergedLabel = buildMergedObstacleLabel(
|
|
7286
|
+
next.label,
|
|
7287
|
+
this.outputNetLabelPlacements.filter(
|
|
7288
|
+
(l) => l.globalConnNetId !== traceToFix.globalConnNetId
|
|
7289
|
+
)
|
|
7290
|
+
);
|
|
7291
|
+
const mergeKey = `${next.trace.mspPairId}::merged::${mergedLabel.center.x},${mergedLabel.center.y},${mergedLabel.width},${mergedLabel.height}`;
|
|
7292
|
+
const detourCount = this.detourCounts.get(mergeKey) ?? 0;
|
|
7293
|
+
if (detourCount >= MAX_DETOUR_ATTEMPTS) {
|
|
7294
|
+
this.recentlyFailed.add(this.getOverlapKey(next.trace, next.label));
|
|
7295
|
+
this.currentOverlap = null;
|
|
7296
|
+
return;
|
|
7297
|
+
}
|
|
7298
|
+
this.detourCounts.set(mergeKey, detourCount + 1);
|
|
7299
|
+
this.activeSubSolver = new SingleOverlapSolver({
|
|
7300
|
+
trace: traceToFix,
|
|
7301
|
+
label: mergedLabel,
|
|
7302
|
+
problem: this.inputProblem,
|
|
7303
|
+
paddingBuffer: PADDING_BUFFER,
|
|
7304
|
+
detourCount
|
|
7305
|
+
});
|
|
7306
|
+
}
|
|
7307
|
+
getOutput() {
|
|
7308
|
+
return {
|
|
7309
|
+
traces: this.outputTraces,
|
|
7310
|
+
netLabelPlacements: this.outputNetLabelPlacements
|
|
7311
|
+
};
|
|
7312
|
+
}
|
|
7313
|
+
getOverlapKey(trace, label) {
|
|
7314
|
+
return `${trace.mspPairId}::${label.globalConnNetId}`;
|
|
7315
|
+
}
|
|
7316
|
+
visualize() {
|
|
7317
|
+
if (this.activeSubSolver) return this.activeSubSolver.visualize();
|
|
7318
|
+
const graphics = visualizeInputProblem(this.inputProblem);
|
|
7319
|
+
if (!graphics.lines) graphics.lines = [];
|
|
7320
|
+
if (!graphics.rects) graphics.rects = [];
|
|
7321
|
+
if (!graphics.points) graphics.points = [];
|
|
7322
|
+
for (const trace of this.outputTraces) {
|
|
7323
|
+
graphics.lines.push({
|
|
7324
|
+
points: trace.tracePath,
|
|
7325
|
+
strokeColor: "purple"
|
|
7326
|
+
});
|
|
7327
|
+
}
|
|
7328
|
+
for (const label of this.outputNetLabelPlacements) {
|
|
7329
|
+
graphics.rects.push({
|
|
7330
|
+
center: label.center,
|
|
7331
|
+
width: label.width,
|
|
7332
|
+
height: label.height,
|
|
7333
|
+
fill: getColorFromString(label.globalConnNetId, 0.35),
|
|
7334
|
+
strokeColor: getColorFromString(label.globalConnNetId, 0.9),
|
|
7335
|
+
label: `netId: ${label.netId}
|
|
7336
|
+
globalConnNetId: ${label.globalConnNetId}`
|
|
7337
|
+
});
|
|
7338
|
+
graphics.points.push({
|
|
7339
|
+
x: label.anchorPoint.x,
|
|
7340
|
+
y: label.anchorPoint.y,
|
|
7341
|
+
color: getColorFromString(label.globalConnNetId, 0.9)
|
|
7342
|
+
});
|
|
7343
|
+
}
|
|
7344
|
+
if (this.currentOverlap) {
|
|
7345
|
+
graphics.lines.push({
|
|
7346
|
+
points: this.currentOverlap.trace.tracePath,
|
|
7347
|
+
strokeColor: "red"
|
|
7348
|
+
});
|
|
7349
|
+
graphics.rects.push({
|
|
7350
|
+
center: this.currentOverlap.label.center,
|
|
7351
|
+
width: this.currentOverlap.label.width,
|
|
7352
|
+
height: this.currentOverlap.label.height,
|
|
7353
|
+
fill: "rgba(255,0,0,0.3)",
|
|
7354
|
+
strokeColor: "red"
|
|
7355
|
+
});
|
|
7356
|
+
}
|
|
7357
|
+
return graphics;
|
|
7358
|
+
}
|
|
7359
|
+
};
|
|
7360
|
+
|
|
7107
7361
|
// lib/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver.ts
|
|
7108
7362
|
function definePipelineStep(solverName, solverClass, getConstructorParams, opts = {}) {
|
|
7109
7363
|
return {
|
|
@@ -7128,6 +7382,7 @@ var SchematicTracePipelineSolver = class extends BaseSolver {
|
|
|
7128
7382
|
availableNetOrientationSolver;
|
|
7129
7383
|
vccNetLabelCornerPlacementSolver;
|
|
7130
7384
|
traceAnchoredNetLabelOverlapSolver;
|
|
7385
|
+
netLabelTraceCollisionSolver;
|
|
7131
7386
|
startTimeOfPhase;
|
|
7132
7387
|
endTimeOfPhase;
|
|
7133
7388
|
timeSpentOnPhase;
|
|
@@ -7308,6 +7563,17 @@ var SchematicTracePipelineSolver = class extends BaseSolver {
|
|
|
7308
7563
|
netLabelPlacements: instance.vccNetLabelCornerPlacementSolver.outputNetLabelPlacements
|
|
7309
7564
|
}
|
|
7310
7565
|
]
|
|
7566
|
+
),
|
|
7567
|
+
definePipelineStep(
|
|
7568
|
+
"netLabelTraceCollisionSolver",
|
|
7569
|
+
NetLabelTraceCollisionSolver,
|
|
7570
|
+
(instance) => [
|
|
7571
|
+
{
|
|
7572
|
+
inputProblem: instance.inputProblem,
|
|
7573
|
+
traces: instance.availableNetOrientationSolver.traces,
|
|
7574
|
+
netLabelPlacements: instance.traceAnchoredNetLabelOverlapSolver.outputNetLabelPlacements
|
|
7575
|
+
}
|
|
7576
|
+
]
|
|
7311
7577
|
)
|
|
7312
7578
|
];
|
|
7313
7579
|
constructor(inputProblem) {
|
|
@@ -12,6 +12,7 @@ import { doesTraceOverlapWithExistingTraces } from "lib/utils/does-trace-overlap
|
|
|
12
12
|
import { visualizeInputProblem } from "../SchematicTracePipelineSolver/visualizeInputProblem"
|
|
13
13
|
import type { SolvedTracePath } from "../SchematicTraceLinesSolver/SchematicTraceLinesSolver"
|
|
14
14
|
import type { ConnectivityMap } from "connectivity-map"
|
|
15
|
+
import { arePinsInDifferentSchematicSections } from "../../utils/arePinsInDifferentSchematicSections"
|
|
15
16
|
|
|
16
17
|
const NEAREST_NEIGHBOR_COUNT = 3
|
|
17
18
|
|
|
@@ -104,6 +105,11 @@ export class LongDistancePairSolver extends BaseSolver {
|
|
|
104
105
|
InputPin & { chipId: string },
|
|
105
106
|
InputPin & { chipId: string },
|
|
106
107
|
] = [sourcePin, neighbor.pin]
|
|
108
|
+
if (
|
|
109
|
+
arePinsInDifferentSchematicSections(inputProblem, pair[0], pair[1])
|
|
110
|
+
) {
|
|
111
|
+
continue
|
|
112
|
+
}
|
|
107
113
|
const pairKey = pair
|
|
108
114
|
.map((p) => p.pinId)
|
|
109
115
|
.sort()
|
|
@@ -225,7 +231,10 @@ export class LongDistancePairSolver extends BaseSolver {
|
|
|
225
231
|
allTracesMerged: SolvedTracePath[]
|
|
226
232
|
} {
|
|
227
233
|
if (!this.solved) {
|
|
228
|
-
return {
|
|
234
|
+
return {
|
|
235
|
+
newTraces: [],
|
|
236
|
+
allTracesMerged: this.params.alreadySolvedTraces,
|
|
237
|
+
}
|
|
229
238
|
}
|
|
230
239
|
return {
|
|
231
240
|
newTraces: this.solvedLongDistanceTraces,
|
|
@@ -12,6 +12,7 @@ import { doesPairCrossRestrictedCenterLines } from "./doesPairCrossRestrictedCen
|
|
|
12
12
|
import type { GraphicsObject } from "graphics-debug"
|
|
13
13
|
import { getColorFromString } from "lib/utils/getColorFromString"
|
|
14
14
|
import { visualizeInputProblem } from "../SchematicTracePipelineSolver/visualizeInputProblem"
|
|
15
|
+
import { arePinsInDifferentSchematicSections } from "../../utils/arePinsInDifferentSchematicSections"
|
|
15
16
|
|
|
16
17
|
export type MspConnectionPairId = string
|
|
17
18
|
|
|
@@ -110,6 +111,9 @@ export class MspConnectionPairSolver extends BaseSolver {
|
|
|
110
111
|
// Too far apart; skip creating an MSP pair for this net
|
|
111
112
|
return
|
|
112
113
|
}
|
|
114
|
+
if (arePinsInDifferentSchematicSections(this.inputProblem, p1, p2)) {
|
|
115
|
+
return
|
|
116
|
+
}
|
|
113
117
|
// Avoid pairs that would cross restricted center lines
|
|
114
118
|
const pinIdMap = new Map(Object.entries(this.pinMap)) as Map<
|
|
115
119
|
PinId,
|
|
@@ -153,6 +157,11 @@ export class MspConnectionPairSolver extends BaseSolver {
|
|
|
153
157
|
{
|
|
154
158
|
maxDistance: this.maxMspPairDistance,
|
|
155
159
|
forbidEdge: (a, b) =>
|
|
160
|
+
arePinsInDifferentSchematicSections(
|
|
161
|
+
this.inputProblem,
|
|
162
|
+
a as InputPin & { chipId: string },
|
|
163
|
+
b as InputPin & { chipId: string },
|
|
164
|
+
) ||
|
|
156
165
|
doesPairCrossRestrictedCenterLines({
|
|
157
166
|
inputProblem: this.inputProblem,
|
|
158
167
|
chipMap: this.chipMap,
|
|
@@ -166,6 +175,11 @@ export class MspConnectionPairSolver extends BaseSolver {
|
|
|
166
175
|
for (const [pin1, pin2] of msp) {
|
|
167
176
|
const p1Obj = this.pinMap[pin1!]!
|
|
168
177
|
const p2Obj = this.pinMap[pin2!]!
|
|
178
|
+
if (
|
|
179
|
+
arePinsInDifferentSchematicSections(this.inputProblem, p1Obj, p2Obj)
|
|
180
|
+
) {
|
|
181
|
+
continue
|
|
182
|
+
}
|
|
169
183
|
// Skip any edge that would cross a restricted center line (safety filter)
|
|
170
184
|
if (
|
|
171
185
|
doesPairCrossRestrictedCenterLines({
|