@tscircuit/schematic-trace-solver 0.0.143 → 0.0.145

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
@@ -96,7 +96,9 @@ interface InputDirectConnection {
96
96
  *
97
97
  * Only set this for connections whose net name is worth showing on the wire -
98
98
  * the solver trusts the caller (e.g. @tscircuit/core) to make that decision.
99
- * An inline label is only emitted when the connection actually got routed.
99
+ * When the connection is routed, the label is placed along the trace. If
100
+ * routing is intentionally skipped, both endpoint labels may instead become
101
+ * outward inline stubs.
100
102
  */
101
103
  allowInlineNetLabel?: boolean;
102
104
  /**
@@ -116,9 +118,10 @@ interface InputNetConnection {
116
118
  netLabelWidth?: number;
117
119
  netLabelHeight?: number;
118
120
  /**
119
- * When true, a named single-pin net may be drawn as a short outward trace
120
- * stub with its net name placed inline. Multi-pin net connections retain the
121
- * regular anchored-label behavior.
121
+ * When true, a named one- or two-pin net may use inline labels. A single-pin
122
+ * net gets an outward stub. A routed two-pin net gets one label along its
123
+ * trace; when that route is intentionally skipped, both endpoints get
124
+ * outward stubs. Nets with more than two pins retain anchored labels.
122
125
  */
123
126
  allowInlineNetLabel?: boolean;
124
127
  /** Extent of the inline text along the generated trace stub. */
@@ -143,6 +146,8 @@ type MspConnectionPair = {
143
146
  dcConnNetId: string;
144
147
  globalConnNetId: string;
145
148
  userNetId?: string;
149
+ /** The trace replaces fallback labels that could not fit between its pins. */
150
+ suppressNetLabel?: boolean;
146
151
  pins: [InputPin & {
147
152
  chipId: string;
148
153
  }, InputPin & {
@@ -1200,8 +1205,9 @@ interface InlineNetLabelPlacement {
1200
1205
  mspPairId?: string;
1201
1206
  pinIds: PinId[];
1202
1207
  /**
1203
- * A generated single-ended trace stub. Present only for an eligible
1204
- * single-pin net connection; routed point-to-point traces omit it.
1208
+ * A generated single-ended trace stub. Present for a single-pin net or for
1209
+ * one endpoint of an unrouted two-pin net; routed point-to-point traces omit
1210
+ * it.
1205
1211
  */
1206
1212
  stubTracePath?: [Point, Point];
1207
1213
  /** Axis the text runs along: "x" reads left-to-right, "y" reads bottom-to-top */
@@ -1226,9 +1232,11 @@ interface InlineNetLabelSolverInput {
1226
1232
  traces: SolvedTracePath[];
1227
1233
  netLabelPlacements: NetLabelPlacement[];
1228
1234
  }
1235
+ type InlineEligibleConnection = InputDirectConnection | InputNetConnection;
1229
1236
  /**
1230
1237
  * Places "inline net labels" - net names drawn alongside the trace they belong
1231
- * to - for direct connections that opted in via `allowInlineNetLabel`.
1238
+ * to - for one- or two-pin connections that opted in via
1239
+ * `allowInlineNetLabel`.
1232
1240
  *
1233
1241
  * Any regular (anchored) net label placement for the same net is dropped, so a
1234
1242
  * net is never labeled twice.
@@ -1238,22 +1246,20 @@ declare class InlineNetLabelSolver extends BaseSolver {
1238
1246
  traces: SolvedTracePath[];
1239
1247
  inputNetLabelPlacements: NetLabelPlacement[];
1240
1248
  inlineNetLabelPlacements: InlineNetLabelPlacement[];
1241
- /** Direct connections that opted in, still waiting to be processed */
1242
- queuedDirectConnections: InputDirectConnection[];
1243
- /** Single-pin net connections that opted in, still waiting to be processed */
1244
- queuedPortOnlyNetConnections: InputNetConnection[];
1249
+ /** Eligible one- or two-pin connections still waiting to be processed. */
1250
+ queuedConnections: InlineEligibleConnection[];
1245
1251
  private tracesByPinPairKey;
1246
1252
  private hasAlignedPortOnlyStubs;
1247
1253
  constructor(input: InlineNetLabelSolverInput);
1248
1254
  getConstructorParams(): [InlineNetLabelSolverInput];
1249
1255
  _step(): void;
1250
1256
  /**
1251
- * Converts a conventional port-only anchored placement into an inline label
1252
- * on a generated outward stub. The stub follows the pin's true facing
1253
- * direction; an anchored label may finish in another direction after an
1254
- * elbow, which is not the direction a terminal stub should leave the pin.
1257
+ * Converts one conventional endpoint placement into an inline label on a
1258
+ * generated outward stub. The stub follows the pin's true facing direction;
1259
+ * an anchored label may finish in another direction after an elbow, which is
1260
+ * not the direction a terminal stub should leave the pin.
1255
1261
  */
1256
- private computePortOnlyInlinePlacement;
1262
+ private computeTerminalInlinePlacement;
1257
1263
  private computeInlinePlacement;
1258
1264
  /**
1259
1265
  * Places the label over the whole route when the route is straight except
package/dist/index.js CHANGED
@@ -420,8 +420,48 @@ function getOrthogonalMinimumSpanningTree(pins, opts = {}) {
420
420
  return edges;
421
421
  }
422
422
 
423
+ // lib/solvers/NetLabelPlacementSolver/SingleNetLabelPlacementSolver/geometry.ts
424
+ var NET_LABEL_HORIZONTAL_WIDTH = 0.45;
425
+ var NET_LABEL_HORIZONTAL_HEIGHT = 0.2;
426
+ function getDimsForOrientation(params) {
427
+ const { orientation, netLabelWidth, netLabelHeight } = params;
428
+ const horizWidth = typeof netLabelWidth === "number" ? netLabelWidth : NET_LABEL_HORIZONTAL_WIDTH;
429
+ const horizHeight = typeof netLabelHeight === "number" ? netLabelHeight : NET_LABEL_HORIZONTAL_HEIGHT;
430
+ if (orientation === "y+" || orientation === "y-") {
431
+ return {
432
+ // Rotated: horizontal length = netLabelHeight, vertical length = netLabelWidth
433
+ width: horizHeight,
434
+ height: horizWidth
435
+ };
436
+ }
437
+ return {
438
+ width: horizWidth,
439
+ height: horizHeight
440
+ };
441
+ }
442
+ function getCenterFromAnchor(anchor, orientation, width, height) {
443
+ switch (orientation) {
444
+ case "x+":
445
+ return { x: anchor.x + width / 2, y: anchor.y };
446
+ case "x-":
447
+ return { x: anchor.x - width / 2, y: anchor.y };
448
+ case "y+":
449
+ return { x: anchor.x, y: anchor.y + height / 2 };
450
+ case "y-":
451
+ return { x: anchor.x, y: anchor.y - height / 2 };
452
+ }
453
+ }
454
+ function getRectBounds(center, w, h) {
455
+ return {
456
+ minX: center.x - w / 2,
457
+ minY: center.y - h / 2,
458
+ maxX: center.x + w / 2,
459
+ maxY: center.y + h / 2
460
+ };
461
+ }
462
+
423
463
  // lib/solvers/MspConnectionPairSolver/isLabeledPeripheralConnection.ts
424
- var isLabeledPeripheralConnection = ({
464
+ var getLabeledConnectionRouteReason = ({
425
465
  inputProblem,
426
466
  chipMap,
427
467
  pins
@@ -430,12 +470,10 @@ var isLabeledPeripheralConnection = ({
430
470
  const directConnection = inputProblem.directConnections.find(
431
471
  (connection) => connection.pinIds.includes(firstPin.pinId) && connection.pinIds.includes(secondPin.pinId)
432
472
  );
433
- if (directConnection?.netLabelWidth === void 0) return false;
473
+ if (directConnection?.netLabelWidth === void 0) return null;
434
474
  const firstChip = chipMap[firstPin.chipId];
435
475
  const secondChip = chipMap[secondPin.chipId];
436
- if (!firstChip || !secondChip) return false;
437
- const hasSinglePinPeripheral = firstChip.pins.length === 1 || secondChip.pins.length === 1;
438
- if (!hasSinglePinPeripheral) return false;
476
+ if (!firstChip || !secondChip) return null;
439
477
  let firstFacingDirection = firstPin._facingDirection;
440
478
  if (!firstFacingDirection) {
441
479
  firstFacingDirection = getPinDirection(firstPin, firstChip);
@@ -444,8 +482,20 @@ var isLabeledPeripheralConnection = ({
444
482
  if (!secondFacingDirection) {
445
483
  secondFacingDirection = getPinDirection(secondPin, secondChip);
446
484
  }
447
- return firstFacingDirection === "x-" && secondFacingDirection === "x+" || firstFacingDirection === "x+" && secondFacingDirection === "x-";
448
- };
485
+ const hasOpposingHorizontalDirections = firstFacingDirection === "x-" && secondFacingDirection === "x+" || firstFacingDirection === "x+" && secondFacingDirection === "x-";
486
+ if (!hasOpposingHorizontalDirections) return null;
487
+ const hasSinglePinPeripheral = firstChip.pins.length === 1 || secondChip.pins.length === 1;
488
+ if (hasSinglePinPeripheral) return "single-pin-peripheral";
489
+ const sharedSectionId = firstChip.sectionId && firstChip.sectionId === secondChip.sectionId ? firstChip.sectionId : null;
490
+ if (!sharedSectionId) return null;
491
+ const firstIsLeft = firstPin.x <= secondPin.x;
492
+ const directionsPointTowardEachOther = firstIsLeft ? firstFacingDirection === "x+" && secondFacingDirection === "x-" : firstFacingDirection === "x-" && secondFacingDirection === "x+";
493
+ const labelsOverlapAlongX = Math.abs(firstPin.x - secondPin.x) < directConnection.netLabelWidth * 2;
494
+ const labelsOverlapAlongY = Math.abs(firstPin.y - secondPin.y) < NET_LABEL_HORIZONTAL_HEIGHT;
495
+ const fallbackLabelsOverlap = directionsPointTowardEachOther && labelsOverlapAlongX && labelsOverlapAlongY;
496
+ return fallbackLabelsOverlap ? "overlapping-fallback-labels" : null;
497
+ };
498
+ var isLabeledPeripheralConnection = (params) => getLabeledConnectionRouteReason(params) !== null;
449
499
 
450
500
  // lib/solvers/MspConnectionPairSolver/MspConnectionPairSolver.ts
451
501
  var DEFAULT_MAX_MSP_PAIR_DISTANCE = 1;
@@ -520,12 +570,12 @@ var MspConnectionPairSolver = class extends BaseSolver {
520
570
  if (this.directConnectionPinPairKeys.has(pinPairKey)) {
521
571
  pairDistance = distance(p1, p2);
522
572
  }
523
- const isLabeledPeripheral = isLabeledPeripheralConnection({
573
+ const labeledConnectionRouteReason = getLabeledConnectionRouteReason({
524
574
  inputProblem: this.inputProblem,
525
575
  chipMap: this.chipMap,
526
576
  pins: [p1, p2]
527
577
  });
528
- if (pairDistance > this.maxMspPairDistance && !isLabeledPeripheral) {
578
+ if (pairDistance > this.maxMspPairDistance && !labeledConnectionRouteReason) {
529
579
  return;
530
580
  }
531
581
  if (arePinsInDifferentSchematicSections(this.inputProblem, p1, p2)) {
@@ -543,11 +593,13 @@ var MspConnectionPairSolver = class extends BaseSolver {
543
593
  }
544
594
  const globalConnNetId = this.globalConnMap.getNetConnectedToId(pin1);
545
595
  const userNetId = this.userNetIdByPinId[pin1] ?? this.userNetIdByPinId[pin2];
596
+ const suppressNetLabel = pairDistance > this.maxMspPairDistance && labeledConnectionRouteReason === "overlapping-fallback-labels";
546
597
  this.mspConnectionPairs.push({
547
598
  mspPairId: `${pin1}-${pin2}`,
548
599
  dcConnNetId: dcNetId,
549
600
  globalConnNetId,
550
601
  userNetId,
602
+ suppressNetLabel,
551
603
  pins: [p1, p2]
552
604
  });
553
605
  return;
@@ -626,46 +678,6 @@ import "graphics-debug";
626
678
  // lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver2/SchematicTraceSingleLineSolver2.ts
627
679
  import { calculateElbow as calculateElbow2 } from "calculate-elbow";
628
680
 
629
- // lib/solvers/NetLabelPlacementSolver/SingleNetLabelPlacementSolver/geometry.ts
630
- var NET_LABEL_HORIZONTAL_WIDTH = 0.45;
631
- var NET_LABEL_HORIZONTAL_HEIGHT = 0.2;
632
- function getDimsForOrientation(params) {
633
- const { orientation, netLabelWidth, netLabelHeight } = params;
634
- const horizWidth = typeof netLabelWidth === "number" ? netLabelWidth : NET_LABEL_HORIZONTAL_WIDTH;
635
- const horizHeight = typeof netLabelHeight === "number" ? netLabelHeight : NET_LABEL_HORIZONTAL_HEIGHT;
636
- if (orientation === "y+" || orientation === "y-") {
637
- return {
638
- // Rotated: horizontal length = netLabelHeight, vertical length = netLabelWidth
639
- width: horizHeight,
640
- height: horizWidth
641
- };
642
- }
643
- return {
644
- width: horizWidth,
645
- height: horizHeight
646
- };
647
- }
648
- function getCenterFromAnchor(anchor, orientation, width, height) {
649
- switch (orientation) {
650
- case "x+":
651
- return { x: anchor.x + width / 2, y: anchor.y };
652
- case "x-":
653
- return { x: anchor.x - width / 2, y: anchor.y };
654
- case "y+":
655
- return { x: anchor.x, y: anchor.y + height / 2 };
656
- case "y-":
657
- return { x: anchor.x, y: anchor.y - height / 2 };
658
- }
659
- }
660
- function getRectBounds(center, w, h) {
661
- return {
662
- minX: center.x - w / 2,
663
- minY: center.y - h / 2,
664
- maxX: center.x + w / 2,
665
- maxY: center.y + h / 2
666
- };
667
- }
668
-
669
681
  // lib/utils/textBoxBounds.ts
670
682
  function getTextBoxBounds(textBox, padding = {}) {
671
683
  return {
@@ -3148,6 +3160,7 @@ var NetLabelPlacementSolver = class extends BaseSolver {
3148
3160
  (t) => component.has(t.pins[0].pinId) && component.has(t.pins[1].pinId)
3149
3161
  );
3150
3162
  if (compTraces.length > 0) {
3163
+ if (compTraces.some((trace) => trace.suppressNetLabel)) continue;
3151
3164
  const lengthOf = (path) => {
3152
3165
  let sum = 0;
3153
3166
  const pts = path.tracePath;
@@ -12786,10 +12799,8 @@ var InlineNetLabelSolver = class extends BaseSolver {
12786
12799
  traces;
12787
12800
  inputNetLabelPlacements;
12788
12801
  inlineNetLabelPlacements = [];
12789
- /** Direct connections that opted in, still waiting to be processed */
12790
- queuedDirectConnections;
12791
- /** Single-pin net connections that opted in, still waiting to be processed */
12792
- queuedPortOnlyNetConnections;
12802
+ /** Eligible one- or two-pin connections still waiting to be processed. */
12803
+ queuedConnections;
12793
12804
  tracesByPinPairKey;
12794
12805
  hasAlignedPortOnlyStubs = false;
12795
12806
  constructor(input) {
@@ -12797,12 +12808,14 @@ var InlineNetLabelSolver = class extends BaseSolver {
12797
12808
  this.inputProblem = input.inputProblem;
12798
12809
  this.traces = input.traces;
12799
12810
  this.inputNetLabelPlacements = input.netLabelPlacements;
12800
- this.queuedDirectConnections = this.inputProblem.directConnections.filter(
12801
- (dc) => dc.allowInlineNetLabel && dc.netId
12802
- );
12803
- this.queuedPortOnlyNetConnections = this.inputProblem.netConnections.filter(
12804
- (nc) => nc.allowInlineNetLabel && nc.pinIds.length === 1 && nc.netId
12805
- );
12811
+ this.queuedConnections = [
12812
+ ...this.inputProblem.directConnections.filter(
12813
+ (connection) => connection.allowInlineNetLabel && connection.netId
12814
+ ),
12815
+ ...this.inputProblem.netConnections.filter(
12816
+ (connection) => connection.allowInlineNetLabel && connection.pinIds.length >= 1 && connection.pinIds.length <= 2 && connection.netId
12817
+ )
12818
+ ];
12806
12819
  this.tracesByPinPairKey = /* @__PURE__ */ new Map();
12807
12820
  for (const trace of this.traces) {
12808
12821
  const key = getPinPairKey2(trace.pins.map((p) => p.pinId));
@@ -12824,21 +12837,19 @@ var InlineNetLabelSolver = class extends BaseSolver {
12824
12837
  ];
12825
12838
  }
12826
12839
  _step() {
12827
- const directConnection = this.queuedDirectConnections.shift();
12828
- if (directConnection) {
12829
- const placement = this.computeInlinePlacement(directConnection);
12830
- if (placement) {
12831
- this.inlineNetLabelPlacements.push(placement);
12832
- }
12833
- return;
12834
- }
12835
- const portOnlyNetConnection = this.queuedPortOnlyNetConnections.shift();
12836
- if (portOnlyNetConnection) {
12837
- const placement = this.computePortOnlyInlinePlacement(
12838
- portOnlyNetConnection
12839
- );
12840
- if (placement) {
12841
- this.inlineNetLabelPlacements.push(placement);
12840
+ const connection = this.queuedConnections.shift();
12841
+ if (connection) {
12842
+ const routedTraces = connection.pinIds.length === 2 ? this.tracesByPinPairKey.get(getPinPairKey2(connection.pinIds)) ?? [] : [];
12843
+ if (routedTraces.length > 0) {
12844
+ const placement = this.computeInlinePlacement(connection);
12845
+ if (placement) this.inlineNetLabelPlacements.push(placement);
12846
+ } else {
12847
+ const terminalPlacements = connection.pinIds.map(
12848
+ (pinId) => this.computeTerminalInlinePlacement(connection, pinId)
12849
+ );
12850
+ if (terminalPlacements.every((placement) => placement !== null)) {
12851
+ this.inlineNetLabelPlacements.push(...terminalPlacements);
12852
+ }
12842
12853
  }
12843
12854
  return;
12844
12855
  }
@@ -12856,24 +12867,23 @@ var InlineNetLabelSolver = class extends BaseSolver {
12856
12867
  this.stats.inlineNetLabelCount = this.inlineNetLabelPlacements.length;
12857
12868
  }
12858
12869
  /**
12859
- * Converts a conventional port-only anchored placement into an inline label
12860
- * on a generated outward stub. The stub follows the pin's true facing
12861
- * direction; an anchored label may finish in another direction after an
12862
- * elbow, which is not the direction a terminal stub should leave the pin.
12870
+ * Converts one conventional endpoint placement into an inline label on a
12871
+ * generated outward stub. The stub follows the pin's true facing direction;
12872
+ * an anchored label may finish in another direction after an elbow, which is
12873
+ * not the direction a terminal stub should leave the pin.
12863
12874
  */
12864
- computePortOnlyInlinePlacement(netConnection) {
12865
- const [pinId] = netConnection.pinIds;
12866
- if (!pinId) return null;
12875
+ computeTerminalInlinePlacement(connection, pinId) {
12876
+ if (!connection.netId) return null;
12867
12877
  const anchoredPlacement = this.inputNetLabelPlacements.find(
12868
- (placement) => placement.netId === netConnection.netId && placement.pinIds.length === 1 && placement.pinIds[0] === pinId
12878
+ (placement) => placement.netId === connection.netId && placement.pinIds.length === 1 && placement.pinIds[0] === pinId
12869
12879
  );
12870
12880
  if (!anchoredPlacement) return null;
12871
12881
  const inputChip = this.inputProblem.chips.find(
12872
12882
  (chip) => chip.pins.some((pin) => pin.pinId === pinId)
12873
12883
  );
12874
12884
  const inputPin = inputChip?.pins.find((pin) => pin.pinId === pinId);
12875
- const height = netConnection.inlineNetLabelHeight ?? DEFAULT_INLINE_NET_LABEL_HEIGHT;
12876
- const width = netConnection.inlineNetLabelWidth ?? netConnection.netLabelWidth ?? estimateInlineNetLabelWidth(netConnection.netId, height);
12885
+ const height = connection.inlineNetLabelHeight ?? DEFAULT_INLINE_NET_LABEL_HEIGHT;
12886
+ const width = connection.inlineNetLabelWidth ?? connection.netLabelWidth ?? estimateInlineNetLabelWidth(connection.netId, height);
12877
12887
  const stubLength = Math.max(width + 0.2, 0.6);
12878
12888
  const start = inputPin ? { x: inputPin.x, y: inputPin.y } : anchoredPlacement.anchorPoint;
12879
12889
  const direction = inputPin && inputChip ? inputPin._facingDirection ?? getPinDirection(inputPin, inputChip) : anchoredPlacement.orientation;
@@ -12906,7 +12916,7 @@ var InlineNetLabelSolver = class extends BaseSolver {
12906
12916
  }
12907
12917
  return {
12908
12918
  globalConnNetId: anchoredPlacement.globalConnNetId,
12909
- netId: netConnection.netId,
12919
+ netId: connection.netId,
12910
12920
  pinIds: [pinId],
12911
12921
  stubTracePath: [start, end],
12912
12922
  axis,
@@ -12917,14 +12927,14 @@ var InlineNetLabelSolver = class extends BaseSolver {
12917
12927
  side
12918
12928
  };
12919
12929
  }
12920
- computeInlinePlacement(directConnection) {
12921
- const traces = this.tracesByPinPairKey.get(getPinPairKey2(directConnection.pinIds)) ?? [];
12930
+ computeInlinePlacement(connection) {
12931
+ const traces = this.tracesByPinPairKey.get(getPinPairKey2(connection.pinIds)) ?? [];
12922
12932
  if (traces.length === 0) return null;
12923
12933
  const trace = traces[0];
12924
12934
  const segments = getAxisAlignedSegments(trace.tracePath);
12925
12935
  if (segments.length === 0) return null;
12926
- const height = directConnection.inlineNetLabelHeight ?? DEFAULT_INLINE_NET_LABEL_HEIGHT;
12927
- const width = directConnection.inlineNetLabelWidth ?? directConnection.netLabelWidth ?? estimateInlineNetLabelWidth(directConnection.netId, height);
12936
+ const height = connection.inlineNetLabelHeight ?? DEFAULT_INLINE_NET_LABEL_HEIGHT;
12937
+ const width = connection.inlineNetLabelWidth ?? connection.netLabelWidth ?? estimateInlineNetLabelWidth(connection.netId, height);
12928
12938
  const offset = height / 2 + INLINE_NET_LABEL_TRACE_MARGIN;
12929
12939
  const usableSegments = segments.filter((segment) => segment.length >= width).sort((a, b) => b.length - a.length);
12930
12940
  for (const segment of usableSegments) {
@@ -12952,9 +12962,9 @@ var InlineNetLabelSolver = class extends BaseSolver {
12952
12962
  continue;
12953
12963
  return {
12954
12964
  globalConnNetId: trace.globalConnNetId,
12955
- netId: directConnection.netId,
12965
+ netId: connection.netId,
12956
12966
  mspPairId: trace.mspPairId,
12957
- pinIds: [...directConnection.pinIds],
12967
+ pinIds: [...connection.pinIds],
12958
12968
  axis: segment.axis,
12959
12969
  anchorPoint,
12960
12970
  center,
@@ -12967,7 +12977,7 @@ var InlineNetLabelSolver = class extends BaseSolver {
12967
12977
  }
12968
12978
  const spanPlacement = this.computeSpanPlacement({
12969
12979
  trace,
12970
- directConnection,
12980
+ connection,
12971
12981
  width,
12972
12982
  height,
12973
12983
  offset
@@ -12983,7 +12993,7 @@ var InlineNetLabelSolver = class extends BaseSolver {
12983
12993
  */
12984
12994
  computeSpanPlacement({
12985
12995
  trace,
12986
- directConnection,
12996
+ connection,
12987
12997
  width,
12988
12998
  height,
12989
12999
  offset
@@ -13042,9 +13052,9 @@ var InlineNetLabelSolver = class extends BaseSolver {
13042
13052
  const anchorPoint = axis === "x" ? { x: along, y: side === "y+" ? maxY : minY } : { x: side === "x-" ? minX : maxX, y: along };
13043
13053
  return {
13044
13054
  globalConnNetId: trace.globalConnNetId,
13045
- netId: directConnection.netId,
13055
+ netId: connection.netId,
13046
13056
  mspPairId: trace.mspPairId,
13047
- pinIds: [...directConnection.pinIds],
13057
+ pinIds: [...connection.pinIds],
13048
13058
  axis,
13049
13059
  anchorPoint,
13050
13060
  center,