@tscircuit/schematic-trace-solver 0.0.34 → 0.0.36

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 (21) hide show
  1. package/dist/index.d.ts +3 -0
  2. package/dist/index.js +51 -11
  3. package/lib/solvers/NetLabelPlacementSolver/NetLabelPlacementSolver.ts +13 -0
  4. package/lib/solvers/NetLabelPlacementSolver/SingleNetLabelPlacementSolver/SingleNetLabelPlacementSolver.ts +11 -1
  5. package/lib/solvers/NetLabelPlacementSolver/SingleNetLabelPlacementSolver/geometry.ts +13 -3
  6. package/lib/solvers/NetLabelPlacementSolver/SingleNetLabelPlacementSolver/solvePortOnlyPin.ts +10 -2
  7. package/lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver2/SchematicTraceSingleLineSolver2.ts +19 -0
  8. package/lib/types/InputProblem.ts +1 -0
  9. package/package.json +2 -2
  10. package/site/SchematicTraceSingleLineSolver2/SchematicTraceSingleLineSolver2_01-example17.page.tsx +324 -0
  11. package/tests/examples/__snapshots__/example02.snap.svg +5 -8
  12. package/tests/examples/__snapshots__/example04.snap.svg +15 -12
  13. package/tests/examples/__snapshots__/example15.snap.svg +5 -8
  14. package/tests/examples/__snapshots__/example17.snap.svg +13 -16
  15. package/tests/examples/__snapshots__/example20.snap.svg +235 -0
  16. package/tests/examples/example20.test.tsx +190 -0
  17. package/tests/fixtures/matcher.ts +17 -15
  18. package/tests/fixtures/preload.ts +1 -0
  19. package/tests/solvers/SchematicTraceSingleLineSolver/SchematicTraceSingleLineSolver_repro01.test.ts +1 -1
  20. package/tests/solvers/SchematicTraceSingleLineSolver2/SchematicTraceSingleLineSolver2_01-example17-d1_1-u1_1.test.ts +323 -0
  21. package/tests/solvers/SchematicTraceSingleLineSolver2/__snapshots__/SchematicTraceSingleLineSolver2_01-example17-d1_1-u1_1.snap.svg +160 -0
