@tscircuit/schematic-trace-solver 0.0.7 → 0.0.9

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 (19) hide show
  1. package/dist/index.d.ts +5 -5
  2. package/dist/index.js +488 -344
  3. package/lib/solvers/NetLabelPlacementSolver/NetLabelPlacementSolver.ts +29 -0
  4. package/lib/solvers/NetLabelPlacementSolver/SingleNetLabelPlacementSolver/SingleNetLabelPlacementSolver.ts +199 -465
  5. package/lib/solvers/NetLabelPlacementSolver/SingleNetLabelPlacementSolver/SingleNetLabelPlacementSolver_visualize.ts +89 -0
  6. package/lib/solvers/NetLabelPlacementSolver/SingleNetLabelPlacementSolver/anchors.ts +11 -0
  7. package/lib/solvers/NetLabelPlacementSolver/SingleNetLabelPlacementSolver/collisions.ts +45 -0
  8. package/lib/solvers/NetLabelPlacementSolver/SingleNetLabelPlacementSolver/geometry.ts +48 -0
  9. package/lib/solvers/NetLabelPlacementSolver/SingleNetLabelPlacementSolver/host.ts +64 -0
  10. package/lib/solvers/NetLabelPlacementSolver/SingleNetLabelPlacementSolver/solvePortOnlyPin.ts +177 -0
  11. package/lib/solvers/SchematicTraceLinesSolver/SchematicTraceLinesSolver.ts +24 -3
  12. package/lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver/SchematicTraceSingleLineSolver.ts +38 -3
  13. package/package.json +1 -1
  14. package/site/SchematicTraceLinesSolver/SchematicTraceLinesSolver01.page.tsx +122 -0
  15. package/site/components/GenericSolverDebugger.tsx +16 -0
  16. package/site/examples/example01-basic.page.tsx +2 -2
  17. package/site/examples/example04-single-symbol.page.tsx +46 -0
  18. package/tests/solvers/SchematicTraceSingleLineSolver/SchematicTraceSingleLineSolver_repro01.json +88 -0
  19. package/tests/solvers/SchematicTraceSingleLineSolver/SchematicTraceSingleLineSolver_repro01.test.ts +16 -0
