@tscircuit/schematic-trace-solver 0.0.41 → 0.0.43

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 (58) hide show
  1. package/dist/index.d.ts +118 -8
  2. package/dist/index.js +1067 -748
  3. package/lib/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver.ts +48 -16
  4. package/lib/solvers/TraceCleanupSolver/TraceCleanupSolver.ts +133 -0
  5. package/lib/solvers/TraceCleanupSolver/balanceZShapes.ts +200 -0
  6. package/lib/solvers/{TraceLabelOverlapAvoidanceSolver → TraceCleanupSolver}/hasCollisions.ts +1 -1
  7. package/lib/solvers/{TraceLabelOverlapAvoidanceSolver → TraceCleanupSolver}/hasCollisionsWithLabels.ts +1 -1
  8. package/lib/solvers/TraceCleanupSolver/minimizeTurnsWithFilteredLabels.ts +76 -0
  9. package/lib/solvers/{TraceLabelOverlapAvoidanceSolver → TraceCleanupSolver}/simplifyPath.ts +1 -1
  10. package/lib/solvers/{TraceLabelOverlapAvoidanceSolver → TraceCleanupSolver}/turnMinimization.ts +0 -2
  11. package/lib/solvers/TraceLabelOverlapAvoidanceSolver/TraceLabelOverlapAvoidanceSolver.ts +74 -192
  12. package/lib/solvers/TraceLabelOverlapAvoidanceSolver/rerouteCollidingTrace.ts +13 -24
  13. package/lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/LabelMergingSolver/LabelMergingSolver.ts +205 -0
  14. package/lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/OverlapAvoidanceStepSolver/OverlapAvoidanceStepSolver.ts +144 -0
  15. package/lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/SingleOverlapSolver/SingleOverlapSolver.ts +117 -0
  16. package/lib/solvers/TraceLabelOverlapAvoidanceSolver/tryFourPointDetour.ts +104 -0
  17. package/lib/solvers/TraceLabelOverlapAvoidanceSolver/trySnipAndReconnect.ts +24 -154
  18. package/package.json +1 -1
  19. package/site/examples/example26.page.tsx +4 -0
  20. package/tests/assets/1.input.json +379 -0
  21. package/tests/assets/2.input.json +330 -0
  22. package/tests/assets/3.input.json +388 -0
  23. package/tests/assets/MergedNetLabelObstacles.test.input.json +154 -0
  24. package/tests/assets/OverlapAvoidanceStepSolver.test.input.json +682 -0
  25. package/tests/assets/SingleOverlapSolver.test.input.json +170 -0
  26. package/tests/assets/TraceCleanupSolver.test.input.json +216 -0
  27. package/tests/assets/TraceLabelOverlapAvoidanceSolver.test.input.json +424 -0
  28. package/tests/assets/example26.json +1206 -0
  29. package/tests/examples/__snapshots__/example02.snap.svg +1 -1
  30. package/tests/examples/__snapshots__/example09.snap.svg +34 -34
  31. package/tests/examples/__snapshots__/example11.snap.svg +13 -13
  32. package/tests/examples/__snapshots__/example12.snap.svg +3 -3
  33. package/tests/examples/__snapshots__/example13.snap.svg +12 -12
  34. package/tests/examples/__snapshots__/example16.snap.svg +4 -4
  35. package/tests/examples/__snapshots__/example19.snap.svg +9 -9
  36. package/tests/examples/__snapshots__/example28.snap.svg +3 -3
  37. package/tests/examples/__snapshots__/example29.snap.svg +1208 -0
  38. package/tests/examples/example29.test.ts +13 -0
  39. package/tests/solvers/TraceCleanupSolver/TraceCleanupSolver.test.ts +19 -0
  40. package/tests/solvers/TraceCleanupSolver/__snapshots__/TraceCleanupSolver.snap.svg +119 -0
  41. package/tests/solvers/TraceLabelOverlapAvoidanceSolver/TraceLabelOverlapAvoidanceSolver.test.ts +18 -0
  42. package/tests/solvers/TraceLabelOverlapAvoidanceSolver/__snapshots__/TraceLabelOverlapAvoidanceSolver.snap.svg +243 -0
  43. package/tests/solvers/TraceLabelOverlapAvoidanceSolver/renderComparisonView/__snapshots__/renderComparisonView01.snap.svg +223 -0
  44. package/tests/solvers/TraceLabelOverlapAvoidanceSolver/renderComparisonView/__snapshots__/renderComparisonView02.snap.svg +205 -0
  45. package/tests/solvers/TraceLabelOverlapAvoidanceSolver/renderComparisonView/__snapshots__/renderComparisonView03.snap.svg +184 -0
  46. package/tests/solvers/TraceLabelOverlapAvoidanceSolver/renderComparisonView/renderComparisonView01.test.ts +29 -0
  47. package/tests/solvers/TraceLabelOverlapAvoidanceSolver/renderComparisonView/renderComparisonView02.test.ts +27 -0
  48. package/tests/solvers/TraceLabelOverlapAvoidanceSolver/renderComparisonView/renderComparisonView03.test.ts +39 -0
  49. package/tests/solvers/TraceLabelOverlapAvoidanceSolver/sub-solver/MergedNetLabelObstacles.test.ts +14 -0
  50. package/tests/solvers/TraceLabelOverlapAvoidanceSolver/sub-solver/OverlapAvoidanceStepSolver.test.ts +20 -0
  51. package/tests/solvers/TraceLabelOverlapAvoidanceSolver/sub-solver/SingleOverlapSolver.test.ts +10 -0
  52. package/tests/solvers/TraceLabelOverlapAvoidanceSolver/sub-solver/__snapshots__/MergedNetLabelObstacles.snap.svg +140 -0
  53. package/tests/solvers/TraceLabelOverlapAvoidanceSolver/sub-solver/__snapshots__/OverlapAvoidanceStepSolver.snap.svg +216 -0
  54. package/tests/solvers/TraceLabelOverlapAvoidanceSolver/sub-solver/__snapshots__/SingleOverlapSolver.snap.svg +125 -0
  55. package/lib/solvers/TraceLabelOverlapAvoidanceSolver/balanceLShapes.ts +0 -207
  56. package/lib/solvers/TraceLabelOverlapAvoidanceSolver/minimizeTurnsWithFilteredLabels.ts +0 -66
  57. /package/lib/solvers/{TraceLabelOverlapAvoidanceSolver → TraceCleanupSolver}/countTurns.ts +0 -0
  58. /package/lib/solvers/{TraceLabelOverlapAvoidanceSolver → TraceCleanupSolver}/tryConnectPoints.ts +0 -0
