@tscircuit/schematic-trace-solver 0.0.152 → 0.0.154

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 (25) hide show
  1. package/dist/index.d.ts +5 -5
  2. package/dist/index.js +84 -27
  3. package/lib/solvers/AvailableNetOrientationSolver/AvailableNetOrientationSolver.ts +7 -0
  4. package/lib/solvers/NetLabelPlacementSolver/NetLabelPlacementSolver.ts +1 -0
  5. package/lib/solvers/SameNetJunctionAlignmentSolver/alignSameNetJunctions.ts +81 -8
  6. package/lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver2/SchematicTraceSingleLineSolver2.ts +1 -1
  7. package/lib/solvers/TraceAnchoredNetLabelOverlapSolver/candidates.ts +1 -0
  8. package/lib/types/InputProblem.ts +5 -5
  9. package/lib/utils/getNetLabelWidthForConnection.ts +9 -10
  10. package/package.json +1 -1
  11. package/site/bug-reports/bug-report-20260825T103621Z.page.tsx +4 -0
  12. package/tests/assets/example51.json +159 -32
  13. package/tests/bug-reports/bug-report-20260825T103621Z/__snapshots__/bug-report-20260825T103621Z.snap.svg +452 -0
  14. package/tests/bug-reports/bug-report-20260825T103621Z/bug-report-20260825T103621Z.json +1696 -0
  15. package/tests/bug-reports/bug-report-20260825T103621Z/bug-report-20260825T103621Z.test.ts +12 -0
  16. package/tests/examples/__snapshots__/example51.snap.svg +485 -473
  17. package/tests/examples/example51.test.ts +3 -1
  18. package/tests/repros/__snapshots__/repro-core-tb67s579ftg-inline-label-routing.snap.svg +8 -8
  19. package/tests/repros/__snapshots__/repro-pga300-c6-trace-alignment.snap.svg +88 -0
  20. package/tests/repros/assets/repro-core-tb67s579ftg-inline-label-routing.input.json +33 -33
  21. package/tests/repros/assets/repro-pga300-c6-trace-alignment.input.json +97 -0
  22. package/tests/repros/repro-core-tb67s579ftg-inline-label-routing.test.ts +3 -2
  23. package/tests/repros/repro-pga300-c6-trace-alignment.test.ts +36 -0
  24. package/tests/solvers/InlineNetLabelSolver/{fallback-net-label-width.test.ts → anchored-net-label-width.test.ts} +34 -11
  25. /package/tests/solvers/InlineNetLabelSolver/__snapshots__/{fallback-net-label-width.snap.svg → anchored-net-label-width.snap.svg} +0 -0
