@tscircuit/schematic-trace-solver 0.0.196 → 0.0.197
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 +1 -0
- package/dist/index.js +38 -3
- package/lib/solvers/NetLabelToTraceSolver/NetLabelToTraceSolver.ts +42 -1
- package/lib/solvers/NetLabelToTraceSolver/getSimpleElbowPath.ts +31 -0
- package/package.json +1 -1
- package/site/bug-reports/enc-scl-hop.page.tsx +6 -0
- package/tests/assets/enc-scl-hop.json +185 -0
- package/tests/bug-reports/bug-report-20260707T134549Z/__snapshots__/bug-report-20260707T134549Z.snap.svg +13 -31
- package/tests/bug-reports/bug-report-20260901T064117Z/__snapshots__/bug-report-20260901T064117Z.snap.svg +25 -61
- package/tests/repros/__snapshots__/repro-mcp73831-charger-traces.snap.svg +5 -23
- package/tests/repros/__snapshots__/repro-trellis-core-gnd-net-label-overlap.snap.svg +25 -61
- package/tests/repros/__snapshots__/rp2040-robot-controller-disconnected-gnd.snap.svg +12 -26
- package/tests/solvers/SchematicTracePipelineSolver/__snapshots__/enc-scl-hop.snap.svg +101 -0
- package/tests/solvers/SchematicTracePipelineSolver/__snapshots__/explicit-hop.snap.svg +101 -0
- package/tests/solvers/SchematicTracePipelineSolver/enc-scl-hop.test.ts +139 -0
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
<svg width="1200" height="2016" viewBox="0 0 1200 2016" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Solver debug visualization on top and Circuit JSON schematic on the bottom">
|
|
2
|
+
<g transform="translate(0, 0) scale(1.875, 1.875) translate(0, 0)">
|
|
3
|
+
<rect width="100%" height="100%" fill="white"/><g><polyline data-points="6.1000000000000005,1.2000000000000002 6.1000000000000005,1.4000000000000004 5.9,1.4000000000000004 5.9,1.2000000000000002" data-type="line" data-label="" points="510.4607046070461,263.089430894309 510.4607046070461,247.91327913279133 495.28455284552854,247.91327913279133 495.28455284552854,263.089430894309" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="5.9,-1.2000000000000002 5.9,-1.4000000000000004 6.1000000000000005,-1.4000000000000004 6.1000000000000005,-1.2000000000000002" data-type="line" data-label="" points="495.28455284552854,445.20325203252037 495.28455284552854,460.379403794038 510.4607046070461,460.379403794038 510.4607046070461,445.20325203252037" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="0,2.1 0,2.3000000000000003 2,2.3000000000000003 2,2.1" data-type="line" data-label="" points="47.58807588075882,194.7967479674797 47.58807588075882,179.62059620596207 199.34959349593498,179.62059620596207 199.34959349593498,194.7967479674797" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="0,1.5 0,0.10000000000000009 4.72,0.10000000000000009" data-type="line" data-label="" points="47.58807588075882,240.32520325203257 47.58807588075882,346.55826558265585 405.74525745257455,346.55826558265585" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="2,1.5 2,-0.10000000000000009 4.72,-0.10000000000000009" data-type="line" data-label="" points="199.34959349593498,240.32520325203257 199.34959349593498,361.7344173441735 405.74525745257455,361.7344173441735" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="0,1.5 0,0.10000000000000009 4.72,0.10000000000000009" data-type="line" data-label="recovered from net labels: R_ENC_SDA.2 -> U_ENCODER.6" points="47.58807588075882,240.32520325203257 47.58807588075882,346.55826558265585 405.74525745257455,346.55826558265585" fill="none" stroke="green" stroke-width="1px"/></g><g><polyline data-points="2,1.5 2,-0.10000000000000009 4.72,-0.10000000000000009" data-type="line" data-label="recovered from net labels: R_ENC_SCL.2 -> U_ENCODER.7" points="199.34959349593498,240.32520325203257 199.34959349593498,361.7344173441735 405.74525745257455,361.7344173441735" fill="none" stroke="green" stroke-width="1px"/></g><g><rect data-type="rect" data-label="R_ENC_SDA" data-x="0" data-y="1.8" x="41.51761517615177" y="194.7967479674797" width="12.140921409214101" height="45.52845528455288" fill="hsl(222, 100%, 50%, 0.8)" stroke="black" stroke-width="0.013178571428571428"/></g><g><rect data-type="rect" data-label="R_ENC_SCL" data-x="2" data-y="1.8" x="193.27913279132792" y="194.7967479674797" width="12.140921409214116" height="45.52845528455288" fill="hsl(202, 100%, 50%, 0.8)" stroke="black" stroke-width="0.013178571428571428"/></g><g><rect data-type="rect" data-label="U_ENCODER" data-x="6" data-y="0" x="405.7452574525746" y="263.089430894309" width="194.25474254742545" height="182.1138211382114" fill="hsl(242, 100%, 50%, 0.8)" stroke="black" stroke-width="0.013178571428571428"/></g><g><rect data-type="rect" data-label="netId: V3V3
|
|
4
|
+
globalConnNetId: connectivity_net1" data-x="0" data-y="2.5250000000000004" x="40.000000000000014" y="145.47425474254743" width="15.176151761517616" height="34.14634146341464" fill="#ef444466" stroke="#ef4444" stroke-width="0.013178571428571428"/></g><g><rect data-type="rect" data-label="netId: V3V3
|
|
5
|
+
globalConnNetId: connectivity_net1" data-x="6.1000000000000005" data-y="1.6250000000000004" x="502.8726287262873" y="213.76693766937672" width="15.176151761517588" height="34.14634146341464" fill="#ef444466" stroke="#ef4444" stroke-width="0.013178571428571428"/></g><g><rect data-type="rect" data-label="netId: GND
|
|
6
|
+
globalConnNetId: connectivity_net3" data-x="5.9" data-y="-1.6250000000000004" x="487.6964769647698" y="460.379403794038" width="15.176151761517588" height="34.146341463414615" fill="#00000066" stroke="#000000" stroke-width="0.013178571428571428"/></g><g><circle data-type="point" data-label="R_ENC_SDA.1
|
|
7
|
+
y+" data-x="0" data-y="2.1" cx="47.58807588075882" cy="194.7967479674797" r="3" fill="hsl(256, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="R_ENC_SDA.2
|
|
8
|
+
y-" data-x="0" data-y="1.5" cx="47.58807588075882" cy="240.32520325203257" r="3" fill="hsl(256, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="R_ENC_SCL.1
|
|
9
|
+
y+" data-x="2" data-y="2.1" cx="199.34959349593498" cy="194.7967479674797" r="3" fill="hsl(120, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="R_ENC_SCL.2
|
|
10
|
+
y-" data-x="2" data-y="1.5" cx="199.34959349593498" cy="240.32520325203257" r="3" fill="hsl(120, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="SDA
|
|
11
|
+
x-" data-x="4.72" data-y="0.1" cx="405.74525745257455" cy="346.55826558265585" r="3" fill="hsl(32, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="SCL
|
|
12
|
+
x-" data-x="4.72" data-y="-0.1" cx="405.74525745257455" cy="361.7344173441735" r="3" fill="hsl(32, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="VDD5V
|
|
13
|
+
y+" data-x="5.9" data-y="1.2000000000000002" cx="495.28455284552854" cy="263.089430894309" r="3" fill="hsl(32, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="VDD3V3
|
|
14
|
+
y+" data-x="6.1000000000000005" data-y="1.2000000000000002" cx="510.4607046070461" cy="263.089430894309" r="3" fill="hsl(32, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="GND
|
|
15
|
+
y-" data-x="5.9" data-y="-1.2000000000000002" cx="495.28455284552854" cy="445.20325203252037" r="3" fill="hsl(32, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="DIR
|
|
16
|
+
y-" data-x="6.1000000000000005" data-y="-1.2000000000000002" cx="510.4607046070461" cy="445.20325203252037" r="3" fill="hsl(48, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="OUT
|
|
17
|
+
x+" data-x="7.28" data-y="0.1" cx="600" cy="346.55826558265585" r="3" fill="hsl(32, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="PGO
|
|
18
|
+
x+" data-x="7.28" data-y="-0.1" cx="600" cy="361.7344173441735" r="3" fill="hsl(32, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="anchorPoint
|
|
19
|
+
orientation: y+" data-x="0" data-y="2.3000000000000003" cx="47.58807588075882" cy="179.62059620596207" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g><circle data-type="point" data-label="anchorPoint
|
|
20
|
+
orientation: y+" data-x="6.1000000000000005" data-y="1.4000000000000004" cx="510.4607046070461" cy="247.91327913279133" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g><circle data-type="point" data-label="anchorPoint
|
|
21
|
+
orientation: y-" data-x="5.9" data-y="-1.4000000000000004" cx="495.28455284552854" cy="460.379403794038" 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[
|
|
22
|
+
document.currentScript.parentElement.addEventListener('mousemove', (e) => {
|
|
23
|
+
const svg = e.currentTarget;
|
|
24
|
+
const rect = svg.getBoundingClientRect();
|
|
25
|
+
const x = e.clientX - rect.left;
|
|
26
|
+
const y = e.clientY - rect.top;
|
|
27
|
+
const crosshair = svg.getElementById('crosshair');
|
|
28
|
+
const h = svg.getElementById('crosshair-h');
|
|
29
|
+
const v = svg.getElementById('crosshair-v');
|
|
30
|
+
const coords = svg.getElementById('coordinates');
|
|
31
|
+
|
|
32
|
+
crosshair.style.display = 'block';
|
|
33
|
+
h.setAttribute('x1', '0');
|
|
34
|
+
h.setAttribute('x2', '640');
|
|
35
|
+
h.setAttribute('y1', y);
|
|
36
|
+
h.setAttribute('y2', y);
|
|
37
|
+
v.setAttribute('x1', x);
|
|
38
|
+
v.setAttribute('x2', x);
|
|
39
|
+
v.setAttribute('y1', '0');
|
|
40
|
+
v.setAttribute('y2', '640');
|
|
41
|
+
|
|
42
|
+
// Calculate real coordinates using inverse transformation
|
|
43
|
+
const matrix = {"a":75.88075880758808,"c":0,"e":47.58807588075882,"b":0,"d":-75.88075880758808,"f":354.1463414634147};
|
|
44
|
+
// Manually invert and apply the affine transform
|
|
45
|
+
// Since we only use translate and scale, we can directly compute:
|
|
46
|
+
// x' = (x - tx) / sx
|
|
47
|
+
// y' = (y - ty) / sy
|
|
48
|
+
const sx = matrix.a;
|
|
49
|
+
const sy = matrix.d;
|
|
50
|
+
const tx = matrix.e;
|
|
51
|
+
const ty = matrix.f;
|
|
52
|
+
const realPoint = {
|
|
53
|
+
x: (x - tx) / sx,
|
|
54
|
+
y: (y - ty) / sy // Flip y back since we used negative scale
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
coords.textContent = `(${realPoint.x.toFixed(2)}, ${realPoint.y.toFixed(2)})`;
|
|
58
|
+
coords.setAttribute('x', (x + 5).toString());
|
|
59
|
+
coords.setAttribute('y', (y - 5).toString());
|
|
60
|
+
});
|
|
61
|
+
document.currentScript.parentElement.addEventListener('mouseleave', () => {
|
|
62
|
+
document.currentScript.parentElement.getElementById('crosshair').style.display = 'none';
|
|
63
|
+
});
|
|
64
|
+
]]></script>
|
|
65
|
+
</g>
|
|
66
|
+
<g transform="translate(0, 1216)">
|
|
67
|
+
<style>
|
|
68
|
+
.boundary { fill: rgb(245, 241, 237); }
|
|
69
|
+
.schematic-boundary { fill: none; stroke: #fff; }
|
|
70
|
+
.component { fill: none; stroke: rgb(132, 0, 0); }
|
|
71
|
+
.chip { fill: rgb(255, 255, 194); stroke: rgb(132, 0, 0); }
|
|
72
|
+
.component-pin { fill: none; stroke: rgb(132, 0, 0); }
|
|
73
|
+
.text { font-family: sans-serif; fill: rgb(0, 150, 0); }
|
|
74
|
+
.pin-number { fill: rgb(169, 0, 0); }
|
|
75
|
+
.port-label { fill: rgb(0, 100, 100); }
|
|
76
|
+
.component-name { fill: rgb(0, 100, 100); }
|
|
77
|
+
|
|
78
|
+
</style><rect class="boundary" x="0" y="0" width="1200" height="800"/><g class="trace sch-trace" data-layer="base" data-circuit-json-type="schematic_trace" data-schematic-trace-id="schematic_trace_0__stack1"><path d="M 958.09739524318 301.07361268414 L 958.09739524318 273.89354473398 L 930.91732729302 273.89354473398 L 930.91732729302 301.07361268414" class="trace-invisible-hover-outline sch-trace-hitbox" stroke="rgb(0, 150, 0)" fill="none" stroke-width="21.744054360127997px" stroke-linecap="round" opacity="0" stroke-linejoin="round"/><path class="sch-trace-path" d="M 958.09739524318 301.07361268414 L 958.09739524318 273.89354473398 L 930.91732729302 273.89354473398 L 930.91732729302 301.07361268414" stroke="rgb(0, 150, 0)" fill="none" stroke-width="2.7180067950159996px" stroke-linecap="round" stroke-linejoin="round"/></g><g class="trace sch-trace" data-layer="base" data-circuit-json-type="schematic_trace" data-schematic-trace-id="schematic_trace_1__stack1"><path d="M 930.91732729302 627.23442808606 L 930.91732729302 654.41449603622 L 958.09739524318 654.41449603622 L 958.09739524318 627.23442808606" class="trace-invisible-hover-outline sch-trace-hitbox" stroke="rgb(0, 150, 0)" fill="none" stroke-width="21.744054360127997px" stroke-linecap="round" opacity="0" stroke-linejoin="round"/><path class="sch-trace-path" d="M 930.91732729302 627.23442808606 L 930.91732729302 654.41449603622 L 958.09739524318 654.41449603622 L 958.09739524318 627.23442808606" stroke="rgb(0, 150, 0)" fill="none" stroke-width="2.7180067950159996px" stroke-linecap="round" stroke-linejoin="round"/></g><g class="trace sch-trace" data-layer="base" data-circuit-json-type="schematic_trace" data-schematic-trace-id="schematic_trace_2__stack1"><path d="M 129.1053227633 178.76330690842002 L 129.1053227633 151.58323895825998 L 400.90600226489994 151.58323895825998 L 400.90600226489994 178.76330690842002" class="trace-invisible-hover-outline sch-trace-hitbox" stroke="rgb(0, 150, 0)" fill="none" stroke-width="21.744054360127997px" stroke-linecap="round" opacity="0" stroke-linejoin="round"/><path class="sch-trace-path" d="M 129.1053227633 178.76330690842002 L 129.1053227633 151.58323895825998 L 400.90600226489994 151.58323895825998 L 400.90600226489994 178.76330690842002" stroke="rgb(0, 150, 0)" fill="none" stroke-width="2.7180067950159996px" stroke-linecap="round" stroke-linejoin="round"/></g><g class="trace sch-trace" data-layer="base" data-circuit-json-type="schematic_trace" data-schematic-trace-id="schematic_trace_3__stack1"><path d="M 129.1053227633 260.3035107589 L 129.1053227633 450.56398641002 L 770.554926387076 450.56398641002" class="trace-invisible-hover-outline sch-trace-hitbox" stroke="rgb(0, 150, 0)" fill="none" stroke-width="21.744054360127997px" stroke-linecap="round" opacity="0" stroke-linejoin="round"/><path class="sch-trace-path" d="M 129.1053227633 260.3035107589 L 129.1053227633 450.56398641002 L 770.554926387076 450.56398641002" stroke="rgb(0, 150, 0)" fill="none" stroke-width="2.7180067950159996px" stroke-linecap="round" stroke-linejoin="round"/></g><g class="trace sch-trace" data-layer="base" data-circuit-json-type="schematic_trace" data-schematic-trace-id="schematic_trace_4__stack1"><path d="M 400.90600226489994 260.3035107589 L 400.90600226489994 477.74405436018003 L 770.554926387076 477.74405436018003" class="trace-invisible-hover-outline sch-trace-hitbox" stroke="rgb(0, 150, 0)" fill="none" stroke-width="21.744054360127997px" stroke-linecap="round" opacity="0" stroke-linejoin="round"/><path class="sch-trace-path" d="M 400.90600226489994 260.3035107589 L 400.90600226489994 477.74405436018003 L 770.554926387076 477.74405436018003" stroke="rgb(0, 150, 0)" fill="none" stroke-width="2.7180067950159996px" stroke-linecap="round" stroke-linejoin="round"/></g><g class="trace-overlays sch-trace-overlays" data-layer="overlay" data-circuit-json-type="schematic_trace" data-schematic-trace-id="schematic_trace_0__stack1"/><g class="trace-overlays sch-trace-overlays" data-layer="overlay" data-circuit-json-type="schematic_trace" data-schematic-trace-id="schematic_trace_1__stack1"/><g class="trace-overlays sch-trace-overlays" data-layer="overlay" data-circuit-json-type="schematic_trace" data-schematic-trace-id="schematic_trace_2__stack1"/><g class="trace-overlays sch-trace-overlays" data-layer="overlay" data-circuit-json-type="schematic_trace" data-schematic-trace-id="schematic_trace_3__stack1"/><g class="trace-overlays sch-trace-overlays" data-layer="overlay" data-circuit-json-type="schematic_trace" data-schematic-trace-id="schematic_trace_4__stack1"/><g class="sch-component" data-circuit-json-type="schematic_component" data-schematic-component-id="schematic_component_0__stack1"><rect class="component-overlay sch-component-overlay" x="118.236013590031" y="178.76330690842002" width="21.738618346537976" height="81.54020385048" fill="transparent"/><path class="sch-component-symbol-path" d="M 129.1053227633 178.76330690842002 L 129.1053227633 192.35605889029503" stroke="rgb(132, 0, 0)" fill="none" stroke-width="2.7180067950159996px" stroke-linecap="round"/><path class="sch-component-symbol-path" d="M 129.1053227633 246.710758777025 L 129.1053227633 260.3035107589" stroke="rgb(132, 0, 0)" fill="none" stroke-width="2.7180067950159996px" stroke-linecap="round"/><path class="sch-component-symbol-path" d="M 139.97463193656898 192.35605889029503 L 139.97463193656898 246.710758777025 L 118.236013590031 246.710758777025 L 118.236013590031 192.35605889029503 L 139.97463193656898 192.35605889029503" stroke="rgb(132, 0, 0)" fill="none" stroke-width="2.7180067950159996px" stroke-linecap="round"/><text class="sch-component-name sch-component-text" x="150.84937712342798" y="197.789354473532" stroke="rgb(245, 241, 237)" stroke-width="2.7180067950159996px" paint-order="stroke" fill="rgb(15, 15, 15)" font-family="sans-serif" text-anchor="start" dominant-baseline="middle" font-size="24.462061155143996px">R_ENC_SDA</text><text class="sch-component-text" x="150.84937712342798" y="241.27746319378804" fill="rgb(15, 15, 15)" font-family="sans-serif" text-anchor="start" dominant-baseline="middle" font-size="24.462061155143996px"></text></g><g class="sch-component" data-circuit-json-type="schematic_component" data-schematic-component-id="schematic_component_1__stack1"><rect class="component-overlay sch-component-overlay" x="390.036693091631" y="178.76330690842002" width="21.73861834653792" height="81.54020385048" fill="transparent"/><path class="sch-component-symbol-path" d="M 400.90600226489994 178.76330690842002 L 400.90600226489994 192.35605889029503" stroke="rgb(132, 0, 0)" fill="none" stroke-width="2.7180067950159996px" stroke-linecap="round"/><path class="sch-component-symbol-path" d="M 400.90600226489994 246.710758777025 L 400.90600226489994 260.3035107589" stroke="rgb(132, 0, 0)" fill="none" stroke-width="2.7180067950159996px" stroke-linecap="round"/><path class="sch-component-symbol-path" d="M 411.7753114381689 192.35605889029503 L 411.7753114381689 246.710758777025 L 390.036693091631 246.710758777025 L 390.036693091631 192.35605889029503 L 411.7753114381689 192.35605889029503" stroke="rgb(132, 0, 0)" fill="none" stroke-width="2.7180067950159996px" stroke-linecap="round"/><text class="sch-component-name sch-component-text" x="422.65005662502796" y="197.789354473532" stroke="rgb(245, 241, 237)" stroke-width="2.7180067950159996px" paint-order="stroke" fill="rgb(15, 15, 15)" font-family="sans-serif" text-anchor="start" dominant-baseline="middle" font-size="24.462061155143996px">R_ENC_SCL</text><text class="sch-component-text" x="422.65005662502796" y="241.27746319378804" fill="rgb(15, 15, 15)" font-family="sans-serif" text-anchor="start" dominant-baseline="middle" font-size="24.462061155143996px"></text></g><g class="sch-component" data-circuit-json-type="schematic_component" data-schematic-component-id="schematic_component_2__stack1"><rect class="component chip sch-component-body" x="824.9150622873959" y="355.43374858446" width="239.18459796140803" height="217.44054360128007" stroke-width="2.7180067950159996px" fill="rgb(255, 255, 194)" stroke="rgb(132, 0, 0)"/><rect class="component-overlay sch-component-overlay" x="824.9150622873959" y="355.43374858446" width="239.18459796140803" height="217.44054360128007" fill="transparent"/><text class="sch-text" x="944.5073612681" y="464.1540203851" fill="#0f172a" text-anchor="middle" dominant-baseline="middle" font-family="sans-serif" font-size="24.462061155143996px" transform="rotate(0, 944.5073612681, 464.1540203851)">U_ENCODER</text><line class="component-pin sch-component-pin sch-port-line" x1="824.9150622873959" y1="450.56398641002" x2="770.554926387076" y2="450.56398641002" stroke-width="2.7180067950159996px"/><g class="sch-port" data-schematic-port-id="source_port_2_0__stack1"><rect x="767.83691959206" y="447.845979615004" width="5.436013590031999" height="5.436013590031999" opacity="0"/></g><text class="pin-number sch-pin-number" x="797.734994337236" y="447.845979615004" style="font-family: sans-serif;" fill="rgb(169, 0, 0)" text-anchor="middle" dominant-baseline="auto" font-size="20.385050962619996px" transform="">6</text><text class="pin-number sch-pin-label" x="838.505096262476" y="450.56398641002" style="font-family: sans-serif;" fill="rgb(169, 0, 0)" text-anchor="start" dominant-baseline="middle" font-size="20.385050962619996px" transform="">SDA</text><line class="component-pin sch-component-pin sch-port-line" x1="824.9150622873959" y1="477.74405436018003" x2="770.554926387076" y2="477.74405436018003" stroke-width="2.7180067950159996px"/><g class="sch-port" data-schematic-port-id="source_port_2_1__stack1"><rect x="767.83691959206" y="475.02604756516405" width="5.436013590031999" height="5.436013590031999" opacity="0"/></g><text class="pin-number sch-pin-number" x="797.734994337236" y="475.026047565164" style="font-family: sans-serif;" fill="rgb(169, 0, 0)" text-anchor="middle" dominant-baseline="auto" font-size="20.385050962619996px" transform="">7</text><text class="pin-number sch-pin-label" x="838.505096262476" y="477.74405436018003" style="font-family: sans-serif;" fill="rgb(169, 0, 0)" text-anchor="start" dominant-baseline="middle" font-size="20.385050962619996px" transform="">SCL</text><line class="component-pin sch-component-pin sch-port-line" x1="930.91732729302" y1="355.43374858446" x2="930.91732729302" y2="301.07361268414" stroke-width="2.7180067950159996px"/><g class="sch-port" data-schematic-port-id="source_port_2_2__stack1"><rect x="928.199320498004" y="298.35560588912404" width="5.436013590031999" height="5.436013590031999" opacity="0"/></g><text class="pin-number sch-pin-number" x="928.199320498004" y="328.2536806343" style="font-family: sans-serif;" fill="rgb(169, 0, 0)" text-anchor="middle" dominant-baseline="auto" font-size="20.385050962619996px" transform="rotate(-90 928.199320498004 328.2536806343)">1</text><text class="pin-number sch-pin-label" x="930.91732729302" y="369.02378255954" style="font-family: sans-serif;" fill="rgb(169, 0, 0)" text-anchor="end" dominant-baseline="middle" font-size="20.385050962619996px" transform="rotate(-90 930.91732729302 369.02378255954)">VDD5V</text><line class="component-pin sch-component-pin sch-port-line" x1="958.09739524318" y1="355.43374858446" x2="958.09739524318" y2="301.07361268414" stroke-width="2.7180067950159996px"/><g class="sch-port" data-schematic-port-id="source_port_2_3__stack1"><rect x="955.379388448164" y="298.35560588912404" width="5.436013590031999" height="5.436013590031999" opacity="0"/></g><text class="pin-number sch-pin-number" x="955.379388448164" y="328.2536806343" style="font-family: sans-serif;" fill="rgb(169, 0, 0)" text-anchor="middle" dominant-baseline="auto" font-size="20.385050962619996px" transform="rotate(-90 955.379388448164 328.2536806343)">2</text><text class="pin-number sch-pin-label" x="958.09739524318" y="369.02378255954" style="font-family: sans-serif;" fill="rgb(169, 0, 0)" text-anchor="end" dominant-baseline="middle" font-size="20.385050962619996px" transform="rotate(-90 958.09739524318 369.02378255954)">VDD3V3</text><line class="component-pin sch-component-pin sch-port-line" x1="930.91732729302" y1="572.87429218574" x2="930.91732729302" y2="627.23442808606" stroke-width="2.7180067950159996px"/><g class="sch-port" data-schematic-port-id="source_port_2_4__stack1"><rect x="928.199320498004" y="624.516421291044" width="5.436013590031999" height="5.436013590031999" opacity="0"/></g><text class="pin-number sch-pin-number" x="928.199320498004" y="600.0543601359" style="font-family: sans-serif;" fill="rgb(169, 0, 0)" text-anchor="middle" dominant-baseline="auto" font-size="20.385050962619996px" transform="rotate(-90 928.199320498004 600.0543601359)">4</text><text class="pin-number sch-pin-label" x="930.91732729302" y="559.28425821066" style="font-family: sans-serif;" fill="rgb(169, 0, 0)" text-anchor="start" dominant-baseline="middle" font-size="20.385050962619996px" transform="rotate(-90 930.91732729302 559.28425821066)">GND</text><line class="component-pin sch-component-pin sch-port-line" x1="958.09739524318" y1="572.87429218574" x2="958.09739524318" y2="627.23442808606" stroke-width="2.7180067950159996px"/><g class="sch-port" data-schematic-port-id="source_port_2_5__stack1"><rect x="955.379388448164" y="624.516421291044" width="5.436013590031999" height="5.436013590031999" opacity="0"/></g><text class="pin-number sch-pin-number" x="955.379388448164" y="600.0543601359" style="font-family: sans-serif;" fill="rgb(169, 0, 0)" text-anchor="middle" dominant-baseline="auto" font-size="20.385050962619996px" transform="rotate(-90 955.379388448164 600.0543601359)">8</text><text class="pin-number sch-pin-label" x="958.09739524318" y="559.28425821066" style="font-family: sans-serif;" fill="rgb(169, 0, 0)" text-anchor="start" dominant-baseline="middle" font-size="20.385050962619996px" transform="rotate(-90 958.09739524318 559.28425821066)">DIR</text><line class="component-pin sch-component-pin sch-port-line" x1="1064.099660248804" y1="450.56398641002" x2="1115.741789354108" y2="450.56398641002" stroke-width="2.7180067950159996px"/><g class="sch-port" data-schematic-port-id="source_port_2_6__stack1"><circle class="component-pin sch-component-pin sch-port-terminal" cx="1118.4597961491238" cy="450.56398641002" r="2.7180067950159996" stroke-width="2.7180067950159996px"/><rect x="1115.7417893541078" y="447.845979615004" width="5.436013590031999" height="5.436013590031999" opacity="0"/></g><text class="pin-number sch-pin-number" x="1091.2797281989638" y="447.845979615004" style="font-family: sans-serif;" fill="rgb(169, 0, 0)" text-anchor="middle" dominant-baseline="auto" font-size="20.385050962619996px" transform="">3</text><text class="pin-number sch-pin-label" x="1050.5096262737238" y="450.56398641002" style="font-family: sans-serif;" fill="rgb(169, 0, 0)" text-anchor="end" dominant-baseline="middle" font-size="20.385050962619996px" transform="">OUT</text><line class="component-pin sch-component-pin sch-port-line" x1="1064.099660248804" y1="477.74405436018003" x2="1115.741789354108" y2="477.74405436018003" stroke-width="2.7180067950159996px"/><g class="sch-port" data-schematic-port-id="source_port_2_7__stack1"><circle class="component-pin sch-component-pin sch-port-terminal" cx="1118.4597961491238" cy="477.74405436018003" r="2.7180067950159996" stroke-width="2.7180067950159996px"/><rect x="1115.7417893541078" y="475.02604756516405" width="5.436013590031999" height="5.436013590031999" opacity="0"/></g><text class="pin-number sch-pin-number" x="1091.2797281989638" y="475.026047565164" style="font-family: sans-serif;" fill="rgb(169, 0, 0)" text-anchor="middle" dominant-baseline="auto" font-size="20.385050962619996px" transform="">5</text><text class="pin-number sch-pin-label" x="1050.5096262737238" y="477.74405436018003" style="font-family: sans-serif;" fill="rgb(169, 0, 0)" text-anchor="end" dominant-baseline="middle" font-size="20.385050962619996px" transform="">PGO</text></g><g class="schematic-port-hover sch-port-hover" data-schematic-port-id="source_port_0_0__stack1"><circle cx="129.1053227633" cy="178.76330690842002" r="5.436013590031999" fill="red" opacity="0"/></g><g class="schematic-port-hover sch-port-hover" data-schematic-port-id="source_port_0_1__stack1"><circle cx="129.1053227633" cy="260.3035107589" r="5.436013590031999" fill="red" opacity="0"/></g><g class="schematic-port-hover sch-port-hover" data-schematic-port-id="source_port_1_0__stack1"><circle cx="400.90600226489994" cy="178.76330690842002" r="5.436013590031999" fill="red" opacity="0"/></g><g class="schematic-port-hover sch-port-hover" data-schematic-port-id="source_port_1_1__stack1"><circle cx="400.90600226489994" cy="260.3035107589" r="5.436013590031999" fill="red" opacity="0"/></g><g class="schematic-port-hover sch-port-hover" data-schematic-port-id="source_port_2_0__stack1"><circle cx="770.554926387076" cy="450.56398641002" r="5.436013590031999" fill="red" opacity="0"/></g><g class="schematic-port-hover sch-port-hover" data-schematic-port-id="source_port_2_1__stack1"><circle cx="770.554926387076" cy="477.74405436018003" r="5.436013590031999" fill="red" opacity="0"/></g><g class="schematic-port-hover sch-port-hover" data-schematic-port-id="source_port_2_2__stack1"><circle cx="930.91732729302" cy="301.07361268414" r="5.436013590031999" fill="red" opacity="0"/></g><g class="schematic-port-hover sch-port-hover" data-schematic-port-id="source_port_2_3__stack1"><circle cx="958.09739524318" cy="301.07361268414" r="5.436013590031999" fill="red" opacity="0"/></g><g class="schematic-port-hover sch-port-hover" data-schematic-port-id="source_port_2_4__stack1"><circle cx="930.91732729302" cy="627.23442808606" r="5.436013590031999" fill="red" opacity="0"/></g><g class="schematic-port-hover sch-port-hover" data-schematic-port-id="source_port_2_5__stack1"><circle cx="958.09739524318" cy="627.23442808606" r="5.436013590031999" fill="red" opacity="0"/></g><g class="schematic-port-hover sch-port-hover" data-schematic-port-id="source_port_2_6__stack1"><circle cx="1118.4597961491238" cy="450.56398641002" r="5.436013590031999" fill="red" opacity="0"/></g><g class="schematic-port-hover sch-port-hover" data-schematic-port-id="source_port_2_7__stack1"><circle cx="1118.4597961491238" cy="477.74405436018003" r="5.436013590031999" fill="red" opacity="0"/></g><path class="net-label sch-net-label" data-circuit-json-type="schematic_net_label" data-schematic-net-label-id="schematic_net_label_0__stack1" d="
|
|
79
|
+
M 129.1053227633,151.58323895825998
|
|
80
|
+
L 115.51528878821999,144.24462061171678
|
|
81
|
+
L 115.51528878822,71.14835787108649
|
|
82
|
+
L 142.69535673837999,71.14835787108649
|
|
83
|
+
L 142.69535673837999,144.24462061171678
|
|
84
|
+
Z
|
|
85
|
+
" fill="rgba(255, 255, 255, 0.6)" stroke="rgb(132, 0, 0)" stroke-width="2.7180067950159996px"/><text class="net-label-text sch-net-label-text" data-circuit-json-type="schematic_net_label" data-schematic-net-label-id="schematic_net_label_0__stack1" x="129.1053227633" y="139.35220838068798" fill="rgb(132, 0, 0)" text-anchor="start" dominant-baseline="central" font-family="sans-serif" font-variant-numeric="tabular-nums" font-size="24.462061155143996px" transform="rotate(-90 129.1053227633 139.35220838068798)">V3V3</text><path class="net-label sch-net-label" data-circuit-json-type="schematic_net_label" data-schematic-net-label-id="schematic_net_label_1__stack1" d="
|
|
86
|
+
M 958.09739524318,273.89354473398
|
|
87
|
+
L 944.5073612681,266.5549263874368
|
|
88
|
+
L 944.5073612681,193.45866364680649
|
|
89
|
+
L 971.68742921826,193.45866364680649
|
|
90
|
+
L 971.68742921826,266.5549263874368
|
|
91
|
+
Z
|
|
92
|
+
" fill="rgba(255, 255, 255, 0.6)" stroke="rgb(132, 0, 0)" stroke-width="2.7180067950159996px"/><text class="net-label-text sch-net-label-text" data-circuit-json-type="schematic_net_label" data-schematic-net-label-id="schematic_net_label_1__stack1" x="958.09739524318" y="261.662514156408" fill="rgb(132, 0, 0)" text-anchor="start" dominant-baseline="central" font-family="sans-serif" font-variant-numeric="tabular-nums" font-size="24.462061155143996px" transform="rotate(-90 958.09739524318 261.662514156408)">V3V3</text><path class="net-label sch-net-label" data-circuit-json-type="schematic_net_label" data-schematic-net-label-id="schematic_net_label_2__stack1" d="
|
|
93
|
+
M 930.91732729302,654.41449603622
|
|
94
|
+
L 944.5073612681,661.7531143827632
|
|
95
|
+
L 944.5073612681,728.8516421290582
|
|
96
|
+
L 917.32729331794,728.8516421290582
|
|
97
|
+
L 917.32729331794,661.7531143827632
|
|
98
|
+
Z
|
|
99
|
+
" fill="rgba(255, 255, 255, 0.6)" stroke="rgb(132, 0, 0)" stroke-width="2.7180067950159996px"/><text class="net-label-text sch-net-label-text" data-circuit-json-type="schematic_net_label" data-schematic-net-label-id="schematic_net_label_2__stack1" x="930.91732729302" y="666.6455266137921" fill="rgb(132, 0, 0)" text-anchor="start" dominant-baseline="central" font-family="sans-serif" font-variant-numeric="tabular-nums" font-size="24.462061155143996px" transform="rotate(90 930.91732729302 666.6455266137921)">GND</text>
|
|
100
|
+
</g>
|
|
101
|
+
</svg>
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { NetLabelToTraceSolver } from "lib/solvers/NetLabelToTraceSolver/NetLabelToTraceSolver"
|
|
2
|
+
import { expect, test } from "bun:test"
|
|
3
|
+
import { SchematicTracePipelineSolver } from "lib/index"
|
|
4
|
+
import { findPerpendicularPathCrossings } from "lib/solvers/TraceCleanupSolver/sub-solver/findIntersectionsWithObstacles"
|
|
5
|
+
import type { InputProblem } from "lib/types/InputProblem"
|
|
6
|
+
import input from "../../assets/enc-scl-hop.json"
|
|
7
|
+
import "tests/fixtures/matcher"
|
|
8
|
+
|
|
9
|
+
const sclPins = ["R_ENC_SCL.2", "U_ENCODER.7"]
|
|
10
|
+
const solve = (problem: InputProblem) => {
|
|
11
|
+
const solver = new SchematicTracePipelineSolver(problem, {
|
|
12
|
+
hideRatsNet: true,
|
|
13
|
+
})
|
|
14
|
+
solver.solve()
|
|
15
|
+
expect(solver.solved).toBe(true)
|
|
16
|
+
return solver
|
|
17
|
+
}
|
|
18
|
+
const hasSclTrace = (solver: SchematicTracePipelineSolver) =>
|
|
19
|
+
solver
|
|
20
|
+
.netLabelToTraceSolver!.getOutput()
|
|
21
|
+
.traces.some((trace) =>
|
|
22
|
+
sclPins.every((pinId) => trace.pinIds.includes(pinId)),
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
// Geometry reconstructed from the ENC_SCL screenshot, not an exported input.
|
|
26
|
+
// SDA is explicitly wired; SCL is connected through its named net.
|
|
27
|
+
test("ENC_SCL routes across SDA instead of becoming two endpoint labels", () => {
|
|
28
|
+
const solver = solve(input as unknown as InputProblem)
|
|
29
|
+
const output = solver.netLabelToTraceSolver!.getOutput()
|
|
30
|
+
expect(
|
|
31
|
+
output.traces.some((trace) =>
|
|
32
|
+
["R_ENC_SDA.2", "U_ENCODER.6"].every((pinId) =>
|
|
33
|
+
trace.pinIds.includes(pinId),
|
|
34
|
+
),
|
|
35
|
+
),
|
|
36
|
+
).toBe(true)
|
|
37
|
+
expect(hasSclTrace(solver)).toBe(true)
|
|
38
|
+
expect(
|
|
39
|
+
output.netLabelPlacements.filter(
|
|
40
|
+
(label) => label.netId === "ENC_SCL" && label.pinIds.length === 1,
|
|
41
|
+
),
|
|
42
|
+
).toHaveLength(0)
|
|
43
|
+
expect(solver).toMatchSolverSnapshot(import.meta.path)
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
test("ENC_SCL recovers exactly one interior crossing of SDA", () => {
|
|
47
|
+
const solver = solve(input as unknown as InputProblem)
|
|
48
|
+
const traces = solver.netLabelToTraceSolver!.getOutput().traces
|
|
49
|
+
const scl = traces.find((trace) =>
|
|
50
|
+
sclPins.every((pinId) => trace.pinIds.includes(pinId)),
|
|
51
|
+
)!
|
|
52
|
+
const sda = traces.find((trace) => trace.pinIds.includes("R_ENC_SDA.2"))!
|
|
53
|
+
expect(
|
|
54
|
+
findPerpendicularPathCrossings(scl.tracePath, sda.tracePath, {
|
|
55
|
+
includeTerminalSegments: true,
|
|
56
|
+
}),
|
|
57
|
+
).toHaveLength(1)
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
test("ENC_SCL control: explicit wiring produces the available hop", () => {
|
|
61
|
+
const problem = structuredClone(input) as unknown as InputProblem
|
|
62
|
+
problem.directConnections.push({
|
|
63
|
+
pinIds: [sclPins[0]!, sclPins[1]!],
|
|
64
|
+
netId: "ENC_SCL",
|
|
65
|
+
})
|
|
66
|
+
const solver = solve(problem)
|
|
67
|
+
expect(hasSclTrace(solver)).toBe(true)
|
|
68
|
+
const output = solver.netLabelToTraceSolver!.getOutput()
|
|
69
|
+
const scl = output.traces.find((trace) =>
|
|
70
|
+
sclPins.every((pinId) => trace.pinIds.includes(pinId)),
|
|
71
|
+
)!
|
|
72
|
+
const sda = output.traces.find((trace) =>
|
|
73
|
+
trace.pinIds.includes("R_ENC_SDA.2"),
|
|
74
|
+
)!
|
|
75
|
+
expect(
|
|
76
|
+
findPerpendicularPathCrossings(scl.tracePath, sda.tracePath, {
|
|
77
|
+
includeTerminalSegments: true,
|
|
78
|
+
}),
|
|
79
|
+
).toHaveLength(1)
|
|
80
|
+
expect(solver).toMatchSolverSnapshot(import.meta.path, "explicit-hop")
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
test("ENC_SCL keeps labels when its elbow is blocked by a component", () => {
|
|
84
|
+
const problem = structuredClone(input) as unknown as InputProblem
|
|
85
|
+
problem.chips.push({
|
|
86
|
+
chipId: "BLOCKER",
|
|
87
|
+
center: { x: 2, y: 0.7 },
|
|
88
|
+
width: 0.5,
|
|
89
|
+
height: 0.5,
|
|
90
|
+
pins: [],
|
|
91
|
+
})
|
|
92
|
+
expect(hasSclTrace(solve(problem))).toBe(false)
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
test("ENC_SCL keeps labels across schematic sections", () => {
|
|
96
|
+
const problem = structuredClone(input) as unknown as InputProblem
|
|
97
|
+
problem.chips.find((chip) => chip.chipId === "R_ENC_SCL")!.sectionId =
|
|
98
|
+
"pullups"
|
|
99
|
+
problem.chips.find((chip) => chip.chipId === "U_ENCODER")!.sectionId =
|
|
100
|
+
"encoder"
|
|
101
|
+
expect(hasSclTrace(solve(problem))).toBe(false)
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
// Test the recovery stage directly so earlier routing cannot remove the obstacle.
|
|
105
|
+
test("ENC_SCL keeps labels when its elbow would require two hops", () => {
|
|
106
|
+
const pipeline = solve(input as unknown as InputProblem)
|
|
107
|
+
const stageInput = pipeline.netLabelToTraceSolver!.getConstructorParams()[0]
|
|
108
|
+
const sda = pipeline
|
|
109
|
+
.netLabelToTraceSolver!.getOutput()
|
|
110
|
+
.traces.find((trace) => trace.pinIds.includes("R_ENC_SDA.2"))!
|
|
111
|
+
const secondCrossing = {
|
|
112
|
+
...sda,
|
|
113
|
+
mspPairId: "second-crossing",
|
|
114
|
+
globalConnNetId: "other-net",
|
|
115
|
+
tracePath: [
|
|
116
|
+
{ x: 0, y: 0.7 },
|
|
117
|
+
{ x: 4.72, y: 0.7 },
|
|
118
|
+
],
|
|
119
|
+
}
|
|
120
|
+
const solver = new NetLabelToTraceSolver({
|
|
121
|
+
...stageInput,
|
|
122
|
+
traces: [...stageInput.traces, sda, secondCrossing],
|
|
123
|
+
netLabelPlacements: stageInput.netLabelPlacements.filter(
|
|
124
|
+
(label) => label.netId !== "ENC_SDA",
|
|
125
|
+
),
|
|
126
|
+
})
|
|
127
|
+
solver.solve()
|
|
128
|
+
expect(
|
|
129
|
+
solver
|
|
130
|
+
.getOutput()
|
|
131
|
+
.netLabelPlacements.filter((label) => label.netId === "ENC_SCL"),
|
|
132
|
+
).toHaveLength(2)
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
test("ground nets keep endpoint labels instead of elbow recovery", () => {
|
|
136
|
+
const problem = structuredClone(input) as unknown as InputProblem
|
|
137
|
+
problem.netConnections.find((net) => net.netId === "ENC_SCL")!.isGround = true
|
|
138
|
+
expect(hasSclTrace(solve(problem))).toBe(false)
|
|
139
|
+
})
|