@tscircuit/schematic-trace-solver 0.0.43 → 0.0.45

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 (27) hide show
  1. package/dist/index.d.ts +17 -3
  2. package/dist/index.js +809 -86
  3. package/lib/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver.ts +0 -1
  4. package/lib/solvers/TraceCleanupSolver/TraceCleanupSolver.ts +83 -36
  5. package/lib/solvers/TraceCleanupSolver/hasCollisions.ts +16 -4
  6. package/lib/solvers/TraceCleanupSolver/is4PointRectangle.ts +17 -0
  7. package/lib/solvers/TraceCleanupSolver/isSegmentAnEndpointSegment.ts +36 -0
  8. package/lib/solvers/TraceCleanupSolver/mergeGraphicsObjects.ts +28 -0
  9. package/lib/solvers/TraceCleanupSolver/minimizeTurnsWithFilteredLabels.ts +18 -1
  10. package/lib/solvers/TraceCleanupSolver/recognizeStairStepPattern.ts +56 -0
  11. package/lib/solvers/TraceCleanupSolver/sub-solver/UntangleTraceSubsolver.ts +370 -0
  12. package/lib/solvers/TraceCleanupSolver/sub-solver/findAllLShapedTurns.ts +48 -0
  13. package/lib/solvers/TraceCleanupSolver/sub-solver/findIntersectionsWithObstacles.ts +36 -0
  14. package/lib/solvers/TraceCleanupSolver/sub-solver/generateLShapeRerouteCandidates.ts +107 -0
  15. package/lib/solvers/TraceCleanupSolver/sub-solver/generateRectangleCandidates.ts +55 -0
  16. package/lib/solvers/TraceCleanupSolver/sub-solver/getTraceObstacles.ts +25 -0
  17. package/lib/solvers/TraceCleanupSolver/sub-solver/isPathColliding.ts +58 -0
  18. package/lib/solvers/TraceCleanupSolver/sub-solver/visualizeCandidates.ts +33 -0
  19. package/lib/solvers/TraceCleanupSolver/sub-solver/visualizeCollision.ts +20 -0
  20. package/lib/solvers/TraceCleanupSolver/sub-solver/visualizeIntersectionPoints.ts +26 -0
  21. package/lib/solvers/TraceCleanupSolver/sub-solver/visualizeLSapes.ts +33 -0
  22. package/lib/solvers/TraceCleanupSolver/turnMinimization.ts +50 -56
  23. package/lib/solvers/TraceCleanupSolver/visualizeTightRectangle.ts +24 -0
  24. package/lib/solvers/TraceOverlapShiftSolver/TraceOverlapShiftSolver.ts +83 -0
  25. package/package.json +1 -1
  26. package/tests/examples/__snapshots__/example16.snap.svg +4 -4
  27. package/tests/examples/__snapshots__/example29.snap.svg +7 -7
