@tscircuit/schematic-trace-solver 0.0.94 → 0.0.96
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 +19 -12
- package/dist/index.js +78 -57
- package/lib/solvers/{VccNetLabelCornerPlacementSolver/VccNetLabelCornerPlacementSolver.ts → RailNetLabelCornerPlacementSolver/RailNetLabelCornerPlacementSolver.ts} +27 -9
- package/lib/solvers/{VccNetLabelCornerPlacementSolver → RailNetLabelCornerPlacementSolver}/types.ts +7 -1
- package/lib/solvers/{VccNetLabelCornerPlacementSolver → RailNetLabelCornerPlacementSolver}/visualize.ts +1 -1
- package/lib/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver.ts +17 -12
- package/lib/solvers/SchematicTracePipelineSolver/visualizeInputProblem.ts +47 -40
- package/lib/types/InputProblem.ts +1 -0
- package/package.json +1 -1
- package/tests/bug-reports/bug-report-20260706T213649Z/__snapshots__/bug-report-20260706T213649Z.snap.svg +1 -1
- package/tests/bug-reports/bug-report-20260706T213649Z/bug-report-20260706T213649Z.test.ts +3 -1
- package/tests/bug-reports/bug-report-20260706T220324Z/__snapshots__/bug-report-20260706T220324Z.snap.svg +314 -314
- package/tests/bug-reports/bug-report-20260707T092615Z/__snapshots__/bug-report-20260707T092615Z.snap.svg +5 -5
- package/tests/bug-reports/bug-report-20260707T092615Z/bug-report-20260707T092615Z.test.ts +3 -1
- package/tests/bug-reports/bug-report-20260707T134722Z/__snapshots__/bug-report-20260707T134722Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260707T140410Z/__snapshots__/bug-report-20260707T140410Z.snap.svg +8 -8
- package/tests/bug-reports/bug-report-20260707T141421Z/__snapshots__/bug-report-20260707T141421Z.snap.svg +4 -4
- package/tests/bug-reports/bug-report-20260707T230831Z/__snapshots__/bug-report-20260707T230831Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260708T095725Z/__snapshots__/bug-report-20260708T095725Z.snap.svg +2 -2
- package/tests/examples/__snapshots__/example01.snap.svg +2 -2
- package/tests/examples/__snapshots__/example02.snap.svg +4 -4
- package/tests/examples/__snapshots__/example07.snap.svg +2 -2
- package/tests/examples/__snapshots__/example12.snap.svg +2 -2
- package/tests/examples/__snapshots__/example14.snap.svg +36 -36
- package/tests/examples/__snapshots__/example15.snap.svg +2 -2
- package/tests/examples/__snapshots__/example18.snap.svg +4 -4
- package/tests/examples/__snapshots__/example19.snap.svg +22 -22
- package/tests/examples/__snapshots__/example21.snap.svg +4 -4
- package/tests/examples/__snapshots__/example25.snap.svg +35 -35
- package/tests/examples/__snapshots__/example29.snap.svg +10 -10
- package/tests/examples/__snapshots__/example31.snap.svg +6 -6
- package/tests/examples/__snapshots__/example32.snap.svg +2 -2
- package/tests/examples/__snapshots__/example46.snap.svg +2 -2
- package/tests/examples/__snapshots__/example47.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-ina237-current-monitor.snap.svg +4 -4
- package/tests/repros/__snapshots__/repro-netlabel-overlap-trace.snap.svg +2 -2
- package/tests/repros/__snapshots__/trace-overlap-box-resistor.snap.svg +2 -2
- /package/lib/solvers/{VccNetLabelCornerPlacementSolver → RailNetLabelCornerPlacementSolver}/geometry.ts +0 -0
package/dist/index.d.ts
CHANGED
|
@@ -103,6 +103,7 @@ interface InputProblem {
|
|
|
103
103
|
availableNetLabelOrientations: Record<NetId, FacingDirection[]>;
|
|
104
104
|
maxMspPairDistance?: number;
|
|
105
105
|
_chipObstacleSpatialIndex?: ChipObstacleSpatialIndex;
|
|
106
|
+
_hideRatsNet?: boolean;
|
|
106
107
|
}
|
|
107
108
|
|
|
108
109
|
type MspConnectionPairId = string;
|
|
@@ -788,7 +789,7 @@ declare class AvailableNetOrientationSolver extends BaseSolver {
|
|
|
788
789
|
visualize(): GraphicsObject;
|
|
789
790
|
}
|
|
790
791
|
|
|
791
|
-
interface
|
|
792
|
+
interface RailNetLabelCornerPlacementSolverParams {
|
|
792
793
|
inputProblem: InputProblem;
|
|
793
794
|
traces: SolvedTracePath[];
|
|
794
795
|
netLabelPlacements: NetLabelPlacement[];
|
|
@@ -797,6 +798,12 @@ type TraceCornerCandidate = {
|
|
|
797
798
|
anchorPoint: Point;
|
|
798
799
|
traceId: string;
|
|
799
800
|
distance: number;
|
|
801
|
+
/**
|
|
802
|
+
* True when the corner lines up with one of the trace's pins along the
|
|
803
|
+
* label's stub axis (same x for a vertical rail label), so the label reads as
|
|
804
|
+
* a clean stub off that pin rather than floating over a mid-trace bend.
|
|
805
|
+
*/
|
|
806
|
+
pinAligned: boolean;
|
|
800
807
|
};
|
|
801
808
|
type CornerCandidateStatus = "valid" | "chip-collision" | "text-collision" | "trace-collision" | "netlabel-collision";
|
|
802
809
|
type EvaluatedCornerCandidate = TraceCornerCandidate & {
|
|
@@ -807,7 +814,7 @@ type EvaluatedCornerCandidate = TraceCornerCandidate & {
|
|
|
807
814
|
selected: boolean;
|
|
808
815
|
};
|
|
809
816
|
|
|
810
|
-
declare class
|
|
817
|
+
declare class RailNetLabelCornerPlacementSolver extends BaseSolver {
|
|
811
818
|
inputProblem: InputProblem;
|
|
812
819
|
traces: SolvedTracePath[];
|
|
813
820
|
netLabelPlacements: NetLabelPlacement[];
|
|
@@ -819,8 +826,8 @@ declare class VccNetLabelCornerPlacementSolver extends BaseSolver {
|
|
|
819
826
|
private queuedCornerCandidates;
|
|
820
827
|
private shouldAdvanceToNextLabel;
|
|
821
828
|
private traceMap;
|
|
822
|
-
constructor(params:
|
|
823
|
-
getConstructorParams(): ConstructorParameters<typeof
|
|
829
|
+
constructor(params: RailNetLabelCornerPlacementSolverParams);
|
|
830
|
+
getConstructorParams(): ConstructorParameters<typeof RailNetLabelCornerPlacementSolver>[0];
|
|
824
831
|
_step(): void;
|
|
825
832
|
getOutput(): {
|
|
826
833
|
netLabelPlacements: NetLabelPlacement[];
|
|
@@ -1006,9 +1013,8 @@ type PipelineStep<T extends new (...args: any[]) => BaseSolver> = {
|
|
|
1006
1013
|
onSolved?: (instance: SchematicTracePipelineSolver) => void;
|
|
1007
1014
|
shouldSkip?: (instance: SchematicTracePipelineSolver) => boolean;
|
|
1008
1015
|
};
|
|
1009
|
-
interface
|
|
1010
|
-
|
|
1011
|
-
allowLongDistanceTraces?: boolean;
|
|
1016
|
+
interface Options {
|
|
1017
|
+
hideRatsNet?: boolean;
|
|
1012
1018
|
}
|
|
1013
1019
|
declare class SchematicTracePipelineSolver extends BaseSolver {
|
|
1014
1020
|
mspConnectionPairSolver?: MspConnectionPairSolver;
|
|
@@ -1021,7 +1027,7 @@ declare class SchematicTracePipelineSolver extends BaseSolver {
|
|
|
1021
1027
|
traceCleanupSolver?: TraceCleanupSolver;
|
|
1022
1028
|
example28Solver?: Example28Solver;
|
|
1023
1029
|
availableNetOrientationSolver?: AvailableNetOrientationSolver;
|
|
1024
|
-
|
|
1030
|
+
railNetLabelCornerPlacementSolver?: RailNetLabelCornerPlacementSolver;
|
|
1025
1031
|
traceAnchoredNetLabelOverlapSolver?: TraceAnchoredNetLabelOverlapSolver;
|
|
1026
1032
|
netLabelTraceCollisionSolver?: NetLabelTraceCollisionSolver;
|
|
1027
1033
|
netLabelNetLabelCollisionSolver?: NetLabelNetLabelCollisionSolver;
|
|
@@ -1030,9 +1036,10 @@ declare class SchematicTracePipelineSolver extends BaseSolver {
|
|
|
1030
1036
|
timeSpentOnPhase: Record<string, number>;
|
|
1031
1037
|
firstIterationOfPhase: Record<string, number>;
|
|
1032
1038
|
inputProblem: InputProblem;
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1039
|
+
hideRatsNet: boolean;
|
|
1040
|
+
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 RailNetLabelCornerPlacementSolver> | PipelineStep<typeof TraceAnchoredNetLabelOverlapSolver> | PipelineStep<typeof NetLabelTraceCollisionSolver> | PipelineStep<typeof NetLabelNetLabelCollisionSolver>)[];
|
|
1041
|
+
constructor(inputProblem: InputProblem, opts?: Options);
|
|
1042
|
+
getConstructorParams(): ConstructorParameters<typeof SchematicTracePipelineSolver>;
|
|
1036
1043
|
currentPipelineStepIndex: number;
|
|
1037
1044
|
private cloneAndCorrectInputProblem;
|
|
1038
1045
|
_step(): void;
|
|
@@ -1046,4 +1053,4 @@ declare class SchematicTracePipelineSolver extends BaseSolver {
|
|
|
1046
1053
|
preview(): GraphicsObject;
|
|
1047
1054
|
}
|
|
1048
1055
|
|
|
1049
|
-
export { type ChipId, type InputChip, type InputDirectConnection, type InputNetConnection, type InputPin, type InputProblem, type NetId, type PinId, SchematicTracePipelineSolver,
|
|
1056
|
+
export { type ChipId, type InputChip, type InputDirectConnection, type InputNetConnection, type InputPin, type InputProblem, type NetId, type PinId, SchematicTracePipelineSolver, SchematicTraceSingleLineSolver2, type SectionId, type TextBoxes };
|
package/dist/index.js
CHANGED
|
@@ -327,7 +327,11 @@ var arePinsInDifferentSchematicSections = (inputProblem, p1, p2) => {
|
|
|
327
327
|
|
|
328
328
|
// lib/solvers/SchematicTracePipelineSolver/visualizeInputProblem.ts
|
|
329
329
|
var visualizeInputProblem = (inputProblem, opts = {}) => {
|
|
330
|
-
const {
|
|
330
|
+
const {
|
|
331
|
+
connectionAlpha = 0.8,
|
|
332
|
+
chipAlpha = 0.8,
|
|
333
|
+
hideRatsNet = inputProblem._hideRatsNet ?? false
|
|
334
|
+
} = opts;
|
|
331
335
|
const graphics = {
|
|
332
336
|
lines: [],
|
|
333
337
|
points: [],
|
|
@@ -367,47 +371,49 @@ ${pin._facingDirection ?? getPinDirection(pin, chip)}`,
|
|
|
367
371
|
strokeColor: "rgba(160, 0, 220, 0.9)"
|
|
368
372
|
});
|
|
369
373
|
}
|
|
370
|
-
|
|
371
|
-
const
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
374
|
+
if (!hideRatsNet) {
|
|
375
|
+
for (const directConn of inputProblem.directConnections) {
|
|
376
|
+
const [pinId1, pinId2] = directConn.pinIds;
|
|
377
|
+
const pin1 = pinIdMap.get(pinId1);
|
|
378
|
+
const pin2 = pinIdMap.get(pinId2);
|
|
379
|
+
if (arePinsInDifferentSchematicSections(inputProblem, pin1, pin2)) {
|
|
380
|
+
continue;
|
|
381
|
+
}
|
|
382
|
+
graphics.lines.push({
|
|
383
|
+
points: [
|
|
384
|
+
{
|
|
385
|
+
x: pin1.x,
|
|
386
|
+
y: pin1.y
|
|
387
|
+
},
|
|
388
|
+
{
|
|
389
|
+
x: pin2.x,
|
|
390
|
+
y: pin2.y
|
|
391
|
+
}
|
|
392
|
+
],
|
|
393
|
+
strokeColor: getColorFromString(
|
|
394
|
+
directConn.netId ?? `${pinId1}-${pinId2}`,
|
|
395
|
+
connectionAlpha
|
|
396
|
+
)
|
|
397
|
+
});
|
|
376
398
|
}
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
for (const netConn of inputProblem.netConnections) {
|
|
395
|
-
const pins = netConn.pinIds.map((pinId) => pinIdMap.get(pinId));
|
|
396
|
-
for (let i = 0; i < pins.length - 1; i++) {
|
|
397
|
-
for (let j = i + 1; j < pins.length; j++) {
|
|
398
|
-
const pin1 = pins[i];
|
|
399
|
-
const pin2 = pins[j];
|
|
400
|
-
if (arePinsInDifferentSchematicSections(inputProblem, pin1, pin2)) {
|
|
401
|
-
continue;
|
|
399
|
+
for (const netConn of inputProblem.netConnections) {
|
|
400
|
+
const pins = netConn.pinIds.map((pinId) => pinIdMap.get(pinId));
|
|
401
|
+
for (let i = 0; i < pins.length - 1; i++) {
|
|
402
|
+
for (let j = i + 1; j < pins.length; j++) {
|
|
403
|
+
const pin1 = pins[i];
|
|
404
|
+
const pin2 = pins[j];
|
|
405
|
+
if (arePinsInDifferentSchematicSections(inputProblem, pin1, pin2)) {
|
|
406
|
+
continue;
|
|
407
|
+
}
|
|
408
|
+
graphics.lines.push({
|
|
409
|
+
points: [
|
|
410
|
+
{ x: pin1.x, y: pin1.y },
|
|
411
|
+
{ x: pin2.x, y: pin2.y }
|
|
412
|
+
],
|
|
413
|
+
strokeColor: getColorFromString(netConn.netId, connectionAlpha),
|
|
414
|
+
strokeDash: "4 2"
|
|
415
|
+
});
|
|
402
416
|
}
|
|
403
|
-
graphics.lines.push({
|
|
404
|
-
points: [
|
|
405
|
-
{ x: pin1.x, y: pin1.y },
|
|
406
|
-
{ x: pin2.x, y: pin2.y }
|
|
407
|
-
],
|
|
408
|
-
strokeColor: getColorFromString(netConn.netId, connectionAlpha),
|
|
409
|
-
strokeDash: "4 2"
|
|
410
|
-
});
|
|
411
417
|
}
|
|
412
418
|
}
|
|
413
419
|
}
|
|
@@ -7302,7 +7308,7 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
7302
7308
|
}
|
|
7303
7309
|
};
|
|
7304
7310
|
|
|
7305
|
-
// lib/solvers/
|
|
7311
|
+
// lib/solvers/RailNetLabelCornerPlacementSolver/geometry.ts
|
|
7306
7312
|
var EPS9 = 1e-6;
|
|
7307
7313
|
var isTraceLine = (trace) => getUniquePinCount(trace.pinIds) >= 2;
|
|
7308
7314
|
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;
|
|
@@ -7335,10 +7341,10 @@ var isPointOnSegment = (point, start, end) => {
|
|
|
7335
7341
|
};
|
|
7336
7342
|
var getSegmentOrientation2 = (a, b) => Math.abs(a.y - b.y) <= EPS9 ? "horizontal" : "vertical";
|
|
7337
7343
|
|
|
7338
|
-
// lib/solvers/
|
|
7344
|
+
// lib/solvers/RailNetLabelCornerPlacementSolver/visualize.ts
|
|
7339
7345
|
var CANDIDATE_SELECTED_COLOR3 = "blue";
|
|
7340
7346
|
var CANDIDATE_REJECTED_COLOR3 = "red";
|
|
7341
|
-
var
|
|
7347
|
+
var visualizeRailNetLabelCornerPlacementSolver = (state) => {
|
|
7342
7348
|
const graphics = visualizeInputProblem(state.inputProblem);
|
|
7343
7349
|
ensureGraphicsArrays2(graphics);
|
|
7344
7350
|
drawTraces3(graphics, state.traces);
|
|
@@ -7419,8 +7425,8 @@ var ensureGraphicsArrays2 = (graphics) => {
|
|
|
7419
7425
|
if (!graphics.texts) graphics.texts = [];
|
|
7420
7426
|
};
|
|
7421
7427
|
|
|
7422
|
-
// lib/solvers/
|
|
7423
|
-
var
|
|
7428
|
+
// lib/solvers/RailNetLabelCornerPlacementSolver/RailNetLabelCornerPlacementSolver.ts
|
|
7429
|
+
var RailNetLabelCornerPlacementSolver = class extends BaseSolver {
|
|
7424
7430
|
inputProblem;
|
|
7425
7431
|
traces;
|
|
7426
7432
|
netLabelPlacements;
|
|
@@ -7552,7 +7558,8 @@ var VccNetLabelCornerPlacementSolver = class extends BaseSolver {
|
|
|
7552
7558
|
};
|
|
7553
7559
|
}
|
|
7554
7560
|
shouldProcessLabel(label) {
|
|
7555
|
-
|
|
7561
|
+
const isVerticalRailLabel = label.orientation === "y+" || label.orientation === "y-";
|
|
7562
|
+
return isVerticalRailLabel && this.getCornerCandidatesForLabel(label).length > 0;
|
|
7556
7563
|
}
|
|
7557
7564
|
intersectsAnyChip(bounds) {
|
|
7558
7565
|
return this.inputProblem.chips.some(
|
|
@@ -7569,17 +7576,26 @@ var VccNetLabelCornerPlacementSolver = class extends BaseSolver {
|
|
|
7569
7576
|
});
|
|
7570
7577
|
}
|
|
7571
7578
|
getCornerCandidatesForLabel(label) {
|
|
7579
|
+
const isVertical4 = label.orientation === "y+" || label.orientation === "y-";
|
|
7572
7580
|
const candidates = [];
|
|
7573
7581
|
const seenCornerKeys = /* @__PURE__ */ new Set();
|
|
7574
7582
|
for (const trace of this.getTraceLinesForLabel(label)) {
|
|
7575
|
-
|
|
7583
|
+
const path = trace.tracePath;
|
|
7584
|
+
const pins = [path[0], path[path.length - 1]];
|
|
7585
|
+
for (const anchorPoint of getTraceCorners(path)) {
|
|
7576
7586
|
const key = `${anchorPoint.x}:${anchorPoint.y}`;
|
|
7577
7587
|
if (seenCornerKeys.has(key)) continue;
|
|
7578
7588
|
seenCornerKeys.add(key);
|
|
7589
|
+
const pinAligned = pins.some((pin) => {
|
|
7590
|
+
if (isVertical4) return Math.abs(pin.x - anchorPoint.x) < EPS9;
|
|
7591
|
+
return Math.abs(pin.y - anchorPoint.y) < EPS9;
|
|
7592
|
+
});
|
|
7593
|
+
if (!pinAligned) continue;
|
|
7579
7594
|
candidates.push({
|
|
7580
7595
|
anchorPoint,
|
|
7581
7596
|
traceId: trace.mspPairId,
|
|
7582
|
-
distance: getDistance2(anchorPoint, label.anchorPoint)
|
|
7597
|
+
distance: getDistance2(anchorPoint, label.anchorPoint),
|
|
7598
|
+
pinAligned
|
|
7583
7599
|
});
|
|
7584
7600
|
}
|
|
7585
7601
|
}
|
|
@@ -7601,7 +7617,7 @@ var VccNetLabelCornerPlacementSolver = class extends BaseSolver {
|
|
|
7601
7617
|
return trace.globalConnNetId === label.globalConnNetId;
|
|
7602
7618
|
}
|
|
7603
7619
|
visualize() {
|
|
7604
|
-
return
|
|
7620
|
+
return visualizeRailNetLabelCornerPlacementSolver({
|
|
7605
7621
|
inputProblem: this.inputProblem,
|
|
7606
7622
|
traces: this.traces,
|
|
7607
7623
|
outputNetLabelPlacements: this.outputNetLabelPlacements,
|
|
@@ -9015,7 +9031,7 @@ var SchematicTracePipelineSolver = class extends BaseSolver {
|
|
|
9015
9031
|
traceCleanupSolver;
|
|
9016
9032
|
example28Solver;
|
|
9017
9033
|
availableNetOrientationSolver;
|
|
9018
|
-
|
|
9034
|
+
railNetLabelCornerPlacementSolver;
|
|
9019
9035
|
traceAnchoredNetLabelOverlapSolver;
|
|
9020
9036
|
netLabelTraceCollisionSolver;
|
|
9021
9037
|
netLabelNetLabelCollisionSolver;
|
|
@@ -9024,6 +9040,7 @@ var SchematicTracePipelineSolver = class extends BaseSolver {
|
|
|
9024
9040
|
timeSpentOnPhase;
|
|
9025
9041
|
firstIterationOfPhase;
|
|
9026
9042
|
inputProblem;
|
|
9043
|
+
hideRatsNet;
|
|
9027
9044
|
pipelineDef = [
|
|
9028
9045
|
definePipelineStep(
|
|
9029
9046
|
"mspConnectionPairSolver",
|
|
@@ -9177,8 +9194,8 @@ var SchematicTracePipelineSolver = class extends BaseSolver {
|
|
|
9177
9194
|
]
|
|
9178
9195
|
),
|
|
9179
9196
|
definePipelineStep(
|
|
9180
|
-
"
|
|
9181
|
-
|
|
9197
|
+
"railNetLabelCornerPlacementSolver",
|
|
9198
|
+
RailNetLabelCornerPlacementSolver,
|
|
9182
9199
|
(instance) => {
|
|
9183
9200
|
return [
|
|
9184
9201
|
{
|
|
@@ -9196,7 +9213,7 @@ var SchematicTracePipelineSolver = class extends BaseSolver {
|
|
|
9196
9213
|
{
|
|
9197
9214
|
inputProblem: instance.inputProblem,
|
|
9198
9215
|
traces: instance.availableNetOrientationSolver.traces,
|
|
9199
|
-
netLabelPlacements: instance.
|
|
9216
|
+
netLabelPlacements: instance.railNetLabelCornerPlacementSolver.outputNetLabelPlacements
|
|
9200
9217
|
}
|
|
9201
9218
|
]
|
|
9202
9219
|
),
|
|
@@ -9223,8 +9240,9 @@ var SchematicTracePipelineSolver = class extends BaseSolver {
|
|
|
9223
9240
|
]
|
|
9224
9241
|
)
|
|
9225
9242
|
];
|
|
9226
|
-
constructor(inputProblem) {
|
|
9243
|
+
constructor(inputProblem, opts) {
|
|
9227
9244
|
super();
|
|
9245
|
+
this.hideRatsNet = opts?.hideRatsNet ?? false;
|
|
9228
9246
|
this.inputProblem = this.cloneAndCorrectInputProblem(inputProblem);
|
|
9229
9247
|
this.MAX_ITERATIONS = 1e6;
|
|
9230
9248
|
this.startTimeOfPhase = {};
|
|
@@ -9233,13 +9251,14 @@ var SchematicTracePipelineSolver = class extends BaseSolver {
|
|
|
9233
9251
|
this.firstIterationOfPhase = {};
|
|
9234
9252
|
}
|
|
9235
9253
|
getConstructorParams() {
|
|
9236
|
-
return this.inputProblem;
|
|
9254
|
+
return [this.inputProblem, { hideRatsNet: this.hideRatsNet }];
|
|
9237
9255
|
}
|
|
9238
9256
|
currentPipelineStepIndex = 0;
|
|
9239
9257
|
cloneAndCorrectInputProblem(original) {
|
|
9240
9258
|
const cloned = structuredClone({
|
|
9241
9259
|
...original,
|
|
9242
|
-
_chipObstacleSpatialIndex: void 0
|
|
9260
|
+
_chipObstacleSpatialIndex: void 0,
|
|
9261
|
+
_hideRatsNet: this.hideRatsNet
|
|
9243
9262
|
});
|
|
9244
9263
|
expandChipsToFitPins(cloned);
|
|
9245
9264
|
correctPinsInsideChips(cloned);
|
|
@@ -9285,7 +9304,9 @@ var SchematicTracePipelineSolver = class extends BaseSolver {
|
|
|
9285
9304
|
if (!this.solved && this.activeSubSolver)
|
|
9286
9305
|
return this.activeSubSolver.visualize();
|
|
9287
9306
|
const visualizations = [
|
|
9288
|
-
visualizeInputProblem(this.inputProblem
|
|
9307
|
+
visualizeInputProblem(this.inputProblem, {
|
|
9308
|
+
hideRatsNet: this.hideRatsNet
|
|
9309
|
+
}),
|
|
9289
9310
|
...this.pipelineDef.map((p) => this[p.solverName]?.visualize()).filter(Boolean).map((viz, stepIndex) => {
|
|
9290
9311
|
for (const rect of viz.rects ?? []) {
|
|
9291
9312
|
rect.step = stepIndex;
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
import type { SolvedTracePath } from "lib/solvers/SchematicTraceLinesSolver/SchematicTraceLinesSolver"
|
|
10
10
|
import type { InputProblem } from "lib/types/InputProblem"
|
|
11
11
|
import {
|
|
12
|
+
EPS,
|
|
12
13
|
getDistance,
|
|
13
14
|
getTraceCorners,
|
|
14
15
|
isTraceLine,
|
|
@@ -20,12 +21,12 @@ import type {
|
|
|
20
21
|
CornerCandidateStatus,
|
|
21
22
|
EvaluatedCornerCandidate,
|
|
22
23
|
TraceCornerCandidate,
|
|
23
|
-
|
|
24
|
+
RailNetLabelCornerPlacementSolverParams,
|
|
24
25
|
} from "./types"
|
|
25
|
-
import {
|
|
26
|
+
import { visualizeRailNetLabelCornerPlacementSolver } from "./visualize"
|
|
26
27
|
import { rectIntersectsAnyTextBox } from "lib/utils/textBoxBounds"
|
|
27
28
|
|
|
28
|
-
export class
|
|
29
|
+
export class RailNetLabelCornerPlacementSolver extends BaseSolver {
|
|
29
30
|
inputProblem: InputProblem
|
|
30
31
|
traces: SolvedTracePath[]
|
|
31
32
|
netLabelPlacements: NetLabelPlacement[]
|
|
@@ -40,7 +41,7 @@ export class VccNetLabelCornerPlacementSolver extends BaseSolver {
|
|
|
40
41
|
private shouldAdvanceToNextLabel = false
|
|
41
42
|
private traceMap: Record<string, SolvedTracePath>
|
|
42
43
|
|
|
43
|
-
constructor(params:
|
|
44
|
+
constructor(params: RailNetLabelCornerPlacementSolverParams) {
|
|
44
45
|
super()
|
|
45
46
|
this.inputProblem = params.inputProblem
|
|
46
47
|
this.traces = params.traces
|
|
@@ -54,7 +55,7 @@ export class VccNetLabelCornerPlacementSolver extends BaseSolver {
|
|
|
54
55
|
}
|
|
55
56
|
|
|
56
57
|
override getConstructorParams(): ConstructorParameters<
|
|
57
|
-
typeof
|
|
58
|
+
typeof RailNetLabelCornerPlacementSolver
|
|
58
59
|
>[0] {
|
|
59
60
|
return {
|
|
60
61
|
inputProblem: this.inputProblem,
|
|
@@ -197,9 +198,13 @@ export class VccNetLabelCornerPlacementSolver extends BaseSolver {
|
|
|
197
198
|
}
|
|
198
199
|
|
|
199
200
|
private shouldProcessLabel(label: NetLabelPlacement) {
|
|
201
|
+
// Power/ground rail labels (VCC, GND, V3_3, ...) have a fixed vertical
|
|
202
|
+
// orientation and read best snapped to a trace corner rather than floating
|
|
203
|
+
// mid-segment. Signal labels (x+/x-) are left where they are.
|
|
204
|
+
const isVerticalRailLabel =
|
|
205
|
+
label.orientation === "y+" || label.orientation === "y-"
|
|
200
206
|
return (
|
|
201
|
-
label.
|
|
202
|
-
this.getCornerCandidatesForLabel(label).length > 0
|
|
207
|
+
isVerticalRailLabel && this.getCornerCandidatesForLabel(label).length > 0
|
|
203
208
|
)
|
|
204
209
|
}
|
|
205
210
|
|
|
@@ -220,18 +225,31 @@ export class VccNetLabelCornerPlacementSolver extends BaseSolver {
|
|
|
220
225
|
}
|
|
221
226
|
|
|
222
227
|
private getCornerCandidatesForLabel(label: NetLabelPlacement) {
|
|
228
|
+
const isVertical = label.orientation === "y+" || label.orientation === "y-"
|
|
223
229
|
const candidates: TraceCornerCandidate[] = []
|
|
224
230
|
const seenCornerKeys = new Set<string>()
|
|
225
231
|
|
|
226
232
|
for (const trace of this.getTraceLinesForLabel(label)) {
|
|
227
|
-
|
|
233
|
+
const path = trace.tracePath
|
|
234
|
+
const pins = [path[0]!, path[path.length - 1]!]
|
|
235
|
+
for (const anchorPoint of getTraceCorners(path)) {
|
|
228
236
|
const key = `${anchorPoint.x}:${anchorPoint.y}`
|
|
229
237
|
if (seenCornerKeys.has(key)) continue
|
|
230
238
|
seenCornerKeys.add(key)
|
|
239
|
+
const pinAligned = pins.some((pin) => {
|
|
240
|
+
if (isVertical) return Math.abs(pin.x - anchorPoint.x) < EPS
|
|
241
|
+
return Math.abs(pin.y - anchorPoint.y) < EPS
|
|
242
|
+
})
|
|
243
|
+
// Only pin-aligned corners are worth snapping a rail label to (a clean
|
|
244
|
+
// stub off a pin). Non-aligned corners are no better than where the
|
|
245
|
+
// label already is, so they aren't offered as candidates — this keeps
|
|
246
|
+
// already-well-placed labels untouched.
|
|
247
|
+
if (!pinAligned) continue
|
|
231
248
|
candidates.push({
|
|
232
249
|
anchorPoint,
|
|
233
250
|
traceId: trace.mspPairId,
|
|
234
251
|
distance: getDistance(anchorPoint, label.anchorPoint),
|
|
252
|
+
pinAligned,
|
|
235
253
|
})
|
|
236
254
|
}
|
|
237
255
|
}
|
|
@@ -259,7 +277,7 @@ export class VccNetLabelCornerPlacementSolver extends BaseSolver {
|
|
|
259
277
|
}
|
|
260
278
|
|
|
261
279
|
override visualize(): GraphicsObject {
|
|
262
|
-
return
|
|
280
|
+
return visualizeRailNetLabelCornerPlacementSolver({
|
|
263
281
|
inputProblem: this.inputProblem,
|
|
264
282
|
traces: this.traces,
|
|
265
283
|
outputNetLabelPlacements: this.outputNetLabelPlacements,
|
package/lib/solvers/{VccNetLabelCornerPlacementSolver → RailNetLabelCornerPlacementSolver}/types.ts
RENAMED
|
@@ -3,7 +3,7 @@ import type { NetLabelPlacement } from "lib/solvers/NetLabelPlacementSolver/NetL
|
|
|
3
3
|
import type { SolvedTracePath } from "lib/solvers/SchematicTraceLinesSolver/SchematicTraceLinesSolver"
|
|
4
4
|
import type { InputProblem } from "lib/types/InputProblem"
|
|
5
5
|
|
|
6
|
-
export interface
|
|
6
|
+
export interface RailNetLabelCornerPlacementSolverParams {
|
|
7
7
|
inputProblem: InputProblem
|
|
8
8
|
traces: SolvedTracePath[]
|
|
9
9
|
netLabelPlacements: NetLabelPlacement[]
|
|
@@ -20,6 +20,12 @@ export type TraceCornerCandidate = {
|
|
|
20
20
|
anchorPoint: Point
|
|
21
21
|
traceId: string
|
|
22
22
|
distance: number
|
|
23
|
+
/**
|
|
24
|
+
* True when the corner lines up with one of the trace's pins along the
|
|
25
|
+
* label's stub axis (same x for a vertical rail label), so the label reads as
|
|
26
|
+
* a clean stub off that pin rather than floating over a mid-trace bend.
|
|
27
|
+
*/
|
|
28
|
+
pinAligned: boolean
|
|
23
29
|
}
|
|
24
30
|
|
|
25
31
|
export type CornerCandidateStatus =
|
|
@@ -9,7 +9,7 @@ import type { EvaluatedCornerCandidate } from "./types"
|
|
|
9
9
|
const CANDIDATE_SELECTED_COLOR = "blue"
|
|
10
10
|
const CANDIDATE_REJECTED_COLOR = "red"
|
|
11
11
|
|
|
12
|
-
export const
|
|
12
|
+
export const visualizeRailNetLabelCornerPlacementSolver = (state: {
|
|
13
13
|
inputProblem: InputProblem
|
|
14
14
|
traces: SolvedTracePath[]
|
|
15
15
|
outputNetLabelPlacements: NetLabelPlacement[]
|
|
@@ -23,7 +23,7 @@ import { MergedNetLabelObstacleSolver } from "../TraceLabelOverlapAvoidanceSolve
|
|
|
23
23
|
import { TraceCleanupSolver } from "../TraceCleanupSolver/TraceCleanupSolver"
|
|
24
24
|
import { Example28Solver } from "../Example28Solver/Example28Solver"
|
|
25
25
|
import { AvailableNetOrientationSolver } from "../AvailableNetOrientationSolver/AvailableNetOrientationSolver"
|
|
26
|
-
import {
|
|
26
|
+
import { RailNetLabelCornerPlacementSolver } from "../RailNetLabelCornerPlacementSolver/RailNetLabelCornerPlacementSolver"
|
|
27
27
|
import { TraceAnchoredNetLabelOverlapSolver } from "../TraceAnchoredNetLabelOverlapSolver/TraceAnchoredNetLabelOverlapSolver"
|
|
28
28
|
import { NetLabelTraceCollisionSolver } from "../NetLabelTraceCollisionSolver/NetLabelTraceCollisionSolver"
|
|
29
29
|
import { NetLabelNetLabelCollisionSolver } from "../NetLabelNetLabelCollisionSolver/NetLabelNetLabelCollisionSolver"
|
|
@@ -61,9 +61,8 @@ function definePipelineStep<
|
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
allowLongDistanceTraces?: boolean
|
|
64
|
+
interface Options {
|
|
65
|
+
hideRatsNet?: boolean
|
|
67
66
|
}
|
|
68
67
|
|
|
69
68
|
export class SchematicTracePipelineSolver extends BaseSolver {
|
|
@@ -78,7 +77,7 @@ export class SchematicTracePipelineSolver extends BaseSolver {
|
|
|
78
77
|
traceCleanupSolver?: TraceCleanupSolver
|
|
79
78
|
example28Solver?: Example28Solver
|
|
80
79
|
availableNetOrientationSolver?: AvailableNetOrientationSolver
|
|
81
|
-
|
|
80
|
+
railNetLabelCornerPlacementSolver?: RailNetLabelCornerPlacementSolver
|
|
82
81
|
traceAnchoredNetLabelOverlapSolver?: TraceAnchoredNetLabelOverlapSolver
|
|
83
82
|
netLabelTraceCollisionSolver?: NetLabelTraceCollisionSolver
|
|
84
83
|
netLabelNetLabelCollisionSolver?: NetLabelNetLabelCollisionSolver
|
|
@@ -89,6 +88,7 @@ export class SchematicTracePipelineSolver extends BaseSolver {
|
|
|
89
88
|
firstIterationOfPhase: Record<string, number>
|
|
90
89
|
|
|
91
90
|
inputProblem: InputProblem
|
|
91
|
+
hideRatsNet: boolean
|
|
92
92
|
|
|
93
93
|
pipelineDef = [
|
|
94
94
|
definePipelineStep(
|
|
@@ -264,8 +264,8 @@ export class SchematicTracePipelineSolver extends BaseSolver {
|
|
|
264
264
|
],
|
|
265
265
|
),
|
|
266
266
|
definePipelineStep(
|
|
267
|
-
"
|
|
268
|
-
|
|
267
|
+
"railNetLabelCornerPlacementSolver",
|
|
268
|
+
RailNetLabelCornerPlacementSolver,
|
|
269
269
|
(instance) => {
|
|
270
270
|
return [
|
|
271
271
|
{
|
|
@@ -285,7 +285,8 @@ export class SchematicTracePipelineSolver extends BaseSolver {
|
|
|
285
285
|
inputProblem: instance.inputProblem,
|
|
286
286
|
traces: instance.availableNetOrientationSolver!.traces,
|
|
287
287
|
netLabelPlacements:
|
|
288
|
-
instance.
|
|
288
|
+
instance.railNetLabelCornerPlacementSolver!
|
|
289
|
+
.outputNetLabelPlacements,
|
|
289
290
|
},
|
|
290
291
|
],
|
|
291
292
|
),
|
|
@@ -317,8 +318,9 @@ export class SchematicTracePipelineSolver extends BaseSolver {
|
|
|
317
318
|
),
|
|
318
319
|
]
|
|
319
320
|
|
|
320
|
-
constructor(inputProblem: InputProblem) {
|
|
321
|
+
constructor(inputProblem: InputProblem, opts?: Options) {
|
|
321
322
|
super()
|
|
323
|
+
this.hideRatsNet = opts?.hideRatsNet ?? false
|
|
322
324
|
this.inputProblem = this.cloneAndCorrectInputProblem(inputProblem)
|
|
323
325
|
this.MAX_ITERATIONS = 1e6
|
|
324
326
|
this.startTimeOfPhase = {}
|
|
@@ -329,8 +331,8 @@ export class SchematicTracePipelineSolver extends BaseSolver {
|
|
|
329
331
|
|
|
330
332
|
override getConstructorParams(): ConstructorParameters<
|
|
331
333
|
typeof SchematicTracePipelineSolver
|
|
332
|
-
>
|
|
333
|
-
return this.inputProblem
|
|
334
|
+
> {
|
|
335
|
+
return [this.inputProblem, { hideRatsNet: this.hideRatsNet }]
|
|
334
336
|
}
|
|
335
337
|
|
|
336
338
|
currentPipelineStepIndex = 0
|
|
@@ -339,6 +341,7 @@ export class SchematicTracePipelineSolver extends BaseSolver {
|
|
|
339
341
|
const cloned: InputProblem = structuredClone({
|
|
340
342
|
...original,
|
|
341
343
|
_chipObstacleSpatialIndex: undefined,
|
|
344
|
+
_hideRatsNet: this.hideRatsNet,
|
|
342
345
|
})
|
|
343
346
|
|
|
344
347
|
// First, expand chips so existing pin coordinates sit on or within their edges without shrinking.
|
|
@@ -398,7 +401,9 @@ export class SchematicTracePipelineSolver extends BaseSolver {
|
|
|
398
401
|
return this.activeSubSolver.visualize()
|
|
399
402
|
|
|
400
403
|
const visualizations = [
|
|
401
|
-
visualizeInputProblem(this.inputProblem
|
|
404
|
+
visualizeInputProblem(this.inputProblem, {
|
|
405
|
+
hideRatsNet: this.hideRatsNet,
|
|
406
|
+
}),
|
|
402
407
|
...(this.pipelineDef
|
|
403
408
|
.map((p) => (this as any)[p.solverName]?.visualize())
|
|
404
409
|
.filter(Boolean)
|