@tscircuit/schematic-trace-solver 0.0.5 → 0.0.7

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/dist/index.d.ts CHANGED
@@ -409,6 +409,7 @@ declare class SchematicTracePipelineSolver extends BaseSolver {
409
409
  pipelineDef: (PipelineStep<typeof MspConnectionPairSolver> | PipelineStep<typeof GuidelinesSolver> | PipelineStep<typeof SchematicTraceLinesSolver> | PipelineStep<typeof TraceOverlapShiftSolver> | PipelineStep<typeof NetLabelPlacementSolver>)[];
410
410
  constructor(inputProblem: InputProblem);
411
411
  currentPipelineStepIndex: number;
412
+ private cloneAndCorrectInputProblem;
412
413
  _step(): void;
413
414
  solveUntilPhase(phase: string): void;
414
415
  getCurrentPhase(): string;
package/dist/index.js CHANGED
@@ -7865,6 +7865,57 @@ var GuidelinesSolver = class extends BaseSolver {
7865
7865
  }
7866
7866
  };
7867
7867
 
7868
+ // lib/solvers/SchematicTracePipelineSolver/correctPinsInsideChip.ts
7869
+ var correctPinsInsideChips = (problem) => {
7870
+ for (const chip of problem.chips) {
7871
+ const bounds = getInputChipBounds(chip);
7872
+ for (const pin of chip.pins) {
7873
+ const isInside = pin.x > bounds.minX && pin.x < bounds.maxX && pin.y > bounds.minY && pin.y < bounds.maxY;
7874
+ if (!isInside) continue;
7875
+ const distLeft = pin.x - bounds.minX;
7876
+ const distRight = bounds.maxX - pin.x;
7877
+ const distBottom = pin.y - bounds.minY;
7878
+ const distTop = bounds.maxY - pin.y;
7879
+ const minDist = Math.min(distLeft, distRight, distBottom, distTop);
7880
+ if (minDist === distLeft) {
7881
+ pin.x = bounds.minX;
7882
+ } else if (minDist === distRight) {
7883
+ pin.x = bounds.maxX;
7884
+ } else if (minDist === distBottom) {
7885
+ pin.y = bounds.minY;
7886
+ } else {
7887
+ pin.y = bounds.maxY;
7888
+ }
7889
+ pin._facingDirection = void 0;
7890
+ }
7891
+ }
7892
+ };
7893
+
7894
+ // lib/solvers/SchematicTracePipelineSolver/expandChipsToFitPins.ts
7895
+ var expandChipsToFitPins = (problem) => {
7896
+ for (const chip of problem.chips) {
7897
+ const halfWidth = chip.width / 2;
7898
+ const halfHeight = chip.height / 2;
7899
+ let maxDx = 0;
7900
+ let maxDy = 0;
7901
+ for (const pin of chip.pins) {
7902
+ const dx = Math.abs(pin.x - chip.center.x);
7903
+ const dy = Math.abs(pin.y - chip.center.y);
7904
+ if (dx > maxDx) maxDx = dx;
7905
+ if (dy > maxDy) maxDy = dy;
7906
+ }
7907
+ const newHalfWidth = Math.max(halfWidth, maxDx);
7908
+ const newHalfHeight = Math.max(halfHeight, maxDy);
7909
+ if (newHalfWidth > halfWidth || newHalfHeight > halfHeight) {
7910
+ chip.width = newHalfWidth * 2;
7911
+ chip.height = newHalfHeight * 2;
7912
+ for (const pin of chip.pins) {
7913
+ pin._facingDirection = void 0;
7914
+ }
7915
+ }
7916
+ }
7917
+ };
7918
+
7868
7919
  // lib/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver.ts
