@tscircuit/schematic-trace-solver 0.0.145 → 0.0.147
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 +9 -2
- package/dist/index.js +482 -86
- package/lib/solvers/AvailableNetOrientationSolver/AvailableNetOrientationSolver.ts +38 -30
- package/lib/solvers/InlineNetLabelSolver/InlineNetLabelSolver.ts +30 -8
- package/lib/solvers/InlineNetLabelSolver/pushAnchoredNetLabelsAwayFromInlineLabels.ts +530 -0
- package/lib/solvers/NetLabelPlacementSolver/NetLabelPlacementSolver.ts +6 -21
- package/lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver2/SchematicTraceSingleLineSolver2.ts +7 -23
- package/lib/solvers/TraceAnchoredNetLabelOverlapSolver/candidates.ts +7 -14
- package/lib/types/InputProblem.ts +8 -0
- package/lib/utils/getNetLabelWidthForConnection.ts +63 -0
- package/package.json +1 -1
- package/tests/assets/inline-net-label-anchored-label-clearance.json +56 -0
- package/tests/repros/__snapshots__/repro-ti-power-output-section.snap.svg +80 -0
- package/tests/repros/repro-ti-power-output-section.input.ts +341 -0
- package/tests/repros/repro-ti-power-output-section.test.ts +13 -0
- package/tests/solvers/InlineNetLabelSolver/__snapshots__/fallback-net-label-width.snap.svg +69 -0
- package/tests/solvers/InlineNetLabelSolver/__snapshots__/inline-net-label-anchored-label-clearance.snap.svg +54 -0
- package/tests/solvers/InlineNetLabelSolver/fallback-net-label-width.test.ts +152 -0
- package/tests/solvers/InlineNetLabelSolver/inline-net-label-anchored-label-clearance.test.ts +28 -0
- package/tests/solvers/InlineNetLabelSolver/push-anchored-net-labels-away.test.ts +227 -0
|
@@ -0,0 +1,69 @@
|
|
|
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="5.575,1.4 2.045,2.6" data-type="line" data-label="" points="447.56446991404016,256.8863419293219 258.75835721107927,192.70296084049664" fill="none" stroke="hsl(193, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="5.575,1.2 2.045,2.4" data-type="line" data-label="" points="447.56446991404016,267.5835721107927 258.75835721107927,203.40019102196752" fill="none" stroke="hsl(191, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="5.575,1 2.045,2.2" data-type="line" data-label="" points="447.56446991404016,278.2808022922636 258.75835721107927,214.0974212034384" fill="none" stroke="hsl(72, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="5.575,0.8 2.045,2" data-type="line" data-label="" points="447.56446991404016,288.97803247373446 258.75835721107927,224.79465138490926" fill="none" stroke="hsl(74, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="5.575,0.6 2.045,0.7" data-type="line" data-label="" points="447.56446991404016,299.67526265520536 258.75835721107927,294.3266475644699" fill="none" stroke="hsl(184, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="5.575,1.4 5.375,1.4 5.375,2.6 2.045,2.6" data-type="line" data-label="" points="447.56446991404016,256.8863419293219 436.86723973256926,256.8863419293219 436.86723973256926,192.70296084049664 258.75835721107927,192.70296084049664" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="5.575,1.2 3.81,1.2 3.81,2.4 2.045,2.4" data-type="line" data-label="" points="447.56446991404016,267.5835721107927 353.1614135625597,267.5835721107927 353.1614135625597,203.40019102196752 258.75835721107927,203.40019102196752" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="5.575,1 3.71,1 3.71,2.2 2.045,2.2" data-type="line" data-label="" points="447.56446991404016,278.2808022922636 347.81279847182424,278.2808022922636 347.81279847182424,214.0974212034384 258.75835721107927,214.0974212034384" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="5.575,0.8 2.245,0.8 2.245,2 2.045,2" data-type="line" data-label="" points="447.56446991404016,288.97803247373446 269.4555873925501,288.97803247373446 269.4555873925501,224.79465138490926 258.75835721107927,224.79465138490926" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="5.575,0.6 3.81,0.6 3.81,0.7 2.045,0.7" data-type="line" data-label="" points="447.56446991404016,299.67526265520536 353.1614135625597,299.67526265520536 353.1614135625597,294.3266475644699 258.75835721107927,294.3266475644699" fill="none" stroke="purple" stroke-width="1px"/></g><g><rect data-type="rect" data-label="U1" data-x="0" data-y="0" x="40" y="161.9484240687679" width="218.75835721107927" height="339.6370582617001" fill="hsl(164, 100%, 50%, 0.8)" stroke="black" stroke-width="0.018696428571428572"/></g><g><rect data-type="rect" data-label="J4" data-x="7" data-y="-0.4" x="447.5644699140401" y="246.189111747851" width="152.43553008595984" height="213.94460362941737" fill="hsl(186, 100%, 50%, 0.8)" stroke="black" stroke-width="0.018696428571428572"/></g><g><rect data-type="rect" data-label="TB67S579FTG" data-x="2.405" data-y="3.525" x="242.71251193887292" y="138.41451766953202" width="70.60171919770775" height="9.627507163323742" fill="rgba(160, 0, 220, 0.14)" stroke="black" stroke-width="0.018696428571428572"/></g><g><rect data-type="rect" data-label="U1" data-x="1.865" data-y="3.29" x="239.50334288443167" y="149.11174785100286" width="19.25501432664757" height="13.371537726838596" fill="rgba(160, 0, 220, 0.14)" stroke="black" stroke-width="0.018696428571428572"/></g><g><rect data-type="rect" data-label="J4" data-x="6.095" data-y="1.715" x="465.74976122254054" y="233.35243553008593" width="19.255014326647597" height="13.371537726838568" fill="rgba(160, 0, 220, 0.14)" stroke="black" stroke-width="0.018696428571428572"/></g><g><rect data-type="rect" data-label="INLINE netId: OUT_A_P
|
|
2
|
+
axis: x
|
|
3
|
+
side: y+" data-x="3.71" data-y="2.71" x="330.69723018147084" y="183.6103151862464" width="34.23113658070679" height="6.418338108882523" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.018696428571428572"/></g><g><rect data-type="rect" data-label="INLINE netId: OUT_A_N
|
|
4
|
+
axis: x
|
|
5
|
+
side: y+" data-x="4.6925" data-y="1.31" x="383.24737344794653" y="258.4909264565425" width="34.231136580706846" height="6.418338108882551" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.018696428571428572"/></g><g><rect data-type="rect" data-label="INLINE netId: OUT_B_N
|
|
6
|
+
axis: x
|
|
7
|
+
side: y+" data-x="4.6425" data-y="1.11" x="380.5730659025787" y="269.18815663801337" width="34.231136580706846" height="6.4183381088824945" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.018696428571428572"/></g><g><rect data-type="rect" data-label="INLINE netId: OUT_B_P
|
|
8
|
+
axis: x
|
|
9
|
+
side: y+" data-x="3.91" data-y="0.91" x="341.39446036294174" y="279.8853868194842" width="34.23113658070679" height="6.418338108882551" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.018696428571428572"/></g><g><rect data-type="rect" data-label="INLINE netId: SERIAL_IN
|
|
10
|
+
axis: x
|
|
11
|
+
side: y+" data-x="4.6925" data-y="0.71" x="378.9684813753582" y="290.5826170009551" width="42.788920725883486" height="6.4183381088824945" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.018696428571428572"/></g><text data-type="text" data-label="OUT_A_P" data-x="3.71" data-y="2.71" x="347.81279847182424" y="186.81948424068767" fill="green" font-size="6.418338108882521" font-family="sans-serif" text-anchor="middle" dominant-baseline="central">OUT_A_P</text><text data-type="text" data-label="OUT_A_N" data-x="4.6925" data-y="1.31" x="400.3629417382999" y="261.7000955109838" fill="green" font-size="6.418338108882521" font-family="sans-serif" text-anchor="middle" dominant-baseline="central">OUT_A_N</text><text data-type="text" data-label="OUT_B_N" data-x="4.6425" data-y="1.11" x="397.68863419293217" y="272.3973256924546" fill="green" font-size="6.418338108882521" font-family="sans-serif" text-anchor="middle" dominant-baseline="central">OUT_B_N</text><text data-type="text" data-label="OUT_B_P" data-x="3.91" data-y="0.91" x="358.51002865329514" y="283.0945558739255" fill="green" font-size="6.418338108882521" font-family="sans-serif" text-anchor="middle" dominant-baseline="central">OUT_B_P</text><text data-type="text" data-label="SERIAL_IN" data-x="4.6925" data-y="0.71" x="400.3629417382999" y="293.79178605539636" fill="green" font-size="6.418338108882521" font-family="sans-serif" text-anchor="middle" dominant-baseline="central">SERIAL_IN</text><g><circle data-type="point" data-label="U1.4
|
|
12
|
+
x+" data-x="2.045" data-y="2.6" cx="258.75835721107927" cy="192.70296084049664" r="3" fill="hsl(322, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.6
|
|
13
|
+
x+" data-x="2.045" data-y="2.4" cx="258.75835721107927" cy="203.40019102196752" r="3" fill="hsl(324, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.7
|
|
14
|
+
x+" data-x="2.045" data-y="2.2" cx="258.75835721107927" cy="214.0974212034384" r="3" fill="hsl(325, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.9
|
|
15
|
+
x+" data-x="2.045" data-y="2" cx="258.75835721107927" cy="224.79465138490926" r="3" fill="hsl(327, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.48
|
|
16
|
+
x+" data-x="2.045" data-y="0.7" cx="258.75835721107927" cy="294.3266475644699" r="3" fill="hsl(318, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="J4.1
|
|
17
|
+
x-" data-x="5.575" data-y="1.4" cx="447.56446991404016" cy="256.8863419293219" r="3" fill="hsl(221, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="J4.2
|
|
18
|
+
x-" data-x="5.575" data-y="1.2" cx="447.56446991404016" cy="267.5835721107927" r="3" fill="hsl(222, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="J4.3
|
|
19
|
+
x-" data-x="5.575" data-y="1" cx="447.56446991404016" cy="278.2808022922636" r="3" fill="hsl(223, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="J4.4
|
|
20
|
+
x-" data-x="5.575" data-y="0.8" cx="447.56446991404016" cy="288.97803247373446" r="3" fill="hsl(224, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="J4.5
|
|
21
|
+
x-" data-x="5.575" data-y="0.6" cx="447.56446991404016" cy="299.67526265520536" r="3" fill="hsl(225, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="inline anchor
|
|
22
|
+
OUT_A_P" data-x="3.71" data-y="2.6" cx="347.81279847182424" cy="192.70296084049664" r="3" fill="green"/></g><g><circle data-type="point" data-label="inline anchor
|
|
23
|
+
OUT_A_N" data-x="4.6925" data-y="1.2" cx="400.3629417382999" cy="267.5835721107927" r="3" fill="green"/></g><g><circle data-type="point" data-label="inline anchor
|
|
24
|
+
OUT_B_N" data-x="4.6425" data-y="1" cx="397.68863419293217" cy="278.2808022922636" r="3" fill="green"/></g><g><circle data-type="point" data-label="inline anchor
|
|
25
|
+
OUT_B_P" data-x="3.91" data-y="0.8" cx="358.51002865329514" cy="288.97803247373446" r="3" fill="green"/></g><g><circle data-type="point" data-label="inline anchor
|
|
26
|
+
SERIAL_IN" data-x="4.6925" data-y="0.6" cx="400.3629417382999" cy="299.67526265520536" r="3" fill="green"/></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[
|
|
27
|
+
document.currentScript.parentElement.addEventListener('mousemove', (e) => {
|
|
28
|
+
const svg = e.currentTarget;
|
|
29
|
+
const rect = svg.getBoundingClientRect();
|
|
30
|
+
const x = e.clientX - rect.left;
|
|
31
|
+
const y = e.clientY - rect.top;
|
|
32
|
+
const crosshair = svg.getElementById('crosshair');
|
|
33
|
+
const h = svg.getElementById('crosshair-h');
|
|
34
|
+
const v = svg.getElementById('crosshair-v');
|
|
35
|
+
const coords = svg.getElementById('coordinates');
|
|
36
|
+
|
|
37
|
+
crosshair.style.display = 'block';
|
|
38
|
+
h.setAttribute('x1', '0');
|
|
39
|
+
h.setAttribute('x2', '640');
|
|
40
|
+
h.setAttribute('y1', y);
|
|
41
|
+
h.setAttribute('y2', y);
|
|
42
|
+
v.setAttribute('x1', x);
|
|
43
|
+
v.setAttribute('x2', x);
|
|
44
|
+
v.setAttribute('y1', '0');
|
|
45
|
+
v.setAttribute('y2', '640');
|
|
46
|
+
|
|
47
|
+
// Calculate real coordinates using inverse transformation
|
|
48
|
+
const matrix = {"a":53.48615090735434,"c":0,"e":149.37917860553964,"b":0,"d":-53.48615090735434,"f":331.76695319961794};
|
|
49
|
+
// Manually invert and apply the affine transform
|
|
50
|
+
// Since we only use translate and scale, we can directly compute:
|
|
51
|
+
// x' = (x - tx) / sx
|
|
52
|
+
// y' = (y - ty) / sy
|
|
53
|
+
const sx = matrix.a;
|
|
54
|
+
const sy = matrix.d;
|
|
55
|
+
const tx = matrix.e;
|
|
56
|
+
const ty = matrix.f;
|
|
57
|
+
const realPoint = {
|
|
58
|
+
x: (x - tx) / sx,
|
|
59
|
+
y: (y - ty) / sy // Flip y back since we used negative scale
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
coords.textContent = `(${realPoint.x.toFixed(2)}, ${realPoint.y.toFixed(2)})`;
|
|
63
|
+
coords.setAttribute('x', (x + 5).toString());
|
|
64
|
+
coords.setAttribute('y', (y - 5).toString());
|
|
65
|
+
});
|
|
66
|
+
document.currentScript.parentElement.addEventListener('mouseleave', () => {
|
|
67
|
+
document.currentScript.parentElement.getElementById('crosshair').style.display = 'none';
|
|
68
|
+
});
|
|
69
|
+
]]></script></svg>
|
|
@@ -0,0 +1,54 @@
|
|
|
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="-0.7,0.2 -1.3290000000000002,0.2" data-type="line" data-label="" points="337.7926421404682,320 219.98662207357856,320" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="-0.7,0.4 -1.3290000000000002,0.4" data-type="line" data-label="" points="337.7926421404682,282.54180602006693 219.98662207357856,282.54180602006693" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="-0.7,0 -1.38,0" data-type="line" data-label="" points="337.7926421404682,357.4581939799331 210.43478260869568,357.4581939799331" fill="none" stroke="purple" stroke-width="1px"/></g><g><rect data-type="rect" data-label="U1" data-x="0" data-y="0.2" x="337.79264214046816" y="226.35451505016724" width="262.2073578595318" height="187.29096989966553" fill="hsl(164, 100%, 50%, 0.8)" stroke="black" stroke-width="0.005339285714285715"/></g><g><rect data-type="rect" data-label="netId: D_MINUS
|
|
2
|
+
globalConnNetId: connectivity_net0" data-x="-1.81" data-y="0.4" x="40" y="263.81270903010034" width="179.79933110367892" height="37.45819397993313" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.005339285714285715"/></g><g><rect data-type="rect" data-label="netId: D_PLUS
|
|
3
|
+
globalConnNetId: connectivity_net1" data-x="-1.75" data-y="0.2" x="62.474916387959894" y="301.2709030100334" width="157.324414715719" height="37.45819397993313" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.005339285714285715"/></g><g><rect data-type="rect" data-label="INLINE netId: SWCLK
|
|
4
|
+
axis: x
|
|
5
|
+
side: y+" data-x="-1.04" data-y="0.11" x="229.16387959866222" y="325.61872909698997" width="89.89966555183949" height="22.474916387959865" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.005339285714285715"/></g><text data-type="text" data-label="SWCLK" data-x="-0.8" data-y="0.11" x="319.0635451505017" y="336.8561872909699" fill="green" font-size="22.474916387959862" font-family="sans-serif" text-anchor="end" dominant-baseline="central">SWCLK</text><g><circle data-type="point" data-label="U1.minus
|
|
6
|
+
x-" data-x="-0.7" data-y="0.4" cx="337.7926421404682" cy="282.54180602006693" r="3" fill="hsl(166, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.plus
|
|
7
|
+
x-" data-x="-0.7" data-y="0.2" cx="337.7926421404682" cy="320" r="3" fill="hsl(92, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.swclk
|
|
8
|
+
x-" data-x="-0.7" data-y="0" cx="337.7926421404682" cy="357.4581939799331" r="3" fill="hsl(308, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="anchorPoint
|
|
9
|
+
orientation: x-" data-x="-1.3290000000000002" data-y="0.4" cx="219.98662207357856" cy="282.54180602006693" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g><circle data-type="point" data-label="anchorPoint
|
|
10
|
+
orientation: x-" data-x="-1.3290000000000002" data-y="0.2" cx="219.98662207357856" cy="320" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g><circle data-type="point" data-label="inline anchor
|
|
11
|
+
SWCLK" data-x="-1.04" data-y="0" cx="274.11371237458195" cy="357.4581939799331" r="3" fill="green"/></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[
|
|
12
|
+
document.currentScript.parentElement.addEventListener('mousemove', (e) => {
|
|
13
|
+
const svg = e.currentTarget;
|
|
14
|
+
const rect = svg.getBoundingClientRect();
|
|
15
|
+
const x = e.clientX - rect.left;
|
|
16
|
+
const y = e.clientY - rect.top;
|
|
17
|
+
const crosshair = svg.getElementById('crosshair');
|
|
18
|
+
const h = svg.getElementById('crosshair-h');
|
|
19
|
+
const v = svg.getElementById('crosshair-v');
|
|
20
|
+
const coords = svg.getElementById('coordinates');
|
|
21
|
+
|
|
22
|
+
crosshair.style.display = 'block';
|
|
23
|
+
h.setAttribute('x1', '0');
|
|
24
|
+
h.setAttribute('x2', '640');
|
|
25
|
+
h.setAttribute('y1', y);
|
|
26
|
+
h.setAttribute('y2', y);
|
|
27
|
+
v.setAttribute('x1', x);
|
|
28
|
+
v.setAttribute('x2', x);
|
|
29
|
+
v.setAttribute('y1', '0');
|
|
30
|
+
v.setAttribute('y2', '640');
|
|
31
|
+
|
|
32
|
+
// Calculate real coordinates using inverse transformation
|
|
33
|
+
const matrix = {"a":187.29096989966553,"c":0,"e":468.8963210702341,"b":0,"d":-187.29096989966553,"f":357.4581939799331};
|
|
34
|
+
// Manually invert and apply the affine transform
|
|
35
|
+
// Since we only use translate and scale, we can directly compute:
|
|
36
|
+
// x' = (x - tx) / sx
|
|
37
|
+
// y' = (y - ty) / sy
|
|
38
|
+
const sx = matrix.a;
|
|
39
|
+
const sy = matrix.d;
|
|
40
|
+
const tx = matrix.e;
|
|
41
|
+
const ty = matrix.f;
|
|
42
|
+
const realPoint = {
|
|
43
|
+
x: (x - tx) / sx,
|
|
44
|
+
y: (y - ty) / sy // Flip y back since we used negative scale
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
coords.textContent = `(${realPoint.x.toFixed(2)}, ${realPoint.y.toFixed(2)})`;
|
|
48
|
+
coords.setAttribute('x', (x + 5).toString());
|
|
49
|
+
coords.setAttribute('y', (y - 5).toString());
|
|
50
|
+
});
|
|
51
|
+
document.currentScript.parentElement.addEventListener('mouseleave', () => {
|
|
52
|
+
document.currentScript.parentElement.getElementById('crosshair').style.display = 'none';
|
|
53
|
+
});
|
|
54
|
+
]]></script></svg>
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { expect, test } from "bun:test"
|
|
2
|
+
import { SchematicTracePipelineSolver } from "lib/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver"
|
|
3
|
+
import type {
|
|
4
|
+
InputDirectConnection,
|
|
5
|
+
InputProblem,
|
|
6
|
+
} from "lib/types/InputProblem"
|
|
7
|
+
import "tests/fixtures/matcher"
|
|
8
|
+
|
|
9
|
+
const inlineConnection = (
|
|
10
|
+
netId: string,
|
|
11
|
+
pinIds: [string, string],
|
|
12
|
+
fallbackNetLabelWidth: number,
|
|
13
|
+
inlineNetLabelWidth: number,
|
|
14
|
+
): InputDirectConnection => ({
|
|
15
|
+
netId,
|
|
16
|
+
pinIds,
|
|
17
|
+
allowInlineNetLabel: true,
|
|
18
|
+
fallbackNetLabelWidth,
|
|
19
|
+
inlineNetLabelWidth,
|
|
20
|
+
inlineNetLabelHeight: 0.12,
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
const routedInputProblem: InputProblem = {
|
|
24
|
+
chips: [
|
|
25
|
+
{
|
|
26
|
+
chipId: "U1",
|
|
27
|
+
center: { x: 0, y: 0 },
|
|
28
|
+
width: 3.29,
|
|
29
|
+
height: 6.35,
|
|
30
|
+
sectionId: "driver",
|
|
31
|
+
pins: [
|
|
32
|
+
{ pinId: "U1.4", x: 2.045, y: 2.6, _facingDirection: "x+" },
|
|
33
|
+
{ pinId: "U1.6", x: 2.045, y: 2.4, _facingDirection: "x+" },
|
|
34
|
+
{ pinId: "U1.7", x: 2.045, y: 2.2, _facingDirection: "x+" },
|
|
35
|
+
{ pinId: "U1.9", x: 2.045, y: 2, _facingDirection: "x+" },
|
|
36
|
+
{ pinId: "U1.48", x: 2.045, y: 0.7, _facingDirection: "x+" },
|
|
37
|
+
],
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
chipId: "J4",
|
|
41
|
+
center: { x: 7, y: -0.4 },
|
|
42
|
+
width: 2.05,
|
|
43
|
+
height: 4,
|
|
44
|
+
sectionId: "driver",
|
|
45
|
+
pins: [
|
|
46
|
+
{ pinId: "J4.1", x: 5.575, y: 1.4, _facingDirection: "x-" },
|
|
47
|
+
{ pinId: "J4.2", x: 5.575, y: 1.2, _facingDirection: "x-" },
|
|
48
|
+
{ pinId: "J4.3", x: 5.575, y: 1, _facingDirection: "x-" },
|
|
49
|
+
{ pinId: "J4.4", x: 5.575, y: 0.8, _facingDirection: "x-" },
|
|
50
|
+
{ pinId: "J4.5", x: 5.575, y: 0.6, _facingDirection: "x-" },
|
|
51
|
+
],
|
|
52
|
+
},
|
|
53
|
+
],
|
|
54
|
+
directConnections: [
|
|
55
|
+
inlineConnection("OUT_A_P", ["J4.1", "U1.4"], 0.96, 0.64),
|
|
56
|
+
inlineConnection("OUT_A_N", ["J4.2", "U1.6"], 0.96, 0.64),
|
|
57
|
+
inlineConnection("OUT_B_N", ["J4.3", "U1.7"], 0.96, 0.64),
|
|
58
|
+
inlineConnection("OUT_B_P", ["J4.4", "U1.9"], 0.96, 0.64),
|
|
59
|
+
inlineConnection("SERIAL_IN", ["J4.5", "U1.48"], 1.2, 0.8),
|
|
60
|
+
],
|
|
61
|
+
netConnections: [],
|
|
62
|
+
textBoxes: [
|
|
63
|
+
{
|
|
64
|
+
chipId: "U1",
|
|
65
|
+
center: { x: 2.405, y: 3.525 },
|
|
66
|
+
width: 1.32,
|
|
67
|
+
height: 0.18,
|
|
68
|
+
text: "TB67S579FTG",
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
chipId: "U1",
|
|
72
|
+
center: { x: 1.865, y: 3.29 },
|
|
73
|
+
width: 0.36,
|
|
74
|
+
height: 0.25,
|
|
75
|
+
text: "U1",
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
chipId: "J4",
|
|
79
|
+
center: { x: 6.095, y: 1.715 },
|
|
80
|
+
width: 0.36,
|
|
81
|
+
height: 0.25,
|
|
82
|
+
text: "J4",
|
|
83
|
+
},
|
|
84
|
+
],
|
|
85
|
+
availableNetLabelOrientations: {},
|
|
86
|
+
maxMspPairDistance: 20,
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
test("fallback label width does not split routable inline connections", () => {
|
|
90
|
+
const solver = new SchematicTracePipelineSolver(routedInputProblem)
|
|
91
|
+
|
|
92
|
+
solver.solve()
|
|
93
|
+
|
|
94
|
+
expect(solver.schematicTraceLinesSolver!.solvedTracePaths).toHaveLength(5)
|
|
95
|
+
expect(solver.schematicTraceLinesSolver!.failedConnectionPairs).toHaveLength(
|
|
96
|
+
0,
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
const output = solver.inlineNetLabelSolver!.getOutput()
|
|
100
|
+
expect(output.traces).toHaveLength(5)
|
|
101
|
+
expect(output.inlineNetLabelPlacements).toHaveLength(5)
|
|
102
|
+
expect(
|
|
103
|
+
output.inlineNetLabelPlacements.every(
|
|
104
|
+
(placement) => placement.stubTracePath === undefined,
|
|
105
|
+
),
|
|
106
|
+
).toBe(true)
|
|
107
|
+
|
|
108
|
+
expect(solver).toMatchSolverSnapshot(import.meta.path)
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
test("fallback label width sizes anchored labels when routing is skipped", () => {
|
|
112
|
+
const inputProblem: InputProblem = {
|
|
113
|
+
chips: [
|
|
114
|
+
{
|
|
115
|
+
chipId: "U1",
|
|
116
|
+
center: { x: -3, y: 0 },
|
|
117
|
+
width: 1,
|
|
118
|
+
height: 1,
|
|
119
|
+
pins: [{ pinId: "U1.1", x: -2.5, y: 0, _facingDirection: "x+" }],
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
chipId: "U2",
|
|
123
|
+
center: { x: 3, y: 0 },
|
|
124
|
+
width: 1,
|
|
125
|
+
height: 1,
|
|
126
|
+
pins: [{ pinId: "U2.1", x: 2.5, y: 0, _facingDirection: "x-" }],
|
|
127
|
+
},
|
|
128
|
+
],
|
|
129
|
+
directConnections: [
|
|
130
|
+
{
|
|
131
|
+
netId: "SIGNAL",
|
|
132
|
+
pinIds: ["U1.1", "U2.1"],
|
|
133
|
+
allowInlineNetLabel: true,
|
|
134
|
+
fallbackNetLabelWidth: 0.96,
|
|
135
|
+
inlineNetLabelWidth: 0.64,
|
|
136
|
+
inlineNetLabelHeight: 0.12,
|
|
137
|
+
},
|
|
138
|
+
],
|
|
139
|
+
netConnections: [],
|
|
140
|
+
availableNetLabelOrientations: {},
|
|
141
|
+
maxMspPairDistance: 1,
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const solver = new SchematicTracePipelineSolver(inputProblem)
|
|
145
|
+
solver.solve()
|
|
146
|
+
|
|
147
|
+
const [fallbackPlacement] = solver.netLabelPlacementSolver!.netLabelPlacements
|
|
148
|
+
expect(fallbackPlacement).toBeDefined()
|
|
149
|
+
expect(Math.max(fallbackPlacement!.width, fallbackPlacement!.height)).toBe(
|
|
150
|
+
0.96,
|
|
151
|
+
)
|
|
152
|
+
})
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { expect, test } from "bun:test"
|
|
2
|
+
import { SchematicTracePipelineSolver } from "lib/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver"
|
|
3
|
+
import inputProblem from "../../assets/inline-net-label-anchored-label-clearance.json"
|
|
4
|
+
import "tests/fixtures/matcher"
|
|
5
|
+
|
|
6
|
+
test("regular labels are drawn beyond adjacent inline labels", () => {
|
|
7
|
+
const solver = new SchematicTracePipelineSolver(inputProblem as any)
|
|
8
|
+
|
|
9
|
+
solver.solve()
|
|
10
|
+
|
|
11
|
+
const output = solver.inlineNetLabelSolver!.getOutput()
|
|
12
|
+
const regularLabels = output.netLabelPlacements.filter((label) =>
|
|
13
|
+
["D_MINUS", "D_PLUS"].includes(label.netId ?? ""),
|
|
14
|
+
)
|
|
15
|
+
expect(solver.inlineNetLabelSolver!.stats.pushedAnchoredNetLabelCount).toBe(2)
|
|
16
|
+
expect(regularLabels).toHaveLength(2)
|
|
17
|
+
expect(regularLabels[0]!.anchorPoint.x).toBeCloseTo(
|
|
18
|
+
regularLabels[1]!.anchorPoint.x,
|
|
19
|
+
)
|
|
20
|
+
expect(regularLabels[0]!.anchorPoint.x).toBeLessThan(-0.7)
|
|
21
|
+
expect(
|
|
22
|
+
output.traces.filter((trace) =>
|
|
23
|
+
trace.mspPairId.startsWith("inline-net-label-clearance-"),
|
|
24
|
+
),
|
|
25
|
+
).toHaveLength(2)
|
|
26
|
+
|
|
27
|
+
expect(solver).toMatchSolverSnapshot(import.meta.path)
|
|
28
|
+
})
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
import { expect, test } from "bun:test"
|
|
2
|
+
import type { NetLabelPlacement } from "lib/solvers/NetLabelPlacementSolver/NetLabelPlacementSolver"
|
|
3
|
+
import type { SolvedTracePath } from "lib/solvers/SchematicTraceLinesSolver/SchematicTraceLinesSolver"
|
|
4
|
+
import type { InputProblem } from "lib/types/InputProblem"
|
|
5
|
+
import { pushAnchoredNetLabelsAwayFromInlineLabels } from "lib/solvers/InlineNetLabelSolver/pushAnchoredNetLabelsAwayFromInlineLabels"
|
|
6
|
+
import type { InlineNetLabelPlacement } from "lib/solvers/InlineNetLabelSolver/InlineNetLabelSolver"
|
|
7
|
+
|
|
8
|
+
test("pushes a regular endpoint label and its wick past nearby inline text", () => {
|
|
9
|
+
const inputProblem: InputProblem = {
|
|
10
|
+
chips: [
|
|
11
|
+
{
|
|
12
|
+
chipId: "U1",
|
|
13
|
+
center: { x: 0, y: 0 },
|
|
14
|
+
width: 1,
|
|
15
|
+
height: 1,
|
|
16
|
+
pins: [],
|
|
17
|
+
},
|
|
18
|
+
],
|
|
19
|
+
directConnections: [],
|
|
20
|
+
netConnections: [],
|
|
21
|
+
availableNetLabelOrientations: {},
|
|
22
|
+
}
|
|
23
|
+
const netLabelPlacements: NetLabelPlacement[] = [
|
|
24
|
+
{
|
|
25
|
+
globalConnNetId: "regular-net",
|
|
26
|
+
netId: "D_PLUS",
|
|
27
|
+
mspConnectionPairIds: [],
|
|
28
|
+
pinIds: ["U1.1"],
|
|
29
|
+
orientation: "x-",
|
|
30
|
+
anchorPoint: { x: -0.7, y: 0.2 },
|
|
31
|
+
center: { x: -1.2, y: 0.2 },
|
|
32
|
+
width: 1,
|
|
33
|
+
height: 0.2,
|
|
34
|
+
},
|
|
35
|
+
]
|
|
36
|
+
const traces: SolvedTracePath[] = [
|
|
37
|
+
{
|
|
38
|
+
mspPairId: "available-net-orientation-0-D_PLUS",
|
|
39
|
+
dcConnNetId: "regular-net",
|
|
40
|
+
globalConnNetId: "regular-net",
|
|
41
|
+
pins: [] as any,
|
|
42
|
+
tracePath: [
|
|
43
|
+
{ x: -0.5, y: 0.2 },
|
|
44
|
+
{ x: -0.7, y: 0.2 },
|
|
45
|
+
],
|
|
46
|
+
mspConnectionPairIds: [],
|
|
47
|
+
pinIds: ["U1.1"],
|
|
48
|
+
},
|
|
49
|
+
]
|
|
50
|
+
const inlineNetLabelPlacements: InlineNetLabelPlacement[] = [
|
|
51
|
+
{
|
|
52
|
+
globalConnNetId: "inline-net",
|
|
53
|
+
netId: "SWCLK",
|
|
54
|
+
pinIds: ["U1.2"],
|
|
55
|
+
stubTracePath: [
|
|
56
|
+
{ x: -0.5, y: 0 },
|
|
57
|
+
{ x: -1.7, y: 0 },
|
|
58
|
+
],
|
|
59
|
+
axis: "x",
|
|
60
|
+
anchorPoint: { x: -1.1, y: 0 },
|
|
61
|
+
center: { x: -1.1, y: 0.11 },
|
|
62
|
+
width: 1.2,
|
|
63
|
+
height: 0.12,
|
|
64
|
+
side: "y+",
|
|
65
|
+
},
|
|
66
|
+
]
|
|
67
|
+
|
|
68
|
+
const output = pushAnchoredNetLabelsAwayFromInlineLabels({
|
|
69
|
+
inputProblem,
|
|
70
|
+
traces,
|
|
71
|
+
netLabelPlacements,
|
|
72
|
+
inlineNetLabelPlacements,
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
expect(output.movedLabelCount).toBe(1)
|
|
76
|
+
expect(output.netLabelPlacements[0]!.anchorPoint.x).toBeCloseTo(-1.75)
|
|
77
|
+
expect(output.netLabelPlacements[0]!.center.x).toBeCloseTo(-2.25)
|
|
78
|
+
expect(output.traces[0]!.tracePath[0]).toEqual({ x: -0.5, y: 0.2 })
|
|
79
|
+
expect(output.traces[0]!.tracePath[1]!.x).toBeCloseTo(-1.75)
|
|
80
|
+
expect(output.traces[0]!.tracePath[1]!.y).toBeCloseTo(0.2)
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
test("leaves a label without a movable connector in place", () => {
|
|
84
|
+
const label: NetLabelPlacement = {
|
|
85
|
+
globalConnNetId: "regular-net",
|
|
86
|
+
netId: "D_PLUS",
|
|
87
|
+
mspConnectionPairIds: ["routed-pair"],
|
|
88
|
+
pinIds: ["U1.1", "J1.1"],
|
|
89
|
+
orientation: "x-",
|
|
90
|
+
anchorPoint: { x: -0.7, y: 0.2 },
|
|
91
|
+
center: { x: -1.2, y: 0.2 },
|
|
92
|
+
width: 1,
|
|
93
|
+
height: 0.2,
|
|
94
|
+
}
|
|
95
|
+
const inlineLabel: InlineNetLabelPlacement = {
|
|
96
|
+
globalConnNetId: "inline-net",
|
|
97
|
+
netId: "SWCLK",
|
|
98
|
+
pinIds: ["U1.2"],
|
|
99
|
+
axis: "x",
|
|
100
|
+
anchorPoint: { x: -1.1, y: 0 },
|
|
101
|
+
center: { x: -1.1, y: 0.11 },
|
|
102
|
+
width: 1.2,
|
|
103
|
+
height: 0.12,
|
|
104
|
+
side: "y+",
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const output = pushAnchoredNetLabelsAwayFromInlineLabels({
|
|
108
|
+
inputProblem: {
|
|
109
|
+
chips: [],
|
|
110
|
+
directConnections: [],
|
|
111
|
+
netConnections: [],
|
|
112
|
+
availableNetLabelOrientations: {},
|
|
113
|
+
},
|
|
114
|
+
traces: [],
|
|
115
|
+
netLabelPlacements: [label],
|
|
116
|
+
inlineNetLabelPlacements: [inlineLabel],
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
expect(output.movedLabelCount).toBe(0)
|
|
120
|
+
expect(output.netLabelPlacements[0]).toEqual(label)
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
test("moves a contiguous label row together and shoves an anchored obstacle", () => {
|
|
124
|
+
const inputProblem: InputProblem = {
|
|
125
|
+
chips: [
|
|
126
|
+
{
|
|
127
|
+
chipId: "U1",
|
|
128
|
+
center: { x: 0, y: 0.2 },
|
|
129
|
+
width: 1.4,
|
|
130
|
+
height: 1,
|
|
131
|
+
pins: [
|
|
132
|
+
{ pinId: "U1.minus", x: -0.7, y: 0.4, _facingDirection: "x-" },
|
|
133
|
+
{ pinId: "U1.plus", x: -0.7, y: 0.2, _facingDirection: "x-" },
|
|
134
|
+
{ pinId: "U1.inline", x: -0.7, y: 0, _facingDirection: "x-" },
|
|
135
|
+
{ pinId: "U1.gnd1", x: -0.7, y: 0.5, _facingDirection: "x-" },
|
|
136
|
+
{ pinId: "U1.gnd2", x: -2.5, y: 0.5, _facingDirection: "x+" },
|
|
137
|
+
],
|
|
138
|
+
},
|
|
139
|
+
],
|
|
140
|
+
directConnections: [],
|
|
141
|
+
netConnections: [],
|
|
142
|
+
availableNetLabelOrientations: {},
|
|
143
|
+
}
|
|
144
|
+
const netLabelPlacements: NetLabelPlacement[] = [
|
|
145
|
+
{
|
|
146
|
+
globalConnNetId: "minus-net",
|
|
147
|
+
netId: "D_MINUS",
|
|
148
|
+
mspConnectionPairIds: [],
|
|
149
|
+
pinIds: ["U1.minus"],
|
|
150
|
+
orientation: "x-",
|
|
151
|
+
anchorPoint: { x: -0.7, y: 0.4 },
|
|
152
|
+
center: { x: -1.2, y: 0.4 },
|
|
153
|
+
width: 1,
|
|
154
|
+
height: 0.2,
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
globalConnNetId: "plus-net",
|
|
158
|
+
netId: "D_PLUS",
|
|
159
|
+
mspConnectionPairIds: [],
|
|
160
|
+
pinIds: ["U1.plus"],
|
|
161
|
+
orientation: "x-",
|
|
162
|
+
anchorPoint: { x: -0.7, y: 0.2 },
|
|
163
|
+
center: { x: -1.2, y: 0.2 },
|
|
164
|
+
width: 1,
|
|
165
|
+
height: 0.2,
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
globalConnNetId: "gnd-net",
|
|
169
|
+
netId: "GND",
|
|
170
|
+
mspConnectionPairIds: ["gnd-route"],
|
|
171
|
+
pinIds: ["U1.gnd1", "U1.gnd2"],
|
|
172
|
+
orientation: "y-",
|
|
173
|
+
anchorPoint: { x: -2.5, y: 0.5 },
|
|
174
|
+
center: { x: -2.5, y: 0.3 },
|
|
175
|
+
width: 0.4,
|
|
176
|
+
height: 0.4,
|
|
177
|
+
},
|
|
178
|
+
]
|
|
179
|
+
const traces: SolvedTracePath[] = [
|
|
180
|
+
{
|
|
181
|
+
mspPairId: "gnd-route",
|
|
182
|
+
dcConnNetId: "gnd-net",
|
|
183
|
+
globalConnNetId: "gnd-net",
|
|
184
|
+
pins: [] as any,
|
|
185
|
+
tracePath: [
|
|
186
|
+
{ x: -0.7, y: 0.5 },
|
|
187
|
+
{ x: -2.5, y: 0.5 },
|
|
188
|
+
],
|
|
189
|
+
mspConnectionPairIds: ["gnd-route"],
|
|
190
|
+
pinIds: ["U1.gnd1", "U1.gnd2"],
|
|
191
|
+
},
|
|
192
|
+
]
|
|
193
|
+
const inlineNetLabelPlacements: InlineNetLabelPlacement[] = [
|
|
194
|
+
{
|
|
195
|
+
globalConnNetId: "inline-net",
|
|
196
|
+
netId: "SWCLK",
|
|
197
|
+
pinIds: ["U1.inline"],
|
|
198
|
+
stubTracePath: [
|
|
199
|
+
{ x: -0.7, y: 0 },
|
|
200
|
+
{ x: -1.9, y: 0 },
|
|
201
|
+
],
|
|
202
|
+
axis: "x",
|
|
203
|
+
anchorPoint: { x: -1.3, y: 0 },
|
|
204
|
+
center: { x: -1.1, y: 0.11 },
|
|
205
|
+
width: 1.2,
|
|
206
|
+
height: 0.12,
|
|
207
|
+
side: "y+",
|
|
208
|
+
},
|
|
209
|
+
]
|
|
210
|
+
|
|
211
|
+
const output = pushAnchoredNetLabelsAwayFromInlineLabels({
|
|
212
|
+
inputProblem,
|
|
213
|
+
traces,
|
|
214
|
+
netLabelPlacements,
|
|
215
|
+
inlineNetLabelPlacements,
|
|
216
|
+
})
|
|
217
|
+
|
|
218
|
+
expect(output.movedLabelCount).toBe(3)
|
|
219
|
+
expect(output.netLabelPlacements[0]!.anchorPoint.x).toBeCloseTo(-1.75)
|
|
220
|
+
expect(output.netLabelPlacements[1]!.anchorPoint.x).toBeCloseTo(-1.75)
|
|
221
|
+
expect(output.netLabelPlacements[2]!.center.x).toBeLessThan(-2.5)
|
|
222
|
+
expect(
|
|
223
|
+
output.traces.filter((trace) =>
|
|
224
|
+
trace.mspPairId.startsWith("inline-net-label-clearance-"),
|
|
225
|
+
),
|
|
226
|
+
).toHaveLength(3)
|
|
227
|
+
})
|