package/dist/index.d.ts CHANGED
@@ -79,6 +79,7 @@ interface InputDirectConnection {
79
79
  interface InputNetConnection {
80
80
  netId: string;
81
81
  pinIds: Array<PinId>;
82
+ netLabelWidth?: number;
82
83
  }
83
84
  interface InputProblem {
84
85
  chips: Array<InputChip>;
@@ -279,6 +280,7 @@ declare class SingleNetLabelPlacementSolver extends BaseSolver {
279
280
  overlappingSameNetTraceGroup: OverlappingSameNetTraceGroup;
280
281
  availableOrientations: Array<FacingDirection>;
281
282
  chipObstacleSpatialIndex: ChipObstacleSpatialIndex;
283
+ netLabelWidth?: number;
282
284
  netLabelPlacement: NetLabelPlacement | null;
283
285
  testedCandidates: Array<{
284
286
  center: {
@@ -306,6 +308,7 @@ declare class SingleNetLabelPlacementSolver extends BaseSolver {
306
308
  inputTraceMap: Record<MspConnectionPairId, SolvedTracePath>;
307
309
  overlappingSameNetTraceGroup: OverlappingSameNetTraceGroup;
308
310
  availableOrientations: FacingDirection[];
311
+ netLabelWidth?: number;
309
312
  });
310
313
  getConstructorParams(): ConstructorParameters<typeof SingleNetLabelPlacementSolver>[0];
311
314
  _step(): void;
package/dist/index.js CHANGED
@@ -842,6 +842,20 @@ var SchematicTraceSingleLineSolver2 = class extends BaseSolver {
842
842
  chipAlpha: 0.1,
843
843
  connectionAlpha: 0.1
844
844
  });
845
+ g.lines.push({
846
+ points: this.baseElbow,
847
+ strokeColor: "red",
848
+ strokeDash: "4 4"
849
+ });
850
+ const [pin1, pin2] = this.pins;
851
+ g.lines.push({
852
+ points: [
853
+ { x: pin1.x, y: pin1.y },
854
+ { x: pin2.x, y: pin2.y }
855
+ ],
856
+ strokeColor: "blue",
857
+ strokeDash: "5 5"
858
+ });
845
859
  for (const { path, collisionChipIds: collisionRectIds } of this.queue) {
846
860
  g.lines.push({ points: path, strokeColor: "teal", strokeDash: "2 2" });
847
861
  }
@@ -1357,15 +1371,18 @@ var ChipObstacleSpatialIndex = class {
1357
1371
  // lib/solvers/NetLabelPlacementSolver/SingleNetLabelPlacementSolver/geometry.ts
1358
1372
  var NET_LABEL_HORIZONTAL_WIDTH = 0.45;
1359
1373
  var NET_LABEL_HORIZONTAL_HEIGHT = 0.2;
1360
- function getDimsForOrientation(orientation) {
1374
+ function getDimsForOrientation(params) {
1375
+ const { orientation, netLabelWidth } = params;
1376
+ const horizWidth = typeof netLabelWidth === "number" ? netLabelWidth : NET_LABEL_HORIZONTAL_WIDTH;
1361
1377
  if (orientation === "y+" || orientation === "y-") {
1362
1378
  return {
1379
+ // Rotated, so width/height swap
1363
1380
  width: NET_LABEL_HORIZONTAL_HEIGHT,
1364
- height: NET_LABEL_HORIZONTAL_WIDTH
1381
+ height: horizWidth
1365
1382
  };
1366
1383
  }
1367
1384
  return {
1368
- width: NET_LABEL_HORIZONTAL_WIDTH,
1385
+ width: horizWidth,
1369
1386
  height: NET_LABEL_HORIZONTAL_HEIGHT
1370
1387
  };
1371
1388
  }
@@ -1494,7 +1511,8 @@ function solveNetLabelPlacementForPortOnlyPin(params) {
1494
1511
  inputTraceMap,
1495
1512
  chipObstacleSpatialIndex,
1496
1513
  overlappingSameNetTraceGroup,
1497
- availableOrientations
1514
+ availableOrientations,
1515
+ netLabelWidth
1498
1516
  } = params;
1499
1517
  const pinId = overlappingSameNetTraceGroup.portOnlyPinId;
1500
1518
  if (!pinId) {
@@ -1526,7 +1544,10 @@ function solveNetLabelPlacementForPortOnlyPin(params) {
1526
1544
  const outwardOf = (o) => o === "x+" ? { x: 1, y: 0 } : o === "x-" ? { x: -1, y: 0 } : o === "y+" ? { x: 0, y: 1 } : { x: 0, y: -1 };
1527
1545
  const testedCandidates = [];
1528
1546
  for (const orientation of orientations) {
1529
- const { width: width2, height: height2 } = getDimsForOrientation(orientation);
1547
+ const { width: width2, height: height2 } = getDimsForOrientation({
1548
+ orientation,
1549
+ netLabelWidth
1550
+ });
1530
1551
  const baseCenter2 = getCenterFromAnchor(anchor, orientation, width2, height2);
1531
1552
  const outward2 = outwardOf(orientation);
1532
1553
  const offset2 = 1e-3;
@@ -1593,7 +1614,10 @@ function solveNetLabelPlacementForPortOnlyPin(params) {
1593
1614
  return { placement, testedCandidates };
1594
1615
  }
1595
1616
  const fallbackOrientation = pinFacingDirection;
1596
- const { width, height } = getDimsForOrientation(fallbackOrientation);
1617
+ const { width, height } = getDimsForOrientation({
1618
+ orientation: fallbackOrientation,
1619
+ netLabelWidth
1620
+ });
1597
1621
  const baseCenter = getCenterFromAnchor(
1598
1622
  anchor,
1599
1623
  fallbackOrientation,
@@ -1685,6 +1709,8 @@ var SingleNetLabelPlacementSolver = class extends BaseSolver {
1685
1709
  overlappingSameNetTraceGroup;
1686
1710
  availableOrientations;
1687
1711
  chipObstacleSpatialIndex;
1712
+ // Optional override for the width of the net label (per netId)
1713
+ netLabelWidth;
1688
1714
  netLabelPlacement = null;
1689
1715
  testedCandidates = [];
1690
1716
  constructor(params) {
@@ -1693,6 +1719,7 @@ var SingleNetLabelPlacementSolver = class extends BaseSolver {
1693
1719
  this.inputTraceMap = params.inputTraceMap;
1694
1720
  this.overlappingSameNetTraceGroup = params.overlappingSameNetTraceGroup;
1695
1721
  this.availableOrientations = params.availableOrientations;
1722
+ this.netLabelWidth = params.netLabelWidth;
1696
1723
  this.chipObstacleSpatialIndex = params.inputProblem._chipObstacleSpatialIndex ?? new ChipObstacleSpatialIndex(params.inputProblem.chips);
1697
1724
  }
1698
1725
  getConstructorParams() {
@@ -1700,7 +1727,8 @@ var SingleNetLabelPlacementSolver = class extends BaseSolver {
1700
1727
  inputProblem: this.inputProblem,
1701
1728
  inputTraceMap: this.inputTraceMap,
1702
1729
  overlappingSameNetTraceGroup: this.overlappingSameNetTraceGroup,
1703
- availableOrientations: this.availableOrientations
1730
+ availableOrientations: this.availableOrientations,
1731
+ netLabelWidth: this.netLabelWidth
1704
1732
  };
1705
1733
  }
1706
1734
  _step() {
@@ -1714,7 +1742,8 @@ var SingleNetLabelPlacementSolver = class extends BaseSolver {
1714
1742
  inputTraceMap: this.inputTraceMap,
1715
1743
  chipObstacleSpatialIndex: this.chipObstacleSpatialIndex,
1716
1744
  overlappingSameNetTraceGroup: this.overlappingSameNetTraceGroup,
1717
- availableOrientations: this.availableOrientations
1745
+ availableOrientations: this.availableOrientations,
1746
+ netLabelWidth: this.netLabelWidth
1718
1747
  });
1719
1748
  this.testedCandidates.push(...res.testedCandidates);
1720
1749
  if (res.placement) {
@@ -1782,7 +1811,10 @@ var SingleNetLabelPlacementSolver = class extends BaseSolver {
1782
1811
  const anchors = anchorsForSegment(a, b);
1783
1812
  for (const anchor of anchors) {
1784
1813
  for (const orientation of candidateOrients) {
1785
- const { width, height } = getDimsForOrientation(orientation);
1814
+ const { width, height } = getDimsForOrientation({
1815
+ orientation,
1816
+ netLabelWidth: this.netLabelWidth
1817
+ });
1786
1818
  const center = getCenterFromAnchor(
1787
1819
  anchor,
1788
1820
  orientation,
@@ -2061,11 +2093,15 @@ var NetLabelPlacementSolver = class extends BaseSolver {
2061
2093
  const isAlreadyFull = currOrients.length === 4 && fullOrients.every((o) => currOrients.includes(o));
2062
2094
  if (!this.triedAnyOrientationFallbackForCurrentGroup && !isAlreadyFull && this.currentGroup) {
2063
2095
  this.triedAnyOrientationFallbackForCurrentGroup = true;
2096
+ const netLabelWidth2 = this.currentGroup.netId ? this.inputProblem.netConnections.find(
2097
+ (nc) => nc.netId === this.currentGroup.netId
2098
+ )?.netLabelWidth : void 0;
2064
2099
  this.activeSubSolver = new SingleNetLabelPlacementSolver({
2065
2100
  inputProblem: this.inputProblem,
2066
2101
  inputTraceMap: this.inputTraceMap,
2067
2102
  overlappingSameNetTraceGroup: this.currentGroup,
2068
- availableOrientations: fullOrients
2103
+ availableOrientations: fullOrients,
2104
+ netLabelWidth: netLabelWidth2
2069
2105
  });
2070
2106
  return;
2071
2107
  }
@@ -2085,11 +2121,15 @@ var NetLabelPlacementSolver = class extends BaseSolver {
2085
2121
  const netId = nextOverlappingSameNetTraceGroup.netId ?? nextOverlappingSameNetTraceGroup.globalConnNetId;
2086
2122
  this.currentGroup = nextOverlappingSameNetTraceGroup;
2087
2123
  this.triedAnyOrientationFallbackForCurrentGroup = false;
2124
+ const netLabelWidth = this.currentGroup.netId ? this.inputProblem.netConnections.find(
2125
+ (nc) => nc.netId === this.currentGroup.netId
2126
+ )?.netLabelWidth : void 0;
2088
2127
  this.activeSubSolver = new SingleNetLabelPlacementSolver({
2089
2128
  inputProblem: this.inputProblem,
2090
2129
  inputTraceMap: this.inputTraceMap,
2091
2130
  overlappingSameNetTraceGroup: nextOverlappingSameNetTraceGroup,
2092
- availableOrientations: this.inputProblem.availableNetLabelOrientations[netId] ?? ["x+", "x-", "y+", "y-"]
2131
+ availableOrientations: this.inputProblem.availableNetLabelOrientations[netId] ?? ["x+", "x-", "y+", "y-"],
2132
+ netLabelWidth
2093
2133
  });
2094
2134
  }
2095
2135
  visualize() {
@@ -273,11 +273,17 @@ export class NetLabelPlacementSolver extends BaseSolver {
273
273
  this.currentGroup
274
274
  ) {
275
275
  this.triedAnyOrientationFallbackForCurrentGroup = true
276
+ const netLabelWidth = this.currentGroup.netId
277
+ ? this.inputProblem.netConnections.find(
278
+ (nc) => nc.netId === this.currentGroup!.netId,
279
+ )?.netLabelWidth
280
+ : undefined
276
281
  this.activeSubSolver = new SingleNetLabelPlacementSolver({
277
282
  inputProblem: this.inputProblem,
278
283
  inputTraceMap: this.inputTraceMap,
279
284
  overlappingSameNetTraceGroup: this.currentGroup,
280
285
  availableOrientations: fullOrients,
286
+ netLabelWidth,
281
287
  })
282
288
  return
283
289
  }
@@ -307,6 +313,12 @@ export class NetLabelPlacementSolver extends BaseSolver {
307
313
  this.currentGroup = nextOverlappingSameNetTraceGroup
308
314
  this.triedAnyOrientationFallbackForCurrentGroup = false
309
315
 
316
+ const netLabelWidth = this.currentGroup.netId
317
+ ? this.inputProblem.netConnections.find(
318
+ (nc) => nc.netId === this.currentGroup!.netId,
319
+ )?.netLabelWidth
320
+ : undefined
321
+
310
322
  this.activeSubSolver = new SingleNetLabelPlacementSolver({
311
323
  inputProblem: this.inputProblem,
312
324
  inputTraceMap: this.inputTraceMap,
@@ -314,6 +326,7 @@ export class NetLabelPlacementSolver extends BaseSolver {
314
326
  availableOrientations: this.inputProblem.availableNetLabelOrientations[
315
327
  netId
316
328
  ] ?? ["x+", "x-", "y+", "y-"],
329
+ netLabelWidth,
317
330
  })
318
331
  }
319
332
 
@@ -58,6 +58,9 @@ export class SingleNetLabelPlacementSolver extends BaseSolver {
58
58
 
59
59
  chipObstacleSpatialIndex: ChipObstacleSpatialIndex
60
60
 
61
+ // Optional override for the width of the net label (per netId)
62
+ netLabelWidth?: number
63
+
61
64
  netLabelPlacement: NetLabelPlacement | null = null
62
65
  testedCandidates: Array<{
63
66
  center: { x: number; y: number }
@@ -75,12 +78,14 @@ export class SingleNetLabelPlacementSolver extends BaseSolver {
75
78
  inputTraceMap: Record<MspConnectionPairId, SolvedTracePath>
76
79
  overlappingSameNetTraceGroup: OverlappingSameNetTraceGroup
77
80
  availableOrientations: FacingDirection[]
81
+ netLabelWidth?: number
78
82
  }) {
79
83
  super()
80
84
  this.inputProblem = params.inputProblem
81
85
  this.inputTraceMap = params.inputTraceMap
82
86
  this.overlappingSameNetTraceGroup = params.overlappingSameNetTraceGroup
83
87
  this.availableOrientations = params.availableOrientations
88
+ this.netLabelWidth = params.netLabelWidth
84
89
 
85
90
  this.chipObstacleSpatialIndex =
86
91
  params.inputProblem._chipObstacleSpatialIndex ??
@@ -95,6 +100,7 @@ export class SingleNetLabelPlacementSolver extends BaseSolver {
95
100
  inputTraceMap: this.inputTraceMap,
96
101
  overlappingSameNetTraceGroup: this.overlappingSameNetTraceGroup,
97
102
  availableOrientations: this.availableOrientations,
103
+ netLabelWidth: this.netLabelWidth,
98
104
  }
99
105
  }
100
106
 
@@ -112,6 +118,7 @@ export class SingleNetLabelPlacementSolver extends BaseSolver {
112
118
  chipObstacleSpatialIndex: this.chipObstacleSpatialIndex,
113
119
  overlappingSameNetTraceGroup: this.overlappingSameNetTraceGroup,
114
120
  availableOrientations: this.availableOrientations,
121
+ netLabelWidth: this.netLabelWidth,
115
122
  })
116
123
  this.testedCandidates.push(...res.testedCandidates)
117
124
  if (res.placement) {
@@ -220,7 +227,10 @@ export class SingleNetLabelPlacementSolver extends BaseSolver {
220
227
  const anchors = anchorsForSegment(a, b)
221
228
  for (const anchor of anchors) {
222
229
  for (const orientation of candidateOrients) {
223
- const { width, height } = getDimsForOrientation(orientation)
230
+ const { width, height } = getDimsForOrientation({
231
+ orientation,
232
+ netLabelWidth: this.netLabelWidth,
233
+ })
224
234
  const center = getCenterFromAnchor(
225
235
  anchor,
226
236
  orientation,
@@ -3,15 +3,25 @@ import type { FacingDirection } from "lib/utils/dir"
3
3
  export const NET_LABEL_HORIZONTAL_WIDTH = 0.45
4
4
  export const NET_LABEL_HORIZONTAL_HEIGHT = 0.2
5
5
 
6
- export function getDimsForOrientation(orientation: FacingDirection) {
6
+ export function getDimsForOrientation(params: {
7
+ orientation: FacingDirection
8
+ netLabelWidth?: number
9
+ }) {
10
+ const { orientation, netLabelWidth } = params
11
+ const horizWidth =
12
+ typeof netLabelWidth === "number"
13
+ ? netLabelWidth
14
+ : NET_LABEL_HORIZONTAL_WIDTH
15
+
7
16
  if (orientation === "y+" || orientation === "y-") {
8
17
  return {
18
+ // Rotated, so width/height swap
9
19
  width: NET_LABEL_HORIZONTAL_HEIGHT,
10
- height: NET_LABEL_HORIZONTAL_WIDTH,
20
+ height: horizWidth,
11
21
  }
12
22
  }
13
23
  return {
14
- width: NET_LABEL_HORIZONTAL_WIDTH,
24
+ width: horizWidth,
15
25
  height: NET_LABEL_HORIZONTAL_HEIGHT,
16
26
  }
17
27
  }
@@ -21,6 +21,7 @@ export function solveNetLabelPlacementForPortOnlyPin(params: {
21
21
  chipObstacleSpatialIndex: ChipObstacleSpatialIndex
22
22
  overlappingSameNetTraceGroup: OverlappingSameNetTraceGroup
23
23
  availableOrientations: FacingDirection[]
24
+ netLabelWidth?: number
24
25
  }): {
25
26
  placement: NetLabelPlacement | null
26
27
  testedCandidates: Array<{
@@ -41,6 +42,7 @@ export function solveNetLabelPlacementForPortOnlyPin(params: {
41
42
  chipObstacleSpatialIndex,
42
43
  overlappingSameNetTraceGroup,
43
44
  availableOrientations,
45
+ netLabelWidth,
44
46
  } = params
45
47
 
46
48
  const pinId = overlappingSameNetTraceGroup.portOnlyPinId
@@ -98,7 +100,10 @@ export function solveNetLabelPlacementForPortOnlyPin(params: {
98
100
  }> = []
99
101
 
100
102
  for (const orientation of orientations) {
101
- const { width, height } = getDimsForOrientation(orientation)
103
+ const { width, height } = getDimsForOrientation({
104
+ orientation,
105
+ netLabelWidth,
106
+ })
102
107
  // Place label fully outside the chip: shift center slightly outward
103
108
  const baseCenter = getCenterFromAnchor(anchor, orientation, width, height)
104
109
  const outward = outwardOf(orientation)
@@ -176,7 +181,10 @@ export function solveNetLabelPlacementForPortOnlyPin(params: {
176
181
 
177
182
  // If no valid placements found, return placement using pin's facing direction
178
183
  const fallbackOrientation = pinFacingDirection
179
- const { width, height } = getDimsForOrientation(fallbackOrientation)
184
+ const { width, height } = getDimsForOrientation({
185
+ orientation: fallbackOrientation,
186
+ netLabelWidth,
187
+ })
180
188
  const baseCenter = getCenterFromAnchor(
181
189
  anchor,
182
190
  fallbackOrientation,
@@ -222,6 +222,25 @@ export class SchematicTraceSingleLineSolver2 extends BaseSolver {
222
222
  connectionAlpha: 0.1,
223
223
  })
224
224
 
225
+ // Draw the base elbow
226
+
227
+ g.lines!.push({
228
+ points: this.baseElbow,
229
+ strokeColor: "red",
230
+ strokeDash: "4 4",
231
+ })
232
+
233
+ // Draw the MSP pair connection with a dashed line
234
+ const [pin1, pin2] = this.pins
235
+ g.lines!.push({
236
+ points: [
237
+ { x: pin1.x, y: pin1.y },
238
+ { x: pin2.x, y: pin2.y },
239
+ ],
240
+ strokeColor: "blue",
241
+ strokeDash: "5 5",
242
+ })
243
+
225
244
  // Draw all the new candidates
226
245
  for (const { path, collisionChipIds: collisionRectIds } of this.queue) {
227
246
  g.lines!.push({ points: path, strokeColor: "teal", strokeDash: "2 2" })
@@ -27,6 +27,7 @@ export interface InputDirectConnection {
27
27
  export interface InputNetConnection {
28
28
  netId: string
29
29
  pinIds: Array<PinId>
30
+ netLabelWidth?: number
30
31
  }
31
32
 
32
33
  export interface InputProblem {
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.34",
4
+ "version": "0.0.36",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "start": "cosmos",
@@ -15,7 +15,7 @@
15
15
  "@tscircuit/math-utils": "^0.0.19",
16
16
  "@types/bun": "^1.2.21",
17
17
  "bun-match-svg": "^0.0.13",
18
- "calculate-elbow": "^0.0.11",
18
+ "calculate-elbow": "^0.0.12",
19
19
  "connectivity-map": "^1.0.0",
20
20
  "flatbush": "^4.5.0",
21
21
  "graphics-debug": "^0.0.62",