@tscircuit/schematic-trace-solver 0.0.49 → 0.0.50
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 +78 -1
- package/dist/index.js +762 -41
- package/lib/solvers/AvailableNetOrientationSolver/AvailableNetOrientationSolver.ts +682 -0
- package/lib/solvers/AvailableNetOrientationSolver/constants.ts +6 -0
- package/lib/solvers/AvailableNetOrientationSolver/geometry.ts +192 -0
- package/lib/solvers/AvailableNetOrientationSolver/traces.ts +43 -0
- package/lib/solvers/AvailableNetOrientationSolver/types.ts +44 -0
- package/lib/solvers/AvailableNetOrientationSolver/visualize.ts +123 -0
- package/lib/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver.ts +14 -0
- package/package.json +1 -1
- package/tests/assets/example22.json +1 -1
- package/tests/examples/__snapshots__/example12.snap.svg +33 -30
- package/tests/examples/__snapshots__/example13.snap.svg +10 -4
- package/tests/examples/__snapshots__/example14.snap.svg +10 -4
- package/tests/examples/__snapshots__/example16.snap.svg +33 -27
- package/tests/examples/__snapshots__/example20.snap.svg +29 -23
- package/tests/examples/__snapshots__/example21.snap.svg +77 -65
- package/tests/examples/__snapshots__/example22.snap.svg +31 -25
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import type { Point } from "@tscircuit/math-utils"
|
|
2
|
+
import type { SolvedTracePath } from "lib/solvers/SchematicTraceLinesSolver/SchematicTraceLinesSolver"
|
|
3
|
+
import type { InputProblem } from "lib/types/InputProblem"
|
|
4
|
+
import type { FacingDirection } from "lib/utils/dir"
|
|
5
|
+
import { EPS, TRACE_BOUNDARY_TOLERANCE } from "./constants"
|
|
6
|
+
import type { Bounds, ChipSide } from "./types"
|
|
7
|
+
|
|
8
|
+
export const isYOrientation = (
|
|
9
|
+
orientation: FacingDirection,
|
|
10
|
+
): orientation is "y+" | "y-" => orientation === "y+" || orientation === "y-"
|
|
11
|
+
|
|
12
|
+
export const isXOrientation = (
|
|
13
|
+
orientation: FacingDirection,
|
|
14
|
+
): orientation is "x+" | "x-" => orientation === "x+" || orientation === "x-"
|
|
15
|
+
|
|
16
|
+
export const rectsOverlap = (a: Bounds, b: Bounds) =>
|
|
17
|
+
Math.min(a.maxX, b.maxX) - Math.max(a.minX, b.minX) > EPS &&
|
|
18
|
+
Math.min(a.maxY, b.maxY) - Math.max(a.minY, b.minY) > EPS
|
|
19
|
+
|
|
20
|
+
export const rangesOverlap = (
|
|
21
|
+
minA: number,
|
|
22
|
+
maxA: number,
|
|
23
|
+
minB: number,
|
|
24
|
+
maxB: number,
|
|
25
|
+
) => Math.min(maxA, maxB) - Math.max(minA, minB) > EPS
|
|
26
|
+
|
|
27
|
+
export const traceCrossesBoundsInterior = (
|
|
28
|
+
bounds: Bounds,
|
|
29
|
+
traceMap: Record<string, SolvedTracePath>,
|
|
30
|
+
) => {
|
|
31
|
+
for (const trace of Object.values(traceMap)) {
|
|
32
|
+
const points = trace.tracePath
|
|
33
|
+
for (let i = 0; i < points.length - 1; i++) {
|
|
34
|
+
if (segmentCrossesBoundsInterior(points[i]!, points[i + 1]!, bounds)) {
|
|
35
|
+
return true
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return false
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const segmentCrossesBoundsInterior = (p1: Point, p2: Point, bounds: Bounds) => {
|
|
44
|
+
const interiorBounds = {
|
|
45
|
+
minX: bounds.minX + TRACE_BOUNDARY_TOLERANCE,
|
|
46
|
+
minY: bounds.minY + TRACE_BOUNDARY_TOLERANCE,
|
|
47
|
+
maxX: bounds.maxX - TRACE_BOUNDARY_TOLERANCE,
|
|
48
|
+
maxY: bounds.maxY - TRACE_BOUNDARY_TOLERANCE,
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (
|
|
52
|
+
interiorBounds.minX >= interiorBounds.maxX ||
|
|
53
|
+
interiorBounds.minY >= interiorBounds.maxY
|
|
54
|
+
) {
|
|
55
|
+
return false
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (sameX(p1, p2)) {
|
|
59
|
+
if (
|
|
60
|
+
p1.x <= interiorBounds.minX + EPS ||
|
|
61
|
+
p1.x >= interiorBounds.maxX - EPS
|
|
62
|
+
) {
|
|
63
|
+
return false
|
|
64
|
+
}
|
|
65
|
+
return rangesOverlap(
|
|
66
|
+
Math.min(p1.y, p2.y),
|
|
67
|
+
Math.max(p1.y, p2.y),
|
|
68
|
+
interiorBounds.minY,
|
|
69
|
+
interiorBounds.maxY,
|
|
70
|
+
)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (sameY(p1, p2)) {
|
|
74
|
+
if (
|
|
75
|
+
p1.y <= interiorBounds.minY + EPS ||
|
|
76
|
+
p1.y >= interiorBounds.maxY - EPS
|
|
77
|
+
) {
|
|
78
|
+
return false
|
|
79
|
+
}
|
|
80
|
+
return rangesOverlap(
|
|
81
|
+
Math.min(p1.x, p2.x),
|
|
82
|
+
Math.max(p1.x, p2.x),
|
|
83
|
+
interiorBounds.minX,
|
|
84
|
+
interiorBounds.maxX,
|
|
85
|
+
)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return false
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export const tracePathCrossesAnyTrace = (
|
|
92
|
+
tracePath: Point[],
|
|
93
|
+
traceMap: Record<string, SolvedTracePath>,
|
|
94
|
+
) => {
|
|
95
|
+
for (const trace of Object.values(traceMap)) {
|
|
96
|
+
const points = trace.tracePath
|
|
97
|
+
for (let i = 0; i < tracePath.length - 1; i++) {
|
|
98
|
+
for (let j = 0; j < points.length - 1; j++) {
|
|
99
|
+
if (
|
|
100
|
+
segmentsStrictlyCross(
|
|
101
|
+
tracePath[i]!,
|
|
102
|
+
tracePath[i + 1]!,
|
|
103
|
+
points[j]!,
|
|
104
|
+
points[j + 1]!,
|
|
105
|
+
)
|
|
106
|
+
) {
|
|
107
|
+
return true
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return false
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const segmentsStrictlyCross = (a1: Point, a2: Point, b1: Point, b2: Point) => {
|
|
117
|
+
if (sameX(a1, a2) && sameY(b1, b2)) {
|
|
118
|
+
return (
|
|
119
|
+
a1.x > Math.min(b1.x, b2.x) + EPS &&
|
|
120
|
+
a1.x < Math.max(b1.x, b2.x) - EPS &&
|
|
121
|
+
b1.y > Math.min(a1.y, a2.y) + EPS &&
|
|
122
|
+
b1.y < Math.max(a1.y, a2.y) - EPS
|
|
123
|
+
)
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (sameY(a1, a2) && sameX(b1, b2)) {
|
|
127
|
+
return (
|
|
128
|
+
b1.x > Math.min(a1.x, a2.x) + EPS &&
|
|
129
|
+
b1.x < Math.max(a1.x, a2.x) - EPS &&
|
|
130
|
+
a1.y > Math.min(b1.y, b2.y) + EPS &&
|
|
131
|
+
a1.y < Math.max(b1.y, b2.y) - EPS
|
|
132
|
+
)
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return false
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export const getSideDistances = (point: Point, bounds: Bounds) =>
|
|
139
|
+
[
|
|
140
|
+
["left", Math.abs(point.x - bounds.minX)] as const,
|
|
141
|
+
["right", Math.abs(point.x - bounds.maxX)] as const,
|
|
142
|
+
["bottom", Math.abs(point.y - bounds.minY)] as const,
|
|
143
|
+
["top", Math.abs(point.y - bounds.maxY)] as const,
|
|
144
|
+
] satisfies Array<readonly [ChipSide, number]>
|
|
145
|
+
|
|
146
|
+
export const getConnectorTracePath = (
|
|
147
|
+
source: Point,
|
|
148
|
+
target: Point,
|
|
149
|
+
orientation: FacingDirection,
|
|
150
|
+
) =>
|
|
151
|
+
simplifyOrthogonalPath(
|
|
152
|
+
isYOrientation(orientation)
|
|
153
|
+
? [source, { x: target.x, y: source.y }, target]
|
|
154
|
+
: [source, { x: source.x, y: target.y }, target],
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
const simplifyOrthogonalPath = (path: Point[]) => {
|
|
158
|
+
const deduped = path.filter(
|
|
159
|
+
(point, index) => index === 0 || !pointsEqual(point, path[index - 1]!),
|
|
160
|
+
)
|
|
161
|
+
if (deduped.length < 3) return deduped
|
|
162
|
+
|
|
163
|
+
const simplified: Point[] = [deduped[0]!]
|
|
164
|
+
for (let i = 1; i < deduped.length - 1; i++) {
|
|
165
|
+
const prev = simplified[simplified.length - 1]!
|
|
166
|
+
const point = deduped[i]!
|
|
167
|
+
const next = deduped[i + 1]!
|
|
168
|
+
if (
|
|
169
|
+
(sameX(prev, point) && sameX(point, next)) ||
|
|
170
|
+
(sameY(prev, point) && sameY(point, next))
|
|
171
|
+
) {
|
|
172
|
+
continue
|
|
173
|
+
}
|
|
174
|
+
simplified.push(point)
|
|
175
|
+
}
|
|
176
|
+
simplified.push(deduped[deduped.length - 1]!)
|
|
177
|
+
return simplified
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const pointsEqual = (a: Point, b: Point) => sameX(a, b) && sameY(a, b)
|
|
181
|
+
|
|
182
|
+
const sameX = (a: Point, b: Point) => Math.abs(a.x - b.x) <= EPS
|
|
183
|
+
|
|
184
|
+
const sameY = (a: Point, b: Point) => Math.abs(a.y - b.y) <= EPS
|
|
185
|
+
|
|
186
|
+
export const getMaxSearchDistance = (inputProblem: InputProblem) => {
|
|
187
|
+
const maxChipWidth = Math.max(
|
|
188
|
+
...inputProblem.chips.map((chip) => chip.width),
|
|
189
|
+
1,
|
|
190
|
+
)
|
|
191
|
+
return maxChipWidth * 3
|
|
192
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { NetLabelPlacement } from "lib/solvers/NetLabelPlacementSolver/NetLabelPlacementSolver"
|
|
2
|
+
import type { SolvedTracePath } from "lib/solvers/SchematicTraceLinesSolver/SchematicTraceLinesSolver"
|
|
3
|
+
import type { InputPin, InputProblem } from "lib/types/InputProblem"
|
|
4
|
+
import type { CandidateLabel } from "./types"
|
|
5
|
+
|
|
6
|
+
export const getPinMap = (inputProblem: InputProblem) => {
|
|
7
|
+
const pinMap: Record<string, InputPin & { chipId: string }> = {}
|
|
8
|
+
for (const chip of inputProblem.chips) {
|
|
9
|
+
for (const pin of chip.pins) {
|
|
10
|
+
pinMap[pin.pinId] = { ...pin, chipId: chip.chipId }
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
return pinMap
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const getTracePins = (
|
|
17
|
+
label: NetLabelPlacement,
|
|
18
|
+
pinMap: Record<string, InputPin & { chipId: string }>,
|
|
19
|
+
): SolvedTracePath["pins"] => {
|
|
20
|
+
const pins = label.pinIds.flatMap((pinId) => {
|
|
21
|
+
const pin = pinMap[pinId]
|
|
22
|
+
return pin ? [pin] : []
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
if (pins.length >= 2) return [pins[0]!, pins[1]!]
|
|
26
|
+
if (pins.length === 1) return [pins[0]!, pins[0]!]
|
|
27
|
+
|
|
28
|
+
const syntheticPin = {
|
|
29
|
+
pinId: `${label.globalConnNetId}-netlabel-anchor`,
|
|
30
|
+
x: label.anchorPoint.x,
|
|
31
|
+
y: label.anchorPoint.y,
|
|
32
|
+
chipId: "available-net-orientation",
|
|
33
|
+
}
|
|
34
|
+
return [syntheticPin, syntheticPin]
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export const toNetLabelPlacementPatch = (candidate: CandidateLabel) => ({
|
|
38
|
+
orientation: candidate.orientation,
|
|
39
|
+
anchorPoint: candidate.anchorPoint,
|
|
40
|
+
center: candidate.center,
|
|
41
|
+
width: candidate.width,
|
|
42
|
+
height: candidate.height,
|
|
43
|
+
})
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { Point } from "@tscircuit/math-utils"
|
|
2
|
+
import type { NetLabelPlacement } from "lib/solvers/NetLabelPlacementSolver/NetLabelPlacementSolver"
|
|
3
|
+
import type { SolvedTracePath } from "lib/solvers/SchematicTraceLinesSolver/SchematicTraceLinesSolver"
|
|
4
|
+
import type { InputProblem } from "lib/types/InputProblem"
|
|
5
|
+
import type { FacingDirection } from "lib/utils/dir"
|
|
6
|
+
|
|
7
|
+
export interface AvailableNetOrientationSolverParams {
|
|
8
|
+
inputProblem: InputProblem
|
|
9
|
+
traces: SolvedTracePath[]
|
|
10
|
+
netLabelPlacements: NetLabelPlacement[]
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export type Bounds = {
|
|
14
|
+
minX: number
|
|
15
|
+
minY: number
|
|
16
|
+
maxX: number
|
|
17
|
+
maxY: number
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export type ChipSide = "left" | "right" | "top" | "bottom"
|
|
21
|
+
|
|
22
|
+
export type CandidateLabel = {
|
|
23
|
+
orientation: FacingDirection
|
|
24
|
+
anchorPoint: Point
|
|
25
|
+
center: Point
|
|
26
|
+
width: number
|
|
27
|
+
height: number
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export type CandidateStatus =
|
|
31
|
+
| "valid"
|
|
32
|
+
| "chip-collision"
|
|
33
|
+
| "trace-collision"
|
|
34
|
+
| "netlabel-collision"
|
|
35
|
+
|
|
36
|
+
export type CandidatePhase = "rotate" | "shift"
|
|
37
|
+
|
|
38
|
+
export type EvaluatedCandidate = CandidateLabel & {
|
|
39
|
+
status: CandidateStatus
|
|
40
|
+
selected: boolean
|
|
41
|
+
phase: CandidatePhase
|
|
42
|
+
distance?: number
|
|
43
|
+
outwardDistance?: number
|
|
44
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import type { GraphicsObject } from "graphics-debug"
|
|
2
|
+
import type { NetLabelPlacement } from "lib/solvers/NetLabelPlacementSolver/NetLabelPlacementSolver"
|
|
3
|
+
import type { SolvedTracePath } from "lib/solvers/SchematicTraceLinesSolver/SchematicTraceLinesSolver"
|
|
4
|
+
import { visualizeInputProblem } from "lib/solvers/SchematicTracePipelineSolver/visualizeInputProblem"
|
|
5
|
+
import type { InputProblem } from "lib/types/InputProblem"
|
|
6
|
+
import { getColorFromString } from "lib/utils/getColorFromString"
|
|
7
|
+
import { CANDIDATE_REJECTED_COLOR, CANDIDATE_SELECTED_COLOR } from "./constants"
|
|
8
|
+
import type { EvaluatedCandidate } from "./types"
|
|
9
|
+
|
|
10
|
+
export const visualizeAvailableNetOrientationSolver = (params: {
|
|
11
|
+
inputProblem: InputProblem
|
|
12
|
+
traces: SolvedTracePath[]
|
|
13
|
+
outputNetLabelPlacements: NetLabelPlacement[]
|
|
14
|
+
currentLabel: NetLabelPlacement | null
|
|
15
|
+
currentCandidateResults: EvaluatedCandidate[]
|
|
16
|
+
solved: boolean
|
|
17
|
+
}): GraphicsObject => {
|
|
18
|
+
const graphics = visualizeInputProblem(params.inputProblem)
|
|
19
|
+
ensureGraphicsArrays(graphics)
|
|
20
|
+
|
|
21
|
+
drawTraces(graphics, params.traces)
|
|
22
|
+
drawNetLabels(graphics, params.outputNetLabelPlacements)
|
|
23
|
+
drawCurrentLabel(graphics, params.currentLabel, params.solved)
|
|
24
|
+
drawCurrentCandidates(graphics, params.currentCandidateResults, params.solved)
|
|
25
|
+
|
|
26
|
+
return graphics
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const drawTraces = (graphics: GraphicsObject, traces: SolvedTracePath[]) => {
|
|
30
|
+
for (const trace of traces) {
|
|
31
|
+
graphics.lines!.push({
|
|
32
|
+
points: trace.tracePath,
|
|
33
|
+
strokeColor: "purple",
|
|
34
|
+
} as any)
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const drawNetLabels = (
|
|
39
|
+
graphics: GraphicsObject,
|
|
40
|
+
labels: NetLabelPlacement[],
|
|
41
|
+
) => {
|
|
42
|
+
for (const label of labels) {
|
|
43
|
+
graphics.rects!.push({
|
|
44
|
+
center: label.center,
|
|
45
|
+
width: label.width,
|
|
46
|
+
height: label.height,
|
|
47
|
+
fill: getColorFromString(label.globalConnNetId, 0.35),
|
|
48
|
+
strokeColor: getColorFromString(label.globalConnNetId, 0.9),
|
|
49
|
+
label: `netId: ${label.netId}\nglobalConnNetId: ${label.globalConnNetId}`,
|
|
50
|
+
} as any)
|
|
51
|
+
graphics.points!.push({
|
|
52
|
+
x: label.anchorPoint.x,
|
|
53
|
+
y: label.anchorPoint.y,
|
|
54
|
+
color: getColorFromString(label.globalConnNetId, 0.9),
|
|
55
|
+
label: `anchorPoint\norientation: ${label.orientation}`,
|
|
56
|
+
} as any)
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const drawCurrentLabel = (
|
|
61
|
+
graphics: GraphicsObject,
|
|
62
|
+
currentLabel: NetLabelPlacement | null,
|
|
63
|
+
solved: boolean,
|
|
64
|
+
) => {
|
|
65
|
+
if (!currentLabel || solved) return
|
|
66
|
+
|
|
67
|
+
graphics.rects!.push({
|
|
68
|
+
center: currentLabel.center,
|
|
69
|
+
width: currentLabel.width,
|
|
70
|
+
height: currentLabel.height,
|
|
71
|
+
fill: "rgba(255, 0, 0, 0.2)",
|
|
72
|
+
strokeColor: CANDIDATE_REJECTED_COLOR,
|
|
73
|
+
label: `available orientation target\n${currentLabel.netId ?? currentLabel.globalConnNetId}`,
|
|
74
|
+
} as any)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const drawCurrentCandidates = (
|
|
78
|
+
graphics: GraphicsObject,
|
|
79
|
+
candidates: EvaluatedCandidate[],
|
|
80
|
+
solved: boolean,
|
|
81
|
+
) => {
|
|
82
|
+
if (solved) return
|
|
83
|
+
|
|
84
|
+
for (const candidate of candidates) {
|
|
85
|
+
const color = candidate.selected
|
|
86
|
+
? CANDIDATE_SELECTED_COLOR
|
|
87
|
+
: CANDIDATE_REJECTED_COLOR
|
|
88
|
+
const distanceLabel =
|
|
89
|
+
candidate.distance === undefined
|
|
90
|
+
? ""
|
|
91
|
+
: `\ndistance: ${candidate.distance.toFixed(3)}`
|
|
92
|
+
const outwardDistanceLabel =
|
|
93
|
+
candidate.outwardDistance === undefined || candidate.outwardDistance === 0
|
|
94
|
+
? ""
|
|
95
|
+
: `\noutward distance: ${candidate.outwardDistance.toFixed(3)}`
|
|
96
|
+
|
|
97
|
+
graphics.rects!.push({
|
|
98
|
+
center: candidate.center,
|
|
99
|
+
width: candidate.width,
|
|
100
|
+
height: candidate.height,
|
|
101
|
+
fill: candidate.selected
|
|
102
|
+
? "rgba(0, 0, 255, 0.2)"
|
|
103
|
+
: "rgba(255, 0, 0, 0.15)",
|
|
104
|
+
strokeColor: color,
|
|
105
|
+
strokeDash: candidate.selected ? undefined : "4 2",
|
|
106
|
+
label: `${candidate.selected ? "selected" : candidate.status} available orientation\nphase: ${candidate.phase}\norientation: ${candidate.orientation}${distanceLabel}${outwardDistanceLabel}`,
|
|
107
|
+
} as any)
|
|
108
|
+
graphics.points!.push({
|
|
109
|
+
x: candidate.anchorPoint.x,
|
|
110
|
+
y: candidate.anchorPoint.y,
|
|
111
|
+
color,
|
|
112
|
+
label: `candidate anchor\n${candidate.phase}\n${candidate.orientation}`,
|
|
113
|
+
} as any)
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const ensureGraphicsArrays = (graphics: GraphicsObject) => {
|
|
118
|
+
if (!graphics.lines) graphics.lines = []
|
|
119
|
+
if (!graphics.points) graphics.points = []
|
|
120
|
+
if (!graphics.rects) graphics.rects = []
|
|
121
|
+
if (!graphics.circles) graphics.circles = []
|
|
122
|
+
if (!graphics.texts) graphics.texts = []
|
|
123
|
+
}
|
|
@@ -21,6 +21,7 @@ import { LongDistancePairSolver } from "../LongDistancePairSolver/LongDistancePa
|
|
|
21
21
|
import { MergedNetLabelObstacleSolver } from "../TraceLabelOverlapAvoidanceSolver/sub-solvers/LabelMergingSolver/LabelMergingSolver"
|
|
22
22
|
import { TraceCleanupSolver } from "../TraceCleanupSolver/TraceCleanupSolver"
|
|
23
23
|
import { Example28Solver } from "../Example28Solver/Example28Solver"
|
|
24
|
+
import { AvailableNetOrientationSolver } from "../AvailableNetOrientationSolver/AvailableNetOrientationSolver"
|
|
24
25
|
|
|
25
26
|
type PipelineStep<T extends new (...args: any[]) => BaseSolver> = {
|
|
26
27
|
solverName: string
|
|
@@ -71,6 +72,7 @@ export class SchematicTracePipelineSolver extends BaseSolver {
|
|
|
71
72
|
traceLabelOverlapAvoidanceSolver?: TraceLabelOverlapAvoidanceSolver
|
|
72
73
|
traceCleanupSolver?: TraceCleanupSolver
|
|
73
74
|
example28Solver?: Example28Solver
|
|
75
|
+
availableNetOrientationSolver?: AvailableNetOrientationSolver
|
|
74
76
|
|
|
75
77
|
startTimeOfPhase: Record<string, number>
|
|
76
78
|
endTimeOfPhase: Record<string, number>
|
|
@@ -240,6 +242,18 @@ export class SchematicTracePipelineSolver extends BaseSolver {
|
|
|
240
242
|
},
|
|
241
243
|
]
|
|
242
244
|
}),
|
|
245
|
+
definePipelineStep(
|
|
246
|
+
"availableNetOrientationSolver",
|
|
247
|
+
AvailableNetOrientationSolver,
|
|
248
|
+
(instance) => [
|
|
249
|
+
{
|
|
250
|
+
inputProblem: instance.inputProblem,
|
|
251
|
+
traces: instance.example28Solver!.outputTraces,
|
|
252
|
+
netLabelPlacements:
|
|
253
|
+
instance.example28Solver!.outputNetLabelPlacements,
|
|
254
|
+
},
|
|
255
|
+
],
|
|
256
|
+
),
|
|
243
257
|
]
|
|
244
258
|
|
|
245
259
|
constructor(inputProblem: InputProblem) {
|
package/package.json
CHANGED
|
@@ -2,96 +2,99 @@
|
|
|
2
2
|
<rect width="100%" height="100%" fill="white" />
|
|
3
3
|
<g>
|
|
4
4
|
<circle data-type="point" data-label="J1.1
|
|
5
|
-
x+" data-x="1.1" data-y="0.2" cx="
|
|
5
|
+
x+" data-x="1.1" data-y="0.2" cx="301.5156017830609" cy="201.4588202080238" r="3" fill="hsl(218, 100%, 50%, 0.8)" />
|
|
6
6
|
</g>
|
|
7
7
|
<g>
|
|
8
8
|
<circle data-type="point" data-label="J1.2
|
|
9
|
-
x+" data-x="1.1" data-y="0" cx="
|
|
9
|
+
x+" data-x="1.1" data-y="0" cx="301.5156017830609" cy="225.2329658246657" r="3" fill="hsl(219, 100%, 50%, 0.8)" />
|
|
10
10
|
</g>
|
|
11
11
|
<g>
|
|
12
12
|
<circle data-type="point" data-label="J1.3
|
|
13
|
-
x+" data-x="1.1" data-y="-0.2" cx="
|
|
13
|
+
x+" data-x="1.1" data-y="-0.2" cx="301.5156017830609" cy="249.00711144130761" r="3" fill="hsl(220, 100%, 50%, 0.8)" />
|
|
14
14
|
</g>
|
|
15
15
|
<g>
|
|
16
16
|
<circle data-type="point" data-label="R1.1
|
|
17
|
-
x-" data-x="0.5499999999999996" data-y="-1.7944553499999996" cx="
|
|
17
|
+
x-" data-x="0.5499999999999996" data-y="-1.7944553499999996" cx="236.13670133729568" cy="438.5411797919762" r="3" fill="hsl(226, 100%, 50%, 0.8)" />
|
|
18
18
|
</g>
|
|
19
19
|
<g>
|
|
20
20
|
<circle data-type="point" data-label="R1.2
|
|
21
|
-
x+" data-x="1.6499999999999997" data-y="-1.7944553499999996" cx="
|
|
21
|
+
x+" data-x="1.6499999999999997" data-y="-1.7944553499999996" cx="366.8945022288261" cy="438.5411797919762" r="3" fill="hsl(227, 100%, 50%, 0.8)" />
|
|
22
22
|
</g>
|
|
23
23
|
<g>
|
|
24
24
|
<circle data-type="point" data-label="C1.1
|
|
25
|
-
x-" data-x="2.3099999999999996" data-y="0.01999999999999985" cx="
|
|
25
|
+
x-" data-x="2.3099999999999996" data-y="0.01999999999999985" cx="445.34918276374435" cy="222.85555126300153" r="3" fill="hsl(121, 100%, 50%, 0.8)" />
|
|
26
26
|
</g>
|
|
27
27
|
<g>
|
|
28
28
|
<circle data-type="point" data-label="C1.2
|
|
29
|
-
x+" data-x="3.41" data-y="0.01999999999999985" cx="
|
|
29
|
+
x+" data-x="3.41" data-y="0.01999999999999985" cx="576.1069836552749" cy="222.85555126300153" r="3" fill="hsl(122, 100%, 50%, 0.8)" />
|
|
30
30
|
</g>
|
|
31
31
|
<g>
|
|
32
32
|
<circle data-type="point" data-label="anchorPoint
|
|
33
|
-
orientation: y+" data-x="1.4024999999999999" data-y="0.2" cx="
|
|
33
|
+
orientation: y+" data-x="1.4024999999999999" data-y="0.2" cx="337.4739970282318" cy="201.4588202080238" r="3" fill="hsl(40, 100%, 50%, 0.9)" />
|
|
34
34
|
</g>
|
|
35
35
|
<g>
|
|
36
36
|
<circle data-type="point" data-label="anchorPoint
|
|
37
|
-
orientation: x+" data-x="1.3" data-y="-0.4486138374999999" cx="
|
|
37
|
+
orientation: x+" data-x="1.3" data-y="-0.4486138374999999" cx="325.28974739970283" cy="278.5600193164933" r="3" fill="hsl(40, 100%, 50%, 0.9)" />
|
|
38
38
|
</g>
|
|
39
39
|
<g>
|
|
40
40
|
<circle data-type="point" data-label="anchorPoint
|
|
41
|
-
orientation: y-" data-x="1.8499999999999996" data-y="-1.7944553499999996" cx="
|
|
41
|
+
orientation: y-" data-x="1.8499999999999996" data-y="-1.7944553499999996" cx="390.668647845468" cy="438.5411797919762" r="3" fill="hsl(40, 100%, 50%, 0.9)" />
|
|
42
42
|
</g>
|
|
43
43
|
<g>
|
|
44
44
|
<circle data-type="point" data-label="anchorPoint
|
|
45
|
-
orientation:
|
|
45
|
+
orientation: y-" data-x="3.511" data-y="-0.4310000000000001" cx="588.1129271916791" cy="276.466249628529" r="3" fill="hsl(40, 100%, 50%, 0.9)" />
|
|
46
46
|
</g>
|
|
47
47
|
<g>
|
|
48
|
-
<polyline data-points="1.1,0.2 2.3099999999999996,0.01999999999999985" data-type="line" data-label="" points="
|
|
48
|
+
<polyline data-points="1.1,0.2 2.3099999999999996,0.01999999999999985" data-type="line" data-label="" points="301.5156017830609,201.4588202080238 445.34918276374435,222.85555126300153" fill="none" stroke="hsl(190, 100%, 50%, 0.8)" stroke-width="1" stroke-dasharray="4 2" />
|
|
49
49
|
</g>
|
|
50
50
|
<g>
|
|
51
|
-
<polyline data-points="1.1,0 0.5499999999999996,-1.7944553499999996" data-type="line" data-label="" points="
|
|
51
|
+
<polyline data-points="1.1,0 0.5499999999999996,-1.7944553499999996" data-type="line" data-label="" points="301.5156017830609,225.2329658246657 236.13670133729568,438.5411797919762" fill="none" stroke="hsl(158, 100%, 50%, 0.8)" stroke-width="1" stroke-dasharray="4 2" />
|
|
52
52
|
</g>
|
|
53
53
|
<g>
|
|
54
|
-
<polyline data-points="1.1,-0.2 1.6499999999999997,-1.7944553499999996" data-type="line" data-label="" points="
|
|
54
|
+
<polyline data-points="1.1,-0.2 1.6499999999999997,-1.7944553499999996" data-type="line" data-label="" points="301.5156017830609,249.00711144130761 366.8945022288261,438.5411797919762" fill="none" stroke="hsl(157, 100%, 50%, 0.8)" stroke-width="1" stroke-dasharray="4 2" />
|
|
55
55
|
</g>
|
|
56
56
|
<g>
|
|
57
|
-
<polyline data-points="1.1,-0.2 3.41,0.01999999999999985" data-type="line" data-label="" points="
|
|
57
|
+
<polyline data-points="1.1,-0.2 3.41,0.01999999999999985" data-type="line" data-label="" points="301.5156017830609,249.00711144130761 576.1069836552749,222.85555126300153" fill="none" stroke="hsl(157, 100%, 50%, 0.8)" stroke-width="1" stroke-dasharray="4 2" />
|
|
58
58
|
</g>
|
|
59
59
|
<g>
|
|
60
|
-
<polyline data-points="1.6499999999999997,-1.7944553499999996 3.41,0.01999999999999985" data-type="line" data-label="" points="
|
|
60
|
+
<polyline data-points="1.6499999999999997,-1.7944553499999996 3.41,0.01999999999999985" data-type="line" data-label="" points="366.8945022288261,438.5411797919762 576.1069836552749,222.85555126300153" fill="none" stroke="hsl(157, 100%, 50%, 0.8)" stroke-width="1" stroke-dasharray="4 2" />
|
|
61
61
|
</g>
|
|
62
62
|
<g>
|
|
63
|
-
<polyline data-points="1.1,0.2 1.7049999999999998,0.2 1.7049999999999998,0.01999999999999985 2.3099999999999996,0.01999999999999985" data-type="line" data-label="" points="
|
|
63
|
+
<polyline data-points="1.1,0.2 1.7049999999999998,0.2 1.7049999999999998,0.01999999999999985 2.3099999999999996,0.01999999999999985" data-type="line" data-label="" points="301.5156017830609,201.4588202080238 373.4323922734027,201.4588202080238 373.4323922734027,222.85555126300153 445.34918276374435,222.85555126300153" fill="none" stroke="purple" stroke-width="1" />
|
|
64
64
|
</g>
|
|
65
65
|
<g>
|
|
66
|
-
<polyline data-points="1.1,0 1.3,0 1.3,-0.8972276749999998 0.34999999999999964,-0.8972276749999998 0.34999999999999964,-1.7944553499999996 0.5499999999999996,-1.7944553499999996" data-type="line" data-label="" points="
|
|
66
|
+
<polyline data-points="1.1,0 1.3,0 1.3,-0.8972276749999998 0.34999999999999964,-0.8972276749999998 0.34999999999999964,-1.7944553499999996 0.5499999999999996,-1.7944553499999996" data-type="line" data-label="" points="301.5156017830609,225.2329658246657 325.28974739970283,225.2329658246657 325.28974739970283,331.88707280832097 212.36255572065375,331.88707280832097 212.36255572065375,438.5411797919762 236.13670133729568,438.5411797919762" fill="none" stroke="purple" stroke-width="1" />
|
|
67
67
|
</g>
|
|
68
68
|
<g>
|
|
69
|
-
<polyline data-points="1.6499999999999997,-1.7944553499999996 1.8499999999999996,-1.7944553499999996 1.8499999999999996,-0.2 1.1,-0.2" data-type="line" data-label="" points="
|
|
69
|
+
<polyline data-points="1.6499999999999997,-1.7944553499999996 1.8499999999999996,-1.7944553499999996 1.8499999999999996,-0.2 1.1,-0.2" data-type="line" data-label="" points="366.8945022288261,438.5411797919762 390.668647845468,438.5411797919762 390.668647845468,249.00711144130761 301.5156017830609,249.00711144130761" fill="none" stroke="purple" stroke-width="1" />
|
|
70
70
|
</g>
|
|
71
71
|
<g>
|
|
72
|
-
<
|
|
72
|
+
<polyline data-points="3.41,0.01999999999999985 3.511,0.01999999999999985 3.511,-0.4310000000000001" data-type="line" data-label="" points="576.1069836552749,222.85555126300153 588.1129271916791,222.85555126300153 588.1129271916791,276.466249628529" fill="none" stroke="purple" stroke-width="1" />
|
|
73
73
|
</g>
|
|
74
74
|
<g>
|
|
75
|
-
<rect data-type="rect" data-label="
|
|
75
|
+
<rect data-type="rect" data-label="schematic_component_0" data-x="0" data-y="0" x="40.00000000000003" y="177.6846745913819" width="261.5156017830609" height="95.09658246656761" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.008412500000000002" />
|
|
76
76
|
</g>
|
|
77
77
|
<g>
|
|
78
|
-
<rect data-type="rect" data-label="
|
|
78
|
+
<rect data-type="rect" data-label="schematic_component_1" data-x="1.0999999999999996" data-y="-1.7944553499999996" x="236.13670133729568" y="415.42613075780093" width="130.75780089153045" height="46.230098068350514" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.008412500000000002" />
|
|
79
|
+
</g>
|
|
80
|
+
<g>
|
|
81
|
+
<rect data-type="rect" data-label="schematic_component_2" data-x="2.86" data-y="0.01999999999999985" x="445.34918276374435" y="172.92984546805354" width="130.75780089153056" height="99.85141158989597" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.008412500000000002" />
|
|
79
82
|
</g>
|
|
80
83
|
<g>
|
|
81
84
|
<rect data-type="rect" data-label="netId: VCC
|
|
82
|
-
globalConnNetId: connectivity_net0" data-x="1.4024999999999999" data-y="0.42500000000000004" x="
|
|
85
|
+
globalConnNetId: connectivity_net0" data-x="1.4024999999999999" data-y="0.42500000000000004" x="325.5869242199108" y="147.96699257057952" width="23.77414561664193" height="53.49182763744429" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.008412500000000002" />
|
|
83
86
|
</g>
|
|
84
87
|
<g>
|
|
85
88
|
<rect data-type="rect" data-label="netId: OUT
|
|
86
|
-
globalConnNetId: connectivity_net1" data-x="1.5250000000000001" data-y="-0.4486138374999999" x="
|
|
89
|
+
globalConnNetId: connectivity_net1" data-x="1.5250000000000001" data-y="-0.4486138374999999" x="325.28974739970283" y="266.6729465081724" width="53.49182763744432" height="23.774145616641874" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.008412500000000002" />
|
|
87
90
|
</g>
|
|
88
91
|
<g>
|
|
89
92
|
<rect data-type="rect" data-label="netId: GND
|
|
90
|
-
globalConnNetId: connectivity_net2" data-x="1.8499999999999996" data-y="-2.0194553499999994" x="
|
|
93
|
+
globalConnNetId: connectivity_net2" data-x="1.8499999999999996" data-y="-2.0194553499999994" x="378.78157503714704" y="438.54117979197616" width="23.77414561664193" height="53.49182763744432" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.008412500000000002" />
|
|
91
94
|
</g>
|
|
92
95
|
<g>
|
|
93
96
|
<rect data-type="rect" data-label="netId: GND
|
|
94
|
-
globalConnNetId: connectivity_net2" data-x="3.
|
|
97
|
+
globalConnNetId: connectivity_net2" data-x="3.511" data-y="-0.6560000000000001" x="576.2258543833581" y="276.466249628529" width="23.77414561664193" height="53.49182763744432" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.008412500000000002" />
|
|
95
98
|
</g>
|
|
96
99
|
<g id="crosshair" style="display: none">
|
|
97
100
|
<line id="crosshair-h" y1="0" y2="640" stroke="#666" stroke-width="0.5" />
|
|
@@ -121,12 +124,12 @@ globalConnNetId: connectivity_net2" data-x="3.636" data-y="0.01999999999999985"
|
|
|
121
124
|
|
|
122
125
|
// Calculate real coordinates using inverse transformation
|
|
123
126
|
const matrix = {
|
|
124
|
-
"a":
|
|
127
|
+
"a": 118.8707280832095,
|
|
125
128
|
"c": 0,
|
|
126
|
-
"e":
|
|
129
|
+
"e": 170.75780089153048,
|
|
127
130
|
"b": 0,
|
|
128
|
-
"d": -
|
|
129
|
-
"f":
|
|
131
|
+
"d": -118.8707280832095,
|
|
132
|
+
"f": 225.2329658246657
|
|
130
133
|
};
|
|
131
134
|
// Manually invert and apply the affine transform
|
|
132
135
|
// Since we only use translate and scale, we can directly compute:
|