Skip to content

Commit

Permalink
Introduced new footprint type: breakoutheaders (#98)
Browse files Browse the repository at this point in the history
* Introduced new footprint type:

* renamed getTriangleDir to getTrianglePath and change defualt value of od to 1.5mm

* renamed routes to silkscreenTriangleRoutes
  • Loading branch information
AnasSarkiz authored Dec 19, 2024
1 parent dff0a4d commit d589f7a
Show file tree
Hide file tree
Showing 5 changed files with 271 additions and 0 deletions.
239 changes: 239 additions & 0 deletions src/fn/breakoutheaders.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,239 @@
import {
length,
type AnyCircuitElement,
type PcbPlatedHole,
type PcbSilkscreenPath,
} from "circuit-json"
import { z } from "zod"
import { rectpad } from "../helpers/rectpad"
import { silkscreenRef, type SilkscreenRef } from "src/helpers/silkscreenRef"
import { platedhole } from "src/helpers/platedhole"

export const breakoutheaders_def = z.object({
fn: z.string(),
w: length.default("10mm"),
h: length.optional(),
left: length.optional().default(20),
right: length.optional().default(20),
top: length.optional().default(0),
bottom: length.optional().default(0),
p: length.default(length.parse("2.54mm")),
id: length.optional().default(length.parse("1mm")),
od: length.optional().default(length.parse("1.5mm")),
})

export type breakoutheaders_def = z.input<typeof breakoutheaders_def>

const getHeight = (parameters: breakoutheaders_def): number => {
const params = breakoutheaders_def.parse(parameters)

// Calculate height based on the presence of left and right parameters
if (params.left && params.right) {
return Math.max(params.left, params.right) * params.p
}

if (params.left) {
return params.left * params.p
}

if (params.right) {
return params.right * params.p
}

return 51
}

type Point = { x: number; y: number }
type Direction = "left" | "right" | "top" | "bottom"

const getTrianglePath = (
x: number,
y: number,
side: Direction,
triangleHeight = 1,
triangleWidth = 0.6,
): Point[] => {
const halfHeight = triangleHeight / 2
const halfWidth = triangleWidth / 2

const silkscreenTriangleRoutes: Record<Direction, Point[]> = {
left: [
{ x: x + halfHeight, y },
{ x: x - halfHeight, y: y + halfWidth },
{ x: x - halfHeight, y: y - halfWidth },
{ x: x + halfHeight, y },
],
right: [
{ x: x - halfHeight, y },
{ x: x + halfHeight, y: y + halfWidth },
{ x: x + halfHeight, y: y - halfWidth },
{ x: x - halfHeight, y },
],
top: [
{ x, y: y - halfHeight },
{ x: x - halfWidth, y: y + halfHeight },
{ x: x + halfWidth, y: y + halfHeight },
{ x, y: y - halfHeight },
],
bottom: [
{ x, y: y + halfHeight },
{ x: x - halfWidth, y: y - halfHeight },
{ x: x + halfWidth, y: y - halfHeight },
{ x, y: y + halfHeight },
],
}

return silkscreenTriangleRoutes[side]
}
export const breakoutheaders = (
raw_params: breakoutheaders_def,
): { circuitJson: AnyCircuitElement[]; parameters: any } => {
const params = breakoutheaders_def.parse(raw_params)
const height = params.h ?? getHeight(params)
const holes: PcbPlatedHole[] = []
const innerDiameter = params.id
const outerDiameter = params.od
let silkscreenTriangleRoutes: { x: number; y: number }[] = []
if (params.right) {
const yoff = -((params.right - 1) / 2) * params.p
for (let i = 0; i < params.right; i++) {
if (i === 0 && !params.left && !params.bottom) {
silkscreenTriangleRoutes = getTrianglePath(
params.w / 2 + outerDiameter * 1.4,
yoff + i * params.p,
"right",
)
}
holes.push(
platedhole(
i + 1 + params.left + (params.bottom ?? 0),
params.w / 2,
yoff + i * params.p,
innerDiameter,
outerDiameter,
),
)
}
}
if (params.left) {
const yoff = -((params.left - 1) / 2) * params.p
for (let i = 0; i < params.left; i++) {
if (i === params.left - 1) {
silkscreenTriangleRoutes = getTrianglePath(
-params.w / 2 - outerDiameter * 1.4,
yoff + i * params.p,
"left",
)
}
holes.push(
platedhole(
i + 1,
-params.w / 2,
yoff + i * params.p,
innerDiameter,
outerDiameter,
),
)
}
}
if (params.top) {
const xoff = -((params.top - 1) / 2) * params.p
for (let i = 0; i < params.top; i++) {
if (
i === params.top - 1 &&
!params.left &&
!params.bottom &&
!params.right
) {
silkscreenTriangleRoutes = getTrianglePath(
xoff + i * params.p,
height / 2 + outerDiameter * 1.4,
"top",
)
}
holes.push(
platedhole(
i + 1 + params.right + (params.bottom ?? 0) + params.left,
xoff + i * params.p,
height / 2,
innerDiameter,
outerDiameter,
),
)
}
}
if (params.bottom) {
const xoff = -((params.bottom - 1) / 2) * params.p
for (let i = 0; i < params.bottom; i++) {
if (i === 0 && !params.left) {
silkscreenTriangleRoutes = getTrianglePath(
xoff + i * params.p,
-height / 2 - outerDiameter * 1.4,
"bottom",
)
}
holes.push(
platedhole(
i + 1 + params.left,
xoff + i * params.p,
-height / 2,
innerDiameter,
outerDiameter,
),
)
}
}

const silkscreenTriangle: PcbSilkscreenPath = {
type: "pcb_silkscreen_path",
pcb_silkscreen_path_id: "1",
pcb_component_id: "1",
layer: "top",
route: silkscreenTriangleRoutes,
stroke_width: 0.1,
}

const silkscreenPath: PcbSilkscreenPath = {
type: "pcb_silkscreen_path",
pcb_silkscreen_path_id: "pcb_silkscreen_path_1",
pcb_component_id: "1",
route: [
{
x: -params.w / 2 - outerDiameter,
y: height / 2 + outerDiameter,
},
{
x: params.w / 2 + outerDiameter,
y: height / 2 + outerDiameter,
},
{
x: params.w / 2 + outerDiameter,
y: -height / 2 - outerDiameter,
},
{
x: -params.w / 2 - outerDiameter,
y: -height / 2 - outerDiameter,
},
{
x: -params.w / 2 - outerDiameter,
y: height / 2 + outerDiameter,
},
],
stroke_width: 0.1,
layer: "top",
}
const silkscreenRefText: SilkscreenRef = silkscreenRef(
0,
height / 1.7,
height / 25,
)
return {
circuitJson: [
...holes,
silkscreenPath,
silkscreenRefText,
silkscreenTriangle,
],
parameters: params,
}
}
1 change: 1 addition & 0 deletions src/fn/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,4 @@ export { stampboard } from "./stampboard"
export { stampreceiver } from "./stampreceiver"
export { lqfp } from "./lqfp"
export { sot235 } from "./sot235"
export { breakoutheaders } from "./breakoutheaders"
4 changes: 4 additions & 0 deletions src/footprinter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ export type Footprinter = {
| "innerhole"
| "innerholeedgedistance"
>
breakoutheaders: () => FootprinterParamsBuilder<
"w" | "h" | "left" | "right" | "top" | "bottom" | "p" | "id" | "od"
>

params: () => any
/** @deprecated use circuitJson() instead */
soup: () => AnySoupElement[]
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 14 additions & 0 deletions tests/breakoutheaders.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { test, expect } from "bun:test"
import { convertCircuitJsonToPcbSvg } from "circuit-to-svg"
import { fp } from "../src/footprinter"

test("breakoutheaders", () => {
const soup = fp
.string("breakoutheaders_left15_right15_w8mm_p1.54mm")
.circuitJson()
const svgContent = convertCircuitJsonToPcbSvg(soup)
expect(svgContent).toMatchSvgSnapshot(
import.meta.path,
"breakoutheaders_left20_right20_w8mm_p2.54mm",
)
})

0 comments on commit d589f7a

Please sign in to comment.