@tscircuit/schematic-trace-solver 0.0.116 → 0.0.117

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
@@ -782,6 +782,8 @@ declare class AvailableNetOrientationSolver extends BaseSolver {
782
782
  private findValidCandidateInShiftColumn;
783
783
  private evaluateCandidate;
784
784
  private getCandidateConnectorTrace;
785
+ private isStandaloneSinglePinNetLabel;
786
+ private labelIntersectsDifferentNetTrace;
785
787
  private getSearchStartAnchor;
786
788
  private getWickOffsetAnchor;
787
789
  private getSideOffsetAnchor;
package/dist/index.js CHANGED
@@ -7895,6 +7895,34 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
7895
7895
  indices.push(i);
7896
7896
  }
7897
7897
  }
7898
+ const blockedStandaloneLabelIndex = indices.find((index) => {
7899
+ const label = this.outputNetLabelPlacements[index];
7900
+ const orientations = this.getAvailableOrientations(label);
7901
+ return this.isPortOnlyLabel(label) && this.isStandaloneSinglePinNetLabel(label) && orientations.length === 1 && isYOrientation(orientations[0]) && this.labelIntersectsDifferentNetTrace(label);
7902
+ });
7903
+ if (blockedStandaloneLabelIndex === void 0) return indices;
7904
+ const blockedLabel = this.outputNetLabelPlacements[blockedStandaloneLabelIndex];
7905
+ const requiredOrientation = this.getAvailableOrientations(blockedLabel)[0];
7906
+ const chipSide = this.getChipSideForPoint(blockedLabel.anchorPoint);
7907
+ const affectedSlots = [];
7908
+ const labelsToOrder = [];
7909
+ for (let slot = 0; slot < indices.length; slot++) {
7910
+ const index = indices[slot];
7911
+ const label = this.outputNetLabelPlacements[index];
7912
+ const orientations = this.getAvailableOrientations(label);
7913
+ if (this.getChipSideForPoint(label.anchorPoint) === chipSide && orientations.length === 1 && orientations[0] === requiredOrientation) {
7914
+ affectedSlots.push(slot);
7915
+ labelsToOrder.push(index);
7916
+ }
7917
+ }
7918
+ labelsToOrder.sort((a, b) => {
7919
+ const aY = this.outputNetLabelPlacements[a].anchorPoint.y;
7920
+ const bY = this.outputNetLabelPlacements[b].anchorPoint.y;
7921
+ return requiredOrientation === "y+" ? bY - aY : aY - bY;
7922
+ });
7923
+ for (let i = 0; i < affectedSlots.length; i++) {
7924
+ indices[affectedSlots[i]] = labelsToOrder[i];
7925
+ }
7898
7926
  return indices;
7899
7927
  }
7900
7928
  shouldProcessLabel(label) {
@@ -8213,6 +8241,28 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
8213
8241
  candidate.orientation
8214
8242
  );
8215
8243
  }
