@tscircuit/schematic-trace-solver 0.0.130 → 0.0.131

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.
@@ -2,11 +2,130 @@ import { expect, test } from "bun:test"
2
2
  import { SchematicTracePipelineSolver } from "lib/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver"
3
3
  import inputProblem from "./bug-report-20260811T075142Z.json"
4
4
  import "tests/fixtures/matcher"
5
+ import { getRectBounds } from "lib/solvers/NetLabelPlacementSolver/SingleNetLabelPlacementSolver/geometry"
6
+ import {
7
+ rectsOverlap,
8
+ traceCrossesBoundsInterior,
9
+ } from "lib/solvers/AvailableNetOrientationSolver/geometry"
5
10
 
6
11
  test("bug-report-20260811T075142Z", () => {
7
12
  const solver = new SchematicTracePipelineSolver(inputProblem as any)
8
13
 
9
14
  solver.solve()
10
15
 
16
+ const output = solver.inlineNetLabelSolver!.getOutput()
17
+ const usbPlusLabel = output.netLabelPlacements.find(
18
+ (label) => label.netId === "USB_D_PLUS",
19
+ )
20
+ const gndLabel = output.netLabelPlacements.find(
21
+ (label) => label.netId === "GND",
22
+ )
23
+ const upwardPowerLabels = ["V3_3", "VBUS_5V", "VBAT"].map(
24
+ (netId) =>
25
+ output.netLabelPlacements.find((label) => label.netId === netId)!,
26
+ )
27
+
28
+ expect(usbPlusLabel).toBeDefined()
29
+ expect(["x-", "x+"]).toContain(usbPlusLabel!.orientation)
30
+ expect(upwardPowerLabels.map((label) => label.orientation)).toEqual([
31
+ "y+",
32
+ "y+",
33
+ "y+",
34
+ ])
35
+ expect(upwardPowerLabels[1]!.anchorPoint.y).toBeGreaterThan(
36
+ upwardPowerLabels[0]!.anchorPoint.y,
37
+ )
38
+ expect(upwardPowerLabels[2]!.anchorPoint.y).toBeGreaterThan(
39
+ upwardPowerLabels[1]!.anchorPoint.y,
40
+ )
41
+ expect(gndLabel?.orientation).toBe("y-")
42
+ expect(gndLabel!.anchorPoint.y).toBe(upwardPowerLabels[1]!.center.y)
43
+ expect(gndLabel!.center.y).toBeGreaterThan(upwardPowerLabels[0]!.center.y)
44
+ expect(gndLabel!.center.y).toBeLessThan(upwardPowerLabels[2]!.center.y)
45
+
46
+ for (const netId of ["V3_3", "VBUS_5V", "VBAT", "GND"]) {
47
+ const connector = output.traces.find(
48
+ (trace) =>
49
+ trace.userNetId === netId &&
50
+ trace.mspPairId.startsWith("available-net-orientation-"),
51
+ )
52
+ expect(connector).toBeDefined()
53
+ expect(connector!.tracePath).toHaveLength(3)
54
+ const [pin, bend, labelAnchor] = connector!.tracePath
55
+ expect(bend!.x).toBe(pin!.x)
56
+ expect(bend!.y).toBeGreaterThan(pin!.y)
57
+ expect(labelAnchor!.y).toBe(bend!.y)
58
+ }
59
+
60
+ const gndConnector = output.traces.find(
61
+ (trace) =>
62
+ trace.userNetId === "GND" &&
63
+ trace.mspPairId.startsWith("available-net-orientation-"),
64
+ )!
65
+ expect(gndConnector.tracePath[2]!.x).toBeGreaterThan(
66
+ gndConnector.tracePath[1]!.x,
67
+ )
68
+
69
+ const overlappingLabelPairs: string[] = []
70
+ for (let i = 0; i < output.netLabelPlacements.length; i++) {
71
+ for (let j = i + 1; j < output.netLabelPlacements.length; j++) {
72
+ const a = output.netLabelPlacements[i]!
73
+ const b = output.netLabelPlacements[j]!
74
+ if (
75
+ rectsOverlap(
76
+ getRectBounds(a.center, a.width, a.height),
77
+ getRectBounds(b.center, b.width, b.height),
78
+ )
79
+ ) {
80
+ overlappingLabelPairs.push(`${a.netId}::${b.netId}`)
81
+ }
82
+ }
83
+ }
84
+ expect(overlappingLabelPairs).toEqual([])
85
+
86
+ const traceLabelIntersections: string[] = []
87
+ for (const label of output.netLabelPlacements) {
88
+ const bounds = getRectBounds(label.center, label.width, label.height)
89
+ for (const trace of output.traces) {
90
+ if (trace.globalConnNetId === label.globalConnNetId) continue
91
+ if (
92
+ traceCrossesBoundsInterior(bounds, {
93
+ [trace.mspPairId]: trace,
94
+ })
95
+ ) {
96
+ traceLabelIntersections.push(`${trace.userNetId}::${label.netId}`)
97
+ }
98
+ }
99
+ }
100
+ expect(traceLabelIntersections).toEqual([])
101
+
11
102
  expect(solver).toMatchSolverSnapshot(import.meta.path)
12
103
  })