7869
7920
  function definePipelineStep(solverName, solverClass, getConstructorParams, opts = {}) {
7870
7921
  return {
@@ -7963,7 +8014,7 @@ var SchematicTracePipelineSolver = class extends BaseSolver {
7963
8014
  ];
7964
8015
  constructor(inputProblem) {
7965
8016
  super();
7966
- this.inputProblem = inputProblem;
8017
+ this.inputProblem = this.cloneAndCorrectInputProblem(inputProblem);
7967
8018
  this.MAX_ITERATIONS = 1e6;
7968
8019
  this.startTimeOfPhase = {};
7969
8020
  this.endTimeOfPhase = {};
@@ -7971,6 +8022,15 @@ var SchematicTracePipelineSolver = class extends BaseSolver {
7971
8022
  this.firstIterationOfPhase = {};
7972
8023
  }
7973
8024
  currentPipelineStepIndex = 0;
8025
+ cloneAndCorrectInputProblem(original) {
8026
+ const cloned = structuredClone({
8027
+ ...original,
8028
+ _chipObstacleSpatialIndex: void 0
8029
+ });
8030
+ expandChipsToFitPins(cloned);
8031
+ correctPinsInsideChips(cloned);
8032
+ return cloned;
8033
+ }
7974
8034
  _step() {
7975
8035
  const pipelineStepDef = this.pipelineDef[this.currentPipelineStepIndex];
7976
8036
  if (!pipelineStepDef) {
@@ -12,6 +12,9 @@ import { TraceOverlapShiftSolver } from "../TraceOverlapShiftSolver/TraceOverlap
12
12
  import { NetLabelPlacementSolver } from "../NetLabelPlacementSolver/NetLabelPlacementSolver"
13
13
  import { visualizeInputProblem } from "./visualizeInputProblem"
14
14
  import { GuidelinesSolver } from "../GuidelinesSolver/GuidelinesSolver"
15
+ import { getInputChipBounds } from "../GuidelinesSolver/getInputChipBounds"
16
+ import { correctPinsInsideChips } from "./correctPinsInsideChip"
17
+ import { expandChipsToFitPins } from "./expandChipsToFitPins"
15
18
 
16
19
  type PipelineStep<T extends new (...args: any[]) => BaseSolver> = {
17
20
  solverName: string
@@ -135,7 +138,7 @@ export class SchematicTracePipelineSolver extends BaseSolver {
135
138
 
136
139
  constructor(inputProblem: InputProblem) {
137
140
  super()
138
- this.inputProblem = inputProblem
141
+ this.inputProblem = this.cloneAndCorrectInputProblem(inputProblem)
139
142
  this.MAX_ITERATIONS = 1e6
140
143
  this.startTimeOfPhase = {}
141
144
  this.endTimeOfPhase = {}
@@ -145,6 +148,20 @@ export class SchematicTracePipelineSolver extends BaseSolver {
145
148
 
146
149
  currentPipelineStepIndex = 0
147
150
 
151
+ private cloneAndCorrectInputProblem(original: InputProblem): InputProblem {
152
+ const cloned: InputProblem = structuredClone({
153
+ ...original,
154
+ _chipObstacleSpatialIndex: undefined,
155
+ })
156
+
157
+ // First, expand chips so existing pin coordinates sit on or within their edges without shrinking.
158
+ expandChipsToFitPins(cloned)
159
+ // Then, for any remaining pins that are still inside due to mixed extremes, snap them to the nearest edge.
160
+ correctPinsInsideChips(cloned)
161
+
162
+ return cloned
163
+ }
164
+
148
165
  override _step() {
149
166
  const pipelineStepDef = this.pipelineDef[this.currentPipelineStepIndex]
150
167
  if (!pipelineStepDef) {
@@ -0,0 +1,37 @@
1
+ import type { InputProblem } from "lib/types/InputProblem"
2
+ import { getInputChipBounds } from "../GuidelinesSolver/getInputChipBounds"
3
+
4
+ export const correctPinsInsideChips = (problem: InputProblem) => {
5
+ for (const chip of problem.chips) {
6
+ const bounds = getInputChipBounds(chip)
7
+ for (const pin of chip.pins) {
8
+ const isInside =
9
+ pin.x > bounds.minX &&
10
+ pin.x < bounds.maxX &&
11
+ pin.y > bounds.minY &&
12
+ pin.y < bounds.maxY
13
+
14
+ if (!isInside) continue
15
+
16
+ const distLeft = pin.x - bounds.minX
17
+ const distRight = bounds.maxX - pin.x
18
+ const distBottom = pin.y - bounds.minY
19
+ const distTop = bounds.maxY - pin.y
20
+
21
+ const minDist = Math.min(distLeft, distRight, distBottom, distTop)
22
+
23
+ if (minDist === distLeft) {
24
+ pin.x = bounds.minX
25
+ } else if (minDist === distRight) {
26
+ pin.x = bounds.maxX
27
+ } else if (minDist === distBottom) {
28
+ pin.y = bounds.minY
29
+ } else {
30
+ pin.y = bounds.maxY
31
+ }
32
+
33
+ // Clear any cached facing direction since geometry changed.
34
+ pin._facingDirection = undefined
35
+ }
36
+ }
37
+ }
@@ -0,0 +1,41 @@
1
+ import type { InputProblem } from "lib/types/InputProblem"
2
+
3
+ /**
4
+ * Expands chip width/height (never shrinks) so that all existing pin coordinates
5
+ * are inside or on the chip boundary, and any pin at the furthest extent in X/Y
6
+ * lies exactly on an edge.
7
+ *
8
+ * Notes:
9
+ * - Center is preserved.
10
+ * - Only increases dimensions as needed.
11
+ * - Clears cached _facingDirection on pins since geometry changed.
12
+ */
13
+ export const expandChipsToFitPins = (problem: InputProblem) => {
14
+ for (const chip of problem.chips) {
15
+ const halfWidth = chip.width / 2
16
+ const halfHeight = chip.height / 2
17
+
18
+ let maxDx = 0
19
+ let maxDy = 0
20
+
21
+ for (const pin of chip.pins) {
22
+ const dx = Math.abs(pin.x - chip.center.x)
23
+ const dy = Math.abs(pin.y - chip.center.y)
24
+ if (dx > maxDx) maxDx = dx
25
+ if (dy > maxDy) maxDy = dy
26
+ }
27
+
28
+ const newHalfWidth = Math.max(halfWidth, maxDx)
29
+ const newHalfHeight = Math.max(halfHeight, maxDy)
30
+
31
+ if (newHalfWidth > halfWidth || newHalfHeight > halfHeight) {
32
+ chip.width = newHalfWidth * 2
33
+ chip.height = newHalfHeight * 2
34
+
35
+ // Clear any cached facing direction since geometry changed.
36
+ for (const pin of chip.pins) {
37
+ pin._facingDirection = undefined
38
+ }
39
+ }
40
+ }
41
+ }
package/package.json CHANGED
@@ -1,12 +1,13 @@
1
1
  {
2
2
  "name": "@tscircuit/schematic-trace-solver",
3
3
  "main": "dist/index.js",
4
- "version": "0.0.5",
4
+ "version": "0.0.7",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "start": "cosmos",
8
8
  "build": "tsup lib/index.ts --format esm --dts",
9
- "format": "biome format --write ."
9
+ "format": "biome format --write .",
10
+ "format:check": "biome format ."
10
11
  },
11
12
  "devDependencies": {
12
13
  "@biomejs/biome": "^2.2.2",
@@ -0,0 +1,215 @@
1
+ import type { InputProblem } from "lib/index"
2
+ import { PipelineDebugger } from "site/components/PipelineDebugger"
3
+
4
+ const inputProblem: InputProblem = {
5
+ chips: [
6
+ {
7
+ chipId: "schematic_component_0",
8
+ center: {
9
+ x: -3,
10
+ y: 1.5,
11
+ },
12
+ width: 1.0011537820000012,
13
+ height: 0.44923699999999833,
14
+ pins: [
15
+ {
16
+ pinId: "PIN1_PIN2.1",
17
+ x: -3.4724184500000006,
18
+ y: 1.4489565000000004,
19
+ },
20
+ {
21
+ pinId: "PIN1_PIN2.2",
22
+ x: -3.4724184500000006,
23
+ y: 1.4489565000000004,
24
+ },
25
+ {
26
+ pinId: "PIN1_PIN2.3",
27
+ x: -2.5275815499999994,
28
+ y: 1.4485175000000003,
29
+ },
30
+ {
31
+ pinId: "PIN1_PIN2.4",
32
+ x: -2.5275815499999994,
33
+ y: 1.4485175000000003,
34
+ },
35
+ ],
36
+ },
37
+ {
38
+ chipId: "schematic_component_1",
39
+ center: {
40
+ x: 0,
41
+ y: 1.5,
42
+ },
43
+ width: 1.0011537820000012,
44
+ height: 0.44923699999999833,
45
+ pins: [
46
+ {
47
+ pinId: "PIN1_PIN3.1",
48
+ x: -0.4724184500000006,
49
+ y: 1.4489565000000004,
50
+ },
51
+ {
52
+ pinId: "PIN1_PIN3.2",
53
+ x: -0.4724184500000006,
54
+ y: 1.4489565000000004,
55
+ },
56
+ {
57
+ pinId: "PIN1_PIN3.3",
58
+ x: 0.4724184500000006,
59
+ y: 1.4485175000000003,
60
+ },
61
+ {
62
+ pinId: "PIN1_PIN3.4",
63
+ x: 0.4724184500000006,
64
+ y: 1.4485175000000003,
65
+ },
66
+ ],
67
+ },
68
+ {
69
+ chipId: "schematic_component_2",
70
+ center: {
71
+ x: 3,
72
+ y: 1.5,
73
+ },
74
+ width: 1.0011537820000012,
75
+ height: 0.44923699999999833,
76
+ pins: [
77
+ {
78
+ pinId: "PIN1_PIN4.1",
79
+ x: 2.5275815499999994,
80
+ y: 1.4489565000000004,
81
+ },
82
+ {
83
+ pinId: "PIN1_PIN4.2",
84
+ x: 2.5275815499999994,
85
+ y: 1.4489565000000004,
86
+ },
87
+ {
88
+ pinId: "PIN1_PIN4.3",
89
+ x: 3.4724184500000006,
90
+ y: 1.4485175000000003,
91
+ },
92
+ {
93
+ pinId: "PIN1_PIN4.4",
94
+ x: 3.4724184500000006,
95
+ y: 1.4485175000000003,
96
+ },
97
+ ],
98
+ },
99
+ {
100
+ chipId: "schematic_component_3",
101
+ center: {
102
+ x: -3,
103
+ y: -1.5,
104
+ },
105
+ width: 1.0011537820000012,
106
+ height: 0.44923699999999833,
107
+ pins: [
108
+ {
109
+ pinId: "PIN2_PIN3.1",
110
+ x: -3.4724184500000006,
111
+ y: -1.5510434999999996,
112
+ },
113
+ {
114
+ pinId: "PIN2_PIN3.2",
115
+ x: -3.4724184500000006,
116
+ y: -1.5510434999999996,
117
+ },
118
+ {
119
+ pinId: "PIN2_PIN3.3",
120
+ x: -2.5275815499999994,
121
+ y: -1.5514824999999997,
122
+ },
123
+ {
124
+ pinId: "PIN2_PIN3.4",
125
+ x: -2.5275815499999994,
126
+ y: -1.5514824999999997,
127
+ },
128
+ ],
129
+ },
130
+ {
131
+ chipId: "schematic_component_4",
132
+ center: {
133
+ x: 0,
134
+ y: -1.5,
135
+ },
136
+ width: 1.0011537820000012,
137
+ height: 0.44923699999999833,
138
+ pins: [
139
+ {
140
+ pinId: "PIN2_PIN4.1",
141
+ x: -0.4724184500000006,
142
+ y: -1.5510434999999996,
143
+ },
144
+ {
145
+ pinId: "PIN2_PIN4.2",
146
+ x: -0.4724184500000006,
147
+ y: -1.5510434999999996,
148
+ },
149
+ {
150
+ pinId: "PIN2_PIN4.3",
151
+ x: 0.4724184500000006,
152
+ y: -1.5514824999999997,
153
+ },
154
+ {
155
+ pinId: "PIN2_PIN4.4",
156
+ x: 0.4724184500000006,
157
+ y: -1.5514824999999997,
158
+ },
159
+ ],
160
+ },
161
+ {
162
+ chipId: "schematic_component_5",
163
+ center: {
164
+ x: 3,
165
+ y: -1.5,
166
+ },
167
+ width: 1.0011537820000012,
168
+ height: 0.44923699999999833,
169
+ pins: [
170
+ {
171
+ pinId: "PIN3_PIN4.1",
172
+ x: 2.5275815499999994,
173
+ y: -1.5510434999999996,
174
+ },
175
+ {
176
+ pinId: "PIN3_PIN4.2",
177
+ x: 2.5275815499999994,
178
+ y: -1.5510434999999996,
179
+ },
180
+ {
181
+ pinId: "PIN3_PIN4.3",
182
+ x: 3.4724184500000006,
183
+ y: -1.5514824999999997,
184
+ },
185
+ {
186
+ pinId: "PIN3_PIN4.4",
187
+ x: 3.4724184500000006,
188
+ y: -1.5514824999999997,
189
+ },
190
+ ],
191
+ },
192
+ ],
193
+ directConnections: [],
194
+ netConnections: [
195
+ {
196
+ netId: "PIN1",
197
+ pinIds: ["PIN1_PIN2.1", "PIN1_PIN3.1", "PIN1_PIN4.1"],
198
+ },
199
+ {
200
+ netId: "PIN2",
201
+ pinIds: ["PIN1_PIN2.2", "PIN2_PIN3.2", "PIN2_PIN4.2"],
202
+ },
203
+ {
204
+ netId: "PIN3",
205
+ pinIds: ["PIN1_PIN3.3", "PIN2_PIN3.3", "PIN3_PIN4.3"],
206
+ },
207
+ {
208
+ netId: "PIN4",
209
+ pinIds: ["PIN1_PIN4.4", "PIN2_PIN4.4", "PIN3_PIN4.4"],
210
+ },
211
+ ],
212
+ availableNetLabelOrientations: {},
213
+ }
214
+
215
+ export default () => <PipelineDebugger inputProblem={inputProblem} />