@tscircuit/schematic-trace-solver 0.0.149 → 0.0.151

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 (162) hide show
  1. package/.agents/skills/schematic-trace-visualization/SKILL.md +7 -2
  2. package/README.md +6 -4
  3. package/dist/index.d.ts +64 -3
  4. package/dist/index.js +383 -66
  5. package/lib/solvers/InlineNetLabelSolver/InlineNetLabelSolver.ts +123 -84
  6. package/lib/solvers/NetLabelPlacementSolver/NetLabelPlacementSolver.ts +17 -1
  7. package/lib/solvers/NetLabelPlacementSolver/SingleNetLabelPlacementSolver/SingleNetLabelPlacementSolver.ts +2 -0
  8. package/lib/solvers/NetLabelPlacementSolver/SingleNetLabelPlacementSolver/solvePortOnlyPin.ts +2 -0
  9. package/lib/solvers/NetLabelToTraceSolver/NetLabelToTraceSolver.ts +338 -0
  10. package/lib/solvers/NetLabelTraceRecovery/getTraceRecoveryConnectivityMaps.ts +33 -0
  11. package/lib/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver.ts +15 -0
  12. package/lib/types/InputProblem.ts +27 -1
  13. package/package.json +8 -1
  14. package/tests/bug-reports/bug-report-20260706T213649Z/__snapshots__/bug-report-20260706T213649Z.snap.svg +751 -5
  15. package/tests/bug-reports/bug-report-20260706T220324Z/__snapshots__/bug-report-20260706T220324Z.snap.svg +660 -5
  16. package/tests/bug-reports/bug-report-20260707T020342Z/__snapshots__/bug-report-20260707T020342Z.snap.svg +44 -5
  17. package/tests/bug-reports/bug-report-20260707T092615Z/__snapshots__/bug-report-20260707T092615Z.snap.svg +394 -5
  18. package/tests/bug-reports/bug-report-20260707T134549Z/__snapshots__/bug-report-20260707T134549Z.snap.svg +170 -5
  19. package/tests/bug-reports/bug-report-20260707T134722Z/__snapshots__/bug-report-20260707T134722Z.snap.svg +79 -5
  20. package/tests/bug-reports/bug-report-20260707T140410Z/__snapshots__/bug-report-20260707T140410Z.snap.svg +219 -5
  21. package/tests/bug-reports/bug-report-20260707T141025Z/__snapshots__/bug-report-20260707T141025Z.snap.svg +65 -5
  22. package/tests/bug-reports/bug-report-20260707T141421Z/__snapshots__/bug-report-20260707T141421Z.snap.svg +142 -5
  23. package/tests/bug-reports/bug-report-20260707T230831Z/__snapshots__/bug-report-20260707T230831Z.snap.svg +100 -5
  24. package/tests/bug-reports/bug-report-20260708T053736Z/__snapshots__/bug-report-20260708T053736Z.snap.svg +23 -5
  25. package/tests/bug-reports/bug-report-20260708T055430Z/__snapshots__/bug-report-20260708T055430Z.snap.svg +58 -5
  26. package/tests/bug-reports/bug-report-20260708T095725Z/__snapshots__/bug-report-20260708T095725Z.snap.svg +86 -5
  27. package/tests/bug-reports/bug-report-20260716T144856Z/__snapshots__/bug-report-20260716T144856Z.snap.svg +226 -5
  28. package/tests/bug-reports/bug-report-20260717T022934Z/__snapshots__/bug-report-20260717T022934Z.snap.svg +191 -5
  29. package/tests/bug-reports/bug-report-20260717T031704Z/__snapshots__/bug-report-20260717T031704Z.snap.svg +30 -5
  30. package/tests/bug-reports/bug-report-20260717T042845Z/__snapshots__/bug-report-20260717T042845Z.snap.svg +37 -5
  31. package/tests/bug-reports/bug-report-20260721T221026Z/__snapshots__/bug-report-20260721T221026Z.snap.svg +580 -2
  32. package/tests/bug-reports/bug-report-20260724T175257Z/__snapshots__/bug-report-20260724T175257Z.snap.svg +44 -5
  33. package/tests/bug-reports/bug-report-20260728T144234Z/__snapshots__/bug-report-20260728T144234Z.snap.svg +107 -5
  34. package/tests/bug-reports/bug-report-20260728T225606Z/__snapshots__/bug-report-20260728T225606Z.snap.svg +114 -5
  35. package/tests/bug-reports/bug-report-20260730T061837Z/__snapshots__/bug-report-20260730T061837Z.snap.svg +121 -5
  36. package/tests/bug-reports/bug-report-20260731T052229Z/__snapshots__/bug-report-20260731T052229Z.snap.svg +51 -5
  37. package/tests/bug-reports/bug-report-20260804T095800Z/__snapshots__/bug-report-20260804T095800Z.snap.svg +212 -5
  38. package/tests/bug-reports/bug-report-20260804T171919Z/__snapshots__/bug-report-20260804T171919Z.snap.svg +569 -5
  39. package/tests/bug-reports/bug-report-20260804T225912Z/__snapshots__/bug-report-20260804T225912Z.snap.svg +37 -5
  40. package/tests/bug-reports/bug-report-20260805T061316Z/__snapshots__/bug-report-20260805T061316Z.snap.svg +289 -5
  41. package/tests/bug-reports/bug-report-20260806T061548Z/__snapshots__/bug-report-20260806T061548Z.snap.svg +289 -5
  42. package/tests/bug-reports/bug-report-20260806T093501Z/__snapshots__/bug-report-20260806T093501Z.snap.svg +149 -5
  43. package/tests/bug-reports/bug-report-20260811T075142Z/__snapshots__/bug-report-20260811T075142Z.snap.svg +93 -5
  44. package/tests/bug-reports/bug-report-20260815T073240Z/__snapshots__/bug-report-20260815T073240Z.snap.svg +79 -5
  45. package/tests/bug-reports/bug-report-20260819T091818Z/__snapshots__/bug-report-20260819T091818Z.snap.svg +244 -2
  46. package/tests/examples/__snapshots__/example01.snap.svg +44 -5
  47. package/tests/examples/__snapshots__/example02.snap.svg +51 -5
  48. package/tests/examples/__snapshots__/example03.snap.svg +86 -5
  49. package/tests/examples/__snapshots__/example04.snap.svg +30 -5
  50. package/tests/examples/__snapshots__/example05.snap.svg +30 -5
  51. package/tests/examples/__snapshots__/example06.snap.svg +30 -5
  52. package/tests/examples/__snapshots__/example07.snap.svg +58 -5
  53. package/tests/examples/__snapshots__/example08.snap.svg +37 -5
  54. package/tests/examples/__snapshots__/example09.snap.svg +149 -5
  55. package/tests/examples/__snapshots__/example10.snap.svg +65 -5
  56. package/tests/examples/__snapshots__/example11.snap.svg +51 -5
  57. package/tests/examples/__snapshots__/example12.snap.svg +51 -5
  58. package/tests/examples/__snapshots__/example13.snap.svg +72 -5
  59. package/tests/examples/__snapshots__/example14.snap.svg +79 -5
  60. package/tests/examples/__snapshots__/example15.snap.svg +86 -5
  61. package/tests/examples/__snapshots__/example16.snap.svg +51 -5
  62. package/tests/examples/__snapshots__/example17.snap.svg +51 -5
  63. package/tests/examples/__snapshots__/example18.snap.svg +58 -5
  64. package/tests/examples/__snapshots__/example19.snap.svg +44 -5
  65. package/tests/examples/__snapshots__/example20.snap.svg +44 -5
  66. package/tests/examples/__snapshots__/example21.snap.svg +72 -5
  67. package/tests/examples/__snapshots__/example22.snap.svg +51 -5
  68. package/tests/examples/__snapshots__/example23.snap.svg +51 -5
  69. package/tests/examples/__snapshots__/example24.snap.svg +51 -5
  70. package/tests/examples/__snapshots__/example25.snap.svg +86 -5
  71. package/tests/examples/__snapshots__/example26.snap.svg +51 -5
  72. package/tests/examples/__snapshots__/example27.snap.svg +72 -5
  73. package/tests/examples/__snapshots__/example28.snap.svg +44 -5
  74. package/tests/examples/__snapshots__/example29.snap.svg +324 -5
  75. package/tests/examples/__snapshots__/example30.snap.svg +107 -5
  76. package/tests/examples/__snapshots__/example31.snap.svg +37 -5
  77. package/tests/examples/__snapshots__/example32.snap.svg +149 -5
  78. package/tests/examples/__snapshots__/example33.snap.svg +93 -5
  79. package/tests/examples/__snapshots__/example34.snap.svg +51 -5
  80. package/tests/examples/__snapshots__/example35.snap.svg +58 -5
  81. package/tests/examples/__snapshots__/example36.snap.svg +44 -5
  82. package/tests/examples/__snapshots__/example37.snap.svg +72 -5
  83. package/tests/examples/__snapshots__/example38.snap.svg +30 -5
  84. package/tests/examples/__snapshots__/example39.snap.svg +37 -5
  85. package/tests/examples/__snapshots__/example40.snap.svg +100 -5
  86. package/tests/examples/__snapshots__/example41.snap.svg +44 -5
  87. package/tests/examples/__snapshots__/example42.snap.svg +65 -5
  88. package/tests/examples/__snapshots__/example43.snap.svg +58 -5
  89. package/tests/examples/__snapshots__/example44.snap.svg +107 -5
  90. package/tests/examples/__snapshots__/example45.snap.svg +51 -5
  91. package/tests/examples/__snapshots__/example46.snap.svg +93 -5
  92. package/tests/examples/__snapshots__/example47.snap.svg +93 -5
  93. package/tests/examples/__snapshots__/example48.snap.svg +65 -5
  94. package/tests/examples/__snapshots__/example49.snap.svg +177 -5
  95. package/tests/examples/__snapshots__/example50.snap.svg +93 -5
  96. package/tests/examples/__snapshots__/example51.snap.svg +594 -21
  97. package/tests/fixtures/convertSolverOutputToCircuitJson.test.ts +219 -0
  98. package/tests/fixtures/convertSolverOutputToCircuitJson.ts +1058 -0
  99. package/tests/fixtures/matcher.ts +45 -8
  100. package/tests/repros/__snapshots__/board-1273-trace-overlap-cycle.snap.svg +762 -2
  101. package/tests/repros/__snapshots__/board-15984-same-net-junction.snap.svg +111 -2
  102. package/tests/repros/__snapshots__/board1096-usb-label-overlap-iteration.snap.svg +170 -5
  103. package/tests/repros/__snapshots__/bugreport-001-gnd-overlap.snap.svg +65 -5
  104. package/tests/repros/__snapshots__/manufacturePartNumber-text-box.snap.svg +30 -5
  105. package/tests/repros/__snapshots__/netlabel-connector-through-rail-label.snap.svg +79 -5
  106. package/tests/repros/__snapshots__/repro-atmega328p-fault-pullup.snap.svg +65 -5
  107. package/tests/repros/__snapshots__/repro-atmega328p-missing-gnd-netlabel.snap.svg +149 -5
  108. package/tests/repros/__snapshots__/repro-board-589-regulator-section.snap.svg +55 -2
  109. package/tests/repros/__snapshots__/repro-board-648-esp12f-section.snap.svg +160 -2
  110. package/tests/repros/__snapshots__/repro-bq24074-battery-charger.snap.svg +135 -5
  111. package/tests/repros/__snapshots__/repro-bq25895-cross-net-trace-overlap.snap.svg +69 -2
  112. package/tests/repros/__snapshots__/repro-cc2340r5.snap.svg +86 -5
  113. package/tests/repros/__snapshots__/repro-core-555-power-cross-net-overlap.snap.svg +44 -5
  114. package/tests/repros/__snapshots__/repro-core-subcircuit-missing-ground.snap.svg +44 -5
  115. package/tests/repros/__snapshots__/repro-core-tb67s579ftg-inline-label-routing.snap.svg +30 -5
  116. package/tests/repros/__snapshots__/repro-example35-minimize-trace-crossing.snap.svg +335 -2
  117. package/tests/repros/__snapshots__/repro-ground-label-on-lower-rail-end.snap.svg +48 -2
  118. package/tests/repros/__snapshots__/repro-ina237-current-monitor.snap.svg +149 -5
  119. package/tests/repros/__snapshots__/repro-missing-trace-netlabel.snap.svg +72 -5
  120. package/tests/repros/__snapshots__/repro-netlabel-collision-687.snap.svg +100 -5
  121. package/tests/repros/__snapshots__/repro-netlabel-overlap-trace.snap.svg +51 -5
  122. package/tests/repros/__snapshots__/repro-nrf52810-clock-routing.snap.svg +90 -2
  123. package/tests/repros/__snapshots__/repro-power-group-rail-labels.snap.svg +37 -5
  124. package/tests/repros/__snapshots__/repro-rectifier-trace-overlap.snap.svg +44 -5
  125. package/tests/repros/__snapshots__/repro-rp2040-gamepad-trace-alignment.snap.svg +237 -2
  126. package/tests/repros/__snapshots__/repro-rp2040-usb-cc2-ground-overlap.snap.svg +72 -5
  127. package/tests/repros/__snapshots__/repro-rp2040-v3v3-label-placement.snap.svg +51 -5
  128. package/tests/repros/__snapshots__/repro-rp2040-zero-crystal-fallback-netlabels.snap.svg +30 -5
  129. package/tests/repros/__snapshots__/repro-ti-power-output-section.snap.svg +79 -5
  130. package/tests/repros/__snapshots__/repro-tida010076-j4-ground-bus.snap.svg +27 -2
  131. package/tests/repros/__snapshots__/repro-tida010076-page02.snap.svg +1150 -5
  132. package/tests/repros/__snapshots__/repro-tps61222-trace-intersection.snap.svg +51 -5
  133. package/tests/repros/__snapshots__/repro-type-c-16pin-self-connection.snap.svg +30 -5
  134. package/tests/repros/__snapshots__/repro-type-c-16pin-to-resistor.snap.svg +30 -5
  135. package/tests/repros/__snapshots__/repro-type-c-vbus-led-ground-label.snap.svg +44 -5
  136. package/tests/repros/__snapshots__/repro-usb-power-vbus-label-detour.snap.svg +685 -2
  137. package/tests/repros/__snapshots__/repro-vcc-pin1-detour.snap.svg +27 -2
  138. package/tests/repros/__snapshots__/repro129-host-custom-symbol-passives.snap.svg +51 -5
  139. package/tests/repros/__snapshots__/repro130-bq27441-fuel-gauge-trace-through-c1.snap.svg +100 -5
  140. package/tests/repros/__snapshots__/repro161-power-section-autolayout.snap.svg +107 -5
  141. package/tests/repros/__snapshots__/repro47-endpoint-obstacle-detour.snap.svg +51 -5
  142. package/tests/repros/__snapshots__/repro48-555-timer-vcc-rail-label.snap.svg +104 -2
  143. package/tests/repros/__snapshots__/repro5-escape-padded-text-obstacles.snap.svg +30 -5
  144. package/tests/repros/__snapshots__/repro51-overlap-junction-crossing.snap.svg +65 -5
  145. package/tests/repros/__snapshots__/repro84-stacked-gnd-label-orientation.snap.svg +27 -2
  146. package/tests/repros/__snapshots__/small-variant-resistor-facing-direction.snap.svg +58 -5
  147. package/tests/repros/__snapshots__/trace-overlap-box-resistor.snap.svg +37 -5
  148. package/tests/solvers/InlineNetLabelSolver/__snapshots__/fallback-net-label-width.snap.svg +25 -7
  149. package/tests/solvers/InlineNetLabelSolver/__snapshots__/inline-net-label-anchored-label-clearance.snap.svg +34 -2
  150. package/tests/solvers/InlineNetLabelSolver/__snapshots__/inline-net-label-port-stub.snap.svg +23 -5
  151. package/tests/solvers/InlineNetLabelSolver/__snapshots__/inline-net-label-two-pin-net.snap.svg +23 -5
  152. package/tests/solvers/InlineNetLabelSolver/__snapshots__/inline-net-label01.snap.svg +23 -5
  153. package/tests/solvers/InlineNetLabelSolver/__snapshots__/inline-net-label02.snap.svg +23 -5
  154. package/tests/solvers/InlineNetLabelSolver/__snapshots__/terminal-stub-trace-clearance.snap.svg +23 -5
  155. package/tests/solvers/InlineNetLabelSolver/fallback-net-label-width.test.ts +10 -1
  156. package/tests/solvers/SchematicTraceSingleLineSolver2/__snapshots__/SchematicTraceSingleLineSolver2_01-example17-d1_1-u1_1.snap.svg +23 -5
  157. package/tests/solvers/SchematicTraceSingleLineSolver2/__snapshots__/SchematicTraceSingleLineSolver2_repro47-short-opposing-pins.snap.svg +20 -2
  158. package/tests/solvers/TraceCleanupSolver/__snapshots__/TraceCleanupSolver.snap.svg +44 -5
  159. package/tests/solvers/TraceLabelOverlapAvoidanceSolver/__snapshots__/TraceLabelOverlapAvoidanceSolver.snap.svg +79 -5
  160. package/tests/solvers/TraceLabelOverlapAvoidanceSolver/sub-solver/__snapshots__/MergedNetLabelObstacles.snap.svg +44 -5
  161. package/tests/solvers/TraceLabelOverlapAvoidanceSolver/sub-solver/__snapshots__/OverlapAvoidanceStepSolver.snap.svg +23 -5
  162. package/tests/solvers/TraceLabelOverlapAvoidanceSolver/sub-solver/__snapshots__/SingleOverlapSolver.snap.svg +30 -5