@@ -0,0 +1,89 @@
1
+ import type { GraphicsObject } from "graphics-debug"
2
+ import { visualizeInputProblem } from "lib/solvers/SchematicTracePipelineSolver/visualizeInputProblem"
3
+ import { getColorFromString } from "lib/utils/getColorFromString"
4
+ import { chooseHostTraceForGroup } from "./host"
5
+ import type { SingleNetLabelPlacementSolver } from "./SingleNetLabelPlacementSolver"
6
+
7
+ export function visualizeSingleNetLabelPlacementSolver(
8
+ solver: SingleNetLabelPlacementSolver,
9
+ ): GraphicsObject {
10
+ const graphics = visualizeInputProblem(solver.inputProblem)
11
+
12
+ // Visualize the entire trace group for this net id
13
+ const groupId = solver.overlappingSameNetTraceGroup.globalConnNetId
14
+ const host = chooseHostTraceForGroup({
15
+ inputProblem: solver.inputProblem,
16
+ inputTraceMap: solver.inputTraceMap,
17
+ globalConnNetId: groupId,
18
+ fallbackTrace: solver.overlappingSameNetTraceGroup.overlappingTraces,
19
+ })
20
+ const groupStroke = getColorFromString(groupId, 0.9)
21
+ const groupFill = getColorFromString(groupId, 0.5)
22
+
23
+ for (const trace of Object.values(solver.inputTraceMap)) {
24
+ if (trace.globalConnNetId !== groupId) continue
25
+ const isHost = host ? trace.mspPairId === host.mspPairId : false
26
+ graphics.lines!.push({
27
+ points: trace.tracePath,
28
+ strokeColor: isHost ? groupStroke : groupFill,
29
+ strokeWidth: isHost ? 0.006 : 0.003,
30
+ strokeDash: isHost ? undefined : "4 2",
31
+ } as any)
32
+ }
33
+
34
+ // Visualize all tested candidate rectangles with reason coloring
35
+ for (const c of solver.testedCandidates) {
36
+ const fill =
37
+ c.status === "ok"
38
+ ? "rgba(0, 180, 0, 0.25)"
39
+ : c.status === "chip-collision"
40
+ ? "rgba(220, 0, 0, 0.25)"
41
+ : c.status === "trace-collision"
42
+ ? "rgba(220, 140, 0, 0.25)"
43
+ : "rgba(120, 120, 120, 0.15)"
44
+ const stroke =
45
+ c.status === "ok"
46
+ ? "green"
47
+ : c.status === "chip-collision"
48
+ ? "red"
49
+ : c.status === "trace-collision"
50
+ ? "orange"
51
+ : "gray"
52
+
53
+ graphics.rects!.push({
54
+ center: {
55
+ x: (c.bounds.minX + c.bounds.maxX) / 2,
56
+ y: (c.bounds.minY + c.bounds.maxY) / 2,
57
+ },
58
+ width: c.width,
59
+ height: c.height,
60
+ fill,
61
+ strokeColor: stroke,
62
+ } as any)
63
+
64
+ graphics.points!.push({
65
+ x: c.anchor.x,
66
+ y: c.anchor.y,
67
+ color: stroke,
68
+ } as any)
69
+ }
70
+
71
+ // Visualize the final accepted label (if any)
72
+ if (solver.netLabelPlacement) {
73
+ const p = solver.netLabelPlacement
74
+ graphics.rects!.push({
75
+ center: p.center,
76
+ width: p.width,
77
+ height: p.height,
78
+ fill: "rgba(0, 128, 255, 0.35)",
79
+ strokeColor: "blue",
80
+ } as any)
81
+ graphics.points!.push({
82
+ x: p.anchorPoint.x,
83
+ y: p.anchorPoint.y,
84
+ color: "blue",
85
+ } as any)
86
+ }
87
+
88
+ return graphics
89
+ }
@@ -0,0 +1,11 @@
1
+ export function anchorsForSegment(
2
+ a: { x: number; y: number },
3
+ b: { x: number; y: number },
4
+ ) {
5
+ // Start, midpoint, end
6
+ return [
7
+ { x: a.x, y: a.y },
8
+ { x: (a.x + b.x) / 2, y: (a.y + b.y) / 2 },
9
+ { x: b.x, y: b.y },
10
+ ]
11
+ }
@@ -0,0 +1,45 @@
1
+ import type { MspConnectionPairId } from "lib/solvers/MspConnectionPairSolver/MspConnectionPairSolver"
2
+ import type { SolvedTracePath } from "lib/solvers/SchematicTraceLinesSolver/SchematicTraceLinesSolver"
3
+
4
+ export function segmentIntersectsRect(
5
+ p1: { x: number; y: number },
6
+ p2: { x: number; y: number },
7
+ rect: { minX: number; minY: number; maxX: number; maxY: number },
8
+ EPS = 1e-9,
9
+ ): boolean {
10
+ const isVert = Math.abs(p1.x - p2.x) < EPS
11
+ const isHorz = Math.abs(p1.y - p2.y) < EPS
12
+ if (!isVert && !isHorz) return false
13
+
14
+ if (isVert) {
15
+ const x = p1.x
16
+ if (x < rect.minX - EPS || x > rect.maxX + EPS) return false
17
+ const segMinY = Math.min(p1.y, p2.y)
18
+ const segMaxY = Math.max(p1.y, p2.y)
19
+ const overlap = Math.min(segMaxY, rect.maxY) - Math.max(segMinY, rect.minY)
20
+ return overlap > EPS
21
+ } else {
22
+ const y = p1.y
23
+ if (y < rect.minY - EPS || y > rect.maxY + EPS) return false
24
+ const segMinX = Math.min(p1.x, p2.x)
25
+ const segMaxX = Math.max(p1.x, p2.x)
26
+ const overlap = Math.min(segMaxX, rect.maxX) - Math.max(segMinX, rect.minX)
27
+ return overlap > EPS
28
+ }
29
+ }
30
+
31
+ export function rectIntersectsAnyTrace(
32
+ bounds: { minX: number; minY: number; maxX: number; maxY: number },
33
+ inputTraceMap: Record<MspConnectionPairId, SolvedTracePath>,
34
+ hostPathId?: MspConnectionPairId,
35
+ hostSegIndex?: number,
36
+ ): boolean {
37
+ for (const [pairId, solved] of Object.entries(inputTraceMap)) {
38
+ const pts = solved.tracePath
39
+ for (let i = 0; i < pts.length - 1; i++) {
40
+ if (pairId === hostPathId && i === hostSegIndex) continue
41
+ if (segmentIntersectsRect(pts[i]!, pts[i + 1]!, bounds)) return true
42
+ }
43
+ }
44
+ return false
45
+ }
@@ -0,0 +1,48 @@
1
+ import type { FacingDirection } from "lib/utils/dir"
2
+
3
+ export const NET_LABEL_HORIZONTAL_WIDTH = 0.4
4
+ export const NET_LABEL_HORIZONTAL_HEIGHT = 0.2
5
+
6
+ export function getDimsForOrientation(orientation: FacingDirection) {
7
+ if (orientation === "y+" || orientation === "y-") {
8
+ return {
9
+ width: NET_LABEL_HORIZONTAL_HEIGHT,
10
+ height: NET_LABEL_HORIZONTAL_WIDTH,
11
+ }
12
+ }
13
+ return {
14
+ width: NET_LABEL_HORIZONTAL_WIDTH,
15
+ height: NET_LABEL_HORIZONTAL_HEIGHT,
16
+ }
17
+ }
18
+
19
+ export function getCenterFromAnchor(
20
+ anchor: { x: number; y: number },
21
+ orientation: FacingDirection,
22
+ width: number,
23
+ height: number,
24
+ ) {
25
+ switch (orientation) {
26
+ case "x+":
27
+ return { x: anchor.x + width / 2, y: anchor.y }
28
+ case "x-":
29
+ return { x: anchor.x - width / 2, y: anchor.y }
30
+ case "y+":
31
+ return { x: anchor.x, y: anchor.y + height / 2 }
32
+ case "y-":
33
+ return { x: anchor.x, y: anchor.y - height / 2 }
34
+ }
35
+ }
36
+
37
+ export function getRectBounds(
38
+ center: { x: number; y: number },
39
+ w: number,
40
+ h: number,
41
+ ) {
42
+ return {
43
+ minX: center.x - w / 2,
44
+ minY: center.y - h / 2,
45
+ maxX: center.x + w / 2,
46
+ maxY: center.y + h / 2,
47
+ }
48
+ }
@@ -0,0 +1,64 @@
1
+ import type { InputChip, InputProblem } from "lib/types/InputProblem"
2
+ import type { SolvedTracePath } from "lib/solvers/SchematicTraceLinesSolver/SchematicTraceLinesSolver"
3
+ import type { MspConnectionPairId } from "lib/solvers/MspConnectionPairSolver/MspConnectionPairSolver"
4
+
5
+ export function lengthOfTrace(path: SolvedTracePath): number {
6
+ let sum = 0
7
+ const pts = path.tracePath
8
+ for (let i = 0; i < pts.length - 1; i++) {
9
+ sum +=
10
+ Math.abs(pts[i + 1]!.x - pts[i]!.x) + Math.abs(pts[i + 1]!.y - pts[i]!.y)
11
+ }
12
+ return sum
13
+ }
14
+
15
+ export function chooseHostTraceForGroup(params: {
16
+ inputProblem: InputProblem
17
+ inputTraceMap: Record<MspConnectionPairId, SolvedTracePath>
18
+ globalConnNetId: string
19
+ fallbackTrace?: SolvedTracePath
20
+ }): SolvedTracePath | undefined {
21
+ const { inputProblem, inputTraceMap, globalConnNetId, fallbackTrace } = params
22
+
23
+ const chipsById: Record<string, InputChip> = Object.fromEntries(
24
+ inputProblem.chips.map((c) => [c.chipId, c]),
25
+ )
26
+
27
+ const groupTraces = Object.values(inputTraceMap).filter(
28
+ (t) => t.globalConnNetId === globalConnNetId,
29
+ )
30
+
31
+ const chipIdsInGroup = new Set<string>()
32
+ for (const t of groupTraces) {
33
+ chipIdsInGroup.add(t.pins[0].chipId)
34
+ chipIdsInGroup.add(t.pins[1].chipId)
35
+ }
36
+
37
+ let largestChipId: string | null = null
38
+ let largestPinCount = -1
39
+ for (const id of chipIdsInGroup) {
40
+ const chip = chipsById[id]
41
+ const count = chip?.pins?.length ?? 0
42
+ if (count > largestPinCount) {
43
+ largestPinCount = count
44
+ largestChipId = id
45
+ }
46
+ }
47
+
48
+ const hostCandidates =
49
+ largestChipId == null
50
+ ? []
51
+ : groupTraces.filter(
52
+ (t) =>
53
+ t.pins[0].chipId === largestChipId ||
54
+ t.pins[1].chipId === largestChipId,
55
+ )
56
+
57
+ if (hostCandidates.length > 0) {
58
+ return hostCandidates.reduce((a, b) =>
59
+ lengthOfTrace(a) >= lengthOfTrace(b) ? a : b,
60
+ )
61
+ }
62
+
63
+ return fallbackTrace
64
+ }
@@ -0,0 +1,177 @@
1
+ import type { InputProblem } from "lib/types/InputProblem"
2
+ import type { MspConnectionPairId } from "lib/solvers/MspConnectionPairSolver/MspConnectionPairSolver"
3
+ import type { SolvedTracePath } from "lib/solvers/SchematicTraceLinesSolver/SchematicTraceLinesSolver"
4
+ import type { FacingDirection } from "lib/utils/dir"
5
+ import { ChipObstacleSpatialIndex } from "lib/data-structures/ChipObstacleSpatialIndex"
6
+ import type {
7
+ NetLabelPlacement,
8
+ OverlappingSameNetTraceGroup,
9
+ } from "../NetLabelPlacementSolver"
10
+ import {
11
+ getDimsForOrientation,
12
+ getCenterFromAnchor,
13
+ getRectBounds,
14
+ } from "./geometry"
15
+ import { rectIntersectsAnyTrace } from "./collisions"
16
+
17
+ export function solveNetLabelPlacementForPortOnlyPin(params: {
18
+ inputProblem: InputProblem
19
+ inputTraceMap: Record<MspConnectionPairId, SolvedTracePath>
20
+ chipObstacleSpatialIndex: ChipObstacleSpatialIndex
21
+ overlappingSameNetTraceGroup: OverlappingSameNetTraceGroup
22
+ availableOrientations: FacingDirection[]
23
+ }): {
24
+ placement: NetLabelPlacement | null
25
+ testedCandidates: Array<{
26
+ center: { x: number; y: number }
27
+ width: number
28
+ height: number
29
+ bounds: { minX: number; minY: number; maxX: number; maxY: number }
30
+ anchor: { x: number; y: number }
31
+ orientation: FacingDirection
32
+ status: "ok" | "chip-collision" | "trace-collision" | "parallel-to-segment"
33
+ hostSegIndex: number
34
+ }>
35
+ error?: string
36
+ } {
37
+ const {
38
+ inputProblem,
39
+ inputTraceMap,
40
+ chipObstacleSpatialIndex,
41
+ overlappingSameNetTraceGroup,
42
+ availableOrientations,
43
+ } = params
44
+
45
+ const pinId = overlappingSameNetTraceGroup.portOnlyPinId
46
+ if (!pinId) {
47
+ return {
48
+ placement: null,
49
+ testedCandidates: [],
50
+ error: "No portOnlyPinId provided",
51
+ }
52
+ }
53
+
54
+ // Find pin coordinates
55
+ let pin: { x: number; y: number } | null = null
56
+ for (const chip of inputProblem.chips) {
57
+ const p = chip.pins.find((pp) => pp.pinId === pinId)
58
+ if (p) {
59
+ pin = { x: p.x, y: p.y }
60
+ break
61
+ }
62
+ }
63
+ if (!pin) {
64
+ return {
65
+ placement: null,
66
+ testedCandidates: [],
67
+ error: `Port-only pin not found: ${pinId}`,
68
+ }
69
+ }
70
+
71
+ const orientations =
72
+ availableOrientations.length > 0
73
+ ? availableOrientations
74
+ : (["x+", "x-", "y+", "y-"] as FacingDirection[])
75
+
76
+ const anchor = { x: pin.x, y: pin.y }
77
+ const outwardOf = (o: FacingDirection) =>
78
+ o === "x+"
79
+ ? { x: 1, y: 0 }
80
+ : o === "x-"
81
+ ? { x: -1, y: 0 }
82
+ : o === "y+"
83
+ ? { x: 0, y: 1 }
84
+ : { x: 0, y: -1 }
85
+
86
+ const testedCandidates: Array<{
87
+ center: { x: number; y: number }
88
+ width: number
89
+ height: number
90
+ bounds: { minX: number; minY: number; maxX: number; maxY: number }
91
+ anchor: { x: number; y: number }
92
+ orientation: FacingDirection
93
+ status: "ok" | "chip-collision" | "trace-collision" | "parallel-to-segment"
94
+ hostSegIndex: number
95
+ }> = []
96
+
97
+ for (const orientation of orientations) {
98
+ const { width, height } = getDimsForOrientation(orientation)
99
+ // Place label fully outside the chip: shift center slightly outward
100
+ const baseCenter = getCenterFromAnchor(anchor, orientation, width, height)
101
+ const outward = outwardOf(orientation)
102
+ const offset = 1e-3
103
+ const center = {
104
+ x: baseCenter.x + outward.x * offset,
105
+ y: baseCenter.y + outward.y * offset,
106
+ }
107
+ const bounds = getRectBounds(center, width, height)
108
+
109
+ // Chip collision check
110
+ const chips = chipObstacleSpatialIndex.getChipsInBounds(bounds)
111
+ if (chips.length > 0) {
112
+ testedCandidates.push({
113
+ center,
114
+ width,
115
+ height,
116
+ bounds,
117
+ anchor,
118
+ orientation,
119
+ status: "chip-collision",
120
+ hostSegIndex: -1,
121
+ })
122
+ continue
123
+ }
124
+
125
+ // Trace collision check
126
+ if (
127
+ rectIntersectsAnyTrace(
128
+ bounds,
129
+ inputTraceMap,
130
+ "" as MspConnectionPairId,
131
+ -1,
132
+ )
133
+ ) {
134
+ testedCandidates.push({
135
+ center,
136
+ width,
137
+ height,
138
+ bounds,
139
+ anchor,
140
+ orientation,
141
+ status: "trace-collision",
142
+ hostSegIndex: -1,
143
+ })
144
+ continue
145
+ }
146
+
147
+ // Found a valid placement
148
+ testedCandidates.push({
149
+ center,
150
+ width,
151
+ height,
152
+ bounds,
153
+ anchor,
154
+ orientation,
155
+ status: "ok",
156
+ hostSegIndex: -1,
157
+ })
158
+
159
+ const placement: NetLabelPlacement = {
160
+ globalConnNetId: overlappingSameNetTraceGroup.globalConnNetId,
161
+ dcConnNetId: undefined,
162
+ orientation,
163
+ anchorPoint: anchor,
164
+ width,
165
+ height,
166
+ center,
167
+ }
168
+
169
+ return { placement, testedCandidates }
170
+ }
171
+
172
+ return {
173
+ placement: null,
174
+ testedCandidates,
175
+ error: "Could not place net label at port without collisions",
176
+ }
177
+ }
@@ -30,6 +30,7 @@ export class SchematicTraceLinesSolver extends BaseSolver {
30
30
  currentConnectionPair: MspConnectionPair | null = null
31
31
 
32
32
  solvedTracePaths: Array<SolvedTracePath> = []
33
+ failedConnectionPairs: Array<MspConnectionPair & { error?: string }> = []
33
34
 
34
35
  declare activeSubSolver: SchematicTraceSingleLineSolver | null
35
36
 
@@ -75,9 +76,16 @@ export class SchematicTraceLinesSolver extends BaseSolver {
75
76
  this.currentConnectionPair = null
76
77
  }
77
78
  if (this.activeSubSolver?.failed) {
78
- this.failed = true
79
- this.error = this.activeSubSolver.error
80
- return
79
+ // Record the failure for this connection and continue to the next pair
80
+ if (this.currentConnectionPair) {
81
+ this.failedConnectionPairs.push({
82
+ ...this.currentConnectionPair,
83
+ error: this.activeSubSolver.error || undefined,
84
+ })
85
+ }
86
+ this.activeSubSolver = null
87
+ this.currentConnectionPair = null
88
+ // Do not fail the whole solver; proceed to schedule the next pair
81
89
  }
82
90
 
83
91
  if (this.activeSubSolver) {
@@ -122,6 +130,19 @@ export class SchematicTraceLinesSolver extends BaseSolver {
122
130
  })
123
131
  }
