@tscircuit/footprinter 0.0.16 → 0.0.18
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/biome.json +15 -0
- package/package.json +2 -1
- package/src/fn/quad.ts +62 -24
- package/src/helpers/get-quad-pin-map.ts +1 -1
- package/tests/quad.test.ts +8 -0
package/biome.json
ADDED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tscircuit/footprinter",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.18",
|
|
5
5
|
"description": "",
|
|
6
6
|
"main": "dist/index.cjs",
|
|
7
7
|
"scripts": {
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
"author": "",
|
|
13
13
|
"license": "ISC",
|
|
14
14
|
"devDependencies": {
|
|
15
|
+
"@biomejs/biome": "^1.7.3",
|
|
15
16
|
"@tscircuit/log-soup": "^1.0.1",
|
|
16
17
|
"@tscircuit/soup": "^0.0.17",
|
|
17
18
|
"@tscircuit/soup-util": "^0.0.11",
|
package/src/fn/quad.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import type { AnySoupElement } from "@tscircuit/soup"
|
|
1
|
+
import type { AnySoupElement, PcbSilkscreenPath } from "@tscircuit/soup"
|
|
2
2
|
import { z } from "zod"
|
|
3
3
|
import { length } from "@tscircuit/soup"
|
|
4
4
|
import type { NowDefined } from "../helpers/zod/now-defined"
|
|
5
5
|
import { rectpad } from "../helpers/rectpad"
|
|
6
6
|
import { pin_order_specifier } from "src/helpers/zod/pin-order-specifier"
|
|
7
7
|
import { getQuadPinMap } from "src/helpers/get-quad-pin-map"
|
|
8
|
+
import { dim2d } from "src/helpers/zod/dim-2d"
|
|
8
9
|
|
|
9
10
|
const base_quad_def = z.object({
|
|
10
11
|
quad: z.literal(true),
|
|
@@ -17,6 +18,7 @@ const base_quad_def = z.object({
|
|
|
17
18
|
p: length.default(length.parse("0.5mm")),
|
|
18
19
|
pw: length.optional(),
|
|
19
20
|
pl: length.optional(),
|
|
21
|
+
thermalpad: z.union([z.literal(true), dim2d]).optional(),
|
|
20
22
|
})
|
|
21
23
|
|
|
22
24
|
const quad_def = base_quad_def.transform((v) => {
|
|
@@ -58,15 +60,13 @@ export const getQuadCoords = (
|
|
|
58
60
|
pn: number, // pin number
|
|
59
61
|
w: number, // width of the package
|
|
60
62
|
h: number, // height (length) of the package
|
|
61
|
-
p: number // pitch between pins
|
|
63
|
+
p: number, // pitch between pins
|
|
64
|
+
pl: number // length of the pin
|
|
62
65
|
) => {
|
|
63
66
|
const sidePinCount = pinCount / 4
|
|
64
67
|
const side = SIDES_CCW[Math.floor((pn - 1) / sidePinCount)]
|
|
65
68
|
const pos = (pn - 1) % sidePinCount
|
|
66
69
|
|
|
67
|
-
const halfW = w / 2
|
|
68
|
-
const halfH = h / 2
|
|
69
|
-
|
|
70
70
|
/** inner box width */
|
|
71
71
|
const ibw = p * (sidePinCount - 1)
|
|
72
72
|
/** inner box height */
|
|
@@ -74,27 +74,21 @@ export const getQuadCoords = (
|
|
|
74
74
|
|
|
75
75
|
switch (side) {
|
|
76
76
|
case "left":
|
|
77
|
-
return { x: -
|
|
77
|
+
return { x: -w / 2 + pl / 2, y: ibh / 2 - pos * p, o: "vert" }
|
|
78
78
|
case "bottom":
|
|
79
|
-
return { x: -ibw / 2 + pos * p, y: -
|
|
79
|
+
return { x: -ibw / 2 + pos * p, y: -h / 2 + pl / 2, o: "horz" }
|
|
80
80
|
case "right":
|
|
81
|
-
return { x:
|
|
81
|
+
return { x: w / 2 - pl / 2, y: -ibh / 2 + pos * p, o: "vert" }
|
|
82
82
|
case "top":
|
|
83
|
-
return { x: ibw / 2 - pos * p, y:
|
|
83
|
+
return { x: ibw / 2 - pos * p, y: h / 2 - pl / 2, o: "horz" }
|
|
84
84
|
default:
|
|
85
85
|
throw new Error("Invalid pin number")
|
|
86
86
|
}
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
-
export const quad = (
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
w: number
|
|
93
|
-
l: number
|
|
94
|
-
p?: number
|
|
95
|
-
id?: string | number
|
|
96
|
-
od?: string | number
|
|
97
|
-
}): AnySoupElement[] => {
|
|
89
|
+
export const quad = (
|
|
90
|
+
raw_params: z.input<typeof quad_def>
|
|
91
|
+
): AnySoupElement[] => {
|
|
98
92
|
const params = quad_def.parse(raw_params)
|
|
99
93
|
const pads: AnySoupElement[] = []
|
|
100
94
|
const pin_map = getQuadPinMap(params)
|
|
@@ -108,17 +102,61 @@ export const quad = (raw_params: {
|
|
|
108
102
|
i + 1,
|
|
109
103
|
params.w,
|
|
110
104
|
params.h,
|
|
111
|
-
params.p ?? 0.5
|
|
105
|
+
params.p ?? 0.5,
|
|
106
|
+
params.pl
|
|
112
107
|
)
|
|
113
108
|
|
|
114
|
-
let pw = params.pw
|
|
115
|
-
|
|
109
|
+
let pw = params.pw
|
|
110
|
+
let pl = params.pl
|
|
116
111
|
if (orientation === "vert") {
|
|
117
112
|
;[pw, pl] = [pl, pw]
|
|
118
113
|
}
|
|
119
114
|
|
|
120
|
-
const pn = pin_map[i + 1]
|
|
121
|
-
pads.push(rectpad(pn
|
|
115
|
+
const pn = pin_map[i + 1]!
|
|
116
|
+
pads.push(rectpad(pn, x, y, pw, pl))
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (params.thermalpad) {
|
|
120
|
+
if (typeof params.thermalpad === "boolean") {
|
|
121
|
+
const sidePinCount = params.num_pins / 4
|
|
122
|
+
const ibw = params.p * (sidePinCount - 1) + params.pw
|
|
123
|
+
const ibh = params.p * (sidePinCount - 1) + params.pw
|
|
124
|
+
pads.push(rectpad(["thermalpad"], 0, 0, ibw, ibh))
|
|
125
|
+
} else {
|
|
126
|
+
pads.push(
|
|
127
|
+
rectpad(["thermalpad"], 0, 0, params.thermalpad.x, params.thermalpad.y)
|
|
128
|
+
)
|
|
129
|
+
}
|
|
122
130
|
}
|
|
123
|
-
|
|
131
|
+
|
|
132
|
+
// Silkscreen corners
|
|
133
|
+
const silkscreen_corners: PcbSilkscreenPath[] = []
|
|
134
|
+
for (let corner_index = 0; corner_index < 4; corner_index++) {
|
|
135
|
+
const dx = Math.floor(corner_index / 2) * 2 - 1
|
|
136
|
+
const dy = (corner_index % 2) * 2 - 1
|
|
137
|
+
const corner_x = (params.w / 2) * dx
|
|
138
|
+
const corner_y = (params.h / 2) * dy
|
|
139
|
+
silkscreen_corners.push({
|
|
140
|
+
layer: "top",
|
|
141
|
+
pcb_component_id: "",
|
|
142
|
+
pcb_silkscreen_path_id: `pcb_silkscreen_path_${corner_index}`,
|
|
143
|
+
route: [
|
|
144
|
+
{
|
|
145
|
+
x: corner_x - params.pw * dx,
|
|
146
|
+
y: corner_y,
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
x: corner_x,
|
|
150
|
+
y: corner_y,
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
x: corner_x,
|
|
154
|
+
y: corner_y - params.pw * dy,
|
|
155
|
+
},
|
|
156
|
+
],
|
|
157
|
+
type: "pcb_silkscreen_path",
|
|
158
|
+
})
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return [...pads, ...silkscreen_corners]
|
|
124
162
|
}
|
|
@@ -89,7 +89,7 @@ export const getQuadPinMap = ({
|
|
|
89
89
|
// decrementing
|
|
90
90
|
for (let i = 0; i < num_pins; i++) {
|
|
91
91
|
pin_map.push(current_position_ccw_normal)
|
|
92
|
-
if (ccw) {
|
|
92
|
+
if (ccw || !cw) {
|
|
93
93
|
current_position_ccw_normal++
|
|
94
94
|
if (current_position_ccw_normal > num_pins) {
|
|
95
95
|
current_position_ccw_normal = 1
|
package/tests/quad.test.ts
CHANGED
|
@@ -11,6 +11,14 @@ test("quad16_w4_l4_p0.4_pw0.25_pl0.4", async (t) => {
|
|
|
11
11
|
t.pass()
|
|
12
12
|
})
|
|
13
13
|
|
|
14
|
+
test("quad16_w4_l4_p0.4_pw0.25_pl0.4_thermalpad", async (t) => {
|
|
15
|
+
const { fp, logSoup } = await getTestFixture(t)
|
|
16
|
+
const soup = fp.string("quad16_w4_l4_p0.4_pw0.25_pl0.4_thermalpad").soup()
|
|
17
|
+
|
|
18
|
+
await logSoup(soup)
|
|
19
|
+
t.pass()
|
|
20
|
+
})
|
|
21
|
+
|
|
14
22
|
// const ps = toPinPositionString(soup)
|
|
15
23
|
|
|
16
24
|
// t.is(
|