@tscircuit/schematic-trace-solver 0.0.150 → 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.
package/README.md CHANGED
@@ -48,10 +48,12 @@ decides which connections deserve one; the solver only honors the request when
48
48
  the connection actually got routed, since there is nothing to run parallel to
49
49
  otherwise.
50
50
 
51
- The `InlineNetLabelSolver` runs last in the pipeline and exposes
52
- `inlineNetLabelPlacements`. A net that receives an inline label has its anchored
53
- `NetLabelPlacement` removed from `getOutput().netLabelPlacements`, so a net is
54
- never labeled twice.
51
+ The `InlineNetLabelSolver` exposes `inlineNetLabelPlacements`. A net that
52
+ receives an inline label has its anchored `NetLabelPlacement` removed from
53
+ `getOutput().netLabelPlacements`, so a net is never labeled twice.
54
+ `NetLabelToTraceSolver` then replaces pairs of port-only fallback labels with
55
+ real traces whenever the router finds a clear path. Its `getOutput()` is the
56
+ pipeline's final output.
55
57
 
56
58
  ```tsx
57
59
  directConnections: [
package/dist/index.d.ts CHANGED
@@ -1266,6 +1266,12 @@ interface InlineNetLabelSolverInput {
1266
1266
  traces: SolvedTracePath[];
1267
1267
  netLabelPlacements: NetLabelPlacement[];
1268
1268
  }
1269
+ interface InlineNetLabelOutput {
1270
+ inputProblem: InputProblem;
1271
+ traces: SolvedTracePath[];
1272
+ netLabelPlacements: NetLabelPlacement[];
1273
+ inlineNetLabelPlacements: InlineNetLabelPlacement[];
1274
+ }
1269
1275
  type InlineEligibleConnection = InputDirectConnection | InputNetConnection;
1270
1276
  /**
1271
1277
  * Places "inline net labels" - net names drawn alongside the trace they belong
@@ -1322,12 +1328,39 @@ declare class InlineNetLabelSolver extends BaseSolver {
1322
1328
  };
1323
1329
  visualize(): GraphicsObject;
1324
1330
  }
1331
+ declare const visualizeInlineNetLabelOutput: ({ inputProblem, traces, netLabelPlacements, inlineNetLabelPlacements, }: InlineNetLabelOutput) => GraphicsObject;
1325
1332
  /**
1326
1333
  * Mirrors the net label text width used by @tscircuit/core so a label that core
1327
1334
  * did not measure for us still reserves a sane amount of space.
1328
1335
  */
1329
1336
  declare const estimateInlineNetLabelWidth: (text: string, fontSize?: number) => number;
1330
1337
 
1338
+ declare class NetLabelToTraceSolver extends BaseSolver {
1339
+ private input;
1340
+ inputProblem: InputProblem;
1341
+ outputTraces: SolvedTracePath[];
1342
+ outputNetLabelPlacements: NetLabelPlacement[];
1343
+ private chipMap;
1344
+ private pinMap;
1345
+ private queuedCandidates;
1346
+ private currentCandidate;
1347
+ activeSubSolver: SchematicTraceSingleLineSolver2 | null;
1348
+ constructor(input: InlineNetLabelOutput);
1349
+ getConstructorParams(): [InlineNetLabelOutput];
1350
+ private isEligiblePortOnlyDirectConnectionLabel;
1351
+ private buildCandidatePairs;
1352
+ private isSupersededConnectorTrace;
1353
+ private routeIntersectsRemainingLabels;
1354
+ private tryAcceptCurrentRoute;
1355
+ _step(): void;
1356
+ getOutput(): {
1357
+ traces: SolvedTracePath[];
1358
+ netLabelPlacements: NetLabelPlacement[];
1359
+ inlineNetLabelPlacements: InlineNetLabelPlacement[];
1360
+ };
1361
+ visualize(): GraphicsObject;
1362
+ }
1363
+
1331
1364
  /**
1332
1365
  * Pipeline solver that runs a series of solvers to find the best schematic layout.
1333
1366
  * Coordinates the entire layout process from chip partitioning through final packing.
@@ -1368,13 +1401,14 @@ declare class SchematicTracePipelineSolver extends BaseSolver {
1368
1401
  finalTraceElbowTransitionSimplificationSolver?: TraceElbowTransitionSimplificationSolver;
1369
1402
  sameNetJunctionAlignmentSolver?: SameNetJunctionAlignmentSolver;
1370
1403
  inlineNetLabelSolver?: InlineNetLabelSolver;
1404
+ netLabelToTraceSolver?: NetLabelToTraceSolver;
1371
1405
  startTimeOfPhase: Record<string, number>;
1372
1406
  endTimeOfPhase: Record<string, number>;
1373
1407
  timeSpentOnPhase: Record<string, number>;
1374
1408
  firstIterationOfPhase: Record<string, number>;
1375
1409
  inputProblem: InputProblem;
1376
1410
  hideRatsNet: boolean;
1377
- pipelineDef: (PipelineStep<typeof MspConnectionPairSolver> | PipelineStep<typeof SchematicTraceLinesSolver> | PipelineStep<typeof LongDistancePairSolver> | PipelineStep<typeof UnroutedTraceRecoverySolver> | PipelineStep<typeof TraceOverlapShiftSolver> | PipelineStep<typeof NetLabelPlacementSolver> | PipelineStep<typeof TraceLabelOverlapAvoidanceSolver> | PipelineStep<typeof TraceElbowTransitionSimplificationSolver> | PipelineStep<typeof TraceCleanupSolver> | PipelineStep<typeof Example28Solver> | PipelineStep<typeof AvailableNetOrientationSolver> | PipelineStep<typeof RailNetLabelCornerPlacementSolver> | PipelineStep<typeof TraceAnchoredNetLabelOverlapSolver> | PipelineStep<typeof NetLabelTraceCollisionSolver> | PipelineStep<typeof NetLabelNetLabelCollisionSolver> | PipelineStep<typeof SameNetJunctionAlignmentSolver> | PipelineStep<typeof InlineNetLabelSolver>)[];
1411
+ pipelineDef: (PipelineStep<typeof MspConnectionPairSolver> | PipelineStep<typeof SchematicTraceLinesSolver> | PipelineStep<typeof LongDistancePairSolver> | PipelineStep<typeof UnroutedTraceRecoverySolver> | PipelineStep<typeof TraceOverlapShiftSolver> | PipelineStep<typeof NetLabelPlacementSolver> | PipelineStep<typeof TraceLabelOverlapAvoidanceSolver> | PipelineStep<typeof TraceElbowTransitionSimplificationSolver> | PipelineStep<typeof TraceCleanupSolver> | PipelineStep<typeof Example28Solver> | PipelineStep<typeof AvailableNetOrientationSolver> | PipelineStep<typeof RailNetLabelCornerPlacementSolver> | PipelineStep<typeof TraceAnchoredNetLabelOverlapSolver> | PipelineStep<typeof NetLabelTraceCollisionSolver> | PipelineStep<typeof NetLabelNetLabelCollisionSolver> | PipelineStep<typeof SameNetJunctionAlignmentSolver> | PipelineStep<typeof InlineNetLabelSolver> | PipelineStep<typeof NetLabelToTraceSolver>)[];
1378
1412
  constructor(inputProblem: InputProblem, opts?: Options);
1379
1413
  getConstructorParams(): ConstructorParameters<typeof SchematicTracePipelineSolver>;
1380
1414
  currentPipelineStepIndex: number;
@@ -1390,4 +1424,4 @@ declare class SchematicTracePipelineSolver extends BaseSolver {
1390
1424
  preview(): GraphicsObject;
1391
1425
  }
1392
1426
 
1393
- export { type ChipId, DEFAULT_INLINE_NET_LABEL_HEIGHT, INLINE_NET_LABEL_MAX_SPAN_JOG, INLINE_NET_LABEL_STUB_TRACE_CLEARANCE, INLINE_NET_LABEL_TRACE_MARGIN, type InlineNetLabelPlacement, InlineNetLabelSolver, type InputChip, type InputDirectConnection, type InputNetConnection, type InputPin, type InputProblem, type NetId, type NetLabelPlacement, type PinId, SchematicTracePipelineSolver, SchematicTraceSingleLineSolver2, type SectionId, type TextBoxes, estimateInlineNetLabelWidth };
1427
+ export { type ChipId, DEFAULT_INLINE_NET_LABEL_HEIGHT, INLINE_NET_LABEL_MAX_SPAN_JOG, INLINE_NET_LABEL_STUB_TRACE_CLEARANCE, INLINE_NET_LABEL_TRACE_MARGIN, type InlineNetLabelOutput, type InlineNetLabelPlacement, InlineNetLabelSolver, type InputChip, type InputDirectConnection, type InputNetConnection, type InputPin, type InputProblem, type NetId, type NetLabelPlacement, type PinId, SchematicTracePipelineSolver, SchematicTraceSingleLineSolver2, type SectionId, type TextBoxes, estimateInlineNetLabelWidth, visualizeInlineNetLabelOutput };
package/dist/index.js CHANGED
@@ -13606,77 +13606,113 @@ var InlineNetLabelSolver = class extends BaseSolver {
13606
13606
  return this.buildPostProcessedOutput();
13607
13607
  }
13608
13608
  visualize() {
13609
- const graphics = visualizeInputProblem(this.inputProblem);
13610
- graphics.lines ??= [];
13611
- graphics.rects ??= [];
13612
- graphics.points ??= [];
13613
- graphics.texts ??= [];
13614
- const output = this.getOutput();
13615
- 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) {
13616
13652
  graphics.lines.push({
13617
- points: trace.tracePath,
13653
+ points: inlineLabel.stubTracePath,
13618
13654
  strokeColor: "purple"
13619
13655
  });
13620
13656
  }
13621
- const { netLabelPlacements } = this.getOutput();
13622
- for (const label of netLabelPlacements) {
13623
- graphics.rects.push({
13624
- center: label.center,
13625
- width: label.width,
13626
- height: label.height,
13627
- fill: getColorFromString(label.globalConnNetId, 0.35),
13628
- strokeColor: getColorFromString(label.globalConnNetId, 0.9),
13629
- label: `netId: ${label.netId}
13630
- globalConnNetId: ${label.globalConnNetId}`
13631
- });
13632
- graphics.points.push({
13633
- x: label.anchorPoint.x,
13634
- y: label.anchorPoint.y,
13635
- color: getColorFromString(label.globalConnNetId, 0.9),
13636
- label: `anchorPoint
13637
- orientation: ${label.orientation}`
13638
- });
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;
13639
13663
  }
13640
- for (const inlineLabel of this.inlineNetLabelPlacements) {
13641
- if (inlineLabel.stubTracePath) {
13642
- graphics.lines.push({
13643
- points: inlineLabel.stubTracePath,
13644
- strokeColor: "purple"
13645
- });
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;
13646
13694
  }
13647
- const isHorizontal4 = inlineLabel.axis === "x";
13648
- graphics.rects.push({
13649
- center: inlineLabel.center,
13650
- width: isHorizontal4 ? inlineLabel.width : inlineLabel.height,
13651
- height: isHorizontal4 ? inlineLabel.height : inlineLabel.width,
13652
- fill: getColorFromString(inlineLabel.globalConnNetId, 0.35),
13653
- strokeColor: "green",
13654
- label: [
13655
- `INLINE netId: ${inlineLabel.netId}`,
13656
- `axis: ${inlineLabel.axis}`,
13657
- `side: ${inlineLabel.side}`
13658
- ].join("\n")
13659
- });
13660
- graphics.texts.push({
13661
- 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,
13662
- 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,
13663
- text: inlineLabel.netLabelText ?? inlineLabel.netId ?? "",
13664
- color: "green",
13665
- fontSize: inlineLabel.height,
13666
- anchorSide: inlineLabel.stubTracePath ? inlineLabel.stubTracePath[1][inlineLabel.axis] > inlineLabel.stubTracePath[0][inlineLabel.axis] ? "center_left" : "center_right" : "center",
13667
- // Vertical labels read bottom-to-top, alongside the wire they name.
13668
- rotation: inlineLabel.axis === "y" ? 90 : void 0
13669
- });
13670
- graphics.points.push({
13671
- x: inlineLabel.anchorPoint.x,
13672
- y: inlineLabel.anchorPoint.y,
13673
- color: "green",
13674
- label: `inline anchor
13675
- ${inlineLabel.netLabelText ?? inlineLabel.netId}`
13676
- });
13677
13695
  }
13678
- 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
+ });
13679
13714
  }
13715
+ return graphics;
13680
13716
  };
13681
13717
  var estimateInlineNetLabelWidth = (text, fontSize = DEFAULT_INLINE_NET_LABEL_HEIGHT) => {
13682
13718
  const fontScale = fontSize / 0.18;
@@ -13762,6 +13798,250 @@ var getCollisionLimitedTerminalStubEnd = ({
13762
13798
  return isHorizontal4 ? { x: start.x + direction * availableLength, y: start.y } : { x: start.x, y: start.y + direction * availableLength };
13763
13799
  };
13764
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
+
13765
14045
  // lib/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver.ts
13766
14046
  function definePipelineStep(solverName, solverClass, getConstructorParams, opts = {}) {
13767
14047
  return {
@@ -13800,6 +14080,7 @@ var SchematicTracePipelineSolver = class extends BaseSolver {
13800
14080
  finalTraceElbowTransitionSimplificationSolver;
13801
14081
  sameNetJunctionAlignmentSolver;
13802
14082
  inlineNetLabelSolver;
14083
+ netLabelToTraceSolver;
13803
14084
  startTimeOfPhase;
13804
14085
  endTimeOfPhase;
13805
14086
  timeSpentOnPhase;
@@ -14211,6 +14492,19 @@ var SchematicTracePipelineSolver = class extends BaseSolver {
14211
14492
  }
14212
14493
  ];
14213
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
+ }
14214
14508
  )
14215
14509
  ];
14216
14510
  constructor(inputProblem, opts) {
@@ -14331,5 +14625,6 @@ export {
14331
14625
  InlineNetLabelSolver,
14332
14626
  SchematicTracePipelineSolver,
14333
14627
  SchematicTraceSingleLineSolver2,
14334
- estimateInlineNetLabelWidth
14628
+ estimateInlineNetLabelWidth,
14629
+ visualizeInlineNetLabelOutput
14335
14630
  };