Skip to content

Commit 4ba46aa

Browse files
authored
Merge pull request #484 from rushabhcodes/fix/polygon-smtpad-export-nan
Fix polygon SMT pad export producing NaN DSN padstack and pin coordinates
2 parents 96c62d1 + 2c6492a commit 4ba46aa

10 files changed

Lines changed: 346 additions & 39 deletions

bun.lock

Lines changed: 7 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/dsn-pcb/circuit-json-to-dsn-json/process-components-and-pads.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,11 @@ export function processComponentsAndPads(
8282

8383
// Add padstacks for SMT pads
8484
for (const pad of componentGroup.pcb_smtpads) {
85-
createAndAddPadstackFromPcbSmtPad(pcb, pad, processedPadstacks)
85+
createAndAddPadstackFromPcbSmtPad({
86+
pcb,
87+
pad,
88+
processedPadstacks,
89+
})
8690
}
8791

8892
// Add image once per footprint
@@ -106,7 +110,11 @@ export function processComponentsAndPads(
106110
.source_port.list()
107111
.find((e) => e.source_port_id === pcbPort?.source_port_id)
108112

109-
return createPinForImage(pad, pcbComponent, sourcePort)
113+
return createPinForImage({
114+
pad,
115+
pcbComponent,
116+
sourcePort,
117+
})
110118
})
111119
.filter((pin): pin is Pin => pin !== undefined),
112120
}

lib/utils/create-and-add-padstack-for-pcb-smtpad.ts

Lines changed: 65 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,40 +3,83 @@ import type { Padstack } from "lib"
33
import type { DsnPcb } from "lib"
44
import {
55
createCircularPadstack,
6+
createPolygonPadstack,
67
createRectangularPadstack,
78
} from "./create-padstack"
89
import { type PadstackNameArgs, getPadstackName } from "./get-padstack-name"
10+
import { getPolygonSmtPadGeometry } from "./get-polygon-smt-pad-geometry"
911