8244
+ isStandaloneSinglePinNetLabel(label) {
8245
+ return this.inputProblem.netConnections.some(
8246
+ (connection) => connection.netId === label.netId && connection.pinIds.length === 1 && connection.pinIds[0] === label.pinIds[0]
8247
+ );
8248
+ }
8249
+ labelIntersectsDifferentNetTrace(label) {
8250
+ const { width, height } = getDimsForOrientation({
8251
+ orientation: label.orientation,
8252
+ netLabelWidth: this.getNetLabelWidth(label),
8253
+ netLabelHeight: this.getNetLabelHeight(label)
8254
+ });
8255
+ const center = getCenterFromAnchor(
8256
+ label.anchorPoint,
8257
+ label.orientation,
8258
+ width,
8259
+ height
8260
+ );
8261
+ const bounds = getRectBounds(center, width, height);
8262
+ return Object.values(this.traceMap).some(
8263
+ (trace) => trace.globalConnNetId !== label.globalConnNetId && tracePathIntersectsBounds(trace.tracePath, bounds)
8264
+ );
8265
+ }
8216
8266
  getSearchStartAnchor(label, orientation) {
8217
8267
  const anchorPoint = this.getWickOffsetAnchor(label.anchorPoint, orientation);
8218
8268
  const { width, height } = getDimsForOrientation({
@@ -110,6 +110,52 @@ export class AvailableNetOrientationSolver extends BaseSolver {
110
110
  }
111
111
  }
112
112
 
113
+ const blockedStandaloneLabelIndex = indices.find((index) => {
114
+ const label = this.outputNetLabelPlacements[index]!
115
+ const orientations = this.getAvailableOrientations(label)
116
+ return (
117
+ this.isPortOnlyLabel(label) &&
118
+ this.isStandaloneSinglePinNetLabel(label) &&
119
+ orientations.length === 1 &&
120
+ isYOrientation(orientations[0]!) &&
121
+ this.labelIntersectsDifferentNetTrace(label)
122
+ )
123
+ })
124
+ if (blockedStandaloneLabelIndex === undefined) return indices
125
+
126
+ const blockedLabel =
127
+ this.outputNetLabelPlacements[blockedStandaloneLabelIndex]!
128
+ const requiredOrientation = this.getAvailableOrientations(blockedLabel)[0]!
129
+ const chipSide = this.getChipSideForPoint(blockedLabel.anchorPoint)
130
+ const affectedSlots: number[] = []
131
+ const labelsToOrder: number[] = []
132
+
133
+ for (let slot = 0; slot < indices.length; slot++) {
134
+ const index = indices[slot]!
135
+ const label = this.outputNetLabelPlacements[index]!
136
+ const orientations = this.getAvailableOrientations(label)
137
+ if (
138
+ this.getChipSideForPoint(label.anchorPoint) === chipSide &&
139
+ orientations.length === 1 &&
140
+ orientations[0] === requiredOrientation
141
+ ) {
142
+ affectedSlots.push(slot)
143
+ labelsToOrder.push(index)
144
+ }
145
+ }
146
+
147
+ // Place vertical labels on the same chip side from the outward end inward.
148
+ // The standalone label is corrected first, then a lower neighbor yields
149
+ // space during its own placement, keeping the standalone connector direct.
150
+ labelsToOrder.sort((a, b) => {
151
+ const aY = this.outputNetLabelPlacements[a]!.anchorPoint.y
152
+ const bY = this.outputNetLabelPlacements[b]!.anchorPoint.y
153
+ return requiredOrientation === "y+" ? bY - aY : aY - bY
154
+ })
155
+ for (let i = 0; i < affectedSlots.length; i++) {
156
+ indices[affectedSlots[i]!] = labelsToOrder[i]!
157
+ }
158
+
113
159
  return indices
114
160
  }
115
161
 
@@ -551,6 +597,35 @@ export class AvailableNetOrientationSolver extends BaseSolver {
551
597
  )
552
598
  }
553
599
 