@@ -0,0 +1,29 @@
1
+ import { MergedNetLabelObstacleSolver } from "lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/LabelMergingSolver/LabelMergingSolver"
2
+ import { expect } from "bun:test"
3
+ import { test } from "bun:test"
4
+ import {
5
+ getSvgFromGraphicsObject,
6
+ stackGraphicsHorizontally,
7
+ } from "graphics-debug"
8
+ import { NetLabelPlacementSolver } from "lib/solvers/NetLabelPlacementSolver/NetLabelPlacementSolver"
9
+ import inputData from "../../../assets/1.input.json"
10
+
11
+ test("NetLabelPlacementSolver-to-MergedNetLabelObstacles snapshot", () => {
12
+ const solver1 = new MergedNetLabelObstacleSolver(
13
+ inputData.mergedNetLabelObstacleSolver as any,
14
+ )
15
+ const solver2 = new NetLabelPlacementSolver(
16
+ inputData.netLabelPlacementSolver as any,
17
+ )
18
+ solver1.solve()
19
+ solver2.solve()
20
+ const sideBySide = getSvgFromGraphicsObject(
21
+ stackGraphicsHorizontally([solver2.visualize(), solver1.visualize()], {
22
+ titles: ["NetLabelPlacementSolver", "MergedNetLabelObstacles"],
23
+ }),
24
+ {
25
+ backgroundColor: "white",
26
+ },
27
+ )
28
+ expect(sideBySide).toMatchSvgSnapshot(import.meta.path)
29
+ })
@@ -0,0 +1,27 @@
1
+ import { MergedNetLabelObstacleSolver } from "lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/LabelMergingSolver/LabelMergingSolver"
2
+ import { expect } from "bun:test"
3
+ import { test } from "bun:test"
4
+ import {
5
+ getSvgFromGraphicsObject,
6
+ stackGraphicsHorizontally,
7
+ } from "graphics-debug"
8
+ import { SingleOverlapSolver } from "lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/SingleOverlapSolver/SingleOverlapSolver"
9
+ import inputData from "../../../assets/2.input.json"
10
+
11
+ test("MergedNetLabelObstaclesSolver-to-SingleOverlapSolver snapshot", () => {
12
+ const solver1 = new MergedNetLabelObstacleSolver(
13
+ inputData.mergedNetLabelObstacleSolver as any,
14
+ )
15
+ const solver2 = new SingleOverlapSolver(inputData.singleOverlapSolver as any)
16
+ solver1.solve()
17
+ solver2.solve()
18
+ const sideBySide = getSvgFromGraphicsObject(
19
+ stackGraphicsHorizontally([solver1.visualize(), solver2.visualize()], {
20
+ titles: ["MergedNetLabelObstaclesSolver", "SingleOverlapSolver"],
21
+ }),
22
+ {
23
+ backgroundColor: "white",
24
+ },
25
+ )
26
+ expect(sideBySide).toMatchSvgSnapshot(import.meta.path)
27
+ })
@@ -0,0 +1,39 @@
1
+ import { expect } from "bun:test"
2
+ import { test } from "bun:test"
3
+ import {
4
+ getSvgFromGraphicsObject,
5
+ stackGraphicsHorizontally,
6
+ } from "graphics-debug"
7
+ import { SingleOverlapSolver } from "lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/SingleOverlapSolver/SingleOverlapSolver"
8
+ import inputData from "../../../assets/3.input.json"
9
+ import { TraceCleanupSolver } from "lib/solvers/TraceCleanupSolver/TraceCleanupSolver"
10
+
11
+ test("SingleOverlapSolver-to-TraceCleanupSolver snapshot", () => {
12
+ // Convert targetTraceIds to Set
13
+ // @ts-expect-error
14
+ inputData.traceCleanupSolver.targetTraceIds = new Set(
15
+ inputData.traceCleanupSolver.targetTraceIds,
16
+ )
17
+
18
+ // Convert mergedLabelNetIdMap arrays to Sets
19
+ // @ts-expect-error
20
+ inputData.traceCleanupSolver.mergedLabelNetIdMap = Object.fromEntries(
21
+ Object.entries(inputData.traceCleanupSolver.mergedLabelNetIdMap).map(
22
+ ([key, value]) => [key, new Set(value)],
23
+ ),
24
+ )
25
+
26
+ const solver1 = new TraceCleanupSolver(inputData.traceCleanupSolver as any)
27
+ const solver2 = new SingleOverlapSolver(inputData.singleOverlapSolver as any)
28
+ solver1.solve()
29
+ solver2.solve()
30
+ const sideBySide = getSvgFromGraphicsObject(
31
+ stackGraphicsHorizontally([solver2.visualize(), solver1.visualize()], {
32
+ titles: ["SingleOverlapSolver", "TraceCleanupSolver"],
33
+ }),
34
+ {
35
+ backgroundColor: "white",
36
+ },
37
+ )
38
+ expect(sideBySide).toMatchSvgSnapshot(import.meta.path)
39
+ })
@@ -0,0 +1,14 @@
1
+ import { MergedNetLabelObstacleSolver } from "lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/LabelMergingSolver/LabelMergingSolver"
2
+ import { expect } from "bun:test"
3
+ import { test } from "bun:test"
4
+ import inputData from "../../../assets/MergedNetLabelObstacles.test.input.json"
5
+
6
+ test("LabelMergingSolver snapshot", () => {
7
+ const solver = new MergedNetLabelObstacleSolver({
8
+ netLabelPlacements: inputData.netLabelPlacements as any,
9
+ inputProblem: inputData.inputProblem as any,
10
+ traces: inputData.traces as any,
11
+ })
12
+ solver.solve()
13
+ expect(solver).toMatchSolverSnapshot(import.meta.path)
14
+ })
@@ -0,0 +1,20 @@
1
+ import { OverlapAvoidanceStepSolver } from "lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/OverlapAvoidanceStepSolver/OverlapAvoidanceStepSolver"
2
+ import { expect } from "bun:test"
3
+ import { test } from "bun:test"
4
+ import inputData from "../../../assets/OverlapAvoidanceStepSolver.test.input.json"
5
+
6
+ test("OverlapAvoidanceStepSolver snapshot", () => {
7
+ const solver = new OverlapAvoidanceStepSolver({
8
+ inputProblem: inputData.problem as any,
9
+ traces: inputData.traces as any,
10
+ netLabelPlacements: inputData.netLabelPlacements as any,
11
+ mergedLabelNetIdMap: Object.fromEntries(
12
+ Object.entries(inputData.mergedLabelNetIdMap).map(([k, v]) => [
13
+ k,
14
+ new Set(v as any),
15
+ ]),
16
+ ),
17
+ } as any)
18
+ solver.solve()
19
+ expect(solver).toMatchSolverSnapshot(import.meta.path)
20
+ })
@@ -0,0 +1,10 @@
1
+ import { expect } from "bun:test"
2
+ import { test } from "bun:test"
3
+ import { SingleOverlapSolver } from "lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/SingleOverlapSolver/SingleOverlapSolver"
4
+ import inputData from "../../../assets/SingleOverlapSolver.test.input.json"
5
+
6
+ test("SingleOverlapSolver snapshot", () => {
7
+ const solver = new SingleOverlapSolver(inputData as any)
8
+ solver.solve()
9
+ expect(solver).toMatchSolverSnapshot(import.meta.path)
10
+ })
@@ -0,0 +1,140 @@
1
+ <svg width="640" height="640" viewBox="0 0 640 640" xmlns="http://www.w3.org/2000/svg">
2
+ <rect width="100%" height="100%" fill="white" />
3
+ <g>
4
+ <circle data-type="point" data-label="U1.1
5
+ x+" data-x="1.2000000000000002" data-y="-0.30000000000000004" cx="308.80000000000007" cy="227.88" r="3" fill="hsl(319, 100%, 50%, 0.8)" />
6
+ </g>
7
+ <g>
8
+ <circle data-type="point" data-label="U1.2
9
+ x-" data-x="-1.2000000000000002" data-y="-0.30000000000000004" cx="40" cy="227.88" r="3" fill="hsl(320, 100%, 50%, 0.8)" />
10
+ </g>
11
+ <g>
12
+ <circle data-type="point" data-label="U1.3
13
+ x+" data-x="1.2000000000000002" data-y="0.09999999999999998" cx="308.80000000000007" cy="183.08" r="3" fill="hsl(321, 100%, 50%, 0.8)" />
14
+ </g>
15
+ <g>
16
+ <circle data-type="point" data-label="U1.4
17
+ x-" data-x="-1.2000000000000002" data-y="0.30000000000000004" cx="40" cy="160.68" r="3" fill="hsl(322, 100%, 50%, 0.8)" />
18
+ </g>
19
+ <g>
20
+ <circle data-type="point" data-label="U1.5
21
+ x-" data-x="-1.2000000000000002" data-y="0.10000000000000003" cx="40" cy="183.07999999999998" r="3" fill="hsl(323, 100%, 50%, 0.8)" />
22
+ </g>
23
+ <g>
24
+ <circle data-type="point" data-label="U1.6
25
+ x-" data-x="-1.2000000000000002" data-y="-0.09999999999999998" cx="40" cy="205.48" r="3" fill="hsl(324, 100%, 50%, 0.8)" />
26
+ </g>
27
+ <g>
28
+ <circle data-type="point" data-label="U1.7
29
+ x+" data-x="1.2000000000000002" data-y="-0.10000000000000003" cx="308.80000000000007" cy="205.48000000000002" r="3" fill="hsl(325, 100%, 50%, 0.8)" />
30
+ </g>
31
+ <g>
32
+ <circle data-type="point" data-label="U1.8
33
+ x+" data-x="1.2000000000000002" data-y="0.30000000000000004" cx="308.80000000000007" cy="160.68" r="3" fill="hsl(326, 100%, 50%, 0.8)" />
34
+ </g>
35
+ <g>
36
+ <circle data-type="point" data-label="J1.1
37
+ x-" data-x="1.6" data-y="-1.895" cx="353.6" cy="406.52" r="3" fill="hsl(218, 100%, 50%, 0.8)" />
38
+ </g>
39
+ <g>
40
+ <circle data-type="point" data-label="J1.2
41
+ x-" data-x="1.6" data-y="-2.095" cx="353.6" cy="428.92" r="3" fill="hsl(219, 100%, 50%, 0.8)" />
42
+ </g>
43
+ <g>
44
+ <circle data-type="point" data-label="J1.3
45
+ x-" data-x="1.6" data-y="-2.295" cx="353.6" cy="451.31999999999994" r="3" fill="hsl(220, 100%, 50%, 0.8)" />
46
+ </g>
47
+ <g>
48
+ <polyline data-points="1.2000000000000002,-0.30000000000000004 1.6,-2.295" data-type="line" data-label="" points="308.80000000000007,227.88 353.6,451.31999999999994" fill="none" stroke="hsl(157, 100%, 50%, 0.1)" stroke-width="1" stroke-dasharray="4 2" />
49
+ </g>
50
+ <g>
51
+ <polyline data-points="1.2000000000000002,0.30000000000000004 1.6,-1.895" data-type="line" data-label="" points="308.80000000000007,160.68 353.6,406.52" fill="none" stroke="hsl(190, 100%, 50%, 0.1)" stroke-width="1" stroke-dasharray="4 2" />
52
+ </g>
53
+ <g>
54
+ <polyline data-points="1.2000000000000002,-0.30000000000000004 1.4000000000000001,-0.30000000000000004 1.4000000000000001,-1.2974999999999999 1.4000000000000001,-2.295 1.6,-2.295" data-type="line" data-label="" points="308.80000000000007,227.88 331.20000000000005,227.88 331.20000000000005,339.6 331.20000000000005,451.31999999999994 353.6,451.31999999999994" fill="none" stroke="blue" stroke-width="1" />
55
+ </g>
56
+ <g>
57
+ <polyline data-points="1.149,-1.995 1.5990000000000002,-1.995 1.5990000000000002,-1.795 1.149,-1.795 1.149,-1.995" data-type="line" data-label="" points="303.088,417.72 353.48800000000006,417.72 353.48800000000006,395.32 303.088,395.32 303.088,417.72" fill="none" stroke="hsl(296, 100%, 50%, 1)" stroke-width="1" stroke-dasharray="4 4" />
58
+ </g>
59
+ <g>
60
+ <polyline data-points="1.374,-1.895 1.374,-1.995" data-type="line" data-label="" points="328.288,406.52 328.288,417.72" fill="none" stroke="hsl(296, 100%, 50%, 1)" stroke-width="1" stroke-dasharray="2 2" />
61
+ </g>
62
+ <g>
63
+ <polyline data-points="1.149,-2.1950000000000003 1.5990000000000002,-2.1950000000000003 1.5990000000000002,-1.995 1.149,-1.995 1.149,-2.1950000000000003" data-type="line" data-label="" points="303.088,440.12 353.48800000000006,440.12 353.48800000000006,417.72 303.088,417.72 303.088,440.12" fill="none" stroke="hsl(296, 100%, 50%, 1)" stroke-width="1" stroke-dasharray="4 4" />
64
+ </g>
65
+ <g>
66
+ <polyline data-points="1.374,-2.095 1.374,-1.995" data-type="line" data-label="" points="328.288,428.92 328.288,417.72" fill="none" stroke="hsl(296, 100%, 50%, 1)" stroke-width="1" stroke-dasharray="2 2" />
67
+ </g>
68
+ <g>
69
+ <rect data-type="rect" data-label="schematic_component_0" data-x="0" data-y="0" x="40" y="138.28" width="268.80000000000007" height="112" fill="hsl(24, 100%, 50%, 0.1)" stroke="black" stroke-width="0.008928571428571428" />
70
+ </g>
71
+ <g>
72
+ <rect data-type="rect" data-label="schematic_component_1" data-x="2.7" data-y="-2.095" x="353.6" y="384.12" width="246.39999999999998" height="89.60000000000002" fill="hsl(24, 100%, 50%, 0.1)" stroke="black" stroke-width="0.008928571428571428" />
73
+ </g>
74
+ <g>
75
+ <rect data-type="rect" data-label="connectivity_net0" data-x="1.4000000000000001" data-y="-2.52" x="320" y="451.31999999999994" width="22.40000000000009" height="50.40000000000009" fill="none" stroke="hsl(40, 100%, 50%, 1)" stroke-width="0.008928571428571428" />
76
+ </g>
77
+ <g>
78
+ <rect data-type="rect" data-label="connectivity_net1" data-x="1.4260000000000002" data-y="0.30000000000000004" x="308.91200000000003" y="149.48" width="50.400000000000034" height="22.400000000000006" fill="none" stroke="hsl(40, 100%, 50%, 1)" stroke-width="0.008928571428571428" />
79
+ </g>
80
+ <g>
81
+ <rect data-type="rect" data-label="merged-group-J1-x-" data-x="1.374" data-y="-1.995" x="303.088" y="395.32" width="50.400000000000034" height="44.80000000000001" fill="hsl(296, 100%, 50%, 0.2)" stroke="hsl(296, 100%, 50%, 1)" stroke-width="0.008928571428571428" />
82
+ </g>
83
+ <g id="crosshair" style="display: none">
84
+ <line id="crosshair-h" y1="0" y2="640" stroke="#666" stroke-width="0.5" />
85
+ <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>
86
+ </g>
87
+ <script>
88
+ <![CDATA[
89
+ document.currentScript.parentElement.addEventListener('mousemove', (e) => {
90
+ const svg = e.currentTarget;
91
+ const rect = svg.getBoundingClientRect();
92
+ const x = e.clientX - rect.left;
93
+ const y = e.clientY - rect.top;
94
+ const crosshair = svg.getElementById('crosshair');
95
+ const h = svg.getElementById('crosshair-h');
96
+ const v = svg.getElementById('crosshair-v');
97
+ const coords = svg.getElementById('coordinates');
98
+
99
+ crosshair.style.display = 'block';
100
+ h.setAttribute('x1', '0');
101
+ h.setAttribute('x2', '640');
102
+ h.setAttribute('y1', y);
103
+ h.setAttribute('y2', y);
104
+ v.setAttribute('x1', x);
105
+ v.setAttribute('x2', x);
106
+ v.setAttribute('y1', '0');
107
+ v.setAttribute('y2', '640');
108
+
109
+ // Calculate real coordinates using inverse transformation
110
+ const matrix = {
111
+ "a": 112,
112
+ "c": 0,
113
+ "e": 174.40000000000003,
114
+ "b": 0,
115
+ "d": -112,
116
+ "f": 194.28
117
+ };
118
+ // Manually invert and apply the affine transform
119
+ // Since we only use translate and scale, we can directly compute:
120
+ // x' = (x - tx) / sx
121
+ // y' = (y - ty) / sy
122
+ const sx = matrix.a;
123
+ const sy = matrix.d;
124
+ const tx = matrix.e;
125
+ const ty = matrix.f;
126
+ const realPoint = {
127
+ x: (x - tx) / sx,
128
+ y: (y - ty) / sy // Flip y back since we used negative scale
129
+ }
130
+
131
+ coords.textContent = `(${realPoint.x.toFixed(2)}, ${realPoint.y.toFixed(2)})`;
132
+ coords.setAttribute('x', (x + 5).toString());
133
+ coords.setAttribute('y', (y - 5).toString());
134
+ });
135
+ document.currentScript.parentElement.addEventListener('mouseleave', () => {
136
+ document.currentScript.parentElement.getElementById('crosshair').style.display = 'none';
137
+ });
138
+ ]]>
139
+ </script>
140
+ </svg>
@@ -0,0 +1,216 @@
1
+ <svg width="640" height="640" viewBox="0 0 640 640" xmlns="http://www.w3.org/2000/svg">
2
+ <rect width="100%" height="100%" fill="white" />
3
+ <g>
4
+ <circle data-type="point" data-label="U1.1
5
+ x+" data-x="1.2000000000000002" data-y="-0.30000000000000004" cx="425" cy="337.5" r="3" fill="hsl(319, 100%, 50%, 0.8)" />
6
+ </g>
7
+ <g>
8
+ <circle data-type="point" data-label="U1.2
9
+ x-" data-x="-1.2000000000000002" data-y="-0.30000000000000004" cx="215" cy="337.5" r="3" fill="hsl(320, 100%, 50%, 0.8)" />
10
+ </g>
11
+ <g>
12
+ <circle data-type="point" data-label="U1.3
13
+ x+" data-x="1.2000000000000002" data-y="0.09999999999999998" cx="425" cy="302.5" r="3" fill="hsl(321, 100%, 50%, 0.8)" />
14
+ </g>
15
+ <g>
16
+ <circle data-type="point" data-label="U1.4
17
+ x-" data-x="-1.2000000000000002" data-y="0.30000000000000004" cx="215" cy="285" r="3" fill="hsl(322, 100%, 50%, 0.8)" />
18
+ </g>
19
+ <g>
20
+ <circle data-type="point" data-label="U1.5
21
+ x-" data-x="-1.2000000000000002" data-y="0.10000000000000003" cx="215" cy="302.5" r="3" fill="hsl(323, 100%, 50%, 0.8)" />
22
+ </g>
23
+ <g>
24
+ <circle data-type="point" data-label="U1.6
25
+ x-" data-x="-1.2000000000000002" data-y="-0.09999999999999998" cx="215" cy="320" r="3" fill="hsl(324, 100%, 50%, 0.8)" />
26
+ </g>
27
+ <g>
28
+ <circle data-type="point" data-label="U1.7
29
+ x+" data-x="1.2000000000000002" data-y="-0.10000000000000003" cx="425" cy="320" r="3" fill="hsl(325, 100%, 50%, 0.8)" />
30
+ </g>
31
+ <g>
32
+ <circle data-type="point" data-label="U1.8
33
+ x+" data-x="1.2000000000000002" data-y="0.30000000000000004" cx="425" cy="285" r="3" fill="hsl(326, 100%, 50%, 0.8)" />
34
+ </g>
35
+ <g>
36
+ <circle data-type="point" data-label="R1.1
37
+ x+" data-x="3" data-y="-0.10000000000000016" cx="582.5" cy="320" r="3" fill="hsl(226, 100%, 50%, 0.8)" />
38
+ </g>
39
+ <g>
40
+ <circle data-type="point" data-label="R1.2
41
+ x-" data-x="1.9000000000000004" data-y="-0.10000000000000002" cx="486.25" cy="320" r="3" fill="hsl(227, 100%, 50%, 0.8)" />
42
+ </g>
43
+ <g>
44
+ <circle data-type="point" data-label="R2.1
45
+ x+" data-x="1.2000000000000002" data-y="-1.2944553500000002" cx="425" cy="424.514843125" r="3" fill="hsl(107, 100%, 50%, 0.8)" />
46
+ </g>
47
+ <g>
48
+ <circle data-type="point" data-label="R2.2
49
+ x-" data-x="0.10000000000000009" data-y="-1.2944553500000002" cx="328.75" cy="424.514843125" r="3" fill="hsl(108, 100%, 50%, 0.8)" />
50
+ </g>
51
+ <g>
52
+ <circle data-type="point" data-label="C1.1
53
+ y+" data-x="-1.2000000000000002" data-y="-1.1500000000000001" cx="215" cy="411.875" r="3" fill="hsl(121, 100%, 50%, 0.8)" />
54
+ </g>
55
+ <g>
56
+ <circle data-type="point" data-label="C1.2
57
+ y-" data-x="-1.2000000000000002" data-y="-2.25" cx="215" cy="508.125" r="3" fill="hsl(122, 100%, 50%, 0.8)" />
58
+ </g>
59
+ <g>
60
+ <circle data-type="point" data-label="C2.1
61
+ x+" data-x="-1.9000000000000004" data-y="0.10000000000000002" cx="153.74999999999997" cy="302.5" r="3" fill="hsl(2, 100%, 50%, 0.8)" />
62
+ </g>
63
+ <g>
64
+ <circle data-type="point" data-label="C2.2
65
+ x-" data-x="-3" data-y="0.10000000000000016" cx="57.5" cy="302.5" r="3" fill="hsl(3, 100%, 50%, 0.8)" />
66
+ </g>
67
+ <g>
68
+ <circle data-type="point" data-label="R3.1
69
+ y-" data-x="1.2000000000000002" data-y="1.1500000000000001" cx="425" cy="210.625" r="3" fill="hsl(348, 100%, 50%, 0.8)" />
70
+ </g>
71
+ <g>
72
+ <circle data-type="point" data-label="R3.2
73
+ y+" data-x="1.2000000000000002" data-y="2.25" cx="425" cy="114.375" r="3" fill="hsl(349, 100%, 50%, 0.8)" />
74
+ </g>
75
+ <g>
76
+ <polyline data-points="-1.2000000000000002,0.10000000000000003 -1.9000000000000004,0.10000000000000002" data-type="line" data-label="" points="215,302.5 153.74999999999997,302.5" fill="none" stroke="hsl(296, 100%, 50%, 0.8)" stroke-width="1" />
77
+ </g>
78
+ <g>
79
+ <polyline data-points="-1.2000000000000002,-0.09999999999999998 -1.2000000000000002,-0.30000000000000004" data-type="line" data-label="" points="215,320 215,337.5" fill="none" stroke="hsl(168, 100%, 50%, 0.8)" stroke-width="1" />
80
+ </g>
81
+ <g>
82
+ <polyline data-points="1.9000000000000004,-0.10000000000000002 1.2000000000000002,-0.10000000000000003" data-type="line" data-label="" points="486.25,320 425,320" fill="none" stroke="hsl(248, 100%, 50%, 0.8)" stroke-width="1" />
83
+ </g>
84
+ <g>
85
+ <polyline data-points="1.2000000000000002,-0.10000000000000003 1.2000000000000002,-1.2944553500000002" data-type="line" data-label="" points="425,320 425,424.514843125" fill="none" stroke="hsl(160, 100%, 50%, 0.8)" stroke-width="1" />
86
+ </g>
87
+ <g>
88
+ <polyline data-points="0.10000000000000009,-1.2944553500000002 -1.2000000000000002,-0.09999999999999998" data-type="line" data-label="" points="328.75,424.514843125 215,320" fill="none" stroke="hsl(104, 100%, 50%, 0.8)" stroke-width="1" />
89
+ </g>
90
+ <g>
91
+ <polyline data-points="-1.2000000000000002,-0.09999999999999998 -1.2000000000000002,-1.1500000000000001" data-type="line" data-label="" points="215,320 215,411.875" fill="none" stroke="hsl(168, 100%, 50%, 0.8)" stroke-width="1" />
92
+ </g>
93
+ <g>
94
+ <polyline data-points="1.2000000000000002,0.09999999999999998 1.2000000000000002,1.1500000000000001" data-type="line" data-label="" points="425,302.5 425,210.625" fill="none" stroke="hsl(320, 100%, 50%, 0.8)" stroke-width="1" />
95
+ </g>
96
+ <g>
97
+ <polyline data-points="1.2000000000000002,-0.30000000000000004 -1.2000000000000002,-2.25" data-type="line" data-label="" points="425,337.5 215,508.125" fill="none" stroke="hsl(157, 100%, 50%, 0.8)" stroke-width="1" stroke-dasharray="4 2" />
98
+ </g>
99
+ <g>
100
+ <polyline data-points="1.2000000000000002,-0.30000000000000004 -3,0.10000000000000016" data-type="line" data-label="" points="425,337.5 57.5,302.5" fill="none" stroke="hsl(157, 100%, 50%, 0.8)" stroke-width="1" stroke-dasharray="4 2" />
101
+ </g>
102
+ <g>
103
+ <polyline data-points="-1.2000000000000002,-2.25 -3,0.10000000000000016" data-type="line" data-label="" points="215,508.125 57.5,302.5" fill="none" stroke="hsl(157, 100%, 50%, 0.8)" stroke-width="1" stroke-dasharray="4 2" />
104
+ </g>
105
+ <g>
106
+ <polyline data-points="-1.2000000000000002,0.30000000000000004 1.2000000000000002,0.30000000000000004" data-type="line" data-label="" points="215,285 425,285" fill="none" stroke="hsl(190, 100%, 50%, 0.8)" stroke-width="1" stroke-dasharray="4 2" />
107
+ </g>
108
+ <g>
109
+ <polyline data-points="-1.2000000000000002,0.30000000000000004 3,-0.10000000000000016" data-type="line" data-label="" points="215,285 582.5,320" fill="none" stroke="hsl(190, 100%, 50%, 0.8)" stroke-width="1" stroke-dasharray="4 2" />
110
+ </g>
111
+ <g>
112
+ <polyline data-points="1.2000000000000002,0.30000000000000004 3,-0.10000000000000016" data-type="line" data-label="" points="425,285 582.5,320" fill="none" stroke="hsl(190, 100%, 50%, 0.8)" stroke-width="1" stroke-dasharray="4 2" />
113
+ </g>
114
+ <g>
115
+ <polyline data-points="-1.2000000000000002,0.10000000000000003 -1.9000000000000004,0.10000000000000002" data-type="line" data-label="" points="215,302.5 153.74999999999997,302.5" fill="none" stroke="purple" stroke-width="1" />
116
+ </g>
117
+ <g>
118
+ <polyline data-points="-1.2000000000000002,-0.30000000000000004 -1.4000000000000001,-0.30000000000000004 -1.4000000000000001,-0.7250000000000001 -1.2000000000000002,-0.7250000000000001 -1.2000000000000002,-1.1500000000000001" data-type="line" data-label="" points="215,337.5 197.5,337.5 197.5,374.6875 215,374.6875 215,411.875" fill="none" stroke="purple" stroke-width="1" />
119
+ </g>
120
+ <g>
121
+ <polyline data-points="-1.2000000000000002,-0.09999999999999998 -1.4000000000000001,-0.09999999999999998 -1.4000000000000001,-0.30000000000000004 -1.2000000000000002,-0.30000000000000004" data-type="line" data-label="" points="215,320 197.5,320 197.5,337.5 215,337.5" fill="none" stroke="purple" stroke-width="1" />
122
+ </g>
123
+ <g>
124
+ <polyline data-points="0.09999999999999987,-1.2944553500000002 -0.55,-1.2944553500000002 -0.55,-0.9500000000000002 -1.2000000000000002,-0.9500000000000002 -1.2000000000000002,-1.1500000000000001" data-type="line" data-label="" points="328.75,424.514843125 271.875,424.514843125 271.875,394.375 215,394.375 215,411.875" fill="none" stroke="purple" stroke-width="1" />
125
+ </g>
126
+ <g>
127
+ <polyline data-points="1.2000000000000002,-0.10000000000000003 1.9000000000000004,-0.10000000000000002" data-type="line" data-label="" points="425,320 486.25,320" fill="none" stroke="purple" stroke-width="1" />
128
+ </g>
129
+ <g>
130
+ <polyline data-points="1.2000000000000002,-1.2944553500000002 1.4000000000000001,-1.2944553500000002 1.4000000000000001,-0.10000000000000003 1.2000000000000002,-0.10000000000000003" data-type="line" data-label="" points="425,424.514843125 442.5,424.514843125 442.5,320 425,320" fill="none" stroke="purple" stroke-width="1" />
131
+ </g>
132
+ <g>
133
+ <polyline data-points="1.2000000000000002,0.09999999999999998 1.4000000000000001,0.09999999999999998 1.4000000000000001,0.625 1.2000000000000002,0.625 1.2000000000000002,1.1500000000000001" data-type="line" data-label="" points="425,302.5 442.5,302.5 442.5,256.5625 425,256.5625 425,210.625" fill="none" stroke="purple" stroke-width="1" />
134
+ </g>
135
+ <g>
136
+ <polyline data-points="1.2000000000000002,0.30000000000000004 3.2,0.30000000000000004 3.2,-0.10000000000000016 3,-0.10000000000000016" data-type="line" data-label="" points="425,285 600,285 600,320 582.5,320" fill="none" stroke="purple" stroke-width="1" />
137
+ </g>
138
+ <g>
139
+ <polyline data-points="-1.2000000000000002,-2.25 -1.2000000000000002,-2.45 -3.2,-2.45 -3.2,0.10000000000000016 -3,0.10000000000000016" data-type="line" data-label="" points="215,508.125 215,525.625 40,525.625 40,302.5 57.5,302.5" fill="none" stroke="purple" stroke-width="1" />
140
+ </g>
141
+ <g>
142
+ <rect data-type="rect" data-label="schematic_component_0" data-x="0" data-y="0" x="215" y="267.5" width="210" height="87.5" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.011428571428571429" />
143
+ </g>
144
+ <g>
145
+ <rect data-type="rect" data-label="schematic_component_1" data-x="2.45" data-y="-0.10000000000000009" x="486.25" y="302.98515687500003" width="96.25" height="34.02968624999994" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.011428571428571429" />
146
+ </g>
147
+ <g>
148
+ <rect data-type="rect" data-label="schematic_component_2" data-x="0.6500000000000001" data-y="-1.2944553500000002" x="328.75" y="407.50000000000006" width="96.25" height="34.029686249999884" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.011428571428571429" />
149
+ </g>
150
+ <g>
151
+ <rect data-type="rect" data-label="schematic_component_3" data-x="-1.2000000000000002" data-y="-1.7000000000000002" x="168.62499999999997" y="411.875" width="92.75000000000003" height="96.25" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.011428571428571429" />
152
+ </g>
153
+ <g>
154
+ <rect data-type="rect" data-label="schematic_component_4" data-x="-2.45" data-y="0.10000000000000009" x="57.5" y="265.75" width="96.24999999999997" height="73.5" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.011428571428571429" />
155
+ </g>
156
+ <g>
157
+ <rect data-type="rect" data-label="schematic_component_5" data-x="1.2000000000000002" data-y="1.7000000000000002" x="378.625" y="114.375" width="92.75" height="96.25" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.011428571428571429" />
158
+ </g>
159
+ <g id="crosshair" style="display: none">
160
+ <line id="crosshair-h" y1="0" y2="640" stroke="#666" stroke-width="0.5" />
161
+ <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>
162
+ </g>
163
+ <script>
164
+ <![CDATA[
165
+ document.currentScript.parentElement.addEventListener('mousemove', (e) => {
166
+ const svg = e.currentTarget;
167
+ const rect = svg.getBoundingClientRect();
168
+ const x = e.clientX - rect.left;
169
+ const y = e.clientY - rect.top;
170
+ const crosshair = svg.getElementById('crosshair');
171
+ const h = svg.getElementById('crosshair-h');
172
+ const v = svg.getElementById('crosshair-v');
173
+ const coords = svg.getElementById('coordinates');
174
+
175
+ crosshair.style.display = 'block';
176
+ h.setAttribute('x1', '0');
177
+ h.setAttribute('x2', '640');
178
+ h.setAttribute('y1', y);
179
+ h.setAttribute('y2', y);
180
+ v.setAttribute('x1', x);
181
+ v.setAttribute('x2', x);
182
+ v.setAttribute('y1', '0');
183
+ v.setAttribute('y2', '640');
184
+
185
+ // Calculate real coordinates using inverse transformation
186
+ const matrix = {
187
+ "a": 87.5,
188
+ "c": 0,
189
+ "e": 320,
190
+ "b": 0,
191
+ "d": -87.5,
192
+ "f": 311.25
193
+ };
194
+ // Manually invert and apply the affine transform
195
+ // Since we only use translate and scale, we can directly compute:
196
+ // x' = (x - tx) / sx
197
+ // y' = (y - ty) / sy
198
+ const sx = matrix.a;
199
+ const sy = matrix.d;
200
+ const tx = matrix.e;
201
+ const ty = matrix.f;
202
+ const realPoint = {
203
+ x: (x - tx) / sx,
204
+ y: (y - ty) / sy // Flip y back since we used negative scale
205
+ }
206
+
207
+ coords.textContent = `(${realPoint.x.toFixed(2)}, ${realPoint.y.toFixed(2)})`;
208
+ coords.setAttribute('x', (x + 5).toString());
209
+ coords.setAttribute('y', (y - 5).toString());
210
+ });
211
+ document.currentScript.parentElement.addEventListener('mouseleave', () => {
212
+ document.currentScript.parentElement.getElementById('crosshair').style.display = 'none';
213
+ });
214
+ ]]>
215
+ </script>
216
+ </svg>
@@ -0,0 +1,125 @@
1
+ <svg width="640" height="640" viewBox="0 0 640 640" xmlns="http://www.w3.org/2000/svg">
2
+ <rect width="100%" height="100%" fill="white" />
3
+ <g>
4
+ <circle data-type="point" data-label="U1.1
5
+ x+" data-x="1.2000000000000002" data-y="-0.30000000000000004" cx="308.80000000000007" cy="241.88" r="3" fill="hsl(319, 100%, 50%, 0.8)" />
6
+ </g>
7
+ <g>
8
+ <circle data-type="point" data-label="U1.2
9
+ x-" data-x="-1.2000000000000002" data-y="-0.30000000000000004" cx="40" cy="241.88" r="3" fill="hsl(320, 100%, 50%, 0.8)" />
10
+ </g>
11
+ <g>
12
+ <circle data-type="point" data-label="U1.3
13
+ x+" data-x="1.2000000000000002" data-y="0.09999999999999998" cx="308.80000000000007" cy="197.08" r="3" fill="hsl(321, 100%, 50%, 0.8)" />
14
+ </g>
15
+ <g>
16
+ <circle data-type="point" data-label="U1.4
17
+ x-" data-x="-1.2000000000000002" data-y="0.30000000000000004" cx="40" cy="174.68" r="3" fill="hsl(322, 100%, 50%, 0.8)" />
18
+ </g>
19
+ <g>
20
+ <circle data-type="point" data-label="U1.5
21
+ x-" data-x="-1.2000000000000002" data-y="0.10000000000000003" cx="40" cy="197.07999999999998" r="3" fill="hsl(323, 100%, 50%, 0.8)" />
22
+ </g>
23
+ <g>
24
+ <circle data-type="point" data-label="U1.6
25
+ x-" data-x="-1.2000000000000002" data-y="-0.09999999999999998" cx="40" cy="219.48" r="3" fill="hsl(324, 100%, 50%, 0.8)" />
26
+ </g>
27
+ <g>
28
+ <circle data-type="point" data-label="U1.7
29
+ x+" data-x="1.2000000000000002" data-y="-0.10000000000000003" cx="308.80000000000007" cy="219.48000000000002" r="3" fill="hsl(325, 100%, 50%, 0.8)" />
30
+ </g>
31
+ <g>
32
+ <circle data-type="point" data-label="U1.8
33
+ x+" data-x="1.2000000000000002" data-y="0.30000000000000004" cx="308.80000000000007" cy="174.68" r="3" fill="hsl(326, 100%, 50%, 0.8)" />
34
+ </g>
35
+ <g>
36
+ <circle data-type="point" data-label="J1.1
37
+ x-" data-x="1.6" data-y="-1.895" cx="353.6" cy="420.52" r="3" fill="hsl(218, 100%, 50%, 0.8)" />
38
+ </g>
39
+ <g>
40
+ <circle data-type="point" data-label="J1.2
41
+ x-" data-x="1.6" data-y="-2.095" cx="353.6" cy="442.92" r="3" fill="hsl(219, 100%, 50%, 0.8)" />
42
+ </g>
43
+ <g>
44
+ <circle data-type="point" data-label="J1.3
45
+ x-" data-x="1.6" data-y="-2.295" cx="353.6" cy="465.31999999999994" r="3" fill="hsl(220, 100%, 50%, 0.8)" />
46
+ </g>
47
+ <g>
48
+ <polyline data-points="1.2000000000000002,-0.30000000000000004 1.6,-2.295" data-type="line" data-label="" points="308.80000000000007,241.88 353.6,465.31999999999994" fill="none" stroke="hsl(157, 100%, 50%, 0.1)" stroke-width="1" stroke-dasharray="4 2" />
49
+ </g>
50
+ <g>
51
+ <polyline data-points="1.2000000000000002,0.30000000000000004 1.6,-1.895" data-type="line" data-label="" points="308.80000000000007,174.68 353.6,420.52" fill="none" stroke="hsl(190, 100%, 50%, 0.1)" stroke-width="1" stroke-dasharray="4 2" />
52
+ </g>
53
+ <g>
54
+ <polyline data-points="1.2000000000000002,-0.30000000000000004 1.4000000000000001,-0.30000000000000004 1.4000000000000001,-1.2974999999999999 1.4000000000000001,-2.295 1.6,-2.295" data-type="line" data-label="" points="308.80000000000007,241.88 331.20000000000005,241.88 331.20000000000005,353.6 331.20000000000005,465.31999999999994 353.6,465.31999999999994" fill="none" stroke="red" stroke-width="1" stroke-dasharray="4 4" />
55
+ </g>
56
+ <g>
57
+ <polyline data-points="1.2000000000000002,-0.30000000000000004 1.4000000000000001,-0.30000000000000004 1.4000000000000001,-1.6949999999999998 1.049,-1.6949999999999998 1.049,-2.2950000000000004 1.6,-2.295" data-type="line" data-label="" points="308.80000000000007,241.88 331.20000000000005,241.88 331.20000000000005,398.12 291.88800000000003,398.12 291.88800000000003,465.32000000000005 353.6,465.31999999999994" fill="none" stroke="green" stroke-width="1" />
58
+ </g>
59
+ <g>
60
+ <rect data-type="rect" data-label="schematic_component_0" data-x="0" data-y="0" x="40" y="152.28" width="268.80000000000007" height="111.99999999999997" fill="hsl(24, 100%, 50%, 0.1)" stroke="black" stroke-width="0.008928571428571428" />
61
+ </g>
62
+ <g>
63
+ <rect data-type="rect" data-label="schematic_component_1" data-x="2.7" data-y="-2.095" x="353.6" y="398.12" width="246.39999999999998" height="89.60000000000002" fill="hsl(24, 100%, 50%, 0.1)" stroke="black" stroke-width="0.008928571428571428" />
64
+ </g>
65
+ <g>
66
+ <rect data-type="rect" data-label="" data-x="1.374" data-y="-1.995" x="303.088" y="409.32" width="50.400000000000034" height="44.80000000000001" fill="rgba(255, 0, 0, 0.2)" stroke="black" stroke-width="0.008928571428571428" />
67
+ </g>
68
+ <g id="crosshair" style="display: none">
69
+ <line id="crosshair-h" y1="0" y2="640" stroke="#666" stroke-width="0.5" />
70
+ <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>
71
+ </g>
72
+ <script>
73
+ <![CDATA[
74
+ document.currentScript.parentElement.addEventListener('mousemove', (e) => {
75
+ const svg = e.currentTarget;
76
+ const rect = svg.getBoundingClientRect();
77
+ const x = e.clientX - rect.left;
78
+ const y = e.clientY - rect.top;
79
+ const crosshair = svg.getElementById('crosshair');
80
+ const h = svg.getElementById('crosshair-h');
81
+ const v = svg.getElementById('crosshair-v');
82
+ const coords = svg.getElementById('coordinates');
83
+
84
+ crosshair.style.display = 'block';
85
+ h.setAttribute('x1', '0');
86
+ h.setAttribute('x2', '640');
87
+ h.setAttribute('y1', y);
88
+ h.setAttribute('y2', y);
89
+ v.setAttribute('x1', x);
90
+ v.setAttribute('x2', x);
91
+ v.setAttribute('y1', '0');
92
+ v.setAttribute('y2', '640');
93
+
94
+ // Calculate real coordinates using inverse transformation
95
+ const matrix = {
96
+ "a": 112,
97
+ "c": 0,
98
+ "e": 174.40000000000003,
99
+ "b": 0,
100
+ "d": -112,
101
+ "f": 208.28
102
+ };
103
+ // Manually invert and apply the affine transform
104
+ // Since we only use translate and scale, we can directly compute:
105
+ // x' = (x - tx) / sx
106
+ // y' = (y - ty) / sy
107
+ const sx = matrix.a;
108
+ const sy = matrix.d;
109
+ const tx = matrix.e;
110
+ const ty = matrix.f;
111
+ const realPoint = {
112
+ x: (x - tx) / sx,
113
+ y: (y - ty) / sy // Flip y back since we used negative scale
114
+ }
115
+
116
+ coords.textContent = `(${realPoint.x.toFixed(2)}, ${realPoint.y.toFixed(2)})`;
117
+ coords.setAttribute('x', (x + 5).toString());
118
+ coords.setAttribute('y', (y - 5).toString());
119
+ });
120
+ document.currentScript.parentElement.addEventListener('mouseleave', () => {
121
+ document.currentScript.parentElement.getElementById('crosshair').style.display = 'none';
122
+ });
123
+ ]]>
124
+ </script>
125
+ </svg>