@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.
- package/dist/index.d.ts +2 -2
- package/dist/index.js +285 -212
- package/lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver2/SchematicTraceSingleLineSolver2.ts +58 -27
- package/lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver2/generateEndpointCollisionDetours.ts +1 -10
- package/lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver2/generateInternalSegmentCollisionDetours.ts +94 -0
- package/lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver2/pathOps.ts +10 -0
- package/lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver2/rect.ts +5 -1
- package/package.json +1 -1
- package/tests/bug-reports/bug-report-20260708T095725Z/__snapshots__/bug-report-20260708T095725Z.snap.svg +5 -5
- package/tests/bug-reports/bug-report-20260708T095725Z/bug-report-20260708T095725Z.test.ts +15 -0
- package/tests/repros/__snapshots__/repro-tps61222-trace-intersection.snap.svg +63 -220
- package/tests/repros/repro-tps61222-trace-intersection.test.ts +27 -0
- package/tests/solvers/SchematicTraceSingleLineSolver2/generate-internal-segment-collision-detours.test.ts +49 -0
|
@@ -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
|
|
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 {
|
|
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<
|
|
62
|
-
endpointTextObstacles: Set<
|
|
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
|
|
105
|
-
(
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
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
|
-
|
|
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
|
|
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,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
|
+
<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.
|
|
7
|
-
globalConnNetId: connectivity_net1" data-x="
|
|
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:
|
|
41
|
-
orientation:
|
|
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
|
})
|