@tscircuit/schematic-trace-solver 0.0.107 → 0.0.108

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.
@@ -7,16 +7,18 @@ import { getDimsForOrientation } from "lib/solvers/NetLabelPlacementSolver/Singl
7
7
  import { visualizeInputProblem } from "lib/solvers/SchematicTracePipelineSolver/visualizeInputProblem"
8
8
  import type { InputChip, InputProblem } from "lib/types/InputProblem"
9
9
  import type { FacingDirection } from "lib/utils/dir"
10
- import type { RectPadding } from "lib/utils/textBoxBounds"
10
+ import { getTextBoxBounds, type RectPadding } from "lib/utils/textBoxBounds"
11
11
  import { getPinDirection } from "../SchematicTraceSingleLineSolver/getPinDirection"
12
12
  import { calculateDirectShortPath } from "./calculateDirectShortPath"
13
13
  import {
14
14
  findFirstCollision,
15
15
  isHorizontal,
16
16
  isVertical,
17
+ segmentIntersectsRect,
17
18
  segmentOverlapsRectBoundary,
18
19
  } from "./collisions"
19
20
  import { generateEndpointCollisionDetours } from "./generateEndpointCollisionDetours"
21
+ import { generateInternalSegmentCollisionDetours } from "./generateInternalSegmentCollisionDetours"
20
22
  import {
21
23
  type Axis,
22
24
  aabbFromPoints,
@@ -24,7 +26,12 @@ import {
24
26
  midBetweenPointAndRect,
25
27
  } from "./mid"
26
28
  import { pathKey, shiftSegmentOrth } from "./pathOps"
27
- import { getObstacleRects, type ObstacleRect } from "./rect"
29
+ import {
30
+ getObstacleRects,
31
+ isTextBoxObstacle,
32
+ type ObstacleRect,
33
+ type TextBoxObstacleRect,
34
+ } from "./rect"
28
35
 
29
36
  type PathKey = string
30
37
 
@@ -58,8 +65,8 @@ export class SchematicTraceSingleLineSolver2 extends BaseSolver {
58
65
  chipMap: Record<string, InputChip>
59
66
 
60
67
  obstacles: ObstacleRect[]
61
- textObstacles: Set<ObstacleRect>
62
- endpointTextObstacles: Set<ObstacleRect>
68
+ textObstacles: Set<TextBoxObstacleRect>
69
+ endpointTextObstacles: Set<TextBoxObstacleRect>
63
70
  aabb: { minX: number; maxX: number; minY: number; maxY: number }
64
71
 
65
72
  baseElbow: Point[]
@@ -95,18 +102,17 @@ export class SchematicTraceSingleLineSolver2 extends BaseSolver {
95
102
  this.obstacles = getObstacleRects(this.inputProblem, {
96
103
  textBoxPadding: this.getTextBoxPaddingForConnectionPair(),
97
104
  })
98
- this.textObstacles = new Set(
99
- this.obstacles.filter((r) => r.kind === "text_box"),
100
- )
105
+ this.textObstacles = new Set(this.obstacles.filter(isTextBoxObstacle))
101
106
  const endpointChipIds = new Set(this.pins.map((pin) => pin.chipId))
102
107
  this.endpointTextObstacles = new Set(
103
108
  endpointChipIds.size > 1
104
- ? this.obstacles.filter(
105
- (r) =>
106
- r.kind === "text_box" &&
107
- r.textBox.chipId !== undefined &&
108
- endpointChipIds.has(r.textBox.chipId),
109
- )
109
+ ? this.obstacles
110
+ .filter(isTextBoxObstacle)
111
+ .filter(
112
+ (obstacle) =>
113
+ obstacle.textBox.chipId !== undefined &&
114
+ endpointChipIds.has(obstacle.textBox.chipId),
115
+ )
110
116
  : [],
111
117
  )
112
118
 
@@ -356,7 +362,12 @@ export class SchematicTraceSingleLineSolver2 extends BaseSolver {
356
362
  )
357
363
  ) {
358
364
  for (const textObstacle of this.endpointTextObstacles) {
359
- excludedRects.add(textObstacle)
365
+ // Outside-pin-band routing may cross label padding around endpoint
366
+ // text, but the actual text bounds remain a hard obstacle.
367
+ const textBounds = getTextBoxBounds(textObstacle.textBox)
368
+ if (!segmentIntersectsRect(segmentStart, segmentEnd, textBounds)) {
369
+ excludedRects.add(textObstacle)
370
+ }
360
371
  }
361
372
  }
362
373
 
@@ -500,18 +511,7 @@ export class SchematicTraceSingleLineSolver2 extends BaseSolver {
500
511
  pinBandPenalty: number
501
512
  }> = []
502
513
 
503
- const addShiftedCandidate = (
504
- candidateSegIndex: number,
505
- candidateAxis: Axis,
506
- coord: number,
507
- ) => {
508
- const newPath = shiftSegmentOrth(
509
- path,
510
- candidateSegIndex,
511
- candidateAxis,
512
- coord,
513
- )
514
- if (!newPath) return
514
+ const addPathCandidate = (newPath: Point[]) => {
515
515
  const key = pathKey(newPath)
516
516
  if (this.visited.has(key)) return
517
517
  this.visited.add(key)
@@ -525,11 +525,42 @@ export class SchematicTraceSingleLineSolver2 extends BaseSolver {
525
525
  })
526
526
  }
527
527
 
528
+ const addShiftedCandidate = (
529
+ candidateSegIndex: number,
530
+ candidateAxis: Axis,
531
+ coord: number,
532
+ ) => {
533
+ const newPath = shiftSegmentOrth(
534
+ path,
535
+ candidateSegIndex,
536
+ candidateAxis,
537
+ coord,
538
+ )
539
+ if (newPath) addPathCandidate(newPath)
540
+ }
541
+
542
+ const lastSegIndex = path.length - 2
543
+ if (
544
+ this.connectionPair === undefined &&
545
+ rect.kind === "text_box" &&
546
+ this.endpointTextObstacles.has(rect) &&
547
+ !collisionRects.has(rect) &&
548
+ originalSegIndex > 0 &&
549
+ originalSegIndex < lastSegIndex
550
+ ) {
551
+ for (const detour of generateInternalSegmentCollisionDetours({
552
+ path,
553
+ collidingSegmentIndex: originalSegIndex,
554
+ obstacle: rect,
555
+ })) {
556
+ addPathCandidate(detour)
557
+ }
558
+ }
559
+
528
560
  for (const coord of candidates) {
529
561
  addShiftedCandidate(segIndex, axis, coord)
530
562
  }
531
563
 
532
- const lastSegIndex = path.length - 2
533
564
  const adjacentSegmentIndexes =
534
565
  originalSegIndex === 1
535
566
  ? [2]
@@ -1,6 +1,7 @@
1
1
  import type { Point } from "@tscircuit/math-utils"
2
2
  import { isHorizontal, isVertical } from "./collisions"
3
3
  import { type Axis, midBetweenPointAndRect } from "./mid"
4
+ import { hasOnlyNonzeroOrthogonalSegments } from "./pathOps"
4
5
  import type { ObstacleRect } from "./rect"
5
6
 
6
7
  const getSegmentAxis = (start: Point, end: Point): Axis | null => {
@@ -9,16 +10,6 @@ const getSegmentAxis = (start: Point, end: Point): Axis | null => {
9
10
  return null
10
11
  }
11
12
 
12
- const hasOnlyNonzeroOrthogonalSegments = (path: Point[]) =>
13
- path.every((point, index) => {
14
- const nextPoint = path[index + 1]
15
- if (!nextPoint) return true
16
- if (!isHorizontal(point, nextPoint) && !isVertical(point, nextPoint)) {
17
- return false
18
- }
19
- return Math.abs(point.x - nextPoint.x) + Math.abs(point.y - nextPoint.y) > 0
20
- })
21
-
22
13
  export const generateEndpointCollisionDetours = ({
23
14
  path,
24
15
  collidingSegmentIndex,
@@ -0,0 +1,94 @@
1
+ import type { Point } from "@tscircuit/math-utils"
2
+ import { isHorizontal, isVertical } from "./collisions"
3
+ import { hasOnlyNonzeroOrthogonalSegments } from "./pathOps"
4
+ import type { RectBounds } from "./rect"
5
+
6
+ const EPS = 1e-9
7
+ const DEFAULT_CLEARANCE = 0.2
8
+
9
+ const isStrictlyBetween = (value: number, a: number, b: number) =>
10
+ value > Math.min(a, b) + EPS && value < Math.max(a, b) - EPS
11
+
12
+ export const generateInternalSegmentCollisionDetours = ({
13
+ path,
14
+ collidingSegmentIndex,
15
+ obstacle,
16
+ clearance = DEFAULT_CLEARANCE,
17
+ }: {
18
+ path: Point[]
19
+ collidingSegmentIndex: number
20
+ obstacle: RectBounds
21
+ clearance?: number
22
+ }): Point[][] => {
23
+ if (collidingSegmentIndex <= 0 || collidingSegmentIndex >= path.length - 2) {
24
+ return []
25
+ }
26
+
27
+ const start = path[collidingSegmentIndex]!
28
+ const end = path[collidingSegmentIndex + 1]!
29
+ const detourPoints: Point[][] = []
30
+
31
+ if (isHorizontal(start, end)) {
32
+ const movingRight = start.x < end.x
33
+ const entryX = movingRight
34
+ ? obstacle.minX - clearance
35
+ : obstacle.maxX + clearance
36
+ const exitX = movingRight
37
+ ? obstacle.maxX + clearance
38
+ : obstacle.minX - clearance
39
+
40
+ if (
41
+ !isStrictlyBetween(entryX, start.x, end.x) ||
42
+ !isStrictlyBetween(exitX, start.x, end.x)
43
+ ) {
44
+ return []
45
+ }
46
+
47
+ for (const detourY of [
48
+ obstacle.minY - clearance,
49
+ obstacle.maxY + clearance,
50
+ ]) {
51
+ detourPoints.push([
52
+ { x: entryX, y: start.y },
53
+ { x: entryX, y: detourY },
54
+ { x: exitX, y: detourY },
55
+ { x: exitX, y: end.y },
56
+ ])
57
+ }
58
+ } else if (isVertical(start, end)) {
59
+ const movingUp = start.y < end.y
60
+ const entryY = movingUp
61
+ ? obstacle.minY - clearance
62
+ : obstacle.maxY + clearance
63
+ const exitY = movingUp
64
+ ? obstacle.maxY + clearance
65
+ : obstacle.minY - clearance
66
+
67
+ if (
68
+ !isStrictlyBetween(entryY, start.y, end.y) ||
69
+ !isStrictlyBetween(exitY, start.y, end.y)
70
+ ) {
71
+ return []
72
+ }
73
+
74
+ for (const detourX of [
75
+ obstacle.minX - clearance,
76
+ obstacle.maxX + clearance,
77
+ ]) {
78
+ detourPoints.push([
79
+ { x: start.x, y: entryY },
80
+ { x: detourX, y: entryY },
81
+ { x: detourX, y: exitY },
82
+ { x: end.x, y: exitY },
83
+ ])
84
+ }
85
+ }
86
+
87
+ return detourPoints
88
+ .map((points) => [
89
+ ...path.slice(0, collidingSegmentIndex + 1),
90
+ ...points,
91
+ ...path.slice(collidingSegmentIndex + 1),
92
+ ])
93
+ .filter(hasOnlyNonzeroOrthogonalSegments)
94
+ }
@@ -5,6 +5,16 @@ const EPS = 1e-9
5
5
 
6
6
  export type Axis = "x" | "y"
7
7
 
8
+ export const hasOnlyNonzeroOrthogonalSegments = (path: Point[]) =>
9
+ path.every((point, index) => {
10
+ const nextPoint = path[index + 1]
11
+ if (!nextPoint) return true
12
+ if (!isHorizontal(point, nextPoint) && !isVertical(point, nextPoint)) {
13
+ return false
14
+ }
15
+ return Math.abs(point.x - nextPoint.x) + Math.abs(point.y - nextPoint.y) > 0
16
+ })
17
+
8
18
  export const shiftSegmentOrth = (
9
19
  pts: Point[],
10
20
  segIndex: number,
@@ -1,5 +1,5 @@
1
- import type { InputChip, InputProblem } from "lib/types/InputProblem"
2
1
  import { getInputChipBounds } from "lib/solvers/GuidelinesSolver/getInputChipBounds"
2
+ import type { InputChip, InputProblem } from "lib/types/InputProblem"
3
3
  import { getTextBoxBounds, type RectPadding } from "lib/utils/textBoxBounds"
4
4
 
5
5
  export type RectBounds = {
@@ -21,6 +21,10 @@ export type TextBoxObstacleRect = RectBounds & {
21
21
 
22
22
  export type ObstacleRect = ChipObstacleRect | TextBoxObstacleRect
23
23
 
24
+ export const isTextBoxObstacle = (
25
+ obstacle: ObstacleRect,
26
+ ): obstacle is TextBoxObstacleRect => obstacle.kind === "text_box"
27
+
24
28
  export const chipToRect = (chip: InputChip): ChipObstacleRect => {
25
29
  const b = getInputChipBounds(chip)
26
30
  return { kind: "chip", chipId: chip.chipId, ...b }
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.107",
4
+ "version": "0.0.108",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "start": "cosmos",
@@ -1,10 +1,10 @@
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.05,0.20000000000000007 -12,-1.6999999999999993" data-type="line" data-label="" points="325.95072409253333,329.4369005078052 51.05886778258409,369.45946962572884" fill="none" stroke="hsl(112, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="1.05,0.4 -12,0.1100000000000021" data-type="line" data-label="" points="325.95072409253333,325.22399849539215 51.05886778258409,331.332706413391" fill="none" stroke="hsl(24, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="-1.05,-0.5 -12,1.9750000000000014" data-type="line" data-label="" points="281.71525296219664,344.18205755125075 51.05886778258409,292.04739514763963" fill="none" stroke="hsl(328, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="1.05,1.1102230246251565e-16 11.7,-1" data-type="line" data-label="" points="325.95072409253333,333.6498025202182 550.2877562535264,354.7143125822833" fill="none" stroke="hsl(8, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="12.3,-1 13.3,-0.9999999999999996" data-type="line" data-label="" points="562.9264622907654,354.7143125822833 583.9909723528306,354.71431258228324" fill="none" stroke="hsl(176, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="-12,-2.3000000000000007 -12,-0.4899999999999993" data-type="line" data-label="" points="51.05886778258409,382.0981756629679 51.05886778258409,343.97141245063005" fill="none" stroke="hsl(157, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="-12,-2.3000000000000007 -12,1.375" data-type="line" data-label="" points="51.05886778258409,382.0981756629679 51.05886778258409,304.68610118487874" fill="none" stroke="hsl(157, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="-12,-2.3000000000000007 13.3,-1.600000000000001" data-type="line" data-label="" points="51.05886778258409,382.0981756629679 583.9909723528306,367.35301861952235" fill="none" stroke="hsl(157, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="-12,-0.4899999999999993 -12,1.375" data-type="line" data-label="" points="51.05886778258409,343.97141245063005 51.05886778258409,304.68610118487874" fill="none" stroke="hsl(157, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="-12,-0.4899999999999993 13.3,-1.600000000000001" data-type="line" data-label="" points="51.05886778258409,343.97141245063005 583.9909723528306,367.35301861952235" fill="none" stroke="hsl(157, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="-12,1.375 13.3,-1.600000000000001" data-type="line" data-label="" points="51.05886778258409,304.68610118487874 583.9909723528306,367.35301861952235" fill="none" stroke="hsl(157, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="12.3,-1 12.8,-1 12.8,-0.7999999999999996 13.3,-0.7999999999999996 13.3,-0.9999999999999996" data-type="line" data-label="" points="562.9264622907654,354.7143125822833 573.458717321798,354.7143125822833 573.458717321798,350.50141056987025 583.9909723528306,350.50141056987025 583.9909723528306,354.71431258228324" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="-12,-0.4899999999999993 -12,-0.6899999999999986 -12.524999999999999,-0.6899999999999986 -12.524999999999999,1.1749999999999998 -12,1.1749999999999998 -12,1.3749999999999991" data-type="line" data-label="" points="51.05886778258409,343.97141245063005 51.05886778258409,348.18431446304305 39.99999999999994,348.18431446304305 39.99999999999994,308.89900319729173 51.05886778258409,308.89900319729173 51.05886778258409,304.68610118487874" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="-12,-2.3000000000000007 -12,-2.5 -12.524999999999999,-2.5 -12.524999999999999,-0.6899999999999977 -12,-0.6899999999999977 -12,-0.48999999999999844" data-type="line" data-label="" points="51.05886778258409,382.0981756629679 51.05886778258409,386.3110776753809 39.99999999999994,386.3110776753809 39.99999999999994,348.18431446304305 51.05886778258409,348.18431446304305 51.05886778258409,343.97141245063005" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="1.0500000000000007,0.39999999999999947 1.25,0.39999999999999947 1.25,1.0999999999999999 -12,1.0999999999999999 -12,0.1100000000000021" data-type="line" data-label="" points="325.95072409253333,325.2239984953922 330.16362610494633,325.2239984953922 330.16362610494633,310.4788414519466 51.05886778258409,310.4788414519466 51.05886778258409,331.332706413391" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="1.0500000000000007,0.1999999999999993 1.25,0.1999999999999993 1.25,-1.0999999999999999 -12,-1.0999999999999999 -12,-1.6999999999999993" data-type="line" data-label="" points="325.95072409253333,329.4369005078052 330.16362610494633,329.4369005078052 330.16362610494633,356.8207635884898 51.05886778258409,356.8207635884898 51.05886778258409,369.45946962572884" 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="281.71525296219664" y="314.69174346435966" width="44.23547113033669" height="37.91611811171708" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.047473214285714285"/></g><g><rect data-type="rect" data-label="schematic_component_1" data-x="-11.782499999999999" data-y="-2" x="44.212902012412954" y="369.45946962572884" width="22.854993417340637" height="12.638706037239047" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.047473214285714285"/></g><g><rect data-type="rect" data-label="schematic_component_2" data-x="-11.782499999999999" data-y="-0.18999999999999861" x="44.212902012412954" y="331.33270641339107" width="22.854993417340637" height="12.638706037239047" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.047473214285714285"/></g><g><rect data-type="rect" data-label="schematic_component_3" data-x="-11.7225" data-y="1.6750000000000007" x="44.21290201241294" y="292.04739514763963" width="25.382734624788384" height="12.638706037239103" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.047473214285714285"/></g><g><rect data-type="rect" data-label="schematic_component_4" data-x="12" data-y="-1" x="550.2877562535264" y="345.867218356216" width="12.63870603723899" height="17.694188452134654" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.047473214285714285"/></g><g><rect data-type="rect" data-label="schematic_component_5" data-x="13.517500000000002" data-y="-1.3000000000000003" x="577.1450065826593" y="354.71431258228324" width="22.854993417340665" height="12.638706037239103" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.047473214285714285"/></g><g><rect data-type="rect" data-label="TPS923655DMTR" data-x="0.13" data-y="-1.0299999999999998" x="290.1410569870227" y="353.45044197855935" width="32.86063569682153" height="3.7916118111717196" fill="rgba(160, 0, 220, 0.14)" stroke="black" stroke-width="0.047473214285714285"/></g><g><rect data-type="rect" data-label="U1" data-x="-0.53" data-y="1.0150000000000001" x="288.87718638329886" y="309.636261049464" width="7.583223622343382" height="5.2661275155163025" fill="rgba(160, 0, 220, 0.14)" stroke="black" stroke-width="0.047473214285714285"/></g><g><rect data-type="rect" data-label="netId: U1.FAULT to RFAULT.pin1
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.05,0.20000000000000007 -12,-1.6999999999999993" data-type="line" data-label="" points="325.95072409253333,329.4369005078052 51.05886778258409,369.45946962572884" fill="none" stroke="hsl(112, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="1.05,0.4 -12,0.1100000000000021" data-type="line" data-label="" points="325.95072409253333,325.22399849539215 51.05886778258409,331.332706413391" fill="none" stroke="hsl(24, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="-1.05,-0.5 -12,1.9750000000000014" data-type="line" data-label="" points="281.71525296219664,344.18205755125075 51.05886778258409,292.04739514763963" fill="none" stroke="hsl(328, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="1.05,1.1102230246251565e-16 11.7,-1" data-type="line" data-label="" points="325.95072409253333,333.6498025202182 550.2877562535264,354.7143125822833" fill="none" stroke="hsl(8, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="12.3,-1 13.3,-0.9999999999999996" data-type="line" data-label="" points="562.9264622907654,354.7143125822833 583.9909723528306,354.71431258228324" fill="none" stroke="hsl(176, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="-12,-2.3000000000000007 -12,-0.4899999999999993" data-type="line" data-label="" points="51.05886778258409,382.0981756629679 51.05886778258409,343.97141245063005" fill="none" stroke="hsl(157, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="-12,-2.3000000000000007 -12,1.375" data-type="line" data-label="" points="51.05886778258409,382.0981756629679 51.05886778258409,304.68610118487874" fill="none" stroke="hsl(157, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="-12,-2.3000000000000007 13.3,-1.600000000000001" data-type="line" data-label="" points="51.05886778258409,382.0981756629679 583.9909723528306,367.35301861952235" fill="none" stroke="hsl(157, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="-12,-0.4899999999999993 -12,1.375" data-type="line" data-label="" points="51.05886778258409,343.97141245063005 51.05886778258409,304.68610118487874" fill="none" stroke="hsl(157, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="-12,-0.4899999999999993 13.3,-1.600000000000001" data-type="line" data-label="" points="51.05886778258409,343.97141245063005 583.9909723528306,367.35301861952235" fill="none" stroke="hsl(157, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="-12,1.375 13.3,-1.600000000000001" data-type="line" data-label="" points="51.05886778258409,304.68610118487874 583.9909723528306,367.35301861952235" fill="none" stroke="hsl(157, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="12.3,-1 12.8,-1 12.8,-0.7999999999999996 13.3,-0.7999999999999996 13.3,-0.9999999999999996" data-type="line" data-label="" points="562.9264622907654,354.7143125822833 573.458717321798,354.7143125822833 573.458717321798,350.50141056987025 583.9909723528306,350.50141056987025 583.9909723528306,354.71431258228324" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="-12,-0.4899999999999993 -12,-0.6899999999999986 -12.524999999999999,-0.6899999999999986 -12.524999999999999,1.1749999999999998 -12,1.1749999999999998 -12,1.3749999999999991" data-type="line" data-label="" points="51.05886778258409,343.97141245063005 51.05886778258409,348.18431446304305 39.99999999999994,348.18431446304305 39.99999999999994,308.89900319729173 51.05886778258409,308.89900319729173 51.05886778258409,304.68610118487874" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="-12,-2.3000000000000007 -12,-2.5 -12.524999999999999,-2.5 -12.524999999999999,-0.6899999999999977 -12,-0.6899999999999977 -12,-0.48999999999999844" data-type="line" data-label="" points="51.05886778258409,382.0981756629679 51.05886778258409,386.3110776753809 39.99999999999994,386.3110776753809 39.99999999999994,348.18431446304305 51.05886778258409,348.18431446304305 51.05886778258409,343.97141245063005" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="1.0500000000000007,0.39999999999999947 1.25,0.39999999999999947 1.25,1.34 -5.375,1.34 -5.375,1.0999999999999999 -12,1.0999999999999999 -12,0.1100000000000021" data-type="line" data-label="" points="325.95072409253333,325.2239984953922 330.16362610494633,325.2239984953922 330.16362610494633,305.423359037051 190.6112469437652,305.423359037051 190.6112469437652,310.4788414519466 51.05886778258409,310.4788414519466 51.05886778258409,331.332706413391" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="1.0500000000000007,0.1999999999999993 3.111,0.20000000000000012 3.111,-1.2999999999999996 -12,-1.2999999999999996 -12,-1.6999999999999993" data-type="line" data-label="" points="325.95072409253333,329.4369005078052 369.36467933044946,329.4369005078052 369.36467933044946,361.0336656009028 51.05886778258409,361.0336656009028 51.05886778258409,369.45946962572884" 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="281.71525296219664" y="314.69174346435966" width="44.23547113033669" height="37.91611811171708" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.047473214285714285"/></g><g><rect data-type="rect" data-label="schematic_component_1" data-x="-11.782499999999999" data-y="-2" x="44.212902012412954" y="369.45946962572884" width="22.854993417340637" height="12.638706037239047" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.047473214285714285"/></g><g><rect data-type="rect" data-label="schematic_component_2" data-x="-11.782499999999999" data-y="-0.18999999999999861" x="44.212902012412954" y="331.33270641339107" width="22.854993417340637" height="12.638706037239047" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.047473214285714285"/></g><g><rect data-type="rect" data-label="schematic_component_3" data-x="-11.7225" data-y="1.6750000000000007" x="44.21290201241294" y="292.04739514763963" width="25.382734624788384" height="12.638706037239103" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.047473214285714285"/></g><g><rect data-type="rect" data-label="schematic_component_4" data-x="12" data-y="-1" x="550.2877562535264" y="345.867218356216" width="12.63870603723899" height="17.694188452134654" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.047473214285714285"/></g><g><rect data-type="rect" data-label="schematic_component_5" data-x="13.517500000000002" data-y="-1.3000000000000003" x="577.1450065826593" y="354.71431258228324" width="22.854993417340665" height="12.638706037239103" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.047473214285714285"/></g><g><rect data-type="rect" data-label="TPS923655DMTR" data-x="0.13" data-y="-1.0299999999999998" x="290.1410569870227" y="353.45044197855935" width="32.86063569682153" height="3.7916118111717196" fill="rgba(160, 0, 220, 0.14)" stroke="black" stroke-width="0.047473214285714285"/></g><g><rect data-type="rect" data-label="U1" data-x="-0.53" data-y="1.0150000000000001" x="288.87718638329886" y="309.636261049464" width="7.583223622343382" height="5.2661275155163025" fill="rgba(160, 0, 220, 0.14)" stroke="black" stroke-width="0.047473214285714285"/></g><g><rect data-type="rect" data-label="netId: U1.FAULT to RFAULT.pin1
2
2
  globalConnNetId: connectivity_net2" data-x="-2.171" data-y="-0.5" x="234.50968591310885" y="342.07560654504425" width="47.18450253902577" height="4.2129020124129966" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.047473214285714285"/></g><g><rect data-type="rect" data-label="netId: U1.FAULT to RFAULT.pin1
3
3
  globalConnNetId: connectivity_net2" data-x="-12" data-y="3.0960000000000014" x="48.95241677637759" y="244.84182809855184" width="4.2129020124129966" height="47.18450253902574" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.047473214285714285"/></g><g><rect data-type="rect" data-label="netId: U1.COMP to CCOMP.pos
4
4
  globalConnNetId: connectivity_net3" data-x="2.031" data-y="1.1102230246251565e-16" x="325.9717886025953" y="331.5433515140117" width="41.28643972164758" height="4.2129020124129966" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.047473214285714285"/></g><g><rect data-type="rect" data-label="netId: U1.COMP to CCOMP.pos
5
5
  globalConnNetId: connectivity_net3" data-x="10.719" data-y="-1" x="508.9802520218167" y="352.60786157607674" width="41.28643972164758" height="4.212902012413053" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.047473214285714285"/></g><g><rect data-type="rect" data-label="netId: U1.FSET to RFSET.pin1
6
- globalConnNetId: connectivity_net0" data-x="2.275" data-y="0.1999999999999993" x="330.1636261049464" y="327.3304495015987" width="43.182245627233385" height="4.2129020124129966" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.047473214285714285"/></g><g><rect data-type="rect" data-label="netId: U1.TEMP to RTEMP.pin1
7
- globalConnNetId: connectivity_net1" data-x="2.275" data-y="0.39999999999999947" x="330.1636261049464" y="323.11754748918565" width="43.182245627233385" height="4.212902012413053" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.047473214285714285"/></g><g><rect data-type="rect" data-label="netId: GND
6
+ globalConnNetId: connectivity_net0" data-x="2.0805000000000007" data-y="1.2249999999999996" x="345.5512507052848" y="286.2546548805718" width="4.212902012413053" height="43.182245627233385" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.047473214285714285"/></g><g><rect data-type="rect" data-label="netId: U1.TEMP to RTEMP.pin1
7
+ globalConnNetId: connectivity_net1" data-x="1.25" data-y="2.365" x="328.05717509873983" y="262.24111340981756" width="4.2129020124129966" height="43.182245627233385" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.047473214285714285"/></g><g><rect data-type="rect" data-label="netId: GND
8
8
  globalConnNetId: connectivity_net5" data-x="-12" data-y="-2.71" x="46.00338536768845" y="386.31107767538094" width="10.110964829791271" height="8.847094226067327" fill="#00000066" stroke="#000000" stroke-width="0.047473214285714285"/></g><g><rect data-type="rect" data-label="netId: GND
9
9
  globalConnNetId: connectivity_net5" data-x="13.3" data-y="-1.8110000000000008" x="578.935489937935" y="367.3740831295844" width="10.110964829791214" height="8.847094226067327" fill="#00000066" stroke="#000000" stroke-width="0.047473214285714285"/></g><g><rect data-type="rect" data-label="netId: CCOMP.neg to RCOMP.pin1
10
10
  globalConnNetId: connectivity_net4" data-x="13.3" data-y="-0.5749999999999996" x="581.8845213466241" y="341.022381041941" width="4.2129020124129966" height="9.479029527929299" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.047473214285714285"/></g><g><circle data-type="point" data-label="U1.1
@@ -37,8 +37,8 @@ orientation: x-" data-x="-1.05" data-y="-0.5" cx="281.71525296219664" cy="344.18
37
37
  orientation: y+" data-x="-12" data-y="1.9750000000000014" cx="51.05886778258409" cy="292.04739514763963" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g><circle data-type="point" data-label="anchorPoint
38
38
  orientation: x+" data-x="1.05" data-y="1.1102230246251565e-16" cx="325.95072409253333" cy="333.6498025202182" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g><circle data-type="point" data-label="anchorPoint
39
39
  orientation: x-" data-x="11.7" data-y="-1" cx="550.2877562535264" cy="354.7143125822833" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g><circle data-type="point" data-label="anchorPoint
40
- orientation: x+" data-x="1.25" data-y="0.1999999999999993" cx="330.16362610494633" cy="329.4369005078052" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g><circle data-type="point" data-label="anchorPoint
41
- orientation: x+" data-x="1.25" data-y="0.39999999999999947" cx="330.16362610494633" cy="325.2239984953922" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g><circle data-type="point" data-label="anchorPoint
40
+ orientation: y+" data-x="2.0805000000000007" data-y="0.1999999999999997" cx="347.65770171149137" cy="329.4369005078052" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g><circle data-type="point" data-label="anchorPoint
41
+ orientation: y+" data-x="1.25" data-y="1.34" cx="330.16362610494633" cy="305.423359037051" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g><circle data-type="point" data-label="anchorPoint
42
42
  orientation: y-" data-x="-12" data-y="-2.5" cx="51.05886778258409" cy="386.3110776753809" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g><circle data-type="point" data-label="anchorPoint
43
43
  orientation: y-" data-x="13.3" data-y="-1.600000000000001" cx="583.9909723528306" cy="367.35301861952235" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g><circle data-type="point" data-label="anchorPoint
44
44
  orientation: y+" data-x="13.3" data-y="-0.7999999999999996" cx="583.9909723528306" cy="350.50141056987025" 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[
@@ -1,5 +1,7 @@
1
1
  import { expect, test } from "bun:test"
2
+ import { isPathCollidingWithObstacles } from "lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver2/collisions"
2
3
  import { SchematicTracePipelineSolver } from "lib/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver"
4
+ import { getTextBoxBounds } from "lib/utils/textBoxBounds"
3
5
  import inputProblem from "./bug-report-20260708T095725Z.json"
4
6
  import "tests/fixtures/matcher"
5
7
 
@@ -8,5 +10,18 @@ test("bug-report-20260708T095725Z", () => {
8
10
 
9
11
  solver.solve()
10
12
 
13
+ const finalTraces = solver.netLabelTraceCollisionSolver!.getOutput().traces
14
+ expect(finalTraces.map((trace) => trace.mspPairId)).toContain("U1.14-RTEMP.1")
15
+
16
+ const componentTextBounds = inputProblem.textBoxes.map((textBox) =>
17
+ getTextBoxBounds(textBox),
18
+ )
19
+ const crossingTraceIds = finalTraces
20
+ .filter((trace) =>
21
+ isPathCollidingWithObstacles(trace.tracePath, componentTextBounds),
22
+ )
23
+ .map((trace) => trace.mspPairId)
24
+
25
+ expect(crossingTraceIds).toEqual([])
11
26
  expect(solver).toMatchSolverSnapshot(import.meta.path)
12
27
  })