@tscircuit/schematic-trace-solver 0.0.45 → 0.0.46
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/.github/workflows/bun-formatcheck.yml +1 -1
- package/.github/workflows/bun-pver-release.yml +1 -1
- package/.github/workflows/bun-test.yml +1 -1
- package/.github/workflows/bun-typecheck.yml +1 -1
- package/dist/index.d.ts +29 -5
- package/dist/index.js +355 -90
- package/lib/solvers/TraceLabelOverlapAvoidanceSolver/TraceLabelOverlapAvoidanceSolver.ts +17 -3
- package/lib/solvers/TraceLabelOverlapAvoidanceSolver/detectTraceLabelOverlap.ts +26 -11
- package/lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/LabelMergingSolver/LabelMergingSolver.ts +95 -75
- package/lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/LabelMergingSolver/filterLabelsAtTraceEdges.ts +74 -0
- package/lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/LabelMergingSolver/groupLabelsByChipAndOrientation.ts +45 -0
- package/lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/LabelMergingSolver/mergeLabelGroup.ts +71 -0
- package/lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/OverlapAvoidanceStepSolver/OverlapAvoidanceStepSolver.ts +150 -27
- package/lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/OverlapAvoidanceStepSolver/isPointInsideLabel.ts +23 -0
- package/lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/OverlapAvoidanceStepSolver/visualizeDecomposition.ts +54 -0
- package/package.json +1 -1
- package/tests/solvers/TraceLabelOverlapAvoidanceSolver/__snapshots__/TraceLabelOverlapAvoidanceSolver.snap.svg +8 -8
|
@@ -6,14 +6,17 @@ import { visualizeInputProblem } from "lib/solvers/SchematicTracePipelineSolver/
|
|
|
6
6
|
import type { InputProblem } from "lib/types/InputProblem"
|
|
7
7
|
import { detectTraceLabelOverlap } from "../../detectTraceLabelOverlap"
|
|
8
8
|
import { SingleOverlapSolver } from "../SingleOverlapSolver/SingleOverlapSolver"
|
|
9
|
+
import { isPointInsideLabel } from "./isPointInsideLabel"
|
|
10
|
+
import { visualizeDecomposition } from "./visualizeDecomposition"
|
|
9
11
|
|
|
10
12
|
type Overlap = ReturnType<typeof detectTraceLabelOverlap>[0]
|
|
11
13
|
|
|
12
14
|
// Define a type for the input of the internal overlap solver to avoid conflicts
|
|
13
|
-
interface OverlapCollectionSolverInput {
|
|
15
|
+
export interface OverlapCollectionSolverInput {
|
|
14
16
|
inputProblem: InputProblem
|
|
15
17
|
traces: SolvedTracePath[]
|
|
16
|
-
|
|
18
|
+
initialNetLabelPlacements: NetLabelPlacement[]
|
|
19
|
+
mergedNetLabelPlacements: NetLabelPlacement[]
|
|
17
20
|
mergedLabelNetIdMap: Record<string, Set<string>>
|
|
18
21
|
}
|
|
19
22
|
|
|
@@ -23,7 +26,8 @@ interface OverlapCollectionSolverInput {
|
|
|
23
26
|
*/
|
|
24
27
|
export class OverlapAvoidanceStepSolver extends BaseSolver {
|
|
25
28
|
inputProblem: InputProblem
|
|
26
|
-
|
|
29
|
+
initialNetLabelPlacements: NetLabelPlacement[]
|
|
30
|
+
mergedNetLabelPlacements: NetLabelPlacement[]
|
|
27
31
|
mergedLabelNetIdMap: Record<string, Set<string>>
|
|
28
32
|
|
|
29
33
|
allTraces: SolvedTracePath[]
|
|
@@ -36,15 +40,21 @@ export class OverlapAvoidanceStepSolver extends BaseSolver {
|
|
|
36
40
|
private overlapQueue: Overlap[] = []
|
|
37
41
|
private recentlyFailed: Set<string> = new Set()
|
|
38
42
|
|
|
43
|
+
private currentlyProcessingOverlap: Overlap | null = null
|
|
44
|
+
private decomposedChildLabels: NetLabelPlacement[] | null = null
|
|
45
|
+
|
|
39
46
|
constructor(solverInput: OverlapCollectionSolverInput) {
|
|
40
47
|
super()
|
|
41
48
|
this.inputProblem = solverInput.inputProblem
|
|
42
|
-
this.
|
|
49
|
+
this.initialNetLabelPlacements = solverInput.initialNetLabelPlacements
|
|
50
|
+
this.mergedNetLabelPlacements = solverInput.mergedNetLabelPlacements
|
|
43
51
|
this.mergedLabelNetIdMap = solverInput.mergedLabelNetIdMap
|
|
44
52
|
this.allTraces = [...solverInput.traces]
|
|
45
53
|
}
|
|
46
54
|
|
|
47
55
|
override _step() {
|
|
56
|
+
this.currentlyProcessingOverlap = null
|
|
57
|
+
this.decomposedChildLabels = null
|
|
48
58
|
if (this.activeSubSolver) {
|
|
49
59
|
this.activeSubSolver.step()
|
|
50
60
|
|
|
@@ -65,19 +75,14 @@ export class OverlapAvoidanceStepSolver extends BaseSolver {
|
|
|
65
75
|
const overlapId = `${this.activeSubSolver.initialTrace.mspPairId}-${this.activeSubSolver.label.globalConnNetId}`
|
|
66
76
|
this.recentlyFailed.add(overlapId)
|
|
67
77
|
this.activeSubSolver = null
|
|
78
|
+
} else {
|
|
68
79
|
}
|
|
69
80
|
return
|
|
70
81
|
}
|
|
71
82
|
|
|
72
|
-
const overlaps = detectTraceLabelOverlap(
|
|
73
|
-
this.allTraces,
|
|
74
|
-
this.
|
|
75
|
-
).filter((o) => {
|
|
76
|
-
const originalNetIds = this.mergedLabelNetIdMap[o.label.globalConnNetId]
|
|
77
|
-
if (originalNetIds) {
|
|
78
|
-
return !originalNetIds.has(o.trace.globalConnNetId)
|
|
79
|
-
}
|
|
80
|
-
return o.trace.globalConnNetId !== o.label.globalConnNetId
|
|
83
|
+
const overlaps = detectTraceLabelOverlap({
|
|
84
|
+
traces: this.allTraces,
|
|
85
|
+
netLabels: this.mergedNetLabelPlacements,
|
|
81
86
|
})
|
|
82
87
|
|
|
83
88
|
if (overlaps.length === 0) {
|
|
@@ -85,6 +90,7 @@ export class OverlapAvoidanceStepSolver extends BaseSolver {
|
|
|
85
90
|
return
|
|
86
91
|
}
|
|
87
92
|
|
|
93
|
+
// Filter out overlaps that have recently failed to avoid infinite loops
|
|
88
94
|
const nonFailedOverlaps = overlaps.filter((o) => {
|
|
89
95
|
const overlapId = `${o.trace.mspPairId}-${o.label.globalConnNetId}`
|
|
90
96
|
return !this.recentlyFailed.has(overlapId)
|
|
@@ -98,24 +104,104 @@ export class OverlapAvoidanceStepSolver extends BaseSolver {
|
|
|
98
104
|
this.overlapQueue = nonFailedOverlaps
|
|
99
105
|
|
|
100
106
|
const nextOverlap = this.overlapQueue.shift()
|
|
107
|
+
this.currentlyProcessingOverlap = nextOverlap ?? null
|
|
101
108
|
|
|
102
109
|
if (nextOverlap) {
|
|
103
110
|
const traceToFix = this.allTraces.find(
|
|
104
111
|
(t) => t.mspPairId === nextOverlap.trace.mspPairId,
|
|
105
|
-
)
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
112
|
+
)!
|
|
113
|
+
const labelToAvoid = nextOverlap.label
|
|
114
|
+
const traceStartPoint = traceToFix.tracePath[0]
|
|
115
|
+
|
|
116
|
+
const originalNetIds =
|
|
117
|
+
this.mergedLabelNetIdMap[labelToAvoid.globalConnNetId]
|
|
118
|
+
const isSelfOverlap = originalNetIds?.has(traceToFix.globalConnNetId)
|
|
119
|
+
|
|
120
|
+
if (isSelfOverlap) {
|
|
121
|
+
const childLabels = this.initialNetLabelPlacements.filter((l) =>
|
|
122
|
+
originalNetIds.has(l.globalConnNetId),
|
|
123
|
+
)
|
|
124
|
+
this.decomposedChildLabels = childLabels
|
|
125
|
+
let actualOverlapLabel: NetLabelPlacement | null = null
|
|
126
|
+
|
|
127
|
+
for (const childLabel of childLabels) {
|
|
128
|
+
const overlapsWithChild = detectTraceLabelOverlap({
|
|
129
|
+
traces: [traceToFix],
|
|
130
|
+
netLabels: [childLabel],
|
|
131
|
+
})
|
|
132
|
+
if (overlapsWithChild.length > 0) {
|
|
133
|
+
actualOverlapLabel = childLabel
|
|
134
|
+
break
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (actualOverlapLabel) {
|
|
139
|
+
const labelId = actualOverlapLabel.globalConnNetId
|
|
140
|
+
const detourCount = this.detourCountByLabel[labelId] || 0
|
|
141
|
+
this.detourCountByLabel[labelId] = detourCount + 1
|
|
142
|
+
this.activeSubSolver = new SingleOverlapSolver({
|
|
143
|
+
trace: traceToFix,
|
|
144
|
+
label: actualOverlapLabel,
|
|
145
|
+
problem: this.inputProblem,
|
|
146
|
+
paddingBuffer: this.PADDING_BUFFER,
|
|
147
|
+
detourCount,
|
|
148
|
+
})
|
|
149
|
+
} else {
|
|
150
|
+
const overlapId = `${traceToFix.mspPairId}-${labelToAvoid.globalConnNetId}`
|
|
151
|
+
this.recentlyFailed.add(overlapId)
|
|
152
|
+
}
|
|
153
|
+
return
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (
|
|
157
|
+
originalNetIds &&
|
|
158
|
+
isPointInsideLabel({ point: traceStartPoint, label: labelToAvoid })
|
|
159
|
+
) {
|
|
160
|
+
const childLabels = this.initialNetLabelPlacements.filter((l) =>
|
|
161
|
+
originalNetIds.has(l.globalConnNetId),
|
|
162
|
+
)
|
|
163
|
+
this.decomposedChildLabels = childLabels
|
|
164
|
+
let actualOverlapLabel: NetLabelPlacement | null = null
|
|
165
|
+
|
|
166
|
+
for (const childLabel of childLabels) {
|
|
167
|
+
const overlapsWithChild = detectTraceLabelOverlap({
|
|
168
|
+
traces: [traceToFix],
|
|
169
|
+
netLabels: [childLabel],
|
|
170
|
+
})
|
|
171
|
+
if (overlapsWithChild.length > 0) {
|
|
172
|
+
actualOverlapLabel = childLabel
|
|
173
|
+
break
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (actualOverlapLabel) {
|
|
178
|
+
const labelId = actualOverlapLabel.globalConnNetId
|
|
179
|
+
const detourCount = this.detourCountByLabel[labelId] || 0
|
|
180
|
+
this.detourCountByLabel[labelId] = detourCount + 1
|
|
181
|
+
this.activeSubSolver = new SingleOverlapSolver({
|
|
182
|
+
trace: traceToFix,
|
|
183
|
+
label: actualOverlapLabel,
|
|
184
|
+
problem: this.inputProblem,
|
|
185
|
+
paddingBuffer: this.PADDING_BUFFER,
|
|
186
|
+
detourCount,
|
|
187
|
+
})
|
|
188
|
+
} else {
|
|
189
|
+
const overlapId = `${traceToFix.mspPairId}-${labelToAvoid.globalConnNetId}`
|
|
190
|
+
this.recentlyFailed.add(overlapId)
|
|
191
|
+
}
|
|
192
|
+
return
|
|
118
193
|
}
|
|
194
|
+
|
|
195
|
+
const labelId = labelToAvoid.globalConnNetId
|
|
196
|
+
const detourCount = this.detourCountByLabel[labelId] || 0
|
|
197
|
+
this.detourCountByLabel[labelId] = detourCount + 1
|
|
198
|
+
this.activeSubSolver = new SingleOverlapSolver({
|
|
199
|
+
trace: traceToFix,
|
|
200
|
+
label: labelToAvoid,
|
|
201
|
+
problem: this.inputProblem,
|
|
202
|
+
paddingBuffer: this.PADDING_BUFFER,
|
|
203
|
+
detourCount,
|
|
204
|
+
})
|
|
119
205
|
}
|
|
120
206
|
}
|
|
121
207
|
|
|
@@ -130,7 +216,7 @@ export class OverlapAvoidanceStepSolver extends BaseSolver {
|
|
|
130
216
|
if (this.activeSubSolver) {
|
|
131
217
|
return this.activeSubSolver.visualize()
|
|
132
218
|
}
|
|
133
|
-
|
|
219
|
+
|
|
134
220
|
const graphics = visualizeInputProblem(this.inputProblem)
|
|
135
221
|
if (!graphics.lines) graphics.lines = []
|
|
136
222
|
for (const trace of this.allTraces) {
|
|
@@ -139,6 +225,43 @@ export class OverlapAvoidanceStepSolver extends BaseSolver {
|
|
|
139
225
|
strokeColor: "purple",
|
|
140
226
|
})
|
|
141
227
|
}
|
|
228
|
+
|
|
229
|
+
if (this.currentlyProcessingOverlap) {
|
|
230
|
+
const { trace, label } = this.currentlyProcessingOverlap
|
|
231
|
+
|
|
232
|
+
// Highlight the colliding trace
|
|
233
|
+
graphics.lines!.push({
|
|
234
|
+
points: trace.tracePath,
|
|
235
|
+
strokeColor: "red",
|
|
236
|
+
})
|
|
237
|
+
|
|
238
|
+
if (this.decomposedChildLabels) {
|
|
239
|
+
visualizeDecomposition({
|
|
240
|
+
decomposedChildLabels: this.decomposedChildLabels,
|
|
241
|
+
collidingTrace: trace,
|
|
242
|
+
mergedLabel: label,
|
|
243
|
+
graphics,
|
|
244
|
+
})
|
|
245
|
+
} else {
|
|
246
|
+
// Standard case: highlight the entire label
|
|
247
|
+
if (!graphics.rects) graphics.rects = []
|
|
248
|
+
graphics.rects.push({
|
|
249
|
+
center: label.center,
|
|
250
|
+
width: label.width,
|
|
251
|
+
height: label.height,
|
|
252
|
+
fill: "yellow",
|
|
253
|
+
})
|
|
254
|
+
if (!graphics.texts) graphics.texts = []
|
|
255
|
+
graphics.texts.push({
|
|
256
|
+
x: label.center.x,
|
|
257
|
+
y: label.center.y + label.height / 2 + 0.5,
|
|
258
|
+
text: `COLLISION: Trace ${trace.mspPairId} vs Label ${label.globalConnNetId}`,
|
|
259
|
+
fontSize: 0.3,
|
|
260
|
+
color: "red",
|
|
261
|
+
})
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
142
265
|
return graphics
|
|
143
266
|
}
|
|
144
267
|
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { Point } from "graphics-debug"
|
|
2
|
+
import type { NetLabelPlacement } from "lib/solvers/NetLabelPlacementSolver/NetLabelPlacementSolver"
|
|
3
|
+
import { getRectBounds } from "lib/solvers/NetLabelPlacementSolver/SingleNetLabelPlacementSolver/geometry"
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Checks if a point is inside the bounding box of a net label.
|
|
7
|
+
*/
|
|
8
|
+
export const isPointInsideLabel = ({
|
|
9
|
+
point,
|
|
10
|
+
label,
|
|
11
|
+
}: {
|
|
12
|
+
point: Point
|
|
13
|
+
label: NetLabelPlacement
|
|
14
|
+
}): boolean => {
|
|
15
|
+
const bounds = getRectBounds(label.center, label.width, label.height)
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
point.x >= bounds.minX &&
|
|
19
|
+
point.x <= bounds.maxX &&
|
|
20
|
+
point.y >= bounds.minY &&
|
|
21
|
+
point.y <= bounds.maxY
|
|
22
|
+
)
|
|
23
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { GraphicsObject } from "graphics-debug"
|
|
2
|
+
import type { NetLabelPlacement } from "lib/solvers/NetLabelPlacementSolver/NetLabelPlacementSolver"
|
|
3
|
+
import type { SolvedTracePath } from "lib/solvers/SchematicTraceLinesSolver/SchematicTraceLinesSolver"
|
|
4
|
+
|
|
5
|
+
interface VisualizeDecompositionParams {
|
|
6
|
+
decomposedChildLabels: NetLabelPlacement[]
|
|
7
|
+
collidingTrace: SolvedTracePath
|
|
8
|
+
mergedLabel: NetLabelPlacement
|
|
9
|
+
graphics: GraphicsObject
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Visualizes the decomposition of a merged label during overlap avoidance.
|
|
14
|
+
* It draws individual child labels with distinct colors based on their relation
|
|
15
|
+
* to the colliding trace and adds a textual report to the graphics.
|
|
16
|
+
*
|
|
17
|
+
* @param {VisualizeDecompositionParams} params - The parameters for visualization.
|
|
18
|
+
* @param {NetLabelPlacement[]} params.decomposedChildLabels - The individual labels that make up the merged group.
|
|
19
|
+
* @param {SolvedTracePath} params.collidingTrace - The trace that is currently colliding with the merged label.
|
|
20
|
+
* @param {NetLabelPlacement} params.mergedLabel - The original merged label that is being decomposed.
|
|
21
|
+
* @param {GraphicsObject} params.graphics - The graphics object to which the visualization elements will be added.
|
|
22
|
+
* @returns {GraphicsObject} The modified graphics object with decomposition visualization elements.
|
|
23
|
+
*/
|
|
24
|
+
export const visualizeDecomposition = (
|
|
25
|
+
params: VisualizeDecompositionParams,
|
|
26
|
+
): GraphicsObject => {
|
|
27
|
+
const { decomposedChildLabels, collidingTrace, mergedLabel, graphics } =
|
|
28
|
+
params
|
|
29
|
+
|
|
30
|
+
if (!graphics.rects) graphics.rects = []
|
|
31
|
+
if (!graphics.texts) graphics.texts = []
|
|
32
|
+
|
|
33
|
+
for (const childLabel of decomposedChildLabels) {
|
|
34
|
+
const isOwnLabel =
|
|
35
|
+
childLabel.globalConnNetId === collidingTrace.globalConnNetId
|
|
36
|
+
|
|
37
|
+
graphics.rects.push({
|
|
38
|
+
center: childLabel.center,
|
|
39
|
+
width: childLabel.width,
|
|
40
|
+
height: childLabel.height,
|
|
41
|
+
fill: isOwnLabel ? "green" : "red", // Green for own label, red for others
|
|
42
|
+
})
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
graphics.texts.push({
|
|
46
|
+
x: mergedLabel.center.x,
|
|
47
|
+
y: mergedLabel.center.y + mergedLabel.height / 2 + 0.5,
|
|
48
|
+
text: `DECOMPOSITION: Trace ${collidingTrace.mspPairId} vs Merged Label ${mergedLabel.globalConnNetId}`,
|
|
49
|
+
fontSize: 0.3,
|
|
50
|
+
color: "blue",
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
return graphics
|
|
54
|
+
}
|
package/package.json
CHANGED
|
@@ -160,28 +160,28 @@ x-" data-x="-0.42" data-y="-0.1" cx="279.0224461302513" cy="382.68590086027035"
|
|
|
160
160
|
<rect data-type="rect" data-label="schematic_component_6" data-x="0" data-y="0" x="277.802876074604" y="349.51359534666426" width="43.416693981043295" height="56.58805058203393" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.020499027410714285" />
|
|
161
161
|
</g>
|
|
162
162
|
<g>
|
|
163
|
-
<rect data-type="rect" data-label="
|
|
163
|
+
<rect data-type="rect" data-label="connectivity_net2" data-x="6" data-y="0.776" x="587.3297561978845" y="328.976035609564" width="9.756560445178138" height="21.952261001651095" fill="hsl(40, 100%, 50%, 0.3)" stroke="hsl(40, 100%, 50%, 1)" stroke-width="0.020499027410714285" />
|
|
164
164
|
</g>
|
|
165
165
|
<g>
|
|
166
|
-
<rect data-type="rect" data-label="
|
|
166
|
+
<rect data-type="rect" data-label="connectivity_net2" data-x="3.7199999999999998" data-y="3.225" x="476.10496712285226" y="209.50695295835615" width="9.756560445178252" height="21.952261001651095" fill="hsl(40, 100%, 50%, 0.3)" stroke="hsl(40, 100%, 50%, 1)" stroke-width="0.020499027410714285" />
|
|
167
167
|
</g>
|
|
168
168
|
<g>
|
|
169
|
-
<rect data-type="rect" data-label="
|
|
169
|
+
<rect data-type="rect" data-label="connectivity_net1" data-x="0.3" data-y="0.8059999999999999" x="309.2677835103039" y="327.51255154278726" width="9.756560445178309" height="21.952261001651095" fill="hsl(40, 100%, 50%, 0.3)" stroke="hsl(40, 100%, 50%, 1)" stroke-width="0.020499027410714285" />
|
|
170
170
|
</g>
|
|
171
171
|
<g>
|
|
172
|
-
<rect data-type="rect" data-label="
|
|
172
|
+
<rect data-type="rect" data-label="connectivity_net1" data-x="0.78" data-y="3.1950000000000003" x="332.68352857873174" y="210.97043702513287" width="9.756560445178252" height="21.952261001651124" fill="hsl(40, 100%, 50%, 0.3)" stroke="hsl(40, 100%, 50%, 1)" stroke-width="0.020499027410714285" />
|
|
173
173
|
</g>
|
|
174
174
|
<g>
|
|
175
|
-
<rect data-type="rect" data-label="
|
|
175
|
+
<rect data-type="rect" data-label="connectivity_net3" data-x="6" data-y="-0.7010000000000001" x="587.3297561978845" y="404.68694466414735" width="9.756560445178138" height="14.634840667767378" fill="hsl(40, 100%, 50%, 0.3)" stroke="hsl(40, 100%, 50%, 1)" stroke-width="0.020499027410714285" />
|
|
176
176
|
</g>
|
|
177
177
|
<g>
|
|
178
|
-
<rect data-type="rect" data-label="
|
|
178
|
+
<rect data-type="rect" data-label="connectivity_net3" data-x="3" data-y="-0.93" x="440.9813495202105" y="415.85820637387644" width="9.756560445178309" height="14.634840667767435" fill="hsl(40, 100%, 50%, 0.3)" stroke="hsl(40, 100%, 50%, 1)" stroke-width="0.020499027410714285" />
|
|
179
179
|
</g>
|
|
180
180
|
<g>
|
|
181
|
-
<rect data-type="rect" data-label="
|
|
181
|
+
<rect data-type="rect" data-label="connectivity_net0" data-x="-4.78" data-y="2.7600000000000002" x="55.35329792453959" y="238.288806271632" width="21.95226100165104" height="9.75656044517828" fill="hsl(40, 100%, 50%, 0.3)" stroke="hsl(40, 100%, 50%, 1)" stroke-width="0.020499027410714285" />
|
|
182
182
|
</g>
|
|
183
183
|
<g>
|
|
184
|
-
<rect data-type="rect" data-label="
|
|
184
|
+
<rect data-type="rect" data-label="connectivity_net4" data-x="-1.08373445" data-y="0.12500000000000014" x="241.7653395028014" y="360.73363985861926" width="9.75656044517828" height="21.952261001651095" fill="hsl(40, 100%, 50%, 0.3)" stroke="hsl(40, 100%, 50%, 1)" stroke-width="0.020499027410714285" />
|
|
185
185
|
</g>
|
|
186
186
|
<g id="crosshair" style="display: none">
|
|
187
187
|
<line id="crosshair-h" y1="0" y2="640" stroke="#666" stroke-width="0.5" />
|