@tscircuit/schematic-trace-solver 0.0.63 → 0.0.64

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
@@ -704,6 +704,7 @@ declare class AvailableNetOrientationSolver extends BaseSolver {
704
704
  private findValidLateralShiftedCandidate;
705
705
  private findValidCandidateInShiftColumn;
706
706
  private evaluateCandidate;
707
+ private getCandidateConnectorTrace;
707
708
  private getSearchStartAnchor;
708
709
  private getWickOffsetAnchor;
709
710
  private getSideOffsetAnchor;
package/dist/index.js CHANGED
@@ -5636,6 +5636,14 @@ var tracePathCrossesAnyBounds = (tracePath, bounds) => {
5636
5636
  }
5637
5637
  return false;
5638
5638
  };
5639
+ var tracePathIntersectsBounds = (tracePath, bounds) => {
5640
+ for (let i = 0; i < tracePath.length - 1; i++) {
5641
+ if (segmentIntersectsRect2(tracePath[i], tracePath[i + 1], bounds)) {
5642
+ return true;
5643
+ }
5644
+ }
5645
+ return false;
5646
+ };
5639
5647
  var tracePathCrossesAnyTrace = (tracePath, traceMap) => {
5640
5648
  for (const trace of Object.values(traceMap)) {
5641
5649
  const points = trace.tracePath;
@@ -5900,28 +5908,7 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
5900
5908
  this.addConnectorTrace(label, candidate, labelIndex);
5901
5909
  }
5902
5910
  addConnectorTrace(label, candidate, labelIndex) {
5903
- let tracePath;
5904
- if (candidate.phase === "lateral-shift") {
5905
- const orientDir = dir(candidate.orientation);
5906
- const kickedSource = {
5907
- x: label.anchorPoint.x - orientDir.x * LABEL_SEARCH_STEP,
5908
- y: label.anchorPoint.y - orientDir.y * LABEL_SEARCH_STEP
5909
- };
5910
- tracePath = simplifyOrthogonalPath([
5911
- label.anchorPoint,
5912
- ...getConnectorTracePath(
5913
- kickedSource,
5914
- candidate.anchorPoint,
5915
- candidate.orientation
5916
- )
5917
- ]);
5918
- } else {
5919
- tracePath = getConnectorTracePath(
5920
- label.anchorPoint,
5921
- candidate.anchorPoint,
5922
- candidate.orientation
5923
- );
5924
- }
5911
+ const tracePath = this.getCandidateConnectorTrace(label, candidate);
5925
5912
  if (tracePath.length < 2) return;
5926
5913
  const mspPairId = `available-net-orientation-${labelIndex}-${label.netId ?? label.globalConnNetId}`;
5927
5914
  const connectorTrace = {
@@ -6104,9 +6091,36 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
6104
6091
  distance: distance3,
6105
6092
  outwardDistance,
6106
6093
  selected: false,
6107
- status: this.getCandidateStatus(candidate, label, labelIndex)
6094
+ status: this.getCandidateStatus({
6095
+ candidate,
6096
+ label,
6097
+ labelIndex,
6098
+ phase
6099
+ })
6108
6100
  };
6109
6101
  }
6102
+ getCandidateConnectorTrace(label, candidate) {
6103
+ if (candidate.phase === "lateral-shift") {
6104
+ const orientDir = dir(candidate.orientation);
6105
+ const kickedSource = {
6106
+ x: label.anchorPoint.x - orientDir.x * LABEL_SEARCH_STEP,
6107
+ y: label.anchorPoint.y - orientDir.y * LABEL_SEARCH_STEP
6108
+ };
6109
+ return simplifyOrthogonalPath([
6110
+ label.anchorPoint,
6111
+ ...getConnectorTracePath(
6112
+ kickedSource,
6113
+ candidate.anchorPoint,
6114
+ candidate.orientation
6115
+ )
6116
+ ]);
6117
+ }
6118
+ return getConnectorTracePath(
6119
+ label.anchorPoint,
6120
+ candidate.anchorPoint,
6121
+ candidate.orientation
6122
+ );
6123
+ }
6110
6124
  getSearchStartAnchor(label, orientation) {
6111
6125
  const anchorPoint = this.getWickOffsetAnchor(label.anchorPoint, orientation);
6112
6126
  const { width, height } = getDimsForOrientation({
@@ -6226,17 +6240,18 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
6226
6240
  (nc) => nc.pinIds.some((pid) => label.pinIds.includes(pid))
6227
6241
  )?.netLabelHeight;
6228
6242
  }
6229
- getCandidateStatus(candidate, label, labelIndex) {
6243
+ getCandidateStatus(params) {
6244
+ const { candidate, label, labelIndex, phase } = params;
6230
6245
  const boundsStatus = this.getBoundsStatus(
6231
6246
  getRectBounds(candidate.center, candidate.width, candidate.height),
6232
6247
  labelIndex
6233
6248
  );
6234
6249
  if (boundsStatus !== "valid") return boundsStatus;
6235
- const connectorTrace = getConnectorTracePath(
6236
- label.anchorPoint,
6237
- candidate.anchorPoint,
6238
- candidate.orientation
6239
- );
6250
+ const connectorTrace = this.getCandidateConnectorTrace(label, {
6251
+ anchorPoint: candidate.anchorPoint,
6252
+ orientation: candidate.orientation,
6253
+ phase
6254
+ });
6240
6255
  if (tracePathCrossesAnyTrace(connectorTrace, this.traceMap)) {
6241
6256
  return "trace-collision";
6242
6257
  }
@@ -6248,7 +6263,7 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
6248
6263
  for (let i = 0; i < this.outputNetLabelPlacements.length; i++) {
6249
6264
  if (i === labelIndex) continue;
6250
6265
  const otherLabel = this.outputNetLabelPlacements[i];
6251
- if (tracePathCrossesAnyBounds(
6266
+ if (tracePathIntersectsBounds(
6252
6267
  connectorTrace,
6253
6268
  getRectBounds(otherLabel.center, otherLabel.width, otherLabel.height)
6254
6269
  )) {
@@ -7491,16 +7506,14 @@ function buildMergedObstacleLabel(seedLabel, allLabels) {
7491
7506
  height: h
7492
7507
  };
7493
7508
  }
7494
- function detectInnerTraceLabelOverlaps(traces, labels) {
7509
+ function detectTraceLabelOverlaps(traces, labels) {
7495
7510
  const overlaps = [];
7496
7511
  for (const trace of traces) {
7497
7512
  for (const label of labels) {
7498
7513
  if (trace.globalConnNetId === label.globalConnNetId) continue;
7499
7514
  const bounds = getRectBounds(label.center, label.width, label.height);
7500
7515
  const path = trace.tracePath;
7501
- const innerStart = 1;
7502
- const innerEnd = path.length - 2;
7503
- for (let i = innerStart; i < innerEnd; i++) {
7516
+ for (let i = 0; i < path.length - 1; i++) {
7504
7517
  if (segmentIntersectsRect2(path[i], path[i + 1], bounds)) {
7505
7518
  overlaps.push({ trace, label });
7506
7519
  break;
@@ -7566,7 +7579,7 @@ var NetLabelTraceCollisionSolver = class extends BaseSolver {
7566
7579
  }
7567
7580
  return;
7568
7581
  }
7569
- const overlaps = detectInnerTraceLabelOverlaps(
7582
+ const overlaps = detectTraceLabelOverlaps(
7570
7583
  this.outputTraces,
7571
7584
  this.outputNetLabelPlacements
7572
7585
  );
@@ -22,6 +22,7 @@ import {
22
22
  rectsOverlap,
23
23
  simplifyOrthogonalPath,
24
24
  traceCrossesBoundsInterior,
25
+ tracePathIntersectsBounds,
25
26
  tracePathCrossesAnyBounds,
26
27
  tracePathCrossesAnyTrace,
27
28
  } from "./geometry"
@@ -143,30 +144,7 @@ export class AvailableNetOrientationSolver extends BaseSolver {
143
144
  candidate: EvaluatedCandidate,
144
145
  labelIndex: number,
145
146
  ) {
146
- let tracePath: Point[]
147
-
148
- if (candidate.phase === "lateral-shift") {
149
- const orientDir = dir(candidate.orientation)
150
- const kickedSource = {
151
- x: label.anchorPoint.x - orientDir.x * LABEL_SEARCH_STEP,
152
- y: label.anchorPoint.y - orientDir.y * LABEL_SEARCH_STEP,
153
- }
154
- tracePath = simplifyOrthogonalPath([
155
- label.anchorPoint,
156
- ...getConnectorTracePath(
157
- kickedSource,
158
- candidate.anchorPoint,
159
- candidate.orientation,
160
- ),
161
- ])
162
- } else {
163
- tracePath = getConnectorTracePath(
164
- label.anchorPoint,
165
- candidate.anchorPoint,
166
- candidate.orientation,
167
- )
168
- }
169
-
147
+ const tracePath = this.getCandidateConnectorTrace(label, candidate)
170
148
  if (tracePath.length < 2) return
171
149
 
172
150
  const mspPairId = `available-net-orientation-${labelIndex}-${label.netId ?? label.globalConnNetId}`
@@ -417,8 +395,43 @@ export class AvailableNetOrientationSolver extends BaseSolver {
417
395
  distance,
418
396
  outwardDistance,
419
397
  selected: false,
420
- status: this.getCandidateStatus(candidate, label, labelIndex),
398
+ status: this.getCandidateStatus({
399
+ candidate,
400
+ label,
401
+ labelIndex,
402
+ phase,
403
+ }),
404
+ }
405
+ }
406
+
407
+ private getCandidateConnectorTrace(
408
+ label: NetLabelPlacement,
409
+ candidate: Pick<
410
+ EvaluatedCandidate,
411
+ "anchorPoint" | "orientation" | "phase"
412
+ >,
413
+ ) {
414
+ if (candidate.phase === "lateral-shift") {
415
+ const orientDir = dir(candidate.orientation)
416
+ const kickedSource = {
417
+ x: label.anchorPoint.x - orientDir.x * LABEL_SEARCH_STEP,
418
+ y: label.anchorPoint.y - orientDir.y * LABEL_SEARCH_STEP,
419
+ }
420
+ return simplifyOrthogonalPath([
421
+ label.anchorPoint,
422
+ ...getConnectorTracePath(
423
+ kickedSource,
424
+ candidate.anchorPoint,
425
+ candidate.orientation,
426
+ ),
427
+ ])
421
428
  }
429
+
430
+ return getConnectorTracePath(
431
+ label.anchorPoint,
432
+ candidate.anchorPoint,
433
+ candidate.orientation,
434
+ )
422
435
  }
423
436
 
424
437
  private getSearchStartAnchor(
@@ -583,22 +596,24 @@ export class AvailableNetOrientationSolver extends BaseSolver {
583
596
  )?.netLabelHeight
584
597
  }
585
598
 
586
- private getCandidateStatus(
587
- candidate: CandidateLabel,
588
- label: NetLabelPlacement,
589
- labelIndex: number,
590
- ) {
599
+ private getCandidateStatus(params: {
600
+ candidate: CandidateLabel
601
+ label: NetLabelPlacement
602
+ labelIndex: number
603
+ phase: CandidatePhase
604
+ }) {
605
+ const { candidate, label, labelIndex, phase } = params
591
606
  const boundsStatus = this.getBoundsStatus(
592
607
  getRectBounds(candidate.center, candidate.width, candidate.height),
593
608
  labelIndex,
594
609
  )
595
610
  if (boundsStatus !== "valid") return boundsStatus
596
611
 
597
- const connectorTrace = getConnectorTracePath(
598
- label.anchorPoint,
599
- candidate.anchorPoint,
600
- candidate.orientation,
601
- )
612
+ const connectorTrace = this.getCandidateConnectorTrace(label, {
613
+ anchorPoint: candidate.anchorPoint,
614
+ orientation: candidate.orientation,
615
+ phase,
616
+ })
602
617
 
603
618
  if (tracePathCrossesAnyTrace(connectorTrace, this.traceMap)) {
604
619
  return "trace-collision"
@@ -614,7 +629,7 @@ export class AvailableNetOrientationSolver extends BaseSolver {
614
629
  if (i === labelIndex) continue
615
630
  const otherLabel = this.outputNetLabelPlacements[i]!
616
631
  if (
617
- tracePathCrossesAnyBounds(
632
+ tracePathIntersectsBounds(
618
633
  connectorTrace,
619
634
  getRectBounds(otherLabel.center, otherLabel.width, otherLabel.height),
620
635
  )
@@ -2,6 +2,7 @@ import type { Point } from "@tscircuit/math-utils"
2
2
  import type { SolvedTracePath } from "lib/solvers/SchematicTraceLinesSolver/SchematicTraceLinesSolver"
3
3
  import type { InputProblem } from "lib/types/InputProblem"
4
4
  import type { FacingDirection } from "lib/utils/dir"
5
+ import { segmentIntersectsRect } from "lib/solvers/NetLabelPlacementSolver/SingleNetLabelPlacementSolver/collisions"
5
6
  import { EPS, TRACE_BOUNDARY_TOLERANCE } from "./constants"
6
7
  import type { Bounds, ChipSide } from "./types"
7
8
 
@@ -102,6 +103,18 @@ export const tracePathCrossesAnyBounds = (
102
103
  return false
103
104
  }
104
105
 
106
+ export const tracePathIntersectsBounds = (
107
+ tracePath: Point[],
108
+ bounds: Bounds,
109
+ ) => {
110
+ for (let i = 0; i < tracePath.length - 1; i++) {
111
+ if (segmentIntersectsRect(tracePath[i]!, tracePath[i + 1]!, bounds)) {
112
+ return true
113
+ }
114
+ }
115
+ return false
116
+ }
117
+
105
118
  export const tracePathCrossesAnyTrace = (
106
119
  tracePath: Point[],
107
120
  traceMap: Record<string, SolvedTracePath>,
@@ -72,31 +72,27 @@ function buildMergedObstacleLabel(
72
72
  }
73
73
  }
74
74
 
75
- interface TraceInnerLabelOverlap {
75
+ interface TraceLabelOverlap {
76
76
  trace: SolvedTracePath
77
77
  label: NetLabelPlacement
78
78
  }
79
79
 
80
80
  /**
81
- * Detects overlaps where a trace's INTERIOR (non-endpoint) segments cross a label.
82
- * Traces are allowed to boundary a label at their endpoints (pin locations),
83
- * just not allowed to cross through it in the middle.
81
+ * Detects overlaps where a trace segment intersects a label from another net.
82
+ * Point-only contact is allowed by segmentIntersectsRect; positive overlap on
83
+ * a label edge is still a visual collision and should be rerouted.
84
84
  */
85
- function detectInnerTraceLabelOverlaps(
85
+ function detectTraceLabelOverlaps(
86
86
  traces: SolvedTracePath[],
87
87
  labels: NetLabelPlacement[],
88
- ): TraceInnerLabelOverlap[] {
89
- const overlaps: TraceInnerLabelOverlap[] = []
88
+ ): TraceLabelOverlap[] {
89
+ const overlaps: TraceLabelOverlap[] = []
90
90
  for (const trace of traces) {
91
91
  for (const label of labels) {
92
92
  if (trace.globalConnNetId === label.globalConnNetId) continue
93
93
  const bounds = getRectBounds(label.center, label.width, label.height)
94
94
  const path = trace.tracePath
95
- // Skip first and last segments trace endpoints (pins) may legitimately
96
- // sit inside or adjacent to labels of neighbouring nets.
97
- const innerStart = 1
98
- const innerEnd = path.length - 2
99
- for (let i = innerStart; i < innerEnd; i++) {
95
+ for (let i = 0; i < path.length - 1; i++) {
100
96
  if (segmentIntersectsRect(path[i]!, path[i + 1]!, bounds)) {
101
97
  overlaps.push({ trace, label })
102
98
  break
@@ -183,7 +179,7 @@ export class NetLabelTraceCollisionSolver extends BaseSolver {
183
179
  return
184
180
  }
185
181
 
186
- const overlaps = detectInnerTraceLabelOverlaps(
182
+ const overlaps = detectTraceLabelOverlaps(
187
183
  this.outputTraces,
188
184
  this.outputNetLabelPlacements,
189
185
  )
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.63",
4
+ "version": "0.0.64",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "start": "cosmos",
@@ -2,56 +2,60 @@
2
2
  <rect width="100%" height="100%" fill="white" />
3
3
  <g>
4
4
  <circle data-type="point" data-label="U1.1
5
- x+" data-x="1.1" data-y="0.30000000000000004" cx="487.83715012722644" cy="248.75318066157763" r="3" fill="hsl(319, 100%, 50%, 0.8)" />
5
+ x+" data-x="1.1" data-y="0.30000000000000004" cx="479.84291324526953" cy="250.0249910746162" r="3" fill="hsl(319, 100%, 50%, 0.8)" />
6
6
  </g>
7
7
  <g>
8
8
  <circle data-type="point" data-label="U1.2
9
- x+" data-x="1.1" data-y="0.09999999999999998" cx="487.83715012722644" cy="289.46564885496184" r="3" fill="hsl(320, 100%, 50%, 0.8)" />
9
+ x+" data-x="1.1" data-y="0.09999999999999998" cx="479.84291324526953" cy="290.0107104605498" r="3" fill="hsl(320, 100%, 50%, 0.8)" />
10
10
  </g>
11
11
  <g>
12
12
  <circle data-type="point" data-label="U1.3
13
- x+" data-x="1.1" data-y="-0.10000000000000003" cx="487.83715012722644" cy="330.17811704834605" r="3" fill="hsl(321, 100%, 50%, 0.8)" />
13
+ x+" data-x="1.1" data-y="-0.10000000000000003" cx="479.84291324526953" cy="329.9964298464834" r="3" fill="hsl(321, 100%, 50%, 0.8)" />
14
14
  </g>
15
15
  <g>
16
16
  <circle data-type="point" data-label="U1.4
17
- x+" data-x="1.1" data-y="-0.30000000000000004" cx="487.83715012722644" cy="370.89058524173026" r="3" fill="hsl(322, 100%, 50%, 0.8)" />
17
+ x+" data-x="1.1" data-y="-0.30000000000000004" cx="479.84291324526953" cy="369.982149232417" r="3" fill="hsl(322, 100%, 50%, 0.8)" />
18
18
  </g>
19
19
  <g>
20
- <circle data-type="point" data-label="" data-x="1.1" data-y="0.30000000000000004" cx="487.83715012722644" cy="248.75318066157763" r="3" fill="hsl(40, 100%, 50%, 0.9)" />
20
+ <circle data-type="point" data-label="anchorPoint
21
+ orientation: x+" data-x="1.1" data-y="0.30000000000000004" cx="479.84291324526953" cy="250.0249910746162" r="3" fill="hsl(40, 100%, 50%, 0.9)" />
21
22
  </g>
22
23
  <g>
23
- <circle data-type="point" data-label="" data-x="1.1" data-y="0.09999999999999998" cx="487.83715012722644" cy="289.46564885496184" r="3" fill="hsl(40, 100%, 50%, 0.9)" />
24
+ <circle data-type="point" data-label="anchorPoint
25
+ orientation: x+" data-x="1.1" data-y="0.09999999999999998" cx="479.84291324526953" cy="290.0107104605498" r="3" fill="hsl(40, 100%, 50%, 0.9)" />
24
26
  </g>
25
27
  <g>
26
- <circle data-type="point" data-label="" data-x="1.5510000000000002" data-y="0.4009999999999999" cx="579.6437659033079" cy="228.1933842239186" r="3" fill="hsl(40, 100%, 50%, 0.9)" />
28
+ <circle data-type="point" data-label="anchorPoint
29
+ orientation: y+" data-x="1.601" data-y="0.4009999999999999" cx="580.0071403070332" cy="229.83220278471975" r="3" fill="hsl(40, 100%, 50%, 0.9)" />
27
30
  </g>
28
31
  <g>
29
- <circle data-type="point" data-label="" data-x="1.201" data-y="-0.5010000000000001" cx="508.39694656488547" cy="411.80661577608146" r="3" fill="hsl(40, 100%, 50%, 0.9)" />
32
+ <circle data-type="point" data-label="anchorPoint
33
+ orientation: y-" data-x="1.201" data-y="-0.5010000000000001" cx="500.035701535166" cy="410.1677972152803" r="3" fill="hsl(40, 100%, 50%, 0.9)" />
30
34
  </g>
31
35
  <g>
32
- <polyline data-points="1.1,-0.10000000000000003 1.5510000000000002,-0.10000000000000003 1.5510000000000002,0.4009999999999999" data-type="line" data-label="" points="487.83715012722644,330.17811704834605 579.6437659033079,330.17811704834605 579.6437659033079,228.1933842239186" fill="none" stroke="purple" stroke-width="1" />
36
+ <polyline data-points="1.1,-0.10000000000000003 1.601,-0.10000000000000003 1.601,0.4009999999999999" data-type="line" data-label="" points="479.84291324526953,329.9964298464834 580.0071403070332,329.9964298464834 580.0071403070332,229.83220278471975" fill="none" stroke="purple" stroke-width="1" />
33
37
  </g>
34
38
  <g>
35
- <polyline data-points="1.1,-0.30000000000000004 1.201,-0.30000000000000004 1.201,-0.5010000000000001" data-type="line" data-label="" points="487.83715012722644,370.89058524173026 508.39694656488547,370.89058524173026 508.39694656488547,411.80661577608146" fill="none" stroke="purple" stroke-width="1" />
39
+ <polyline data-points="1.1,-0.30000000000000004 1.201,-0.30000000000000004 1.201,-0.5010000000000001" data-type="line" data-label="" points="479.84291324526953,369.982149232417 500.035701535166,369.982149232417 500.035701535166,410.1677972152803" fill="none" stroke="purple" stroke-width="1" />
36
40
  </g>
37
41
  <g>
38
- <rect data-type="rect" data-label="schematic_component_0" data-x="0" data-y="0" x="40" y="208.04071246819342" width="447.83715012722644" height="203.56234096692106" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.004912500000000001" />
42
+ <rect data-type="rect" data-label="schematic_component_0" data-x="0" data-y="0" x="39.99999999999997" y="210.03927168868262" width="439.84291324526953" height="199.92859692966795" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.005001785714285715" />
39
43
  </g>
40
44
  <g>
41
45
  <rect data-type="rect" data-label="netId: SCL
42
- globalConnNetId: connectivity_net0" data-x="1.326" data-y="0.30000000000000004" x="488.0407124681933" y="228.39694656488552" width="91.60305343511459" height="40.71246819338421" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.004912500000000001" />
46
+ globalConnNetId: connectivity_net0" data-x="1.326" data-y="0.30000000000000004" x="480.0428418421992" y="230.03213138164938" width="89.96786861835062" height="39.985719385933635" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.005001785714285715" />
43
47
  </g>
44
48
  <g>
45
49
  <rect data-type="rect" data-label="netId: SDA
46
- globalConnNetId: connectivity_net1" data-x="1.326" data-y="0.09999999999999998" x="488.0407124681933" y="269.10941475826974" width="91.60305343511459" height="40.71246819338421" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.004912500000000001" />
50
+ globalConnNetId: connectivity_net1" data-x="1.326" data-y="0.09999999999999998" x="480.0428418421992" y="270.017850767583" width="89.96786861835062" height="39.98571938593358" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.005001785714285715" />
47
51
  </g>
48
52
  <g>
49
53
  <rect data-type="rect" data-label="netId: V3_3
50
- globalConnNetId: connectivity_net2" data-x="1.5510000000000002" data-y="0.6259999999999999" x="559.2875318066158" y="136.59033078880412" width="40.71246819338421" height="91.60305343511448" fill="#ef444466" stroke="#ef4444" stroke-width="0.004912500000000001" />
54
+ globalConnNetId: connectivity_net2" data-x="1.601" data-y="0.6259999999999999" x="560.0142806140664" y="139.86433416636916" width="39.985719385933635" height="89.9678686183506" fill="#ef444466" stroke="#ef4444" stroke-width="0.005001785714285715" />
51
55
  </g>
52
56
  <g>
53
57
  <rect data-type="rect" data-label="netId: GND
54
- globalConnNetId: connectivity_net3" data-x="1.201" data-y="-0.7260000000000001" x="488.0407124681933" y="411.80661577608146" width="40.71246819338421" height="91.60305343511448" fill="#00000066" stroke="#000000" stroke-width="0.004912500000000001" />
58
+ globalConnNetId: connectivity_net3" data-x="1.201" data-y="-0.7260000000000001" x="480.0428418421992" y="410.1677972152803" width="39.985719385933635" height="89.96786861835051" fill="#00000066" stroke="#000000" stroke-width="0.005001785714285715" />
55
59
  </g>
56
60
  <g id="crosshair" style="display: none">
57
61
  <line id="crosshair-h" y1="0" y2="640" stroke="#666" stroke-width="0.5" />
@@ -81,12 +85,12 @@ globalConnNetId: connectivity_net3" data-x="1.201" data-y="-0.7260000000000001"
81
85
 
82
86
  // Calculate real coordinates using inverse transformation
83
87
  const matrix = {
84
- "a": 203.56234096692108,
88
+ "a": 199.92859692966798,
85
89
  "c": 0,
86
- "e": 263.9185750636132,
90
+ "e": 259.92145662263476,
87
91
  "b": 0,
88
- "d": -203.56234096692108,
89
- "f": 309.82188295165395
92
+ "d": -199.92859692966798,
93
+ "f": 310.0035701535166
90
94
  };
91
95
  // Manually invert and apply the affine transform
92
96
  // Since we only use translate and scale, we can directly compute:
@@ -2,11 +2,19 @@ import { test, expect } from "bun:test"
2
2
  import { SchematicTracePipelineSolver } from "lib/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver"
3
3
  import inputProblem from "../assets/example34.json"
4
4
  import "tests/fixtures/matcher"
5
+ import { getTraceLabelCollisions } from "tests/fixtures/traceLabelCollisions"
5
6
 
6
7
  test("example34", () => {
7
8
  const solver = new SchematicTracePipelineSolver(inputProblem as any)
8
9
 
9
10
  solver.solve()
10
11
 
12
+ expect(
13
+ getTraceLabelCollisions(
14
+ solver.netLabelNetLabelCollisionSolver!.traces,
15
+ solver.netLabelNetLabelCollisionSolver!.outputNetLabelPlacements,
16
+ ),
17
+ ).toEqual([])
18
+
11
19
  expect(solver).toMatchSolverSnapshot(import.meta.path)
12
20
  })
@@ -0,0 +1,42 @@
1
+ import type { NetLabelPlacement } from "lib/solvers/NetLabelPlacementSolver/NetLabelPlacementSolver"
2
+ import { getRectBounds } from "lib/solvers/NetLabelPlacementSolver/SingleNetLabelPlacementSolver/geometry"
3
+ import { segmentIntersectsRect } from "lib/solvers/NetLabelPlacementSolver/SingleNetLabelPlacementSolver/collisions"
4
+ import type { SolvedTracePath } from "lib/solvers/SchematicTraceLinesSolver/SchematicTraceLinesSolver"
5
+
6
+ export const getTraceLabelCollisions = (
7
+ traces: SolvedTracePath[],
8
+ labels: NetLabelPlacement[],
9
+ ) => {
10
+ const collisions: Array<{
11
+ traceId: string
12
+ traceNetId: string
13
+ labelNetId: string
14
+ segmentIndex: number
15
+ }> = []
16
+
17
+ for (const trace of traces) {
18
+ for (const label of labels) {
19
+ if (trace.globalConnNetId === label.globalConnNetId) continue
20
+
21
+ const bounds = getRectBounds(label.center, label.width, label.height)
22
+ for (let i = 0; i < trace.tracePath.length - 1; i++) {
23
+ if (
24
+ segmentIntersectsRect(
25
+ trace.tracePath[i]!,
26
+ trace.tracePath[i + 1]!,
27
+ bounds,
28
+ )
29
+ ) {
30
+ collisions.push({
31
+ traceId: trace.mspPairId,
32
+ traceNetId: trace.globalConnNetId,
33
+ labelNetId: label.globalConnNetId,
34
+ segmentIndex: i,
35
+ })
36
+ }
37
+ }
38
+ }
39
+ }
40
+
41
+ return collisions
42
+ }
@@ -0,0 +1,273 @@
1
+ <svg width="640" height="640" viewBox="0 0 640 640" xmlns="http://www.w3.org/2000/svg">
2
+ <rect width="100%" height="100%" fill="white" />
3
+ <g>
4
+ <circle data-type="point" data-label="U1.3
5
+ x+" data-x="3.3774999999999995" data-y="-2.7900000000000005" cx="574.6987951807228" cy="508.49397590361446" r="3" fill="hsl(321, 100%, 50%, 0.8)" />
6
+ </g>
7
+ <g>
8
+ <circle data-type="point" data-label="U1.7
9
+ x-" data-x="0.3774999999999997" data-y="-1.39" cx="321.6867469879518" cy="390.4216867469879" r="3" fill="hsl(325, 100%, 50%, 0.8)" />
10
+ </g>
11
+ <g>
12
+ <circle data-type="point" data-label="U1.10
13
+ x-" data-x="0.3774999999999997" data-y="0.3100000000000005" cx="321.6867469879518" cy="247.04819277108427" r="3" fill="hsl(217, 100%, 50%, 0.8)" />
14
+ </g>
15
+ <g>
16
+ <circle data-type="point" data-label="U1.13
17
+ x-" data-x="0.3774999999999997" data-y="-0.1899999999999995" cx="321.6867469879518" cy="289.21686746987945" r="3" fill="hsl(220, 100%, 50%, 0.8)" />
18
+ </g>
19
+ <g>
20
+ <circle data-type="point" data-label="U1.18
21
+ x+" data-x="3.3774999999999995" data-y="-2.5900000000000003" cx="574.6987951807228" cy="491.6265060240964" r="3" fill="hsl(225, 100%, 50%, 0.8)" />
22
+ </g>
23
+ <g>
24
+ <circle data-type="point" data-label="U1.22
25
+ x+" data-x="3.3774999999999995" data-y="1.7100000000000004" cx="574.6987951807228" cy="128.97590361445776" r="3" fill="hsl(250, 100%, 50%, 0.8)" />
26
+ </g>
27
+ <g>
28
+ <circle data-type="point" data-label="U1.28
29
+ x+" data-x="3.3774999999999995" data-y="1.5100000000000002" cx="574.6987951807228" cy="145.84337349397586" r="3" fill="hsl(256, 100%, 50%, 0.8)" />
30
+ </g>
31
+ <g>
32
+ <circle data-type="point" data-label="U1.29
33
+ x+" data-x="3.3774999999999995" data-y="-2.3900000000000006" cx="574.6987951807228" cy="474.7590361445783" r="3" fill="hsl(257, 100%, 50%, 0.8)" />
34
+ </g>
35
+ <g>
36
+ <circle data-type="point" data-label="J2.1
37
+ x-" data-x="-1.2225000000000006" data-y="0.6600000000000018" cx="186.74698795180717" cy="217.53012048192753" r="3" fill="hsl(99, 100%, 50%, 0.8)" />
38
+ </g>
39
+ <g>
40
+ <circle data-type="point" data-label="J2.2
41
+ y-" data-x="-0.7725000000000006" data-y="0.2950000000000018" cx="224.6987951807228" cy="248.31325301204802" r="3" fill="hsl(100, 100%, 50%, 0.8)" />
42
+ </g>
43
+ <g>
44
+ <circle data-type="point" data-label="J2.3
45
+ x+" data-x="-0.3225000000000006" data-y="0.6600000000000018" cx="262.6506024096385" cy="217.53012048192753" r="3" fill="hsl(101, 100%, 50%, 0.8)" />
46
+ </g>
47
+ <g>
48
+ <circle data-type="point" data-label="J3.1
49
+ y-" data-x="-2.4125" data-y="-1.84" cx="86.38554216867468" cy="428.37349397590356" r="3" fill="hsl(340, 100%, 50%, 0.8)" />
50
+ </g>
51
+ <g>
52
+ <circle data-type="point" data-label="J3.2
53
+ x+" data-x="-2.0475" data-y="-1.39" cx="117.16867469879517" cy="390.4216867469879" r="3" fill="hsl(341, 100%, 50%, 0.8)" />
54
+ </g>
55
+ <g>
56
+ <circle data-type="point" data-label="J3.3
57
+ y+" data-x="-2.4125" data-y="-0.9399999999999997" cx="86.38554216867468" cy="352.4698795180722" r="3" fill="hsl(342, 100%, 50%, 0.8)" />
58
+ </g>
59
+ <g>
60
+ <circle data-type="point" data-label="anchorPoint
61
+ orientation: y-" data-x="3.5774999999999997" data-y="-2.7900000000000005" cx="591.566265060241" cy="508.49397590361446" r="3" fill="hsl(40, 100%, 50%, 0.9)" />
62
+ </g>
63
+ <g>
64
+ <circle data-type="point" data-label="anchorPoint
65
+ orientation: y-" data-x="0.20249999999999962" data-y="-0.1899999999999995" cx="306.92771084337346" cy="289.21686746987945" r="3" fill="hsl(40, 100%, 50%, 0.9)" />
66
+ </g>
67
+ <g>
68
+ <circle data-type="point" data-label="anchorPoint
69
+ orientation: y-" data-x="-2.7125000000000004" data-y="-0.9909999999999998" cx="61.08433734939754" cy="356.77108433734935" r="3" fill="hsl(40, 100%, 50%, 0.9)" />
70
+ </g>
71
+ <g>
72
+ <circle data-type="point" data-label="anchorPoint
73
+ orientation: y+" data-x="-0.8350000000000001" data-y="-1.39" cx="219.42771084337346" cy="390.4216867469879" r="3" fill="hsl(40, 100%, 50%, 0.9)" />
74
+ </g>
75
+ <g>
76
+ <circle data-type="point" data-label="anchorPoint
77
+ orientation: x-" data-x="-0.7725000000000006" data-y="0.09500000000000186" cx="224.6987951807228" cy="265.18072289156606" r="3" fill="hsl(40, 100%, 50%, 0.9)" />
78
+ </g>
79
+ <g>
80
+ <circle data-type="point" data-label="anchorPoint
81
+ orientation: y-" data-x="3.5774999999999997" data-y="1.5100000000000002" cx="591.566265060241" cy="145.84337349397586" r="3" fill="hsl(40, 100%, 50%, 0.9)" />
82
+ </g>
83
+ <g>
84
+ <circle data-type="point" data-label="anchorPoint
85
+ orientation: y+" data-x="-1.3235000000000006" data-y="0.8610000000000018" cx="178.22891566265054" cy="200.57831325301186" r="3" fill="hsl(40, 100%, 50%, 0.9)" />
86
+ </g>
87
+ <g>
88
+ <circle data-type="point" data-label="anchorPoint
89
+ orientation: y+" data-x="-2.8625000000000003" data-y="-0.989" cx="48.433734939759006" cy="356.6024096385542" r="3" fill="hsl(40, 100%, 50%, 0.9)" />
90
+ </g>
91
+ <g>
92
+ <polyline data-points="3.3774999999999995,1.5100000000000002 3.3774999999999995,1.7100000000000004" data-type="line" data-label="" points="574.6987951807228,145.84337349397586 574.6987951807228,128.97590361445776" fill="none" stroke="hsl(176, 100%, 50%, 0.8)" stroke-width="1" />
93
+ </g>
94
+ <g>
95
+ <polyline data-points="-0.7725000000000006,0.2950000000000018 0.3774999999999997,0.3100000000000005" data-type="line" data-label="" points="224.6987951807228,248.31325301204802 321.6867469879518,247.04819277108427" fill="none" stroke="hsl(48, 100%, 50%, 0.8)" stroke-width="1" />
96
+ </g>
97
+ <g>
98
+ <polyline data-points="-2.0475,-1.39 0.3774999999999997,-1.39" data-type="line" data-label="" points="117.16867469879517,390.4216867469879 321.6867469879518,390.4216867469879" fill="none" stroke="hsl(312, 100%, 50%, 0.8)" stroke-width="1" />
99
+ </g>
100
+ <g>
101
+ <polyline data-points="3.3774999999999995,-2.7900000000000005 0.3774999999999997,-0.1899999999999995" data-type="line" data-label="" points="574.6987951807228,508.49397590361446 321.6867469879518,289.21686746987945" fill="none" stroke="hsl(157, 100%, 50%, 0.8)" stroke-width="1" stroke-dasharray="4 2" />
102
+ </g>
103
+ <g>
104
+ <polyline data-points="3.3774999999999995,-2.7900000000000005 3.3774999999999995,-2.5900000000000003" data-type="line" data-label="" points="574.6987951807228,508.49397590361446 574.6987951807228,491.6265060240964" fill="none" stroke="hsl(157, 100%, 50%, 0.8)" stroke-width="1" stroke-dasharray="4 2" />
105
+ </g>
106
+ <g>
107
+ <polyline data-points="3.3774999999999995,-2.7900000000000005 3.3774999999999995,-2.3900000000000006" data-type="line" data-label="" points="574.6987951807228,508.49397590361446 574.6987951807228,474.7590361445783" fill="none" stroke="hsl(157, 100%, 50%, 0.8)" stroke-width="1" stroke-dasharray="4 2" />
108
+ </g>
109
+ <g>
110
+ <polyline data-points="3.3774999999999995,-2.7900000000000005 -0.3225000000000006,0.6600000000000018" data-type="line" data-label="" points="574.6987951807228,508.49397590361446 262.6506024096385,217.53012048192753" fill="none" stroke="hsl(157, 100%, 50%, 0.8)" stroke-width="1" stroke-dasharray="4 2" />
111
+ </g>
112
+ <g>
113
+ <polyline data-points="3.3774999999999995,-2.7900000000000005 -2.4125,-0.9399999999999997" data-type="line" data-label="" points="574.6987951807228,508.49397590361446 86.38554216867468,352.4698795180722" fill="none" stroke="hsl(157, 100%, 50%, 0.8)" stroke-width="1" stroke-dasharray="4 2" />
114
+ </g>
115
+ <g>
116
+ <polyline data-points="0.3774999999999997,-0.1899999999999995 3.3774999999999995,-2.5900000000000003" data-type="line" data-label="" points="321.6867469879518,289.21686746987945 574.6987951807228,491.6265060240964" fill="none" stroke="hsl(157, 100%, 50%, 0.8)" stroke-width="1" stroke-dasharray="4 2" />
117
+ </g>
118
+ <g>
119
+ <polyline data-points="0.3774999999999997,-0.1899999999999995 3.3774999999999995,-2.3900000000000006" data-type="line" data-label="" points="321.6867469879518,289.21686746987945 574.6987951807228,474.7590361445783" fill="none" stroke="hsl(157, 100%, 50%, 0.8)" stroke-width="1" stroke-dasharray="4 2" />
120
+ </g>
121
+ <g>
122
+ <polyline data-points="0.3774999999999997,-0.1899999999999995 -0.3225000000000006,0.6600000000000018" data-type="line" data-label="" points="321.6867469879518,289.21686746987945 262.6506024096385,217.53012048192753" fill="none" stroke="hsl(157, 100%, 50%, 0.8)" stroke-width="1" stroke-dasharray="4 2" />
123
+ </g>
124
+ <g>
125
+ <polyline data-points="0.3774999999999997,-0.1899999999999995 -2.4125,-0.9399999999999997" data-type="line" data-label="" points="321.6867469879518,289.21686746987945 86.38554216867468,352.4698795180722" fill="none" stroke="hsl(157, 100%, 50%, 0.8)" stroke-width="1" stroke-dasharray="4 2" />
126
+ </g>
127
+ <g>
128
+ <polyline data-points="3.3774999999999995,-2.5900000000000003 3.3774999999999995,-2.3900000000000006" data-type="line" data-label="" points="574.6987951807228,491.6265060240964 574.6987951807228,474.7590361445783" fill="none" stroke="hsl(157, 100%, 50%, 0.8)" stroke-width="1" stroke-dasharray="4 2" />
129
+ </g>
130
+ <g>
131
+ <polyline data-points="3.3774999999999995,-2.5900000000000003 -0.3225000000000006,0.6600000000000018" data-type="line" data-label="" points="574.6987951807228,491.6265060240964 262.6506024096385,217.53012048192753" fill="none" stroke="hsl(157, 100%, 50%, 0.8)" stroke-width="1" stroke-dasharray="4 2" />
132
+ </g>
133
+ <g>
134
+ <polyline data-points="3.3774999999999995,-2.5900000000000003 -2.4125,-0.9399999999999997" data-type="line" data-label="" points="574.6987951807228,491.6265060240964 86.38554216867468,352.4698795180722" fill="none" stroke="hsl(157, 100%, 50%, 0.8)" stroke-width="1" stroke-dasharray="4 2" />
135
+ </g>
136
+ <g>
137
+ <polyline data-points="3.3774999999999995,-2.3900000000000006 -0.3225000000000006,0.6600000000000018" data-type="line" data-label="" points="574.6987951807228,474.7590361445783 262.6506024096385,217.53012048192753" fill="none" stroke="hsl(157, 100%, 50%, 0.8)" stroke-width="1" stroke-dasharray="4 2" />
138
+ </g>
139
+ <g>
140
+ <polyline data-points="3.3774999999999995,-2.3900000000000006 -2.4125,-0.9399999999999997" data-type="line" data-label="" points="574.6987951807228,474.7590361445783 86.38554216867468,352.4698795180722" fill="none" stroke="hsl(157, 100%, 50%, 0.8)" stroke-width="1" stroke-dasharray="4 2" />
141
+ </g>
142
+ <g>
143
+ <polyline data-points="-0.3225000000000006,0.6600000000000018 -2.4125,-0.9399999999999997" data-type="line" data-label="" points="262.6506024096385,217.53012048192753 86.38554216867468,352.4698795180722" fill="none" stroke="hsl(157, 100%, 50%, 0.8)" stroke-width="1" stroke-dasharray="4 2" />
144
+ </g>
145
+ <g>
146
+ <polyline data-points="-1.2225000000000006,0.6600000000000018 -2.4125,-1.84" data-type="line" data-label="" points="186.74698795180717,217.53012048192753 86.38554216867468,428.37349397590356" fill="none" stroke="hsl(186, 100%, 50%, 0.8)" stroke-width="1" stroke-dasharray="4 2" />
147
+ </g>
148
+ <g>
149
+ <polyline data-points="3.3774999999999995,1.5100000000000002 3.5774999999999997,1.5100000000000002 3.5774999999999997,1.7100000000000004 3.3774999999999995,1.7100000000000004" data-type="line" data-label="" points="574.6987951807228,145.84337349397586 591.566265060241,145.84337349397586 591.566265060241,128.97590361445776 574.6987951807228,128.97590361445776" fill="none" stroke="purple" stroke-width="1" />
150
+ </g>
151
+ <g>
152
+ <polyline data-points="-0.7725000000000006,0.2950000000000018 -0.7725000000000006,0.09500000000000186 0.17749999999999966,0.09500000000000186 0.17749999999999966,0.3100000000000005 0.3774999999999997,0.3100000000000005" data-type="line" data-label="" points="224.6987951807228,248.31325301204802 224.6987951807228,265.18072289156606 304.8192771084337,265.18072289156606 304.8192771084337,247.04819277108427 321.6867469879518,247.04819277108427" fill="none" stroke="purple" stroke-width="1" />
153
+ </g>
154
+ <g>
155
+ <polyline data-points="0.3774999999999997,-0.1899999999999995 0.027499999999999553,-0.1899999999999995 0.027499999999999553,0.6600000000000018 -0.3225000000000006,0.6600000000000018" data-type="line" data-label="" points="321.6867469879518,289.21686746987945 292.16867469879514,289.21686746987945 292.16867469879514,217.53012048192753 262.6506024096385,217.53012048192753" fill="none" stroke="purple" stroke-width="1" />
156
+ </g>
157
+ <g>
158
+ <polyline data-points="3.3774999999999995,-2.3900000000000006 3.5774999999999997,-2.3900000000000006 3.5774999999999997,-2.5900000000000003 3.3774999999999995,-2.5900000000000003" data-type="line" data-label="" points="574.6987951807228,474.7590361445783 591.566265060241,474.7590361445783 591.566265060241,491.6265060240964 574.6987951807228,491.6265060240964" fill="none" stroke="purple" stroke-width="1" />
159
+ </g>
160
+ <g>
161
+ <polyline data-points="3.3774999999999995,-2.7900000000000005 3.5774999999999997,-2.7900000000000005 3.5774999999999997,-2.5900000000000003 3.3774999999999995,-2.5900000000000003" data-type="line" data-label="" points="574.6987951807228,508.49397590361446 591.566265060241,508.49397590361446 591.566265060241,491.6265060240964 574.6987951807228,491.6265060240964" fill="none" stroke="purple" stroke-width="1" />
162
+ </g>
163
+ <g>
164
+ <polyline data-points="-2.0475,-1.39 0.3774999999999997,-1.39" data-type="line" data-label="" points="117.16867469879517,390.4216867469879 321.6867469879518,390.4216867469879" fill="none" stroke="purple" stroke-width="1" />
165
+ </g>
166
+ <g>
167
+ <polyline data-points="-2.4125,-0.9399999999999997 -2.4125,-0.8899999999999997 -2.7125000000000004,-0.8899999999999997 -2.7125000000000004,-0.9909999999999998" data-type="line" data-label="" points="86.38554216867468,352.4698795180722 86.38554216867468,348.2530120481927 61.08433734939754,348.2530120481927 61.08433734939754,356.77108433734935" fill="none" stroke="purple" stroke-width="1" />
168
+ </g>
169
+ <g>
170
+ <polyline data-points="-1.2225000000000006,0.6600000000000018 -1.3235000000000006,0.6600000000000018 -1.3235000000000006,0.8610000000000018" data-type="line" data-label="" points="186.74698795180717,217.53012048192753 178.22891566265054,217.53012048192753 178.22891566265054,200.57831325301186" fill="none" stroke="purple" stroke-width="1" />
171
+ </g>
172
+ <g>
173
+ <polyline data-points="-2.4125,-1.84 -2.4125,-1.8900000000000001 -2.8625000000000003,-1.8900000000000001 -2.8625000000000003,-0.989" data-type="line" data-label="" points="86.38554216867468,428.37349397590356 86.38554216867468,432.5903614457831 48.433734939759006,432.5903614457831 48.433734939759006,356.6024096385542" fill="none" stroke="purple" stroke-width="1" />
174
+ </g>
175
+ <g>
176
+ <rect data-type="rect" data-label="schematic_component_0" data-x="1.8774999999999997" data-y="-0.43999999999999995" x="321.6867469879518" y="91.02409638554212" width="253.01204819277098" height="438.55421686746996" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.011857142857142858" />
177
+ </g>
178
+ <g>
179
+ <rect data-type="rect" data-label="schematic_component_6" data-x="-0.7725000000000006" data-y="0.5600000000000018" x="186.74698795180717" y="203.61445783132513" width="75.90361445783134" height="44.6987951807229" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.011857142857142858" />
180
+ </g>
181
+ <g>
182
+ <rect data-type="rect" data-label="schematic_component_7" data-x="-2.3125" data-y="-1.39" x="72.46987951807228" y="352.4698795180722" width="44.6987951807229" height="75.90361445783134" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.011857142857142858" />
183
+ </g>
184
+ <g>
185
+ <rect data-type="rect" data-label="netId: GND
186
+ globalConnNetId: connectivity_net3" data-x="3.5774999999999997" data-y="-3.0300000000000002" x="583.1325301204819" y="508.49397590361446" width="16.867469879518126" height="40.481927710843365" fill="#00000066" stroke="#000000" stroke-width="0.011857142857142858" />
187
+ </g>
188
+ <g>
189
+ <rect data-type="rect" data-label="netId: GND
190
+ globalConnNetId: connectivity_net3" data-x="0.20249999999999962" data-y="-0.4299999999999995" x="298.4939759036144" y="289.21686746987945" width="16.86746987951807" height="40.481927710843365" fill="#00000066" stroke="#000000" stroke-width="0.011857142857142858" />
191
+ </g>
192
+ <g>
193
+ <rect data-type="rect" data-label="netId: GND
194
+ globalConnNetId: connectivity_net3" data-x="-2.7125000000000004" data-y="-1.2309999999999999" x="52.65060240963851" y="356.77108433734935" width="16.867469879518097" height="40.481927710843365" fill="#00000066" stroke="#000000" stroke-width="0.011857142857142858" />
195
+ </g>
196
+ <g>
197
+ <rect data-type="rect" data-label="netId: .J3 &gt; .pin2 to .U1 &gt; .pin7
198
+ globalConnNetId: connectivity_net2" data-x="-0.8350000000000001" data-y="-1.1649999999999998" x="210.99397590361446" y="352.4698795180723" width="16.86746987951807" height="37.95180722891564" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.011857142857142858" />
199
+ </g>
200
+ <g>
201
+ <rect data-type="rect" data-label="netId: .J2 &gt; .pin2 to .U1 &gt; .pin10
202
+ globalConnNetId: connectivity_net1" data-x="-0.9975000000000006" data-y="0.09500000000000186" x="186.74698795180717" y="256.74698795180706" width="37.95180722891564" height="16.86746987951807" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.011857142857142858" />
203
+ </g>
204
+ <g>
205
+ <rect data-type="rect" data-label="netId: .U1 &gt; .VS2 to .U1 &gt; .pin22
206
+ globalConnNetId: connectivity_net0" data-x="3.5774999999999997" data-y="1.2850000000000001" x="583.1325301204819" y="145.84337349397586" width="16.867469879518126" height="37.95180722891567" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.011857142857142858" />
207
+ </g>
208
+ <g>
209
+ <rect data-type="rect" data-label="netId: VCC_3
210
+ globalConnNetId: connectivity_net4" data-x="-1.3235000000000006" data-y="1.2210000000000019" x="169.7951807228915" y="139.8554216867468" width="16.867469879518097" height="60.72289156626505" fill="#ef444466" stroke="#ef4444" stroke-width="0.011857142857142858" />
211
+ </g>
212
+ <g>
213
+ <rect data-type="rect" data-label="netId: VCC_3
214
+ globalConnNetId: connectivity_net4" data-x="-2.8625000000000003" data-y="-0.629" x="39.99999999999997" y="295.8795180722891" width="16.86746987951807" height="60.722891566265105" fill="#ef444466" stroke="#ef4444" stroke-width="0.011857142857142858" />
215
+ </g>
216
+ <g id="crosshair" style="display: none">
217
+ <line id="crosshair-h" y1="0" y2="640" stroke="#666" stroke-width="0.5" />
218
+ <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>
219
+ </g>
220
+ <script>
221
+ <![CDATA[
222
+ document.currentScript.parentElement.addEventListener('mousemove', (e) => {
223
+ const svg = e.currentTarget;
224
+ const rect = svg.getBoundingClientRect();
225
+ const x = e.clientX - rect.left;
226
+ const y = e.clientY - rect.top;
227
+ const crosshair = svg.getElementById('crosshair');
228
+ const h = svg.getElementById('crosshair-h');
229
+ const v = svg.getElementById('crosshair-v');
230
+ const coords = svg.getElementById('coordinates');
231
+
232
+ crosshair.style.display = 'block';
233
+ h.setAttribute('x1', '0');
234
+ h.setAttribute('x2', '640');
235
+ h.setAttribute('y1', y);
236
+ h.setAttribute('y2', y);
237
+ v.setAttribute('x1', x);
238
+ v.setAttribute('x2', x);
239
+ v.setAttribute('y1', '0');
240
+ v.setAttribute('y2', '640');
241
+
242
+ // Calculate real coordinates using inverse transformation
243
+ const matrix = {
244
+ "a": 84.33734939759036,
245
+ "c": 0,
246
+ "e": 289.84939759036143,
247
+ "b": 0,
248
+ "d": -84.33734939759036,
249
+ "f": 273.1927710843373
250
+ };
251
+ // Manually invert and apply the affine transform
252
+ // Since we only use translate and scale, we can directly compute:
253
+ // x' = (x - tx) / sx
254
+ // y' = (y - ty) / sy
255
+ const sx = matrix.a;
256
+ const sy = matrix.d;
257
+ const tx = matrix.e;
258
+ const ty = matrix.f;
259
+ const realPoint = {
260
+ x: (x - tx) / sx,
261
+ y: (y - ty) / sy // Flip y back since we used negative scale
262
+ }
263
+
264
+ coords.textContent = `(${realPoint.x.toFixed(2)}, ${realPoint.y.toFixed(2)})`;
265
+ coords.setAttribute('x', (x + 5).toString());
266
+ coords.setAttribute('y', (y - 5).toString());
267
+ });
268
+ document.currentScript.parentElement.addEventListener('mouseleave', () => {
269
+ document.currentScript.parentElement.getElementById('crosshair').style.display = 'none';
270
+ });
271
+ ]]>
272
+ </script>
273
+ </svg>
@@ -0,0 +1,113 @@
1
+ <svg width="640" height="640" viewBox="0 0 640 640" xmlns="http://www.w3.org/2000/svg">
2
+ <rect width="100%" height="100%" fill="white" />
3
+ <g>
4
+ <circle data-type="point" data-label="U1.3
5
+ x+" data-x="1.7999999999999998" data-y="-0.975" cx="458.8517829187396" cy="381.2935323383084" r="3" fill="hsl(321, 100%, 50%, 0.8)" />
6
+ </g>
7
+ <g>
8
+ <circle data-type="point" data-label="U1.4
9
+ x+" data-x="1.7999999999999998" data-y="-0.32499999999999996" cx="458.8517829187396" cy="320.9286898839137" r="3" fill="hsl(322, 100%, 50%, 0.8)" />
10
+ </g>
11
+ <g>
12
+ <circle data-type="point" data-label="R1.2
13
+ y-" data-x="2.25" data-y="-0.9" cx="500.642827694859" cy="374.3283582089552" r="3" fill="hsl(227, 100%, 50%, 0.8)" />
14
+ </g>
15
+ <g>
16
+ <circle data-type="point" data-label="R2.2
17
+ y-" data-x="2.25" data-y="-2.6500000000000004" cx="500.642827694859" cy="536.849087893864" r="3" fill="hsl(108, 100%, 50%, 0.8)" />
18
+ </g>
19
+ <g>
20
+ <circle data-type="point" data-label="anchorPoint
21
+ orientation: y-" data-x="2.125" data-y="-2.8500000000000005" cx="489.034204145937" cy="555.4228855721392" r="3" fill="hsl(40, 100%, 50%, 0.9)" />
22
+ </g>
23
+ <g>
24
+ <circle data-type="point" data-label="anchorPoint
25
+ orientation: y+" data-x="1.9249999999999998" data-y="-0.32499999999999996" cx="470.46040646766164" cy="320.9286898839137" r="3" fill="hsl(40, 100%, 50%, 0.9)" />
26
+ </g>
27
+ <g>
28
+ <polyline data-points="1.7999999999999998,-0.32499999999999996 2.25,-0.9" data-type="line" data-label="" points="458.8517829187396,320.9286898839137 500.642827694859,374.3283582089552" fill="none" stroke="hsl(112, 100%, 50%, 0.8)" stroke-width="1" />
29
+ </g>
30
+ <g>
31
+ <polyline data-points="1.7999999999999998,-0.975 2.25,-2.6500000000000004" data-type="line" data-label="" points="458.8517829187396,381.2935323383084 500.642827694859,536.849087893864" fill="none" stroke="hsl(157, 100%, 50%, 0.8)" stroke-width="1" stroke-dasharray="4 2" />
32
+ </g>
33
+ <g>
34
+ <polyline data-points="1.7999999999999998,-0.32499999999999996 1.9249999999999998,-0.32499999999999996 1.9249999999999998,-1.1 2.25,-1.1 2.25,-0.9" data-type="line" data-label="" points="458.8517829187396,320.9286898839137 470.46040646766164,320.9286898839137 470.46040646766164,392.9021558872305 500.642827694859,392.9021558872305 500.642827694859,374.3283582089552" fill="none" stroke="purple" stroke-width="1" />
35
+ </g>
36
+ <g>
37
+ <polyline data-points="1.7999999999999998,-0.975 2.125,-0.975 2.125,-2.8500000000000005 2.25,-2.8500000000000005 2.25,-2.6500000000000004" data-type="line" data-label="" points="458.8517829187396,381.2935323383084 489.034204145937,381.2935323383084 489.034204145937,555.4228855721392 500.642827694859,555.4228855721392 500.642827694859,536.849087893864" fill="none" stroke="purple" stroke-width="1" />
38
+ </g>
39
+ <g>
40
+ <rect data-type="rect" data-label="schematic_component_0" data-x="0" data-y="0" x="124.52342470978448" y="40" width="334.32835820895514" height="501.49253731343276" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.010767857142857145" />
41
+ </g>
42
+ <g>
43
+ <rect data-type="rect" data-label="schematic_component_4" data-x="2.25" data-y="-0.35" x="485.8090800995025" y="272.1724709784411" width="29.667495190713055" height="102.15588723051411" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.010767857142857145" />
44
+ </g>
45
+ <g>
46
+ <rect data-type="rect" data-label="schematic_component_5" data-x="2.25" data-y="-2.1" x="485.8090800995025" y="434.6932006633499" width="29.667495190713055" height="102.15588723051405" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.010767857142857145" />
47
+ </g>
48
+ <g>
49
+ <rect data-type="rect" data-label="netId: GND
50
+ globalConnNetId: connectivity_net1" data-x="2.125" data-y="-3.0900000000000007" x="479.7473053067993" y="555.4228855721392" width="18.573797678275298" height="44.577114427860806" fill="#00000066" stroke="#000000" stroke-width="0.010767857142857145" />
51
+ </g>
52
+ <g>
53
+ <rect data-type="rect" data-label="netId: U1.FB to R1.pin2
54
+ globalConnNetId: connectivity_net0" data-x="1.9249999999999998" data-y="-0.09999999999999995" x="461.173507628524" y="279.1376451077943" width="18.573797678275298" height="41.791044776119406" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.010767857142857145" />
55
+ </g>
56
+ <g id="crosshair" style="display: none">
57
+ <line id="crosshair-h" y1="0" y2="640" stroke="#666" stroke-width="0.5" />
58
+ <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>
59
+ </g>
60
+ <script>
61
+ <![CDATA[
62
+ document.currentScript.parentElement.addEventListener('mousemove', (e) => {
63
+ const svg = e.currentTarget;
64
+ const rect = svg.getBoundingClientRect();
65
+ const x = e.clientX - rect.left;
66
+ const y = e.clientY - rect.top;
67
+ const crosshair = svg.getElementById('crosshair');
68
+ const h = svg.getElementById('crosshair-h');
69
+ const v = svg.getElementById('crosshair-v');
70
+ const coords = svg.getElementById('coordinates');
71
+
72
+ crosshair.style.display = 'block';
73
+ h.setAttribute('x1', '0');
74
+ h.setAttribute('x2', '640');
75
+ h.setAttribute('y1', y);
76
+ h.setAttribute('y2', y);
77
+ v.setAttribute('x1', x);
78
+ v.setAttribute('x2', x);
79
+ v.setAttribute('y1', '0');
80
+ v.setAttribute('y2', '640');
81
+
82
+ // Calculate real coordinates using inverse transformation
83
+ const matrix = {
84
+ "a": 92.86898839137643,
85
+ "c": 0,
86
+ "e": 291.68760381426205,
87
+ "b": 0,
88
+ "d": -92.86898839137643,
89
+ "f": 290.7462686567164
90
+ };
91
+ // Manually invert and apply the affine transform
92
+ // Since we only use translate and scale, we can directly compute:
93
+ // x' = (x - tx) / sx
94
+ // y' = (y - ty) / sy
95
+ const sx = matrix.a;
96
+ const sy = matrix.d;
97
+ const tx = matrix.e;
98
+ const ty = matrix.f;
99
+ const realPoint = {
100
+ x: (x - tx) / sx,
101
+ y: (y - ty) / sy // Flip y back since we used negative scale
102
+ }
103
+
104
+ coords.textContent = `(${realPoint.x.toFixed(2)}, ${realPoint.y.toFixed(2)})`;
105
+ coords.setAttribute('x', (x + 5).toString());
106
+ coords.setAttribute('y', (y - 5).toString());
107
+ });
108
+ document.currentScript.parentElement.addEventListener('mouseleave', () => {
109
+ document.currentScript.parentElement.getElementById('crosshair').style.display = 'none';
110
+ });
111
+ ]]>
112
+ </script>
113
+ </svg>
@@ -0,0 +1,139 @@
1
+ {
2
+ "chips": [
3
+ {
4
+ "chipId": "schematic_component_0",
5
+ "center": {
6
+ "x": 1.8774999999999997,
7
+ "y": -0.43999999999999995
8
+ },
9
+ "width": 2.2,
10
+ "height": 5.2,
11
+ "pins": [
12
+ {
13
+ "pinId": "U1.3",
14
+ "x": 3.3774999999999995,
15
+ "y": -2.7900000000000005
16
+ },
17
+ {
18
+ "pinId": "U1.7",
19
+ "x": 0.3774999999999997,
20
+ "y": -1.39
21
+ },
22
+ {
23
+ "pinId": "U1.10",
24
+ "x": 0.3774999999999997,
25
+ "y": 0.3100000000000005
26
+ },
27
+ {
28
+ "pinId": "U1.13",
29
+ "x": 0.3774999999999997,
30
+ "y": -0.1899999999999995
31
+ },
32
+ {
33
+ "pinId": "U1.18",
34
+ "x": 3.3774999999999995,
35
+ "y": -2.5900000000000003
36
+ },
37
+ {
38
+ "pinId": "U1.22",
39
+ "x": 3.3774999999999995,
40
+ "y": 1.7100000000000004
41
+ },
42
+ {
43
+ "pinId": "U1.28",
44
+ "x": 3.3774999999999995,
45
+ "y": 1.5100000000000002
46
+ },
47
+ {
48
+ "pinId": "U1.29",
49
+ "x": 3.3774999999999995,
50
+ "y": -2.3900000000000006
51
+ }
52
+ ]
53
+ },
54
+ {
55
+ "chipId": "schematic_component_6",
56
+ "center": {
57
+ "x": -0.7725000000000006,
58
+ "y": 0.5600000000000018
59
+ },
60
+ "width": 0.9,
61
+ "height": 0.53,
62
+ "pins": [
63
+ {
64
+ "pinId": "J2.1",
65
+ "x": -1.2225000000000006,
66
+ "y": 0.6600000000000018
67
+ },
68
+ {
69
+ "pinId": "J2.2",
70
+ "x": -0.7725000000000006,
71
+ "y": 0.31000000000000183
72
+ },
73
+ {
74
+ "pinId": "J2.3",
75
+ "x": -0.3225000000000006,
76
+ "y": 0.6600000000000018
77
+ }
78
+ ]
79
+ },
80
+ {
81
+ "chipId": "schematic_component_7",
82
+ "center": {
83
+ "x": -2.3125,
84
+ "y": -1.39
85
+ },
86
+ "width": 0.53,
87
+ "height": 0.9,
88
+ "pins": [
89
+ {
90
+ "pinId": "J3.1",
91
+ "x": -2.4125,
92
+ "y": -1.84
93
+ },
94
+ {
95
+ "pinId": "J3.2",
96
+ "x": -2.0625,
97
+ "y": -1.39
98
+ },
99
+ {
100
+ "pinId": "J3.3",
101
+ "x": -2.4125,
102
+ "y": -0.94
103
+ }
104
+ ]
105
+ }
106
+ ],
107
+ "directConnections": [
108
+ {
109
+ "pinIds": ["U1.28", "U1.22"],
110
+ "netId": ".U1 > .VS2 to .U1 > .pin22"
111
+ },
112
+ {
113
+ "pinIds": ["J2.2", "U1.10"],
114
+ "netId": ".J2 > .pin2 to .U1 > .pin10"
115
+ },
116
+ {
117
+ "pinIds": ["J3.2", "U1.7"],
118
+ "netId": ".J3 > .pin2 to .U1 > .pin7"
119
+ }
120
+ ],
121
+ "netConnections": [
122
+ {
123
+ "netId": "GND",
124
+ "pinIds": ["U1.3", "U1.13", "U1.18", "U1.29", "J2.3", "J3.3"],
125
+ "netLabelWidth": 0.48
126
+ },
127
+ {
128
+ "netId": "VCC_3",
129
+ "pinIds": ["J2.1", "J3.1"],
130
+ "netLabelWidth": 0.72
131
+ }
132
+ ],
133
+ "availableNetLabelOrientations": {
134
+ "GND": ["y-"],
135
+ "VCC_5": ["y+"],
136
+ "VCC_3": ["y+"]
137
+ },
138
+ "maxMspPairDistance": 2.4
139
+ }
@@ -0,0 +1,74 @@
1
+ {
2
+ "chips": [
3
+ {
4
+ "chipId": "schematic_component_0",
5
+ "center": {
6
+ "x": 0,
7
+ "y": 0
8
+ },
9
+ "width": 2.8,
10
+ "height": 5.4,
11
+ "pins": [
12
+ {
13
+ "pinId": "U1.3",
14
+ "x": 1.7999999999999998,
15
+ "y": -0.975
16
+ },
17
+ {
18
+ "pinId": "U1.4",
19
+ "x": 1.7999999999999998,
20
+ "y": -0.32499999999999996
21
+ }
22
+ ]
23
+ },
24
+ {
25
+ "chipId": "schematic_component_4",
26
+ "center": {
27
+ "x": 2.25,
28
+ "y": -0.35
29
+ },
30
+ "width": 0.3194553499999995,
31
+ "height": 1.1,
32
+ "pins": [
33
+ {
34
+ "pinId": "R1.2",
35
+ "x": 2.25,
36
+ "y": -0.8999999999999999
37
+ }
38
+ ]
39
+ },
40
+ {
41
+ "chipId": "schematic_component_5",
42
+ "center": {
43
+ "x": 2.25,
44
+ "y": -2.1
45
+ },
46
+ "width": 0.3194553499999995,
47
+ "height": 1.1,
48
+ "pins": [
49
+ {
50
+ "pinId": "R2.2",
51
+ "x": 2.25,
52
+ "y": -2.65
53
+ }
54
+ ]
55
+ }
56
+ ],
57
+ "directConnections": [
58
+ {
59
+ "pinIds": ["U1.4", "R1.2"],
60
+ "netId": "U1.FB to R1.pin2"
61
+ }
62
+ ],
63
+ "netConnections": [
64
+ {
65
+ "netId": "GND",
66
+ "pinIds": ["U1.3", "R2.2"],
67
+ "netLabelWidth": 0.48
68
+ }
69
+ ],
70
+ "availableNetLabelOrientations": {
71
+ "GND": ["y-"]
72
+ },
73
+ "maxMspPairDistance": 2.4
74
+ }
@@ -0,0 +1,19 @@
1
+ import { test, expect } from "bun:test"
2
+ import { SchematicTracePipelineSolver } from "lib/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver"
3
+ import ip from "./assets/repro-netlabel-connector-through-label.input.json"
4
+ import "tests/fixtures/matcher"
5
+ import { getTraceLabelCollisions } from "tests/fixtures/traceLabelCollisions"
6
+
7
+ test("netlabel connector trace should not pass through a rail label", () => {
8
+ const solver = new SchematicTracePipelineSolver(ip as any)
9
+ solver.solve()
10
+
11
+ expect(
12
+ getTraceLabelCollisions(
13
+ solver.netLabelNetLabelCollisionSolver!.traces,
14
+ solver.netLabelNetLabelCollisionSolver!.outputNetLabelPlacements,
15
+ ),
16
+ ).toEqual([])
17
+
18
+ expect(solver).toMatchSolverSnapshot(import.meta.path)
19
+ })
@@ -0,0 +1,14 @@
1
+ import { expect, test } from "bun:test"
2
+ import { SchematicTracePipelineSolver } from "lib/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver"
3
+ import inputProblem from "./assets/repro126-trace-overlap-box-resistor.input.json"
4
+ import "tests/fixtures/matcher"
5
+
6
+ test("repro126 trace overlaps R2 box", () => {
7
+ const solver = new SchematicTracePipelineSolver(inputProblem as any)
8
+ solver.solve()
9
+
10
+ expect(
11
+ solver.traceOverlapShiftSolver!.correctedTraceMap["U1.3-R2.2"],
12
+ ).toBeDefined()
13
+ expect(solver).toMatchSolverSnapshot(import.meta.path)
14
+ })