@tscircuit/schematic-trace-solver 0.0.42 → 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 (37) hide show
  1. package/dist/index.d.ts +28 -29
  2. package/dist/index.js +917 -926
  3. package/lib/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver.ts +20 -1
  4. package/lib/solvers/TraceCleanupSolver/TraceCleanupSolver.ts +133 -0
  5. package/lib/solvers/TraceCleanupSolver/balanceZShapes.ts +200 -0
  6. package/lib/solvers/TraceCleanupSolver/minimizeTurnsWithFilteredLabels.ts +76 -0
  7. package/lib/solvers/TraceLabelOverlapAvoidanceSolver/TraceLabelOverlapAvoidanceSolver.ts +1 -21
  8. package/lib/solvers/TraceLabelOverlapAvoidanceSolver/rerouteCollidingTrace.ts +1 -1
  9. package/lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/SingleOverlapSolver/SingleOverlapSolver.ts +1 -1
  10. package/package.json +1 -1
  11. package/site/examples/example26.page.tsx +4 -0
  12. package/tests/assets/example26.json +1206 -0
  13. package/tests/examples/__snapshots__/example02.snap.svg +1 -1
  14. package/tests/examples/__snapshots__/example09.snap.svg +34 -34
  15. package/tests/examples/__snapshots__/example11.snap.svg +13 -13
  16. package/tests/examples/__snapshots__/example12.snap.svg +3 -3
  17. package/tests/examples/__snapshots__/example13.snap.svg +12 -12
  18. package/tests/examples/__snapshots__/example16.snap.svg +4 -4
  19. package/tests/examples/__snapshots__/example19.snap.svg +9 -9
  20. package/tests/examples/__snapshots__/example25.snap.svg +3 -3
  21. package/tests/examples/__snapshots__/example26.snap.svg +3 -3
  22. package/tests/examples/__snapshots__/example28.snap.svg +3 -3
  23. package/tests/examples/__snapshots__/example29.snap.svg +1208 -0
  24. package/tests/examples/example29.test.ts +13 -0
  25. package/tests/solvers/{TraceLabelOverlapAvoidanceSolver/sub-solver → TraceCleanupSolver}/TraceCleanupSolver.test.ts +2 -2
  26. package/tests/solvers/{TraceLabelOverlapAvoidanceSolver/sub-solver → TraceCleanupSolver}/__snapshots__/TraceCleanupSolver.snap.svg +1 -1
  27. package/tests/solvers/TraceLabelOverlapAvoidanceSolver/renderComparisonView/__snapshots__/renderComparisonView03.snap.svg +1 -1
  28. package/tests/solvers/TraceLabelOverlapAvoidanceSolver/renderComparisonView/renderComparisonView03.test.ts +1 -1
  29. package/lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/TraceCleanupSolver/TraceCleanupSolver.ts +0 -132
  30. package/lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/TraceCleanupSolver/balanceLShapes.ts +0 -209
  31. package/lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/TraceCleanupSolver/minimizeTurnsWithFilteredLabels.ts +0 -66
  32. /package/lib/solvers/{TraceLabelOverlapAvoidanceSolver/sub-solvers/TraceCleanupSolver → TraceCleanupSolver}/countTurns.ts +0 -0
  33. /package/lib/solvers/{TraceLabelOverlapAvoidanceSolver/sub-solvers/TraceCleanupSolver → TraceCleanupSolver}/hasCollisions.ts +0 -0
  34. /package/lib/solvers/{TraceLabelOverlapAvoidanceSolver/sub-solvers/TraceCleanupSolver → TraceCleanupSolver}/hasCollisionsWithLabels.ts +0 -0
  35. /package/lib/solvers/{TraceLabelOverlapAvoidanceSolver/sub-solvers/TraceCleanupSolver → TraceCleanupSolver}/simplifyPath.ts +0 -0
  36. /package/lib/solvers/{TraceLabelOverlapAvoidanceSolver/sub-solvers/TraceCleanupSolver → TraceCleanupSolver}/tryConnectPoints.ts +0 -0
  37. /package/lib/solvers/{TraceLabelOverlapAvoidanceSolver/sub-solvers/TraceCleanupSolver → TraceCleanupSolver}/turnMinimization.ts +0 -0
