@tscircuit/copper-pour-solver 0.0.24 → 0.0.25
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.js +323 -169
- package/lib/solvers/CopperPourPipelineSolver.ts +35 -22
- package/lib/solvers/copper-pour/generate-brep.ts +45 -52
- package/lib/solvers/copper-pour/get-board-polygon.ts +11 -19
- package/lib/solvers/copper-pour/manifold-geometry-adapter.ts +306 -0
- package/lib/solvers/copper-pour/process-obstacles.ts +65 -87
- package/package.json +4 -1
- package/tests/__snapshots__/2-layers-bottom.snap.svg +1 -1
- package/tests/__snapshots__/2-layers-top.snap.svg +1 -1
- package/tests/__snapshots__/board-edge-margin-2.snap.svg +1 -1
- package/tests/__snapshots__/board-edge-margin.snap.svg +1 -1
- package/tests/__snapshots__/hole-and-cutouts.snap.svg +1 -1
- package/tests/__snapshots__/larger-trace-margin.snap.svg +1 -1
- package/tests/__snapshots__/multiple-pours.snap.svg +1 -1
- package/tests/__snapshots__/pad-margin.snap.svg +1 -1
- package/tests/__snapshots__/polygon-board-2.snap.svg +1 -1
- package/tests/__snapshots__/polygon-board.snap.svg +1 -1
- package/tests/__snapshots__/smaller-trace-margin.snap.svg +1 -1
- package/tests/__snapshots__/stm32f746g-disco.test.tsbottom.snap.svg +1 -0
- package/tests/__snapshots__/stm32f746g-disco.test.tstop.snap.svg +1 -0
- package/tests/__snapshots__/via.snap.svg +1 -1
- package/tests/manifold-copper-pour-geometry.test.ts +194 -0
- package/tests/stm32f746g-disco.test.ts +16 -16
- package/lib/solvers/copper-pour/circle-to-polygon.ts +0 -15
|
@@ -1 +1 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" width="800" height="600" data-software-used-string="@tscircuit/core@0.0.849"><style></style><rect class="boundary" x="0" y="0" fill="#000" width="800" height="600" data-type="pcb_background" data-pcb-layer="global"/><rect class="pcb-boundary" fill="none" stroke="#fff" stroke-width="0.3" x="150" y="50" width="500" height="500" data-type="pcb_boundary" data-pcb-layer="global"/><rect class="pcb-pad" fill="rgb(77, 127, 196)" x="284" y="284" width="27" height="32" data-type="pcb_smtpad" data-pcb-layer="bottom"/><rect class="pcb-pad" fill="rgb(77, 127, 196)" x="233" y="284" width="27" height="32" data-type="pcb_smtpad" data-pcb-layer="bottom"/><path class="pcb-trace" stroke="rgb(77, 127, 196)" fill="none" d="M 297.5 300 L 297.5 379.512341162088" stroke-width="7.5" stroke-linecap="round" stroke-linejoin="round" shape-rendering="crispEdges" data-type="pcb_trace" data-pcb-layer="bottom"/><path class="pcb-trace" stroke="rgb(77, 127, 196)" fill="none" d="M 297.5 379.512341162088 L 303.1454224777405 385.1577636398285" stroke-width="7.5" stroke-linecap="round" stroke-linejoin="round" shape-rendering="crispEdges" data-type="pcb_trace" data-pcb-layer="bottom"/><path class="pcb-trace" stroke="rgb(77, 127, 196)" fill="none" d="M 303.1454224777405 385.1577636398285 L 306.25 393.75" stroke-width="7.5" stroke-linecap="round" stroke-linejoin="round" shape-rendering="crispEdges" data-type="pcb_trace" data-pcb-layer="bottom"/><path class="pcb-trace" stroke="rgb(77, 127, 196)" fill="none" d="M 306.25 393.75 L 306.25 393.75" stroke-width="7.5" stroke-linecap="round" stroke-linejoin="round" shape-rendering="crispEdges" data-type="pcb_trace" data-pcb-layer="bottom"/><path class="pcb-silkscreen pcb-silkscreen-bottom" d="M 246.5 264 L 321 264 L 321 336 L 246.5 336" fill="none" stroke="#5da9e9" stroke-width="5" stroke-linecap="round" stroke-linejoin="round" data-pcb-component-id="pcb_component_1" data-pcb-silkscreen-path-id="pcb_silkscreen_path_1" data-type="pcb_silkscreen_path" data-pcb-layer="bottom"/><text x="0" y="0" dx="0" dy="0" fill="#5da9e9" font-family="Arial, sans-serif" font-size="20" text-anchor="middle" dominant-baseline="central" transform="matrix(-1,0,0,1,272,239)" class="pcb-silkscreen-text pcb-silkscreen-bottom" data-pcb-silkscreen-text-id="pcb_component_1" stroke="none" data-type="pcb_silkscreen_text" data-pcb-layer="bottom">C1</text><path class="pcb-board" d="M 150 550 L 650 550 L 650 50 L 150 50 Z" fill="none" stroke="rgba(255, 255, 255, 0.5)" stroke-width="5" data-type="pcb_board" data-pcb-layer="board"/><rect class="pcb-pad" fill="rgb(200, 52, 52)" x="361" y="284" width="27" height="32" data-type="pcb_smtpad" data-pcb-layer="top"/><rect class="pcb-pad" fill="rgb(200, 52, 52)" x="412" y="284" width="27" height="32" data-type="pcb_smtpad" data-pcb-layer="top"/><path class="pcb-trace" stroke="rgb(200, 52, 52)" fill="none" d="M 306.25 393.75 L 306.25 393.75" stroke-width="7.5" stroke-linecap="round" stroke-linejoin="round" shape-rendering="crispEdges" data-type="pcb_trace" data-pcb-layer="top"/><path class="pcb-trace" stroke="rgb(200, 52, 52)" fill="none" d="M 306.25 393.75 L 306.25 368.25" stroke-width="7.5" stroke-linecap="round" stroke-linejoin="round" shape-rendering="crispEdges" data-type="pcb_trace" data-pcb-layer="top"/><path class="pcb-trace" stroke="rgb(200, 52, 52)" fill="none" d="M 306.25 368.25 L 374.5 300" stroke-width="7.5" stroke-linecap="round" stroke-linejoin="round" shape-rendering="crispEdges" data-type="pcb_trace" data-pcb-layer="top"/><path class="pcb-copper-pour pcb-copper-pour-brep" d="M
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="800" height="600" data-software-used-string="@tscircuit/core@0.0.849"><style></style><rect class="boundary" x="0" y="0" fill="#000" width="800" height="600" data-type="pcb_background" data-pcb-layer="global"/><rect class="pcb-boundary" fill="none" stroke="#fff" stroke-width="0.3" x="150" y="50" width="500" height="500" data-type="pcb_boundary" data-pcb-layer="global"/><rect class="pcb-pad" fill="rgb(77, 127, 196)" x="284" y="284" width="27" height="32" data-type="pcb_smtpad" data-pcb-layer="bottom"/><rect class="pcb-pad" fill="rgb(77, 127, 196)" x="233" y="284" width="27" height="32" data-type="pcb_smtpad" data-pcb-layer="bottom"/><path class="pcb-trace" stroke="rgb(77, 127, 196)" fill="none" d="M 297.5 300 L 297.5 379.512341162088" stroke-width="7.5" stroke-linecap="round" stroke-linejoin="round" shape-rendering="crispEdges" data-type="pcb_trace" data-pcb-layer="bottom"/><path class="pcb-trace" stroke="rgb(77, 127, 196)" fill="none" d="M 297.5 379.512341162088 L 303.1454224777405 385.1577636398285" stroke-width="7.5" stroke-linecap="round" stroke-linejoin="round" shape-rendering="crispEdges" data-type="pcb_trace" data-pcb-layer="bottom"/><path class="pcb-trace" stroke="rgb(77, 127, 196)" fill="none" d="M 303.1454224777405 385.1577636398285 L 306.25 393.75" stroke-width="7.5" stroke-linecap="round" stroke-linejoin="round" shape-rendering="crispEdges" data-type="pcb_trace" data-pcb-layer="bottom"/><path class="pcb-trace" stroke="rgb(77, 127, 196)" fill="none" d="M 306.25 393.75 L 306.25 393.75" stroke-width="7.5" stroke-linecap="round" stroke-linejoin="round" shape-rendering="crispEdges" data-type="pcb_trace" data-pcb-layer="bottom"/><path class="pcb-silkscreen pcb-silkscreen-bottom" d="M 246.5 264 L 321 264 L 321 336 L 246.5 336" fill="none" stroke="#5da9e9" stroke-width="5" stroke-linecap="round" stroke-linejoin="round" data-pcb-component-id="pcb_component_1" data-pcb-silkscreen-path-id="pcb_silkscreen_path_1" data-type="pcb_silkscreen_path" data-pcb-layer="bottom"/><text x="0" y="0" dx="0" dy="0" fill="#5da9e9" font-family="Arial, sans-serif" font-size="20" text-anchor="middle" dominant-baseline="central" transform="matrix(-1,0,0,1,272,239)" class="pcb-silkscreen-text pcb-silkscreen-bottom" data-pcb-silkscreen-text-id="pcb_component_1" stroke="none" data-type="pcb_silkscreen_text" data-pcb-layer="bottom">C1</text><path class="pcb-board" d="M 150 550 L 650 550 L 650 50 L 150 50 Z" fill="none" stroke="rgba(255, 255, 255, 0.5)" stroke-width="5" data-type="pcb_board" data-pcb-layer="board"/><rect class="pcb-pad" fill="rgb(200, 52, 52)" x="361" y="284" width="27" height="32" data-type="pcb_smtpad" data-pcb-layer="top"/><rect class="pcb-pad" fill="rgb(200, 52, 52)" x="412" y="284" width="27" height="32" data-type="pcb_smtpad" data-pcb-layer="top"/><path class="pcb-trace" stroke="rgb(200, 52, 52)" fill="none" d="M 306.25 393.75 L 306.25 393.75" stroke-width="7.5" stroke-linecap="round" stroke-linejoin="round" shape-rendering="crispEdges" data-type="pcb_trace" data-pcb-layer="top"/><path class="pcb-trace" stroke="rgb(200, 52, 52)" fill="none" d="M 306.25 393.75 L 306.25 368.25" stroke-width="7.5" stroke-linecap="round" stroke-linejoin="round" shape-rendering="crispEdges" data-type="pcb_trace" data-pcb-layer="top"/><path class="pcb-trace" stroke="rgb(200, 52, 52)" fill="none" d="M 306.25 368.25 L 374.5 300" stroke-width="7.5" stroke-linecap="round" stroke-linejoin="round" shape-rendering="crispEdges" data-type="pcb_trace" data-pcb-layer="top"/><path class="pcb-copper-pour pcb-copper-pour-brep" d="M 650 550 L 150 550 L 150 50 L 650 50 L 650 550 Z M 306.25 418.75 L 311.12725 418.26965 L 315.8171 416.847 L 320.13925 414.53675 L 323.92764999999997 411.42764999999997 L 327.03675 407.63925 L 329.347 403.3171 L 330.76965 398.62725 L 331.25 393.75 L 330.76965 388.87275 L 329.347 384.1829 L 327.03675 379.86075 L 323.92764999999997 376.07235000000003 L 320.13925 372.96325 L 316.08055 370.79385 L 360.8744 326 L 398 326 L 398 274 L 351 274 L 351 311.1256 L 300.0628 362.0628 L 298.97465 363.38875 L 298.16605 364.9015 L 297.66814999999997 366.54295 L 297.5 368.25 L 297.5 370.40515 L 296.6829 370.653 L 292.36075 372.96325 L 288.57235000000003 376.07235000000003 L 285.46325 379.86075 L 283.153 384.1829 L 281.73035 388.87275 L 281.25 393.75 L 281.73035 398.62725 L 283.153 403.3171 L 285.46325 407.63925 L 288.57235000000003 411.42764999999997 L 292.36075 414.53675 L 296.6829 416.847 L 301.37275 418.26965 L 306.25 418.75 Z" fill="rgb(200, 52, 52)" fill-rule="evenodd" fill-opacity="0.5" data-type="pcb_copper_pour" data-pcb-layer="top"/><path class="pcb-silkscreen pcb-silkscreen-top" d="M 425.5 264 L 351 264 L 351 336 L 425.5 336" fill="none" stroke="#f2eda1" stroke-width="5" stroke-linecap="round" stroke-linejoin="round" data-pcb-component-id="pcb_component_0" data-pcb-silkscreen-path-id="pcb_silkscreen_path_0" data-type="pcb_silkscreen_path" data-pcb-layer="top"/><text x="0" y="0" dx="0" dy="0" fill="#f2eda1" font-family="Arial, sans-serif" font-size="20" text-anchor="middle" dominant-baseline="central" transform="matrix(1,0,0,1,400,239)" class="pcb-silkscreen-text pcb-silkscreen-top" data-pcb-silkscreen-text-id="pcb_component_0" stroke="none" data-type="pcb_silkscreen_text" data-pcb-layer="top">R1</text><g data-type="pcb_via" data-pcb-layer="through"><circle class="pcb-hole-outer" fill="rgb(200, 52, 52)" cx="306.25" cy="393.75" r="15" data-type="pcb_via" data-pcb-layer="top"/><circle class="pcb-hole-inner" fill="#FF26E2" cx="306.25" cy="393.75" r="7.5" data-type="pcb_via" data-pcb-layer="drill"/></g></svg>
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import { expect, test } from "bun:test"
|
|
2
|
+
import type { BRepShape } from "circuit-json"
|
|
3
|
+
import { CopperPourPipelineSolver } from "lib/index"
|
|
4
|
+
import {
|
|
5
|
+
composeCrossSections,
|
|
6
|
+
crossSectionFromPolygon,
|
|
7
|
+
crossSectionToCopperPourIslands,
|
|
8
|
+
removeTinyIslands,
|
|
9
|
+
} from "lib/solvers/copper-pour/manifold-geometry-adapter"
|
|
10
|
+
import type { InputPad, InputProblem } from "lib/types"
|
|
11
|
+
|
|
12
|
+
const baseProblem = (pads: InputPad[]): InputProblem => ({
|
|
13
|
+
regionsForPour: [
|
|
14
|
+
{
|
|
15
|
+
shape: "rect",
|
|
16
|
+
layer: "top",
|
|
17
|
+
bounds: { minX: 0, minY: 0, maxX: 10, maxY: 10 },
|
|
18
|
+
connectivityKey: "net:GND",
|
|
19
|
+
padMargin: 0.2,
|
|
20
|
+
traceMargin: 0.2,
|
|
21
|
+
},
|
|
22
|
+
],
|
|
23
|
+
pads,
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
const solve = (pads: InputPad[]) =>
|
|
27
|
+
new CopperPourPipelineSolver(baseProblem(pads)).getOutput().brep_shapes
|
|
28
|
+
|
|
29
|
+
const ringArea = (ring: { vertices: { x: number; y: number }[] }) => {
|
|
30
|
+
let area = 0
|
|
31
|
+
for (let i = 0; i < ring.vertices.length; i++) {
|
|
32
|
+
const current = ring.vertices[i]!
|
|
33
|
+
const next = ring.vertices[(i + 1) % ring.vertices.length]!
|
|
34
|
+
area += current.x * next.y - next.x * current.y
|
|
35
|
+
}
|
|
36
|
+
return area / 2
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const brepArea = (shape: BRepShape) =>
|
|
40
|
+
Math.abs(ringArea(shape.outer_ring)) -
|
|
41
|
+
shape.inner_rings.reduce((sum, ring) => sum + Math.abs(ringArea(ring)), 0)
|
|
42
|
+
|
|
43
|
+
const totalArea = (shapes: BRepShape[]) =>
|
|
44
|
+
shapes.reduce((sum, shape) => sum + brepArea(shape), 0)
|
|
45
|
+
|
|
46
|
+
const assertValidRings = (shapes: BRepShape[]) => {
|
|
47
|
+
for (const shape of shapes) {
|
|
48
|
+
expect(shape.outer_ring.vertices.length).toBeGreaterThanOrEqual(3)
|
|
49
|
+
for (const point of shape.outer_ring.vertices) {
|
|
50
|
+
expect(Number.isFinite(point.x)).toBe(true)
|
|
51
|
+
expect(Number.isFinite(point.y)).toBe(true)
|
|
52
|
+
}
|
|
53
|
+
for (const ring of shape.inner_rings) {
|
|
54
|
+
expect(ring.vertices.length).toBeGreaterThanOrEqual(3)
|
|
55
|
+
for (const point of ring.vertices) {
|
|
56
|
+
expect(Number.isFinite(point.x)).toBe(true)
|
|
57
|
+
expect(Number.isFinite(point.y)).toBe(true)
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
test("trace clearance subtracts from rectangular pour", () => {
|
|
64
|
+
const shapes = solve([
|
|
65
|
+
{
|
|
66
|
+
padId: "trace-1",
|
|
67
|
+
shape: "trace",
|
|
68
|
+
layer: "top",
|
|
69
|
+
connectivityKey: "net:OTHER",
|
|
70
|
+
width: 0.4,
|
|
71
|
+
segments: [
|
|
72
|
+
{ x: 2, y: 5 },
|
|
73
|
+
{ x: 8, y: 5 },
|
|
74
|
+
],
|
|
75
|
+
},
|
|
76
|
+
])
|
|
77
|
+
|
|
78
|
+
expect(shapes).toHaveLength(1)
|
|
79
|
+
expect(shapes[0]!.inner_rings.length).toBe(1)
|
|
80
|
+
expect(totalArea(shapes)).toBeLessThan(100)
|
|
81
|
+
assertValidRings(shapes)
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
test("overlapping near-touching trace clearances compose before subtraction", () => {
|
|
85
|
+
const shapes = solve([
|
|
86
|
+
{
|
|
87
|
+
padId: "trace-1",
|
|
88
|
+
shape: "trace",
|
|
89
|
+
layer: "top",
|
|
90
|
+
connectivityKey: "net:OTHER",
|
|
91
|
+
width: 0.4,
|
|
92
|
+
segments: [
|
|
93
|
+
{ x: 2, y: 4.7 },
|
|
94
|
+
{ x: 8, y: 4.7 },
|
|
95
|
+
],
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
padId: "trace-2",
|
|
99
|
+
shape: "trace",
|
|
100
|
+
layer: "top",
|
|
101
|
+
connectivityKey: "net:OTHER",
|
|
102
|
+
width: 0.4,
|
|
103
|
+
segments: [
|
|
104
|
+
{ x: 2, y: 5.25 },
|
|
105
|
+
{ x: 8, y: 5.25 },
|
|
106
|
+
],
|
|
107
|
+
},
|
|
108
|
+
])
|
|
109
|
+
|
|
110
|
+
expect(shapes).toHaveLength(1)
|
|
111
|
+
expect(shapes[0]!.inner_rings.length).toBe(1)
|
|
112
|
+
expect(totalArea(shapes)).toBeGreaterThan(90)
|
|
113
|
+
assertValidRings(shapes)
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
test("pads and vias inside pour become holes", () => {
|
|
117
|
+
const shapes = solve([
|
|
118
|
+
{
|
|
119
|
+
padId: "pad-1",
|
|
120
|
+
shape: "rect",
|
|
121
|
+
layer: "top",
|
|
122
|
+
connectivityKey: "net:OTHER",
|
|
123
|
+
bounds: { minX: 2, minY: 2, maxX: 3, maxY: 3 },
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
padId: "via-1",
|
|
127
|
+
shape: "circle",
|
|
128
|
+
layer: "top",
|
|
129
|
+
connectivityKey: "net:OTHER",
|
|
130
|
+
x: 7,
|
|
131
|
+
y: 7,
|
|
132
|
+
radius: 0.35,
|
|
133
|
+
},
|
|
134
|
+
])
|
|
135
|
+
|
|
136
|
+
expect(shapes).toHaveLength(1)
|
|
137
|
+
expect(shapes[0]!.inner_rings.length).toBe(2)
|
|
138
|
+
assertValidRings(shapes)
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
test("blocker covering pour returns empty result", () => {
|
|
142
|
+
const shapes = solve([
|
|
143
|
+
{
|
|
144
|
+
padId: "pad-1",
|
|
145
|
+
shape: "rect",
|
|
146
|
+
layer: "top",
|
|
147
|
+
connectivityKey: "net:OTHER",
|
|
148
|
+
bounds: { minX: -1, minY: -1, maxX: 11, maxY: 11 },
|
|
149
|
+
},
|
|
150
|
+
])
|
|
151
|
+
|
|
152
|
+
expect(shapes).toHaveLength(0)
|
|
153
|
+
})
|
|
154
|
+
|
|
155
|
+
test("clearance can split pour into multiple disconnected islands", () => {
|
|
156
|
+
const shapes = solve([
|
|
157
|
+
{
|
|
158
|
+
padId: "trace-1",
|
|
159
|
+
shape: "trace",
|
|
160
|
+
layer: "top",
|
|
161
|
+
connectivityKey: "net:OTHER",
|
|
162
|
+
width: 0.6,
|
|
163
|
+
segments: [
|
|
164
|
+
{ x: 5, y: -1 },
|
|
165
|
+
{ x: 5, y: 11 },
|
|
166
|
+
],
|
|
167
|
+
},
|
|
168
|
+
])
|
|
169
|
+
|
|
170
|
+
expect(shapes).toHaveLength(2)
|
|
171
|
+
assertValidRings(shapes)
|
|
172
|
+
})
|
|
173
|
+
|
|
174
|
+
test("tiny copper islands are removed below threshold", () => {
|
|
175
|
+
const normalIsland = crossSectionFromPolygon([
|
|
176
|
+
{ x: 0, y: 0 },
|
|
177
|
+
{ x: 1, y: 0 },
|
|
178
|
+
{ x: 1, y: 1 },
|
|
179
|
+
{ x: 0, y: 1 },
|
|
180
|
+
])
|
|
181
|
+
const tinyIsland = crossSectionFromPolygon([
|
|
182
|
+
{ x: 2, y: 0 },
|
|
183
|
+
{ x: 2.00001, y: 0 },
|
|
184
|
+
{ x: 2.00001, y: 0.00001 },
|
|
185
|
+
{ x: 2, y: 0.00001 },
|
|
186
|
+
])
|
|
187
|
+
|
|
188
|
+
const cleaned = removeTinyIslands(
|
|
189
|
+
composeCrossSections([normalIsland, tinyIsland]),
|
|
190
|
+
1e-8,
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
expect(crossSectionToCopperPourIslands(cleaned)).toHaveLength(1)
|
|
194
|
+
})
|
|
@@ -4,23 +4,23 @@ import circuitJson from "./assets/tsci_AnasSarkiz.STM32F746G-DISCO.circuit.json"
|
|
|
4
4
|
import { runSolverAndRenderToSvg } from "./utils/run-solver-and-render-to-svg"
|
|
5
5
|
|
|
6
6
|
test("stm32f746g-disco top layer full board repro", () => {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
7
|
+
const svg = runSolverAndRenderToSvg(circuitJson as AnyCircuitElement[], {
|
|
8
|
+
layer: "top",
|
|
9
|
+
net_name: "GND",
|
|
10
|
+
pad_margin: 0.2,
|
|
11
|
+
trace_margin: 0.2,
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
expect(svg).toMatchSvgSnapshot(import.meta.path+"top")
|
|
15
15
|
})
|
|
16
16
|
|
|
17
17
|
test("stm32f746g-disco bottom layer full board repro", () => {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
18
|
+
const svg = runSolverAndRenderToSvg(circuitJson as AnyCircuitElement[], {
|
|
19
|
+
layer: "bottom",
|
|
20
|
+
net_name: "GND",
|
|
21
|
+
pad_margin: 0.2,
|
|
22
|
+
trace_margin: 0.2,
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
expect(svg).toMatchSvgSnapshot(import.meta.path+"bottom")
|
|
26
26
|
})
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import Flatten from "@flatten-js/core"
|
|
2
|
-
|
|
3
|
-
export const circleToPolygon = (circle: Flatten.Circle, numSegments = 32) => {
|
|
4
|
-
const points: Flatten.Point[] = []
|
|
5
|
-
for (let i = 0; i < numSegments; i++) {
|
|
6
|
-
const angle = (i / numSegments) * 2 * Math.PI
|
|
7
|
-
points.push(
|
|
8
|
-
new Flatten.Point(
|
|
9
|
-
circle.center.x + circle.r * Math.cos(angle),
|
|
10
|
-
circle.center.y + circle.r * Math.sin(angle),
|
|
11
|
-
),
|
|
12
|
-
)
|
|
13
|
-
}
|
|
14
|
-
return new Flatten.Polygon(points)
|
|
15
|
-
}
|