@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 +1 -0
- package/dist/index.js +61 -1
- package/lib/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver.ts +18 -1
- package/lib/solvers/SchematicTracePipelineSolver/correctPinsInsideChip.ts +37 -0
- package/lib/solvers/SchematicTracePipelineSolver/expandChipsToFitPins.ts +41 -0
- package/package.json +3 -2
- package/site/examples/example03.page.tsx +215 -0
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.
|
|
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} />
|