104
+
105
+ test("dense top fanout is independent of net connection input order", () => {
106
+ const reorderedInput = structuredClone(inputProblem)
107
+ reorderedInput.netConnections.reverse()
108
+ const solver = new SchematicTracePipelineSolver(reorderedInput as any)
109
+
110
+ solver.solve()
111
+
112
+ const output = solver.inlineNetLabelSolver!.getOutput()
113
+ const verticalNetIds = ["V3_3", "VBUS_5V", "VBAT", "GND"]
114
+ for (const netId of verticalNetIds) {
115
+ const connector = output.traces.find(
116
+ (trace) =>
117
+ trace.userNetId === netId &&
118
+ trace.mspPairId.startsWith("available-net-orientation-"),
119
+ )
120
+ expect(connector).toBeDefined()
121
+ const [pin, bend, labelAnchor] = connector!.tracePath
122
+ expect(bend!.x).toBe(pin!.x)
123
+ expect(bend!.y).toBeGreaterThan(pin!.y)
124
+ expect(labelAnchor!.y).toBe(bend!.y)
125
+ }
126
+
127
+ expect(
128
+ output.netLabelPlacements.find((label) => label.netId === "GND")
129
+ ?.orientation,
130
+ ).toBe("y-")
131
+ })
@@ -0,0 +1,69 @@
1
+ <svg width="640" height="640" viewBox="0 0 640 640" xmlns="http://www.w3.org/2000/svg"><rect width="100%" height="100%" fill="white"/><g><polyline data-points="-1.6750000000000007,-5.593455349999998 -1.6750000000000007,-5.193455349999998" data-type="line" data-label="" points="339.2947103274559,344.78589420654913 339.2947103274559,324.63476070528964" fill="none" stroke="hsl(344, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="-1.6750000000000007,-5.393455349999998 -4.135000000000001,-6.073455349999998" data-type="line" data-label="" points="339.2947103274559,334.71032745591936 215.36523929471034,368.9672544080604" fill="none" stroke="hsl(157, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="-1.6750000000000007,-5.393455349999998 -2.8950000000000005,-6.073455349999998" data-type="line" data-label="" points="339.2947103274559,334.71032745591936 277.8337531486146,368.9672544080604" fill="none" stroke="hsl(157, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="-1.6750000000000007,-5.393455349999998 1.544999999999999,-6.1734553499999985" data-type="line" data-label="" points="339.2947103274559,334.71032745591936 501.51133501259443,374.0050377833753" fill="none" stroke="hsl(157, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="-1.6750000000000007,-5.393455349999998 2.7849999999999993,-6.1734553499999985" data-type="line" data-label="" points="339.2947103274559,334.71032745591936 563.9798488664987,374.0050377833753" fill="none" stroke="hsl(157, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="-4.135000000000001,-6.073455349999998 -2.8950000000000005,-6.073455349999998" data-type="line" data-label="" points="215.36523929471034,368.9672544080604 277.8337531486146,368.9672544080604" fill="none" stroke="hsl(157, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="-4.135000000000001,-6.073455349999998 1.544999999999999,-6.1734553499999985" data-type="line" data-label="" points="215.36523929471034,368.9672544080604 501.51133501259443,374.0050377833753" fill="none" stroke="hsl(157, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="-4.135000000000001,-6.073455349999998 2.7849999999999993,-6.1734553499999985" data-type="line" data-label="" points="215.36523929471034,368.9672544080604 563.9798488664987,374.0050377833753" fill="none" stroke="hsl(157, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="-2.8950000000000005,-6.073455349999998 1.544999999999999,-6.1734553499999985" data-type="line" data-label="" points="277.8337531486146,368.9672544080604 501.51133501259443,374.0050377833753" fill="none" stroke="hsl(157, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="-2.8950000000000005,-6.073455349999998 2.7849999999999993,-6.1734553499999985" data-type="line" data-label="" points="277.8337531486146,368.9672544080604 563.9798488664987,374.0050377833753" fill="none" stroke="hsl(157, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="1.544999999999999,-6.1734553499999985 2.7849999999999993,-6.1734553499999985" data-type="line" data-label="" points="501.51133501259443,374.0050377833753 563.9798488664987,374.0050377833753" fill="none" stroke="hsl(157, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="-4.655000000000001,-4.030455349999999 -1.6750000000000007,-5.193455349999998" data-type="line" data-label="" points="189.16876574307304,266.04534005037783 339.2947103274559,324.63476070528964" fill="none" stroke="hsl(309, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="-4.655000000000001,-4.030455349999999 -1.6750000000000007,-5.593455349999998" data-type="line" data-label="" points="189.16876574307304,266.04534005037783 339.2947103274559,344.78589420654913" fill="none" stroke="hsl(309, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="-4.655000000000001,-4.030455349999999 -4.135000000000001,-5.313455349999998" data-type="line" data-label="" points="189.16876574307304,266.04534005037783 215.36523929471034,330.68010075566747" fill="none" stroke="hsl(309, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="-4.655000000000001,-4.030455349999999 -2.8950000000000005,-5.313455349999998" data-type="line" data-label="" points="189.16876574307304,266.04534005037783 277.8337531486146,330.68010075566747" fill="none" stroke="hsl(309, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="-1.6750000000000007,-5.193455349999998 -1.6750000000000007,-5.593455349999998" data-type="line" data-label="" points="339.2947103274559,324.63476070528964 339.2947103274559,344.78589420654913" fill="none" stroke="hsl(309, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="-1.6750000000000007,-5.193455349999998 -4.135000000000001,-5.313455349999998" data-type="line" data-label="" points="339.2947103274559,324.63476070528964 215.36523929471034,330.68010075566747" fill="none" stroke="hsl(309, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="-1.6750000000000007,-5.193455349999998 -2.8950000000000005,-5.313455349999998" data-type="line" data-label="" points="339.2947103274559,324.63476070528964 277.8337531486146,330.68010075566747" fill="none" stroke="hsl(309, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="-1.6750000000000007,-5.593455349999998 -4.135000000000001,-5.313455349999998" data-type="line" data-label="" points="339.2947103274559,344.78589420654913 215.36523929471034,330.68010075566747" fill="none" stroke="hsl(309, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="-1.6750000000000007,-5.593455349999998 -2.8950000000000005,-5.313455349999998" data-type="line" data-label="" points="339.2947103274559,344.78589420654913 277.8337531486146,330.68010075566747" fill="none" stroke="hsl(309, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="-4.135000000000001,-5.313455349999998 -2.8950000000000005,-5.313455349999998" data-type="line" data-label="" points="215.36523929471034,330.68010075566747 277.8337531486146,330.68010075566747" fill="none" stroke="hsl(309, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="0.3249999999999993,-5.293455349999999 1.544999999999999,-5.413455349999999" data-type="line" data-label="" points="440.05037783375315,329.67254408060455 501.51133501259443,335.7178841309824" fill="none" stroke="hsl(73, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="0.3249999999999993,-5.293455349999999 2.7849999999999993,-5.413455349999999" data-type="line" data-label="" points="440.05037783375315,329.67254408060455 563.9798488664987,335.7178841309824" fill="none" stroke="hsl(73, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="1.544999999999999,-5.413455349999999 2.7849999999999993,-5.413455349999999" data-type="line" data-label="" points="501.51133501259443,335.7178841309824 563.9798488664987,335.7178841309824" fill="none" stroke="hsl(73, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="-4.135000000000001,-5.313455349999998 -4.135000000000001,-4.030455349999999 -4.655000000000001,-4.030455349999999" data-type="line" data-label="" points="215.36523929471034,330.68010075566747 215.36523929471034,266.04534005037783 189.16876574307304,266.04534005037783" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="-2.8950000000000005,-5.313455349999998 -2.8950000000000005,-5.193455349999998 -4.135000000000001,-5.193455349999998 -4.135000000000001,-5.313455349999998" data-type="line" data-label="" points="277.8337531486146,330.68010075566747 277.8337531486146,324.63476070528964 215.36523929471034,324.63476070528964 215.36523929471034,330.68010075566747" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="-1.6750000000000007,-5.193455349999998 -2.8950000000000005,-5.193455349999998 -2.8950000000000005,-5.313455349999998" data-type="line" data-label="" points="339.2947103274559,324.63476070528964 277.8337531486146,324.63476070528964 277.8337531486146,330.68010075566747" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="-1.6750000000000007,-5.593455349999998 -1.8750000000000007,-5.593455349999998 -1.8750000000000007,-5.193455349999998 -1.6750000000000007,-5.193455349999998" data-type="line" data-label="" points="339.2947103274559,344.78589420654913 329.2191435768262,344.78589420654913 329.2191435768262,324.63476070528964 339.2947103274559,324.63476070528964" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="-2.8950000000000005,-6.073455349999998 -2.8950000000000005,-6.273455349999998 -1.9799999999999998,-6.273455349999998 -1.9799999999999998,-5.393455349999998 -1.6750000000000007,-5.393455349999998" data-type="line" data-label="" points="277.8337531486146,368.9672544080604 277.8337531486146,379.0428211586901 323.92947103274565,379.0428211586901 323.92947103274565,334.71032745591936 339.2947103274559,334.71032745591936" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="-4.135000000000001,-6.073455349999998 -4.135000000000001,-6.273455349999998 -2.8950000000000005,-6.273455349999998 -2.8950000000000005,-6.073455349999998" data-type="line" data-label="" points="215.36523929471034,368.9672544080604 215.36523929471034,379.0428211586901 277.8337531486146,379.0428211586901 277.8337531486146,368.9672544080604" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="2.7849999999999993,-6.1734553499999985 2.7849999999999993,-6.373455349999999 1.544999999999999,-6.373455349999999 1.544999999999999,-6.1734553499999985" data-type="line" data-label="" points="563.9798488664987,374.0050377833753 563.9798488664987,384.08060453400503 501.51133501259443,384.08060453400503 501.51133501259443,374.0050377833753" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="1.544999999999999,-5.413455349999999 1.544999999999999,-5.293455349999999 0.3249999999999993,-5.293455349999999" data-type="line" data-label="" points="501.51133501259443,335.7178841309824 501.51133501259443,329.67254408060455 440.05037783375315,329.67254408060455" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="2.7849999999999993,-5.413455349999999 2.7849999999999993,-5.293455349999999 1.544999999999999,-5.293455349999999 1.544999999999999,-5.413455349999999" data-type="line" data-label="" points="563.9798488664987,335.7178841309824 563.9798488664987,329.67254408060455 501.51133501259443,329.67254408060455 501.51133501259443,335.7178841309824" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="-6.655000000000001,-4.030455349999999 -7.136000000000002,-4.030455349999999 -7.136000000000002,-3.829455349999998" data-type="line" data-label="" points="88.41309823677585,266.04534005037783 64.18136020151132,266.04534005037783 64.18136020151132,255.91939546599494" fill="none" stroke="purple" stroke-width="1px"/></g><g><rect data-type="rect" data-label="schematic_component_3" data-x="-5.655000000000001" data-y="-4.030455349999999" x="88.41309823677585" y="255.9697732997481" width="100.75566750629719" height="20.151133501259437" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.019850000000000003"/></g><g><rect data-type="rect" data-label="schematic_component_4" data-x="-0.6750000000000007" data-y="-5.393455349999998" x="339.29471032745596" y="319.5969773299748" width="100.75566750629724" height="30.226700251889156" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.019850000000000003"/></g><g><rect data-type="rect" data-label="schematic_component_5" data-x="-4.000000000000001" data-y="-5.693455349999998" x="198.99244332493703" y="330.68010075566747" width="46.347607052896734" height="38.28715365239293" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.019850000000000003"/></g><g><rect data-type="rect" data-label="schematic_component_6" data-x="-2.7" data-y="-5.693455349999998" x="261.46095717884134" y="330.68010075566747" width="52.392947103274594" height="38.28715365239293" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.019850000000000003"/></g><g><rect data-type="rect" data-label="schematic_component_7" data-x="1.6799999999999988" data-y="-5.793455349999999" x="485.13853904282115" y="335.7178841309824" width="46.347607052896706" height="38.28715365239293" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.019850000000000003"/></g><g><rect data-type="rect" data-label="schematic_component_8" data-x="2.9799999999999995" data-y="-5.793455349999999" x="547.6070528967255" y="335.7178841309824" width="52.39294710327465" height="38.28715365239293" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.019850000000000003"/></g><g><rect data-type="rect" data-label="BSMD1206_200_12V" data-x="-5.295000000000001" data-y="-4.360455349999999" x="108.56423173803528" y="278.1360201511335" width="96.72544080604533" height="9.068010075566747" fill="rgba(160, 0, 220, 0.14)" stroke="black" stroke-width="0.019850000000000003"/></g><g><rect data-type="rect" data-label="2A PTC" data-x="-5.895000000000001" data-y="-3.7154553499999983" x="105.54156171284637" y="243.87909319899245" width="42.31738035264482" height="12.59445843828712" fill="rgba(160, 0, 220, 0.14)" stroke="black" stroke-width="0.019850000000000003"/></g><g><rect data-type="rect" data-label="AP2112K_3_3TRG1" data-x="-0.3750000000000009" data-y="-5.823455349999998" x="359.4458438287153" y="351.83879093198993" width="90.68010075566752" height="9.068010075566747" fill="rgba(160, 0, 220, 0.14)" stroke="black" stroke-width="0.019850000000000003"/></g><g><rect data-type="rect" data-label="AP2112K-3.3" data-x="-0.6150000000000009" data-y="-4.978455349999999" x="356.4231738035264" y="307.5062972292192" width="72.54408060453397" height="12.59445843828712" fill="rgba(160, 0, 220, 0.14)" stroke="black" stroke-width="0.019850000000000003"/></g><g><rect data-type="rect" data-label="netId: VBUS_5V
2
+ globalConnNetId: connectivity_net2" data-x="-7.136000000000002" data-y="-3.619455349999998" x="40.00000000000003" y="234.76070528967253" width="48.36272040302259" height="21.15869017632241" fill="#ef444466" stroke="#ef4444" stroke-width="0.019850000000000003"/></g><g><rect data-type="rect" data-label="netId: V5_SYS
3
+ globalConnNetId: connectivity_net0" data-x="-4.135000000000001" data-y="-3.8204553499999987" x="194.20654911838793" y="244.88664987405542" width="42.31738035264482" height="21.15869017632241" fill="#ef444466" stroke="#ef4444" stroke-width="0.019850000000000003"/></g><g><rect data-type="rect" data-label="netId: GND
4
+ globalConnNetId: connectivity_net1" data-x="-2.8950000000000005" data-y="-6.483455349999998" x="265.74307304785896" y="379.0428211586901" width="24.181360201511325" height="21.15869017632241" fill="#00000066" stroke="#000000" stroke-width="0.019850000000000003"/></g><g><rect data-type="rect" data-label="netId: GND
5
+ globalConnNetId: connectivity_net1" data-x="2.7849999999999993" data-y="-6.583455349999999" x="551.8891687657431" y="384.08060453400503" width="24.181360201511325" height="21.15869017632241" fill="#00000066" stroke="#000000" stroke-width="0.019850000000000003"/></g><g><rect data-type="rect" data-label="netId: V3_3
6
+ globalConnNetId: connectivity_net3" data-x="2.7849999999999993" data-y="-5.0034553499999985" x="548.8664987405541" y="304.4836272040302" width="30.226700251889156" height="21.158690176322466" fill="#ef444466" stroke="#ef4444" stroke-width="0.019850000000000003"/></g><g><circle data-type="point" data-label="schematic_port_20
7
+ x-" data-x="-6.655000000000001" data-y="-4.030455349999999" cx="88.41309823677585" cy="266.04534005037783" r="3" fill="hsl(184, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_21
8
+ x+" data-x="-4.655000000000001" data-y="-4.030455349999999" cx="189.16876574307304" cy="266.04534005037783" r="3" fill="hsl(184, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_22
9
+ x-" data-x="-1.6750000000000007" data-y="-5.193455349999998" cx="339.2947103274559" cy="324.63476070528964" r="3" fill="hsl(184, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_23
10
+ x-" data-x="-1.6750000000000007" data-y="-5.393455349999998" cx="339.2947103274559" cy="334.71032745591936" r="3" fill="hsl(184, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_24
11
+ x-" data-x="-1.6750000000000007" data-y="-5.593455349999998" cx="339.2947103274559" cy="344.78589420654913" r="3" fill="hsl(184, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_25
12
+ x+" data-x="0.3249999999999993" data-y="-5.493455349999998" cx="440.05037783375315" cy="339.7481108312342" r="3" fill="hsl(184, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_26
13
+ x+" data-x="0.3249999999999993" data-y="-5.293455349999999" cx="440.05037783375315" cy="329.67254408060455" r="3" fill="hsl(184, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_27
14
+ y+" data-x="-4.135000000000001" data-y="-5.313455349999998" cx="215.36523929471034" cy="330.68010075566747" r="3" fill="hsl(184, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_28
15
+ y-" data-x="-4.135000000000001" data-y="-6.073455349999998" cx="215.36523929471034" cy="368.9672544080604" r="3" fill="hsl(184, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_29
16
+ y+" data-x="-2.8950000000000005" data-y="-5.313455349999998" cx="277.8337531486146" cy="330.68010075566747" r="3" fill="hsl(184, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_30
17
+ y-" data-x="-2.8950000000000005" data-y="-6.073455349999998" cx="277.8337531486146" cy="368.9672544080604" r="3" fill="hsl(184, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_31
18
+ y+" data-x="1.544999999999999" data-y="-5.413455349999999" cx="501.51133501259443" cy="335.7178841309824" r="3" fill="hsl(184, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_32
19
+ y-" data-x="1.544999999999999" data-y="-6.1734553499999985" cx="501.51133501259443" cy="374.0050377833753" r="3" fill="hsl(184, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_33
20
+ y+" data-x="2.7849999999999993" data-y="-5.413455349999999" cx="563.9798488664987" cy="335.7178841309824" r="3" fill="hsl(184, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_34
21
+ y-" data-x="2.7849999999999993" data-y="-6.1734553499999985" cx="563.9798488664987" cy="374.0050377833753" r="3" fill="hsl(184, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="anchorPoint
22
+ orientation: y+" data-x="-7.136000000000002" data-y="-3.829455349999998" cx="64.18136020151132" cy="255.91939546599494" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g><circle data-type="point" data-label="anchorPoint
23
+ orientation: y+" data-x="-4.135000000000001" data-y="-4.030455349999999" cx="215.36523929471034" cy="266.04534005037783" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g><circle data-type="point" data-label="anchorPoint
24
+ orientation: y-" data-x="-2.8950000000000005" data-y="-6.273455349999998" cx="277.8337531486146" cy="379.0428211586901" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g><circle data-type="point" data-label="anchorPoint
25
+ orientation: y-" data-x="2.7849999999999993" data-y="-6.373455349999999" cx="563.9798488664987" cy="384.08060453400503" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g><circle data-type="point" data-label="anchorPoint
26
+ orientation: y+" data-x="2.7849999999999993" data-y="-5.2134553499999985" cx="563.9798488664987" cy="325.64231738035267" 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[
27
+ document.currentScript.parentElement.addEventListener('mousemove', (e) => {
28
+ const svg = e.currentTarget;
29
+ const rect = svg.getBoundingClientRect();
30
+ const x = e.clientX - rect.left;
31
+ const y = e.clientY - rect.top;
32
+ const crosshair = svg.getElementById('crosshair');
33
+ const h = svg.getElementById('crosshair-h');
34
+ const v = svg.getElementById('crosshair-v');
35
+ const coords = svg.getElementById('coordinates');
36
+
37
+ crosshair.style.display = 'block';
38
+ h.setAttribute('x1', '0');
39
+ h.setAttribute('x2', '640');
40
+ h.setAttribute('y1', y);
41
+ h.setAttribute('y2', y);
42
+ v.setAttribute('x1', x);
43
+ v.setAttribute('x2', x);
44
+ v.setAttribute('y1', '0');
45
+ v.setAttribute('y2', '640');
46
+
47
+ // Calculate real coordinates using inverse transformation
48
+ const matrix = {"a":50.37783375314861,"c":0,"e":423.67758186397987,"b":0,"d":-50.37783375314861,"f":62.99973047858953};
49
+ // Manually invert and apply the affine transform
50
+ // Since we only use translate and scale, we can directly compute:
51
+ // x' = (x - tx) / sx
52
+ // y' = (y - ty) / sy
53
+ const sx = matrix.a;
54
+ const sy = matrix.d;
55
+ const tx = matrix.e;
56
+ const ty = matrix.f;
57
+ const realPoint = {
58
+ x: (x - tx) / sx,
59
+ y: (y - ty) / sy // Flip y back since we used negative scale
60
+ }
61
+
62
+ coords.textContent = `(${realPoint.x.toFixed(2)}, ${realPoint.y.toFixed(2)})`;
63
+ coords.setAttribute('x', (x + 5).toString());
64
+ coords.setAttribute('y', (y - 5).toString());
65
+ });
66
+ document.currentScript.parentElement.addEventListener('mouseleave', () => {
67
+ document.currentScript.parentElement.getElementById('crosshair').style.display = 'none';
68
+ });
69
+ ]]></script></svg>