@tscircuit/schematic-trace-solver 0.0.118 → 0.0.119
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 +7 -1
- package/dist/index.js +135 -4
- package/lib/solvers/AvailableNetOrientationSolver/AvailableNetOrientationSolver.ts +200 -6
- package/lib/solvers/AvailableNetOrientationSolver/types.ts +2 -0
- package/package.json +1 -1
- package/tests/bug-reports/bug-report-20260721T221026Z/__snapshots__/bug-report-20260721T221026Z.snap.svg +3 -3
- package/tests/repros/__snapshots__/repro-power-group-rail-labels.snap.svg +58 -0
- package/tests/repros/__snapshots__/repro-rp2040-v3v3-label-placement.snap.svg +96 -0
- package/tests/repros/repro-power-group-rail-labels.test.ts +95 -0
- package/tests/repros/repro-rp2040-v3v3-label-placement.test.ts +102 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
<svg width="640" height="640" viewBox="0 0 640 640" xmlns="http://www.w3.org/2000/svg"><rect width="100%" height="100%" fill="white"/><g><polyline data-points="-1,0.5 -1,0.25" data-type="line" data-label="" points="189.74358974358972,229.74358974358975 189.74358974358972,281.02564102564105" fill="none" stroke="hsl(271, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="-1,0.5 -1,0" data-type="line" data-label="" points="189.74358974358972,229.74358974358975 189.74358974358972,332.3076923076923" fill="none" stroke="hsl(271, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="-1,0.25 -1,0" data-type="line" data-label="" points="189.74358974358972,281.02564102564105 189.74358974358972,332.3076923076923" fill="none" stroke="hsl(271, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="-1,-0.25 -1,-0.5" data-type="line" data-label="" points="189.74358974358972,383.5897435897436 189.74358974358972,434.8717948717949" fill="none" stroke="hsl(157, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="-1,0.25 -1.2,0.25 -1.2,0.5 -1,0.5" data-type="line" data-label="" points="189.74358974358972,281.02564102564105 148.7179487179487,281.02564102564105 148.7179487179487,229.74358974358975 189.74358974358972,229.74358974358975" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="-1,0 -1.2,0 -1.2,0.25 -1,0.25" data-type="line" data-label="" points="189.74358974358972,332.3076923076923 148.7179487179487,332.3076923076923 148.7179487179487,281.02564102564105 189.74358974358972,281.02564102564105" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="-1,-0.25 -1.2,-0.25 -1.2,-0.5 -1,-0.5" data-type="line" data-label="" points="189.74358974358972,383.5897435897436 148.7179487179487,383.5897435897436 148.7179487179487,434.8717948717949 189.74358974358972,434.8717948717949" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="-1.2,0.5 -1.49,0.5" data-type="line" data-label="" points="148.7179487179487,229.74358974358975 89.23076923076923,229.74358974358975" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="-1.2,-0.5 -1.49,-0.5" data-type="line" data-label="" points="148.7179487179487,434.8717948717949 89.23076923076923,434.8717948717949" fill="none" stroke="purple" stroke-width="1px"/></g><g><rect data-type="rect" data-label="U1" data-x="0" data-y="0" x="189.74358974358972" y="188.71794871794873" width="410.2564102564103" height="287.1794871794872" fill="hsl(164, 100%, 50%, 0.8)" stroke="black" stroke-width="0.004875"/></g><g><rect data-type="rect" data-label="U1 Power" data-x="-0.25" data-y="0.85" x="271.7948717948718" y="137.43589743589746" width="143.5897435897436" height="41.025641025640994" fill="rgba(160, 0, 220, 0.14)" stroke="black" stroke-width="0.004875"/></g><g><rect data-type="rect" data-label="netId: VBAT
|
|
2
|
+
globalConnNetId: connectivity_net0" data-x="-1.49" data-y="0.74" x="40" y="131.2820512820513" width="98.46153846153845" height="98.46153846153845" fill="#ef444466" stroke="#ef4444" stroke-width="0.004875"/></g><g><rect data-type="rect" data-label="netId: GND
|
|
3
|
+
globalConnNetId: connectivity_net1" data-x="-1.49" data-y="-0.6799999999999999" x="40" y="434.8717948717949" width="98.46153846153845" height="73.84615384615387" fill="#00000066" stroke="#000000" stroke-width="0.004875"/></g><g><circle data-type="point" data-label="U1.1
|
|
4
|
+
x-" data-x="-1" data-y="0.5" cx="189.74358974358972" cy="229.74358974358975" r="3" fill="hsl(319, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.2
|
|
5
|
+
x-" data-x="-1" data-y="0.25" cx="189.74358974358972" cy="281.02564102564105" r="3" fill="hsl(320, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.3
|
|
6
|
+
x-" data-x="-1" data-y="0" cx="189.74358974358972" cy="332.3076923076923" r="3" fill="hsl(321, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.4
|
|
7
|
+
x-" data-x="-1" data-y="-0.25" cx="189.74358974358972" cy="383.5897435897436" r="3" fill="hsl(322, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.5
|
|
8
|
+
x-" data-x="-1" data-y="-0.5" cx="189.74358974358972" cy="434.8717948717949" r="3" fill="hsl(323, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.6
|
|
9
|
+
x+" data-x="1" data-y="0.5" cx="600" cy="229.74358974358975" r="3" fill="hsl(324, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.7
|
|
10
|
+
x+" data-x="1" data-y="0.25" cx="600" cy="281.02564102564105" r="3" fill="hsl(325, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.8
|
|
11
|
+
x+" data-x="1" data-y="0" cx="600" cy="332.3076923076923" r="3" fill="hsl(326, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.9
|
|
12
|
+
x+" data-x="1" data-y="-0.25" cx="600" cy="383.5897435897436" r="3" fill="hsl(327, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.10
|
|
13
|
+
x+" data-x="1" data-y="-0.5" cx="600" cy="434.8717948717949" r="3" fill="hsl(217, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="anchorPoint
|
|
14
|
+
orientation: y+" data-x="-1.49" data-y="0.5" cx="89.23076923076923" cy="229.74358974358975" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g><circle data-type="point" data-label="anchorPoint
|
|
15
|
+
orientation: y-" data-x="-1.49" data-y="-0.5" cx="89.23076923076923" cy="434.8717948717949" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g id="crosshair" style="display: none"><line id="crosshair-h" y1="0" y2="640" stroke="#666" stroke-width="0.5"/><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></g><script><![CDATA[
|
|
16
|
+
document.currentScript.parentElement.addEventListener('mousemove', (e) => {
|
|
17
|
+
const svg = e.currentTarget;
|
|
18
|
+
const rect = svg.getBoundingClientRect();
|
|
19
|
+
const x = e.clientX - rect.left;
|
|
20
|
+
const y = e.clientY - rect.top;
|
|
21
|
+
const crosshair = svg.getElementById('crosshair');
|
|
22
|
+
const h = svg.getElementById('crosshair-h');
|
|
23
|
+
const v = svg.getElementById('crosshair-v');
|
|
24
|
+
const coords = svg.getElementById('coordinates');
|
|
25
|
+
|
|
26
|
+
crosshair.style.display = 'block';
|
|
27
|
+
h.setAttribute('x1', '0');
|
|
28
|
+
h.setAttribute('x2', '640');
|
|
29
|
+
h.setAttribute('y1', y);
|
|
30
|
+
h.setAttribute('y2', y);
|
|
31
|
+
v.setAttribute('x1', x);
|
|
32
|
+
v.setAttribute('x2', x);
|
|
33
|
+
v.setAttribute('y1', '0');
|
|
34
|
+
v.setAttribute('y2', '640');
|
|
35
|
+
|
|
36
|
+
// Calculate real coordinates using inverse transformation
|
|
37
|
+
const matrix = {"a":205.12820512820514,"c":0,"e":394.87179487179486,"b":0,"d":-205.12820512820514,"f":332.3076923076923};
|
|
38
|
+
// Manually invert and apply the affine transform
|
|
39
|
+
// Since we only use translate and scale, we can directly compute:
|
|
40
|
+
// x' = (x - tx) / sx
|
|
41
|
+
// y' = (y - ty) / sy
|
|
42
|
+
const sx = matrix.a;
|
|
43
|
+
const sy = matrix.d;
|
|
44
|
+
const tx = matrix.e;
|
|
45
|
+
const ty = matrix.f;
|
|
46
|
+
const realPoint = {
|
|
47
|
+
x: (x - tx) / sx,
|
|
48
|
+
y: (y - ty) / sy // Flip y back since we used negative scale
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
coords.textContent = `(${realPoint.x.toFixed(2)}, ${realPoint.y.toFixed(2)})`;
|
|
52
|
+
coords.setAttribute('x', (x + 5).toString());
|
|
53
|
+
coords.setAttribute('y', (y - 5).toString());
|
|
54
|
+
});
|
|
55
|
+
document.currentScript.parentElement.addEventListener('mouseleave', () => {
|
|
56
|
+
document.currentScript.parentElement.getElementById('crosshair').style.display = 'none';
|
|
57
|
+
});
|
|
58
|
+
]]></script></svg>
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
<svg width="640" height="640" viewBox="0 0 640 640" xmlns="http://www.w3.org/2000/svg"><rect width="100%" height="100%" fill="white"/><g><polyline data-points="-1.35,0.9999999999999998 -1.35,2.8" data-type="line" data-label="" points="198.84615384615384,241.02564102564105 198.84615384615384,79.48717948717953" fill="none" stroke="hsl(68, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="-1.35,0.9999999999999998 -1.35,-1.4000000000000004" data-type="line" data-label="" points="198.84615384615384,241.02564102564105 198.84615384615384,456.41025641025647" fill="none" stroke="hsl(68, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="-1.35,2.8 -1.35,-1.4000000000000004" data-type="line" data-label="" points="198.84615384615384,79.48717948717953 198.84615384615384,456.41025641025647" fill="none" stroke="hsl(68, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="1.35,0.9999999999999998 1.35,2.8" data-type="line" data-label="" points="441.1538461538462,241.02564102564105 441.1538461538462,79.48717948717953" fill="none" stroke="hsl(271, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="1.35,0.9999999999999998 1.35,-1.4000000000000004" data-type="line" data-label="" points="441.1538461538462,241.02564102564105 441.1538461538462,456.41025641025647" fill="none" stroke="hsl(271, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="1.35,2.8 1.35,-1.4000000000000004" data-type="line" data-label="" points="441.1538461538462,79.48717948717953 441.1538461538462,456.41025641025647" fill="none" stroke="hsl(271, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="-1.35,0.9999999999999998 -1.55,0.9999999999999998 -1.55,2.8 -1.35,2.8" data-type="line" data-label="" points="198.84615384615384,241.02564102564105 180.8974358974359,241.02564102564105 180.8974358974359,79.48717948717953 198.84615384615384,79.48717948717953" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="1.35,0.9999999999999998 1.55,0.9999999999999998 1.55,2.8 1.35,2.8" data-type="line" data-label="" points="441.1538461538462,241.02564102564105 459.1025641025641,241.02564102564105 459.1025641025641,79.48717948717953 441.1538461538462,79.48717948717953" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="-1.55,2.8 -1.9000000000000001,2.8" data-type="line" data-label="" points="180.8974358974359,79.48717948717953 149.48717948717947,79.48717948717953" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="-1.35,-1.4000000000000004 -1.701,-1.4000000000000004 -1.701,-1.3490000000000004" data-type="line" data-label="" points="198.84615384615384,456.41025641025647 167.34615384615384,456.41025641025647 167.34615384615384,451.83333333333337" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="1.55,2.8 1.9000000000000001,2.8" data-type="line" data-label="" points="459.1025641025641,79.48717948717953 490.51282051282055,79.48717948717953" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="1.35,-1.4000000000000004 1.701,-1.4000000000000004 1.701,-1.3490000000000004" data-type="line" data-label="" points="441.1538461538462,456.41025641025647 472.6538461538462,456.41025641025647 472.6538461538462,451.83333333333337" fill="none" stroke="purple" stroke-width="1px"/></g><g><rect data-type="rect" data-label="U1" data-x="0" data-y="0" x="198.8461538461538" y="61.53846153846155" width="242.30769230769235" height="538.4615384615385" fill="hsl(164, 100%, 50%, 0.8)" stroke="black" stroke-width="0.011142857142857144"/></g><g><rect data-type="rect" data-label="U1" data-x="-0.83" data-y="3.115" x="229.35897435897436" y="40" width="32.30769230769232" height="22.43589743589746" fill="rgba(160, 0, 220, 0.14)" stroke="black" stroke-width="0.011142857142857144"/></g><g><rect data-type="rect" data-label="netId: V3V3_LEFT
|
|
2
|
+
globalConnNetId: connectivity_net0" data-x="-1.9000000000000001" data-y="3.01" x="122.56410256410255" y="41.79487179487184" width="53.84615384615384" height="37.69230769230771" fill="#ef444466" stroke="#ef4444" stroke-width="0.011142857142857144"/></g><g><rect data-type="rect" data-label="netId: V3V3_LEFT
|
|
3
|
+
globalConnNetId: connectivity_net0" data-x="-1.701" data-y="-1.1390000000000005" x="140.4230769230769" y="414.14102564102575" width="53.84615384615384" height="37.69230769230768" fill="#ef444466" stroke="#ef4444" stroke-width="0.011142857142857144"/></g><g><rect data-type="rect" data-label="netId: V3V3_RIGHT
|
|
4
|
+
globalConnNetId: connectivity_net1" data-x="1.9000000000000001" data-y="3.01" x="463.58974358974365" y="41.79487179487184" width="53.84615384615387" height="37.69230769230771" fill="#ef444466" stroke="#ef4444" stroke-width="0.011142857142857144"/></g><g><rect data-type="rect" data-label="netId: V3V3_RIGHT
|
|
5
|
+
globalConnNetId: connectivity_net1" data-x="1.701" data-y="-1.1390000000000005" x="445.7307692307693" y="414.14102564102575" width="53.84615384615387" height="37.69230769230768" fill="#ef444466" stroke="#ef4444" stroke-width="0.011142857142857144"/></g><g><circle data-type="point" data-label="U1.left.1
|
|
6
|
+
x-" data-x="-1.35" data-y="2.8" cx="198.84615384615384" cy="79.48717948717953" r="3" fill="hsl(12, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.left.2
|
|
7
|
+
x-" data-x="-1.35" data-y="2.5999999999999996" cx="198.84615384615384" cy="97.43589743589749" r="3" fill="hsl(13, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.left.3
|
|
8
|
+
x-" data-x="-1.35" data-y="2.4" cx="198.84615384615384" cy="115.38461538461542" r="3" fill="hsl(14, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.left.4
|
|
9
|
+
x-" data-x="-1.35" data-y="2.1999999999999997" cx="198.84615384615384" cy="133.33333333333337" r="3" fill="hsl(15, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.left.5
|
|
10
|
+
x-" data-x="-1.35" data-y="1.9999999999999998" cx="198.84615384615384" cy="151.28205128205133" r="3" fill="hsl(16, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.left.6
|
|
11
|
+
x-" data-x="-1.35" data-y="1.7999999999999998" cx="198.84615384615384" cy="169.23076923076925" r="3" fill="hsl(17, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.left.7
|
|
12
|
+
x-" data-x="-1.35" data-y="1.5999999999999996" cx="198.84615384615384" cy="187.17948717948724" r="3" fill="hsl(18, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.left.8
|
|
13
|
+
x-" data-x="-1.35" data-y="1.3999999999999997" cx="198.84615384615384" cy="205.12820512820517" r="3" fill="hsl(19, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.left.9
|
|
14
|
+
x-" data-x="-1.35" data-y="1.1999999999999997" cx="198.84615384615384" cy="223.0769230769231" r="3" fill="hsl(20, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.left.10
|
|
15
|
+
x-" data-x="-1.35" data-y="0.9999999999999998" cx="198.84615384615384" cy="241.02564102564105" r="3" fill="hsl(60, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.left.11
|
|
16
|
+
x-" data-x="-1.35" data-y="0.7999999999999998" cx="198.84615384615384" cy="258.974358974359" r="3" fill="hsl(61, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.left.12
|
|
17
|
+
x-" data-x="-1.35" data-y="0.5999999999999996" cx="198.84615384615384" cy="276.92307692307696" r="3" fill="hsl(62, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.left.13
|
|
18
|
+
x-" data-x="-1.35" data-y="0.39999999999999947" cx="198.84615384615384" cy="294.8717948717949" r="3" fill="hsl(63, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.left.14
|
|
19
|
+
x-" data-x="-1.35" data-y="0.19999999999999973" cx="198.84615384615384" cy="312.8205128205129" r="3" fill="hsl(64, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.left.15
|
|
20
|
+
x-" data-x="-1.35" data-y="-4.440892098500626e-16" cx="198.84615384615384" cy="330.76923076923083" r="3" fill="hsl(65, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.left.16
|
|
21
|
+
x-" data-x="-1.35" data-y="-0.20000000000000018" cx="198.84615384615384" cy="348.71794871794873" r="3" fill="hsl(66, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.left.17
|
|
22
|
+
x-" data-x="-1.35" data-y="-0.40000000000000036" cx="198.84615384615384" cy="366.6666666666667" r="3" fill="hsl(67, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.left.18
|
|
23
|
+
x-" data-x="-1.35" data-y="-0.6000000000000005" cx="198.84615384615384" cy="384.61538461538464" r="3" fill="hsl(68, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.left.19
|
|
24
|
+
x-" data-x="-1.35" data-y="-0.8000000000000003" cx="198.84615384615384" cy="402.5641025641026" r="3" fill="hsl(69, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.left.20
|
|
25
|
+
x-" data-x="-1.35" data-y="-1.0000000000000004" cx="198.84615384615384" cy="420.51282051282055" r="3" fill="hsl(91, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.left.21
|
|
26
|
+
x-" data-x="-1.35" data-y="-1.2000000000000002" cx="198.84615384615384" cy="438.46153846153845" r="3" fill="hsl(92, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.left.22
|
|
27
|
+
x-" data-x="-1.35" data-y="-1.4000000000000004" cx="198.84615384615384" cy="456.41025641025647" r="3" fill="hsl(93, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.right.1
|
|
28
|
+
x+" data-x="1.35" data-y="2.8" cx="441.1538461538462" cy="79.48717948717953" r="3" fill="hsl(277, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.right.2
|
|
29
|
+
x+" data-x="1.35" data-y="2.5999999999999996" cx="441.1538461538462" cy="97.43589743589749" r="3" fill="hsl(278, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.right.3
|
|
30
|
+
x+" data-x="1.35" data-y="2.4" cx="441.1538461538462" cy="115.38461538461542" r="3" fill="hsl(279, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.right.4
|
|
31
|
+
x+" data-x="1.35" data-y="2.1999999999999997" cx="441.1538461538462" cy="133.33333333333337" r="3" fill="hsl(280, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.right.5
|
|
32
|
+
x+" data-x="1.35" data-y="1.9999999999999998" cx="441.1538461538462" cy="151.28205128205133" r="3" fill="hsl(281, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.right.6
|
|
33
|
+
x+" data-x="1.35" data-y="1.7999999999999998" cx="441.1538461538462" cy="169.23076923076925" r="3" fill="hsl(282, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.right.7
|
|
34
|
+
x+" data-x="1.35" data-y="1.5999999999999996" cx="441.1538461538462" cy="187.17948717948724" r="3" fill="hsl(283, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.right.8
|
|
35
|
+
x+" data-x="1.35" data-y="1.3999999999999997" cx="441.1538461538462" cy="205.12820512820517" r="3" fill="hsl(284, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.right.9
|
|
36
|
+
x+" data-x="1.35" data-y="1.1999999999999997" cx="441.1538461538462" cy="223.0769230769231" r="3" fill="hsl(285, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.right.10
|
|
37
|
+
x+" data-x="1.35" data-y="0.9999999999999998" cx="441.1538461538462" cy="241.02564102564105" r="3" fill="hsl(352, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.right.11
|
|
38
|
+
x+" data-x="1.35" data-y="0.7999999999999998" cx="441.1538461538462" cy="258.974358974359" r="3" fill="hsl(352, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.right.12
|
|
39
|
+
x+" data-x="1.35" data-y="0.5999999999999996" cx="441.1538461538462" cy="276.92307692307696" r="3" fill="hsl(352, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.right.13
|
|
40
|
+
x+" data-x="1.35" data-y="0.39999999999999947" cx="441.1538461538462" cy="294.8717948717949" r="3" fill="hsl(352, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.right.14
|
|
41
|
+
x+" data-x="1.35" data-y="0.19999999999999973" cx="441.1538461538462" cy="312.8205128205129" r="3" fill="hsl(352, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.right.15
|
|
42
|
+
x+" data-x="1.35" data-y="-4.440892098500626e-16" cx="441.1538461538462" cy="330.76923076923083" r="3" fill="hsl(0, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.right.16
|
|
43
|
+
x+" data-x="1.35" data-y="-0.20000000000000018" cx="441.1538461538462" cy="348.71794871794873" r="3" fill="hsl(0, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.right.17
|
|
44
|
+
x+" data-x="1.35" data-y="-0.40000000000000036" cx="441.1538461538462" cy="366.6666666666667" r="3" fill="hsl(0, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.right.18
|
|
45
|
+
x+" data-x="1.35" data-y="-0.6000000000000005" cx="441.1538461538462" cy="384.61538461538464" r="3" fill="hsl(0, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.right.19
|
|
46
|
+
x+" data-x="1.35" data-y="-0.8000000000000003" cx="441.1538461538462" cy="402.5641025641026" r="3" fill="hsl(0, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.right.20
|
|
47
|
+
x+" data-x="1.35" data-y="-1.0000000000000004" cx="441.1538461538462" cy="420.51282051282055" r="3" fill="hsl(24, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.right.21
|
|
48
|
+
x+" data-x="1.35" data-y="-1.2000000000000002" cx="441.1538461538462" cy="438.46153846153845" r="3" fill="hsl(24, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.right.22
|
|
49
|
+
x+" data-x="1.35" data-y="-1.4000000000000004" cx="441.1538461538462" cy="456.41025641025647" r="3" fill="hsl(24, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="anchorPoint
|
|
50
|
+
orientation: y+" data-x="-1.9000000000000001" data-y="2.8" cx="149.48717948717947" cy="79.48717948717953" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g><circle data-type="point" data-label="anchorPoint
|
|
51
|
+
orientation: y+" data-x="-1.701" data-y="-1.3490000000000004" cx="167.34615384615384" cy="451.83333333333337" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g><circle data-type="point" data-label="anchorPoint
|
|
52
|
+
orientation: y+" data-x="1.9000000000000001" data-y="2.8" cx="490.51282051282055" cy="79.48717948717953" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g><circle data-type="point" data-label="anchorPoint
|
|
53
|
+
orientation: y+" data-x="1.701" data-y="-1.3490000000000004" cx="472.6538461538462" cy="451.83333333333337" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g id="crosshair" style="display: none"><line id="crosshair-h" y1="0" y2="640" stroke="#666" stroke-width="0.5"/><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></g><script><![CDATA[
|
|
54
|
+
document.currentScript.parentElement.addEventListener('mousemove', (e) => {
|
|
55
|
+
const svg = e.currentTarget;
|
|
56
|
+
const rect = svg.getBoundingClientRect();
|
|
57
|
+
const x = e.clientX - rect.left;
|
|
58
|
+
const y = e.clientY - rect.top;
|
|
59
|
+
const crosshair = svg.getElementById('crosshair');
|
|
60
|
+
const h = svg.getElementById('crosshair-h');
|
|
61
|
+
const v = svg.getElementById('crosshair-v');
|
|
62
|
+
const coords = svg.getElementById('coordinates');
|
|
63
|
+
|
|
64
|
+
crosshair.style.display = 'block';
|
|
65
|
+
h.setAttribute('x1', '0');
|
|
66
|
+
h.setAttribute('x2', '640');
|
|
67
|
+
h.setAttribute('y1', y);
|
|
68
|
+
h.setAttribute('y2', y);
|
|
69
|
+
v.setAttribute('x1', x);
|
|
70
|
+
v.setAttribute('x2', x);
|
|
71
|
+
v.setAttribute('y1', '0');
|
|
72
|
+
v.setAttribute('y2', '640');
|
|
73
|
+
|
|
74
|
+
// Calculate real coordinates using inverse transformation
|
|
75
|
+
const matrix = {"a":89.74358974358974,"c":0,"e":320,"b":0,"d":-89.74358974358974,"f":330.7692307692308};
|
|
76
|
+
// Manually invert and apply the affine transform
|
|
77
|
+
// Since we only use translate and scale, we can directly compute:
|
|
78
|
+
// x' = (x - tx) / sx
|
|
79
|
+
// y' = (y - ty) / sy
|
|
80
|
+
const sx = matrix.a;
|
|
81
|
+
const sy = matrix.d;
|
|
82
|
+
const tx = matrix.e;
|
|
83
|
+
const ty = matrix.f;
|
|
84
|
+
const realPoint = {
|
|
85
|
+
x: (x - tx) / sx,
|
|
86
|
+
y: (y - ty) / sy // Flip y back since we used negative scale
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
coords.textContent = `(${realPoint.x.toFixed(2)}, ${realPoint.y.toFixed(2)})`;
|
|
90
|
+
coords.setAttribute('x', (x + 5).toString());
|
|
91
|
+
coords.setAttribute('y', (y - 5).toString());
|
|
92
|
+
});
|
|
93
|
+
document.currentScript.parentElement.addEventListener('mouseleave', () => {
|
|
94
|
+
document.currentScript.parentElement.getElementById('crosshair').style.display = 'none';
|
|
95
|
+
});
|
|
96
|
+
]]></script></svg>
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { expect, test } from "bun:test"
|
|
2
|
+
import { SchematicTracePipelineSolver } from "lib/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver"
|
|
3
|
+
import type { InputProblem } from "lib/types/InputProblem"
|
|
4
|
+
import "tests/fixtures/matcher"
|
|
5
|
+
|
|
6
|
+
const inputProblem: InputProblem = {
|
|
7
|
+
chips: [
|
|
8
|
+
{
|
|
9
|
+
chipId: "U1",
|
|
10
|
+
center: { x: 0, y: 0 },
|
|
11
|
+
width: 2,
|
|
12
|
+
height: 1.4,
|
|
13
|
+
pins: [
|
|
14
|
+
...[0.5, 0.25, 0, -0.25, -0.5].map((y, index) => ({
|
|
15
|
+
pinId: `U1.${index + 1}`,
|
|
16
|
+
x: -1,
|
|
17
|
+
y,
|
|
18
|
+
_facingDirection: "x-" as const,
|
|
19
|
+
})),
|
|
20
|
+
...[0.5, 0.25, 0, -0.25, -0.5].map((y, index) => ({
|
|
21
|
+
pinId: `U1.${index + 6}`,
|
|
22
|
+
x: 1,
|
|
23
|
+
y,
|
|
24
|
+
_facingDirection: "x+" as const,
|
|
25
|
+
})),
|
|
26
|
+
],
|
|
27
|
+
},
|
|
28
|
+
],
|
|
29
|
+
directConnections: [],
|
|
30
|
+
netConnections: [
|
|
31
|
+
{
|
|
32
|
+
netId: "VBAT",
|
|
33
|
+
pinIds: ["U1.1", "U1.2", "U1.3"],
|
|
34
|
+
netLabelWidth: 0.48,
|
|
35
|
+
netLabelHeight: 0.48,
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
netId: "GND",
|
|
39
|
+
pinIds: ["U1.4", "U1.5"],
|
|
40
|
+
netLabelWidth: 0.36,
|
|
41
|
+
netLabelHeight: 0.48,
|
|
42
|
+
},
|
|
43
|
+
],
|
|
44
|
+
textBoxes: [
|
|
45
|
+
{
|
|
46
|
+
chipId: "U1",
|
|
47
|
+
center: { x: -0.25, y: 0.85 },
|
|
48
|
+
width: 0.7,
|
|
49
|
+
height: 0.2,
|
|
50
|
+
text: "U1 Power",
|
|
51
|
+
},
|
|
52
|
+
],
|
|
53
|
+
availableNetLabelOrientations: {
|
|
54
|
+
VBAT: ["y+"],
|
|
55
|
+
GND: ["y-"],
|
|
56
|
+
},
|
|
57
|
+
maxMspPairDistance: 2.4,
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
test("places same-side VBAT and GND labels at opposite rail ends", () => {
|
|
61
|
+
const solver = new SchematicTracePipelineSolver(inputProblem)
|
|
62
|
+
|
|
63
|
+
solver.solve()
|
|
64
|
+
|
|
65
|
+
const outputLabels =
|
|
66
|
+
solver.netLabelNetLabelCollisionSolver!.getOutput().netLabelPlacements
|
|
67
|
+
const u1 = solver.inputProblem.chips.find((chip) => chip.chipId === "U1")!
|
|
68
|
+
const chipLeft = u1.center.x - u1.width / 2
|
|
69
|
+
|
|
70
|
+
for (const expected of [
|
|
71
|
+
{ netId: "VBAT", orientation: "y+" as const, anchorY: 0.5 },
|
|
72
|
+
{ netId: "GND", orientation: "y-" as const, anchorY: -0.5 },
|
|
73
|
+
]) {
|
|
74
|
+
const label = outputLabels.find(
|
|
75
|
+
(candidate) => candidate.netId === expected.netId,
|
|
76
|
+
)!
|
|
77
|
+
const connector = solver.availableNetOrientationSolver!.traces.find(
|
|
78
|
+
(trace) =>
|
|
79
|
+
trace.userNetId === expected.netId &&
|
|
80
|
+
trace.mspPairId.startsWith("available-net-orientation-"),
|
|
81
|
+
)!
|
|
82
|
+
const [connectorSource, connectorTarget] = connector.tracePath
|
|
83
|
+
const labelRight = label.center.x + label.width / 2
|
|
84
|
+
|
|
85
|
+
expect(label.orientation).toBe(expected.orientation)
|
|
86
|
+
expect(label.anchorPoint.y).toBeCloseTo(expected.anchorY)
|
|
87
|
+
expect(labelRight).toBeLessThan(chipLeft)
|
|
88
|
+
expect(connector.tracePath).toHaveLength(2)
|
|
89
|
+
expect(connectorSource!.y).toBeCloseTo(connectorTarget!.y)
|
|
90
|
+
expect(connectorTarget!.x).toBeLessThan(connectorSource!.x)
|
|
91
|
+
expect(connectorSource!.x - connectorTarget!.x).toBeLessThan(0.5)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
expect(solver).toMatchSolverSnapshot(import.meta.path)
|
|
95
|
+
})
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { expect, test } from "bun:test"
|
|
2
|
+
import { SchematicTracePipelineSolver } from "lib/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver"
|
|
3
|
+
import type { InputProblem } from "lib/types/InputProblem"
|
|
4
|
+
import "tests/fixtures/matcher"
|
|
5
|
+
|
|
6
|
+
const createRp2040SidePins = (side: "left" | "right") =>
|
|
7
|
+
Array.from({ length: 22 }, (_, index) => ({
|
|
8
|
+
pinId: `U1.${side}.${index + 1}`,
|
|
9
|
+
x: side === "left" ? -1.35 : 1.35,
|
|
10
|
+
y: 2.8 - index * 0.2,
|
|
11
|
+
_facingDirection: side === "left" ? ("x-" as const) : ("x+" as const),
|
|
12
|
+
}))
|
|
13
|
+
|
|
14
|
+
// Reduced from the current @tscircuit/core input for an RP2040, then mirrored
|
|
15
|
+
// to cover both chip sides. The important details are the 0.2-unit pin pitch,
|
|
16
|
+
// 0.6-unit rail-label height, and a third distance-split member on each net.
|
|
17
|
+
// The reversed first pair preserves the MSP direction produced by the original
|
|
18
|
+
// multi-pin input (pin 10 to pin 1).
|
|
19
|
+
const inputProblem: InputProblem = {
|
|
20
|
+
chips: [
|
|
21
|
+
{
|
|
22
|
+
chipId: "U1",
|
|
23
|
+
center: { x: 0, y: 0 },
|
|
24
|
+
width: 1.9,
|
|
25
|
+
height: 6,
|
|
26
|
+
pins: [...createRp2040SidePins("left"), ...createRp2040SidePins("right")],
|
|
27
|
+
},
|
|
28
|
+
],
|
|
29
|
+
directConnections: [],
|
|
30
|
+
netConnections: [
|
|
31
|
+
{
|
|
32
|
+
netId: "V3V3_LEFT",
|
|
33
|
+
pinIds: ["U1.left.10", "U1.left.1", "U1.left.22"],
|
|
34
|
+
netLabelWidth: 0.42,
|
|
35
|
+
netLabelHeight: 0.6,
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
netId: "V3V3_RIGHT",
|
|
39
|
+
pinIds: ["U1.right.10", "U1.right.1", "U1.right.22"],
|
|
40
|
+
netLabelWidth: 0.42,
|
|
41
|
+
netLabelHeight: 0.6,
|
|
42
|
+
},
|
|
43
|
+
],
|
|
44
|
+
textBoxes: [
|
|
45
|
+
{
|
|
46
|
+
chipId: "U1",
|
|
47
|
+
center: { x: -0.83, y: 3.115 },
|
|
48
|
+
width: 0.36,
|
|
49
|
+
height: 0.25,
|
|
50
|
+
text: "U1",
|
|
51
|
+
},
|
|
52
|
+
],
|
|
53
|
+
availableNetLabelOrientations: {
|
|
54
|
+
V3V3_LEFT: ["y+"],
|
|
55
|
+
V3V3_RIGHT: ["y+"],
|
|
56
|
+
},
|
|
57
|
+
maxMspPairDistance: 2.4,
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
test("places RP2040 rail labels above and outside both chip sides", () => {
|
|
61
|
+
const solver = new SchematicTracePipelineSolver(inputProblem)
|
|
62
|
+
|
|
63
|
+
solver.solve()
|
|
64
|
+
|
|
65
|
+
const outputLabels =
|
|
66
|
+
solver.netLabelNetLabelCollisionSolver!.getOutput().netLabelPlacements
|
|
67
|
+
const u1 = solver.inputProblem.chips.find((chip) => chip.chipId === "U1")!
|
|
68
|
+
const chipLeft = u1.center.x - u1.width / 2
|
|
69
|
+
const chipRight = u1.center.x + u1.width / 2
|
|
70
|
+
|
|
71
|
+
for (const side of ["left", "right"] as const) {
|
|
72
|
+
const netId = `V3V3_${side.toUpperCase()}`
|
|
73
|
+
const label = outputLabels.find(
|
|
74
|
+
(candidate) =>
|
|
75
|
+
candidate.netId === netId && candidate.pinIds.includes(`U1.${side}.1`),
|
|
76
|
+
)!
|
|
77
|
+
const connector = solver.availableNetOrientationSolver!.traces.find(
|
|
78
|
+
(trace) =>
|
|
79
|
+
trace.userNetId === netId &&
|
|
80
|
+
trace.mspPairId.startsWith("available-net-orientation-"),
|
|
81
|
+
)!
|
|
82
|
+
const [connectorSource, connectorTarget] = connector.tracePath
|
|
83
|
+
const labelLeft = label.center.x - label.width / 2
|
|
84
|
+
const labelRight = label.center.x + label.width / 2
|
|
85
|
+
|
|
86
|
+
expect(label.orientation).toBe("y+")
|
|
87
|
+
expect(label.anchorPoint.y).toBeCloseTo(2.8)
|
|
88
|
+
expect(connector.tracePath).toHaveLength(2)
|
|
89
|
+
expect(connectorSource!.y).toBeCloseTo(connectorTarget!.y)
|
|
90
|
+
expect(Math.abs(connectorSource!.x - connectorTarget!.x)).toBeLessThan(0.5)
|
|
91
|
+
|
|
92
|
+
if (side === "left") {
|
|
93
|
+
expect(labelRight).toBeLessThan(chipLeft)
|
|
94
|
+
expect(connectorTarget!.x).toBeLessThan(connectorSource!.x)
|
|
95
|
+
} else {
|
|
96
|
+
expect(labelLeft).toBeGreaterThan(chipRight)
|
|
97
|
+
expect(connectorTarget!.x).toBeGreaterThan(connectorSource!.x)
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
expect(solver).toMatchSolverSnapshot(import.meta.path)
|
|
102
|
+
})
|