@@ -0,0 +1,33 @@
1
+ import type { GraphicsObject } from "graphics-debug"
2
+ import type { Point } from "@tscircuit/math-utils"
3
+
4
+ /**
5
+ * Visualizes a set of candidate paths and optional intersection points.
6
+ * It draws each candidate path as a line with a specified color and marks intersection points with green circles.
7
+ * This function is useful for debugging and understanding the rerouting process.
8
+ */
9
+ export const visualizeCandidates = (
10
+ candidates: Point[][],
11
+ color = "gray",
12
+ intersectionPoints: Point[] = [],
13
+ ): GraphicsObject => {
14
+ const graphics: GraphicsObject = { lines: [], circles: [] }
15
+
16
+ for (const candidate of candidates) {
17
+ graphics.lines!.push({
18
+ points: candidate,
19
+ strokeColor: color,
20
+ })
21
+ }
22
+
23
+ // Draw intersection points
24
+ for (const point of intersectionPoints) {
25
+ graphics.circles!.push({
26
+ center: point,
27
+ radius: 0.01, // Larger radius for intersection points
28
+ fill: "green",
29
+ })
30
+ }
31
+
32
+ return graphics
33
+ }
@@ -0,0 +1,20 @@
1
+ import type { GraphicsObject } from "graphics-debug"
2
+ import type { CollisionInfo } from "./isPathColliding"
3
+
4
+ /**
5
+ * Visualizes a collision point if collision information is provided and a collision occurred.
6
+ * It draws a red circle at the collision point to highlight the location of the collision.
7
+ */
8
+ export const visualizeCollision = (
9
+ collisionInfo: CollisionInfo | null,
10
+ ): GraphicsObject => {
11
+ const collisionGraphics: GraphicsObject = { circles: [] }
12
+ if (collisionInfo?.isColliding && collisionInfo.collisionPoint) {
13
+ collisionGraphics.circles!.push({
14
+ center: collisionInfo.collisionPoint,
15
+ radius: 0.01,
16
+ fill: "red",
17
+ })
18
+ }
19
+ return collisionGraphics
20
+ }
@@ -0,0 +1,26 @@
1
+ import type { Point } from "@tscircuit/math-utils"
2
+ import type { GraphicsObject } from "graphics-debug"
3
+
4
+ /**
5
+ * Visualizes a set of intersection points by drawing circles at their locations.
6
+ * This function is used to highlight where different trace segments or obstacles intersect.
7
+ */
8
+ export const visualizeIntersectionPoints = (
9
+ points: Point[],
10
+ color = "red",
11
+ ): GraphicsObject => {
12
+ const graphics: GraphicsObject = { circles: [] }
13
+
14
+ for (const point of points) {
15
+ graphics.circles!.push({
16
+ center: {
17
+ x: point.x,
18
+ y: point.y,
19
+ },
20
+ radius: 0.01,
21
+ fill: color,
22
+ })
23
+ }
24
+
25
+ return graphics
26
+ }
@@ -0,0 +1,33 @@
1
+ import type { LShape } from "./findAllLShapedTurns"
2
+ import type { GraphicsObject } from "graphics-debug"
3
+
4
+ /**
5
+ * Visualizes L-shaped turns by drawing a blue circle at the corner point (p2)
6
+ * and light blue lines connecting p1, p2, and p3.
7
+ * This function can visualize a single L-shape or an array of L-shapes.
8
+ */
9
+ export const visualizeLSapes = (lShapes: LShape[] | LShape): GraphicsObject => {
10
+ const graphics: GraphicsObject = { circles: [], lines: [] }
11
+
12
+ const lShapesArray = Array.isArray(lShapes) ? lShapes : [lShapes]
13
+
14
+ for (const lShape of lShapesArray) {
15
+ // Draw the center point as a blue ball
16
+ graphics.circles!.push({
17
+ center: {
18
+ x: lShape.p2.x,
19
+ y: lShape.p2.y,
20
+ },
21
+ radius: 0.01,
22
+ fill: "blue",
23
+ })
24
+
25
+ // Draw the two lines in a light blue color
26
+ graphics.lines!.push({
27
+ points: [lShape.p1, lShape.p2, lShape.p3],
28
+ strokeColor: "lightblue",
29
+ })
30
+ }
31
+
32
+ return graphics
33
+ }
@@ -4,75 +4,32 @@ import { countTurns } from "./countTurns"
4
4
  import { simplifyPath } from "./simplifyPath"
5
5
  import { tryConnectPoints } from "./tryConnectPoints"
6
6
  import { hasCollisionsWithLabels } from "./hasCollisionsWithLabels"