package/dist/index.js CHANGED
@@ -2742,6 +2742,7 @@ function solveNetLabelPlacementForPortOnlyPin(params) {
2742
2742
  globalConnNetId: overlappingSameNetTraceGroup.globalConnNetId,
2743
2743
  dcConnNetId: void 0,
2744
2744
  netId: overlappingSameNetTraceGroup.netId,
2745
+ netLabelText: overlappingSameNetTraceGroup.netLabelText,
2745
2746
  mspConnectionPairIds: [],
2746
2747
  pinIds: [pinId],
2747
2748
  orientation,
@@ -2773,6 +2774,7 @@ function solveNetLabelPlacementForPortOnlyPin(params) {
2773
2774
  globalConnNetId: overlappingSameNetTraceGroup.globalConnNetId,
2774
2775
  dcConnNetId: void 0,
2775
2776
  netId: overlappingSameNetTraceGroup.netId,
2777
+ netLabelText: overlappingSameNetTraceGroup.netLabelText,
2776
2778
  mspConnectionPairIds: [],
2777
2779
  pinIds: [pinId],
2778
2780
  orientation: fallbackOrientation,
@@ -3059,6 +3061,7 @@ var SingleNetLabelPlacementSolver = class extends BaseSolver {
3059
3061
  globalConnNetId: this.overlappingSameNetTraceGroup.globalConnNetId,
3060
3062
  dcConnNetId: curr.dcConnNetId,
3061
3063
  netId: this.overlappingSameNetTraceGroup.netId,
3064
+ netLabelText: this.overlappingSameNetTraceGroup.netLabelText,
3062
3065
  mspConnectionPairIds: [curr.mspPairId],
3063
3066
  pinIds: [curr.pins[0].pinId, curr.pins[1].pinId],
3064
3067
  orientation,
@@ -3078,6 +3081,7 @@ var SingleNetLabelPlacementSolver = class extends BaseSolver {
3078
3081
  globalConnNetId: this.overlappingSameNetTraceGroup.globalConnNetId,
3079
3082
  dcConnNetId: bestCandidate.dcConnNetId,
3080
3083
  netId: this.overlappingSameNetTraceGroup.netId,
3084
+ netLabelText: this.overlappingSameNetTraceGroup.netLabelText,
3081
3085
  mspConnectionPairIds: [bestCandidate.mspPairId],
3082
3086
  pinIds: bestCandidate.pinIds,
3083
3087
  orientation: bestCandidate.orientation,
@@ -3133,16 +3137,25 @@ var NetLabelPlacementSolver = class extends BaseSolver {
3133
3137
  }
3134
3138
  }
3135
3139
  const userNetIdByPinId = {};
3140
+ const netLabelTextByPinId = {};
3136
3141
  for (const dc of this.inputProblem.directConnections) {
3137
3142
  if (dc.netId) {
3138
3143
  const [a, b] = dc.pinIds;
3139
3144
  userNetIdByPinId[a] = dc.netId;
3140
3145
  userNetIdByPinId[b] = dc.netId;
3141
3146
  }
3147
+ const netLabelText = dc.netLabelText?.trim();
3148
+ if (netLabelText) {
3149
+ const [a, b] = dc.pinIds;
3150
+ netLabelTextByPinId[a] = netLabelText;
3151
+ netLabelTextByPinId[b] = netLabelText;
3152
+ }
3142
3153
  }
3143
3154
  for (const nc of this.inputProblem.netConnections) {
3144
3155
  for (const pid of nc.pinIds) {
3145
3156
  userNetIdByPinId[pid] = nc.netId;
3157
+ const netLabelText = nc.netLabelText?.trim();
3158
+ if (netLabelText) netLabelTextByPinId[pid] = netLabelText;
3146
3159
  }
3147
3160
  }
3148
3161
  const groups = [];
@@ -3228,6 +3241,7 @@ var NetLabelPlacementSolver = class extends BaseSolver {
3228
3241
  const group = {
3229
3242
  globalConnNetId,
3230
3243
  netId: userNetId,
3244
+ netLabelText: [...component].map((pinId) => netLabelTextByPinId[pinId]).find((text) => Boolean(text)),
3231
3245
  overlappingTraces: rep,
3232
3246
  mspConnectionPairIds
3233
3247
  };
@@ -3239,6 +3253,7 @@ var NetLabelPlacementSolver = class extends BaseSolver {
3239
3253
  groups.push({
3240
3254
  globalConnNetId,
3241
3255
  netId: userNetId,
3256
+ netLabelText: netLabelTextByPinId[p],
3242
3257
  portOnlyPinId: p
3243
3258
  });
3244
3259
  }
@@ -13326,7 +13341,8 @@ var InlineNetLabelSolver = class extends BaseSolver {
13326
13341
  );
13327
13342
  const inputPin = inputChip?.pins.find((pin) => pin.pinId === pinId);
13328
13343
  const height = connection.inlineNetLabelHeight ?? DEFAULT_INLINE_NET_LABEL_HEIGHT;
13329
- const width = connection.inlineNetLabelWidth ?? connection.netLabelWidth ?? estimateInlineNetLabelWidth(connection.netId, height);
13344
+ const netLabelText = connection.netLabelText?.trim() || void 0;
13345
+ const width = connection.inlineNetLabelWidth ?? connection.netLabelWidth ?? estimateInlineNetLabelWidth(netLabelText ?? connection.netId, height);
13330
13346
  const stubLength = Math.max(width + 0.2, 0.6);
13331
13347
  const start = inputPin ? { x: inputPin.x, y: inputPin.y } : anchoredPlacement.anchorPoint;
13332
13348
  const direction = inputPin && inputChip ? inputPin._facingDirection ?? getPinDirection(inputPin, inputChip) : anchoredPlacement.orientation;
@@ -13368,6 +13384,7 @@ var InlineNetLabelSolver = class extends BaseSolver {
13368
13384
  return {
13369
13385
  globalConnNetId: anchoredPlacement.globalConnNetId,
13370
13386
  netId: connection.netId,
13387
+ netLabelText,
13371
13388
  pinIds: [pinId],
13372
13389
  stubTracePath: [start, end],
13373
13390
  axis,
@@ -13385,7 +13402,8 @@ var InlineNetLabelSolver = class extends BaseSolver {
13385
13402
  const segments = getAxisAlignedSegments(trace.tracePath);
13386
13403
  if (segments.length === 0) return null;
13387
13404
  const height = connection.inlineNetLabelHeight ?? DEFAULT_INLINE_NET_LABEL_HEIGHT;
13388
- const width = connection.inlineNetLabelWidth ?? connection.netLabelWidth ?? estimateInlineNetLabelWidth(connection.netId, height);
13405
+ const netLabelText = connection.netLabelText?.trim() || void 0;
13406
+ const width = connection.inlineNetLabelWidth ?? connection.netLabelWidth ?? estimateInlineNetLabelWidth(netLabelText ?? connection.netId, height);
13389
13407
  const offset = height / 2 + INLINE_NET_LABEL_TRACE_MARGIN;
13390
13408
  const usableSegments = segments.filter((segment) => segment.length >= width).sort((a, b) => b.length - a.length);
13391
13409
  for (const segment of usableSegments) {
@@ -13414,6 +13432,7 @@ var InlineNetLabelSolver = class extends BaseSolver {
13414
13432
  return {
13415
13433
  globalConnNetId: trace.globalConnNetId,
13416
13434
  netId: connection.netId,
13435
+ netLabelText,
13417
13436
  mspPairId: trace.mspPairId,
13418
13437
  pinIds: [...connection.pinIds],
13419
13438
  axis: segment.axis,
@@ -13429,6 +13448,7 @@ var InlineNetLabelSolver = class extends BaseSolver {
13429
13448
  const spanPlacement = this.computeSpanPlacement({
13430
13449
  trace,
13431
13450
  connection,
13451
+ netLabelText,
13432
13452
  width,
13433
13453
  height,
13434
13454
  offset
@@ -13445,6 +13465,7 @@ var InlineNetLabelSolver = class extends BaseSolver {
13445
13465
  computeSpanPlacement({
13446
13466
  trace,
13447
13467
  connection,
13468
+ netLabelText,
13448
13469
  width,
13449
13470
  height,
13450
13471
  offset
@@ -13504,6 +13525,7 @@ var InlineNetLabelSolver = class extends BaseSolver {
13504
13525
  return {
13505
13526
  globalConnNetId: trace.globalConnNetId,
13506
13527
  netId: connection.netId,
13528
+ netLabelText,
13507
13529
  mspPairId: trace.mspPairId,
13508
13530
  pinIds: [...connection.pinIds],
13509
13531
  axis,
@@ -13584,77 +13606,113 @@ var InlineNetLabelSolver = class extends BaseSolver {
13584
13606
  return this.buildPostProcessedOutput();
13585
13607
  }
13586
13608
  visualize() {
13587
- const graphics = visualizeInputProblem(this.inputProblem);
13588
- graphics.lines ??= [];
13589
- graphics.rects ??= [];
13590
- graphics.points ??= [];
13591
- graphics.texts ??= [];
13592
- const output = this.getOutput();
13593
- for (const trace of output.traces) {
13609
+ return visualizeInlineNetLabelOutput({
13610
+ inputProblem: this.inputProblem,
13611
+ ...this.getOutput()
13612
+ });
13613
+ }
13614
+ };
13615
+ var visualizeInlineNetLabelOutput = ({
13616
+ inputProblem,
13617
+ traces,
13618
+ netLabelPlacements,
13619
+ inlineNetLabelPlacements
13620
+ }) => {
13621
+ const graphics = visualizeInputProblem(inputProblem);
13622
+ graphics.lines ??= [];
13623
+ graphics.rects ??= [];
13624
+ graphics.points ??= [];
13625
+ graphics.texts ??= [];
13626
+ for (const trace of traces) {
13627
+ graphics.lines.push({
13628
+ points: trace.tracePath,
13629
+ strokeColor: "purple"
13630
+ });
13631
+ }
13632
+ for (const label of netLabelPlacements) {
13633
+ graphics.rects.push({
13634
+ center: label.center,
13635
+ width: label.width,
13636
+ height: label.height,
13637
+ fill: getColorFromString(label.globalConnNetId, 0.35),
13638
+ strokeColor: getColorFromString(label.globalConnNetId, 0.9),
13639
+ label: `netId: ${label.netId}
13640
+ globalConnNetId: ${label.globalConnNetId}`
13641
+ });
13642
+ graphics.points.push({
13643
+ x: label.anchorPoint.x,
13644
+ y: label.anchorPoint.y,
13645
+ color: getColorFromString(label.globalConnNetId, 0.9),
13646
+ label: `anchorPoint
13647
+ orientation: ${label.orientation}`
13648
+ });
13649
+ }
13650
+ for (const inlineLabel of inlineNetLabelPlacements) {
13651
+ if (inlineLabel.stubTracePath) {
13594
13652
  graphics.lines.push({
13595
- points: trace.tracePath,
13653
+ points: inlineLabel.stubTracePath,
13596
13654
  strokeColor: "purple"
13597
13655
  });
13598
13656
  }
13599
- const { netLabelPlacements } = this.getOutput();
13600
- for (const label of netLabelPlacements) {
13601
- graphics.rects.push({
13602
- center: label.center,
13603
- width: label.width,
13604
- height: label.height,
13605
- fill: getColorFromString(label.globalConnNetId, 0.35),
13606
- strokeColor: getColorFromString(label.globalConnNetId, 0.9),
13607
- label: `netId: ${label.netId}
13608
- globalConnNetId: ${label.globalConnNetId}`
13609
- });
13610
- graphics.points.push({
13611
- x: label.anchorPoint.x,
13612
- y: label.anchorPoint.y,
13613
- color: getColorFromString(label.globalConnNetId, 0.9),
13614
- label: `anchorPoint
13615
- orientation: ${label.orientation}`
13616
- });
13657
+ const isHorizontal4 = inlineLabel.axis === "x";
13658
+ let renderedWidth = inlineLabel.width;
13659
+ let renderedHeight = inlineLabel.height;
13660
+ if (!isHorizontal4) {
13661
+ renderedWidth = inlineLabel.height;
13662
+ renderedHeight = inlineLabel.width;
13617
13663
  }
13618
- for (const inlineLabel of this.inlineNetLabelPlacements) {
13619
- if (inlineLabel.stubTracePath) {
13620
- graphics.lines.push({
13621
- points: inlineLabel.stubTracePath,
13622
- strokeColor: "purple"
13623
- });
13664
+ graphics.rects.push({
13665
+ center: inlineLabel.center,
13666
+ width: renderedWidth,
13667
+ height: renderedHeight,
13668
+ fill: getColorFromString(inlineLabel.globalConnNetId, 0.35),
13669
+ strokeColor: "green",
13670
+ label: [
13671
+ `INLINE netId: ${inlineLabel.netId}`,
13672
+ `axis: ${inlineLabel.axis}`,
13673
+ `side: ${inlineLabel.side}`
13674
+ ].join("\n")
13675
+ });
13676
+ let textX = inlineLabel.center.x;
13677
+ let textY = inlineLabel.center.y;
13678
+ let anchorSide = "center";
13679
+ let rotation;
13680
+ if (inlineLabel.stubTracePath) {
13681
+ const stubStart = inlineLabel.stubTracePath[0];
13682
+ const stubEnd = inlineLabel.stubTracePath[1];
13683
+ let labelOffset = inlineLabel.width / 2;
13684
+ if (stubEnd[inlineLabel.axis] > stubStart[inlineLabel.axis]) {
13685
+ labelOffset = -inlineLabel.width / 2;
13686
+ anchorSide = "center_left";
13687
+ } else {
13688
+ anchorSide = "center_right";
13689
+ }
13690
+ if (inlineLabel.axis === "x") {
13691
+ textX += labelOffset;
13692
+ } else {
13693
+ textY += labelOffset;
13624
13694
  }
13625
- const isHorizontal4 = inlineLabel.axis === "x";
13626
- graphics.rects.push({
13627
- center: inlineLabel.center,
13628
- width: isHorizontal4 ? inlineLabel.width : inlineLabel.height,
13629
- height: isHorizontal4 ? inlineLabel.height : inlineLabel.width,
13630
- fill: getColorFromString(inlineLabel.globalConnNetId, 0.35),
13631
- strokeColor: "green",
13632
- label: [
13633
- `INLINE netId: ${inlineLabel.netId}`,
13634
- `axis: ${inlineLabel.axis}`,
13635
- `side: ${inlineLabel.side}`
13636
- ].join("\n")
13637
- });
13638
- graphics.texts.push({
13639
- x: inlineLabel.stubTracePath && inlineLabel.axis === "x" ? inlineLabel.center.x + (inlineLabel.stubTracePath[1].x > inlineLabel.stubTracePath[0].x ? -inlineLabel.width / 2 : inlineLabel.width / 2) : inlineLabel.center.x,
13640
- y: inlineLabel.stubTracePath && inlineLabel.axis === "y" ? inlineLabel.center.y + (inlineLabel.stubTracePath[1].y > inlineLabel.stubTracePath[0].y ? -inlineLabel.width / 2 : inlineLabel.width / 2) : inlineLabel.center.y,
13641
- text: inlineLabel.netId ?? "",
13642
- color: "green",
13643
- fontSize: inlineLabel.height,
13644
- anchorSide: inlineLabel.stubTracePath ? inlineLabel.stubTracePath[1][inlineLabel.axis] > inlineLabel.stubTracePath[0][inlineLabel.axis] ? "center_left" : "center_right" : "center",
13645
- // Vertical labels read bottom-to-top, alongside the wire they name.
13646
- rotation: inlineLabel.axis === "y" ? 90 : void 0
13647
- });
13648
- graphics.points.push({
13649
- x: inlineLabel.anchorPoint.x,
13650
- y: inlineLabel.anchorPoint.y,
13651
- color: "green",
13652
- label: `inline anchor
13653
- ${inlineLabel.netId}`
13654
- });
13655
13695
  }
13656
- return graphics;
13696
+ if (inlineLabel.axis === "y") rotation = 90;
13697
+ graphics.texts.push({
13698
+ x: textX,
13699
+ y: textY,
13700
+ text: inlineLabel.netLabelText ?? inlineLabel.netId ?? "",
13701
+ color: "green",
13702
+ fontSize: inlineLabel.height,
13703
+ anchorSide,
13704
+ // Vertical labels read bottom-to-top, alongside the wire they name.
13705
+ rotation
13706
+ });
13707
+ graphics.points.push({
13708
+ x: inlineLabel.anchorPoint.x,
13709
+ y: inlineLabel.anchorPoint.y,
13710
+ color: "green",
13711
+ label: `inline anchor
13712
+ ${inlineLabel.netLabelText ?? inlineLabel.netId}`
13713
+ });
13657
13714
  }
13715
+ return graphics;
13658
13716
  };
13659
13717
  var estimateInlineNetLabelWidth = (text, fontSize = DEFAULT_INLINE_NET_LABEL_HEIGHT) => {
13660
13718
  const fontScale = fontSize / 0.18;
@@ -13740,6 +13798,250 @@ var getCollisionLimitedTerminalStubEnd = ({
13740
13798
  return isHorizontal4 ? { x: start.x + direction * availableLength, y: start.y } : { x: start.x, y: start.y + direction * availableLength };
13741
13799
  };
13742
13800
 
13801
+ // lib/solvers/NetLabelToTraceSolver/NetLabelToTraceSolver.ts
13802
+ import {
13803
+ doesSegmentIntersectRect,
13804
+ getBoundFromCenteredRect
13805
+ } from "@tscircuit/math-utils";
13806
+
13807
+ // lib/solvers/NetLabelTraceRecovery/getTraceRecoveryConnectivityMaps.ts
13808
+ var getTraceRecoveryConnectivityMaps = (inputProblem) => {
13809
+ const chipMap = {};
13810
+ const pinMap = /* @__PURE__ */ new Map();
13811
+ for (const chip of inputProblem.chips) {
13812
+ chipMap[chip.chipId] = chip;
13813
+ for (const pin of chip.pins) {
13814
+ pinMap.set(pin.pinId, {
13815
+ ...pin,
13816
+ chipId: chip.chipId,
13817
+ _facingDirection: pin._facingDirection ?? getPinDirection(pin, chip)
13818
+ });
13819
+ }
13820
+ }
13821
+ return { chipMap, pinMap };
13822
+ };
13823
+
13824
+ // lib/solvers/NetLabelToTraceSolver/NetLabelToTraceSolver.ts
13825
+ var AVAILABLE_NET_ORIENTATION_PREFIX = "available-net-orientation-";
13826
+ var RECOVERED_TRACE_PREFIX = "net-label-to-trace-";
13827
+ var getCanonicalPairKey = (firstPinId, secondPinId) => [firstPinId, secondPinId].sort().join("--");
13828
+ var pathIntersectsRenderedLabel = (path, label) => {
13829
+ let width = label.width;
13830
+ let height = label.height;
13831
+ if ("axis" in label && label.axis === "y") {
13832
+ width = label.height;
13833
+ height = label.width;
13834
+ }
13835
+ const bounds = getBoundFromCenteredRect({
13836
+ center: label.center,
13837
+ width,
13838
+ height
13839
+ });
13840
+ for (let pathIndex = 0; pathIndex < path.length - 1; pathIndex++) {
13841
+ if (doesSegmentIntersectRect(path[pathIndex], path[pathIndex + 1], bounds)) {
13842
+ return true;
13843
+ }
13844
+ }
13845
+ return false;
13846
+ };
13847
+ var getPerpendicularOffset = (firstPin, secondPin) => {
13848
+ const xDistance = Math.abs(firstPin.x - secondPin.x);
13849
+ const yDistance = Math.abs(firstPin.y - secondPin.y);
13850
+ if (xDistance >= yDistance) return yDistance;
13851
+ return xDistance;
13852
+ };
13853
+ var NetLabelToTraceSolver = class extends BaseSolver {
13854
+ constructor(input) {
13855
+ super();
13856
+ this.input = input;
13857
+ this.inputProblem = input.inputProblem;
13858
+ this.outputTraces = [...input.traces];
13859
+ this.outputNetLabelPlacements = [...input.netLabelPlacements];
13860
+ const { chipMap, pinMap } = getTraceRecoveryConnectivityMaps(
13861
+ this.inputProblem
13862
+ );
13863
+ this.chipMap = chipMap;
13864
+ this.pinMap = pinMap;
13865
+ this.queuedCandidates = this.buildCandidatePairs();
13866
+ this.stats.candidateCount = this.queuedCandidates.length;
13867
+ this.stats.recoveredTraceCount = 0;
13868
+ }
13869
+ input;
13870
+ inputProblem;
13871
+ outputTraces;
13872
+ outputNetLabelPlacements;
13873
+ chipMap;
13874
+ pinMap;
13875
+ queuedCandidates;
13876
+ currentCandidate = null;
13877
+ getConstructorParams() {
13878
+ return [this.input];
13879
+ }
13880
+ isEligiblePortOnlyDirectConnectionLabel(label, groundGlobalConnNetId) {
13881
+ if (label.pinIds.length !== 1 || label.mspConnectionPairIds.length !== 0 || !label.netId || label.netId === "GND" || label.globalConnNetId === groundGlobalConnNetId) {
13882
+ return false;
13883
+ }
13884
+ const pinId = label.pinIds[0];
13885
+ return this.inputProblem.directConnections.some(
13886
+ (connection) => connection.netId === label.netId && connection.pinIds.includes(pinId)
13887
+ );
13888
+ }
13889
+ buildCandidatePairs() {
13890
+ const { netConnMap } = getConnectivityMapsFromInputProblem(
13891
+ this.inputProblem
13892
+ );
13893
+ const groundGlobalConnNetId = netConnMap.getNetConnectedToId("GND") ?? void 0;
13894
+ const labelsByGlobalNet = /* @__PURE__ */ new Map();
13895
+ for (const label of this.input.netLabelPlacements) {
13896
+ if (!this.isEligiblePortOnlyDirectConnectionLabel(
13897
+ label,
13898
+ groundGlobalConnNetId
13899
+ )) {
13900
+ continue;
13901
+ }
13902
+ const labels = labelsByGlobalNet.get(label.globalConnNetId) ?? [];
13903
+ labels.push(label);
13904
+ labelsByGlobalNet.set(label.globalConnNetId, labels);
13905
+ }
13906
+ const candidates = [];
13907
+ for (const labels of labelsByGlobalNet.values()) {
13908
+ for (let firstIndex = 0; firstIndex < labels.length; firstIndex++) {
13909
+ for (let secondIndex = firstIndex + 1; secondIndex < labels.length; secondIndex++) {
13910
+ const firstLabel = labels[firstIndex];
13911
+ const secondLabel = labels[secondIndex];
13912
+ const firstPin = this.pinMap.get(firstLabel.pinIds[0]);
13913
+ const secondPin = this.pinMap.get(secondLabel.pinIds[0]);
13914
+ if (!firstPin || !secondPin) continue;
13915
+ if (arePinsInDifferentSchematicSections(
13916
+ this.inputProblem,
13917
+ firstPin,
13918
+ secondPin
13919
+ )) {
13920
+ continue;
13921
+ }
13922
+ if (doesPairCrossRestrictedCenterLines({
13923
+ inputProblem: this.inputProblem,
13924
+ chipMap: this.chipMap,
13925
+ pinIdMap: this.pinMap,
13926
+ p1: firstPin,
13927
+ p2: secondPin
13928
+ })) {
13929
+ continue;
13930
+ }
13931
+ candidates.push({
13932
+ firstLabel,
13933
+ secondLabel,
13934
+ pins: [firstPin, secondPin],
13935
+ perpendicularOffset: getPerpendicularOffset(firstPin, secondPin),
13936
+ routeDistance: Math.abs(firstPin.x - secondPin.x) + Math.abs(firstPin.y - secondPin.y),
13937
+ key: getCanonicalPairKey(firstPin.pinId, secondPin.pinId)
13938
+ });
13939
+ }
13940
+ }
13941
+ }
13942
+ candidates.sort(
13943
+ (first, second) => first.perpendicularOffset - second.perpendicularOffset || first.routeDistance - second.routeDistance || first.key.localeCompare(second.key)
13944
+ );
13945
+ return candidates;
13946
+ }
13947
+ isSupersededConnectorTrace(trace, candidate) {
13948
+ if (!trace.mspPairId.startsWith(AVAILABLE_NET_ORIENTATION_PREFIX)) {
13949
+ return false;
13950
+ }
13951
+ if (trace.pinIds.length !== 1) return false;
13952
+ return candidate.pins.some((pin) => pin.pinId === trace.pinIds[0]);
13953
+ }
13954
+ routeIntersectsRemainingLabels(tracePath, candidate) {
13955
+ for (const label of this.outputNetLabelPlacements) {
13956
+ if (label === candidate.firstLabel || label === candidate.secondLabel) {
13957
+ continue;
13958
+ }
13959
+ if (pathIntersectsRenderedLabel(tracePath, label)) return true;
13960
+ }
13961
+ return this.input.inlineNetLabelPlacements.some(
13962
+ (label) => pathIntersectsRenderedLabel(tracePath, label)
13963
+ );
13964
+ }
13965
+ tryAcceptCurrentRoute() {
13966
+ const candidate = this.currentCandidate;
13967
+ const tracePath = this.activeSubSolver?.solvedTracePath;
13968
+ if (!candidate || !tracePath) return;
13969
+ const retainedTraces = this.outputTraces.filter(
13970
+ (trace) => !this.isSupersededConnectorTrace(trace, candidate)
13971
+ );
13972
+ if (doesTraceOverlapWithExistingTraces(tracePath, retainedTraces) || this.routeIntersectsRemainingLabels(tracePath, candidate)) {
13973
+ return;
13974
+ }
13975
+ const [firstPin, secondPin] = candidate.pins;
13976
+ const mspPairId = `${RECOVERED_TRACE_PREFIX}${candidate.key}`;
13977
+ const recoveredTrace = {
13978
+ mspPairId,
13979
+ dcConnNetId: candidate.firstLabel.globalConnNetId,
13980
+ globalConnNetId: candidate.firstLabel.globalConnNetId,
13981
+ pins: [firstPin, secondPin],
13982
+ tracePath,
13983
+ mspConnectionPairIds: [mspPairId],
13984
+ pinIds: [firstPin.pinId, secondPin.pinId]
13985
+ };
13986
+ this.outputTraces = [...retainedTraces, recoveredTrace];
13987
+ this.outputNetLabelPlacements = this.outputNetLabelPlacements.filter(
13988
+ (label) => label !== candidate.firstLabel && label !== candidate.secondLabel
13989
+ );
13990
+ this.stats.recoveredTraceCount++;
13991
+ }
13992
+ _step() {
13993
+ if (this.activeSubSolver) {
13994
+ this.activeSubSolver.step();
13995
+ if (this.activeSubSolver.solved) {
13996
+ this.tryAcceptCurrentRoute();
13997
+ this.activeSubSolver = null;
13998
+ this.currentCandidate = null;
13999
+ } else if (this.activeSubSolver.failed) {
14000
+ this.activeSubSolver = null;
14001
+ this.currentCandidate = null;
14002
+ }
14003
+ return;
14004
+ }
14005
+ let candidate = this.queuedCandidates.shift();
14006
+ while (candidate && (!this.outputNetLabelPlacements.includes(candidate.firstLabel) || !this.outputNetLabelPlacements.includes(candidate.secondLabel))) {
14007
+ candidate = this.queuedCandidates.shift();
14008
+ }
14009
+ if (!candidate) {
14010
+ this.solved = true;
14011
+ return;
14012
+ }
14013
+ this.currentCandidate = candidate;
14014
+ this.activeSubSolver = new SchematicTraceSingleLineSolver2({
14015
+ inputProblem: this.inputProblem,
14016
+ pins: candidate.pins,
14017
+ chipMap: this.chipMap
14018
+ });
14019
+ }
14020
+ getOutput() {
14021
+ return {
14022
+ traces: this.outputTraces,
14023
+ netLabelPlacements: this.outputNetLabelPlacements,
14024
+ inlineNetLabelPlacements: this.input.inlineNetLabelPlacements
14025
+ };
14026
+ }
14027
+ visualize() {
14028
+ if (this.activeSubSolver) return this.activeSubSolver.visualize();
14029
+ const graphics = visualizeInlineNetLabelOutput({
14030
+ inputProblem: this.inputProblem,
14031
+ ...this.getOutput()
14032
+ });
14033
+ for (const trace of this.outputTraces) {
14034
+ if (!trace.mspPairId.startsWith(RECOVERED_TRACE_PREFIX)) continue;
14035
+ graphics.lines.push({
14036
+ points: trace.tracePath,
14037
+ strokeColor: "green",
14038
+ label: `recovered from net labels: ${trace.pinIds.join(" -> ")}`
14039
+ });
14040
+ }
14041
+ return graphics;
14042
+ }
14043
+ };
14044
+
13743
14045
  // lib/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver.ts
13744
14046
  function definePipelineStep(solverName, solverClass, getConstructorParams, opts = {}) {
13745
14047
  return {
@@ -13778,6 +14080,7 @@ var SchematicTracePipelineSolver = class extends BaseSolver {
13778
14080
  finalTraceElbowTransitionSimplificationSolver;
13779
14081
  sameNetJunctionAlignmentSolver;
13780
14082
  inlineNetLabelSolver;
14083
+ netLabelToTraceSolver;
13781
14084
  startTimeOfPhase;
13782
14085
  endTimeOfPhase;
13783
14086
  timeSpentOnPhase;
@@ -14189,6 +14492,19 @@ var SchematicTracePipelineSolver = class extends BaseSolver {
14189
14492
  }
14190
14493
  ];
14191
14494
  }
14495
+ ),
14496
+ definePipelineStep(
14497
+ "netLabelToTraceSolver",
14498
+ NetLabelToTraceSolver,
14499
+ (instance) => {
14500
+ const inlineOutput = instance.inlineNetLabelSolver.getOutput();
14501
+ return [
14502
+ {
14503
+ inputProblem: instance.inputProblem,
14504
+ ...inlineOutput
14505
+ }
14506
+ ];
14507
+ }
14192
14508
  )
14193
14509
  ];
14194
14510
  constructor(inputProblem, opts) {
@@ -14309,5 +14625,6 @@ export {
14309
14625
  InlineNetLabelSolver,
14310
14626
  SchematicTracePipelineSolver,
14311
14627
  SchematicTraceSingleLineSolver2,
14312
- estimateInlineNetLabelWidth
14628
+ estimateInlineNetLabelWidth,
14629
+ visualizeInlineNetLabelOutput
14313
14630
  };