@tscircuit/schematic-trace-solver 0.0.61 → 0.0.62
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 +65 -5
- package/dist/index.js +344 -0
- package/lib/solvers/NetLabelNetLabelCollisionSolver/NetLabelNetLabelCollisionSolver.ts +441 -0
- package/lib/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver.ts +15 -0
- package/package.json +1 -1
- package/site/examples/example39.page.tsx +4 -0
- package/site/examples/example40.page.tsx +4 -0
- package/site/examples/example41.page.tsx +4 -0
- package/tests/assets/example39.json +71 -0
- package/tests/assets/example40.json +157 -0
- package/tests/assets/example41.json +81 -0
- package/tests/examples/__snapshots__/example39.snap.svg +107 -0
- package/tests/examples/__snapshots__/example40.snap.svg +231 -0
- package/tests/examples/__snapshots__/example41.snap.svg +119 -0
- package/tests/examples/example39.test.ts +12 -0
- package/tests/examples/example40.test.ts +12 -0
- package/tests/examples/example41.test.ts +12 -0
package/dist/index.d.ts
CHANGED
|
@@ -647,10 +647,10 @@ type CandidateLabel = {
|
|
|
647
647
|
width: number;
|
|
648
648
|
height: number;
|
|
649
649
|
};
|
|
650
|
-
type CandidateStatus$
|
|
650
|
+
type CandidateStatus$2 = "valid" | "chip-collision" | "trace-collision" | "netlabel-collision";
|
|
651
651
|
type CandidatePhase = "rotate" | "shift" | "lateral-shift";
|
|
652
652
|
type EvaluatedCandidate = CandidateLabel & {
|
|
653
|
-
status: CandidateStatus$
|
|
653
|
+
status: CandidateStatus$2;
|
|
654
654
|
selected: boolean;
|
|
655
655
|
phase: CandidatePhase;
|
|
656
656
|
distance?: number;
|
|
@@ -782,7 +782,7 @@ type LabelOverlap = {
|
|
|
782
782
|
firstLabelIndex: number;
|
|
783
783
|
secondLabelIndex: number;
|
|
784
784
|
};
|
|
785
|
-
type CandidateStatus = "valid" | "chip-collision" | "trace-collision" | "netlabel-collision";
|
|
785
|
+
type CandidateStatus$1 = "valid" | "chip-collision" | "trace-collision" | "netlabel-collision";
|
|
786
786
|
type LabelCandidate = {
|
|
787
787
|
anchorPoint: Point;
|
|
788
788
|
center: Point;
|
|
@@ -792,7 +792,7 @@ type LabelCandidate = {
|
|
|
792
792
|
traceId: string;
|
|
793
793
|
pathDistance: number;
|
|
794
794
|
distanceFromOriginal: number;
|
|
795
|
-
status: CandidateStatus;
|
|
795
|
+
status: CandidateStatus$1;
|
|
796
796
|
selected: boolean;
|
|
797
797
|
};
|
|
798
798
|
|
|
@@ -860,6 +860,65 @@ declare class NetLabelTraceCollisionSolver extends BaseSolver {
|
|
|
860
860
|
visualize(): GraphicsObject;
|
|
861
861
|
}
|
|
862
862
|
|
|
863
|
+
type CandidateStatus = "ok" | "chip-collision" | "trace-collision" | "label-collision";
|
|
864
|
+
type Candidate = {
|
|
865
|
+
orientation: FacingDirection;
|
|
866
|
+
anchor: {
|
|
867
|
+
x: number;
|
|
868
|
+
y: number;
|
|
869
|
+
};
|
|
870
|
+
center: {
|
|
871
|
+
x: number;
|
|
872
|
+
y: number;
|
|
873
|
+
};
|
|
874
|
+
width: number;
|
|
875
|
+
height: number;
|
|
876
|
+
bounds: {
|
|
877
|
+
minX: number;
|
|
878
|
+
minY: number;
|
|
879
|
+
maxX: number;
|
|
880
|
+
maxY: number;
|
|
881
|
+
};
|
|
882
|
+
hostPairId?: MspConnectionPairId;
|
|
883
|
+
hostSegIndex?: number;
|
|
884
|
+
status: CandidateStatus | null;
|
|
885
|
+
};
|
|
886
|
+
interface NetLabelNetLabelCollisionSolverParams {
|
|
887
|
+
inputProblem: InputProblem;
|
|
888
|
+
traces: SolvedTracePath[];
|
|
889
|
+
netLabelPlacements: NetLabelPlacement[];
|
|
890
|
+
}
|
|
891
|
+
declare class NetLabelNetLabelCollisionSolver extends BaseSolver {
|
|
892
|
+
inputProblem: InputProblem;
|
|
893
|
+
traces: SolvedTracePath[];
|
|
894
|
+
netLabelPlacements: NetLabelPlacement[];
|
|
895
|
+
outputNetLabelPlacements: NetLabelPlacement[];
|
|
896
|
+
currentCollision: [NetLabelPlacement, NetLabelPlacement] | null;
|
|
897
|
+
currentLabelToMove: NetLabelPlacement | null;
|
|
898
|
+
candidateResults: Candidate[];
|
|
899
|
+
private chipIndex;
|
|
900
|
+
private traceMap;
|
|
901
|
+
private skippedCollisionKeys;
|
|
902
|
+
private labelsToTry;
|
|
903
|
+
private candidateQueue;
|
|
904
|
+
private candidateIndex;
|
|
905
|
+
constructor(params: NetLabelNetLabelCollisionSolverParams);
|
|
906
|
+
getConstructorParams(): ConstructorParameters<typeof NetLabelNetLabelCollisionSolver>[0];
|
|
907
|
+
getOutput(): {
|
|
908
|
+
netLabelPlacements: NetLabelPlacement[];
|
|
909
|
+
};
|
|
910
|
+
private labelBounds;
|
|
911
|
+
private collisionKey;
|
|
912
|
+
private findNextCollidingPair;
|
|
913
|
+
private netLabelWidthOf;
|
|
914
|
+
private buildCandidatesForLabel;
|
|
915
|
+
private checkCandidate;
|
|
916
|
+
private beginSearchForLabel;
|
|
917
|
+
private clearActiveSearch;
|
|
918
|
+
_step(): void;
|
|
919
|
+
visualize(): GraphicsObject;
|
|
920
|
+
}
|
|
921
|
+
|
|
863
922
|
/**
|
|
864
923
|
* Pipeline solver that runs a series of solvers to find the best schematic layout.
|
|
865
924
|
* Coordinates the entire layout process from chip partitioning through final packing.
|
|
@@ -890,12 +949,13 @@ declare class SchematicTracePipelineSolver extends BaseSolver {
|
|
|
890
949
|
vccNetLabelCornerPlacementSolver?: VccNetLabelCornerPlacementSolver;
|
|
891
950
|
traceAnchoredNetLabelOverlapSolver?: TraceAnchoredNetLabelOverlapSolver;
|
|
892
951
|
netLabelTraceCollisionSolver?: NetLabelTraceCollisionSolver;
|
|
952
|
+
netLabelNetLabelCollisionSolver?: NetLabelNetLabelCollisionSolver;
|
|
893
953
|
startTimeOfPhase: Record<string, number>;
|
|
894
954
|
endTimeOfPhase: Record<string, number>;
|
|
895
955
|
timeSpentOnPhase: Record<string, number>;
|
|
896
956
|
firstIterationOfPhase: Record<string, number>;
|
|
897
957
|
inputProblem: InputProblem;
|
|
898
|
-
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>)[];
|
|
958
|
+
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> | PipelineStep<typeof NetLabelNetLabelCollisionSolver>)[];
|
|
899
959
|
constructor(inputProblem: InputProblem);
|
|
900
960
|
getConstructorParams(): ConstructorParameters<typeof SchematicTracePipelineSolver>[0];
|
|
901
961
|
currentPipelineStepIndex: number;
|
package/dist/index.js
CHANGED
|
@@ -7605,6 +7605,338 @@ globalConnNetId: ${label.globalConnNetId}`
|
|
|
7605
7605
|
}
|
|
7606
7606
|
};
|
|
7607
7607
|
|
|
7608
|
+
// lib/solvers/NetLabelNetLabelCollisionSolver/NetLabelNetLabelCollisionSolver.ts
|
|
7609
|
+
var ANCHOR_TRACE_CLEARANCE = 1e-4;
|
|
7610
|
+
var SEGMENT_PARALLEL_EPS = 1e-6;
|
|
7611
|
+
var CANDIDATE_STEP2 = 0.1;
|
|
7612
|
+
var OUTWARD_DIR = {
|
|
7613
|
+
"x+": { x: 1, y: 0 },
|
|
7614
|
+
"x-": { x: -1, y: 0 },
|
|
7615
|
+
"y+": { x: 0, y: 1 },
|
|
7616
|
+
"y-": { x: 0, y: -1 }
|
|
7617
|
+
};
|
|
7618
|
+
var CANDIDATE_STATUS_COLOR = {
|
|
7619
|
+
ok: "green",
|
|
7620
|
+
"label-collision": "orange",
|
|
7621
|
+
"trace-collision": "darkorange",
|
|
7622
|
+
"chip-collision": "red"
|
|
7623
|
+
};
|
|
7624
|
+
var CANDIDATE_STATUS_FILL = {
|
|
7625
|
+
ok: "rgba(0, 200, 0, 0.25)",
|
|
7626
|
+
"label-collision": "rgba(255, 160, 0, 0.2)",
|
|
7627
|
+
"trace-collision": "rgba(200, 80, 0, 0.2)",
|
|
7628
|
+
"chip-collision": "rgba(220, 0, 0, 0.15)"
|
|
7629
|
+
};
|
|
7630
|
+
function boundsOverlap(a, b) {
|
|
7631
|
+
return a.minX < b.maxX - 1e-9 && a.maxX > b.minX + 1e-9 && a.minY < b.maxY - 1e-9 && a.maxY > b.minY + 1e-9;
|
|
7632
|
+
}
|
|
7633
|
+
function sampleAnchorsAlongSegment(a, b) {
|
|
7634
|
+
const dx = b.x - a.x;
|
|
7635
|
+
const dy = b.y - a.y;
|
|
7636
|
+
const len = Math.sqrt(dx * dx + dy * dy);
|
|
7637
|
+
const steps = Math.max(1, Math.round(len / CANDIDATE_STEP2));
|
|
7638
|
+
const anchors = [];
|
|
7639
|
+
for (let k = 0; k <= steps; k++) {
|
|
7640
|
+
const t = k / steps;
|
|
7641
|
+
anchors.push({ x: a.x + t * dx, y: a.y + t * dy });
|
|
7642
|
+
}
|
|
7643
|
+
return anchors;
|
|
7644
|
+
}
|
|
7645
|
+
var NetLabelNetLabelCollisionSolver = class extends BaseSolver {
|
|
7646
|
+
inputProblem;
|
|
7647
|
+
traces;
|
|
7648
|
+
netLabelPlacements;
|
|
7649
|
+
outputNetLabelPlacements;
|
|
7650
|
+
currentCollision = null;
|
|
7651
|
+
currentLabelToMove = null;
|
|
7652
|
+
candidateResults = [];
|
|
7653
|
+
chipIndex;
|
|
7654
|
+
traceMap;
|
|
7655
|
+
skippedCollisionKeys = /* @__PURE__ */ new Set();
|
|
7656
|
+
labelsToTry = [];
|
|
7657
|
+
candidateQueue = [];
|
|
7658
|
+
candidateIndex = 0;
|
|
7659
|
+
constructor(params) {
|
|
7660
|
+
super();
|
|
7661
|
+
this.inputProblem = params.inputProblem;
|
|
7662
|
+
this.traces = params.traces;
|
|
7663
|
+
this.netLabelPlacements = params.netLabelPlacements;
|
|
7664
|
+
this.outputNetLabelPlacements = [...params.netLabelPlacements];
|
|
7665
|
+
this.chipIndex = params.inputProblem._chipObstacleSpatialIndex ?? new ChipObstacleSpatialIndex(params.inputProblem.chips);
|
|
7666
|
+
this.traceMap = Object.fromEntries(
|
|
7667
|
+
params.traces.map((t) => [t.mspPairId, t])
|
|
7668
|
+
);
|
|
7669
|
+
}
|
|
7670
|
+
getConstructorParams() {
|
|
7671
|
+
return {
|
|
7672
|
+
inputProblem: this.inputProblem,
|
|
7673
|
+
traces: this.traces,
|
|
7674
|
+
netLabelPlacements: this.netLabelPlacements
|
|
7675
|
+
};
|
|
7676
|
+
}
|
|
7677
|
+
getOutput() {
|
|
7678
|
+
return { netLabelPlacements: this.outputNetLabelPlacements };
|
|
7679
|
+
}
|
|
7680
|
+
labelBounds(label) {
|
|
7681
|
+
return getRectBounds(label.center, label.width, label.height);
|
|
7682
|
+
}
|
|
7683
|
+
collisionKey(a, b) {
|
|
7684
|
+
return [a.globalConnNetId, b.globalConnNetId].sort().join("::");
|
|
7685
|
+
}
|
|
7686
|
+
findNextCollidingPair() {
|
|
7687
|
+
const labels = this.outputNetLabelPlacements;
|
|
7688
|
+
for (let i = 0; i < labels.length; i++) {
|
|
7689
|
+
for (let j = i + 1; j < labels.length; j++) {
|
|
7690
|
+
const a = labels[i];
|
|
7691
|
+
const b = labels[j];
|
|
7692
|
+
if (a.globalConnNetId === b.globalConnNetId) continue;
|
|
7693
|
+
if (this.skippedCollisionKeys.has(this.collisionKey(a, b))) continue;
|
|
7694
|
+
if (boundsOverlap(this.labelBounds(a), this.labelBounds(b)))
|
|
7695
|
+
return [a, b];
|
|
7696
|
+
}
|
|
7697
|
+
}
|
|
7698
|
+
return null;
|
|
7699
|
+
}
|
|
7700
|
+
netLabelWidthOf(label) {
|
|
7701
|
+
if (label.orientation === "x+" || label.orientation === "x-")
|
|
7702
|
+
return label.width;
|
|
7703
|
+
return label.height;
|
|
7704
|
+
}
|
|
7705
|
+
buildCandidatesForLabel(label) {
|
|
7706
|
+
const netLabelWidth = this.netLabelWidthOf(label);
|
|
7707
|
+
const candidates = [];
|
|
7708
|
+
const buildCandidate = (orientation, anchor, hostPairId, hostSegIndex) => {
|
|
7709
|
+
const { width, height } = getDimsForOrientation({
|
|
7710
|
+
orientation,
|
|
7711
|
+
netLabelWidth
|
|
7712
|
+
});
|
|
7713
|
+
const baseCenter = getCenterFromAnchor(anchor, orientation, width, height);
|
|
7714
|
+
const outwardDir = OUTWARD_DIR[orientation];
|
|
7715
|
+
const center = {
|
|
7716
|
+
x: baseCenter.x + outwardDir.x * ANCHOR_TRACE_CLEARANCE,
|
|
7717
|
+
y: baseCenter.y + outwardDir.y * ANCHOR_TRACE_CLEARANCE
|
|
7718
|
+
};
|
|
7719
|
+
return {
|
|
7720
|
+
orientation,
|
|
7721
|
+
anchor,
|
|
7722
|
+
center,
|
|
7723
|
+
width,
|
|
7724
|
+
height,
|
|
7725
|
+
bounds: getRectBounds(center, width, height),
|
|
7726
|
+
hostPairId,
|
|
7727
|
+
hostSegIndex,
|
|
7728
|
+
status: null
|
|
7729
|
+
};
|
|
7730
|
+
};
|
|
7731
|
+
const isPortOnly = label.mspConnectionPairIds.length === 0;
|
|
7732
|
+
if (isPortOnly) {
|
|
7733
|
+
const allOrientations = ["x+", "x-", "y+", "y-"];
|
|
7734
|
+
const orderedOrientations = [
|
|
7735
|
+
label.orientation,
|
|
7736
|
+
...allOrientations.filter((o) => o !== label.orientation)
|
|
7737
|
+
];
|
|
7738
|
+
for (const orientation of orderedOrientations) {
|
|
7739
|
+
candidates.push(buildCandidate(orientation, label.anchorPoint));
|
|
7740
|
+
}
|
|
7741
|
+
} else {
|
|
7742
|
+
for (const mspPairId of label.mspConnectionPairIds) {
|
|
7743
|
+
const trace = this.traceMap[mspPairId];
|
|
7744
|
+
if (!trace) continue;
|
|
7745
|
+
const pts = trace.tracePath;
|
|
7746
|
+
for (let si = 0; si < pts.length - 1; si++) {
|
|
7747
|
+
const segStart = pts[si];
|
|
7748
|
+
const segEnd = pts[si + 1];
|
|
7749
|
+
const isHorizontal3 = Math.abs(segStart.y - segEnd.y) < SEGMENT_PARALLEL_EPS;
|
|
7750
|
+
const isVertical4 = Math.abs(segStart.x - segEnd.x) < SEGMENT_PARALLEL_EPS;
|
|
7751
|
+
if (!isHorizontal3 && !isVertical4) continue;
|
|
7752
|
+
let perpendicularOrientations;
|
|
7753
|
+
if (isHorizontal3) {
|
|
7754
|
+
perpendicularOrientations = ["y+", "y-"];
|
|
7755
|
+
} else {
|
|
7756
|
+
perpendicularOrientations = ["x+", "x-"];
|
|
7757
|
+
}
|
|
7758
|
+
for (const anchor of sampleAnchorsAlongSegment(segStart, segEnd)) {
|
|
7759
|
+
for (const orientation of perpendicularOrientations) {
|
|
7760
|
+
candidates.push(
|
|
7761
|
+
buildCandidate(
|
|
7762
|
+
orientation,
|
|
7763
|
+
anchor,
|
|
7764
|
+
mspPairId,
|
|
7765
|
+
si
|
|
7766
|
+
)
|
|
7767
|
+
);
|
|
7768
|
+
}
|
|
7769
|
+
}
|
|
7770
|
+
}
|
|
7771
|
+
}
|
|
7772
|
+
}
|
|
7773
|
+
return candidates;
|
|
7774
|
+
}
|
|
7775
|
+
checkCandidate(candidate, movingLabelNetId, obstacleLabels) {
|
|
7776
|
+
const { bounds, hostPairId, hostSegIndex } = candidate;
|
|
7777
|
+
if (this.chipIndex.getChipsInBounds(bounds).length > 0)
|
|
7778
|
+
return "chip-collision";
|
|
7779
|
+
if (rectIntersectsAnyTrace(bounds, this.traceMap, hostPairId, hostSegIndex).hasIntersection) {
|
|
7780
|
+
return "trace-collision";
|
|
7781
|
+
}
|
|
7782
|
+
for (const obstacle of obstacleLabels) {
|
|
7783
|
+
if (obstacle.globalConnNetId === movingLabelNetId) continue;
|
|
7784
|
+
if (boundsOverlap(bounds, this.labelBounds(obstacle)))
|
|
7785
|
+
return "label-collision";
|
|
7786
|
+
}
|
|
7787
|
+
return "ok";
|
|
7788
|
+
}
|
|
7789
|
+
beginSearchForLabel(label) {
|
|
7790
|
+
this.currentLabelToMove = label;
|
|
7791
|
+
this.candidateQueue = this.buildCandidatesForLabel(label);
|
|
7792
|
+
this.candidateIndex = 0;
|
|
7793
|
+
this.candidateResults = [];
|
|
7794
|
+
}
|
|
7795
|
+
clearActiveSearch() {
|
|
7796
|
+
this.currentCollision = null;
|
|
7797
|
+
this.currentLabelToMove = null;
|
|
7798
|
+
this.labelsToTry = [];
|
|
7799
|
+
this.candidateQueue = [];
|
|
7800
|
+
this.candidateIndex = 0;
|
|
7801
|
+
this.candidateResults = [];
|
|
7802
|
+
}
|
|
7803
|
+
_step() {
|
|
7804
|
+
if (!this.currentCollision) {
|
|
7805
|
+
const pair = this.findNextCollidingPair();
|
|
7806
|
+
if (!pair) {
|
|
7807
|
+
this.solved = true;
|
|
7808
|
+
return;
|
|
7809
|
+
}
|
|
7810
|
+
this.currentCollision = pair;
|
|
7811
|
+
this.labelsToTry = [pair[1], pair[0]];
|
|
7812
|
+
this.beginSearchForLabel(this.labelsToTry.shift());
|
|
7813
|
+
return;
|
|
7814
|
+
}
|
|
7815
|
+
if (this.candidateIndex >= this.candidateQueue.length) {
|
|
7816
|
+
if (this.labelsToTry.length > 0) {
|
|
7817
|
+
this.beginSearchForLabel(this.labelsToTry.shift());
|
|
7818
|
+
} else {
|
|
7819
|
+
this.skippedCollisionKeys.add(
|
|
7820
|
+
this.collisionKey(this.currentCollision[0], this.currentCollision[1])
|
|
7821
|
+
);
|
|
7822
|
+
this.clearActiveSearch();
|
|
7823
|
+
}
|
|
7824
|
+
return;
|
|
7825
|
+
}
|
|
7826
|
+
const candidate = this.candidateQueue[this.candidateIndex++];
|
|
7827
|
+
const [labelA, labelB] = this.currentCollision;
|
|
7828
|
+
let fixedLabel;
|
|
7829
|
+
if (this.currentLabelToMove === labelB) {
|
|
7830
|
+
fixedLabel = labelA;
|
|
7831
|
+
} else {
|
|
7832
|
+
fixedLabel = labelB;
|
|
7833
|
+
}
|
|
7834
|
+
const obstacleLabels = [
|
|
7835
|
+
...this.outputNetLabelPlacements.filter(
|
|
7836
|
+
(l) => l !== labelA && l !== labelB
|
|
7837
|
+
),
|
|
7838
|
+
fixedLabel
|
|
7839
|
+
];
|
|
7840
|
+
const status = this.checkCandidate(
|
|
7841
|
+
candidate,
|
|
7842
|
+
this.currentLabelToMove.globalConnNetId,
|
|
7843
|
+
obstacleLabels
|
|
7844
|
+
);
|
|
7845
|
+
candidate.status = status;
|
|
7846
|
+
this.candidateResults.push({ ...candidate });
|
|
7847
|
+
if (status === "ok") {
|
|
7848
|
+
const idx = this.outputNetLabelPlacements.indexOf(
|
|
7849
|
+
this.currentLabelToMove
|
|
7850
|
+
);
|
|
7851
|
+
if (idx !== -1) {
|
|
7852
|
+
this.outputNetLabelPlacements[idx] = {
|
|
7853
|
+
...this.currentLabelToMove,
|
|
7854
|
+
orientation: candidate.orientation,
|
|
7855
|
+
anchorPoint: candidate.anchor,
|
|
7856
|
+
width: candidate.width,
|
|
7857
|
+
height: candidate.height,
|
|
7858
|
+
center: candidate.center
|
|
7859
|
+
};
|
|
7860
|
+
}
|
|
7861
|
+
this.clearActiveSearch();
|
|
7862
|
+
}
|
|
7863
|
+
}
|
|
7864
|
+
visualize() {
|
|
7865
|
+
const graphics = visualizeInputProblem(this.inputProblem);
|
|
7866
|
+
if (!graphics.lines) graphics.lines = [];
|
|
7867
|
+
if (!graphics.rects) graphics.rects = [];
|
|
7868
|
+
if (!graphics.points) graphics.points = [];
|
|
7869
|
+
for (const trace of this.traces) {
|
|
7870
|
+
graphics.lines.push({
|
|
7871
|
+
points: trace.tracePath,
|
|
7872
|
+
strokeColor: "purple"
|
|
7873
|
+
});
|
|
7874
|
+
}
|
|
7875
|
+
for (const label of this.outputNetLabelPlacements) {
|
|
7876
|
+
const isInActiveCollision = this.currentCollision != null && (label === this.currentCollision[0] || label === this.currentCollision[1]);
|
|
7877
|
+
let labelFill;
|
|
7878
|
+
let labelStroke;
|
|
7879
|
+
let labelText;
|
|
7880
|
+
let pointColor;
|
|
7881
|
+
if (isInActiveCollision) {
|
|
7882
|
+
labelFill = "rgba(255, 0, 0, 0.2)";
|
|
7883
|
+
labelStroke = "red";
|
|
7884
|
+
labelText = `netId: ${label.netId}
|
|
7885
|
+
globalConnNetId: ${label.globalConnNetId}
|
|
7886
|
+
\u26A0 COLLIDING`;
|
|
7887
|
+
pointColor = "red";
|
|
7888
|
+
} else {
|
|
7889
|
+
labelFill = getColorFromString(label.globalConnNetId, 0.35);
|
|
7890
|
+
labelStroke = getColorFromString(label.globalConnNetId, 0.9);
|
|
7891
|
+
labelText = `netId: ${label.netId}
|
|
7892
|
+
globalConnNetId: ${label.globalConnNetId}`;
|
|
7893
|
+
pointColor = getColorFromString(label.globalConnNetId, 0.9);
|
|
7894
|
+
}
|
|
7895
|
+
graphics.rects.push({
|
|
7896
|
+
center: label.center,
|
|
7897
|
+
width: label.width,
|
|
7898
|
+
height: label.height,
|
|
7899
|
+
fill: labelFill,
|
|
7900
|
+
strokeColor: labelStroke,
|
|
7901
|
+
label: labelText
|
|
7902
|
+
});
|
|
7903
|
+
graphics.points.push({
|
|
7904
|
+
x: label.anchorPoint.x,
|
|
7905
|
+
y: label.anchorPoint.y,
|
|
7906
|
+
color: pointColor,
|
|
7907
|
+
label: `anchorPoint
|
|
7908
|
+
orientation: ${label.orientation}`
|
|
7909
|
+
});
|
|
7910
|
+
}
|
|
7911
|
+
const movingNetId = this.currentLabelToMove ? this.currentLabelToMove.netId : "?";
|
|
7912
|
+
for (const c of this.candidateResults) {
|
|
7913
|
+
const statusColor = CANDIDATE_STATUS_COLOR[c.status];
|
|
7914
|
+
const statusFill = CANDIDATE_STATUS_FILL[c.status];
|
|
7915
|
+
let strokeDash;
|
|
7916
|
+
if (c.status !== "ok") strokeDash = "4 2";
|
|
7917
|
+
graphics.rects.push({
|
|
7918
|
+
center: c.center,
|
|
7919
|
+
width: c.width,
|
|
7920
|
+
height: c.height,
|
|
7921
|
+
fill: statusFill,
|
|
7922
|
+
strokeColor: statusColor,
|
|
7923
|
+
strokeDash,
|
|
7924
|
+
label: `candidate: ${c.status}
|
|
7925
|
+
orientation: ${c.orientation}
|
|
7926
|
+
moving: ${movingNetId}`
|
|
7927
|
+
});
|
|
7928
|
+
graphics.points.push({
|
|
7929
|
+
x: c.anchor.x,
|
|
7930
|
+
y: c.anchor.y,
|
|
7931
|
+
color: statusColor,
|
|
7932
|
+
label: `candidate anchor
|
|
7933
|
+
${c.status}`
|
|
7934
|
+
});
|
|
7935
|
+
}
|
|
7936
|
+
return graphics;
|
|
7937
|
+
}
|
|
7938
|
+
};
|
|
7939
|
+
|
|
7608
7940
|
// lib/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver.ts
|
|
7609
7941
|
function definePipelineStep(solverName, solverClass, getConstructorParams, opts = {}) {
|
|
7610
7942
|
return {
|
|
@@ -7630,6 +7962,7 @@ var SchematicTracePipelineSolver = class extends BaseSolver {
|
|
|
7630
7962
|
vccNetLabelCornerPlacementSolver;
|
|
7631
7963
|
traceAnchoredNetLabelOverlapSolver;
|
|
7632
7964
|
netLabelTraceCollisionSolver;
|
|
7965
|
+
netLabelNetLabelCollisionSolver;
|
|
7633
7966
|
startTimeOfPhase;
|
|
7634
7967
|
endTimeOfPhase;
|
|
7635
7968
|
timeSpentOnPhase;
|
|
@@ -7821,6 +8154,17 @@ var SchematicTracePipelineSolver = class extends BaseSolver {
|
|
|
7821
8154
|
netLabelPlacements: instance.traceAnchoredNetLabelOverlapSolver.outputNetLabelPlacements
|
|
7822
8155
|
}
|
|
7823
8156
|
]
|
|
8157
|
+
),
|
|
8158
|
+
definePipelineStep(
|
|
8159
|
+
"netLabelNetLabelCollisionSolver",
|
|
8160
|
+
NetLabelNetLabelCollisionSolver,
|
|
8161
|
+
(instance) => [
|
|
8162
|
+
{
|
|
8163
|
+
inputProblem: instance.inputProblem,
|
|
8164
|
+
traces: instance.netLabelTraceCollisionSolver.getOutput().traces,
|
|
8165
|
+
netLabelPlacements: instance.netLabelTraceCollisionSolver.getOutput().netLabelPlacements
|
|
8166
|
+
}
|
|
8167
|
+
]
|
|
7824
8168
|
)
|
|
7825
8169
|
];
|
|
7826
8170
|
constructor(inputProblem) {
|