@tscircuit/schematic-trace-solver 0.0.101 → 0.0.103

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.
Files changed (37) hide show
  1. package/dist/index.d.ts +14 -6
  2. package/dist/index.js +251 -66
  3. package/lib/solvers/AvailableNetOrientationSolver/AvailableNetOrientationSolver.ts +58 -3
  4. package/lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver2/SchematicTraceSingleLineSolver2.ts +13 -5
  5. package/lib/solvers/TraceOverlapShiftSolver/TraceOverlapIssueSolver/TraceOverlapIssueSolver.ts +168 -24
  6. package/lib/solvers/TraceOverlapShiftSolver/TraceOverlapShiftSolver.ts +128 -48
  7. package/package.json +1 -1
  8. package/site/bug-reports/bug-report-20260716T144856Z.page.tsx +4 -0
  9. package/site/bug-reports/bug-report-20260717T022934Z.page.tsx +4 -0
  10. package/site/bug-reports/bug-report-20260717T031704Z.page.tsx +4 -0
  11. package/site/bug-reports/bug-report-20260717T042845Z.page.tsx +4 -0
  12. package/tests/bug-reports/bug-report-20260706T213649Z/__snapshots__/bug-report-20260706T213649Z.snap.svg +3 -3
  13. package/tests/bug-reports/bug-report-20260706T220324Z/__snapshots__/bug-report-20260706T220324Z.snap.svg +3 -3
  14. package/tests/bug-reports/bug-report-20260707T092615Z/__snapshots__/bug-report-20260707T092615Z.snap.svg +5 -5
  15. package/tests/bug-reports/bug-report-20260707T140410Z/__snapshots__/bug-report-20260707T140410Z.snap.svg +3 -3
  16. package/tests/bug-reports/bug-report-20260716T144856Z/__snapshots__/bug-report-20260716T144856Z.snap.svg +149 -0
  17. package/tests/bug-reports/bug-report-20260716T144856Z/bug-report-20260716T144856Z.json +693 -0
  18. package/tests/bug-reports/bug-report-20260716T144856Z/bug-report-20260716T144856Z.test.ts +12 -0
  19. package/tests/bug-reports/bug-report-20260717T022934Z/__snapshots__/bug-report-20260717T022934Z.snap.svg +130 -0
  20. package/tests/bug-reports/bug-report-20260717T022934Z/bug-report-20260717T022934Z.json +543 -0
  21. package/tests/bug-reports/bug-report-20260717T022934Z/bug-report-20260717T022934Z.test.ts +12 -0
  22. package/tests/bug-reports/bug-report-20260717T031704Z/__snapshots__/bug-report-20260717T031704Z.snap.svg +48 -0
  23. package/tests/bug-reports/bug-report-20260717T031704Z/bug-report-20260717T031704Z.json +77 -0
  24. package/tests/bug-reports/bug-report-20260717T031704Z/bug-report-20260717T031704Z.test.ts +12 -0
  25. package/tests/bug-reports/bug-report-20260717T042845Z/__snapshots__/bug-report-20260717T042845Z.snap.svg +54 -0
  26. package/tests/bug-reports/bug-report-20260717T042845Z/bug-report-20260717T042845Z.json +113 -0
  27. package/tests/bug-reports/bug-report-20260717T042845Z/bug-report-20260717T042845Z.test.ts +12 -0
  28. package/tests/examples/__snapshots__/example11.snap.svg +19 -19
  29. package/tests/examples/__snapshots__/example19.snap.svg +3 -5
  30. package/tests/examples/__snapshots__/example29.snap.svg +13 -13
  31. package/tests/examples/__snapshots__/example37.snap.svg +4 -2
  32. package/tests/examples/example16.test.ts +22 -0
  33. package/tests/repros/__snapshots__/repro-rp2040-gamepad-trace-alignment.snap.svg +2 -8
  34. package/tests/repros/__snapshots__/repro47-endpoint-obstacle-detour.snap.svg +19 -19
  35. package/tests/repros/__snapshots__/trace-overlap-box-resistor.snap.svg +10 -10
  36. package/tests/repros/repro47-endpoint-obstacle-detour.test.ts +30 -0
  37. package/tests/solvers/TraceOverlapShiftSolver/TraceOverlapShiftSolver.test.ts +174 -0
