@tscircuit/schematic-trace-solver 0.0.27 → 0.0.28
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 +4 -0
- package/dist/index.js +106 -4
- package/lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver/SchematicTraceSingleLineSolver.ts +40 -1
- package/lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver/getRestrictedCenterLines.ts +139 -0
- package/package.json +1 -1
- package/site/SchematicTracePipelineSolver/SchematicTracePipelineSolver01.page.tsx +143 -0
- package/tests/examples/__snapshots__/example13.snap.svg +14 -8
- package/tests/examples/__snapshots__/example15.snap.svg +235 -0
- package/tests/examples/example15.test.tsx +187 -0
- package/tests/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver_repro03.test.ts +0 -0
package/dist/index.d.ts
CHANGED
|
@@ -154,6 +154,9 @@ interface MovableSegment {
|
|
|
154
154
|
};
|
|
155
155
|
}
|
|
156
156
|
|
|
157
|
+
type ChipPin = InputPin & {
|
|
158
|
+
chipId: ChipId;
|
|
159
|
+
};
|
|
157
160
|
declare class SchematicTraceSingleLineSolver extends BaseSolver {
|
|
158
161
|
pins: MspConnectionPair["pins"];
|
|
159
162
|
inputProblem: InputProblem;
|
|
@@ -168,6 +171,7 @@ declare class SchematicTraceSingleLineSolver extends BaseSolver {
|
|
|
168
171
|
x: number;
|
|
169
172
|
y: number;
|
|
170
173
|
}[] | null;
|
|
174
|
+
pinIdMap: Map<PinId, ChipPin>;
|
|
171
175
|
constructor(params: {
|
|
172
176
|
pins: MspConnectionPair["pins"];
|
|
173
177
|
guidelines: Guideline[];
|
package/dist/index.js
CHANGED
|
@@ -668,6 +668,86 @@ var visualizeGuidelines = ({
|
|
|
668
668
|
return graphics;
|
|
669
669
|
};
|
|
670
670
|
|
|
671
|
+
// lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver/getRestrictedCenterLines.ts
|
|
672
|
+
var getRestrictedCenterLines = (params) => {
|
|
673
|
+
const { pins, inputProblem, pinIdMap, chipMap } = params;
|
|
674
|
+
const findAllDirectlyConnectedPins = (startPinId) => {
|
|
675
|
+
const visited = /* @__PURE__ */ new Set();
|
|
676
|
+
const queue = [startPinId];
|
|
677
|
+
visited.add(startPinId);
|
|
678
|
+
const directConns = inputProblem.directConnections || [];
|
|
679
|
+
while (queue.length) {
|
|
680
|
+
const cur = queue.shift();
|
|
681
|
+
for (const dc of directConns) {
|
|
682
|
+
if (dc.pinIds.includes(cur)) {
|
|
683
|
+
for (const p of dc.pinIds) {
|
|
684
|
+
if (!visited.has(p)) {
|
|
685
|
+
visited.add(p);
|
|
686
|
+
queue.push(p);
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
return visited;
|
|
693
|
+
};
|
|
694
|
+
const p0 = pins[0].pinId;
|
|
695
|
+
const p1 = pins[1].pinId;
|
|
696
|
+
const relatedPinIds = /* @__PURE__ */ new Set([
|
|
697
|
+
...findAllDirectlyConnectedPins(p0),
|
|
698
|
+
...findAllDirectlyConnectedPins(p1)
|
|
699
|
+
]);
|
|
700
|
+
const restrictedCenterLines = /* @__PURE__ */ new Map();
|
|
701
|
+
const chipFacingMap = /* @__PURE__ */ new Map();
|
|
702
|
+
const chipsOfFacingPins = new Set(pins.map((p) => p.chipId));
|
|
703
|
+
for (const pinId of relatedPinIds) {
|
|
704
|
+
const pin = pinIdMap.get(pinId);
|
|
705
|
+
if (!pin) continue;
|
|
706
|
+
const chip = chipMap[pin.chipId];
|
|
707
|
+
if (!chip) continue;
|
|
708
|
+
const facing = pin._facingDirection ?? getPinDirection(pin, chip);
|
|
709
|
+
let entry = chipFacingMap.get(chip.chipId);
|
|
710
|
+
if (!entry) {
|
|
711
|
+
entry = { center: chip.center };
|
|
712
|
+
const counts = { xPos: 0, xNeg: 0, yPos: 0, yNeg: 0 };
|
|
713
|
+
for (const cp of chip.pins) {
|
|
714
|
+
const cpFacing = cp._facingDirection ?? getPinDirection(cp, chip);
|
|
715
|
+
if (cpFacing === "x+") counts.xPos++;
|
|
716
|
+
if (cpFacing === "x-") counts.xNeg++;
|
|
717
|
+
if (cpFacing === "y+") counts.yPos++;
|
|
718
|
+
if (cpFacing === "y-") counts.yNeg++;
|
|
719
|
+
}
|
|
720
|
+
entry.counts = counts;
|
|
721
|
+
chipFacingMap.set(chip.chipId, entry);
|
|
722
|
+
}
|
|
723
|
+
if (facing === "x+") entry.hasXPos = true;
|
|
724
|
+
if (facing === "x-") entry.hasXNeg = true;
|
|
725
|
+
if (facing === "y+") entry.hasYPos = true;
|
|
726
|
+
if (facing === "y-") entry.hasYNeg = true;
|
|
727
|
+
}
|
|
728
|
+
for (const [chipId, faces] of chipFacingMap) {
|
|
729
|
+
const axes = /* @__PURE__ */ new Set();
|
|
730
|
+
const rcl = { axes };
|
|
731
|
+
const counts = faces.counts;
|
|
732
|
+
const anySideHasMultiplePins = !!(counts && (counts.xPos > 1 || counts.xNeg > 1 || counts.yPos > 1 || counts.yNeg > 1));
|
|
733
|
+
const skipCenterRestriction = !anySideHasMultiplePins && chipsOfFacingPins.has(chipId);
|
|
734
|
+
if (!skipCenterRestriction) {
|
|
735
|
+
if (faces.hasXPos && faces.hasXNeg) {
|
|
736
|
+
rcl.x = faces.center.x;
|
|
737
|
+
axes.add("x");
|
|
738
|
+
}
|
|
739
|
+
if (faces.hasYPos && faces.hasYNeg) {
|
|
740
|
+
rcl.y = faces.center.y;
|
|
741
|
+
axes.add("y");
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
if (axes.size > 0) {
|
|
745
|
+
restrictedCenterLines.set(chipId, rcl);
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
return restrictedCenterLines;
|
|
749
|
+
};
|
|
750
|
+
|
|
671
751
|
// lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver/SchematicTraceSingleLineSolver.ts
|
|
672
752
|
var SchematicTraceSingleLineSolver = class extends BaseSolver {
|
|
673
753
|
pins;
|
|
@@ -680,6 +760,8 @@ var SchematicTraceSingleLineSolver = class extends BaseSolver {
|
|
|
680
760
|
queuedCandidatePaths;
|
|
681
761
|
chipObstacleSpatialIndex;
|
|
682
762
|
solvedTracePath = null;
|
|
763
|
+
// map of pinId -> pin (with chipId attached)
|
|
764
|
+
pinIdMap = /* @__PURE__ */ new Map();
|
|
683
765
|
constructor(params) {
|
|
684
766
|
super();
|
|
685
767
|
this.pins = params.pins;
|
|
@@ -690,6 +772,11 @@ var SchematicTraceSingleLineSolver = class extends BaseSolver {
|
|
|
690
772
|
if (!this.inputProblem._chipObstacleSpatialIndex) {
|
|
691
773
|
this.inputProblem._chipObstacleSpatialIndex = this.chipObstacleSpatialIndex;
|
|
692
774
|
}
|
|
775
|
+
for (const chip of this.inputProblem.chips) {
|
|
776
|
+
for (const pin of chip.pins) {
|
|
777
|
+
this.pinIdMap.set(pin.pinId, { ...pin, chipId: chip.chipId });
|
|
778
|
+
}
|
|
779
|
+
}
|
|
693
780
|
for (const pin of this.pins) {
|
|
694
781
|
if (!pin._facingDirection) {
|
|
695
782
|
const chip = this.chipMap[pin.chipId];
|
|
@@ -746,10 +833,25 @@ var SchematicTraceSingleLineSolver = class extends BaseSolver {
|
|
|
746
833
|
return;
|
|
747
834
|
}
|
|
748
835
|
const nextCandidatePath = this.queuedCandidatePaths.shift();
|
|
836
|
+
const restrictedCenterLines = getRestrictedCenterLines({
|
|
837
|
+
pins: this.pins,
|
|
838
|
+
inputProblem: this.inputProblem,
|
|
839
|
+
pinIdMap: this.pinIdMap,
|
|
840
|
+
chipMap: this.chipMap
|
|
841
|
+
});
|
|
749
842
|
for (let i = 0; i < nextCandidatePath.length - 1; i++) {
|
|
750
843
|
const start = nextCandidatePath[i];
|
|
751
844
|
const end = nextCandidatePath[i + 1];
|
|
752
845
|
let excludeChipIds = [];
|
|
846
|
+
const EPS2 = 1e-9;
|
|
847
|
+
for (const [, rcl] of restrictedCenterLines) {
|
|
848
|
+
if (rcl.axes.has("x") && typeof rcl.x === "number") {
|
|
849
|
+
if ((start.x - rcl.x) * (end.x - rcl.x) < -EPS2) return;
|
|
850
|
+
}
|
|
851
|
+
if (rcl.axes.has("y") && typeof rcl.y === "number") {
|
|
852
|
+
if ((start.y - rcl.y) * (end.y - rcl.y) < -EPS2) return;
|
|
853
|
+
}
|
|
854
|
+
}
|
|
753
855
|
const isStartPin = this.pins.some(
|
|
754
856
|
(pin) => Math.abs(pin.x - start.x) < 1e-10 && Math.abs(pin.y - start.y) < 1e-10
|
|
755
857
|
);
|
|
@@ -764,12 +866,12 @@ var SchematicTraceSingleLineSolver = class extends BaseSolver {
|
|
|
764
866
|
const bounds = getInputChipBounds(this.chipMap[startPin.chipId]);
|
|
765
867
|
const dx = end.x - start.x;
|
|
766
868
|
const dy = end.y - start.y;
|
|
767
|
-
const
|
|
869
|
+
const EPS3 = 1e-9;
|
|
768
870
|
const onLeft = Math.abs(start.x - bounds.minX) < 1e-9;
|
|
769
871
|
const onRight = Math.abs(start.x - bounds.maxX) < 1e-9;
|
|
770
872
|
const onBottom = Math.abs(start.y - bounds.minY) < 1e-9;
|
|
771
873
|
const onTop = Math.abs(start.y - bounds.maxY) < 1e-9;
|
|
772
|
-
const entersInterior = onLeft && dx >
|
|
874
|
+
const entersInterior = onLeft && dx > EPS3 || onRight && dx < -EPS3 || onBottom && dy > EPS3 || onTop && dy < -EPS3;
|
|
773
875
|
if (entersInterior) return;
|
|
774
876
|
if (!excludeChipIds.includes(startPin.chipId)) {
|
|
775
877
|
excludeChipIds.push(startPin.chipId);
|
|
@@ -784,12 +886,12 @@ var SchematicTraceSingleLineSolver = class extends BaseSolver {
|
|
|
784
886
|
const bounds = getInputChipBounds(this.chipMap[endPin.chipId]);
|
|
785
887
|
const dx = start.x - end.x;
|
|
786
888
|
const dy = start.y - end.y;
|
|
787
|
-
const
|
|
889
|
+
const EPS3 = 1e-9;
|
|
788
890
|
const onLeft = Math.abs(end.x - bounds.minX) < 1e-9;
|
|
789
891
|
const onRight = Math.abs(end.x - bounds.maxX) < 1e-9;
|
|
790
892
|
const onBottom = Math.abs(end.y - bounds.minY) < 1e-9;
|
|
791
893
|
const onTop = Math.abs(end.y - bounds.maxY) < 1e-9;
|
|
792
|
-
const entersInterior = onLeft && dx >
|
|
894
|
+
const entersInterior = onLeft && dx > EPS3 || onRight && dx < -EPS3 || onBottom && dy > EPS3 || onTop && dy < -EPS3;
|
|
793
895
|
if (entersInterior) return;
|
|
794
896
|
if (!excludeChipIds.includes(endPin.chipId)) {
|
|
795
897
|
excludeChipIds.push(endPin.chipId);
|
|
@@ -4,7 +4,13 @@ import { BaseSolver } from "lib/solvers/BaseSolver/BaseSolver"
|
|
|
4
4
|
import type { Guideline } from "lib/solvers/GuidelinesSolver/GuidelinesSolver"
|
|
5
5
|
import type { MspConnectionPair } from "lib/solvers/MspConnectionPairSolver/MspConnectionPairSolver"
|
|
6
6
|
import { visualizeInputProblem } from "lib/solvers/SchematicTracePipelineSolver/visualizeInputProblem"
|
|
7
|
-
import type {
|
|
7
|
+
import type {
|
|
8
|
+
ChipId,
|
|
9
|
+
InputChip,
|
|
10
|
+
InputPin,
|
|
11
|
+
InputProblem,
|
|
12
|
+
PinId,
|
|
13
|
+
} from "lib/types/InputProblem"
|
|
8
14
|
import { calculateElbow } from "calculate-elbow"
|
|
9
15
|
import { getPinDirection } from "./getPinDirection"
|
|
10
16
|
import {
|
|
@@ -15,6 +21,9 @@ import type { Point } from "@tscircuit/math-utils"
|
|
|
15
21
|
import { visualizeGuidelines } from "lib/solvers/GuidelinesSolver/visualizeGuidelines"
|
|
16
22
|
import { getInputChipBounds } from "lib/solvers/GuidelinesSolver/getInputChipBounds"
|
|
17
23
|
import { getColorFromString } from "lib/utils/getColorFromString"
|
|
24
|
+
import { getRestrictedCenterLines } from "./getRestrictedCenterLines"
|
|
25
|
+
|
|
26
|
+
type ChipPin = InputPin & { chipId: ChipId }
|
|
18
27
|
|
|
19
28
|
export class SchematicTraceSingleLineSolver extends BaseSolver {
|
|
20
29
|
pins: MspConnectionPair["pins"]
|
|
@@ -31,6 +40,9 @@ export class SchematicTraceSingleLineSolver extends BaseSolver {
|
|
|
31
40
|
|
|
32
41
|
solvedTracePath: { x: number; y: number }[] | null = null
|
|
33
42
|
|
|
43
|
+
// map of pinId -> pin (with chipId attached)
|
|
44
|
+
pinIdMap: Map<PinId, ChipPin> = new Map()
|
|
45
|
+
|
|
34
46
|
constructor(params: {
|
|
35
47
|
pins: MspConnectionPair["pins"]
|
|
36
48
|
guidelines: Guideline[]
|
|
@@ -51,6 +63,13 @@ export class SchematicTraceSingleLineSolver extends BaseSolver {
|
|
|
51
63
|
this.chipObstacleSpatialIndex
|
|
52
64
|
}
|
|
53
65
|
|
|
66
|
+
// Build a lookup of all pins by id and attach chipId to each pin entry
|
|
67
|
+
for (const chip of this.inputProblem.chips) {
|
|
68
|
+
for (const pin of chip.pins) {
|
|
69
|
+
this.pinIdMap.set(pin.pinId, { ...pin, chipId: chip.chipId })
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
54
73
|
for (const pin of this.pins) {
|
|
55
74
|
if (!pin._facingDirection) {
|
|
56
75
|
const chip = this.chipMap[pin.chipId]
|
|
@@ -118,6 +137,13 @@ export class SchematicTraceSingleLineSolver extends BaseSolver {
|
|
|
118
137
|
|
|
119
138
|
const nextCandidatePath = this.queuedCandidatePaths.shift()!
|
|
120
139
|
|
|
140
|
+
const restrictedCenterLines = getRestrictedCenterLines({
|
|
141
|
+
pins: this.pins,
|
|
142
|
+
inputProblem: this.inputProblem,
|
|
143
|
+
pinIdMap: this.pinIdMap,
|
|
144
|
+
chipMap: this.chipMap,
|
|
145
|
+
})
|
|
146
|
+
|
|
121
147
|
for (let i = 0; i < nextCandidatePath.length - 1; i++) {
|
|
122
148
|
const start = nextCandidatePath[i]
|
|
123
149
|
const end = nextCandidatePath[i + 1]
|
|
@@ -125,6 +151,19 @@ export class SchematicTraceSingleLineSolver extends BaseSolver {
|
|
|
125
151
|
// Determine which chips to exclude for this specific segment
|
|
126
152
|
let excludeChipIds: string[] = []
|
|
127
153
|
|
|
154
|
+
// If this segment would cross any restricted center line, reject the candidate path.
|
|
155
|
+
const EPS = 1e-9
|
|
156
|
+
for (const [, rcl] of restrictedCenterLines) {
|
|
157
|
+
if (rcl.axes.has("x") && typeof rcl.x === "number") {
|
|
158
|
+
// segment strictly crosses vertical center line
|
|
159
|
+
if ((start.x - rcl.x) * (end.x - rcl.x) < -EPS) return
|
|
160
|
+
}
|
|
161
|
+
if (rcl.axes.has("y") && typeof rcl.y === "number") {
|
|
162
|
+
// segment strictly crosses horizontal center line
|
|
163
|
+
if ((start.y - rcl.y) * (end.y - rcl.y) < -EPS) return
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
128
167
|
// Always exclude chips that contain the start or end points of this segment
|
|
129
168
|
// if those points are actually pin locations
|
|
130
169
|
const isStartPin = this.pins.some(
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ChipId,
|
|
3
|
+
InputChip,
|
|
4
|
+
InputPin,
|
|
5
|
+
InputProblem,
|
|
6
|
+
PinId,
|
|
7
|
+
} from "lib/types/InputProblem"
|
|
8
|
+
import { getPinDirection } from "./getPinDirection"
|
|
9
|
+
|
|
10
|
+
type ChipPin = InputPin & { chipId: ChipId }
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* A line that should not be crossed by a trace segment.
|
|
14
|
+
* This is used to prevent traces from crossing through the center of a chip when
|
|
15
|
+
* connecting pins on that same chip. Right now this is only enabled when a chip
|
|
16
|
+
* has multiple pins on at least one side.
|
|
17
|
+
*/
|
|
18
|
+
export type RestrictedCenterLine = {
|
|
19
|
+
x?: number
|
|
20
|
+
y?: number
|
|
21
|
+
axes: Set<"x" | "y">
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export const getRestrictedCenterLines = (params: {
|
|
25
|
+
pins: Array<InputPin & { chipId: string }>
|
|
26
|
+
inputProblem: InputProblem
|
|
27
|
+
pinIdMap: Map<PinId, ChipPin>
|
|
28
|
+
chipMap: Record<string, InputChip>
|
|
29
|
+
}): Map<ChipId, RestrictedCenterLine> => {
|
|
30
|
+
const { pins, inputProblem, pinIdMap, chipMap } = params
|
|
31
|
+
|
|
32
|
+
// Determine set of related pin IDs (closure over directConnections) for both endpoints
|
|
33
|
+
const findAllDirectlyConnectedPins = (startPinId: string) => {
|
|
34
|
+
const visited = new Set<string>()
|
|
35
|
+
const queue: string[] = [startPinId]
|
|
36
|
+
visited.add(startPinId)
|
|
37
|
+
const directConns = inputProblem.directConnections || []
|
|
38
|
+
while (queue.length) {
|
|
39
|
+
const cur = queue.shift()!
|
|
40
|
+
for (const dc of directConns) {
|
|
41
|
+
if (dc.pinIds.includes(cur)) {
|
|
42
|
+
for (const p of dc.pinIds) {
|
|
43
|
+
if (!visited.has(p)) {
|
|
44
|
+
visited.add(p)
|
|
45
|
+
queue.push(p)
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return visited
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const p0 = pins[0].pinId
|
|
55
|
+
const p1 = pins[1].pinId
|
|
56
|
+
const relatedPinIds = new Set<string>([
|
|
57
|
+
...findAllDirectlyConnectedPins(p0),
|
|
58
|
+
...findAllDirectlyConnectedPins(p1),
|
|
59
|
+
])
|
|
60
|
+
|
|
61
|
+
const restrictedCenterLines = new Map<ChipId, RestrictedCenterLine>()
|
|
62
|
+
|
|
63
|
+
// Collect facing-signs per chip
|
|
64
|
+
const chipFacingMap = new Map<
|
|
65
|
+
string,
|
|
66
|
+
{
|
|
67
|
+
hasXPos?: boolean
|
|
68
|
+
hasXNeg?: boolean
|
|
69
|
+
hasYPos?: boolean
|
|
70
|
+
hasYNeg?: boolean
|
|
71
|
+
center: { x: number; y: number }
|
|
72
|
+
counts?: { xPos: number; xNeg: number; yPos: number; yNeg: number }
|
|
73
|
+
}
|
|
74
|
+
>()
|
|
75
|
+
|
|
76
|
+
const chipsOfFacingPins = new Set<string>(pins.map((p) => p.chipId))
|
|
77
|
+
|
|
78
|
+
for (const pinId of relatedPinIds) {
|
|
79
|
+
const pin = pinIdMap.get(pinId)
|
|
80
|
+
if (!pin) continue
|
|
81
|
+
const chip = chipMap[pin.chipId]
|
|
82
|
+
if (!chip) continue
|
|
83
|
+
const facing = pin._facingDirection ?? getPinDirection(pin, chip)
|
|
84
|
+
let entry = chipFacingMap.get(chip.chipId)
|
|
85
|
+
if (!entry) {
|
|
86
|
+
entry = { center: chip.center }
|
|
87
|
+
|
|
88
|
+
const counts = { xPos: 0, xNeg: 0, yPos: 0, yNeg: 0 }
|
|
89
|
+
for (const cp of chip.pins) {
|
|
90
|
+
const cpFacing = cp._facingDirection ?? getPinDirection(cp, chip)
|
|
91
|
+
if (cpFacing === "x+") counts.xPos++
|
|
92
|
+
if (cpFacing === "x-") counts.xNeg++
|
|
93
|
+
if (cpFacing === "y+") counts.yPos++
|
|
94
|
+
if (cpFacing === "y-") counts.yNeg++
|
|
95
|
+
}
|
|
96
|
+
entry.counts = counts
|
|
97
|
+
|
|
98
|
+
chipFacingMap.set(chip.chipId, entry)
|
|
99
|
+
}
|
|
100
|
+
if (facing === "x+") entry.hasXPos = true
|
|
101
|
+
if (facing === "x-") entry.hasXNeg = true
|
|
102
|
+
if (facing === "y+") entry.hasYPos = true
|
|
103
|
+
if (facing === "y-") entry.hasYNeg = true
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Only mark a center as restricted on an axis if both signs for that axis
|
|
107
|
+
// are present among related pins on the chip.
|
|
108
|
+
for (const [chipId, faces] of chipFacingMap) {
|
|
109
|
+
const axes = new Set<"x" | "y">()
|
|
110
|
+
const rcl: RestrictedCenterLine = { axes }
|
|
111
|
+
|
|
112
|
+
// determine whether any side on this chip has more than one pin
|
|
113
|
+
const counts = faces.counts
|
|
114
|
+
const anySideHasMultiplePins = !!(
|
|
115
|
+
counts &&
|
|
116
|
+
(counts.xPos > 1 || counts.xNeg > 1 || counts.yPos > 1 || counts.yNeg > 1)
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
const skipCenterRestriction =
|
|
120
|
+
!anySideHasMultiplePins && chipsOfFacingPins.has(chipId)
|
|
121
|
+
|
|
122
|
+
if (!skipCenterRestriction) {
|
|
123
|
+
if (faces.hasXPos && faces.hasXNeg) {
|
|
124
|
+
rcl.x = faces.center.x
|
|
125
|
+
axes.add("x")
|
|
126
|
+
}
|
|
127
|
+
if (faces.hasYPos && faces.hasYNeg) {
|
|
128
|
+
rcl.y = faces.center.y
|
|
129
|
+
axes.add("y")
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (axes.size > 0) {
|
|
134
|
+
restrictedCenterLines.set(chipId, rcl)
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return restrictedCenterLines
|
|
139
|
+
}
|
package/package.json
CHANGED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { GenericSolverDebugger } from "site/components/GenericSolverDebugger"
|
|
2
|
+
import { useMemo } from "react"
|
|
3
|
+
import type { InputProblem } from "lib/types/InputProblem"
|
|
4
|
+
import { SchematicTracePipelineSolver } from "lib/index"
|
|
5
|
+
|
|
6
|
+
const inputProblem = {
|
|
7
|
+
chips: [
|
|
8
|
+
{
|
|
9
|
+
chipId: "schematic_component_0",
|
|
10
|
+
center: {
|
|
11
|
+
x: 0,
|
|
12
|
+
y: 0,
|
|
13
|
+
},
|
|
14
|
+
width: 2,
|
|
15
|
+
height: 1.4,
|
|
16
|
+
pins: [
|
|
17
|
+
{
|
|
18
|
+
pinId: "U3.8",
|
|
19
|
+
x: -1.4,
|
|
20
|
+
y: 0.42500000000000004,
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
pinId: "U3.4",
|
|
24
|
+
x: -1.4,
|
|
25
|
+
y: -0.42500000000000004,
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
pinId: "U3.1",
|
|
29
|
+
x: 1.4,
|
|
30
|
+
y: 0.5,
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
pinId: "U3.6",
|
|
34
|
+
x: 1.4,
|
|
35
|
+
y: 0.30000000000000004,
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
pinId: "U3.5",
|
|
39
|
+
x: 1.4,
|
|
40
|
+
y: 0.10000000000000009,
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
pinId: "U3.2",
|
|
44
|
+
x: 1.4,
|
|
45
|
+
y: -0.09999999999999998,
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
pinId: "U3.3",
|
|
49
|
+
x: 1.4,
|
|
50
|
+
y: -0.3,
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
pinId: "U3.7",
|
|
54
|
+
x: 1.4,
|
|
55
|
+
y: -0.5,
|
|
56
|
+
},
|
|
57
|
+
],
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
chipId: "schematic_component_1",
|
|
61
|
+
center: {
|
|
62
|
+
x: -2.3145833,
|
|
63
|
+
y: 0,
|
|
64
|
+
},
|
|
65
|
+
width: 0.5291665999999999,
|
|
66
|
+
height: 1.0583333000000001,
|
|
67
|
+
pins: [
|
|
68
|
+
{
|
|
69
|
+
pinId: "C20.1",
|
|
70
|
+
x: -2.3148566499999994,
|
|
71
|
+
y: 0.5512093000000002,
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
pinId: "C20.2",
|
|
75
|
+
x: -2.31430995,
|
|
76
|
+
y: -0.5512093000000002,
|
|
77
|
+
},
|
|
78
|
+
],
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
chipId: "schematic_component_2",
|
|
82
|
+
center: {
|
|
83
|
+
x: 1.7577928249999983,
|
|
84
|
+
y: 1.7512907000000002,
|
|
85
|
+
},
|
|
86
|
+
width: 0.3155856499999966,
|
|
87
|
+
height: 1.0583332999999997,
|
|
88
|
+
pins: [
|
|
89
|
+
{
|
|
90
|
+
pinId: "R11.1",
|
|
91
|
+
x: 1.7580660749999977,
|
|
92
|
+
y: 2.3025814000000002,
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
pinId: "R11.2",
|
|
96
|
+
x: 1.757519574999999,
|
|
97
|
+
y: 1.2,
|
|
98
|
+
},
|
|
99
|
+
],
|
|
100
|
+
},
|
|
101
|
+
],
|
|
102
|
+
directConnections: [
|
|
103
|
+
{
|
|
104
|
+
pinIds: ["C20.1", "U3.8"],
|
|
105
|
+
netId: "capacitor.C20 > port.pin1 to .U3 > .VDD",
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
pinIds: ["C20.2", "U3.4"],
|
|
109
|
+
netId: "capacitor.C20 > port.pin2 to .U3 > .GND",
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
pinIds: ["R11.2", "U3.1"],
|
|
113
|
+
netId: "resistor.R11 > port.pin2 to .U3 > .N_CS",
|
|
114
|
+
},
|
|
115
|
+
],
|
|
116
|
+
netConnections: [
|
|
117
|
+
{
|
|
118
|
+
netId: "V3_3",
|
|
119
|
+
pinIds: ["U3.8", "U3.3", "U3.7", "C20.1", "R11.1"],
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
netId: "GND",
|
|
123
|
+
pinIds: ["U3.4", "C20.2"],
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
netId: "FLASH_N_CS",
|
|
127
|
+
pinIds: ["U3.1", "R11.2"],
|
|
128
|
+
},
|
|
129
|
+
],
|
|
130
|
+
availableNetLabelOrientations: {
|
|
131
|
+
V3_3: ["y+"],
|
|
132
|
+
GND: ["y-"],
|
|
133
|
+
},
|
|
134
|
+
maxMspPairDistance: 5,
|
|
135
|
+
} as InputProblem
|
|
136
|
+
|
|
137
|
+
export default () => {
|
|
138
|
+
const solver = useMemo(
|
|
139
|
+
() => new SchematicTracePipelineSolver(inputProblem),
|
|
140
|
+
[],
|
|
141
|
+
)
|
|
142
|
+
return <GenericSolverDebugger solver={solver} />
|
|
143
|
+
}
|
|
@@ -91,11 +91,17 @@ x+" data-x="4.5649999999999995" data-y="3" cx="586.9994196169471" cy="153.430063
|
|
|
91
91
|
<g>
|
|
92
92
|
<circle data-type="point" data-label="" data-x="-2.25" data-y="0" cx="144.0046430644225" cy="348.43876958792805" r="3" fill="hsl(40, 100%, 50%, 0.9)" />
|
|
93
93
|
</g>
|
|
94
|
+
<g>
|
|
95
|
+
<circle data-type="point" data-label="" data-x="3.75" data-y="-1.5" cx="534.022054556007" cy="445.94312246082416" r="3" fill="hsl(40, 100%, 50%, 0.9)" />
|
|
96
|
+
</g>
|
|
94
97
|
<g>
|
|
95
98
|
<circle data-type="point" data-label="" data-x="-2.25" data-y="-1.9999999999999998" cx="144.0046430644225" cy="478.4445734184562" r="3" fill="hsl(40, 100%, 50%, 0.9)" />
|
|
96
99
|
</g>
|
|
97
100
|
<g>
|
|
98
|
-
<circle data-type="point" data-label="" data-x="1.
|
|
101
|
+
<circle data-type="point" data-label="" data-x="1.3499999999999999" data-y="0" cx="378.01508995937314" cy="348.43876958792805" r="3" fill="hsl(40, 100%, 50%, 0.9)" />
|
|
102
|
+
</g>
|
|
103
|
+
<g>
|
|
104
|
+
<circle data-type="point" data-label="" data-x="-1.15" data-y="-1.125" cx="215.507835171213" cy="421.56703424260013" r="3" fill="hsl(40, 100%, 50%, 0.9)" />
|
|
99
105
|
</g>
|
|
100
106
|
<g>
|
|
101
107
|
<polyline data-points="-3.55,0 -1.15,1.125" data-type="line" data-label="" points="59.50087057457921,348.43876958792805 215.507835171213,275.31050493325597" fill="none" stroke="hsl(40, 100%, 50%, 0.8)" stroke-width="1" />
|
|
@@ -199,9 +205,6 @@ x+" data-x="4.5649999999999995" data-y="3" cx="586.9994196169471" cy="153.430063
|
|
|
199
205
|
<g>
|
|
200
206
|
<polyline data-points="1.15,0.75 3.75,0.75 3.75,0 3.55,0" data-type="line" data-label="" points="365.01450957632034,299.68659315148 534.022054556007,299.68659315148 534.022054556007,348.43876958792805 521.0214741729542,348.43876958792805" fill="none" stroke="purple" stroke-width="1" />
|
|
201
207
|
</g>
|
|
202
|
-
<g>
|
|
203
|
-
<polyline data-points="-1.15,-0.375 -1.3499999999999999,-0.375 -1.3499999999999999,2.275 1.35,2.275 1.35,0.75 1.15,0.75" data-type="line" data-label="" points="215.507835171213,372.8148578061521 202.5072547881602,372.8148578061521 202.5072547881602,200.55716773070228 378.0150899593732,200.55716773070228 378.0150899593732,299.68659315148 365.01450957632034,299.68659315148" fill="none" stroke="purple" stroke-width="1" />
|
|
204
|
-
</g>
|
|
205
208
|
<g>
|
|
206
209
|
<polyline data-points="-2.45,-1.9999999999999998 -2.25,-1.9999999999999998 -1.8,-1.9999999999999998 -1.8,-0.375 -1.3499999999999999,-0.375 -1.15,-0.375" data-type="line" data-label="" points="131.00406268136967,478.4445734184562 144.0046430644225,478.4445734184562 173.25594892629132,478.4445734184562 173.25594892629132,372.8148578061521 202.5072547881602,372.8148578061521 215.507835171213,372.8148578061521" fill="none" stroke="purple" stroke-width="1" />
|
|
207
210
|
</g>
|
|
@@ -211,9 +214,6 @@ x+" data-x="4.5649999999999995" data-y="3" cx="586.9994196169471" cy="153.430063
|
|
|
211
214
|
<g>
|
|
212
215
|
<polyline data-points="1.15,0 1.3499999999999999,0 1.8,0 1.8,-1.5 2.25,-1.5 2.45,-1.5" data-type="line" data-label="" points="365.01450957632034,348.43876958792805 378.01508995937314,348.43876958792805 407.266395821242,348.43876958792805 407.266395821242,445.94312246082416 436.51770168311083,445.94312246082416 449.5182820661637,445.94312246082416" fill="none" stroke="purple" stroke-width="1" />
|
|
213
216
|
</g>
|
|
214
|
-
<g>
|
|
215
|
-
<polyline data-points="-1.15,-1.125 -1.3499999999999999,-1.125 -1.3499999999999999,-2.29445535 1.35,-2.29445535 1.35,0 1.15,0" data-type="line" data-label="" points="215.507835171213,421.56703424260013 202.5072547881602,421.56703424260013 202.5072547881602,497.58502565293094 378.0150899593732,497.58502565293094 378.0150899593732,348.43876958792805 365.01450957632034,348.43876958792805" fill="none" stroke="purple" stroke-width="1" />
|
|
216
|
-
</g>
|
|
217
217
|
<g>
|
|
218
218
|
<rect data-type="rect" data-label="schematic_component_0" data-x="0" data-y="0" x="215.507835171213" y="226.55832849680792" width="149.50667440510733" height="243.76088218224027" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.015383928571428571" />
|
|
219
219
|
</g>
|
|
@@ -250,11 +250,17 @@ x+" data-x="4.5649999999999995" data-y="3" cx="586.9994196169471" cy="153.430063
|
|
|
250
250
|
<g>
|
|
251
251
|
<rect data-type="rect" data-label="" data-x="-2.25" data-y="0.225" x="137.50435287289608" y="319.1874637260592" width="13.000580383052835" height="29.251305861868843" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.015383928571428571" />
|
|
252
252
|
</g>
|
|
253
|
+
<g>
|
|
254
|
+
<rect data-type="rect" data-label="" data-x="3.75" data-y="-1.725" x="527.5217643644805" y="445.94312246082416" width="13.000580383052807" height="29.251305861868843" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.015383928571428571" />
|
|
255
|
+
</g>
|
|
253
256
|
<g>
|
|
254
257
|
<rect data-type="rect" data-label="" data-x="-2.25" data-y="-2.2249999999999996" x="137.50435287289608" y="478.4445734184562" width="13.000580383052835" height="29.251305861868843" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.015383928571428571" />
|
|
255
258
|
</g>
|
|
256
259
|
<g>
|
|
257
|
-
<rect data-type="rect" data-label="" data-x="1.
|
|
260
|
+
<rect data-type="rect" data-label="" data-x="1.3499999999999999" data-y="0.225" x="371.51479976784674" y="319.1874637260592" width="13.000580383052807" height="29.251305861868843" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.015383928571428571" />
|
|
261
|
+
</g>
|
|
262
|
+
<g>
|
|
263
|
+
<rect data-type="rect" data-label="" data-x="-1.376" data-y="-1.125" x="186.19152640742888" y="415.0667440510737" width="29.251305861868843" height="13.000580383052807" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.015383928571428571" />
|
|
258
264
|
</g>
|
|
259
265
|
<g id="crosshair" style="display: none">
|
|
260
266
|
<line id="crosshair-h" y1="0" y2="640" stroke="#666" stroke-width="0.5" />
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
<svg width="640" height="640" viewBox="0 0 640 640" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<rect width="100%" height="100%" fill="white" />
|
|
3
|
+
<g>
|
|
4
|
+
<circle data-type="point" data-label="U3.8
|
|
5
|
+
x-" data-x="-1.4" data-y="0.42500000000000004" cx="211.29957848579102" cy="266.28437168733643" r="3" fill="hsl(88, 100%, 50%, 0.8)" />
|
|
6
|
+
</g>
|
|
7
|
+
<g>
|
|
8
|
+
<circle data-type="point" data-label="U3.4
|
|
9
|
+
x-" data-x="-1.4" data-y="-0.42500000000000004" cx="211.29957848579102" cy="342.38151179694313" r="3" fill="hsl(84, 100%, 50%, 0.8)" />
|
|
10
|
+
</g>
|
|
11
|
+
<g>
|
|
12
|
+
<circle data-type="point" data-label="U3.1
|
|
13
|
+
x+" data-x="1.4" data-y="0.5" cx="461.9725106115543" cy="259.56991814825346" r="3" fill="hsl(81, 100%, 50%, 0.8)" />
|
|
14
|
+
</g>
|
|
15
|
+
<g>
|
|
16
|
+
<circle data-type="point" data-label="U3.6
|
|
17
|
+
x+" data-x="1.4" data-y="0.30000000000000004" cx="461.9725106115543" cy="277.47512758580797" r="3" fill="hsl(86, 100%, 50%, 0.8)" />
|
|
18
|
+
</g>
|
|
19
|
+
<g>
|
|
20
|
+
<circle data-type="point" data-label="U3.5
|
|
21
|
+
x+" data-x="1.4" data-y="0.10000000000000009" cx="461.9725106115543" cy="295.38033702336253" r="3" fill="hsl(85, 100%, 50%, 0.8)" />
|
|
22
|
+
</g>
|
|
23
|
+
<g>
|
|
24
|
+
<circle data-type="point" data-label="U3.2
|
|
25
|
+
x+" data-x="1.4" data-y="-0.09999999999999998" cx="461.9725106115543" cy="313.28554646091703" r="3" fill="hsl(82, 100%, 50%, 0.8)" />
|
|
26
|
+
</g>
|
|
27
|
+
<g>
|
|
28
|
+
<circle data-type="point" data-label="U3.3
|
|
29
|
+
x+" data-x="1.4" data-y="-0.3" cx="461.9725106115543" cy="331.1907558984716" r="3" fill="hsl(83, 100%, 50%, 0.8)" />
|
|
30
|
+
</g>
|
|
31
|
+
<g>
|
|
32
|
+
<circle data-type="point" data-label="U3.7
|
|
33
|
+
x+" data-x="1.4" data-y="-0.5" cx="461.9725106115543" cy="349.0959653360261" r="3" fill="hsl(87, 100%, 50%, 0.8)" />
|
|
34
|
+
</g>
|
|
35
|
+
<g>
|
|
36
|
+
<circle data-type="point" data-label="C20.1
|
|
37
|
+
y+" data-x="-2.3148566499999994" data-y="0.5512093000000002" cx="129.39607886784347" cy="254.98535194000064" r="3" fill="hsl(140, 100%, 50%, 0.8)" />
|
|
38
|
+
</g>
|
|
39
|
+
<g>
|
|
40
|
+
<circle data-type="point" data-label="C20.2
|
|
41
|
+
y-" data-x="-2.31430995" data-y="-0.5512093000000002" cx="129.44502275784095" cy="353.6805315442789" r="3" fill="hsl(141, 100%, 50%, 0.8)" />
|
|
42
|
+
</g>
|
|
43
|
+
<g>
|
|
44
|
+
<circle data-type="point" data-label="R11.1
|
|
45
|
+
y+" data-x="1.7580660749999977" data-y="2.3025814000000002" cx="494.0287509383446" cy="98.19193067205222" r="3" fill="hsl(125, 100%, 50%, 0.8)" />
|
|
46
|
+
</g>
|
|
47
|
+
<g>
|
|
48
|
+
<circle data-type="point" data-label="R11.2
|
|
49
|
+
y-" data-x="1.757519574999999" data-y="1.2" cx="493.97982495355666" cy="196.90168511681264" r="3" fill="hsl(126, 100%, 50%, 0.8)" />
|
|
50
|
+
</g>
|
|
51
|
+
<g>
|
|
52
|
+
<circle data-type="point" data-label="R12.1
|
|
53
|
+
y-" data-x="-1.7580660749999977" data-y="-3.3025814000000002" cx="179.24333815900067" cy="600" r="3" fill="hsl(6, 100%, 50%, 0.8)" />
|
|
54
|
+
</g>
|
|
55
|
+
<g>
|
|
56
|
+
<circle data-type="point" data-label="R12.2
|
|
57
|
+
y+" data-x="-1.757519574999999" data-y="-2.2" cx="179.29226414378866" cy="501.29024555523955" r="3" fill="hsl(7, 100%, 50%, 0.8)" />
|
|
58
|
+
</g>
|
|
59
|
+
<g>
|
|
60
|
+
<circle data-type="point" data-label="R13.1
|
|
61
|
+
y-" data-x="1.7580660749999977" data-y="-3.3025814000000002" cx="494.0287509383446" cy="600" r="3" fill="hsl(247, 100%, 50%, 0.8)" />
|
|
62
|
+
</g>
|
|
63
|
+
<g>
|
|
64
|
+
<circle data-type="point" data-label="R13.2
|
|
65
|
+
y+" data-x="1.757519574999999" data-y="-2.2" cx="493.97982495355666" cy="501.29024555523955" r="3" fill="hsl(248, 100%, 50%, 0.8)" />
|
|
66
|
+
</g>
|
|
67
|
+
<g>
|
|
68
|
+
<circle data-type="point" data-label="" data-x="-1.8574283249999997" data-y="0.7512093000000004" cx="170.34782867681724" cy="237.0801425024461" r="3" fill="hsl(40, 100%, 50%, 0.9)" />
|
|
69
|
+
</g>
|
|
70
|
+
<g>
|
|
71
|
+
<circle data-type="point" data-label="" data-x="1.7580660749999977" data-y="2.5025814000000004" cx="494.0287509383446" cy="80.28672123449769" r="3" fill="hsl(40, 100%, 50%, 0.9)" />
|
|
72
|
+
</g>
|
|
73
|
+
<g>
|
|
74
|
+
<circle data-type="point" data-label="" data-x="-2.31430995" data-y="-0.7512093000000004" cx="129.44502275784095" cy="371.58574098183345" r="3" fill="hsl(40, 100%, 50%, 0.9)" />
|
|
75
|
+
</g>
|
|
76
|
+
<g>
|
|
77
|
+
<circle data-type="point" data-label="" data-x="1.757519574999999" data-y="0.85" cx="493.97982495355666" cy="228.23580163253305" r="3" fill="hsl(40, 100%, 50%, 0.9)" />
|
|
78
|
+
</g>
|
|
79
|
+
<g>
|
|
80
|
+
<circle data-type="point" data-label="" data-x="1.757519574999999" data-y="-2" cx="493.97982495355666" cy="483.385036117685" r="3" fill="hsl(40, 100%, 50%, 0.9)" />
|
|
81
|
+
</g>
|
|
82
|
+
<g>
|
|
83
|
+
<polyline data-points="-2.3148566499999994,0.5512093000000002 -1.4,0.42500000000000004" data-type="line" data-label="" points="129.39607886784347,254.98535194000064 211.29957848579102,266.28437168733643" fill="none" stroke="hsl(256, 100%, 50%, 0.8)" stroke-width="1" />
|
|
84
|
+
</g>
|
|
85
|
+
<g>
|
|
86
|
+
<polyline data-points="-2.31430995,-0.5512093000000002 -1.4,-0.42500000000000004" data-type="line" data-label="" points="129.44502275784095,353.6805315442789 211.29957848579102,342.38151179694313" fill="none" stroke="hsl(256, 100%, 50%, 0.8)" stroke-width="1" />
|
|
87
|
+
</g>
|
|
88
|
+
<g>
|
|
89
|
+
<polyline data-points="1.757519574999999,1.2 1.4,0.5" data-type="line" data-label="" points="493.97982495355666,196.90168511681264 461.9725106115543,259.56991814825346" fill="none" stroke="hsl(144, 100%, 50%, 0.8)" stroke-width="1" />
|
|
90
|
+
</g>
|
|
91
|
+
<g>
|
|
92
|
+
<polyline data-points="1.757519574999999,-2.2 -1.757519574999999,-2.2" data-type="line" data-label="" points="493.97982495355666,501.29024555523955 179.29226414378866,501.29024555523955" fill="none" stroke="hsl(144, 100%, 50%, 0.8)" stroke-width="1" />
|
|
93
|
+
</g>
|
|
94
|
+
<g>
|
|
95
|
+
<polyline data-points="-1.4,0.42500000000000004 1.4,-0.3" data-type="line" data-label="" points="211.29957848579102,266.28437168733643 461.9725106115543,331.1907558984716" fill="none" stroke="hsl(73, 100%, 50%, 0.8)" stroke-width="1" stroke-dasharray="4 2" />
|
|
96
|
+
</g>
|
|
97
|
+
<g>
|
|
98
|
+
<polyline data-points="-1.4,0.42500000000000004 1.4,-0.5" data-type="line" data-label="" points="211.29957848579102,266.28437168733643 461.9725106115543,349.0959653360261" fill="none" stroke="hsl(73, 100%, 50%, 0.8)" stroke-width="1" stroke-dasharray="4 2" />
|
|
99
|
+
</g>
|
|
100
|
+
<g>
|
|
101
|
+
<polyline data-points="-1.4,0.42500000000000004 -2.3148566499999994,0.5512093000000002" data-type="line" data-label="" points="211.29957848579102,266.28437168733643 129.39607886784347,254.98535194000064" fill="none" stroke="hsl(73, 100%, 50%, 0.8)" stroke-width="1" stroke-dasharray="4 2" />
|
|
102
|
+
</g>
|
|
103
|
+
<g>
|
|
104
|
+
<polyline data-points="-1.4,0.42500000000000004 1.7580660749999977,2.3025814000000002" data-type="line" data-label="" points="211.29957848579102,266.28437168733643 494.0287509383446,98.19193067205222" fill="none" stroke="hsl(73, 100%, 50%, 0.8)" stroke-width="1" stroke-dasharray="4 2" />
|
|
105
|
+
</g>
|
|
106
|
+
<g>
|
|
107
|
+
<polyline data-points="1.4,-0.3 1.4,-0.5" data-type="line" data-label="" points="461.9725106115543,331.1907558984716 461.9725106115543,349.0959653360261" fill="none" stroke="hsl(73, 100%, 50%, 0.8)" stroke-width="1" stroke-dasharray="4 2" />
|
|
108
|
+
</g>
|
|
109
|
+
<g>
|
|
110
|
+
<polyline data-points="1.4,-0.3 -2.3148566499999994,0.5512093000000002" data-type="line" data-label="" points="461.9725106115543,331.1907558984716 129.39607886784347,254.98535194000064" fill="none" stroke="hsl(73, 100%, 50%, 0.8)" stroke-width="1" stroke-dasharray="4 2" />
|
|
111
|
+
</g>
|
|
112
|
+
<g>
|
|
113
|
+
<polyline data-points="1.4,-0.3 1.7580660749999977,2.3025814000000002" data-type="line" data-label="" points="461.9725106115543,331.1907558984716 494.0287509383446,98.19193067205222" fill="none" stroke="hsl(73, 100%, 50%, 0.8)" stroke-width="1" stroke-dasharray="4 2" />
|
|
114
|
+
</g>
|
|
115
|
+
<g>
|
|
116
|
+
<polyline data-points="1.4,-0.5 -2.3148566499999994,0.5512093000000002" data-type="line" data-label="" points="461.9725106115543,349.0959653360261 129.39607886784347,254.98535194000064" fill="none" stroke="hsl(73, 100%, 50%, 0.8)" stroke-width="1" stroke-dasharray="4 2" />
|
|
117
|
+
</g>
|
|
118
|
+
<g>
|
|
119
|
+
<polyline data-points="1.4,-0.5 1.7580660749999977,2.3025814000000002" data-type="line" data-label="" points="461.9725106115543,349.0959653360261 494.0287509383446,98.19193067205222" fill="none" stroke="hsl(73, 100%, 50%, 0.8)" stroke-width="1" stroke-dasharray="4 2" />
|
|
120
|
+
</g>
|
|
121
|
+
<g>
|
|
122
|
+
<polyline data-points="-2.3148566499999994,0.5512093000000002 1.7580660749999977,2.3025814000000002" data-type="line" data-label="" points="129.39607886784347,254.98535194000064 494.0287509383446,98.19193067205222" fill="none" stroke="hsl(73, 100%, 50%, 0.8)" stroke-width="1" stroke-dasharray="4 2" />
|
|
123
|
+
</g>
|
|
124
|
+
<g>
|
|
125
|
+
<polyline data-points="-1.4,-0.42500000000000004 -2.31430995,-0.5512093000000002" data-type="line" data-label="" points="211.29957848579102,342.38151179694313 129.44502275784095,353.6805315442789" fill="none" stroke="hsl(157, 100%, 50%, 0.8)" stroke-width="1" stroke-dasharray="4 2" />
|
|
126
|
+
</g>
|
|
127
|
+
<g>
|
|
128
|
+
<polyline data-points="1.4,0.5 1.757519574999999,1.2" data-type="line" data-label="" points="461.9725106115543,259.56991814825346 493.97982495355666,196.90168511681264" fill="none" stroke="hsl(304, 100%, 50%, 0.8)" stroke-width="1" stroke-dasharray="4 2" />
|
|
129
|
+
</g>
|
|
130
|
+
<g>
|
|
131
|
+
<polyline data-points="-1.4,0.42500000000000004 -1.8574283249999997,0.42500000000000004 -1.8574283249999997,0.7512093000000004 -2.3148566499999994,0.7512093000000004 -2.3148566499999994,0.5512093000000002" data-type="line" data-label="" points="211.29957848579102,266.28437168733643 170.34782867681724,266.28437168733643 170.34782867681724,237.0801425024461 129.39607886784347,237.0801425024461 129.39607886784347,254.98535194000064" fill="none" stroke="purple" stroke-width="1" />
|
|
132
|
+
</g>
|
|
133
|
+
<g>
|
|
134
|
+
<polyline data-points="1.4,-0.5 1.5999999999999999,-0.5 1.5999999999999999,-0.3 1.4,-0.3" data-type="line" data-label="" points="461.9725106115543,349.0959653360261 479.8777200491088,349.0959653360261 479.8777200491088,331.1907558984716 461.9725106115543,331.1907558984716" fill="none" stroke="purple" stroke-width="1" />
|
|
135
|
+
</g>
|
|
136
|
+
<g>
|
|
137
|
+
<polyline data-points="1.7580660749999977,2.3025814000000002 1.7580660749999977,2.5025814000000004 1.5790330374999988,2.5025814000000004 1.5790330374999988,-0.3 1.4,-0.3" data-type="line" data-label="" points="494.0287509383446,98.19193067205222 494.0287509383446,80.28672123449769 478.0006307749495,80.28672123449769 478.0006307749495,331.1907558984716 461.9725106115543,331.1907558984716" fill="none" stroke="purple" stroke-width="1" />
|
|
138
|
+
</g>
|
|
139
|
+
<g>
|
|
140
|
+
<polyline data-points="-2.31430995,-0.5512093000000002 -2.31430995,-0.7512093000000004 -1.857154975,-0.7512093000000004 -1.857154975,-0.42500000000000004 -1.4,-0.42500000000000004" data-type="line" data-label="" points="129.44502275784095,353.6805315442789 129.44502275784095,371.58574098183345 170.37230062181598,371.58574098183345 170.37230062181598,342.38151179694313 211.29957848579102,342.38151179694313" fill="none" stroke="purple" stroke-width="1" />
|
|
141
|
+
</g>
|
|
142
|
+
<g>
|
|
143
|
+
<polyline data-points="1.757519574999999,1.2 1.757519574999999,0.5 1.4,0.5" data-type="line" data-label="" points="493.97982495355666,196.90168511681264 493.97982495355666,259.56991814825346 461.9725106115543,259.56991814825346" fill="none" stroke="purple" stroke-width="1" />
|
|
144
|
+
</g>
|
|
145
|
+
<g>
|
|
146
|
+
<polyline data-points="1.757519574999999,-2.2 1.757519574999999,-2 -1.757519574999999,-2 -1.757519574999999,-2.2" data-type="line" data-label="" points="493.97982495355666,501.29024555523955 493.97982495355666,483.385036117685 179.29226414378866,483.385036117685 179.29226414378866,501.29024555523955" fill="none" stroke="purple" stroke-width="1" />
|
|
147
|
+
</g>
|
|
148
|
+
<g>
|
|
149
|
+
<rect data-type="rect" data-label="schematic_component_0" data-x="0" data-y="0" x="211.29957848579102" y="241.66470871069896" width="250.67293212576328" height="125.33646606288164" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.011169933571428573" />
|
|
150
|
+
</g>
|
|
151
|
+
<g>
|
|
152
|
+
<rect data-type="rect" data-label="schematic_component_1" data-x="-2.3145833" data-y="0" x="105.73345381194562" y="254.98535194000064" width="47.37419400179317" height="98.69517960427825" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.011169933571428573" />
|
|
153
|
+
</g>
|
|
154
|
+
<g>
|
|
155
|
+
<rect data-type="rect" data-label="schematic_component_2" data-x="1.7577928249999983" data-y="1.7512907000000002" x="479.87772004910886" y="98.19193067205222" width="28.25313579368361" height="98.70975444476042" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.011169933571428573" />
|
|
156
|
+
</g>
|
|
157
|
+
<g>
|
|
158
|
+
<rect data-type="rect" data-label="schematic_component_3" data-x="-1.7577928249999983" data-y="-2.7512907" x="165.14123325455287" y="501.29024555523955" width="28.253135793683583" height="98.70975444476045" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.011169933571428573" />
|
|
159
|
+
</g>
|
|
160
|
+
<g>
|
|
161
|
+
<rect data-type="rect" data-label="schematic_component_4" data-x="1.7577928249999983" data-y="-2.7512907" x="479.87772004910886" y="501.29024555523955" width="28.25313579368361" height="98.70975444476045" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.011169933571428573" />
|
|
162
|
+
</g>
|
|
163
|
+
<g>
|
|
164
|
+
<rect data-type="rect" data-label="" data-x="-1.8574283249999997" data-y="0.9762093000000004" x="161.39522395803996" y="196.79342126794842" width="17.905209437554532" height="40.28672123449769" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.011169933571428573" />
|
|
165
|
+
</g>
|
|
166
|
+
<g>
|
|
167
|
+
<rect data-type="rect" data-label="" data-x="1.7580660749999977" data-y="2.7275814000000005" x="485.07614621956736" y="40" width="17.90520943755456" height="40.28672123449769" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.011169933571428573" />
|
|
168
|
+
</g>
|
|
169
|
+
<g>
|
|
170
|
+
<rect data-type="rect" data-label="" data-x="-2.31430995" data-y="-0.9762093000000004" x="120.4924180390637" y="371.58574098183345" width="17.905209437554532" height="40.28672123449769" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.011169933571428573" />
|
|
171
|
+
</g>
|
|
172
|
+
<g>
|
|
173
|
+
<rect data-type="rect" data-label="" data-x="1.982519574999999" data-y="0.85" x="493.97982495355666" y="219.2831969137558" width="40.28672123449769" height="17.905209437554532" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.011169933571428573" />
|
|
174
|
+
</g>
|
|
175
|
+
<g>
|
|
176
|
+
<rect data-type="rect" data-label="" data-x="1.982519574999999" data-y="-2" x="493.97982495355666" y="474.43243139890774" width="40.28672123449769" height="17.90520943755456" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.011169933571428573" />
|
|
177
|
+
</g>
|
|
178
|
+
<g id="crosshair" style="display: none">
|
|
179
|
+
<line id="crosshair-h" y1="0" y2="640" stroke="#666" stroke-width="0.5" />
|
|
180
|
+
<line id="crosshair-v" x1="0" x2="640" stroke="#666" stroke-width="0.5" /><text id="coordinates" font-family="monospace" font-size="12" fill="#666"></text>
|
|
181
|
+
</g>
|
|
182
|
+
<script>
|
|
183
|
+
<![CDATA[
|
|
184
|
+
document.currentScript.parentElement.addEventListener('mousemove', (e) => {
|
|
185
|
+
const svg = e.currentTarget;
|
|
186
|
+
const rect = svg.getBoundingClientRect();
|
|
187
|
+
const x = e.clientX - rect.left;
|
|
188
|
+
const y = e.clientY - rect.top;
|
|
189
|
+
const crosshair = svg.getElementById('crosshair');
|
|
190
|
+
const h = svg.getElementById('crosshair-h');
|
|
191
|
+
const v = svg.getElementById('crosshair-v');
|
|
192
|
+
const coords = svg.getElementById('coordinates');
|
|
193
|
+
|
|
194
|
+
crosshair.style.display = 'block';
|
|
195
|
+
h.setAttribute('x1', '0');
|
|
196
|
+
h.setAttribute('x2', '640');
|
|
197
|
+
h.setAttribute('y1', y);
|
|
198
|
+
h.setAttribute('y2', y);
|
|
199
|
+
v.setAttribute('x1', x);
|
|
200
|
+
v.setAttribute('x2', x);
|
|
201
|
+
v.setAttribute('y1', '0');
|
|
202
|
+
v.setAttribute('y2', '640');
|
|
203
|
+
|
|
204
|
+
// Calculate real coordinates using inverse transformation
|
|
205
|
+
const matrix = {
|
|
206
|
+
"a": 89.52604718777262,
|
|
207
|
+
"c": 0,
|
|
208
|
+
"e": 336.63604454867266,
|
|
209
|
+
"b": 0,
|
|
210
|
+
"d": -89.52604718777262,
|
|
211
|
+
"f": 304.3329417421398
|
|
212
|
+
};
|
|
213
|
+
// Manually invert and apply the affine transform
|
|
214
|
+
// Since we only use translate and scale, we can directly compute:
|
|
215
|
+
// x' = (x - tx) / sx
|
|
216
|
+
// y' = (y - ty) / sy
|
|
217
|
+
const sx = matrix.a;
|
|
218
|
+
const sy = matrix.d;
|
|
219
|
+
const tx = matrix.e;
|
|
220
|
+
const ty = matrix.f;
|
|
221
|
+
const realPoint = {
|
|
222
|
+
x: (x - tx) / sx,
|
|
223
|
+
y: (y - ty) / sy // Flip y back since we used negative scale
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
coords.textContent = `(${realPoint.x.toFixed(2)}, ${realPoint.y.toFixed(2)})`;
|
|
227
|
+
coords.setAttribute('x', (x + 5).toString());
|
|
228
|
+
coords.setAttribute('y', (y - 5).toString());
|
|
229
|
+
});
|
|
230
|
+
document.currentScript.parentElement.addEventListener('mouseleave', () => {
|
|
231
|
+
document.currentScript.parentElement.getElementById('crosshair').style.display = 'none';
|
|
232
|
+
});
|
|
233
|
+
]]>
|
|
234
|
+
</script>
|
|
235
|
+
</svg>
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { expect } from "bun:test"
|
|
2
|
+
import { test } from "bun:test"
|
|
3
|
+
import { SchematicTracePipelineSolver, type InputProblem } from "lib/index"
|
|
4
|
+
import "tests/fixtures/matcher"
|
|
5
|
+
|
|
6
|
+
const inputProblem = {
|
|
7
|
+
chips: [
|
|
8
|
+
{
|
|
9
|
+
chipId: "schematic_component_0",
|
|
10
|
+
center: {
|
|
11
|
+
x: 0,
|
|
12
|
+
y: 0,
|
|
13
|
+
},
|
|
14
|
+
width: 2,
|
|
15
|
+
height: 1.4,
|
|
16
|
+
pins: [
|
|
17
|
+
{
|
|
18
|
+
pinId: "U3.8",
|
|
19
|
+
x: -1.4,
|
|
20
|
+
y: 0.42500000000000004,
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
pinId: "U3.4",
|
|
24
|
+
x: -1.4,
|
|
25
|
+
y: -0.42500000000000004,
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
pinId: "U3.1",
|
|
29
|
+
x: 1.4,
|
|
30
|
+
y: 0.5,
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
pinId: "U3.6",
|
|
34
|
+
x: 1.4,
|
|
35
|
+
y: 0.30000000000000004,
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
pinId: "U3.5",
|
|
39
|
+
x: 1.4,
|
|
40
|
+
y: 0.10000000000000009,
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
pinId: "U3.2",
|
|
44
|
+
x: 1.4,
|
|
45
|
+
y: -0.09999999999999998,
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
pinId: "U3.3",
|
|
49
|
+
x: 1.4,
|
|
50
|
+
y: -0.3,
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
pinId: "U3.7",
|
|
54
|
+
x: 1.4,
|
|
55
|
+
y: -0.5,
|
|
56
|
+
},
|
|
57
|
+
],
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
chipId: "schematic_component_1",
|
|
61
|
+
center: {
|
|
62
|
+
x: -2.3145833,
|
|
63
|
+
y: 0,
|
|
64
|
+
},
|
|
65
|
+
width: 0.5291665999999999,
|
|
66
|
+
height: 1.0583333000000001,
|
|
67
|
+
pins: [
|
|
68
|
+
{
|
|
69
|
+
pinId: "C20.1",
|
|
70
|
+
x: -2.3148566499999994,
|
|
71
|
+
y: 0.5512093000000002,
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
pinId: "C20.2",
|
|
75
|
+
x: -2.31430995,
|
|
76
|
+
y: -0.5512093000000002,
|
|
77
|
+
},
|
|
78
|
+
],
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
chipId: "schematic_component_2",
|
|
82
|
+
center: {
|
|
83
|
+
x: 1.7577928249999983,
|
|
84
|
+
y: 1.7512907000000002,
|
|
85
|
+
},
|
|
86
|
+
width: 0.3155856499999966,
|
|
87
|
+
height: 1.0583332999999997,
|
|
88
|
+
pins: [
|
|
89
|
+
{
|
|
90
|
+
pinId: "R11.1",
|
|
91
|
+
x: 1.7580660749999977,
|
|
92
|
+
y: 2.3025814000000002,
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
pinId: "R11.2",
|
|
96
|
+
x: 1.757519574999999,
|
|
97
|
+
y: 1.2,
|
|
98
|
+
},
|
|
99
|
+
],
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
chipId: "schematic_component_3",
|
|
103
|
+
center: {
|
|
104
|
+
x: -1.7577928249999983,
|
|
105
|
+
y: -2.7512907000000002,
|
|
106
|
+
},
|
|
107
|
+
width: 0.3155856499999966,
|
|
108
|
+
height: 1.0583332999999997,
|
|
109
|
+
pins: [
|
|
110
|
+
{
|
|
111
|
+
pinId: "R12.1",
|
|
112
|
+
x: -1.7580660749999977,
|
|
113
|
+
y: -3.3025814000000002,
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
pinId: "R12.2",
|
|
117
|
+
x: -1.757519574999999,
|
|
118
|
+
y: -2.2,
|
|
119
|
+
},
|
|
120
|
+
],
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
chipId: "schematic_component_4",
|
|
124
|
+
center: {
|
|
125
|
+
x: 1.7577928249999983,
|
|
126
|
+
y: -2.7512907000000002,
|
|
127
|
+
},
|
|
128
|
+
width: 0.3155856499999966,
|
|
129
|
+
height: 1.0583332999999997,
|
|
130
|
+
pins: [
|
|
131
|
+
{
|
|
132
|
+
pinId: "R13.1",
|
|
133
|
+
x: 1.7580660749999977,
|
|
134
|
+
y: -3.3025814000000002,
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
pinId: "R13.2",
|
|
138
|
+
x: 1.757519574999999,
|
|
139
|
+
y: -2.2,
|
|
140
|
+
},
|
|
141
|
+
],
|
|
142
|
+
},
|
|
143
|
+
],
|
|
144
|
+
directConnections: [
|
|
145
|
+
{
|
|
146
|
+
pinIds: ["C20.1", "U3.8"],
|
|
147
|
+
netId: "capacitor.C20 > port.pin1 to .U3 > .VDD",
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
pinIds: ["C20.2", "U3.4"],
|
|
151
|
+
netId: "capacitor.C20 > port.pin2 to .U3 > .GND",
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
pinIds: ["R11.2", "U3.1"],
|
|
155
|
+
netId: "resistor.R11 > port.pin2 to .U3 > .N_CS",
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
pinIds: ["R13.2", "R12.2"],
|
|
159
|
+
netId: "resistor.R11 > port.pin1 to resistor.R12 > port.pin1",
|
|
160
|
+
},
|
|
161
|
+
],
|
|
162
|
+
netConnections: [
|
|
163
|
+
{
|
|
164
|
+
netId: "V3_3",
|
|
165
|
+
pinIds: ["U3.8", "U3.3", "U3.7", "C20.1", "R11.1"],
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
netId: "GND",
|
|
169
|
+
pinIds: ["U3.4", "C20.2"],
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
netId: "FLASH_N_CS",
|
|
173
|
+
pinIds: ["U3.1", "R11.2"],
|
|
174
|
+
},
|
|
175
|
+
],
|
|
176
|
+
availableNetLabelOrientations: {
|
|
177
|
+
V3_3: ["y+"],
|
|
178
|
+
GND: ["y-"],
|
|
179
|
+
},
|
|
180
|
+
maxMspPairDistance: 5,
|
|
181
|
+
} as InputProblem
|
|
182
|
+
|
|
183
|
+
test("example14", () => {
|
|
184
|
+
const solver = new SchematicTracePipelineSolver(inputProblem)
|
|
185
|
+
solver.solve()
|
|
186
|
+
expect(solver).toMatchSolverSnapshot(import.meta.path)
|
|
187
|
+
})
|
package/tests/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver_repro03.test.ts
ADDED
|
File without changes
|