7
-
7
+ import { recognizeStairStepPattern } from "./recognizeStairStepPattern"
8
+ import { isSegmentAnEndpointSegment } from "./isSegmentAnEndpointSegment"
9
+
10
+ /**
11
+ * Minimizes the number of turns in a given path while avoiding collisions with obstacles and labels.
12
+ * This function employs an iterative approach, attempting to simplify the path in several ways:
13
+ * 1. **Stair-step pattern recognition**: It first looks for and attempts to simplify stair-step patterns by connecting the start and end points of the pattern with a simpler path, if no collisions are introduced.
14
+ * 2. **Point removal and reconnection**: If no stair-step optimization is possible, it tries to remove intermediate points and reconnect the remaining segments with a simpler path, prioritizing solutions that reduce turns or path length.
15
+ * 3. **Collinear segment merging**: Finally, it attempts to merge collinear segments to further simplify the path.
16
+ * The process continues until no further improvements can be made without introducing collisions.
17
+ */
8
18
  export const minimizeTurns = ({
9
19
  path,
10
20
  obstacles,
11
21
  labelBounds,
22
+ originalPath,
12
23
  }: {
13
24
  path: Point[]
14
25
  obstacles: any[]
15
26
  labelBounds: any[]
27
+ originalPath: Point[]
16
28
  }): Point[] => {
17
29
  if (path.length <= 2) {
18
30
  return path
19
31
  }
20
32
 
21
- const recognizeStairStepPattern = (
22
- pathToCheck: Point[],
23
- startIdx: number,
24
- ): number => {
25
- if (startIdx >= pathToCheck.length - 3) return -1
26
-
27
- let endIdx = startIdx
28
- let isStairStep = true
29
-
30
- for (
31
- let i = startIdx;
32
- i < pathToCheck.length - 2 && i < startIdx + 10;
33
- i++
34
- ) {
35
- if (i + 2 >= pathToCheck.length) break
36
-
37
- const p1 = pathToCheck[i]
38
- const p2 = pathToCheck[i + 1]
39
- const p3 = pathToCheck[i + 2]
40
-
41
- const seg1Vertical = p1.x === p2.x
42
- const seg2Vertical = p2.x === p3.x
43
-
44
- if (seg1Vertical === seg2Vertical) {
45
- break
46
- }
47
-
48
- const seg1Direction = seg1Vertical
49
- ? Math.sign(p2.y - p1.y)
50
- : Math.sign(p2.x - p1.x)
51
-
52
- if (i > startIdx) {
53
- const prevP = pathToCheck[i - 1]
54
- const prevSegVertical = prevP.x === p1.x
55
- const prevDirection = prevSegVertical
56
- ? Math.sign(p1.y - prevP.y)
57
- : Math.sign(p1.x - prevP.x)
58
-
59
- if (
60
- (seg1Vertical &&
61
- prevSegVertical &&
62
- seg1Direction !== prevDirection) ||
63
- (!seg1Vertical && !prevSegVertical && seg1Direction !== prevDirection)
64
- ) {
65
- isStairStep = false
66
- break
67
- }
68
- }
69
-
70
- endIdx = i + 2
71
- }
72
-
73
- return isStairStep && endIdx - startIdx >= 3 ? endIdx : -1
74
- }
75
-
76
33
  let optimizedPath = [...path]
77
34
  let currentTurns = countTurns(optimizedPath)
78
35
  let improved = true
@@ -85,6 +42,21 @@ export const minimizeTurns = ({
85
42
  const stairEndIdx = recognizeStairStepPattern(optimizedPath, startIdx)
86
43
 
87
44
  if (stairEndIdx > 0) {
45
+ if (
46
+ isSegmentAnEndpointSegment(
47
+ optimizedPath[startIdx],
48
+ optimizedPath[startIdx + 1],
49
+ originalPath,
50
+ ) ||
51
+ isSegmentAnEndpointSegment(
52
+ optimizedPath[stairEndIdx - 1],
53
+ optimizedPath[stairEndIdx],
54
+ originalPath,
55
+ )
56
+ ) {
57
+ continue
58
+ }
59
+
88
60
  const startPoint = optimizedPath[startIdx]
89
61
  const endPoint = optimizedPath[stairEndIdx]
90
62
 
@@ -129,6 +101,21 @@ export const minimizeTurns = ({
129
101
 
130
102
  if (endIdx >= optimizedPath.length) continue
131
103
 
104
+ if (
105
+ isSegmentAnEndpointSegment(
106
+ optimizedPath[startIdx],
107
+ optimizedPath[startIdx + 1],
108
+ originalPath,
109
+ ) ||
110
+ isSegmentAnEndpointSegment(
111
+ optimizedPath[endIdx - 1],
112
+ optimizedPath[endIdx],
113
+ originalPath,
114
+ )
115
+ ) {
116
+ continue
117
+ }
118
+
132
119
  const startPoint = optimizedPath[startIdx]
133
120
  const endPoint = optimizedPath[endIdx]
134
121
 
@@ -179,6 +166,13 @@ export const minimizeTurns = ({
179
166
  const p2 = optimizedPath[i + 1]
180
167
  const p3 = optimizedPath[i + 2]
181
168
 
169
+ if (
170
+ isSegmentAnEndpointSegment(p1, p2, originalPath) ||
171
+ isSegmentAnEndpointSegment(p2, p3, originalPath)
172
+ ) {
173
+ continue
174
+ }
175
+
182
176
  const allVertical = p1.x === p2.x && p2.x === p3.x
183
177
  const allHorizontal = p1.y === p2.y && p2.y === p3.y
184
178
 
@@ -0,0 +1,24 @@
1
+ import type { GraphicsObject } from "graphics-debug"
2
+ import type { Rectangle } from "./sub-solver/generateRectangleCandidates"
3
+
4
+ /**
5
+ * Visualizes a given rectangle by drawing it as a green-stroked rectangle.
6
+ * This function is useful for highlighting specific rectangular areas in a graphical representation.
7
+ */
8
+ export const visualizeTightRectangle = (
9
+ rectangle: Rectangle,
10
+ ): GraphicsObject => {
11
+ const graphics: GraphicsObject = { rects: [] }
12
+
13
+ graphics.rects!.push({
14
+ center: {
15
+ x: rectangle.x + rectangle.width / 2,
16
+ y: rectangle.y + rectangle.height / 2,
17
+ },
18
+ width: rectangle.width,
19
+ height: rectangle.height,
20
+ stroke: "green",
21
+ })
22
+
23
+ return graphics
24
+ }
@@ -42,6 +42,8 @@ export class TraceOverlapShiftSolver extends BaseSolver {
42
42
 
43
43
  correctedTraceMap: Record<MspConnectionPairId, SolvedTracePath> = {}
44
44
 
45
+ cleanupPhase: "diagonals" | "done" | null = null
46
+
45
47
  constructor(params: {
46
48
  inputProblem: InputProblem
47
49
  inputTracePaths: Array<SolvedTracePath>
@@ -211,6 +213,62 @@ export class TraceOverlapShiftSolver extends BaseSolver {
211
213
  return null
212
214
  }
213
215
 
216
+ private findNextDiagonalSegment() {
217
+ const EPS = 2e-3
218
+ for (const mspPairId in this.correctedTraceMap) {
219
+ const tracePath = this.correctedTraceMap[mspPairId]!.tracePath
220
+ for (let i = 0; i < tracePath.length - 1; i++) {
221
+ const p1 = tracePath[i]!
222
+ const p2 = tracePath[i + 1]!
223
+
224
+ const isHorizontal = Math.abs(p1.y - p2.y) < EPS
225
+ const isVertical = Math.abs(p1.x - p2.x) < EPS
226
+
227
+ if (!isHorizontal && !isVertical) {
228
+ return { mspPairId, tracePath, i, p1, p2 }
229
+ }
230
+ }
231
+ }
232
+ return null
233
+ }
234
+
235
+ private findAndFixNextDiagonalSegment(): boolean {
236
+ const diagonalInfo = this.findNextDiagonalSegment()
237
+
238
+ if (!diagonalInfo) {
239
+ return false // No diagonal segments found
240
+ }
241
+
242
+ const { mspPairId, tracePath, i, p1, p2 } = diagonalInfo
243
+ const EPS = 2e-3
244
+
245
+ const p0 = i > 0 ? tracePath[i - 1] : null
246
+ const p3 = i + 2 < tracePath.length ? tracePath[i + 2] : null
247
+
248
+ const prevIsVertical = p0 ? Math.abs(p0.x - p1.x) < EPS : false
249
+ const prevIsHorizontal = p0 ? Math.abs(p0.y - p1.y) < EPS : false
250
+
251
+ const nextIsVertical = p3 ? Math.abs(p2.x - p3.x) < EPS : false
252
+ const nextIsHorizontal = p3 ? Math.abs(p2.y - p3.y) < EPS : false
253
+
254
+ const elbow1 = { x: p1.x, y: p2.y } // vertical from p1
255
+ const elbow2 = { x: p2.x, y: p1.y } // horizontal from p1
256
+
257
+ let score1 = 0
258
+ if (prevIsVertical) score1++
259
+ if (nextIsHorizontal) score1++
260
+
261
+ let score2 = 0
262
+ if (prevIsHorizontal) score2++
263
+ if (nextIsVertical) score2++
264
+
265
+ const elbowPoint = score1 < score2 ? elbow1 : elbow2
266
+
267
+ // Replace [p1, p2] with [p1, elbowPoint, p2]
268
+ tracePath.splice(i + 1, 0, elbowPoint)
269
+ return true // Fixed one diagonal, return true to re-evaluate in next step
270
+ }
271
+
214
272
  override _step() {
215
273
  if (this.activeSubSolver?.solved) {
216
274
  for (const [mspPairId, newTrace] of Object.entries(
@@ -231,6 +289,19 @@ export class TraceOverlapShiftSolver extends BaseSolver {
231
289
  const overlapIssue = this.findNextOverlapIssue()
232
290
 
233
291
  if (overlapIssue === null) {
292
+ if (this.cleanupPhase === null) {
293
+ this.cleanupPhase = "diagonals"
294
+ }
295
+
296
+ if (this.cleanupPhase === "diagonals") {
297
+ const fixedDiagonal = this.findAndFixNextDiagonalSegment()
298
+ if (!fixedDiagonal) {
299
+ this.cleanupPhase = "done"
300
+ this.solved = true
301
+ }
302
+ return
303
+ }
304
+ // If cleanupPhase is "done", then the solver is truly solved.
234
305
  this.solved = true
235
306
  return
236
307
  }
@@ -249,6 +320,7 @@ export class TraceOverlapShiftSolver extends BaseSolver {
249
320
  }
250
321
 
251
322
  const graphics = visualizeInputProblem(this.inputProblem)
323
+ graphics.circles = graphics.circles || []
252
324
 
253
325
  // Draw current corrected traces
254
326
  for (const trace of Object.values(this.correctedTraceMap)) {
@@ -258,6 +330,17 @@ export class TraceOverlapShiftSolver extends BaseSolver {
258
330
  })
259
331
  }
260
332
 
333
+ if (this.cleanupPhase === "diagonals") {
334
+ const diagonalInfo = this.findNextDiagonalSegment()
335
+ if (diagonalInfo) {
336
+ graphics.lines!.push({
337
+ points: [diagonalInfo.p1, diagonalInfo.p2],
338
+ strokeColor: "red",
339
+ strokeWidth: 0.05,
340
+ })
341
+ }
342
+ }
343
+
261
344
  return graphics
262
345
  }
263
346
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tscircuit/schematic-trace-solver",
3
3
  "main": "dist/index.js",
4
- "version": "0.0.43",
4
+ "version": "0.0.45",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "start": "cosmos",
@@ -51,7 +51,7 @@ x-" data-x="1.6" data-y="1.7049999999999998" cx="353.6" cy="244.12000000000006"
51
51
  <circle data-type="point" data-label="" data-x="1.6" data-y="1.7049999999999998" cx="353.6" cy="244.12000000000006" r="3" fill="hsl(40, 100%, 50%, 0.9)" />
52
52
  </g>
53
53
  <g>
54
- <circle data-type="point" data-label="" data-x="1.3" data-y="1.0025" cx="320" cy="322.80000000000007" r="3" fill="hsl(40, 100%, 50%, 0.9)" />
54
+ <circle data-type="point" data-label="" data-x="1.3" data-y="0.09999999999999998" cx="320" cy="423.88000000000005" r="3" fill="hsl(40, 100%, 50%, 0.9)" />
55
55
  </g>
56
56
  <g>
57
57
  <circle data-type="point" data-label="" data-x="0.9490000000000001" data-y="2.105" cx="280.68800000000005" cy="199.32000000000005" r="3" fill="hsl(40, 100%, 50%, 0.9)" />
@@ -66,10 +66,10 @@ x-" data-x="1.6" data-y="1.7049999999999998" cx="353.6" cy="244.12000000000006"
66
66
  <polyline data-points="1.2000000000000002,0.30000000000000004 1.6,2.105" data-type="line" data-label="" points="308.80000000000007,401.48 353.6,199.32000000000005" fill="none" stroke="hsl(190, 100%, 50%, 0.8)" stroke-width="1" stroke-dasharray="4 2" />
67
67
  </g>
68
68
  <g>
69
- <polyline data-points="1.2000000000000002,0.09999999999999998 1.4000000000000001,0.09999999999999998 1.3,1.0025 1.3,1.5049999999999997 1.049,1.5049999999999997 1.049,1.905 1.6,1.9049999999999998" data-type="line" data-label="" points="308.80000000000007,423.88000000000005 331.20000000000005,423.88000000000005 320,322.80000000000007 320,266.5200000000001 291.88800000000003,266.5200000000001 291.88800000000003,221.72000000000003 353.6,221.72000000000006" fill="none" stroke="purple" stroke-width="1" />
69
+ <polyline data-points="1.2000000000000002,0.09999999999999998 1.3,0.09999999999999998 1.3,1.5049999999999997 1.049,1.5049999999999997 1.049,1.905 1.6,1.9049999999999998" data-type="line" data-label="" points="308.80000000000007,423.88000000000005 320,423.88000000000005 320,266.5200000000001 291.88800000000003,266.5200000000001 291.88800000000003,221.72000000000003 353.6,221.72000000000006" fill="none" stroke="purple" stroke-width="1" />
70
70
  </g>
71
71
  <g>
72
- <polyline data-points="1.2000000000000002,0.30000000000000004 1.4000000000000001,0.30000000000000004 1.5000000000000002,1.2025000000000001 1.5000000000000002,1.4049999999999998 0.9490000000000001,1.4049999999999998 0.9490000000000001,2.105 1.6,2.105" data-type="line" data-label="" points="308.80000000000007,401.48 331.20000000000005,401.48 342.4000000000001,300.40000000000003 342.4000000000001,277.72 280.68800000000005,277.72 280.68800000000005,199.32000000000005 353.6,199.32000000000005" fill="none" stroke="purple" stroke-width="1" />
72
+ <polyline data-points="1.2000000000000002,0.30000000000000004 1.5000000000000002,0.30000000000000004 1.5000000000000002,1.4049999999999998 0.9490000000000001,1.4049999999999998 0.9490000000000001,2.105 1.6,2.105" data-type="line" data-label="" points="308.80000000000007,401.48 342.4000000000001,401.48 342.4000000000001,277.72 280.68800000000005,277.72 280.68800000000005,199.32000000000005 353.6,199.32000000000005" fill="none" stroke="purple" stroke-width="1" />
73
73
  </g>
74
74
  <g>
75
75
  <rect data-type="rect" data-label="schematic_component_0" data-x="0" data-y="0" x="40" y="379.08000000000004" width="268.80000000000007" height="112" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.008928571428571428" />
@@ -84,7 +84,7 @@ x-" data-x="1.6" data-y="1.7049999999999998" cx="353.6" cy="244.12000000000006"
84
84
  <rect data-type="rect" data-label="" data-x="1.374" data-y="1.7049999999999998" x="303.088" y="232.92000000000004" width="50.400000000000034" height="22.400000000000034" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.008928571428571428" />
85
85
  </g>
86
86
  <g>
87
- <rect data-type="rect" data-label="" data-x="1.075" data-y="1.0025" x="269.6" y="311.6" width="50.39999999999998" height="22.400000000000034" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.008928571428571428" />
87
+ <rect data-type="rect" data-label="" data-x="1.5250000000000001" data-y="0.09999999999999998" x="320" y="412.68000000000006" width="50.40000000000009" height="22.399999999999977" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.008928571428571428" />
88
88
  </g>
89
89
  <g>
90
90
  <rect data-type="rect" data-label="" data-x="0.9490000000000001" data-y="2.33" x="269.48800000000006" y="148.92000000000002" width="22.399999999999977" height="50.400000000000034" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.008928571428571428" />
@@ -534,7 +534,7 @@ x+" data-x="-8.4" data-y="-17" cx="198.31710258539454" cy="399.68032912258366" r
534
534
  <circle data-type="point" data-label="" data-x="3.5999999999999996" data-y="0.7000000000000015" cx="413.0516274346982" cy="82.94690496986073" r="3" fill="hsl(80, 100%, 50%, 0.9)" />
535
535
  </g>
536
536
  <g>
537
- <circle data-type="point" data-label="" data-x="-5.750000000000001" data-y="-10.1" cx="245.73764348961578" cy="276.2079773342341" r="3" fill="hsl(80, 100%, 50%, 0.9)" />
537
+ <circle data-type="point" data-label="" data-x="-5.750000000000001" data-y="-10" cx="245.73764348961578" cy="274.4185229604899" r="3" fill="hsl(80, 100%, 50%, 0.9)" />
538
538
  </g>
539
539
  <g>
540
540
  <circle data-type="point" data-label="" data-x="-4" data-y="-11.775" cx="277.0530950301392" cy="306.1813380944494" r="3" fill="hsl(80, 100%, 50%, 0.9)" />
@@ -543,7 +543,7 @@ x+" data-x="-8.4" data-y="-17" cx="198.31710258539454" cy="399.68032912258366" r
543
543
  <circle data-type="point" data-label="" data-x="3.5999999999999996" data-y="0.5000000000000013" cx="413.0516274346982" cy="86.52581371734914" r="3" fill="hsl(80, 100%, 50%, 0.9)" />
544
544
  </g>
545
545
  <g>
546
- <circle data-type="point" data-label="" data-x="-6.262500000000001" data-y="-12" cx="236.56668982417676" cy="310.2076104353738" r="3" fill="hsl(80, 100%, 50%, 0.9)" />
546
+ <circle data-type="point" data-label="" data-x="-6.112500000000001" data-y="-12" cx="239.25087138479304" cy="310.2076104353738" r="3" fill="hsl(80, 100%, 50%, 0.9)" />
547
547
  </g>
548
548
  <g>
549
549
  <circle data-type="point" data-label="" data-x="-4" data-y="-14.225" cx="277.0530950301392" cy="350.0229702511822" r="3" fill="hsl(80, 100%, 50%, 0.9)" />
@@ -849,7 +849,7 @@ x+" data-x="-8.4" data-y="-17" cx="198.31710258539454" cy="399.68032912258366" r
849
849
  <polyline data-points="-4.449999999999999,-10 -4,-10 -4,-10.45" data-type="line" data-label="" points="269.00055034829035,274.4185229604899 277.0530950301392,274.4185229604899 277.0530950301392,282.47106764233877" fill="none" stroke="purple" stroke-width="1" />
850
850
  </g>
851
851
  <g>
852
- <polyline data-points="-5.550000000000001,-10 -5.750000000000001,-10.1 -7.075,-10.1 -7.075,-5 -8.4,-5" data-type="line" data-label="" points="249.31655223710416,274.4185229604899 245.73764348961578,276.2079773342341 222.02737303750516,276.2079773342341 222.02737303750516,184.94580427328003 198.31710258539454,184.94580427328003" fill="none" stroke="purple" stroke-width="1" />
852
+ <polyline data-points="-5.550000000000001,-10 -5.750000000000001,-10 -5.750000000000001,-9 -8.200000000000001,-9 -8.200000000000001,-5 -8.4,-5" data-type="line" data-label="" points="249.31655223710416,274.4185229604899 245.73764348961578,274.4185229604899 245.73764348961578,256.52397922304795 201.89601133288292,256.52397922304795 201.89601133288292,184.94580427328003 198.31710258539454,184.94580427328003" fill="none" stroke="purple" stroke-width="1" />
853
853
  </g>
854
854
  <g>
855
855
  <polyline data-points="-4,-11.55 -4,-12 -3,-12 -3,-12.45" data-type="line" data-label="" points="277.0530950301392,302.1550657535249 277.0530950301392,310.2076104353738 294.9476387675812,310.2076104353738 294.9476387675812,318.2601551172227" fill="none" stroke="purple" stroke-width="1" />
@@ -858,7 +858,7 @@ x+" data-x="-8.4" data-y="-17" cx="198.31710258539454" cy="399.68032912258366" r
858
858
  <polyline data-points="-4.449999999999999,-12 -4,-12 -4,-11.55" data-type="line" data-label="" points="269.00055034829035,310.2076104353738 277.0530950301392,310.2076104353738 277.0530950301392,302.1550657535249" fill="none" stroke="purple" stroke-width="1" />
859
859
  </g>
860
860
  <g>
861
- <polyline data-points="-5.550000000000001,-12 -6.9750000000000005,-12 -6.9750000000000005,-9.2 -8.4,-9.2" data-type="line" data-label="" points="249.31655223710416,310.2076104353738 223.81682741124934,310.2076104353738 223.81682741124934,260.1028879705363 198.31710258539454,260.1028879705363" fill="none" stroke="purple" stroke-width="1" />
861
+ <polyline data-points="-5.550000000000001,-12 -6.675000000000001,-12 -6.675000000000001,-9.2 -8.4,-9.2" data-type="line" data-label="" points="249.31655223710416,310.2076104353738 229.18519053248195,310.2076104353738 229.18519053248195,260.1028879705363 198.31710258539454,260.1028879705363" fill="none" stroke="purple" stroke-width="1" />
862
862
  </g>
863
863
  <g>
864
864
  <polyline data-points="-4,-14.45 -4,-14 -3,-14 -3,-13.55" data-type="line" data-label="" points="277.0530950301392,354.0492425921067 277.0530950301392,345.9966979102578 294.9476387675812,345.9966979102578 294.9476387675812,337.94415322840894" fill="none" stroke="purple" stroke-width="1" />
@@ -876,7 +876,7 @@ x+" data-x="-8.4" data-y="-17" cx="198.31710258539454" cy="399.68032912258366" r
876
876
  <polyline data-points="-3,-16.45 -3,-16 -4,-16 -4,-15.55" data-type="line" data-label="" points="294.9476387675812,389.8383300669906 294.9476387675812,381.7857853851417 277.0530950301392,381.7857853851417 277.0530950301392,373.73324070329284" fill="none" stroke="purple" stroke-width="1" />
877
877
  </g>
878
878
  <g>
879
- <polyline data-points="-5.550000000000001,-16 -6.875000000000001,-16 -6.875000000000001,-9.9 -8.200000000000001,-9.9 -8.4,-10" data-type="line" data-label="" points="249.31655223710416,381.7857853851417 225.60628178499354,381.7857853851417 225.60628178499354,272.6290685867457 201.89601133288292,272.6290685867457 198.31710258539454,274.4185229604899" fill="none" stroke="purple" stroke-width="1" />
879
+ <polyline data-points="-5.550000000000001,-16 -6.875000000000001,-16 -6.875000000000001,-10 -8.4,-10" data-type="line" data-label="" points="249.31655223710416,381.7857853851417 225.60628178499354,381.7857853851417 225.60628178499354,274.4185229604899 198.31710258539454,274.4185229604899" fill="none" stroke="purple" stroke-width="1" />
880
880
  </g>
881
881
  <g>
882
882
  <polyline data-points="-4,-18.45 -4,-18 -3,-18 -3,-17.55" data-type="line" data-label="" points="277.0530950301392,425.6274175418746 277.0530950301392,417.5748728600257 294.9476387675812,417.5748728600257 294.9476387675812,409.52232817817685" fill="none" stroke="purple" stroke-width="1" />
@@ -1056,7 +1056,7 @@ x+" data-x="-8.4" data-y="-17" cx="198.31710258539454" cy="399.68032912258366" r
1056
1056
  <rect data-type="rect" data-label="" data-x="3.3739999999999997" data-y="0.7000000000000015" x="404.9811882091119" y="81.15745059611653" width="8.052544681848872" height="3.5789087474883985" fill="hsl(80, 100%, 50%, 0.35)" stroke="black" stroke-width="0.05588295598214286" />
1057
1057
  </g>
1058
1058
  <g>
1059
- <rect data-type="rect" data-label="" data-x="-5.750000000000001" data-y="-9.875" x="243.94818911587157" y="268.15543265238523" width="3.5789087474883843" height="8.052544681848872" fill="hsl(80, 100%, 50%, 0.35)" stroke="black" stroke-width="0.05588295598214286" />
1059
+ <rect data-type="rect" data-label="" data-x="-5.750000000000001" data-y="-10.225" x="243.94818911587157" y="274.4185229604899" width="3.5789087474883843" height="8.052544681848872" fill="hsl(80, 100%, 50%, 0.35)" stroke="black" stroke-width="0.05588295598214286" />
1060
1060
  </g>
1061
1061
  <g>
1062
1062
  <rect data-type="rect" data-label="" data-x="-3.775" data-y="-11.775" x="277.0530950301392" y="304.3918837207052" width="8.052544681848929" height="3.5789087474884127" fill="hsl(80, 100%, 50%, 0.35)" stroke="black" stroke-width="0.05588295598214286" />
@@ -1065,7 +1065,7 @@ x+" data-x="-8.4" data-y="-17" cx="198.31710258539454" cy="399.68032912258366" r
1065
1065
  <rect data-type="rect" data-label="" data-x="3.3739999999999997" data-y="0.5000000000000013" x="404.9811882091119" y="84.73635934360493" width="8.052544681848872" height="3.5789087474883985" fill="hsl(80, 100%, 50%, 0.35)" stroke="black" stroke-width="0.05588295598214286" />
1066
1066
  </g>
1067
1067
  <g>
1068
- <rect data-type="rect" data-label="" data-x="-6.262500000000001" data-y="-11.775" x="234.77723545043256" y="302.1550657535249" width="3.5789087474883843" height="8.052544681848872" fill="hsl(80, 100%, 50%, 0.35)" stroke="black" stroke-width="0.05588295598214286" />
1068
+ <rect data-type="rect" data-label="" data-x="-6.112500000000001" data-y="-11.775" x="237.46141701104887" y="302.1550657535249" width="3.578908747488356" height="8.052544681848872" fill="hsl(80, 100%, 50%, 0.35)" stroke="black" stroke-width="0.05588295598214286" />
1069
1069
  </g>
1070
1070
  <g>
1071
1071
  <rect data-type="rect" data-label="" data-x="-3.775" data-y="-14.225" x="277.0530950301392" y="348.23351587743804" width="8.052544681848929" height="3.578908747488356" fill="hsl(80, 100%, 50%, 0.35)" stroke="black" stroke-width="0.05588295598214286" />