124
132
 
133
+ // Indicate failed connection pairs with dashed red lines between their pins
134
+ for (const pair of this.failedConnectionPairs) {
135
+ graphics.lines!.push({
136
+ points: [
137
+ { x: pair.pins[0].x, y: pair.pins[0].y },
138
+ { x: pair.pins[1].x, y: pair.pins[1].y },
139
+ ],
140
+ strokeColor: "red",
141
+ strokeDash: "4 2",
142
+ strokeWidth: 0.004,
143
+ })
144
+ }
145
+
125
146
  return graphics
126
147
  }
127
148
  }
@@ -103,12 +103,47 @@ export class SchematicTraceSingleLineSolver extends BaseSolver {
103
103
 
104
104
  const nextCandidatePath = this.queuedCandidatePaths.shift()!
105
105
 
106
- const obstacleOps = {
107
- excludeChipIds: [this.pins[0].chipId, this.pins[1].chipId],
108
- }
109
106
  for (let i = 0; i < nextCandidatePath.length - 1; i++) {
110
107
  const start = nextCandidatePath[i]
111
108
  const end = nextCandidatePath[i + 1]
109
+
110
+ // Determine which chips to exclude for this specific segment
111
+ let excludeChipIds: string[] = []
112
+
113
+ // Always exclude chips that contain the start or end points of this segment
114
+ // if those points are actually pin locations
115
+ const isStartPin = this.pins.some(
116
+ (pin) =>
117
+ Math.abs(pin.x - start.x) < 1e-10 &&
118
+ Math.abs(pin.y - start.y) < 1e-10,
119
+ )
120
+ const isEndPin = this.pins.some(
121
+ (pin) =>
122
+ Math.abs(pin.x - end.x) < 1e-10 && Math.abs(pin.y - end.y) < 1e-10,
123
+ )
124
+
125
+ if (isStartPin) {
126
+ const startPin = this.pins.find(
127
+ (pin) =>
128
+ Math.abs(pin.x - start.x) < 1e-10 &&
129
+ Math.abs(pin.y - start.y) < 1e-10,
130
+ )
131
+ if (startPin && !excludeChipIds.includes(startPin.chipId)) {
132
+ excludeChipIds.push(startPin.chipId)
133
+ }
134
+ }
135
+
136
+ if (isEndPin) {
137
+ const endPin = this.pins.find(
138
+ (pin) =>
139
+ Math.abs(pin.x - end.x) < 1e-10 && Math.abs(pin.y - end.y) < 1e-10,
140
+ )
141
+ if (endPin && !excludeChipIds.includes(endPin.chipId)) {
142
+ excludeChipIds.push(endPin.chipId)
143
+ }
144
+ }
145
+
146
+ const obstacleOps = { excludeChipIds }
112
147
  const intersects =
113
148
  this.chipObstacleSpatialIndex.doesOrthogonalLineIntersectChip(
114
149
  [start, end],
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.7",
4
+ "version": "0.0.9",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "start": "cosmos",
@@ -0,0 +1,122 @@
1
+ import { useMemo } from "react"
2
+ import { GenericSolverDebugger } from "../components/GenericSolverDebugger"
3
+ import { SchematicTraceLinesSolver } from "lib/solvers/SchematicTraceLinesSolver/SchematicTraceLinesSolver"
4
+
5
+ const input = {
6
+ mspConnectionPairs: [
7
+ {
8
+ mspPairId: "Q1.1-Q1.2",
9
+ dcConnNetId: "connectivity_net0",
10
+ globalConnNetId: "connectivity_net0",
11
+ userNetId: "V3_3",
12
+ pins: [
13
+ {
14
+ pinId: "Q1.1",
15
+ x: 0.30397715550000004,
16
+ y: 0.5800832909999993,
17
+ _facingDirection: "y+",
18
+ chipId: "schematic_component_0",
19
+ },
20
+ {
21
+ pinId: "Q1.2",
22
+ x: 0.31067575550000137,
23
+ y: -0.5800832909999993,
24
+ _facingDirection: "y-",
25
+ chipId: "schematic_component_0",
26
+ },
27
+ ],
28
+ },
29
+ ],
30
+ dcConnMap: {
31
+ netMap: {
32
+ connectivity_net0: ["Q1.1", "Q1.2"],
33
+ },
34
+ idToNetMap: {},
35
+ },
36
+ globalConnMap: {
37
+ netMap: {
38
+ connectivity_net0: ["Q1.1", "Q1.2"],
39
+ },
40
+ idToNetMap: {
41
+ "Q1.1": "connectivity_net0",
42
+ "Q1.2": "connectivity_net0",
43
+ },
44
+ },
45
+ inputProblem: {
46
+ chips: [
47
+ {
48
+ chipId: "schematic_component_0",
49
+ center: {
50
+ x: 0,
51
+ y: 0,
52
+ },
53
+ width: 0.8935117710000002,
54
+ height: 1.1601665819999987,
55
+ pins: [
56
+ {
57
+ pinId: "Q1.1",
58
+ x: 0.30397715550000004,
59
+ y: 0.5800832909999993,
60
+ },
61
+ {
62
+ pinId: "Q1.2",
63
+ x: 0.31067575550000137,
64
+ y: -0.5800832909999993,
65
+ },
66
+ {
67
+ pinId: "Q1.3",
68
+ x: -0.4467558855000001,
69
+ y: -0.10250625000000019,
70
+ },
71
+ ],
72
+ },
73
+ ],
74
+ directConnections: [],
75
+ netConnections: [
76
+ {
77
+ netId: "V3_3",
78
+ pinIds: ["Q1.1", "Q1.2"],
79
+ },
80
+ ],
81
+ availableNetLabelOrientations: {
82
+ V3_3: ["y+"],
83
+ },
84
+ maxMspPairDistance: 2,
85
+ },
86
+ guidelines: [],
87
+ chipMap: {
88
+ schematic_component_0: {
89
+ chipId: "schematic_component_0",
90
+ center: {
91
+ x: 0,
92
+ y: 0,
93
+ },
94
+ width: 0.8935117710000002,
95
+ height: 1.1601665819999987,
96
+ pins: [
97
+ {
98
+ pinId: "Q1.1",
99
+ x: 0.30397715550000004,
100
+ y: 0.5800832909999993,
101
+ },
102
+ {
103
+ pinId: "Q1.2",
104
+ x: 0.31067575550000137,
105
+ y: -0.5800832909999993,
106
+ },
107
+ {
108
+ pinId: "Q1.3",
109
+ x: -0.4467558855000001,
110
+ y: -0.10250625000000019,
111
+ },
112
+ ],
113
+ },
114
+ },
115
+ }
116
+
117
+ export default () => {
118
+ const solver = useMemo(() => {
119
+ return new SchematicTraceLinesSolver(input as any)
120
+ }, [])
121
+ return <GenericSolverDebugger solver={solver} />
122
+ }
@@ -0,0 +1,16 @@
1
+ import type { BaseSolver } from "lib/solvers/BaseSolver/BaseSolver"
2
+ import type { InputProblem } from "lib/types/InputProblem"
3
+ import { useMemo, useReducer } from "react"
4
+ import { InteractiveGraphics } from "graphics-debug/react"
5
+ import { SolverToolbar } from "./SolverToolbar"
6
+
7
+ export const GenericSolverDebugger = ({ solver }: { solver: BaseSolver }) => {
8
+ const [, incRenderCount] = useReducer((x) => x + 1, 0)
9
+
10
+ return (
11
+ <div>
12
+ <SolverToolbar triggerRender={() => incRenderCount()} solver={solver} />
13
+ <InteractiveGraphics graphics={solver.visualize()} />
14
+ </div>
15
+ )
16
+ }
@@ -95,9 +95,9 @@ const inputProblem: InputProblem = {
95
95
  },
96
96
  ],
97
97
  availableNetLabelOrientations: {
98
- VCC: ["y+", "y-"],
98
+ VCC: ["y+"],
99
99
  EN: ["x+", "x-"],
100
- GND: ["y+", "y-"],
100
+ GND: ["y-"],
101
101
  },
102
102
  maxMspPairDistance: 2,
103
103
  }