package/dist/index.d.ts CHANGED
@@ -108,11 +108,11 @@ interface InputDirectConnection {
108
108
  netLabelText?: string;
109
109
  netLabelWidth?: number;
110
110
  /**
111
- * Width of the conventional anchored label to use only when an inline label
112
- * cannot be placed. Unlike `netLabelWidth`, this does not affect whether or
113
- * how the point-to-point connection is routed.
111
+ * Width of the conventional label anchored to a trace endpoint. Unlike
112
+ * `netLabelWidth`, this does not affect whether or how the point-to-point
113
+ * connection is routed.
114
114
  */
115
- fallbackNetLabelWidth?: number;
115
+ anchoredNetLabelWidth?: number;
116
116
  /**
117
117
  * When true, this point-to-point connection may be labeled with an "inline
118
118
  * net label": the net name is drawn parallel to (and offset from) the routed
@@ -149,7 +149,7 @@ interface InputNetConnection {
149
149
  */
150
150
  netLabelText?: string;
151
151
  netLabelWidth?: number;
152
- fallbackNetLabelWidth?: number;
152
+ anchoredNetLabelWidth?: number;
153
153
  netLabelHeight?: number;
154
154
  /**
155
155
  * When true, a named one- or two-pin net may use inline labels. A single-pin
package/dist/index.js CHANGED
@@ -679,21 +679,20 @@ import "graphics-debug";
679
679
  import { calculateElbow as calculateElbow2 } from "calculate-elbow";
680
680
 
681
681
  // lib/utils/getNetLabelWidthForConnection.ts
682
- var getConfiguredWidth = (connections, includeFallbackNetLabelWidth) => {
683
- const explicitWidth = connections.find(
682
+ var getConfiguredWidth = (connections, isPortOnlyLabel2) => {
683
+ const width = connections.find(
684
684
  (connection) => connection?.netLabelWidth !== void 0
685
685
  )?.netLabelWidth;
686
- if (explicitWidth !== void 0) return explicitWidth;
687
- if (!includeFallbackNetLabelWidth) return void 0;
686
+ if (width !== void 0 || !isPortOnlyLabel2) return width;
688
687
  return connections.find(
689
- (connection) => connection?.fallbackNetLabelWidth !== void 0
690
- )?.fallbackNetLabelWidth;
688
+ (connection) => connection?.anchoredNetLabelWidth !== void 0
689
+ )?.anchoredNetLabelWidth;
691
690
  };
692
691
  var getNetLabelWidthForConnection = ({
693
692
  inputProblem,
694
693
  netId,
695
694
  pinIds,
696
- includeFallbackNetLabelWidth = true
695
+ isPortOnlyLabel: isPortOnlyLabel2
697
696
  }) => {
698
697
  if (netId) {
699
698
  const widthByNetId = getConfiguredWidth(
@@ -705,7 +704,7 @@ var getNetLabelWidthForConnection = ({
705
704
  (connection) => connection.netId === netId
706
705
  )
707
706
  ],
708
- includeFallbackNetLabelWidth
707
+ isPortOnlyLabel2
709
708
  );
710
709
  if (widthByNetId !== void 0) return widthByNetId;
711
710
  }
@@ -718,7 +717,7 @@ var getNetLabelWidthForConnection = ({
718
717
  (connection) => connection.pinIds.some((pinId) => pinIds.includes(pinId))
719
718
  )
720
719
  ],
721
- includeFallbackNetLabelWidth
720
+ isPortOnlyLabel2
722
721
  );
723
722
  };
724
723
 
@@ -1329,7 +1328,7 @@ var SchematicTraceSingleLineSolver2 = class extends BaseSolver {
1329
1328
  inputProblem: this.inputProblem,
1330
1329
  netId,
1331
1330
  pinIds: this.pins.map((pin) => pin.pinId),
1332
- includeFallbackNetLabelWidth: false
1331
+ isPortOnlyLabel: false
1333
1332
  });
1334
1333
  const netLabelHeight = this.getNetLabelHeightForConnectionPair(netId);
1335
1334
  const padding = {
@@ -3270,7 +3269,8 @@ var NetLabelPlacementSolver = class extends BaseSolver {
3270
3269
  return getNetLabelWidthForConnection({
3271
3270
  inputProblem: this.inputProblem,
3272
3271
  netId: group.netId,
3273
- pinIds
3272
+ pinIds,
3273
+ isPortOnlyLabel: group.portOnlyPinId !== void 0
3274
3274
  });
3275
3275
  }
3276
3276
  getNetLabelHeightForGroup(group) {
@@ -8620,7 +8620,8 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
8620
8620
  const blockedLabelWidth = getNetLabelWidthForConnection({
8621
8621
  inputProblem: this.inputProblem,
8622
8622
  netId: blockedLabel.netId,
8623
- pinIds: blockedLabel.pinIds
8623
+ pinIds: blockedLabel.pinIds,
8624
+ isPortOnlyLabel: this.isPortOnlyLabel(blockedLabel)
8624
8625
  });
8625
8626
  let columnLabelIndex;
8626
8627
  if (blockedLabelWidth !== void 0) {
@@ -8630,7 +8631,8 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
8630
8631
  return getNetLabelWidthForConnection({
8631
8632
  inputProblem: this.inputProblem,
8632
8633
  netId: label.netId,
8633
- pinIds: label.pinIds
8634
+ pinIds: label.pinIds,
8635
+ isPortOnlyLabel: this.isPortOnlyLabel(label)
8634
8636
  }) === blockedLabelWidth;
8635
8637
  });
8636
8638
  }
@@ -8855,7 +8857,8 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
8855
8857
  netLabelWidth: getNetLabelWidthForConnection({
8856
8858
  inputProblem: this.inputProblem,
8857
8859
  netId: label.netId,
8858
- pinIds: label.pinIds
8860
+ pinIds: label.pinIds,
8861
+ isPortOnlyLabel: this.isPortOnlyLabel(label)
8859
8862
  }),
8860
8863
  netLabelHeight: this.getNetLabelHeight(label)
8861
8864
  });
@@ -9293,7 +9296,8 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
9293
9296
  netLabelWidth: getNetLabelWidthForConnection({
9294
9297
  inputProblem: this.inputProblem,
9295
9298
  netId: label.netId,
9296
- pinIds: label.pinIds
9299
+ pinIds: label.pinIds,
9300
+ isPortOnlyLabel: this.isPortOnlyLabel(label)
9297
9301
  }),
9298
9302
  netLabelHeight: this.getNetLabelHeight(label)
9299
9303
  });
@@ -9315,7 +9319,8 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
9315
9319
  netLabelWidth: getNetLabelWidthForConnection({
9316
9320
  inputProblem: this.inputProblem,
9317
9321
  netId: label.netId,
9318
- pinIds: label.pinIds
9322
+ pinIds: label.pinIds,
9323
+ isPortOnlyLabel: this.isPortOnlyLabel(label)
9319
9324
  }),
9320
9325
  netLabelHeight: this.getNetLabelHeight(label)
9321
9326
  });
@@ -9374,7 +9379,8 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
9374
9379
  netLabelWidth: getNetLabelWidthForConnection({
9375
9380
  inputProblem: this.inputProblem,
9376
9381
  netId: label.netId,
9377
- pinIds: label.pinIds
9382
+ pinIds: label.pinIds,
9383
+ isPortOnlyLabel: this.isPortOnlyLabel(label)
9378
9384
  }),
9379
9385
  netLabelHeight: this.getNetLabelHeight(label)
9380
9386
  });
@@ -9429,7 +9435,8 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
9429
9435
  netLabelWidth: getNetLabelWidthForConnection({
9430
9436
  inputProblem: this.inputProblem,
9431
9437
  netId: label.netId,
9432
- pinIds: label.pinIds
9438
+ pinIds: label.pinIds,
9439
+ isPortOnlyLabel: this.isPortOnlyLabel(label)
9433
9440
  }),
9434
9441
  netLabelHeight: this.getNetLabelHeight(label)
9435
9442
  });
@@ -10643,7 +10650,8 @@ var getNetLabelWidth = (inputProblem, label) => {
10643
10650
  const configuredWidth = getNetLabelWidthForConnection({
10644
10651
  inputProblem,
10645
10652
  netId: label.netId,
10646
- pinIds: label.pinIds
10653
+ pinIds: label.pinIds,
10654
+ isPortOnlyLabel: label.mspConnectionPairIds.length === 0
10647
10655
  });
10648
10656
  if (configuredWidth !== void 0) return configuredWidth;
10649
10657
  if (label.orientation === "y+" || label.orientation === "y-") {
@@ -12131,6 +12139,7 @@ var pathEntersAnyNetLabel = ({
12131
12139
  // lib/solvers/SameNetJunctionAlignmentSolver/alignSameNetJunctions.ts
12132
12140
  var MAX_ALIGNED_LOAD_PIN_OFFSET = 0.2;
12133
12141
  var MAX_SAME_NET_LABEL_BOUNDARY_RAIL_OFFSET = 0.2;
12142
+ var MAX_SHARED_PIN_RAIL_OFFSET = 0.05;
12134
12143
  var getSharedPin = ({
12135
12144
  donorTrace,
12136
12145
  branchTrace
@@ -12170,6 +12179,28 @@ var railIsOnFacingSide = ({
12170
12179
  if (pin._facingDirection === "y+") return railY > pin.y;
12171
12180
  return false;
12172
12181
  };
12182
+ var railIsOnSharedPinFacingSide = ({
12183
+ railY,
12184
+ pin
12185
+ }) => {
12186
+ if (pin._facingDirection === "y+") return railY > pin.y;
12187
+ if (pin._facingDirection === "y-") return railY < pin.y;
12188
+ return false;
12189
+ };
12190
+ var getHorizontalPinApproachPoint = ({
12191
+ branchTrace,
12192
+ sharedPin,
12193
+ otherPin
12194
+ }) => {
12195
+ if (otherPin._facingDirection !== "x-" && otherPin._facingDirection !== "x+") {
12196
+ return null;
12197
+ }
12198
+ const sharedToOtherPath = branchTrace.pins[0].pinId === sharedPin.pinId ? branchTrace.tracePath : [...branchTrace.tracePath].reverse();
12199
+ const approachPoint = sharedToOtherPath.at(-2);
12200
+ if (!approachPoint || !nearlyEqual(approachPoint.y, otherPin.y)) return null;
12201
+ const approachesFromFacingSide = otherPin._facingDirection === "x-" ? approachPoint.x < otherPin.x : approachPoint.x > otherPin.x;
12202
+ return approachesFromFacingSide ? approachPoint : null;
12203
+ };
12173
12204
  var getAttachedLabelIndexes = (trace, netLabelPlacements) => netLabelPlacements.flatMap((label, index) => {
12174
12205
  const labelOwnsTrace = label.mspConnectionPairIds.includes(trace.mspPairId) || label.mspConnectionPairIds.length === 0 && label.globalConnNetId === trace.globalConnNetId;
12175
12206
  return labelOwnsTrace && tracePathContainsPoint(trace.tracePath, label.anchorPoint) ? [index] : [];
@@ -12218,19 +12249,45 @@ var getAlignedBranchPath = ({
12218
12249
  if (branchRail && nearlyEqual(branchRail.start.y, donorRail.start.y)) {
12219
12250
  return null;
12220
12251
  }
12221
- if (!railIsOnFacingSide({ railY: donorRail.start.y, pin: otherPin })) {
12252
+ const railFacesOtherPin = railIsOnFacingSide({
12253
+ railY: donorRail.start.y,
12254
+ pin: otherPin
12255
+ });
12256
+ const railFacesSharedPin = railIsOnSharedPinFacingSide({
12257
+ railY: donorRail.start.y,
12258
+ pin: sharedPin
12259
+ }) && Math.abs(donorRail.start.y - sharedPin.y) <= MAX_SHARED_PIN_RAIL_OFFSET;
12260
+ if (!railFacesOtherPin && !railFacesSharedPin) {
12222
12261
  return null;
12223
12262
  }
12224
12263
  const junction = getJunctionPoint({ segment: donorRail, sharedPin });
12225
12264
  const extendsDonorRail = donorOtherPin.x < junction.x && otherPin.x > junction.x || donorOtherPin.x > junction.x && otherPin.x < junction.x;
12226
12265
  if (!extendsDonorRail) return null;
12227
- const sharedToOther = simplifyPath([
12228
- { x: sharedPin.x, y: sharedPin.y },
12229
- { x: junction.x, y: sharedPin.y },
12230
- { x: junction.x, y: junction.y },
12231
- { x: otherPin.x, y: junction.y },
12232
- { x: otherPin.x, y: otherPin.y }
12233
- ]);
12266
+ let sharedToOther;
12267
+ if (!railFacesOtherPin && railFacesSharedPin) {
12268
+ const approachPoint = getHorizontalPinApproachPoint({
12269
+ branchTrace,
12270
+ sharedPin,
12271
+ otherPin
12272
+ });
12273
+ if (!approachPoint) return null;
12274
+ sharedToOther = simplifyPath([
12275
+ { x: sharedPin.x, y: sharedPin.y },
12276
+ { x: junction.x, y: sharedPin.y },
12277
+ { x: junction.x, y: junction.y },
12278
+ { x: approachPoint.x, y: junction.y },
12279
+ { x: approachPoint.x, y: otherPin.y },
12280
+ { x: otherPin.x, y: otherPin.y }
12281
+ ]);
12282
+ } else {
12283
+ sharedToOther = simplifyPath([
12284
+ { x: sharedPin.x, y: sharedPin.y },
12285
+ { x: junction.x, y: sharedPin.y },
12286
+ { x: junction.x, y: junction.y },
12287
+ { x: otherPin.x, y: junction.y },
12288
+ { x: otherPin.x, y: otherPin.y }
12289
+ ]);
12290
+ }
12234
12291
  if (branchTrace.pins[0].pinId === sharedPin.pinId) return sharedToOther;
12235
12292
  return [...sharedToOther].reverse();
12236
12293
  };
@@ -185,6 +185,7 @@ export class AvailableNetOrientationSolver extends BaseSolver {
185
185
  inputProblem: this.inputProblem,
186
186
  netId: blockedLabel.netId,
187
187
  pinIds: blockedLabel.pinIds,
188
+ isPortOnlyLabel: this.isPortOnlyLabel(blockedLabel),
188
189
  })
189
190
  let columnLabelIndex: number | undefined
190
191
  if (blockedLabelWidth !== undefined) {
@@ -196,6 +197,7 @@ export class AvailableNetOrientationSolver extends BaseSolver {
196
197
  inputProblem: this.inputProblem,
197
198
  netId: label.netId,
198
199
  pinIds: label.pinIds,
200
+ isPortOnlyLabel: this.isPortOnlyLabel(label),
199
201
  }) === blockedLabelWidth
200
202
  )
201
203
  })
@@ -496,6 +498,7 @@ export class AvailableNetOrientationSolver extends BaseSolver {
496
498
  inputProblem: this.inputProblem,
497
499
  netId: label.netId,
498
500
  pinIds: label.pinIds,
501
+ isPortOnlyLabel: this.isPortOnlyLabel(label),
499
502
  }),
500
503
  netLabelHeight: this.getNetLabelHeight(label),
501
504
  })
@@ -1113,6 +1116,7 @@ export class AvailableNetOrientationSolver extends BaseSolver {
1113
1116
  inputProblem: this.inputProblem,
1114
1117
  netId: label.netId,
1115
1118
  pinIds: label.pinIds,
1119
+ isPortOnlyLabel: this.isPortOnlyLabel(label),
1116
1120
  }),
1117
1121
  netLabelHeight: this.getNetLabelHeight(label),
1118
1122
  })
@@ -1141,6 +1145,7 @@ export class AvailableNetOrientationSolver extends BaseSolver {
1141
1145
  inputProblem: this.inputProblem,
1142
1146
  netId: label.netId,
1143
1147
  pinIds: label.pinIds,
1148
+ isPortOnlyLabel: this.isPortOnlyLabel(label),
1144
1149
  }),
1145
1150
  netLabelHeight: this.getNetLabelHeight(label),
1146
1151
  })
@@ -1224,6 +1229,7 @@ export class AvailableNetOrientationSolver extends BaseSolver {
1224
1229
  inputProblem: this.inputProblem,
1225
1230
  netId: label.netId,
1226
1231
  pinIds: label.pinIds,
1232
+ isPortOnlyLabel: this.isPortOnlyLabel(label),
1227
1233
  }),
1228
1234
  netLabelHeight: this.getNetLabelHeight(label),
1229
1235
  })
@@ -1309,6 +1315,7 @@ export class AvailableNetOrientationSolver extends BaseSolver {
1309
1315
  inputProblem: this.inputProblem,
1310
1316
  netId: label.netId,
1311
1317
  pinIds: label.pinIds,
1318
+ isPortOnlyLabel: this.isPortOnlyLabel(label),
1312
1319
  }),
1313
1320
  netLabelHeight: this.getNetLabelHeight(label),
1314
1321
  })
@@ -286,6 +286,7 @@ export class NetLabelPlacementSolver extends BaseSolver {
286
286
  inputProblem: this.inputProblem,
287
287
  netId: group.netId,
288
288
  pinIds,
289
+ isPortOnlyLabel: group.portOnlyPinId !== undefined,
289
290
  })
290
291
  }
291
292
 
@@ -34,6 +34,9 @@ interface HorizontalSegment {
34
34
  const MAX_ALIGNED_LOAD_PIN_OFFSET = 0.2
35
35
  // Limit label-boundary alignment to small corrections that cannot create spikes.
36
36
  const MAX_SAME_NET_LABEL_BOUNDARY_RAIL_OFFSET = 0.2
37
+ // A shared vertical pin can anchor an existing rail when the rail is only a
38
+ // symbol-stem correction away from the pin itself.
39
+ const MAX_SHARED_PIN_RAIL_OFFSET = 0.05
37
40
 
38
41
  const getSharedPin = ({
39
42
  donorTrace,
@@ -96,6 +99,48 @@ const railIsOnFacingSide = ({
96
99
  return false
97
100
  }
98
101
 
102
+ const railIsOnSharedPinFacingSide = ({
103
+ railY,
104
+ pin,
105
+ }: {
106
+ railY: number
107
+ pin: InputPin
108
+ }) => {
109
+ if (pin._facingDirection === "y+") return railY > pin.y
110
+ if (pin._facingDirection === "y-") return railY < pin.y
111
+ return false
112
+ }
113
+
114
+ const getHorizontalPinApproachPoint = ({
115
+ branchTrace,
116
+ sharedPin,
117
+ otherPin,
118
+ }: {
119
+ branchTrace: SolvedTracePath
120
+ sharedPin: InputPin
121
+ otherPin: InputPin
122
+ }): Point | null => {
123
+ if (
124
+ otherPin._facingDirection !== "x-" &&
125
+ otherPin._facingDirection !== "x+"
126
+ ) {
127
+ return null
128
+ }
129
+
130
+ const sharedToOtherPath =
131
+ branchTrace.pins[0].pinId === sharedPin.pinId
132
+ ? branchTrace.tracePath
133
+ : [...branchTrace.tracePath].reverse()
134
+ const approachPoint = sharedToOtherPath.at(-2)
135
+ if (!approachPoint || !nearlyEqual(approachPoint.y, otherPin.y)) return null
136
+
137
+ const approachesFromFacingSide =
138
+ otherPin._facingDirection === "x-"
139
+ ? approachPoint.x < otherPin.x
140
+ : approachPoint.x > otherPin.x
141
+ return approachesFromFacingSide ? approachPoint : null
142
+ }
143
+
99
144
  const getAttachedLabelIndexes = (
100
145
  trace: SolvedTracePath,
101
146
  netLabelPlacements: NetLabelPlacement[],
@@ -165,7 +210,17 @@ const getAlignedBranchPath = ({
165
210
  if (branchRail && nearlyEqual(branchRail.start.y, donorRail.start.y)) {
166
211
  return null
167
212
  }
168
- if (!railIsOnFacingSide({ railY: donorRail.start.y, pin: otherPin })) {
213
+ const railFacesOtherPin = railIsOnFacingSide({
214
+ railY: donorRail.start.y,
215
+ pin: otherPin,
216
+ })
217
+ const railFacesSharedPin =
218
+ railIsOnSharedPinFacingSide({
219
+ railY: donorRail.start.y,
220
+ pin: sharedPin,
221
+ }) &&
222
+ Math.abs(donorRail.start.y - sharedPin.y) <= MAX_SHARED_PIN_RAIL_OFFSET
223
+ if (!railFacesOtherPin && !railFacesSharedPin) {
169
224
  return null
170
225
  }
171
226
 
@@ -175,13 +230,31 @@ const getAlignedBranchPath = ({
175
230
  (donorOtherPin.x > junction.x && otherPin.x < junction.x)
176
231
  if (!extendsDonorRail) return null
177
232
 
178
- const sharedToOther = simplifyPath([
179
- { x: sharedPin.x, y: sharedPin.y },
180
- { x: junction.x, y: sharedPin.y },
181
- { x: junction.x, y: junction.y },
182
- { x: otherPin.x, y: junction.y },
183
- { x: otherPin.x, y: otherPin.y },
184
- ])
233
+ let sharedToOther: Point[]
234
+ if (!railFacesOtherPin && railFacesSharedPin) {
235
+ const approachPoint = getHorizontalPinApproachPoint({
236
+ branchTrace,
237
+ sharedPin,
238
+ otherPin,
239
+ })
240
+ if (!approachPoint) return null
241
+ sharedToOther = simplifyPath([
242
+ { x: sharedPin.x, y: sharedPin.y },
243
+ { x: junction.x, y: sharedPin.y },
244
+ { x: junction.x, y: junction.y },
245
+ { x: approachPoint.x, y: junction.y },
246
+ { x: approachPoint.x, y: otherPin.y },
247
+ { x: otherPin.x, y: otherPin.y },
248
+ ])
249
+ } else {
250
+ sharedToOther = simplifyPath([
251
+ { x: sharedPin.x, y: sharedPin.y },
252
+ { x: junction.x, y: sharedPin.y },
253
+ { x: junction.x, y: junction.y },
254
+ { x: otherPin.x, y: junction.y },
255
+ { x: otherPin.x, y: otherPin.y },
256
+ ])
257
+ }
185
258
 
186
259
  if (branchTrace.pins[0].pinId === sharedPin.pinId) return sharedToOther
187
260
  return [...sharedToOther].reverse()
@@ -206,7 +206,7 @@ export class SchematicTraceSingleLineSolver2 extends BaseSolver {
206
206
  inputProblem: this.inputProblem,
207
207
  netId,
208
208
  pinIds: this.pins.map((pin) => pin.pinId),
209
- includeFallbackNetLabelWidth: false,
209
+ isPortOnlyLabel: false,
210
210
  })
211
211
  const netLabelHeight = this.getNetLabelHeightForConnectionPair(netId)
212
212
  const padding: Required<RectPadding> = {
@@ -315,6 +315,7 @@ const getNetLabelWidth = (
315
315
  inputProblem,
316
316
  netId: label.netId,
317
317
  pinIds: label.pinIds,
318
+ isPortOnlyLabel: label.mspConnectionPairIds.length === 0,
318
319
  })
319
320
  if (configuredWidth !== undefined) return configuredWidth
320
321
 
@@ -60,11 +60,11 @@ export interface InputDirectConnection {
60
60
  netLabelWidth?: number
61
61
 
62
62
  /**
63
- * Width of the conventional anchored label to use only when an inline label
64
- * cannot be placed. Unlike `netLabelWidth`, this does not affect whether or
65
- * how the point-to-point connection is routed.
63
+ * Width of the conventional label anchored to a trace endpoint. Unlike
64
+ * `netLabelWidth`, this does not affect whether or how the point-to-point
65
+ * connection is routed.
66
66
  */
67
- fallbackNetLabelWidth?: number
67
+ anchoredNetLabelWidth?: number
68
68
 
69
69
  /**
70
70
  * When true, this point-to-point connection may be labeled with an "inline
@@ -106,7 +106,7 @@ export interface InputNetConnection {
106
106
  */
107
107
  netLabelText?: string
108
108
  netLabelWidth?: number
109
- fallbackNetLabelWidth?: number
109
+ anchoredNetLabelWidth?: number
110
110
  netLabelHeight?: number
111
111
 
112
112
  /**
@@ -10,29 +10,28 @@ type ConnectionWithLabelWidth = InputDirectConnection | InputNetConnection
10
10
 
11
11
  const getConfiguredWidth = (
12
12
  connections: Array<ConnectionWithLabelWidth | undefined>,
13
- includeFallbackNetLabelWidth: boolean,
13
+ isPortOnlyLabel: boolean,
14
14
  ) => {
15
- const explicitWidth = connections.find(
15
+ const width = connections.find(
16
16
  (connection) => connection?.netLabelWidth !== undefined,
17
17
  )?.netLabelWidth
18
- if (explicitWidth !== undefined) return explicitWidth
19
- if (!includeFallbackNetLabelWidth) return undefined
18
+ if (width !== undefined || !isPortOnlyLabel) return width
20
19
 
21
20
  return connections.find(
22
- (connection) => connection?.fallbackNetLabelWidth !== undefined,
23
- )?.fallbackNetLabelWidth
21
+ (connection) => connection?.anchoredNetLabelWidth !== undefined,
22
+ )?.anchoredNetLabelWidth
24
23
  }
25
24
 
26
25
  export const getNetLabelWidthForConnection = ({
27
26
  inputProblem,
28
27
  netId,
29
28
  pinIds,
30
- includeFallbackNetLabelWidth = true,
29
+ isPortOnlyLabel,
31
30
  }: {
32
31
  inputProblem: InputProblem
33
32
  netId?: NetId
34
33
  pinIds: readonly PinId[]
35
- includeFallbackNetLabelWidth?: boolean
34
+ isPortOnlyLabel: boolean
36
35
  }): number | undefined => {
37
36
  if (netId) {
38
37
  const widthByNetId = getConfiguredWidth(
@@ -44,7 +43,7 @@ export const getNetLabelWidthForConnection = ({
44
43
  (connection) => connection.netId === netId,
45
44
  ),
46
45
  ],
47
- includeFallbackNetLabelWidth,
46
+ isPortOnlyLabel,
48
47
  )
49
48
  if (widthByNetId !== undefined) return widthByNetId
50
49
  }
@@ -58,6 +57,6 @@ export const getNetLabelWidthForConnection = ({
58
57
  connection.pinIds.some((pinId) => pinIds.includes(pinId)),
59
58
  ),
60
59
  ],
61
- includeFallbackNetLabelWidth,
60
+ isPortOnlyLabel,
62
61
  )
63
62
  }
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "url": "https://github.com/tscircuit/schematic-trace-solver.git"
6
6
  },
7
7
  "main": "dist/index.js",
8
- "version": "0.0.152",
8
+ "version": "0.0.154",
9
9
  "type": "module",
10
10
  "scripts": {
11
11
  "start": "cosmos",
@@ -0,0 +1,4 @@
1
+ import { PipelineDebugger } from "site/components/PipelineDebugger"
2
+ import inputProblem from "../../tests/bug-reports/bug-report-20260825T103621Z/bug-report-20260825T103621Z.json"
3
+
4
+ export default () => <PipelineDebugger inputProblem={inputProblem as any} />