10-
export function createAndAddPadstackFromPcbSmtPad(
11-
pcb: DsnPcb,
12-
pad: PcbSmtPad,
13-
processedPadstacks: Set<string>,
14-
): string {
12+
export function createAndAddPadstackFromPcbSmtPad({
13+
pcb,
14+
pad,
15+
processedPadstacks,
16+
}: {
17+
pcb: DsnPcb
18+
pad: PcbSmtPad
19+
processedPadstacks: Set<string>
20+
}): string {
1521
const isCircle = pad.shape === "circle"
22+
const isPolygon = pad.shape === "polygon"
23+
const polygonPadGeometry = isPolygon
24+
? getPolygonSmtPadGeometry(pad)
25+
: undefined
26+
27+
let shape: PadstackNameArgs["shape"] = "rect"
28+
let outerDiameter: number | undefined
29+
let holeDiameter: number | undefined
30+
let width: number | undefined
31+
let height: number | undefined
32+
let customDescriptor: string | undefined
33+
34+
if (isCircle) {
35+
shape = "circle"
36+
outerDiameter = pad.radius * 1000 * 2 // Radius to diameter
37+
holeDiameter = pad.radius * 1000 * 2 // Radius to diameter
38+
} else if (isPolygon) {
39+
shape = "polygon"
40+
width = polygonPadGeometry?.widthUm
41+
height = polygonPadGeometry?.heightUm
42+
customDescriptor = `${polygonPadGeometry?.widthUm}x${polygonPadGeometry?.heightUm}_${polygonPadGeometry?.relativePointsUm.join("_")}`
43+
} else {
44+
width = (pad as { width: number }).width * 1000
45+
height = (pad as { height: number }).height * 1000
46+
}
47+
1648
const padstackParams: PadstackNameArgs = {
17-
shape: isCircle ? "circle" : "rect",
18-
outerDiameter: isCircle ? pad.radius * 1000 * 2 : undefined, // Radius to diameter
19-
holeDiameter: isCircle ? pad.radius * 1000 * 2 : undefined, // Radius to diameter
20-
width: isCircle ? undefined : (pad as { width: number }).width * 1000,
21-
height: isCircle ? undefined : (pad as { height: number }).height * 1000,
49+
shape,
50+
outerDiameter,
51+
holeDiameter,
52+
width,
53+
height,
2254
layer: pad.layer as PcbSmtPad["layer"],
55+
customDescriptor,
2356
}
2457

2558
const padstackName = getPadstackName(padstackParams)
2659

2760
if (!processedPadstacks.has(padstackName)) {
28-
const padstack: Padstack = isCircle
29-
? createCircularPadstack(
30-
padstackName,
31-
padstackParams.outerDiameter!,
32-
padstackParams.holeDiameter!,
33-
)
34-
: createRectangularPadstack(
35-
padstackName,
36-
padstackParams.width!,
37-
padstackParams.height!,
38-
pad.layer,
39-
)
61+
let padstack: Padstack
62+
63+
if (isCircle) {
64+
padstack = createCircularPadstack(
65+
padstackName,
66+
padstackParams.outerDiameter!,
67+
padstackParams.holeDiameter!,
68+
)
69+
} else if (isPolygon) {
70+
padstack = createPolygonPadstack({
71+
name: padstackName,
72+
coordinates: polygonPadGeometry!.relativePointsUm,
73+
layer: pad.layer,
74+
})
75+
} else {
76+
padstack = createRectangularPadstack(
77+
padstackName,
78+
padstackParams.width!,
79+
padstackParams.height!,
80+
pad.layer,
81+
)
82+
}
4083

4184
pcb.library.padstacks.push(padstack)
4285
processedPadstacks.add(padstackName)

lib/utils/create-padstack.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,29 @@ export function createRectangularPadstack(
8989
}
9090
}
9191

92+
export function createPolygonPadstack({
93+
name,
94+
coordinates,
95+
layer,
96+
}: {
97+
name: string
98+
coordinates: number[]
99+
layer: PcbSmtPad["layer"]
100+
}): Padstack {
101+
return {
102+
name,
103+
shapes: [
104+
{
105+
shapeType: "polygon",
106+
layer: layer === "bottom" ? "B.Cu" : "F.Cu",
107+
width: 0,
108+
coordinates,
109+
},
110+
],
111+
attach: "off",
112+
}
113+
}
114+
92115
export function createCircularHoleRectangularPadstack(
93116
name: string,
94117
outerWidth: number,

lib/utils/create-pin-for-image.ts

Lines changed: 47 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,29 +3,64 @@ import type { PcbSmtPad } from "circuit-json"
33
import type { PcbComponent, SourcePort } from "circuit-json"
44
import type { Pin } from "lib"
55
import { type PadstackNameArgs, getPadstackName } from "./get-padstack-name"
6+
import { getPolygonSmtPadGeometry } from "./get-polygon-smt-pad-geometry"
67

7-
export function createPinForImage(
8-
pad: any,
9-
pcbComponent: PcbComponent,
10-
sourcePort: SourcePort | undefined,
11-
): Pin | undefined {
8+
export function createPinForImage({
9+
pad,
10+
pcbComponent,
11+
sourcePort,
12+
}: {
13+
pad: PcbSmtPad
14+
pcbComponent: PcbComponent
15+
sourcePort: SourcePort | undefined
16+
}): Pin | undefined {
1217
if (!sourcePort) return undefined
1318

1419
const isCircle = pad.shape === "circle"
20+
const isPolygon = pad.shape === "polygon"
21+
const polygonPadGeometry = isPolygon
22+
? getPolygonSmtPadGeometry(pad)
23+
: undefined
24+
25+
let shape: PadstackNameArgs["shape"] = "rect"
26+
let outerDiameter: number | undefined
27+
let holeDiameter: number | undefined
28+
let width: number | undefined
29+
let height: number | undefined
30+
let customDescriptor: string | undefined
31+
32+
if (isCircle) {
33+
shape = "circle"
34+
outerDiameter = pad.radius * 1000 * 2 // Radius to diameter
35+
holeDiameter = pad.radius * 1000 * 2 // Radius to diameter
36+
} else if (isPolygon) {
37+
shape = "polygon"
38+
width = polygonPadGeometry?.widthUm
39+
height = polygonPadGeometry?.heightUm
40+
customDescriptor = `${polygonPadGeometry?.widthUm}x${polygonPadGeometry?.heightUm}_${polygonPadGeometry?.relativePointsUm.join("_")}`
41+
} else {
42+
width = pad.width * 1000
43+
height = pad.height * 1000
44+
}
45+
1546
const padstackParams: PadstackNameArgs = {
16-
shape: isCircle ? "circle" : "rect",
17-
outerDiameter: isCircle ? pad.radius * 1000 * 2 : undefined, // Radius to diameter
18-
holeDiameter: isCircle ? pad.radius * 1000 * 2 : undefined, // Radius to diameter
19-
width: isCircle ? undefined : pad.width * 1000,
20-
height: isCircle ? undefined : pad.height * 1000,
47+
shape,
48+
outerDiameter,
49+
holeDiameter,
50+
width,
51+
height,
2152
layer: pad.layer as PcbSmtPad["layer"],
53+
customDescriptor,
2254
}
55+
const padCenter = isPolygon
56+
? polygonPadGeometry!.center
57+
: { x: pad.x, y: pad.y }
2358

2459
return {
2560
padstack_name: getPadstackName(padstackParams),
2661
pin_number:
2762
sourcePort.port_hints?.find((hint) => !Number.isNaN(Number(hint))) || 1,
28-
x: (pad.x - pcbComponent.center.x) * 1000,
29-
y: (pad.y - pcbComponent.center.y) * 1000,
63+
x: (padCenter.x - pcbComponent.center.x) * 1000,
64+
y: (padCenter.y - pcbComponent.center.y) * 1000,
3065
}
3166
}

lib/utils/get-padstack-name.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import type { PcbSmtPad } from "circuit-json"
22

33
export interface PadstackNameArgs {
4-
shape: "circle" | "oval" | "pill" | "rect"
4+
shape: "circle" | "oval" | "pill" | "rect" | "polygon"
55
width?: number
66
height?: number
77
holeDiameter?: number
88
outerDiameter?: number
99
layer?: PcbSmtPad["layer"] | "all"
10+
customDescriptor?: string
1011
}
1112

1213
export function getPadstackName({
@@ -16,6 +17,7 @@ export function getPadstackName({
1617
holeDiameter,
1718
outerDiameter,
1819
layer = "top",
20+
customDescriptor,
1921
}: PadstackNameArgs): string {
2022
const layerCode =
2123
{
@@ -32,6 +34,8 @@ export function getPadstackName({
3234
return `Oval[${layerCode}]Pad_${width}x${height}_um`
3335
case "rect":
3436
return `RoundRect[${layerCode}]Pad_${width}x${height}_um`
37+
case "polygon":
38+
return `Cust[${layerCode}]Pad_${customDescriptor ?? `${width}x${height}`}_um`
3539
default:
3640
return "default_pad"
3741
}

0 commit comments

Comments
 (0)