@@ -0,0 +1,13 @@
1
+ import { test, expect } from "bun:test"
2
+ import type { InputProblem } from "lib/index"
3
+ import { SchematicTracePipelineSolver } from "lib/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver"
4
+ import "tests/fixtures/matcher"
5
+ import inputProblem from "../assets/example26.json"
6
+
7
+ test("example29", () => {
8
+ const solver = new SchematicTracePipelineSolver(inputProblem as any)
9
+
10
+ solver.solve()
11
+
12
+ expect(solver).toMatchSolverSnapshot(import.meta.path)
13
+ })
@@ -1,7 +1,7 @@
1
1
  import { expect } from "bun:test"
2
2
  import { test } from "bun:test"
3
- import { TraceCleanupSolver } from "lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/TraceCleanupSolver/TraceCleanupSolver"
4
- import inputData from "../../../assets/TraceCleanupSolver.test.input.json"
3
+ import inputData from "../../assets/TraceCleanupSolver.test.input.json"
4
+ import { TraceCleanupSolver } from "lib/solvers/TraceCleanupSolver/TraceCleanupSolver"
5
5
 
6
6
  test("TraceCleanupSolver snapshot", () => {
7
7
  const solver = new TraceCleanupSolver({
@@ -51,7 +51,7 @@ x-" data-x="1.6" data-y="-2.295" cx="353.6" cy="465.31999999999994" r="3" fill="
51
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
52
  </g>
53
53
  <g>
54
- <polyline data-points="1.2000000000000002,-0.30000000000000004 1.4000000000000001,-0.30000000000000004 1.4000000000000001,-1.2975000000000003 1.049,-1.2975000000000003 1.049,-2.2950000000000004 1.6,-2.295" data-type="line" data-label="" points="308.80000000000007,241.88 331.20000000000005,241.88 331.20000000000005,353.6 291.88800000000003,353.6 291.88800000000003,465.32000000000005 353.6,465.31999999999994" fill="none" stroke="blue" stroke-width="1" />
54
+ <polyline data-points="1.2000000000000002,-0.30000000000000004 1.4000000000000001,-0.30000000000000004 1.4000000000000001,-1.2975000000000003 1.049,-1.2975000000000003 1.049,-2.2950000000000004 1.6,-2.295" data-type="line" data-label="" points="308.80000000000007,241.88 331.20000000000005,241.88 331.20000000000005,353.6 291.88800000000003,353.6 291.88800000000003,465.32000000000005 353.6,465.31999999999994" fill="none" stroke="red" stroke-width="1" />
55
55
  </g>
56
56
  <g>
57
57
  <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" />
@@ -107,7 +107,7 @@ x-" data-x="7.850000000000001" data-y="-2.295" cx="490.488888888889" cy="391.586
107
107
  <polyline data-points="7.450000000000001,0.30000000000000004 7.850000000000001,-1.895" data-type="line" data-label="" points="470.57777777777784,262.41333333333336 490.488888888889,371.6755555555556" fill="none" stroke="hsl(190, 100%, 50%, 0.1)" stroke-width="1" stroke-dasharray="4 2" />
108
108
  </g>
109
109
  <g>
110
- <polyline data-points="7.450000000000001,-0.30000000000000004 7.650000000000001,-0.30000000000000004 7.650000000000001,-1.2975000000000003 7.299000000000001,-1.2975000000000003 7.299000000000001,-2.2950000000000004 7.850000000000001,-2.295" data-type="line" data-label="" points="470.57777777777784,292.28000000000003 480.5333333333334,292.28000000000003 480.5333333333334,341.9333333333334 463.06133333333344,341.9333333333334 463.06133333333344,391.5866666666667 490.488888888889,391.5866666666667" fill="none" stroke="blue" stroke-width="1" />
110
+ <polyline data-points="7.450000000000001,-0.30000000000000004 7.650000000000001,-0.30000000000000004 7.650000000000001,-1.2975000000000003 7.299000000000001,-1.2975000000000003 7.299000000000001,-2.2950000000000004 7.850000000000001,-2.295" data-type="line" data-label="" points="470.57777777777784,292.28000000000003 480.5333333333334,292.28000000000003 480.5333333333334,341.9333333333334 463.06133333333344,341.9333333333334 463.06133333333344,391.5866666666667 490.488888888889,391.5866666666667" fill="none" stroke="red" stroke-width="1" />
111
111
  </g>
112
112
  <g>
113
113
  <rect data-type="rect" data-label="schematic_component_0" data-x="0" data-y="0" x="40.00000000000001" y="252.4577777777778" width="119.4666666666667" height="49.7777777777778" fill="hsl(24, 100%, 50%, 0.1)" stroke="black" stroke-width="0.020089285714285712" />
@@ -5,8 +5,8 @@ import {
5
5
  stackGraphicsHorizontally,
6
6
  } from "graphics-debug"
7
7
  import { SingleOverlapSolver } from "lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/SingleOverlapSolver/SingleOverlapSolver"
8
- import { TraceCleanupSolver } from "lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/TraceCleanupSolver/TraceCleanupSolver"
9
8
  import inputData from "../../../assets/3.input.json"
9
+ import { TraceCleanupSolver } from "lib/solvers/TraceCleanupSolver/TraceCleanupSolver"
10
10
 
11
11
  test("SingleOverlapSolver-to-TraceCleanupSolver snapshot", () => {
12
12
  // Convert targetTraceIds to Set
@@ -1,132 +0,0 @@
1
- import type { InputProblem } from "lib/types/InputProblem"
2
- import type { GraphicsObject, Line } from "graphics-debug"
3
- import type { NetLabelPlacement } from "../../../NetLabelPlacementSolver/NetLabelPlacementSolver"
4
- import { minimizeTurnsWithFilteredLabels } from "./minimizeTurnsWithFilteredLabels"
5
- import { balanceLShapes } from "./balanceLShapes"
6
- import { BaseSolver } from "lib/solvers/BaseSolver/BaseSolver"
7
- import type { SolvedTracePath } from "lib/solvers/SchematicTraceLinesSolver/SchematicTraceLinesSolver"
8
- import { visualizeInputProblem } from "lib/solvers/SchematicTracePipelineSolver/visualizeInputProblem"
9
-
10
- interface TraceCleanupSolverInput {
11
- inputProblem: InputProblem
12
- allTraces: SolvedTracePath[]
13
- targetTraceIds: Set<string>
14
- allLabelPlacements: NetLabelPlacement[]
15
- mergedLabelNetIdMap: Record<string, Set<string>>
16
- paddingBuffer: number
17
- }
18
-
19
- /**
20
- * Cleans up traces by minimizing turns and balancing L-shapes to improve
21
- * the overall aesthetics and readability of the schematic.
22
- */
23
- export class TraceCleanupSolver extends BaseSolver {
24
- private input: TraceCleanupSolverInput
25
- private outputTraces: SolvedTracePath[]
26
- private pipelineStepIndex = 0
27
- private tracesToProcess: SolvedTracePath[]
28
- private minimizedTraces: SolvedTracePath[] | null = null
29
- private balancedTraces: SolvedTracePath[] | null = null
30
-
31
- constructor(solverInput: TraceCleanupSolverInput) {
32
- super()
33
- this.input = solverInput
34
- this.outputTraces = [...solverInput.allTraces]
35
- this.tracesToProcess = this.outputTraces.filter((t) =>
36
- this.input.targetTraceIds.has(t.mspPairId),
37
- )
38
- }
39
-
40
- override _step() {
41
- const {
42
- targetTraceIds,
43
- inputProblem,
44
- allLabelPlacements,
45
- mergedLabelNetIdMap,
46
- paddingBuffer,
47
- } = this.input
48
-
49
- if (targetTraceIds.size === 0) {
50
- this.solved = true
51
- return
52
- }
53
-
54
- switch (this.pipelineStepIndex) {
55
- case 0: {
56
- // Step 0: Minimize turns
57
- const minimizedTracesResult = minimizeTurnsWithFilteredLabels({
58
- traces: this.tracesToProcess,
59
- inputProblem,
60
- allLabelPlacements,
61
- mergedLabelNetIdMap,
62
- paddingBuffer,
63
- })
64
-
65
- this.minimizedTraces = minimizedTracesResult ?? this.tracesToProcess
66
-
67
- const tracesMap = new Map(
68
- this.input.allTraces.map((t) => [t.mspPairId, t]),
69
- )
70
- for (const trace of this.minimizedTraces) {
71
- tracesMap.set(trace.mspPairId, trace)
72
- }
73
- this.outputTraces = Array.from(tracesMap.values())
74
- this.pipelineStepIndex++
75
- break
76
- }
77
- case 1: {
78
- // Step 1: Balance L-shapes
79
- const balancedTracesResult = balanceLShapes({
80
- traces: this.minimizedTraces!,
81
- inputProblem,
82
- allLabelPlacements,
83
- })
84
-
85
- this.balancedTraces = balancedTracesResult ?? this.minimizedTraces
86
-
87
- const tracesMap = new Map(
88
- this.input.allTraces.map((t) => [t.mspPairId, t]),
89
- )
90
- for (const trace of this.balancedTraces!) {
91
- tracesMap.set(trace.mspPairId, trace)
92
- }
93
- this.outputTraces = Array.from(tracesMap.values())
94
- this.pipelineStepIndex++
95
- break
96
- }
97
- case 2: {
98
- // Step 2: Done
99
- this.solved = true
100
- break
101
- }
102
- }
103
- }
104
-
105
- getOutput() {
106
- return {
107
- traces: this.outputTraces,
108
- }
109
- }
110
-
111
- override visualize(): GraphicsObject {
112
- const graphics = visualizeInputProblem(this.input.inputProblem, {
113
- chipAlpha: 0.1,
114
- connectionAlpha: 0.1,
115
- })
116
-
117
- if (!graphics.lines) graphics.lines = []
118
- if (!graphics.points) graphics.points = []
119
- if (!graphics.rects) graphics.rects = []
120
- if (!graphics.circles) graphics.circles = []
121
- if (!graphics.texts) graphics.texts = []
122
-
123
- for (const trace of this.outputTraces) {
124
- const line: Line = {
125
- points: trace.tracePath.map((p) => ({ x: p.x, y: p.y })),
126
- strokeColor: "blue",
127
- }
128
- graphics.lines!.push(line)
129
- }
130
- return graphics
131
- }
132
- }
@@ -1,209 +0,0 @@
1
- import type { Point } from "graphics-debug"
2
- import type { InputProblem } from "lib/types/InputProblem"
3
- import type { NetLabelPlacement } from "../../../NetLabelPlacementSolver/NetLabelPlacementSolver"
4
- import { simplifyPath } from "./simplifyPath"
5
- import type { SolvedTracePath } from "lib/solvers/SchematicTraceLinesSolver/SchematicTraceLinesSolver"
6
- import { segmentIntersectsRect } from "lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver2/collisions"
7
- import { getObstacleRects } from "lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver2/rect"
8
-
9
- export const balanceLShapes = ({
10
- traces,
11
- inputProblem,
12
- allLabelPlacements,
13
- }: {
14
- traces: SolvedTracePath[]
15
- inputProblem: InputProblem
16
- allLabelPlacements: NetLabelPlacement[]
17
- }): SolvedTracePath[] | null => {
18
- const TOLERANCE = 1e-5
19
- let changesMade = false
20
-
21
- for (const trace of traces) {
22
- if (trace.tracePath.length === 4) {
23
- const [p0, p1, p2, p3] = trace.tracePath
24
- const isHVHShape = p0.y === p1.y && p1.x === p2.x && p2.y === p3.y
25
- const isVHVShape = p0.x === p1.x && p1.y === p2.y && p2.x === p3.x
26
-
27
- const isCollinearHorizontal =
28
- p0.y === p1.y && p1.y === p2.y && p2.y === p3.y
29
- const isCollinearVertical =
30
- p0.x === p1.x && p1.x === p2.x && p2.x === p3.x
31
- const isCollinear = isCollinearHorizontal || isCollinearVertical
32
-
33
- let isSameDirection = false
34
- if (isHVHShape) {
35
- isSameDirection = Math.sign(p1.x - p0.x) === Math.sign(p3.x - p2.x)
36
- } else if (isVHVShape) {
37
- isSameDirection = Math.sign(p1.y - p0.y) === Math.sign(p3.y - p2.y)
38
- }
39
-
40
- const isValidZShape =
41
- (isHVHShape || isVHVShape) && !isCollinear && isSameDirection
42
-
43
- if (!isValidZShape) {
44
- return null
45
- }
46
- }
47
- }
48
-
49
- const obstacles = getObstacleRects(inputProblem).map((obs) => ({
50
- ...obs,
51
- minX: obs.minX + TOLERANCE,
52
- maxX: obs.maxX - TOLERANCE,
53
- minY: obs.minY + TOLERANCE,
54
- maxY: obs.maxY - TOLERANCE,
55
- }))
56
-
57
- const segmentIntersectsAnyRect = (
58
- p1: Point,
59
- p2: Point,
60
- rects: any[],
61
- ): boolean => {
62
- for (const rect of rects) {
63
- if (segmentIntersectsRect(p1, p2, rect)) {
64
- return true
65
- }
66
- }
67
- return false
68
- }
69
-
70
- const getLabelBounds = (labels: NetLabelPlacement[], traceNetId: string) => {
71
- const filteredLabels = labels.filter(
72
- (label) => label.globalConnNetId !== traceNetId,
73
- )
74
-
75
- return filteredLabels.map((nl) => ({
76
- minX: nl.center.x - nl.width / 2 + TOLERANCE,
77
- maxX: nl.center.x + nl.width / 2 - TOLERANCE,
78
- minY: nl.center.y - nl.height / 2 + TOLERANCE,
79
- maxY: nl.center.y + nl.height / 2 - TOLERANCE,
80
- }))
81
- }
82
-
83
- const newTraces = traces.map((trace) => {
84
- const newPath = [...trace.tracePath]
85
-
86
- if (newPath.length < 4) {
87
- return { ...trace }
88
- }
89
-
90
- const labelBounds = getLabelBounds(
91
- allLabelPlacements,
92
- trace.globalConnNetId,
93
- )
94
-
95
- if (newPath.length === 4) {
96
- const [p0, p1, p2, p3] = newPath
97
- let p1New: Point
98
- let p2New: Point
99
-
100
- const isHVHShape = p0.y === p1.y && p1.x === p2.x && p2.y === p3.y
101
-
102
- if (isHVHShape) {
103
- const idealX = (p0.x + p3.x) / 2
104
- p1New = { x: idealX, y: p1.y }
105
- p2New = { x: idealX, y: p2.y }
106
- } else {
107
- const idealY = (p0.y + p3.y) / 2
108
- p1New = { x: p1.x, y: idealY }
109
- p2New = { x: p2.x, y: idealY }
110
- }
111
-
112
- const collides =
113
- segmentIntersectsAnyRect(p0, p1New, obstacles) ||
114
- segmentIntersectsAnyRect(p1New, p2New, obstacles) ||
115
- segmentIntersectsAnyRect(p2New, p3, obstacles) ||
116
- segmentIntersectsAnyRect(p0, p1New, labelBounds) ||
117
- segmentIntersectsAnyRect(p1New, p2New, labelBounds) ||
118
- segmentIntersectsAnyRect(p2New, p3, labelBounds)
119
-
120
- if (!collides) {
121
- newPath[1] = p1New
122
- newPath[2] = p2New
123
- changesMade = true
124
- }
125
-
126
- return { ...trace, tracePath: simplifyPath(newPath) }
127
- }
128
-
129
- for (let i = 1; i < newPath.length - 4; i++) {
130
- const p1 = newPath[i]
131
- const p2 = newPath[i + 1]
132
- const p3 = newPath[i + 2]
133
- const p4 = newPath[i + 3]
134
-
135
- const isHVHZShape = p1.y === p2.y && p2.x === p3.x && p3.y === p4.y
136
- const isVHVZShape = p1.x === p2.x && p2.y === p3.y && p3.x === p4.x
137
-
138
- const isCollinearHorizontal =
139
- p1.y === p2.y && p2.y === p3.y && p3.y === p4.y
140
- const isCollinearVertical =
141
- p1.x === p2.x && p2.x === p3.x && p3.x === p4.x
142
- const isCollinear = isCollinearHorizontal || isCollinearVertical
143
-
144
- let isSameDirection = false
145
- if (isHVHZShape) {
146
- isSameDirection = Math.sign(p2.x - p1.x) === Math.sign(p4.x - p3.x)
147
- } else if (isVHVZShape) {
148
- isSameDirection = Math.sign(p2.y - p1.y) === Math.sign(p4.y - p3.y)
149
- }
150
-
151
- const isValidZShape =
152
- (isHVHZShape || isVHVZShape) && !isCollinear && isSameDirection
153
-
154
- if (!isValidZShape) {
155
- continue
156
- }
157
-
158
- let p2New: Point
159
- let p3New: Point
160
- const len1Original = isHVHZShape
161
- ? Math.abs(p1.x - p2.x)
162
- : Math.abs(p1.y - p2.y)
163
- const len2Original = isHVHZShape
164
- ? Math.abs(p3.x - p4.x)
165
- : Math.abs(p3.y - p4.y)
166
-
167
- if (Math.abs(len1Original - len2Original) < 0.001) {
168
- continue
169
- }
170
-
171
- if (isHVHZShape) {
172
- const idealX = (p1.x + p4.x) / 2
173
- p2New = { x: idealX, y: p2.y }
174
- p3New = { x: idealX, y: p3.y }
175
- } else {
176
- const idealY = (p1.y + p4.y) / 2
177
- p2New = { x: p2.x, y: idealY }
178
- p3New = { x: p3.x, y: idealY }
179
- }
180
-
181
- const collides =
182
- segmentIntersectsAnyRect(p1, p2New, obstacles) ||
183
- segmentIntersectsAnyRect(p2New, p3New, obstacles) ||
184
- segmentIntersectsAnyRect(p3New, p4, obstacles) ||
185
- segmentIntersectsAnyRect(p1, p2New, labelBounds) ||
186
- segmentIntersectsAnyRect(p2New, p3New, labelBounds) ||
187
- segmentIntersectsAnyRect(p3New, p4, labelBounds)
188
-
189
- if (!collides) {
190
- newPath[i + 1] = p2New
191
- newPath[i + 2] = p3New
192
- changesMade = true
193
- i = 0
194
- }
195
- }
196
-
197
- const finalSimplifiedPath = simplifyPath(newPath)
198
- return {
199
- ...trace,
200
- tracePath: finalSimplifiedPath,
201
- }
202
- })
203
-
204
- if (changesMade) {
205
- return newTraces
206
- } else {
207
- return null
208
- }
209
- }
@@ -1,66 +0,0 @@
1
- import type { InputProblem } from "lib/types/InputProblem"
2
- import type { NetLabelPlacement } from "../../../NetLabelPlacementSolver/NetLabelPlacementSolver"
3
- import { minimizeTurns } from "./turnMinimization"
4
- import type { SolvedTracePath } from "lib/solvers/SchematicTraceLinesSolver/SchematicTraceLinesSolver"
5
- import { getObstacleRects } from "lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver2/rect"
6
-
7
- export const minimizeTurnsWithFilteredLabels = ({
8
- traces,
9
- inputProblem,
10
- allLabelPlacements,
11
- mergedLabelNetIdMap,
12
- paddingBuffer,
13
- }: {
14
- traces: SolvedTracePath[]
15
- inputProblem: InputProblem
16
- allLabelPlacements: NetLabelPlacement[]
17
- mergedLabelNetIdMap: Record<string, Set<string>>
18
- paddingBuffer: number
19
- }): SolvedTracePath[] | null => {
20
- let changesMade = false
21
- const obstacles = getObstacleRects(inputProblem)
22
-
23
- const newTraces = traces.map((trace) => {
24
- const originalPath = trace.tracePath
25
- const filteredLabels = allLabelPlacements.filter((label) => {
26
- const originalNetIds = mergedLabelNetIdMap[label.globalConnNetId]
27
- if (originalNetIds) {
28
- return !originalNetIds.has(trace.globalConnNetId)
29
- }
30
- return label.globalConnNetId !== trace.globalConnNetId
31
- })
32
-
33
- const labelBounds = filteredLabels.map((nl) => ({
34
- minX: nl.center.x - nl.width / 2 - paddingBuffer,
35
- maxX: nl.center.x + nl.width / 2 + paddingBuffer,
36
- minY: nl.center.y - nl.height / 2 - paddingBuffer,
37
- maxY: nl.center.y + nl.height / 2 + paddingBuffer,
38
- }))
39
-
40
- const newPath = minimizeTurns({
41
- path: originalPath,
42
- obstacles,
43
- labelBounds,
44
- })
45
-
46
- if (
47
- newPath.length !== originalPath.length ||
48
- newPath.some(
49
- (p, i) => p.x !== originalPath[i].x || p.y !== originalPath[i].y,
50
- )
51
- ) {
52
- changesMade = true
53
- }
54
-
55
- return {
56
- ...trace,
57
- tracePath: newPath,
58
- }
59
- })
60
-
61
- if (changesMade) {
62
- return newTraces
63
- } else {
64
- return null
65
- }
66
- }