@@ -1,21 +1,21 @@
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.6499999999999999,0.825 -0.6499999999999999,-0.825" data-type="line" data-label="" points="413.3333333333333,182.22222222222226 182.22222222222223,475.55555555555554" fill="none" stroke="hsl(224, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="1.25,0.825 -1.25,-0.825" data-type="line" data-label="" points="520,182.22222222222226 75.55555555555554,475.55555555555554" fill="none" stroke="hsl(224, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="0.49999999999999994,-0.725 -1.25,0.825" data-type="line" data-label="" points="386.66666666666663,457.7777777777778 75.55555555555554,182.22222222222226" fill="none" stroke="hsl(168, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="1.4,-0.725 -0.6499999999999999,0.825" data-type="line" data-label="" points="546.6666666666666,457.7777777777778 182.22222222222223,182.22222222222226" fill="none" stroke="hsl(168, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="0.6499999999999999,0.825 0.4499999999999999,0.825 0.4499999999999999,0.725 -0.1,0.725 -0.1,-0.825 -0.6499999999999999,-0.825" data-type="line" data-label="" points="413.3333333333333,182.22222222222226 377.77777777777777,182.22222222222226 377.77777777777777,200.00000000000003 280,200.00000000000003 280,475.55555555555554 182.22222222222223,475.55555555555554" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="1.25,0.825 1.4500000000000002,0.825 1.4500000000000002,0 -1.45,0 -1.45,-0.825 -1.25,-0.825" data-type="line" data-label="" points="520,182.22222222222226 555.5555555555557,182.22222222222226 555.5555555555557,328.8888888888889 40,328.8888888888889 40,475.55555555555554 75.55555555555554,475.55555555555554" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="0.5,-0.725 -0.07499999999999996,-0.725 -0.07499999999999996,0.17000000000000004 -1.45,0.17000000000000004 -1.45,0.825 -1.25,0.825" data-type="line" data-label="" points="386.66666666666663,457.7777777777778 284.44444444444446,457.7777777777778 284.44444444444446,298.6666666666667 40,298.6666666666667 40,182.22222222222226 75.55555555555554,182.22222222222226" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="1.4,-0.725 1.5999999999999999,-0.725 1.5999999999999999,0.28499999999999986 0.1,0.28499999999999986 0.1,0.825 -0.6499999999999999,0.825" data-type="line" data-label="" points="546.6666666666666,457.7777777777778 582.2222222222222,457.7777777777778 582.2222222222222,278.2222222222223 315.55555555555554,278.2222222222223 315.55555555555554,182.22222222222226 182.22222222222223,182.22222222222226" fill="none" stroke="purple" stroke-width="1px"/></g><g><rect data-type="rect" data-label="schematic_component_0" data-x="-0.95" data-y="0.825" x="75.55555555555554" y="121.7777777777778" width="106.66666666666669" height="120.88888888888891" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.005625"/></g><g><rect data-type="rect" data-label="schematic_component_1" data-x="0.95" data-y="0.825" x="413.33333333333326" y="121.7777777777778" width="106.66666666666669" height="120.88888888888891" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.005625"/></g><g><rect data-type="rect" data-label="schematic_component_2" data-x="-0.95" data-y="-0.825" x="75.55555555555554" y="415.1111111111111" width="106.66666666666669" height="120.88888888888891" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.005625"/></g><g><rect data-type="rect" data-label="schematic_component_3" data-x="0.95" data-y="-0.825" x="386.66666666666663" y="426.15489151111115" width="160" height="98.8013280888888" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.005625"/></g><g><rect data-type="rect" data-label="netId: .J1 &gt; .pin1 to .R1 &gt; .pin1
2
- globalConnNetId: connectivity_net2" data-x="0.21250000000000002" data-y="-0.5" x="317.77777777777777" y="377.7777777777778" width="35.55555555555554" height="80" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.005625"/></g><g><rect data-type="rect" data-label="netId: .J1 &gt; .pin3 to .R1 &gt; .pin2
3
- globalConnNetId: connectivity_net3" data-x="1.5999999999999999" data-y="-0.95" x="564.4444444444443" y="457.7777777777778" width="35.55555555555566" height="80" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.005625"/></g><g><rect data-type="rect" data-label="netId: .R2 &gt; .pin1 to .R3 &gt; .pin2
4
- globalConnNetId: connectivity_net0" data-x="0.4499999999999999" data-y="1.05" x="360" y="102.22222222222226" width="35.5555555555556" height="80" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.005625"/></g><g><rect data-type="rect" data-label="netId: .R2 &gt; .pin2 to .R3 &gt; .pin1
5
- globalConnNetId: connectivity_net1" data-x="1.4500000000000002" data-y="1.05" x="537.7777777777778" y="102.22222222222226" width="35.55555555555554" height="80" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.005625"/></g><g><circle data-type="point" data-label="R1.1
6
- x-" data-x="-1.25" data-y="0.825" cx="75.55555555555554" cy="182.22222222222226" r="3" fill="hsl(226, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="R1.2
7
- x+" data-x="-0.6499999999999999" data-y="0.825" cx="182.22222222222223" cy="182.22222222222226" r="3" fill="hsl(227, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="R2.1
8
- x-" data-x="0.6499999999999999" data-y="0.825" cx="413.3333333333333" cy="182.22222222222226" r="3" fill="hsl(107, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="R2.2
9
- x+" data-x="1.25" data-y="0.825" cx="520" cy="182.22222222222226" r="3" fill="hsl(108, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="R3.1
10
- x-" data-x="-1.25" data-y="-0.825" cx="75.55555555555554" cy="475.55555555555554" r="3" fill="hsl(348, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="R3.2
11
- x+" data-x="-0.6499999999999999" data-y="-0.825" cx="182.22222222222223" cy="475.55555555555554" r="3" fill="hsl(349, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="J1.1
12
- x-" data-x="0.49999999999999994" data-y="-0.725" cx="386.66666666666663" cy="457.7777777777778" r="3" fill="hsl(218, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="J1.2
13
- y-" data-x="0.95" data-y="-1.1028787352499998" cx="466.66666666666663" cy="524.9562195999999" r="3" fill="hsl(219, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="J1.3
14
- x+" data-x="1.4" data-y="-0.725" cx="546.6666666666666" cy="457.7777777777778" r="3" fill="hsl(220, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="anchorPoint
15
- orientation: y+" data-x="0.21250000000000002" data-y="-0.725" cx="335.55555555555554" cy="457.7777777777778" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g><circle data-type="point" data-label="anchorPoint
16
- orientation: y-" data-x="1.5999999999999999" data-y="-0.725" cx="582.2222222222222" cy="457.7777777777778" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g><circle data-type="point" data-label="anchorPoint
17
- orientation: y+" data-x="0.4499999999999999" data-y="0.825" cx="377.77777777777777" cy="182.22222222222226" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g><circle data-type="point" data-label="anchorPoint
18
- orientation: y+" data-x="1.4500000000000002" data-y="0.825" cx="555.5555555555557" cy="182.22222222222226" 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[
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.6499999999999999,0.825 -0.6499999999999999,-0.825" data-type="line" data-label="" points="419.0769230769231,177.84615384615384 195.0769230769231,462.1538461538462" fill="none" stroke="hsl(224, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="1.25,0.825 -1.25,-0.825" data-type="line" data-label="" points="522.4615384615386,177.84615384615384 91.69230769230768,462.1538461538462" fill="none" stroke="hsl(224, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="0.49999999999999994,-0.725 -1.25,0.825" data-type="line" data-label="" points="393.2307692307692,444.9230769230769 91.69230769230768,177.84615384615384" fill="none" stroke="hsl(168, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="1.4,-0.725 -0.6499999999999999,0.825" data-type="line" data-label="" points="548.3076923076924,444.9230769230769 195.0769230769231,177.84615384615384" fill="none" stroke="hsl(168, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="0.6499999999999999,0.825 0,0.825 0,-0.825 -0.6499999999999999,-0.825" data-type="line" data-label="" points="419.0769230769231,177.84615384615384 307.0769230769231,177.84615384615384 307.0769230769231,462.1538461538462 195.0769230769231,462.1538461538462" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="1.25,0.825 1.4500000000000002,0.825 1.4500000000000002,0 -1.3499999999999999,0 -1.3499999999999999,-0.825 -1.25,-0.825" data-type="line" data-label="" points="522.4615384615386,177.84615384615384 556.923076923077,177.84615384615384 556.923076923077,320 74.46153846153848,320 74.46153846153848,462.1538461538462 91.69230769230768,462.1538461538462" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="0.5,-0.725 0.2,-0.725 0.2,-1.365 -1.55,-1.365 -1.55,0.825 -1.25,0.825" data-type="line" data-label="" points="393.2307692307693,444.9230769230769 341.53846153846155,444.9230769230769 341.53846153846155,555.2 40,555.2 40,177.84615384615384 91.69230769230768,177.84615384615384" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="1.4,-0.725 1.5999999999999999,-0.725 1.5999999999999999,1.365 -0.1,1.365 -0.1,0.825 -0.6499999999999999,0.825" data-type="line" data-label="" points="548.3076923076924,444.9230769230769 582.7692307692307,444.9230769230769 582.7692307692307,84.79999999999998 289.84615384615387,84.79999999999998 289.84615384615387,177.84615384615384 195.0769230769231,177.84615384615384" fill="none" stroke="purple" stroke-width="1px"/></g><g><rect data-type="rect" data-label="schematic_component_0" data-x="-0.95" data-y="0.825" x="91.69230769230768" y="119.26153846153844" width="103.38461538461542" height="117.16923076923081" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.005803571428571428"/></g><g><rect data-type="rect" data-label="schematic_component_1" data-x="0.95" data-y="0.825" x="419.0769230769231" y="119.26153846153844" width="103.38461538461547" height="117.16923076923081" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.005803571428571428"/></g><g><rect data-type="rect" data-label="schematic_component_2" data-x="-0.95" data-y="-0.825" x="91.69230769230768" y="403.5692307692308" width="103.38461538461542" height="117.16923076923081" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.005803571428571428"/></g><g><rect data-type="rect" data-label="schematic_component_3" data-x="0.95" data-y="-0.825" x="393.2307692307693" y="414.2732025415385" width="155.07692307692315" height="95.76128722461533" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.005803571428571428"/></g><g><rect data-type="rect" data-label="netId: .J1 &gt; .pin1 to .R1 &gt; .pin1
2
+ globalConnNetId: connectivity_net2" data-x="0.35" data-y="-0.5" x="350.1538461538462" y="367.3846153846155" width="34.46153846153845" height="77.53846153846149" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.005803571428571428"/></g><g><rect data-type="rect" data-label="netId: .J1 &gt; .pin3 to .R1 &gt; .pin2
3
+ globalConnNetId: connectivity_net3" data-x="1.5999999999999999" data-y="-0.95" x="565.5384615384614" y="444.92307692307696" width="34.46153846153845" height="77.53846153846155" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.005803571428571428"/></g><g><rect data-type="rect" data-label="netId: .R2 &gt; .pin1 to .R3 &gt; .pin2
4
+ globalConnNetId: connectivity_net0" data-x="0.32499999999999996" data-y="1.05" x="345.84615384615387" y="100.30769230769229" width="34.46153846153845" height="77.53846153846155" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.005803571428571428"/></g><g><rect data-type="rect" data-label="netId: .R2 &gt; .pin2 to .R3 &gt; .pin1
5
+ globalConnNetId: connectivity_net1" data-x="1.4500000000000002" data-y="1.05" x="539.6923076923078" y="100.30769230769229" width="34.46153846153845" height="77.53846153846155" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.005803571428571428"/></g><g><circle data-type="point" data-label="R1.1
6
+ x-" data-x="-1.25" data-y="0.825" cx="91.69230769230768" cy="177.84615384615384" r="3" fill="hsl(226, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="R1.2
7
+ x+" data-x="-0.6499999999999999" data-y="0.825" cx="195.0769230769231" cy="177.84615384615384" r="3" fill="hsl(227, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="R2.1
8
+ x-" data-x="0.6499999999999999" data-y="0.825" cx="419.0769230769231" cy="177.84615384615384" r="3" fill="hsl(107, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="R2.2
9
+ x+" data-x="1.25" data-y="0.825" cx="522.4615384615386" cy="177.84615384615384" r="3" fill="hsl(108, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="R3.1
10
+ x-" data-x="-1.25" data-y="-0.825" cx="91.69230769230768" cy="462.1538461538462" r="3" fill="hsl(348, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="R3.2
11
+ x+" data-x="-0.6499999999999999" data-y="-0.825" cx="195.0769230769231" cy="462.1538461538462" r="3" fill="hsl(349, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="J1.1
12
+ x-" data-x="0.49999999999999994" data-y="-0.725" cx="393.2307692307692" cy="444.9230769230769" r="3" fill="hsl(218, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="J1.2
13
+ y-" data-x="0.95" data-y="-1.1028787352499998" cx="470.76923076923083" cy="510.0344897661538" r="3" fill="hsl(219, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="J1.3
14
+ x+" data-x="1.4" data-y="-0.725" cx="548.3076923076924" cy="444.9230769230769" r="3" fill="hsl(220, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="anchorPoint
15
+ orientation: y+" data-x="0.35" data-y="-0.725" cx="367.3846153846154" cy="444.9230769230769" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g><circle data-type="point" data-label="anchorPoint
16
+ orientation: y-" data-x="1.5999999999999999" data-y="-0.725" cx="582.7692307692307" cy="444.9230769230769" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g><circle data-type="point" data-label="anchorPoint
17
+ orientation: y+" data-x="0.32499999999999996" data-y="0.825" cx="363.0769230769231" cy="177.84615384615384" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g><circle data-type="point" data-label="anchorPoint
18
+ orientation: y+" data-x="1.4500000000000002" data-y="0.825" cx="556.923076923077" cy="177.84615384615384" 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[
19
19
  document.currentScript.parentElement.addEventListener('mousemove', (e) => {
20
20
  const svg = e.currentTarget;
21
21
  const rect = svg.getBoundingClientRect();
@@ -37,7 +37,7 @@ orientation: y+" data-x="1.4500000000000002" data-y="0.825" cx="555.555555555555
37
37
  v.setAttribute('y2', '640');
38
38
 
39
39
  // Calculate real coordinates using inverse transformation
40
- const matrix = {"a":177.77777777777777,"c":0,"e":297.77777777777777,"b":0,"d":-177.77777777777777,"f":328.8888888888889};
40
+ const matrix = {"a":172.30769230769232,"c":0,"e":307.0769230769231,"b":0,"d":-172.30769230769232,"f":320};
41
41
  // Manually invert and apply the affine transform
42
42
  // Since we only use translate and scale, we can directly compute:
43
43
  // x' = (x - tx) / sx
@@ -1,12 +1,12 @@
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.7999999999999998,-0.32499999999999996 2.25,-0.9" data-type="line" data-label="" points="458.8517829187396,320.9286898839137 500.642827694859,374.3283582089552" fill="none" stroke="hsl(112, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="1.7999999999999998,-0.975 2.25,-2.6500000000000004" data-type="line" data-label="" points="458.8517829187396,381.2935323383084 500.642827694859,536.849087893864" fill="none" stroke="hsl(157, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="1.7999999999999998,-0.32499999999999996 1.9249999999999998,-0.32499999999999996 1.9249999999999998,-1.1 2.25,-1.1 2.25,-0.9" data-type="line" data-label="" points="458.8517829187396,320.9286898839137 470.46040646766164,320.9286898839137 470.46040646766164,392.9021558872305 500.642827694859,392.9021558872305 500.642827694859,374.3283582089552" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="1.7999999999999998,-0.975 1.9902723250000003,-0.975 1.9902723250000003,-2.8500000000000005 2.25,-2.8500000000000005 2.25,-2.6500000000000004" data-type="line" data-label="" points="458.8517829187396,381.2935323383084 476.52218126036485,381.2935323383084 476.52218126036485,555.4228855721392 500.642827694859,555.4228855721392 500.642827694859,536.849087893864" fill="none" stroke="purple" stroke-width="1px"/></g><g><rect data-type="rect" data-label="schematic_component_0" data-x="0" data-y="0" x="124.52342470978448" y="40" width="334.32835820895514" height="501.49253731343276" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.010767857142857145"/></g><g><rect data-type="rect" data-label="schematic_component_4" data-x="2.25" data-y="-0.35" x="485.80908009950247" y="272.1724709784411" width="29.667495190713055" height="102.15588723051411" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.010767857142857145"/></g><g><rect data-type="rect" data-label="schematic_component_5" data-x="2.25" data-y="-2.1" x="485.80908009950247" y="434.6932006633499" width="29.667495190713055" height="102.15588723051405" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.010767857142857145"/></g><g><rect data-type="rect" data-label="netId: GND
2
- globalConnNetId: connectivity_net1" data-x="2.25" data-y="-3.0900000000000007" x="491.35592885572134" y="555.4228855721393" width="18.573797678275355" height="44.577114427860806" fill="#00000066" stroke="#000000" stroke-width="0.010767857142857145"/></g><g><rect data-type="rect" data-label="netId: U1.FB to R1.pin2
3
- globalConnNetId: connectivity_net0" data-x="1.9249999999999998" data-y="-0.09999999999999995" x="461.173507628524" y="279.1376451077943" width="18.573797678275298" height="41.791044776119406" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.010767857142857145"/></g><g><circle data-type="point" data-label="U1.3
4
- x+" data-x="1.7999999999999998" data-y="-0.975" cx="458.8517829187396" cy="381.2935323383084" r="3" fill="hsl(321, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.4
5
- x+" data-x="1.7999999999999998" data-y="-0.32499999999999996" cx="458.8517829187396" cy="320.9286898839137" r="3" fill="hsl(322, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="R1.2
6
- y-" data-x="2.25" data-y="-0.9" cx="500.642827694859" cy="374.3283582089552" r="3" fill="hsl(227, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="R2.2
7
- y-" data-x="2.25" data-y="-2.6500000000000004" cx="500.642827694859" cy="536.849087893864" r="3" fill="hsl(108, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="anchorPoint
8
- orientation: y-" data-x="2.25" data-y="-2.8500000000000005" cx="500.642827694859" cy="555.4228855721392" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g><circle data-type="point" data-label="anchorPoint
9
- orientation: y+" data-x="1.9249999999999998" data-y="-0.32499999999999996" cx="470.46040646766164" cy="320.9286898839137" 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[
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.7999999999999998,-0.32499999999999996 2.25,-0.9" data-type="line" data-label="" points="445.37313432835816,320.9286898839137 487.16417910447757,374.3283582089552" fill="none" stroke="hsl(112, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="1.7999999999999998,-0.975 2.25,-2.6500000000000004" data-type="line" data-label="" points="445.37313432835816,381.2935323383084 487.16417910447757,536.849087893864" fill="none" stroke="hsl(157, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="1.7999999999999998,-0.32499999999999996 1.9902723250000003,-0.32499999999999996 1.9902723250000003,-1.1 2.25,-1.1 2.25,-0.9" data-type="line" data-label="" points="445.37313432835816,320.9286898839137 463.0435326699834,320.9286898839137 463.0435326699834,392.9021558872305 487.16417910447757,392.9021558872305 487.16417910447757,374.3283582089552" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="1.7999999999999998,-0.975 1.9249999999999998,-0.975 1.9249999999999998,-2.8500000000000005 2.25,-2.8500000000000005 2.25,-2.6500000000000004" data-type="line" data-label="" points="445.37313432835816,381.2935323383084 456.9817578772802,381.2935323383084 456.9817578772802,555.4228855721392 487.16417910447757,555.4228855721392 487.16417910447757,536.849087893864" fill="none" stroke="purple" stroke-width="1px"/></g><g><rect data-type="rect" data-label="schematic_component_0" data-x="0" data-y="0" x="111.04477611940302" y="40" width="334.32835820895514" height="501.49253731343276" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.010767857142857145"/></g><g><rect data-type="rect" data-label="schematic_component_4" data-x="2.25" data-y="-0.35" x="472.33043150912107" y="272.1724709784411" width="29.667495190712998" height="102.15588723051411" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.010767857142857145"/></g><g><rect data-type="rect" data-label="schematic_component_5" data-x="2.25" data-y="-2.1" x="472.33043150912107" y="434.6932006633499" width="29.667495190712998" height="102.15588723051405" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.010767857142857145"/></g><g><rect data-type="rect" data-label="netId: GND
2
+ globalConnNetId: connectivity_net1" data-x="2.25" data-y="-3.0900000000000007" x="477.8772802653399" y="555.4228855721393" width="18.573797678275355" height="44.577114427860806" fill="#00000066" stroke="#000000" stroke-width="0.010767857142857145"/></g><g><rect data-type="rect" data-label="netId: U1.FB to R1.pin2
3
+ globalConnNetId: connectivity_net0" data-x="2.475" data-y="-1.1" x="487.1641791044775" y="383.6152570480929" width="41.79104477611946" height="18.573797678275298" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.010767857142857145"/></g><g><circle data-type="point" data-label="U1.3
4
+ x+" data-x="1.7999999999999998" data-y="-0.975" cx="445.37313432835816" cy="381.2935323383084" r="3" fill="hsl(321, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="U1.4
5
+ x+" data-x="1.7999999999999998" data-y="-0.32499999999999996" cx="445.37313432835816" cy="320.9286898839137" r="3" fill="hsl(322, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="R1.2
6
+ y-" data-x="2.25" data-y="-0.9" cx="487.16417910447757" cy="374.3283582089552" r="3" fill="hsl(227, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="R2.2
7
+ y-" data-x="2.25" data-y="-2.6500000000000004" cx="487.16417910447757" cy="536.849087893864" r="3" fill="hsl(108, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="anchorPoint
8
+ orientation: y-" data-x="2.25" data-y="-2.8500000000000005" cx="487.16417910447757" cy="555.4228855721392" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g><circle data-type="point" data-label="anchorPoint
9
+ orientation: x+" data-x="2.25" data-y="-1.1" cx="487.16417910447757" cy="392.9021558872305" 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[
10
10
  document.currentScript.parentElement.addEventListener('mousemove', (e) => {
11
11
  const svg = e.currentTarget;
12
12
  const rect = svg.getBoundingClientRect();
@@ -28,7 +28,7 @@ orientation: y+" data-x="1.9249999999999998" data-y="-0.32499999999999996" cx="4
28
28
  v.setAttribute('y2', '640');
29
29
 
30
30
  // Calculate real coordinates using inverse transformation
31
- const matrix = {"a":92.86898839137643,"c":0,"e":291.68760381426205,"b":0,"d":-92.86898839137643,"f":290.7462686567164};
31
+ const matrix = {"a":92.86898839137643,"c":0,"e":278.2089552238806,"b":0,"d":-92.86898839137643,"f":290.7462686567164};
32
32
  // Manually invert and apply the affine transform
33
33
  // Since we only use translate and scale, we can directly compute:
34
34
  // x' = (x - tx) / sx
@@ -1,5 +1,6 @@
1
1
  import { expect, test } from "bun:test"
2
2
  import { SchematicTracePipelineSolver } from "lib/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver"
3
+ import { countPathIntersections } from "lib/solvers/Example28Solver/geometry"
3
4
  import "tests/fixtures/matcher"
4
5
  import inputProblem from "./assets/repro47-endpoint-obstacle-detour.input.json"
5
6
 
@@ -15,5 +16,34 @@ test("repro47: endpoint obstacle detours route around nearby components", () =>
15
16
  )
16
17
  .sort(),
17
18
  ).toEqual([])
19
+
20
+ const j1Pin1Trace = solver.schematicTraceLinesSolver!.solvedTracePaths.find(
21
+ (trace) => trace.mspPairId === "J1.1-R1.1",
22
+ )
23
+ const bottomChipEdge = Math.min(
24
+ ...inputProblem.chips.map((chip) => chip.center.y - chip.height / 2),
25
+ )
26
+ expect(j1Pin1Trace).toBeDefined()
27
+ expect(
28
+ Math.min(...j1Pin1Trace!.tracePath.map((point) => point.y)),
29
+ ).toBeLessThan(bottomChipEdge)
30
+
31
+ const finalTraces = solver.netLabelTraceCollisionSolver!.getOutput().traces
32
+ const traceById = new Map(
33
+ finalTraces.map((trace) => [trace.mspPairId, trace]),
34
+ )
35
+ expect(
36
+ countPathIntersections(
37
+ traceById.get("J1.1-R1.1")!.tracePath,
38
+ traceById.get("R2.2-R3.1")!.tracePath,
39
+ ),
40
+ ).toBe(0)
41
+ expect(
42
+ countPathIntersections(
43
+ traceById.get("J1.3-R1.2")!.tracePath,
44
+ traceById.get("R2.1-R3.2")!.tracePath,
45
+ ),
46
+ ).toBe(0)
47
+
18
48
  expect(solver).toMatchSolverSnapshot(import.meta.path)
19
49
  })
@@ -0,0 +1,174 @@
1
+ import type { Point } from "@tscircuit/math-utils"
2
+ import { expect, test } from "bun:test"
3
+ import { countPathIntersections } from "lib/solvers/Example28Solver/geometry"
4
+ import type { SolvedTracePath } from "lib/solvers/SchematicTraceLinesSolver/SchematicTraceLinesSolver"
5
+ import { TraceOverlapShiftSolver } from "lib/solvers/TraceOverlapShiftSolver/TraceOverlapShiftSolver"
6
+ import type { InputProblem } from "lib/types/InputProblem"
7
+
8
+ const inputProblem: InputProblem = {
9
+ chips: [],
10
+ directConnections: [],
11
+ netConnections: [],
12
+ availableNetLabelOrientations: {},
13
+ }
14
+
15
+ const makeTrace = (
16
+ mspPairId: string,
17
+ globalConnNetId: string,
18
+ tracePath: Point[],
19
+ ) =>
20
+ ({
21
+ mspPairId,
22
+ globalConnNetId,
23
+ tracePath,
24
+ }) as SolvedTracePath
25
+
26
+ const createSolver = (inputTracePaths: SolvedTracePath[]) =>
27
+ new TraceOverlapShiftSolver({
28
+ inputProblem,
29
+ inputTracePaths,
30
+ globalConnMap: {} as any,
31
+ })
32
+
33
+ test("separates a collinear point contact using internal rails", () => {
34
+ const traceA = makeTrace("trace-a", "net-a", [
35
+ { x: 0.65, y: 0.825 },
36
+ { x: 0.45, y: 0.825 },
37
+ { x: 0, y: 0.825 },
38
+ { x: 0, y: -0.825 },
39
+ { x: -0.45, y: -0.825 },
40
+ { x: -0.65, y: -0.825 },
41
+ ])
42
+ const traceB = makeTrace("trace-b", "net-b", [
43
+ { x: 1.4, y: -0.725 },
44
+ { x: 1.6, y: -0.725 },
45
+ { x: 1.6, y: 1.365 },
46
+ { x: 0, y: 1.365 },
47
+ { x: 0, y: 0.825 },
48
+ { x: -0.65, y: 0.825 },
49
+ ])
50
+ const solver = createSolver([traceA, traceB])
51
+
52
+ expect(
53
+ solver
54
+ .findNextOverlapIssue()!
55
+ .overlappingTraceSegments.map(
56
+ (group) => group.pathsWithOverlap[0]!.traceSegmentIndex,
57
+ ),
58
+ ).toEqual([2, 3])
59
+
60
+ solver.solve()
61
+
62
+ const correctedA = solver.correctedTraceMap[traceA.mspPairId]!
63
+ const correctedB = solver.correctedTraceMap[traceB.mspPairId]!
64
+ expect(
65
+ countPathIntersections(correctedA.tracePath, correctedB.tracePath),
66
+ ).toBe(0)
67
+ expect(correctedA.tracePath[2]!.x).toBeCloseTo(0)
68
+ expect(correctedB.tracePath[3]!.x).toBeCloseTo(-0.1)
69
+ })
70
+
71
+ test("preserves deterministic separation for a compound overlap", () => {
72
+ const lowerTrace = makeTrace("lower", "lower-net", [
73
+ { x: 0, y: 0 },
74
+ { x: 1, y: 0 },
75
+ { x: 1, y: 1 },
76
+ { x: 1, y: 2 },
77
+ { x: 2, y: 2 },
78
+ ])
79
+ const upperTrace = makeTrace("upper", "upper-net", [
80
+ { x: 0, y: 0.2 },
81
+ { x: 1, y: 0.2 },
82
+ { x: 1, y: 1.2 },
83
+ { x: 1, y: 2.2 },
84
+ { x: 2, y: 2.2 },
85
+ ])
86
+ const solver = createSolver([lowerTrace, upperTrace])
87
+
88
+ const issue = solver.findNextOverlapIssue()
89
+ expect(issue?.interactionKind).toBe("overlap")
90
+ expect(
91
+ issue?.overlappingTraceSegments.map(
92
+ (group) => group.pathsWithOverlap.length,
93
+ ),
94
+ ).toEqual([2, 2])
95
+
96
+ solver.solve()
97
+
98
+ const correctedLower = solver.correctedTraceMap[lowerTrace.mspPairId]!
99
+ const correctedUpper = solver.correctedTraceMap[upperTrace.mspPairId]!
100
+ expect(correctedLower.tracePath.slice(1, 4).map((point) => point.x)).toEqual([
101
+ 0.9, 0.9, 0.9,
102
+ ])
103
+ expect(correctedUpper.tracePath.slice(1, 4).map((point) => point.x)).toEqual([
104
+ 1.1, 1.1, 1.1,
105
+ ])
106
+ })
107
+
108
+ test("chooses the simple-overlap separation with fewer intersections", () => {
109
+ const outerTrace = makeTrace("outer", "outer-net", [
110
+ { x: -1, y: -1 },
111
+ { x: 0, y: -1 },
112
+ { x: 0, y: 1 },
113
+ { x: 1, y: 1 },
114
+ ])
115
+ const innerTrace = makeTrace("inner", "inner-net", [
116
+ { x: -1, y: -0.5 },
117
+ { x: 0, y: -0.5 },
118
+ { x: 0, y: 0.5 },
119
+ { x: -1, y: 0.5 },
120
+ ])
121
+ const solver = createSolver([outerTrace, innerTrace])
122
+
123
+ const issue = solver.findNextOverlapIssue()
124
+ expect(issue?.interactionKind).toBe("overlap")
125
+ expect(
126
+ issue?.overlappingTraceSegments.map(
127
+ (group) => group.pathsWithOverlap.length,
128
+ ),
129
+ ).toEqual([1, 1])
130
+
131
+ solver.solve()
132
+
133
+ const correctedOuter = solver.correctedTraceMap[outerTrace.mspPairId]!
134
+ const correctedInner = solver.correctedTraceMap[innerTrace.mspPairId]!
135
+ expect(
136
+ countPathIntersections(correctedOuter.tracePath, correctedInner.tracePath),
137
+ ).toBe(0)
138
+ expect(correctedOuter.tracePath[1]!.x).toBeCloseTo(0.1)
139
+ expect(correctedInner.tracePath[1]!.x).toBeCloseTo(-0.1)
140
+ })
141
+
142
+ test("chooses the point-contact separation direction with fewer intersections", () => {
143
+ const innerTrace = makeTrace("inner", "inner-net", [
144
+ { x: 1.25, y: 0.825 },
145
+ { x: 1.45, y: 0.825 },
146
+ { x: 1.45, y: 0 },
147
+ { x: -1.45, y: 0 },
148
+ { x: -1.45, y: -0.825 },
149
+ { x: -1.25, y: -0.825 },
150
+ ])
151
+ const exteriorTrace = makeTrace("exterior", "exterior-net", [
152
+ { x: 0.5, y: -0.725 },
153
+ { x: -0.075, y: -0.725 },
154
+ { x: -0.075, y: -1.365 },
155
+ { x: -1.45, y: -1.365 },
156
+ { x: -1.45, y: -0.825 },
157
+ { x: -1.65, y: -0.825 },
158
+ ])
159
+ const solver = createSolver([innerTrace, exteriorTrace])
160
+
161
+ solver.solve()
162
+
163
+ const correctedInner = solver.correctedTraceMap[innerTrace.mspPairId]!
164
+ const correctedExterior = solver.correctedTraceMap[exteriorTrace.mspPairId]!
165
+ expect(
166
+ countPathIntersections(
167
+ correctedInner.tracePath,
168
+ correctedExterior.tracePath,
169
+ ),
170
+ ).toBe(0)
171
+ expect(correctedExterior.tracePath[3]!.x).toBeLessThan(
172
+ correctedInner.tracePath[3]!.x,
173
+ )
174
+ })