600
+ private isStandaloneSinglePinNetLabel(label: NetLabelPlacement) {
601
+ return this.inputProblem.netConnections.some(
602
+ (connection) =>
603
+ connection.netId === label.netId &&
604
+ connection.pinIds.length === 1 &&
605
+ connection.pinIds[0] === label.pinIds[0],
606
+ )
607
+ }
608
+
609
+ private labelIntersectsDifferentNetTrace(label: NetLabelPlacement) {
610
+ const { width, height } = getDimsForOrientation({
611
+ orientation: label.orientation,
612
+ netLabelWidth: this.getNetLabelWidth(label),
613
+ netLabelHeight: this.getNetLabelHeight(label),
614
+ })
615
+ const center = getCenterFromAnchor(
616
+ label.anchorPoint,
617
+ label.orientation,
618
+ width,
619
+ height,
620
+ )
621
+ const bounds = getRectBounds(center, width, height)
622
+ return Object.values(this.traceMap).some(
623
+ (trace) =>
624
+ trace.globalConnNetId !== label.globalConnNetId &&
625
+ tracePathIntersectsBounds(trace.tracePath, bounds),
626
+ )
627
+ }
628
+
554
629
  private getSearchStartAnchor(
555
630
  label: NetLabelPlacement,
556
631
  orientation: FacingDirection,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tscircuit/schematic-trace-solver",
3
3
  "main": "dist/index.js",
4
- "version": "0.0.116",
4
+ "version": "0.0.117",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "start": "cosmos",
@@ -0,0 +1,4 @@
1
+ import { PipelineDebugger } from "site/components/PipelineDebugger"
2
+ import inputProblem from "../../tests/bug-reports/bug-report-20260731T052229Z/bug-report-20260731T052229Z.json"
3
+
4
+ export default () => <PipelineDebugger inputProblem={inputProblem as any} />
@@ -0,0 +1,93 @@
1
+ <svg width="640" height="640" viewBox="0 0 640 640" xmlns="http://www.w3.org/2000/svg"><rect width="100%" height="100%" fill="white"/><g><polyline data-points="-1.9,2.550000000000001 -1.9,2.350000000000001" data-type="line" data-label="" points="216.96369636963695,85.28052805280515 216.96369636963695,103.76237623762367" fill="none" stroke="hsl(124, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="-1.9,2.550000000000001 -1.9,2.1500000000000012" data-type="line" data-label="" points="216.96369636963695,85.28052805280515 216.96369636963695,122.24422442244213" fill="none" stroke="hsl(124, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="-1.9,2.350000000000001 -1.9,2.1500000000000012" data-type="line" data-label="" points="216.96369636963695,103.76237623762367 216.96369636963695,122.24422442244213" fill="none" stroke="hsl(124, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="-1.9,0.7500000000000013 -1.9,0.5500000000000014" data-type="line" data-label="" points="216.96369636963695,251.6171617161715 216.96369636963695,270.09900990099" fill="none" stroke="hsl(44, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="-1.9,1.950000000000001 -1.9,1.750000000000001" data-type="line" data-label="" points="216.96369636963695,140.72607260726062 216.96369636963695,159.2079207920791" fill="none" stroke="hsl(125, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="-1.9,1.950000000000001 -1.9,1.5500000000000012" data-type="line" data-label="" points="216.96369636963695,140.72607260726062 216.96369636963695,177.68976897689757" fill="none" stroke="hsl(125, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="-1.9,1.950000000000001 -1.9,1.3500000000000012" data-type="line" data-label="" points="216.96369636963695,140.72607260726062 216.96369636963695,196.17161716171606" fill="none" stroke="hsl(125, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="-1.9,1.750000000000001 -1.9,1.5500000000000012" data-type="line" data-label="" points="216.96369636963695,159.2079207920791 216.96369636963695,177.68976897689757" fill="none" stroke="hsl(125, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="-1.9,1.750000000000001 -1.9,1.3500000000000012" data-type="line" data-label="" points="216.96369636963695,159.2079207920791 216.96369636963695,196.17161716171606" fill="none" stroke="hsl(125, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="-1.9,1.5500000000000012 -1.9,1.3500000000000012" data-type="line" data-label="" points="216.96369636963695,177.68976897689757 216.96369636963695,196.17161716171606" fill="none" stroke="hsl(125, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="-1.9,2.350000000000001 -2.0999999999999996,2.350000000000001 -2.0999999999999996,2.550000000000001 -1.9,2.550000000000001" data-type="line" data-label="" points="216.96369636963695,103.76237623762367 198.4818481848185,103.76237623762367 198.4818481848185,85.28052805280515 216.96369636963695,85.28052805280515" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="-1.9,2.1500000000000012 -2.0999999999999996,2.1500000000000012 -2.0999999999999996,2.350000000000001 -1.9,2.350000000000001" data-type="line" data-label="" points="216.96369636963695,122.24422442244213 198.4818481848185,122.24422442244213 198.4818481848185,103.76237623762367 216.96369636963695,103.76237623762367" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="-1.9,0.7500000000000013 -2.0999999999999996,0.7500000000000013 -2.0999999999999996,0.5500000000000014 -1.9,0.5500000000000014" data-type="line" data-label="" points="216.96369636963695,251.6171617161715 198.4818481848185,251.6171617161715 198.4818481848185,270.09900990099 216.96369636963695,270.09900990099" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="-1.9,1.750000000000001 -2.0999999999999996,1.750000000000001 -2.0999999999999996,1.950000000000001 -1.9,1.950000000000001" data-type="line" data-label="" points="216.96369636963695,159.2079207920791 198.4818481848185,159.2079207920791 198.4818481848185,140.72607260726062 216.96369636963695,140.72607260726062" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="-1.9,1.5500000000000012 -2.0999999999999996,1.5500000000000012 -2.0999999999999996,1.750000000000001 -1.9,1.750000000000001" data-type="line" data-label="" points="216.96369636963695,177.68976897689757 198.4818481848185,177.68976897689757 198.4818481848185,159.2079207920791 216.96369636963695,159.2079207920791" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="-1.9,1.3500000000000012 -2.0999999999999996,1.3500000000000012 -2.0999999999999996,1.5500000000000012 -1.9,1.5500000000000012" data-type="line" data-label="" points="216.96369636963695,196.17161716171606 198.4818481848185,196.17161716171606 198.4818481848185,177.68976897689757 216.96369636963695,177.68976897689757" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="-2.0999999999999996,2.350000000000001 -2.4499999999999993,2.350000000000001 -2.4499999999999993,2.351000000000001" data-type="line" data-label="" points="198.4818481848185,103.76237623762367 166.13861386138618,103.76237623762367 166.13861386138618,103.66996699669957" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="-2.0999999999999996,1.750000000000001 -2.4499999999999993,1.750000000000001 -2.4499999999999993,1.751000000000001" data-type="line" data-label="" points="198.4818481848185,159.2079207920791 166.13861386138618,159.2079207920791 166.13861386138618,159.115511551155" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="-1.9,1.1500000000000012 -2.401,1.1500000000000012 -2.401,1.2010000000000012" data-type="line" data-label="" points="216.96369636963695,214.65346534653452 170.66666666666666,214.65346534653452 170.66666666666666,209.94059405940584" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="-2.0999999999999996,0.7500000000000013 -3.1099999999999994,0.7500000000000013 -3.1099999999999994,0.8010000000000014" data-type="line" data-label="" points="198.4818481848185,251.6171617161715 105.14851485148517,251.6171617161715 105.14851485148517,246.90429042904276" fill="none" stroke="purple" stroke-width="1px"/></g><g><rect data-type="rect" data-label="schematic_component_0" data-x="0" data-y="0" x="216.96369636963698" y="62.1782178217822" width="351.1551155115511" height="517.4917491749175" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.01082142857142857"/></g><g><rect data-type="rect" data-label="CC2745R10E0WRHARQ1" data-x="-0.41999999999999993" data-y="-2.9299999999999997" x="253.92739273927387" y="583.3663366336633" width="199.60396039603967" height="16.633663366336577" fill="rgba(160, 0, 220, 0.14)" stroke="black" stroke-width="0.01082142857142857"/></g><g><rect data-type="rect" data-label="U1" data-x="-1.38" data-y="2.915" x="248.3828382838284" y="39.99999999999997" width="33.2673267326733" height="23.10231023102307" fill="rgba(160, 0, 220, 0.14)" stroke="black" stroke-width="0.01082142857142857"/></g><g><rect data-type="rect" data-label="netId: VDDR
2
+ globalConnNetId: connectivity_net0" data-x="-2.4499999999999993" data-y="2.561000000000001" x="138.41584158415847" y="64.85808580858078" width="55.44554455445541" height="38.811881188118804" fill="#ef444466" stroke="#ef4444" stroke-width="0.01082142857142857"/></g><g><rect data-type="rect" data-label="netId: VDDIO
3
+ globalConnNetId: connectivity_net1" data-x="-3.1099999999999994" data-y="1.0110000000000015" x="71.8811881188119" y="208.09240924092393" width="66.53465346534654" height="38.811881188118804" fill="#ef444466" stroke="#ef4444" stroke-width="0.01082142857142857"/></g><g><rect data-type="rect" data-label="netId: VDDS
4
+ globalConnNetId: connectivity_net2" data-x="-2.4499999999999993" data-y="1.961000000000001" x="138.41584158415847" y="120.3036303630362" width="55.44554455445541" height="38.81188118811883" fill="#ef444466" stroke="#ef4444" stroke-width="0.01082142857142857"/></g><g><rect data-type="rect" data-label="netId: VDDD
5
+ globalConnNetId: connectivity_net3" data-x="-2.401" data-y="1.4110000000000011" x="142.94389438943895" y="171.128712871287" width="55.44554455445541" height="38.81188118811883" fill="#ef444466" stroke="#ef4444" stroke-width="0.01082142857142857"/></g><g><circle data-type="point" data-label="schematic_port_0
6
+ x-" data-x="-1.9" data-y="2.550000000000001" cx="216.96369636963695" cy="85.28052805280515" r="3" fill="hsl(248, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_1
7
+ x-" data-x="-1.9" data-y="2.350000000000001" cx="216.96369636963695" cy="103.76237623762367" r="3" fill="hsl(248, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_2
8
+ x+" data-x="1.9" data-y="1.7500000000000004" cx="568.1188118811881" cy="159.20792079207916" r="3" fill="hsl(248, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_3
9
+ x+" data-x="1.9" data-y="1.5500000000000003" cx="568.1188118811881" cy="177.68976897689765" r="3" fill="hsl(248, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_4
10
+ x+" data-x="1.9" data-y="1.3500000000000005" cx="568.1188118811881" cy="196.1716171617161" r="3" fill="hsl(248, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_5
11
+ x+" data-x="1.9" data-y="1.1500000000000004" cx="568.1188118811881" cy="214.65346534653463" r="3" fill="hsl(248, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_6
12
+ x+" data-x="1.9" data-y="0.9500000000000002" cx="568.1188118811881" cy="233.13531353135312" r="3" fill="hsl(248, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_7
13
+ x+" data-x="1.9" data-y="0.75" cx="568.1188118811881" cy="251.6171617161716" r="3" fill="hsl(248, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_8
14
+ x-" data-x="-1.9" data-y="0.7500000000000013" cx="216.96369636963695" cy="251.6171617161715" r="3" fill="hsl(248, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_9
15
+ x+" data-x="1.9" data-y="0.5499999999999998" cx="568.1188118811881" cy="270.0990099009901" r="3" fill="hsl(248, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_10
16
+ x+" data-x="1.9" data-y="0.34999999999999964" cx="568.1188118811881" cy="288.5808580858086" r="3" fill="hsl(184, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_11
17
+ x+" data-x="1.9" data-y="0.14999999999999947" cx="568.1188118811881" cy="307.06270627062713" r="3" fill="hsl(184, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_12
18
+ x+" data-x="1.9" data-y="-0.05000000000000071" cx="568.1188118811881" cy="325.5445544554456" r="3" fill="hsl(184, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_13
19
+ x+" data-x="1.9" data-y="-0.2500000000000009" cx="568.1188118811881" cy="344.0264026402641" r="3" fill="hsl(184, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_14
20
+ x+" data-x="1.9" data-y="-0.45000000000000107" cx="568.1188118811881" cy="362.5082508250826" r="3" fill="hsl(184, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_15
21
+ x+" data-x="1.9" data-y="-0.6500000000000012" cx="568.1188118811881" cy="380.9900990099011" r="3" fill="hsl(184, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_16
22
+ x-" data-x="-1.9" data-y="0.5500000000000014" cx="216.96369636963695" cy="270.09900990099" r="3" fill="hsl(184, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_17
23
+ x-" data-x="-1.9" data-y="1.950000000000001" cx="216.96369636963695" cy="140.72607260726062" r="3" fill="hsl(184, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_18
24
+ x-" data-x="-1.9" data-y="0.15000000000000124" cx="216.96369636963695" cy="307.06270627062696" r="3" fill="hsl(184, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_19
25
+ x-" data-x="-1.9" data-y="-0.049999999999998934" cx="216.96369636963695" cy="325.54455445544545" r="3" fill="hsl(184, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_20
26
+ x-" data-x="-1.9" data-y="-0.2499999999999991" cx="216.96369636963695" cy="344.02640264026394" r="3" fill="hsl(184, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_21
27
+ x-" data-x="-1.9" data-y="-0.4499999999999993" cx="216.96369636963695" cy="362.5082508250824" r="3" fill="hsl(184, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_22
28
+ x-" data-x="-1.9" data-y="-0.6499999999999995" cx="216.96369636963695" cy="380.990099009901" r="3" fill="hsl(184, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_23
29
+ x-" data-x="-1.9" data-y="-0.8499999999999996" cx="216.96369636963695" cy="399.47194719471946" r="3" fill="hsl(184, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_24
30
+ x+" data-x="1.9" data-y="2.150000000000001" cx="568.1188118811881" cy="122.24422442244216" r="3" fill="hsl(184, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_25
31
+ x-" data-x="-1.9" data-y="-1.65" cx="216.96369636963695" cy="473.3993399339934" r="3" fill="hsl(184, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_26
32
+ x-" data-x="-1.9" data-y="-2.2500000000000004" cx="216.96369636963695" cy="528.8448844884489" r="3" fill="hsl(184, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_27
33
+ x-" data-x="-1.9" data-y="1.1500000000000012" cx="216.96369636963695" cy="214.65346534653452" r="3" fill="hsl(184, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_28
34
+ x-" data-x="-1.9" data-y="1.750000000000001" cx="216.96369636963695" cy="159.2079207920791" r="3" fill="hsl(184, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_29
35
+ x-" data-x="-1.9" data-y="-2.650000000000001" cx="216.96369636963695" cy="565.8085808580859" r="3" fill="hsl(184, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_30
36
+ x-" data-x="-1.9" data-y="1.5500000000000012" cx="216.96369636963695" cy="177.68976897689757" r="3" fill="hsl(184, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_31
37
+ x-" data-x="-1.9" data-y="-1.0499999999999998" cx="216.96369636963695" cy="417.95379537953795" r="3" fill="hsl(184, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_32
38
+ x-" data-x="-1.9" data-y="-1.25" cx="216.96369636963695" cy="436.43564356435644" r="3" fill="hsl(184, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_33
39
+ x-" data-x="-1.9" data-y="2.1500000000000012" cx="216.96369636963695" cy="122.24422442244213" r="3" fill="hsl(184, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_34
40
+ x+" data-x="1.9" data-y="-1.0500000000000012" cx="568.1188118811881" cy="417.95379537953806" r="3" fill="hsl(184, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_35
41
+ x+" data-x="1.9" data-y="-1.6500000000000012" cx="568.1188118811881" cy="473.39933993399353" r="3" fill="hsl(184, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_36
42
+ x+" data-x="1.9" data-y="-2.050000000000001" cx="568.1188118811881" cy="510.36303630363045" r="3" fill="hsl(184, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_37
43
+ x-" data-x="-1.9" data-y="1.3500000000000012" cx="216.96369636963695" cy="196.17161716171606" r="3" fill="hsl(184, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_38
44
+ x+" data-x="1.9" data-y="2.550000000000001" cx="568.1188118811881" cy="85.28052805280515" r="3" fill="hsl(184, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_39
45
+ x+" data-x="1.9" data-y="-2.450000000000001" cx="568.1188118811881" cy="547.3267326732674" r="3" fill="hsl(184, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="schematic_port_40
46
+ x+" data-x="1.9" data-y="-2.6500000000000012" cx="568.1188118811881" cy="565.808580858086" r="3" fill="hsl(184, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="anchorPoint
47
+ orientation: y+" data-x="-2.4499999999999993" data-y="2.351000000000001" cx="166.13861386138618" cy="103.66996699669957" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g><circle data-type="point" data-label="anchorPoint
48
+ orientation: y+" data-x="-3.1099999999999994" data-y="0.8010000000000014" cx="105.14851485148517" cy="246.90429042904276" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g><circle data-type="point" data-label="anchorPoint
49
+ orientation: y+" data-x="-2.4499999999999993" data-y="1.751000000000001" cx="166.13861386138618" cy="159.115511551155" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g><circle data-type="point" data-label="anchorPoint
50
+ orientation: y+" data-x="-2.401" data-y="1.2010000000000012" cx="170.66666666666666" cy="209.94059405940584" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g id="crosshair" style="display: none"><line id="crosshair-h" y1="0" y2="640" stroke="#666" stroke-width="0.5"/><line id="crosshair-v" x1="0" x2="640" stroke="#666" stroke-width="0.5"/><text id="coordinates" font-family="monospace" font-size="12" fill="#666"></text></g><script><![CDATA[
51
+ document.currentScript.parentElement.addEventListener('mousemove', (e) => {
52
+ const svg = e.currentTarget;
53
+ const rect = svg.getBoundingClientRect();
54
+ const x = e.clientX - rect.left;
55
+ const y = e.clientY - rect.top;
56
+ const crosshair = svg.getElementById('crosshair');
57
+ const h = svg.getElementById('crosshair-h');
58
+ const v = svg.getElementById('crosshair-v');
59
+ const coords = svg.getElementById('coordinates');
60
+
61
+ crosshair.style.display = 'block';
62
+ h.setAttribute('x1', '0');
63
+ h.setAttribute('x2', '640');
64
+ h.setAttribute('y1', y);
65
+ h.setAttribute('y2', y);
66
+ v.setAttribute('x1', x);
67
+ v.setAttribute('x2', x);
68
+ v.setAttribute('y1', '0');
69
+ v.setAttribute('y2', '640');
70
+
71
+ // Calculate real coordinates using inverse transformation
72
+ const matrix = {"a":92.40924092409242,"c":0,"e":392.54125412541254,"b":0,"d":-92.40924092409242,"f":320.9240924092409};
73
+ // Manually invert and apply the affine transform
74
+ // Since we only use translate and scale, we can directly compute:
75
+ // x' = (x - tx) / sx
76
+ // y' = (y - ty) / sy
77
+ const sx = matrix.a;
78
+ const sy = matrix.d;
79
+ const tx = matrix.e;
80
+ const ty = matrix.f;
81
+ const realPoint = {
82
+ x: (x - tx) / sx,
83
+ y: (y - ty) / sy // Flip y back since we used negative scale
84
+ }
85
+
86
+ coords.textContent = `(${realPoint.x.toFixed(2)}, ${realPoint.y.toFixed(2)})`;
87
+ coords.setAttribute('x', (x + 5).toString());
88
+ coords.setAttribute('y', (y - 5).toString());
89
+ });
90
+ document.currentScript.parentElement.addEventListener('mouseleave', () => {
91
+ document.currentScript.parentElement.getElementById('crosshair').style.display = 'none';
92
+ });
93
+ ]]></script></svg>
@@ -0,0 +1,299 @@
1
+ {
2
+ "chips": [
3
+ {
4
+ "chipId": "schematic_component_0",
5
+ "center": {
6
+ "x": 0,
7
+ "y": 0
8
+ },
9
+ "width": 3.8,
10
+ "height": 5.6,
11
+ "pins": [
12
+ {
13
+ "pinId": "schematic_port_0",
14
+ "x": -1.9,
15
+ "y": 2.550000000000001
16
+ },
17
+ {
18
+ "pinId": "schematic_port_1",
19
+ "x": -1.9,
20
+ "y": 2.350000000000001
21
+ },
22
+ {
23
+ "pinId": "schematic_port_2",
24
+ "x": 1.9,
25
+ "y": 1.7500000000000004
26
+ },
27
+ {
28
+ "pinId": "schematic_port_3",
29
+ "x": 1.9,
30
+ "y": 1.5500000000000003
31
+ },
32
+ {
33
+ "pinId": "schematic_port_4",
34
+ "x": 1.9,
35
+ "y": 1.3500000000000005
36
+ },
37
+ {
38
+ "pinId": "schematic_port_5",
39
+ "x": 1.9,
40
+ "y": 1.1500000000000004
41
+ },
42
+ {
43
+ "pinId": "schematic_port_6",
44
+ "x": 1.9,
45
+ "y": 0.9500000000000002
46
+ },
47
+ {
48
+ "pinId": "schematic_port_7",
49
+ "x": 1.9,
50
+ "y": 0.75
51
+ },
52
+ {
53
+ "pinId": "schematic_port_8",
54
+ "x": -1.9,
55
+ "y": 0.7500000000000013
56
+ },
57
+ {
58
+ "pinId": "schematic_port_9",
59
+ "x": 1.9,
60
+ "y": 0.5499999999999998
61
+ },
62
+ {
63
+ "pinId": "schematic_port_10",
64
+ "x": 1.9,
65
+ "y": 0.34999999999999964
66
+ },
67
+ {
68
+ "pinId": "schematic_port_11",
69
+ "x": 1.9,
70
+ "y": 0.14999999999999947
71
+ },
72
+ {
73
+ "pinId": "schematic_port_12",
74
+ "x": 1.9,
75
+ "y": -0.05000000000000071
76
+ },
77
+ {
78
+ "pinId": "schematic_port_13",
79
+ "x": 1.9,
80
+ "y": -0.2500000000000009
81
+ },
82
+ {
83
+ "pinId": "schematic_port_14",
84
+ "x": 1.9,
85
+ "y": -0.45000000000000107
86
+ },
87
+ {
88
+ "pinId": "schematic_port_15",
89
+ "x": 1.9,
90
+ "y": -0.6500000000000012
91
+ },
92
+ {
93
+ "pinId": "schematic_port_16",
94
+ "x": -1.9,
95
+ "y": 0.5500000000000014
96
+ },
97
+ {
98
+ "pinId": "schematic_port_17",
99
+ "x": -1.9,
100
+ "y": 1.950000000000001
101
+ },
102
+ {
103
+ "pinId": "schematic_port_18",
104
+ "x": -1.9,
105
+ "y": 0.15000000000000124
106
+ },
107
+ {
108
+ "pinId": "schematic_port_19",
109
+ "x": -1.9,
110
+ "y": -0.049999999999998934
111
+ },
112
+ {
113
+ "pinId": "schematic_port_20",
114
+ "x": -1.9,
115
+ "y": -0.2499999999999991
116
+ },
117
+ {
118
+ "pinId": "schematic_port_21",
119
+ "x": -1.9,
120
+ "y": -0.4499999999999993
121
+ },
122
+ {
123
+ "pinId": "schematic_port_22",
124
+ "x": -1.9,
125
+ "y": -0.6499999999999995
126
+ },
127
+ {
128
+ "pinId": "schematic_port_23",
129
+ "x": -1.9,
130
+ "y": -0.8499999999999996
131
+ },
132
+ {
133
+ "pinId": "schematic_port_24",
134
+ "x": 1.9,
135
+ "y": 2.150000000000001
136
+ },
137
+ {
138
+ "pinId": "schematic_port_25",
139
+ "x": -1.9,
140
+ "y": -1.65
141
+ },
142
+ {
143
+ "pinId": "schematic_port_26",
144
+ "x": -1.9,
145
+ "y": -2.2500000000000004
146
+ },
147
+ {
148
+ "pinId": "schematic_port_27",
149
+ "x": -1.9,
150
+ "y": 1.1500000000000012
151
+ },
152
+ {
153
+ "pinId": "schematic_port_28",
154
+ "x": -1.9,
155
+ "y": 1.750000000000001
156
+ },
157
+ {
158
+ "pinId": "schematic_port_29",
159
+ "x": -1.9,
160
+ "y": -2.650000000000001
161
+ },
162
+ {
163
+ "pinId": "schematic_port_30",
164
+ "x": -1.9,
165
+ "y": 1.5500000000000012
166
+ },
167
+ {
168
+ "pinId": "schematic_port_31",
169
+ "x": -1.9,
170
+ "y": -1.0499999999999998
171
+ },
172
+ {
173
+ "pinId": "schematic_port_32",
174
+ "x": -1.9,
175
+ "y": -1.25
176
+ },
177
+ {
178
+ "pinId": "schematic_port_33",
179
+ "x": -1.9,
180
+ "y": 2.1500000000000012
181
+ },
182
+ {
183
+ "pinId": "schematic_port_34",
184
+ "x": 1.9,
185
+ "y": -1.0500000000000012
186
+ },
187
+ {
188
+ "pinId": "schematic_port_35",
189
+ "x": 1.9,
190
+ "y": -1.6500000000000012
191
+ },
192
+ {
193
+ "pinId": "schematic_port_36",
194
+ "x": 1.9,
195
+ "y": -2.050000000000001
196
+ },
197
+ {
198
+ "pinId": "schematic_port_37",
199
+ "x": -1.9,
200
+ "y": 1.3500000000000012
201
+ },
202
+ {
203
+ "pinId": "schematic_port_38",
204
+ "x": 1.9,
205
+ "y": 2.550000000000001
206
+ },
207
+ {
208
+ "pinId": "schematic_port_39",
209
+ "x": 1.9,
210
+ "y": -2.450000000000001
211
+ },
212
+ {
213
+ "pinId": "schematic_port_40",
214
+ "x": 1.9,
215
+ "y": -2.6500000000000012
216
+ }
217
+ ]
218
+ }
219
+ ],
220
+ "directConnections": [],
221
+ "netConnections": [
222
+ {
223
+ "netId": "VDDR",
224
+ "netLabelWidth": 0.42,
225
+ "netLabelHeight": 0.6,
226
+ "pinIds": [
227
+ "schematic_port_0",
228
+ "schematic_port_1",
229
+ "schematic_port_33"
230
+ ]
231
+ },
232
+ {
233
+ "netId": "VDDIO",
234
+ "netLabelWidth": 0.42,
235
+ "netLabelHeight": 0.72,
236
+ "pinIds": [
237
+ "schematic_port_8",
238
+ "schematic_port_16"
239
+ ]
240
+ },
241
+ {
242
+ "netId": "VDDS",
243
+ "netLabelWidth": 0.42,
244
+ "netLabelHeight": 0.6,
245
+ "pinIds": [
246
+ "schematic_port_17",
247
+ "schematic_port_28",
248
+ "schematic_port_30",
249
+ "schematic_port_37"
250
+ ]
251
+ },
252
+ {
253
+ "netId": "VDDD",
254
+ "netLabelWidth": 0.42,
255
+ "netLabelHeight": 0.6,
256
+ "pinIds": [
257
+ "schematic_port_27"
258
+ ]
259
+ }
260
+ ],
261
+ "textBoxes": [
262
+ {
263
+ "chipId": "schematic_component_0",
264
+ "center": {
265
+ "x": -0.41999999999999993,
266
+ "y": -2.9299999999999997
267
+ },
268
+ "width": 2.16,
269
+ "height": 0.17999999999999972,
270
+ "text": "CC2745R10E0WRHARQ1"
271
+ },
272
+ {
273
+ "chipId": "schematic_component_0",
274
+ "center": {
275
+ "x": -1.38,
276
+ "y": 2.915
277
+ },
278
+ "width": 0.3600000000000001,
279
+ "height": 0.24999999999999956,
280
+ "text": "U1"
281
+ }
282
+ ],
283
+ "availableNetLabelOrientations": {
284
+ "VDDR": [
285
+ "y+"
286
+ ],
287
+ "VDDS": [
288
+ "y+"
289
+ ],
290
+ "VDDD": [
291
+ "y+"
292
+ ],
293
+ "VDDIO": [
294
+ "y+"
295
+ ]
296
+ },
297
+ "maxMspPairDistance": 2.4,
298
+ "_hideRatsNet": false
299
+ }
@@ -0,0 +1,43 @@
1
+ import { expect, test } from "bun:test"
2
+ import { segmentIntersectsRect } from "lib/solvers/NetLabelPlacementSolver/SingleNetLabelPlacementSolver/collisions"
3
+ import { getRectBounds } from "lib/solvers/NetLabelPlacementSolver/SingleNetLabelPlacementSolver/geometry"
4
+ import { SchematicTracePipelineSolver } from "lib/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver"
5
+ import inputProblem from "./bug-report-20260731T052229Z.json"
6
+ import "tests/fixtures/matcher"
7
+
8
+ test("bug-report-20260731T052229Z", () => {
9
+ const solver = new SchematicTracePipelineSolver(inputProblem as any)
10
+
11
+ solver.solve()
12
+
13
+ const output = solver.sameNetJunctionAlignmentSolver!.getOutput()
14
+ const vdddLabel = output.netLabelPlacements.find(
15
+ (placement) => placement.netId === "VDDD",
16
+ )!
17
+ const vdddBounds = getRectBounds(
18
+ vdddLabel.center,
19
+ vdddLabel.width,
20
+ vdddLabel.height,
21
+ )
22
+ const intersectingDifferentNetTraceIds = output.traces
23
+ .filter((trace) => trace.globalConnNetId !== vdddLabel.globalConnNetId)
24
+ .filter((trace) =>
25
+ trace.tracePath.some(
26
+ (point, index) =>
27
+ index < trace.tracePath.length - 1 &&
28
+ segmentIntersectsRect(point, trace.tracePath[index + 1]!, vdddBounds),
29
+ ),
30
+ )
31
+ .map((trace) => trace.mspPairId)
32
+ const vdddConnector = output.traces.find(
33
+ (trace) =>
34
+ trace.userNetId === "VDDD" &&
35
+ trace.mspPairId.startsWith("available-net-orientation-"),
36
+ )!
37
+
38
+ expect(vdddLabel.orientation).toBe("y+")
39
+ expect(intersectingDifferentNetTraceIds).toEqual([])
40
+ expect(vdddConnector.tracePath).toHaveLength(3)
41
+ expect(vdddConnector.tracePath[0]!.y).toBe(vdddConnector.tracePath[1]!.y)
42
+ expect(solver).toMatchSolverSnapshot(import.meta.path)
43
+ })