@tscircuit/schematic-trace-solver 0.0.98 → 0.0.99
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 +310 -220
- package/lib/solvers/MspConnectionPairSolver/MspConnectionPairSolver.ts +19 -9
- package/lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver2/SchematicTraceSingleLineSolver2.ts +30 -0
- package/lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver2/generateEndpointCollisionDetours.ts +84 -0
- package/package.json +1 -1
- package/tests/bug-reports/bug-report-20260706T220324Z/__snapshots__/bug-report-20260706T220324Z.snap.svg +18 -18
- package/tests/bug-reports/bug-report-20260707T092615Z/__snapshots__/bug-report-20260707T092615Z.snap.svg +7 -7
- package/tests/bug-reports/bug-report-20260707T134549Z/__snapshots__/bug-report-20260707T134549Z.snap.svg +5 -7
- package/tests/bug-reports/bug-report-20260707T140410Z/__snapshots__/bug-report-20260707T140410Z.snap.svg +6 -12
- package/tests/examples/__snapshots__/example09.snap.svg +9 -13
- package/tests/examples/__snapshots__/example21.snap.svg +30 -32
- package/tests/examples/__snapshots__/example29.snap.svg +13 -19
- package/tests/repros/__snapshots__/repro129-host-custom-symbol-passives.snap.svg +60 -0
- package/tests/repros/assets/repro129-host-custom-symbol-passives.input.json +94 -0
- package/tests/repros/repro129-host-custom-symbol-passives.test.ts +16 -0
- package/tests/solvers/MspConnectionPairSolver/msp-connection-pair-solver-direct-connection-distance.test.ts +46 -0
- package/tests/solvers/SchematicTraceSingleLineSolver2/generate-endpoint-collision-detours.test.ts +38 -0
|
@@ -0,0 +1,60 @@
|
|
|
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.9000000000000004,1.25 1.9700000000000002,1.1099999999999999" data-type="line" data-label="" points="312.06477732793525,134.84480431848863 473.7921727395411,156.00539811066136" fill="none" stroke="hsl(248, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="0.9000000000000004,0.8499999999999999 1.9000000000000004,-0.7" data-type="line" data-label="" points="312.06477732793525,195.30364372469646 463.2118758434548,429.5816464237517" fill="none" stroke="hsl(248, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="0.9000000000000004,0.44999999999999996 1.9700000000000002,0.3500000000000001" data-type="line" data-label="" points="312.06477732793525,255.76248313090423 473.7921727395411,270.87719298245617" fill="none" stroke="hsl(248, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="0.9000000000000004,-1.3000000000000003 1.9000000000000004,-1.3" data-type="line" data-label="" points="312.06477732793525,520.2699055330635 463.2118758434548,520.2699055330634" fill="none" stroke="hsl(248, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="0.9000000000000004,1.25 1.9700000000000002,1.25 1.9700000000000002,1.1099999999999999" data-type="line" data-label="" points="312.06477732793525,134.84480431848863 473.7921727395411,134.84480431848863 473.7921727395411,156.00539811066136" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="0.9000000000000004,0.8499999999999999 1.2725000000000004,0.8499999999999999 1.2725000000000004,0.05000000000000007 1.9000000000000004,0.05000000000000007 1.9000000000000004,-0.7" data-type="line" data-label="" points="312.06477732793525,195.30364372469646 368.36707152496626,195.30364372469646 368.36707152496626,316.22132253711203 463.2118758434548,316.22132253711203 463.2118758434548,429.5816464237517" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="0.9000000000000004,0.44999999999999996 1.4350000000000003,0.44999999999999996 1.4350000000000003,0.2500000000000001 1.9700000000000002,0.2500000000000001 1.9700000000000002,0.3500000000000001" data-type="line" data-label="" points="312.06477732793525,255.76248313090423 392.9284750337382,255.76248313090423 392.9284750337382,285.9919028340081 473.7921727395411,285.9919028340081 473.7921727395411,270.87719298245617" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="0.9000000000000004,-1.3000000000000003 1.9000000000000004,-1.3" data-type="line" data-label="" points="312.06477732793525,520.2699055330635 463.2118758434548,520.2699055330634" fill="none" stroke="purple" stroke-width="1px"/></g><g><rect data-type="rect" data-label="schematic_component_0" data-x="1.9975000000000005" data-y="-1" x="414.08906882591106" y="429.58164642375175" width="127.71929824561391" height="90.68825910931167" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.00661607142857143"/></g><g><rect data-type="rect" data-label="schematic_component_1" data-x="2.2250000000000005" data-y="0.73" x="424.66936572199734" y="156.00539811066136" width="175.33063427800266" height="114.8717948717948" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.00661607142857143"/></g><g><rect data-type="rect" data-label="schematic_component_2" data-x="0" data-y="0" x="40" y="74.3859649122808" width="272.06477732793525" height="498.78542510121446" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.00661607142857143"/></g><g><rect data-type="rect" data-label="netId: .HOST > .pin2 to R1.pin1
|
|
2
|
+
globalConnNetId: connectivity_net1" data-x="1.2725000000000004" data-y="-0.17499999999999993" x="353.25236167341427" y="316.22132253711203" width="30.22941970310393" height="68.0161943319838" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.00661607142857143"/></g><g><rect data-type="rect" data-label="netId: .HOST > .pin4 to R1.pin2
|
|
3
|
+
globalConnNetId: connectivity_net3" data-x="1.4000000000000004" data-y="-1.0750000000000002" x="372.52361673414305" y="452.2537112010797" width="30.22941970310393" height="68.0161943319838" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.00661607142857143"/></g><g><rect data-type="rect" data-label="netId: .HOST > .pin1 to C1.pin1
|
|
4
|
+
globalConnNetId: connectivity_net0" data-x="1.9700000000000002" data-y="1.475" x="458.6774628879891" y="66.82860998650477" width="30.229419703103986" height="68.01619433198385" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.00661607142857143"/></g><g><rect data-type="rect" data-label="netId: .HOST > .pin3 to C1.pin2
|
|
5
|
+
globalConnNetId: connectivity_net2" data-x="1.4000000000000004" data-y="0.6749999999999999" x="372.52361673414305" y="187.7462887989205" width="30.22941970310393" height="68.01619433198377" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.00661607142857143"/></g><g><circle data-type="point" data-label="R1.1
|
|
6
|
+
y+" data-x="1.9000000000000004" data-y="-0.7" cx="463.2118758434548" cy="429.5816464237517" r="3" fill="hsl(226, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="R1.2
|
|
7
|
+
y-" data-x="1.9000000000000004" data-y="-1.3" cx="463.2118758434548" cy="520.2699055330634" r="3" fill="hsl(227, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="C1.1
|
|
8
|
+
y+" data-x="1.9700000000000002" data-y="1.1099999999999999" cx="473.7921727395411" cy="156.00539811066136" r="3" fill="hsl(121, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="C1.2
|
|
9
|
+
y-" data-x="1.9700000000000002" data-y="0.3500000000000001" cx="473.7921727395411" cy="270.87719298245617" r="3" fill="hsl(122, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="HOST.pin1
|
|
10
|
+
x+" data-x="0.9000000000000004" data-y="1.25" cx="312.06477732793525" cy="134.84480431848863" r="3" fill="hsl(50, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="HOST.pin2
|
|
11
|
+
x+" data-x="0.9000000000000004" data-y="0.8499999999999999" cx="312.06477732793525" cy="195.30364372469646" r="3" fill="hsl(51, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="HOST.pin3
|
|
12
|
+
x+" data-x="0.9000000000000004" data-y="0.44999999999999996" cx="312.06477732793525" cy="255.76248313090423" r="3" fill="hsl(52, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="HOST.pin4
|
|
13
|
+
x+" data-x="0.9000000000000004" data-y="-1.3000000000000003" cx="312.06477732793525" cy="520.2699055330635" r="3" fill="hsl(53, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="anchorPoint
|
|
14
|
+
orientation: y-" data-x="1.2725000000000004" data-y="0.05000000000000007" cx="368.36707152496626" cy="316.22132253711203" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g><circle data-type="point" data-label="anchorPoint
|
|
15
|
+
orientation: y+" data-x="1.4000000000000004" data-y="-1.3000000000000003" cx="387.63832658569504" cy="520.2699055330635" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g><circle data-type="point" data-label="anchorPoint
|
|
16
|
+
orientation: y+" data-x="1.9700000000000002" data-y="1.25" cx="473.7921727395411" cy="134.84480431848863" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g><circle data-type="point" data-label="anchorPoint
|
|
17
|
+
orientation: y+" data-x="1.4000000000000004" data-y="0.44999999999999996" cx="387.63832658569504" cy="255.76248313090423" 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[
|
|
18
|
+
document.currentScript.parentElement.addEventListener('mousemove', (e) => {
|
|
19
|
+
const svg = e.currentTarget;
|
|
20
|
+
const rect = svg.getBoundingClientRect();
|
|
21
|
+
const x = e.clientX - rect.left;
|
|
22
|
+
const y = e.clientY - rect.top;
|
|
23
|
+
const crosshair = svg.getElementById('crosshair');
|
|
24
|
+
const h = svg.getElementById('crosshair-h');
|
|
25
|
+
const v = svg.getElementById('crosshair-v');
|
|
26
|
+
const coords = svg.getElementById('coordinates');
|
|
27
|
+
|
|
28
|
+
crosshair.style.display = 'block';
|
|
29
|
+
h.setAttribute('x1', '0');
|
|
30
|
+
h.setAttribute('x2', '640');
|
|
31
|
+
h.setAttribute('y1', y);
|
|
32
|
+
h.setAttribute('y2', y);
|
|
33
|
+
v.setAttribute('x1', x);
|
|
34
|
+
v.setAttribute('x2', x);
|
|
35
|
+
v.setAttribute('y1', '0');
|
|
36
|
+
v.setAttribute('y2', '640');
|
|
37
|
+
|
|
38
|
+
// Calculate real coordinates using inverse transformation
|
|
39
|
+
const matrix = {"a":151.14709851551953,"c":0,"e":176.03238866396762,"b":0,"d":-151.14709851551953,"f":323.778677462888};
|
|
40
|
+
// Manually invert and apply the affine transform
|
|
41
|
+
// Since we only use translate and scale, we can directly compute:
|
|
42
|
+
// x' = (x - tx) / sx
|
|
43
|
+
// y' = (y - ty) / sy
|
|
44
|
+
const sx = matrix.a;
|
|
45
|
+
const sy = matrix.d;
|
|
46
|
+
const tx = matrix.e;
|
|
47
|
+
const ty = matrix.f;
|
|
48
|
+
const realPoint = {
|
|
49
|
+
x: (x - tx) / sx,
|
|
50
|
+
y: (y - ty) / sy // Flip y back since we used negative scale
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
coords.textContent = `(${realPoint.x.toFixed(2)}, ${realPoint.y.toFixed(2)})`;
|
|
54
|
+
coords.setAttribute('x', (x + 5).toString());
|
|
55
|
+
coords.setAttribute('y', (y - 5).toString());
|
|
56
|
+
});
|
|
57
|
+
document.currentScript.parentElement.addEventListener('mouseleave', () => {
|
|
58
|
+
document.currentScript.parentElement.getElementById('crosshair').style.display = 'none';
|
|
59
|
+
});
|
|
60
|
+
]]></script></svg>
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
{
|
|
2
|
+
"chips": [
|
|
3
|
+
{
|
|
4
|
+
"chipId": "schematic_component_0",
|
|
5
|
+
"center": { "x": 1.9975000000000005, "y": -1 },
|
|
6
|
+
"width": 0.845,
|
|
7
|
+
"height": 0.6000000000000001,
|
|
8
|
+
"pins": [
|
|
9
|
+
{
|
|
10
|
+
"pinId": "R1.1",
|
|
11
|
+
"x": 1.9000000000000004,
|
|
12
|
+
"y": -0.7,
|
|
13
|
+
"_facingDirection": "y+"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"pinId": "R1.2",
|
|
17
|
+
"x": 1.9000000000000004,
|
|
18
|
+
"y": -1.3,
|
|
19
|
+
"_facingDirection": "y-"
|
|
20
|
+
}
|
|
21
|
+
]
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"chipId": "schematic_component_1",
|
|
25
|
+
"center": { "x": 2.2250000000000005, "y": 0.73 },
|
|
26
|
+
"width": 1.1600000000000004,
|
|
27
|
+
"height": 0.7599999999999998,
|
|
28
|
+
"pins": [
|
|
29
|
+
{
|
|
30
|
+
"pinId": "C1.1",
|
|
31
|
+
"x": 1.9700000000000002,
|
|
32
|
+
"y": 1.1099999999999999,
|
|
33
|
+
"_facingDirection": "y+"
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"pinId": "C1.2",
|
|
37
|
+
"x": 1.9700000000000002,
|
|
38
|
+
"y": 0.3500000000000001,
|
|
39
|
+
"_facingDirection": "y-"
|
|
40
|
+
}
|
|
41
|
+
]
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"chipId": "schematic_component_2",
|
|
45
|
+
"center": { "x": 0, "y": 0 },
|
|
46
|
+
"width": 1.8000000000000007,
|
|
47
|
+
"height": 3.3,
|
|
48
|
+
"pins": [
|
|
49
|
+
{
|
|
50
|
+
"pinId": "HOST.pin1",
|
|
51
|
+
"x": 0.9000000000000004,
|
|
52
|
+
"y": 1.25
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"pinId": "HOST.pin2",
|
|
56
|
+
"x": 0.9000000000000004,
|
|
57
|
+
"y": 0.8499999999999999
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"pinId": "HOST.pin3",
|
|
61
|
+
"x": 0.9000000000000004,
|
|
62
|
+
"y": 0.44999999999999996
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
"pinId": "HOST.pin4",
|
|
66
|
+
"x": 0.9000000000000004,
|
|
67
|
+
"y": -1.3000000000000003
|
|
68
|
+
}
|
|
69
|
+
]
|
|
70
|
+
}
|
|
71
|
+
],
|
|
72
|
+
"directConnections": [
|
|
73
|
+
{
|
|
74
|
+
"pinIds": ["HOST.pin1", "C1.1"],
|
|
75
|
+
"netId": ".HOST > .pin1 to C1.pin1"
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"pinIds": ["HOST.pin2", "R1.1"],
|
|
79
|
+
"netId": ".HOST > .pin2 to R1.pin1"
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
"pinIds": ["HOST.pin3", "C1.2"],
|
|
83
|
+
"netId": ".HOST > .pin3 to C1.pin2"
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
"pinIds": ["HOST.pin4", "R1.2"],
|
|
87
|
+
"netId": ".HOST > .pin4 to R1.pin2"
|
|
88
|
+
}
|
|
89
|
+
],
|
|
90
|
+
"netConnections": [],
|
|
91
|
+
"textBoxes": [],
|
|
92
|
+
"availableNetLabelOrientations": {},
|
|
93
|
+
"maxMspPairDistance": 2.4
|
|
94
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { expect, test } from "bun:test"
|
|
2
|
+
import { SchematicTracePipelineSolver } from "lib/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver"
|
|
3
|
+
import "tests/fixtures/matcher"
|
|
4
|
+
import inputProblem from "./assets/repro129-host-custom-symbol-passives.input.json"
|
|
5
|
+
|
|
6
|
+
test("repro129: HOST custom symbol routes all passive connections", () => {
|
|
7
|
+
const solver = new SchematicTracePipelineSolver(inputProblem as any)
|
|
8
|
+
|
|
9
|
+
solver.solve()
|
|
10
|
+
|
|
11
|
+
expect(solver.schematicTraceLinesSolver!.solvedTracePaths).toHaveLength(4)
|
|
12
|
+
expect(solver.schematicTraceLinesSolver!.failedConnectionPairs).toHaveLength(
|
|
13
|
+
0,
|
|
14
|
+
)
|
|
15
|
+
expect(solver).toMatchSolverSnapshot(import.meta.path)
|
|
16
|
+
})
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { expect, test } from "bun:test"
|
|
2
|
+
import { MspConnectionPairSolver } from "lib/solvers/MspConnectionPairSolver/MspConnectionPairSolver"
|
|
3
|
+
import type { InputProblem } from "lib/types/InputProblem"
|
|
4
|
+
|
|
5
|
+
const createInputProblem = (): InputProblem => ({
|
|
6
|
+
chips: [
|
|
7
|
+
{
|
|
8
|
+
chipId: "U1",
|
|
9
|
+
center: { x: 0, y: 0 },
|
|
10
|
+
width: 1,
|
|
11
|
+
height: 1,
|
|
12
|
+
pins: [{ pinId: "U1.1", x: 0, y: 0, _facingDirection: "x+" }],
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
chipId: "U2",
|
|
16
|
+
center: { x: 2, y: 2 },
|
|
17
|
+
width: 1,
|
|
18
|
+
height: 1,
|
|
19
|
+
pins: [{ pinId: "U2.1", x: 2, y: 2, _facingDirection: "x-" }],
|
|
20
|
+
},
|
|
21
|
+
],
|
|
22
|
+
directConnections: [{ pinIds: ["U1.1", "U2.1"] }],
|
|
23
|
+
netConnections: [],
|
|
24
|
+
availableNetLabelOrientations: {},
|
|
25
|
+
maxMspPairDistance: 3,
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
test("two-pin direct connections use Euclidean max distance", () => {
|
|
29
|
+
const directConnectionSolver = new MspConnectionPairSolver({
|
|
30
|
+
inputProblem: createInputProblem(),
|
|
31
|
+
})
|
|
32
|
+
directConnectionSolver.solve()
|
|
33
|
+
|
|
34
|
+
const netConnectionProblem = createInputProblem()
|
|
35
|
+
netConnectionProblem.directConnections = []
|
|
36
|
+
netConnectionProblem.netConnections = [
|
|
37
|
+
{ pinIds: ["U1.1", "U2.1"], netId: "SIG" },
|
|
38
|
+
]
|
|
39
|
+
const netConnectionSolver = new MspConnectionPairSolver({
|
|
40
|
+
inputProblem: netConnectionProblem,
|
|
41
|
+
})
|
|
42
|
+
netConnectionSolver.solve()
|
|
43
|
+
|
|
44
|
+
expect(directConnectionSolver.mspConnectionPairs).toHaveLength(1)
|
|
45
|
+
expect(netConnectionSolver.mspConnectionPairs).toHaveLength(0)
|
|
46
|
+
})
|
package/tests/solvers/SchematicTraceSingleLineSolver2/generate-endpoint-collision-detours.test.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { expect, test } from "bun:test"
|
|
2
|
+
import { generateEndpointCollisionDetours } from "lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver2/generateEndpointCollisionDetours"
|
|
3
|
+
|
|
4
|
+
test("endpoint collision detours preserve both endpoint anchors", () => {
|
|
5
|
+
const path = [
|
|
6
|
+
{ x: 0, y: 1 },
|
|
7
|
+
{ x: 2, y: 1 },
|
|
8
|
+
{ x: 2, y: -1 },
|
|
9
|
+
]
|
|
10
|
+
|
|
11
|
+
const obstacle = {
|
|
12
|
+
minX: 1,
|
|
13
|
+
maxX: 3,
|
|
14
|
+
minY: 0,
|
|
15
|
+
maxY: 2,
|
|
16
|
+
kind: "chip" as const,
|
|
17
|
+
chipId: "U1",
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const detours = [0, 1].flatMap((collidingSegmentIndex) =>
|
|
21
|
+
generateEndpointCollisionDetours({
|
|
22
|
+
path,
|
|
23
|
+
collidingSegmentIndex,
|
|
24
|
+
obstacle,
|
|
25
|
+
}),
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
expect(detours.length).toBeGreaterThan(0)
|
|
29
|
+
expect(
|
|
30
|
+
detours.every(
|
|
31
|
+
(detour) =>
|
|
32
|
+
detour[0]?.x === path[0]?.x &&
|
|
33
|
+
detour[0]?.y === path[0]?.y &&
|
|
34
|
+
detour.at(-1)?.x === path.at(-1)?.x &&
|
|
35
|
+
detour.at(-1)?.y === path.at(-1)?.y,
|
|
36
|
+
),
|
|
37
|
+
).toBe(true)
|
|
38
|
+
})
|