@tscircuit/schematic-trace-solver 0.0.8 → 0.0.10
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/README.md +2 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +63 -6
- package/lib/solvers/NetLabelPlacementSolver/NetLabelPlacementSolver.ts +29 -0
- package/lib/solvers/SchematicTraceLinesSolver/SchematicTraceLinesSolver.ts +24 -3
- package/lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver/SchematicTraceSingleLineSolver.ts +38 -3
- package/package.json +1 -1
- package/site/SchematicTraceLinesSolver/SchematicTraceLinesSolver01.page.tsx +122 -0
- package/site/components/GenericSolverDebugger.tsx +16 -0
- package/site/examples/example04-single-symbol.page.tsx +46 -0
- package/tests/solvers/SchematicTraceSingleLineSolver/SchematicTraceSingleLineSolver_repro01.json +88 -0
- package/tests/solvers/SchematicTraceSingleLineSolver/SchematicTraceSingleLineSolver_repro01.test.ts +16 -0
package/README.md
CHANGED
|
@@ -4,6 +4,8 @@ Solve for the correct positions and routing for schematic traces and net labels.
|
|
|
4
4
|
|
|
5
5
|
[Online Playground](https://schematic-trace-solver.vercel.app) ・ [tscircuit](https://github.com/tscircuit/tscircuit) ・ [@tscircuit/core](https://github.com/tscircuit/core)
|
|
6
6
|
|
|
7
|
+
<img width="1740" height="896" alt="image" src="https://github.com/user-attachments/assets/53032b97-d7b5-4a00-9eab-58b58e3adecc" />
|
|
8
|
+
|
|
7
9
|
## Overview
|
|
8
10
|
|
|
9
11
|
The Schematic Trace Solver is a pipeline that figures out how to route schematic traces
|
package/dist/index.d.ts
CHANGED
|
@@ -191,6 +191,9 @@ declare class SchematicTraceLinesSolver extends BaseSolver {
|
|
|
191
191
|
chipMap: Record<string, InputChip>;
|
|
192
192
|
currentConnectionPair: MspConnectionPair | null;
|
|
193
193
|
solvedTracePaths: Array<SolvedTracePath>;
|
|
194
|
+
failedConnectionPairs: Array<MspConnectionPair & {
|
|
195
|
+
error?: string;
|
|
196
|
+
}>;
|
|
194
197
|
activeSubSolver: SchematicTraceSingleLineSolver | null;
|
|
195
198
|
constructor(params: {
|
|
196
199
|
mspConnectionPairs: MspConnectionPair[];
|
|
@@ -370,6 +373,8 @@ declare class NetLabelPlacementSolver extends BaseSolver {
|
|
|
370
373
|
queuedOverlappingSameNetTraceGroups: Array<OverlappingSameNetTraceGroup>;
|
|
371
374
|
activeSubSolver: SingleNetLabelPlacementSolver | null;
|
|
372
375
|
netLabelPlacements: Array<NetLabelPlacement>;
|
|
376
|
+
currentGroup: OverlappingSameNetTraceGroup | null;
|
|
377
|
+
triedAnyOrientationFallbackForCurrentGroup: boolean;
|
|
373
378
|
constructor(params: {
|
|
374
379
|
inputProblem: InputProblem;
|
|
375
380
|
inputTraceMap: Record<MspConnectionPairId, SolvedTracePath>;
|
package/dist/index.js
CHANGED
|
@@ -6694,12 +6694,33 @@ var SchematicTraceSingleLineSolver = class extends BaseSolver {
|
|
|
6694
6694
|
return;
|
|
6695
6695
|
}
|
|
6696
6696
|
const nextCandidatePath = this.queuedCandidatePaths.shift();
|
|
6697
|
-
const obstacleOps = {
|
|
6698
|
-
excludeChipIds: [this.pins[0].chipId, this.pins[1].chipId]
|
|
6699
|
-
};
|
|
6700
6697
|
for (let i = 0; i < nextCandidatePath.length - 1; i++) {
|
|
6701
6698
|
const start = nextCandidatePath[i];
|
|
6702
6699
|
const end = nextCandidatePath[i + 1];
|
|
6700
|
+
let excludeChipIds = [];
|
|
6701
|
+
const isStartPin = this.pins.some(
|
|
6702
|
+
(pin) => Math.abs(pin.x - start.x) < 1e-10 && Math.abs(pin.y - start.y) < 1e-10
|
|
6703
|
+
);
|
|
6704
|
+
const isEndPin = this.pins.some(
|
|
6705
|
+
(pin) => Math.abs(pin.x - end.x) < 1e-10 && Math.abs(pin.y - end.y) < 1e-10
|
|
6706
|
+
);
|
|
6707
|
+
if (isStartPin) {
|
|
6708
|
+
const startPin = this.pins.find(
|
|
6709
|
+
(pin) => Math.abs(pin.x - start.x) < 1e-10 && Math.abs(pin.y - start.y) < 1e-10
|
|
6710
|
+
);
|
|
6711
|
+
if (startPin && !excludeChipIds.includes(startPin.chipId)) {
|
|
6712
|
+
excludeChipIds.push(startPin.chipId);
|
|
6713
|
+
}
|
|
6714
|
+
}
|
|
6715
|
+
if (isEndPin) {
|
|
6716
|
+
const endPin = this.pins.find(
|
|
6717
|
+
(pin) => Math.abs(pin.x - end.x) < 1e-10 && Math.abs(pin.y - end.y) < 1e-10
|
|
6718
|
+
);
|
|
6719
|
+
if (endPin && !excludeChipIds.includes(endPin.chipId)) {
|
|
6720
|
+
excludeChipIds.push(endPin.chipId);
|
|
6721
|
+
}
|
|
6722
|
+
}
|
|
6723
|
+
const obstacleOps = { excludeChipIds };
|
|
6703
6724
|
const intersects = this.chipObstacleSpatialIndex.doesOrthogonalLineIntersectChip(
|
|
6704
6725
|
[start, end],
|
|
6705
6726
|
obstacleOps
|
|
@@ -6780,6 +6801,7 @@ var SchematicTraceLinesSolver = class extends BaseSolver {
|
|
|
6780
6801
|
chipMap;
|
|
6781
6802
|
currentConnectionPair = null;
|
|
6782
6803
|
solvedTracePaths = [];
|
|
6804
|
+
failedConnectionPairs = [];
|
|
6783
6805
|
constructor(params) {
|
|
6784
6806
|
super();
|
|
6785
6807
|
this.inputProblem = params.inputProblem;
|
|
@@ -6810,9 +6832,14 @@ var SchematicTraceLinesSolver = class extends BaseSolver {
|
|
|
6810
6832
|
this.currentConnectionPair = null;
|
|
6811
6833
|
}
|
|
6812
6834
|
if (this.activeSubSolver?.failed) {
|
|
6813
|
-
this.
|
|
6814
|
-
|
|
6815
|
-
|
|
6835
|
+
if (this.currentConnectionPair) {
|
|
6836
|
+
this.failedConnectionPairs.push({
|
|
6837
|
+
...this.currentConnectionPair,
|
|
6838
|
+
error: this.activeSubSolver.error || void 0
|
|
6839
|
+
});
|
|
6840
|
+
}
|
|
6841
|
+
this.activeSubSolver = null;
|
|
6842
|
+
this.currentConnectionPair = null;
|
|
6816
6843
|
}
|
|
6817
6844
|
if (this.activeSubSolver) {
|
|
6818
6845
|
this.activeSubSolver.step();
|
|
@@ -6848,6 +6875,17 @@ var SchematicTraceLinesSolver = class extends BaseSolver {
|
|
|
6848
6875
|
strokeColor: "green"
|
|
6849
6876
|
});
|
|
6850
6877
|
}
|
|
6878
|
+
for (const pair of this.failedConnectionPairs) {
|
|
6879
|
+
graphics.lines.push({
|
|
6880
|
+
points: [
|
|
6881
|
+
{ x: pair.pins[0].x, y: pair.pins[0].y },
|
|
6882
|
+
{ x: pair.pins[1].x, y: pair.pins[1].y }
|
|
6883
|
+
],
|
|
6884
|
+
strokeColor: "red",
|
|
6885
|
+
strokeDash: "4 2",
|
|
6886
|
+
strokeWidth: 4e-3
|
|
6887
|
+
});
|
|
6888
|
+
}
|
|
6851
6889
|
return graphics;
|
|
6852
6890
|
}
|
|
6853
6891
|
};
|
|
@@ -7642,6 +7680,8 @@ var NetLabelPlacementSolver = class extends BaseSolver {
|
|
|
7642
7680
|
overlappingSameNetTraceGroups;
|
|
7643
7681
|
queuedOverlappingSameNetTraceGroups;
|
|
7644
7682
|
netLabelPlacements = [];
|
|
7683
|
+
currentGroup = null;
|
|
7684
|
+
triedAnyOrientationFallbackForCurrentGroup = false;
|
|
7645
7685
|
constructor(params) {
|
|
7646
7686
|
super();
|
|
7647
7687
|
this.inputProblem = params.inputProblem;
|
|
@@ -7759,9 +7799,24 @@ var NetLabelPlacementSolver = class extends BaseSolver {
|
|
|
7759
7799
|
if (this.activeSubSolver?.solved) {
|
|
7760
7800
|
this.netLabelPlacements.push(this.activeSubSolver.netLabelPlacement);
|
|
7761
7801
|
this.activeSubSolver = null;
|
|
7802
|
+
this.currentGroup = null;
|
|
7803
|
+
this.triedAnyOrientationFallbackForCurrentGroup = false;
|
|
7762
7804
|
return;
|
|
7763
7805
|
}
|
|
7764
7806
|
if (this.activeSubSolver?.failed) {
|
|
7807
|
+
const fullOrients = ["x+", "x-", "y+", "y-"];
|
|
7808
|
+
const currOrients = this.activeSubSolver.availableOrientations;
|
|
7809
|
+
const isAlreadyFull = currOrients.length === 4 && fullOrients.every((o) => currOrients.includes(o));
|
|
7810
|
+
if (!this.triedAnyOrientationFallbackForCurrentGroup && !isAlreadyFull && this.currentGroup) {
|
|
7811
|
+
this.triedAnyOrientationFallbackForCurrentGroup = true;
|
|
7812
|
+
this.activeSubSolver = new SingleNetLabelPlacementSolver({
|
|
7813
|
+
inputProblem: this.inputProblem,
|
|
7814
|
+
inputTraceMap: this.inputTraceMap,
|
|
7815
|
+
overlappingSameNetTraceGroup: this.currentGroup,
|
|
7816
|
+
availableOrientations: fullOrients
|
|
7817
|
+
});
|
|
7818
|
+
return;
|
|
7819
|
+
}
|
|
7765
7820
|
this.failed = true;
|
|
7766
7821
|
this.error = this.activeSubSolver.error;
|
|
7767
7822
|
return;
|
|
@@ -7776,6 +7831,8 @@ var NetLabelPlacementSolver = class extends BaseSolver {
|
|
|
7776
7831
|
return;
|
|
7777
7832
|
}
|
|
7778
7833
|
const netId = nextOverlappingSameNetTraceGroup.netId ?? nextOverlappingSameNetTraceGroup.globalConnNetId;
|
|
7834
|
+
this.currentGroup = nextOverlappingSameNetTraceGroup;
|
|
7835
|
+
this.triedAnyOrientationFallbackForCurrentGroup = false;
|
|
7779
7836
|
this.activeSubSolver = new SingleNetLabelPlacementSolver({
|
|
7780
7837
|
inputProblem: this.inputProblem,
|
|
7781
7838
|
inputTraceMap: this.inputTraceMap,
|
|
@@ -60,6 +60,8 @@ export class NetLabelPlacementSolver extends BaseSolver {
|
|
|
60
60
|
declare activeSubSolver: SingleNetLabelPlacementSolver | null
|
|
61
61
|
|
|
62
62
|
netLabelPlacements: Array<NetLabelPlacement> = []
|
|
63
|
+
currentGroup: OverlappingSameNetTraceGroup | null = null
|
|
64
|
+
triedAnyOrientationFallbackForCurrentGroup = false
|
|
63
65
|
|
|
64
66
|
constructor(params: {
|
|
65
67
|
inputProblem: InputProblem
|
|
@@ -209,10 +211,34 @@ export class NetLabelPlacementSolver extends BaseSolver {
|
|
|
209
211
|
if (this.activeSubSolver?.solved) {
|
|
210
212
|
this.netLabelPlacements.push(this.activeSubSolver.netLabelPlacement!)
|
|
211
213
|
this.activeSubSolver = null
|
|
214
|
+
this.currentGroup = null
|
|
215
|
+
this.triedAnyOrientationFallbackForCurrentGroup = false
|
|
212
216
|
return
|
|
213
217
|
}
|
|
214
218
|
|
|
215
219
|
if (this.activeSubSolver?.failed) {
|
|
220
|
+
// Retry once with all orientations as a fallback before failing
|
|
221
|
+
const fullOrients: FacingDirection[] = ["x+", "x-", "y+", "y-"]
|
|
222
|
+
const currOrients = this.activeSubSolver.availableOrientations
|
|
223
|
+
const isAlreadyFull =
|
|
224
|
+
currOrients.length === 4 &&
|
|
225
|
+
fullOrients.every((o) => currOrients.includes(o))
|
|
226
|
+
|
|
227
|
+
if (
|
|
228
|
+
!this.triedAnyOrientationFallbackForCurrentGroup &&
|
|
229
|
+
!isAlreadyFull &&
|
|
230
|
+
this.currentGroup
|
|
231
|
+
) {
|
|
232
|
+
this.triedAnyOrientationFallbackForCurrentGroup = true
|
|
233
|
+
this.activeSubSolver = new SingleNetLabelPlacementSolver({
|
|
234
|
+
inputProblem: this.inputProblem,
|
|
235
|
+
inputTraceMap: this.inputTraceMap,
|
|
236
|
+
overlappingSameNetTraceGroup: this.currentGroup,
|
|
237
|
+
availableOrientations: fullOrients,
|
|
238
|
+
})
|
|
239
|
+
return
|
|
240
|
+
}
|
|
241
|
+
|
|
216
242
|
this.failed = true
|
|
217
243
|
this.error = this.activeSubSolver.error
|
|
218
244
|
return
|
|
@@ -235,6 +261,9 @@ export class NetLabelPlacementSolver extends BaseSolver {
|
|
|
235
261
|
nextOverlappingSameNetTraceGroup.netId ??
|
|
236
262
|
nextOverlappingSameNetTraceGroup.globalConnNetId
|
|
237
263
|
|
|
264
|
+
this.currentGroup = nextOverlappingSameNetTraceGroup
|
|
265
|
+
this.triedAnyOrientationFallbackForCurrentGroup = false
|
|
266
|
+
|
|
238
267
|
this.activeSubSolver = new SingleNetLabelPlacementSolver({
|
|
239
268
|
inputProblem: this.inputProblem,
|
|
240
269
|
inputTraceMap: this.inputTraceMap,
|
|
@@ -30,6 +30,7 @@ export class SchematicTraceLinesSolver extends BaseSolver {
|
|
|
30
30
|
currentConnectionPair: MspConnectionPair | null = null
|
|
31
31
|
|
|
32
32
|
solvedTracePaths: Array<SolvedTracePath> = []
|
|
33
|
+
failedConnectionPairs: Array<MspConnectionPair & { error?: string }> = []
|
|
33
34
|
|
|
34
35
|
declare activeSubSolver: SchematicTraceSingleLineSolver | null
|
|
35
36
|
|
|
@@ -75,9 +76,16 @@ export class SchematicTraceLinesSolver extends BaseSolver {
|
|
|
75
76
|
this.currentConnectionPair = null
|
|
76
77
|
}
|
|
77
78
|
if (this.activeSubSolver?.failed) {
|
|
78
|
-
this
|
|
79
|
-
this.
|
|
80
|
-
|
|
79
|
+
// Record the failure for this connection and continue to the next pair
|
|
80
|
+
if (this.currentConnectionPair) {
|
|
81
|
+
this.failedConnectionPairs.push({
|
|
82
|
+
...this.currentConnectionPair,
|
|
83
|
+
error: this.activeSubSolver.error || undefined,
|
|
84
|
+
})
|
|
85
|
+
}
|
|
86
|
+
this.activeSubSolver = null
|
|
87
|
+
this.currentConnectionPair = null
|
|
88
|
+
// Do not fail the whole solver; proceed to schedule the next pair
|
|
81
89
|
}
|
|
82
90
|
|
|
83
91
|
if (this.activeSubSolver) {
|
|
@@ -122,6 +130,19 @@ export class SchematicTraceLinesSolver extends BaseSolver {
|
|
|
122
130
|
})
|
|
123
131
|
}
|
|
124
132
|
|
|
133
|
+
// Indicate failed connection pairs with dashed red lines between their pins
|
|
134
|
+
for (const pair of this.failedConnectionPairs) {
|
|
135
|
+
graphics.lines!.push({
|
|
136
|
+
points: [
|
|
137
|
+
{ x: pair.pins[0].x, y: pair.pins[0].y },
|
|
138
|
+
{ x: pair.pins[1].x, y: pair.pins[1].y },
|
|
139
|
+
],
|
|
140
|
+
strokeColor: "red",
|
|
141
|
+
strokeDash: "4 2",
|
|
142
|
+
strokeWidth: 0.004,
|
|
143
|
+
})
|
|
144
|
+
}
|
|
145
|
+
|
|
125
146
|
return graphics
|
|
126
147
|
}
|
|
127
148
|
}
|
|
@@ -103,12 +103,47 @@ export class SchematicTraceSingleLineSolver extends BaseSolver {
|
|
|
103
103
|
|
|
104
104
|
const nextCandidatePath = this.queuedCandidatePaths.shift()!
|
|
105
105
|
|
|
106
|
-
const obstacleOps = {
|
|
107
|
-
excludeChipIds: [this.pins[0].chipId, this.pins[1].chipId],
|
|
108
|
-
}
|
|
109
106
|
for (let i = 0; i < nextCandidatePath.length - 1; i++) {
|
|
110
107
|
const start = nextCandidatePath[i]
|
|
111
108
|
const end = nextCandidatePath[i + 1]
|
|
109
|
+
|
|
110
|
+
// Determine which chips to exclude for this specific segment
|
|
111
|
+
let excludeChipIds: string[] = []
|
|
112
|
+
|
|
113
|
+
// Always exclude chips that contain the start or end points of this segment
|
|
114
|
+
// if those points are actually pin locations
|
|
115
|
+
const isStartPin = this.pins.some(
|
|
116
|
+
(pin) =>
|
|
117
|
+
Math.abs(pin.x - start.x) < 1e-10 &&
|
|
118
|
+
Math.abs(pin.y - start.y) < 1e-10,
|
|
119
|
+
)
|
|
120
|
+
const isEndPin = this.pins.some(
|
|
121
|
+
(pin) =>
|
|
122
|
+
Math.abs(pin.x - end.x) < 1e-10 && Math.abs(pin.y - end.y) < 1e-10,
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
if (isStartPin) {
|
|
126
|
+
const startPin = this.pins.find(
|
|
127
|
+
(pin) =>
|
|
128
|
+
Math.abs(pin.x - start.x) < 1e-10 &&
|
|
129
|
+
Math.abs(pin.y - start.y) < 1e-10,
|
|
130
|
+
)
|
|
131
|
+
if (startPin && !excludeChipIds.includes(startPin.chipId)) {
|
|
132
|
+
excludeChipIds.push(startPin.chipId)
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (isEndPin) {
|
|
137
|
+
const endPin = this.pins.find(
|
|
138
|
+
(pin) =>
|
|
139
|
+
Math.abs(pin.x - end.x) < 1e-10 && Math.abs(pin.y - end.y) < 1e-10,
|
|
140
|
+
)
|
|
141
|
+
if (endPin && !excludeChipIds.includes(endPin.chipId)) {
|
|
142
|
+
excludeChipIds.push(endPin.chipId)
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const obstacleOps = { excludeChipIds }
|
|
112
147
|
const intersects =
|
|
113
148
|
this.chipObstacleSpatialIndex.doesOrthogonalLineIntersectChip(
|
|
114
149
|
[start, end],
|
package/package.json
CHANGED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { useMemo } from "react"
|
|
2
|
+
import { GenericSolverDebugger } from "../components/GenericSolverDebugger"
|
|
3
|
+
import { SchematicTraceLinesSolver } from "lib/solvers/SchematicTraceLinesSolver/SchematicTraceLinesSolver"
|
|
4
|
+
|
|
5
|
+
const input = {
|
|
6
|
+
mspConnectionPairs: [
|
|
7
|
+
{
|
|
8
|
+
mspPairId: "Q1.1-Q1.2",
|
|
9
|
+
dcConnNetId: "connectivity_net0",
|
|
10
|
+
globalConnNetId: "connectivity_net0",
|
|
11
|
+
userNetId: "V3_3",
|
|
12
|
+
pins: [
|
|
13
|
+
{
|
|
14
|
+
pinId: "Q1.1",
|
|
15
|
+
x: 0.30397715550000004,
|
|
16
|
+
y: 0.5800832909999993,
|
|
17
|
+
_facingDirection: "y+",
|
|
18
|
+
chipId: "schematic_component_0",
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
pinId: "Q1.2",
|
|
22
|
+
x: 0.31067575550000137,
|
|
23
|
+
y: -0.5800832909999993,
|
|
24
|
+
_facingDirection: "y-",
|
|
25
|
+
chipId: "schematic_component_0",
|
|
26
|
+
},
|
|
27
|
+
],
|
|
28
|
+
},
|
|
29
|
+
],
|
|
30
|
+
dcConnMap: {
|
|
31
|
+
netMap: {
|
|
32
|
+
connectivity_net0: ["Q1.1", "Q1.2"],
|
|
33
|
+
},
|
|
34
|
+
idToNetMap: {},
|
|
35
|
+
},
|
|
36
|
+
globalConnMap: {
|
|
37
|
+
netMap: {
|
|
38
|
+
connectivity_net0: ["Q1.1", "Q1.2"],
|
|
39
|
+
},
|
|
40
|
+
idToNetMap: {
|
|
41
|
+
"Q1.1": "connectivity_net0",
|
|
42
|
+
"Q1.2": "connectivity_net0",
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
inputProblem: {
|
|
46
|
+
chips: [
|
|
47
|
+
{
|
|
48
|
+
chipId: "schematic_component_0",
|
|
49
|
+
center: {
|
|
50
|
+
x: 0,
|
|
51
|
+
y: 0,
|
|
52
|
+
},
|
|
53
|
+
width: 0.8935117710000002,
|
|
54
|
+
height: 1.1601665819999987,
|
|
55
|
+
pins: [
|
|
56
|
+
{
|
|
57
|
+
pinId: "Q1.1",
|
|
58
|
+
x: 0.30397715550000004,
|
|
59
|
+
y: 0.5800832909999993,
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
pinId: "Q1.2",
|
|
63
|
+
x: 0.31067575550000137,
|
|
64
|
+
y: -0.5800832909999993,
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
pinId: "Q1.3",
|
|
68
|
+
x: -0.4467558855000001,
|
|
69
|
+
y: -0.10250625000000019,
|
|
70
|
+
},
|
|
71
|
+
],
|
|
72
|
+
},
|
|
73
|
+
],
|
|
74
|
+
directConnections: [],
|
|
75
|
+
netConnections: [
|
|
76
|
+
{
|
|
77
|
+
netId: "V3_3",
|
|
78
|
+
pinIds: ["Q1.1", "Q1.2"],
|
|
79
|
+
},
|
|
80
|
+
],
|
|
81
|
+
availableNetLabelOrientations: {
|
|
82
|
+
V3_3: ["y+"],
|
|
83
|
+
},
|
|
84
|
+
maxMspPairDistance: 2,
|
|
85
|
+
},
|
|
86
|
+
guidelines: [],
|
|
87
|
+
chipMap: {
|
|
88
|
+
schematic_component_0: {
|
|
89
|
+
chipId: "schematic_component_0",
|
|
90
|
+
center: {
|
|
91
|
+
x: 0,
|
|
92
|
+
y: 0,
|
|
93
|
+
},
|
|
94
|
+
width: 0.8935117710000002,
|
|
95
|
+
height: 1.1601665819999987,
|
|
96
|
+
pins: [
|
|
97
|
+
{
|
|
98
|
+
pinId: "Q1.1",
|
|
99
|
+
x: 0.30397715550000004,
|
|
100
|
+
y: 0.5800832909999993,
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
pinId: "Q1.2",
|
|
104
|
+
x: 0.31067575550000137,
|
|
105
|
+
y: -0.5800832909999993,
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
pinId: "Q1.3",
|
|
109
|
+
x: -0.4467558855000001,
|
|
110
|
+
y: -0.10250625000000019,
|
|
111
|
+
},
|
|
112
|
+
],
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export default () => {
|
|
118
|
+
const solver = useMemo(() => {
|
|
119
|
+
return new SchematicTraceLinesSolver(input as any)
|
|
120
|
+
}, [])
|
|
121
|
+
return <GenericSolverDebugger solver={solver} />
|
|
122
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { BaseSolver } from "lib/solvers/BaseSolver/BaseSolver"
|
|
2
|
+
import type { InputProblem } from "lib/types/InputProblem"
|
|
3
|
+
import { useMemo, useReducer } from "react"
|
|
4
|
+
import { InteractiveGraphics } from "graphics-debug/react"
|
|
5
|
+
import { SolverToolbar } from "./SolverToolbar"
|
|
6
|
+
|
|
7
|
+
export const GenericSolverDebugger = ({ solver }: { solver: BaseSolver }) => {
|
|
8
|
+
const [, incRenderCount] = useReducer((x) => x + 1, 0)
|
|
9
|
+
|
|
10
|
+
return (
|
|
11
|
+
<div>
|
|
12
|
+
<SolverToolbar triggerRender={() => incRenderCount()} solver={solver} />
|
|
13
|
+
<InteractiveGraphics graphics={solver.visualize()} />
|
|
14
|
+
</div>
|
|
15
|
+
)
|
|
16
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { PipelineDebugger } from "../components/PipelineDebugger"
|
|
2
|
+
import type { InputProblem } from "lib/types/InputProblem"
|
|
3
|
+
|
|
4
|
+
const inputProblem: InputProblem = {
|
|
5
|
+
chips: [
|
|
6
|
+
{
|
|
7
|
+
chipId: "schematic_component_0",
|
|
8
|
+
center: {
|
|
9
|
+
x: 0,
|
|
10
|
+
y: 0,
|
|
11
|
+
},
|
|
12
|
+
width: 0.8935117710000002,
|
|
13
|
+
height: 1.1601665819999987,
|
|
14
|
+
pins: [
|
|
15
|
+
{
|
|
16
|
+
pinId: "Q1.1",
|
|
17
|
+
x: 0.30397715550000004,
|
|
18
|
+
y: 0.5519248499999994,
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
pinId: "Q1.2",
|
|
22
|
+
x: 0.31067575550000137,
|
|
23
|
+
y: -0.5519248499999994,
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
pinId: "Q1.3",
|
|
27
|
+
x: -0.41859744450000014,
|
|
28
|
+
y: -0.10250625000000019,
|
|
29
|
+
},
|
|
30
|
+
],
|
|
31
|
+
},
|
|
32
|
+
],
|
|
33
|
+
directConnections: [],
|
|
34
|
+
netConnections: [
|
|
35
|
+
{
|
|
36
|
+
netId: "V3_3",
|
|
37
|
+
pinIds: ["Q1.1", "Q1.2"],
|
|
38
|
+
},
|
|
39
|
+
],
|
|
40
|
+
availableNetLabelOrientations: {
|
|
41
|
+
V3_3: ["y+"],
|
|
42
|
+
},
|
|
43
|
+
maxMspPairDistance: 2,
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export default () => <PipelineDebugger inputProblem={inputProblem} />
|
package/tests/solvers/SchematicTraceSingleLineSolver/SchematicTraceSingleLineSolver_repro01.json
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
{
|
|
2
|
+
"chipMap": {
|
|
3
|
+
"schematic_component_0": {
|
|
4
|
+
"chipId": "schematic_component_0",
|
|
5
|
+
"center": {
|
|
6
|
+
"x": 0,
|
|
7
|
+
"y": 0
|
|
8
|
+
},
|
|
9
|
+
"width": 0.8935117710000002,
|
|
10
|
+
"height": 1.1601665819999987,
|
|
11
|
+
"pins": [
|
|
12
|
+
{
|
|
13
|
+
"pinId": "Q1.1",
|
|
14
|
+
"x": 0.30397715550000004,
|
|
15
|
+
"y": 0.5800832909999993
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"pinId": "Q1.2",
|
|
19
|
+
"x": 0.31067575550000137,
|
|
20
|
+
"y": -0.5800832909999993
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"pinId": "Q1.3",
|
|
24
|
+
"x": -0.4467558855000001,
|
|
25
|
+
"y": -0.10250625000000019
|
|
26
|
+
}
|
|
27
|
+
]
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"pins": [
|
|
31
|
+
{
|
|
32
|
+
"pinId": "Q1.1",
|
|
33
|
+
"x": 0.30397715550000004,
|
|
34
|
+
"y": 0.5800832909999993,
|
|
35
|
+
"_facingDirection": "y+",
|
|
36
|
+
"chipId": "schematic_component_0"
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"pinId": "Q1.2",
|
|
40
|
+
"x": 0.31067575550000137,
|
|
41
|
+
"y": -0.5800832909999993,
|
|
42
|
+
"_facingDirection": "y-",
|
|
43
|
+
"chipId": "schematic_component_0"
|
|
44
|
+
}
|
|
45
|
+
],
|
|
46
|
+
"guidelines": [],
|
|
47
|
+
"inputProblem": {
|
|
48
|
+
"chips": [
|
|
49
|
+
{
|
|
50
|
+
"chipId": "schematic_component_0",
|
|
51
|
+
"center": {
|
|
52
|
+
"x": 0,
|
|
53
|
+
"y": 0
|
|
54
|
+
},
|
|
55
|
+
"width": 0.8935117710000002,
|
|
56
|
+
"height": 1.1601665819999987,
|
|
57
|
+
"pins": [
|
|
58
|
+
{
|
|
59
|
+
"pinId": "Q1.1",
|
|
60
|
+
"x": 0.30397715550000004,
|
|
61
|
+
"y": 0.5800832909999993
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"pinId": "Q1.2",
|
|
65
|
+
"x": 0.31067575550000137,
|
|
66
|
+
"y": -0.5800832909999993
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"pinId": "Q1.3",
|
|
70
|
+
"x": -0.4467558855000001,
|
|
71
|
+
"y": -0.10250625000000019
|
|
72
|
+
}
|
|
73
|
+
]
|
|
74
|
+
}
|
|
75
|
+
],
|
|
76
|
+
"directConnections": [],
|
|
77
|
+
"netConnections": [
|
|
78
|
+
{
|
|
79
|
+
"netId": "V3_3",
|
|
80
|
+
"pinIds": ["Q1.1", "Q1.2"]
|
|
81
|
+
}
|
|
82
|
+
],
|
|
83
|
+
"availableNetLabelOrientations": {
|
|
84
|
+
"V3_3": ["y+"]
|
|
85
|
+
},
|
|
86
|
+
"maxMspPairDistance": 2
|
|
87
|
+
}
|
|
88
|
+
}
|
package/tests/solvers/SchematicTraceSingleLineSolver/SchematicTraceSingleLineSolver_repro01.test.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { test, expect } from "bun:test"
|
|
2
|
+
import input from "./SchematicTraceSingleLineSolver_repro01.json"
|
|
3
|
+
import { SchematicTraceSingleLineSolver } from "lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver/SchematicTraceSingleLineSolver"
|
|
4
|
+
|
|
5
|
+
test("SchematicTraceSingleLineSolver_repro01", () => {
|
|
6
|
+
const solver = new SchematicTraceSingleLineSolver(input as any)
|
|
7
|
+
solver.solve()
|
|
8
|
+
|
|
9
|
+
// The solver should fail because it cannot find a path around the chip
|
|
10
|
+
// without guidelines to help navigate around it
|
|
11
|
+
expect(solver.failed).toBe(true)
|
|
12
|
+
expect(solver.error).toBe(
|
|
13
|
+
"No more candidate elbows, everything had collisions",
|
|
14
|
+
)
|
|
15
|
+
expect(solver.solvedTracePath).toBe(null)
|
|
16
|
+
})
|