Skip to content

Commit

Permalink
Merge pull request #46 from tscircuit/fix/different-size-plated-holes
Browse files Browse the repository at this point in the history
  • Loading branch information
imrishabh18 authored Dec 4, 2024
2 parents 72ea9b5 + bd1f55b commit aab7a55
Show file tree
Hide file tree
Showing 3 changed files with 280 additions and 93 deletions.
178 changes: 85 additions & 93 deletions lib/dsn-pcb/circuit-json-to-dsn-json/process-plated-holes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import type {
PcbPlatedHoleCircle,
SourceComponentBase,
} from "circuit-json"
import type { DsnPcb } from "../types"
import { applyToPoint, scale } from "transformation-matrix"
import type { DsnPcb } from "../types"

const transformMmToUm = scale(1000)

Expand All @@ -29,6 +29,16 @@ export function processPlatedHoles(
platedHolesByComponent.get(componentId)?.push(hole)
})

const placesByDimensions = new Map<
string,
Array<{
refdes: string
x: number
y: number
rotation: number
}>
>()

// Process each component's plated holes
for (const [componentId, holes] of platedHolesByComponent) {
const pcbComponent = circuitElements.find(
Expand All @@ -45,84 +55,41 @@ export function processPlatedHoles(

const componentName = sourceComponent?.name || `H${componentId}`

// TODO each hole can have it's own imageName and padstackName, we can't
// just use the first hole's values for all holes
const platedHole = holes[0]

if (platedHole.shape === "oval" || platedHole.shape === "pill") {
throw new Error("Oval or pill plated holes are not supported")
}

const platedHoleCircle = platedHole as PcbPlatedHoleCircle
// Check if all holes have the same dimensions
const firstHole = holes[0] as PcbPlatedHoleCircle
const allHolesSameDimensions = holes.every((hole) => {
const currentHole = hole as PcbPlatedHoleCircle
return (
currentHole.outer_diameter === firstHole.outer_diameter &&
currentHole.hole_diameter === firstHole.hole_diameter
)
})

const outerDiameterUm = Math.round(platedHoleCircle.outer_diameter * 1000)
const holeDiameterUm = Math.round(platedHoleCircle.hole_diameter * 1000)
const imageName = `MountingHole:MountingHole_${holeDiameterUm}um_${outerDiameterUm}um_Pad`
const padstackName = `Round[A]Pad_${holeDiameterUm}_${outerDiameterUm}_um` // Group all holes by image name
const outerDiameterUm = Math.round(firstHole.outer_diameter * 1000)
const holeDiameterUm = Math.round(firstHole.hole_diameter * 1000)

const placesByImage = new Map<
string,
Array<{
refdes: string
x: number
y: number
rotation: number
}>
>()
const imageName = allHolesSameDimensions
? `MountingHole:MountingHole_${holeDiameterUm}um_${outerDiameterUm}um_Pad`
: `MountingHole:MountingHole_Component_${componentId}`

if (pcbComponent) {
const circuitSpaceCoordinates = applyToPoint(
transformMmToUm,
pcbComponent.center,
)

// Add to places collection
if (!placesByImage.has(imageName)) {
placesByImage.set(imageName, [])
// Group places by dimensions
if (!placesByDimensions.has(imageName)) {
placesByDimensions.set(imageName, [])
}
placesByImage.get(imageName)?.push({
placesByDimensions.get(imageName)?.push({
refdes: componentName,
x: circuitSpaceCoordinates.x,
y: -circuitSpaceCoordinates.y, // Flip Y coordinate
y: -circuitSpaceCoordinates.y,
rotation: 0,
})
}

// Add single component with all places
if (placesByImage.size > 0) {
// Check if component with this image name already exists
const existingComponent = pcb.placement.components.find(
(comp) => comp.name === imageName,
)

if (existingComponent) {
// Add new places to existing component
existingComponent.places.push(
...placesByImage.get(imageName)!.map((place) => ({
refdes: place.refdes,
x: place.x,
y: place.y,
side: "front" as const,
rotation: place.rotation,
PN: "",
})),
)
} else {
// Create new component
pcb.placement.components.push({
name: imageName,
places: placesByImage.get(imageName)!.map((place) => ({
refdes: place.refdes,
x: place.x,
y: place.y,
side: "front",
rotation: place.rotation,
PN: "",
})),
})
}
}

// Add or update image in library
const existingImage = pcb.library.images.find(
(img) => img.name === imageName,
Expand All @@ -131,38 +98,63 @@ export function processPlatedHoles(
pcb.library.images.push({
name: imageName,
outlines: [],
pins: holes.map((hole, index) => ({
padstack_name: padstackName,
pin_number: index + 1,
x: (hole.x - (pcbComponent?.center.x || 0)) * 1000,
y: -(hole.y - (pcbComponent?.center.y || 0)) * 1000,
})),
pins: holes.map((hole, index) => {
const platedHoleCircle = hole as PcbPlatedHoleCircle
const currentOuterDiameterUm = Math.round(
platedHoleCircle.outer_diameter * 1000,
)
const currentHoleDiameterUm = Math.round(
platedHoleCircle.hole_diameter * 1000,
)
const padstackName = `Round[A]Pad_${currentHoleDiameterUm}_${currentOuterDiameterUm}_um`

// Add padstack if not already present
if (!pcb.library.padstacks.find((p) => p.name === padstackName)) {
pcb.library.padstacks.push({
name: padstackName,
shapes: [
{
shapeType: "circle",
layer: "F.Cu",
diameter: currentOuterDiameterUm,
},
{
shapeType: "circle",
layer: "B.Cu",
diameter: currentOuterDiameterUm,
},
],
hole: {
shape: "circle",
diameter: currentHoleDiameterUm,
},
attach: "off",
})
}

return {
padstack_name: padstackName,
pin_number: index + 1,
x: (hole.x - (pcbComponent?.center.x || 0)) * 1000,
y: -(hole.y - (pcbComponent?.center.y || 0)) * 1000,
}
}),
})
}
}

// Add padstack if not already present
if (!pcb.library.padstacks.find((p) => p.name === padstackName)) {
pcb.library.padstacks.push({
name: padstackName,
shapes: [
{
shapeType: "circle",
layer: "F.Cu",
diameter: outerDiameterUm,
},
{
shapeType: "circle",
layer: "B.Cu",
diameter: outerDiameterUm,
},
],
// Add drill hole
hole: {
shape: "circle",
diameter: holeDiameterUm,
},
attach: "off",
})
}
// Add components to placement after processing all holes
for (const [imageName, places] of placesByDimensions) {
pcb.placement.components.push({
name: imageName,
places: places.map((place) => ({
refdes: place.refdes,
x: place.x,
y: place.y,
side: "front",
rotation: place.rotation,
PN: "",
})),
})
}
}
157 changes: 157 additions & 0 deletions tests/assets/repro/different-sized-plated-holes.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
[
{
"type": "source_port",
"source_port_id": "source_port_0",
"name": "pin1",
"pin_number": 1,
"port_hints": ["anode", "pos", "left", "pin1", "1"],
"source_component_id": "source_component_0"
},
{
"type": "source_port",
"source_port_id": "source_port_1",
"name": "pin2",
"pin_number": 2,
"port_hints": ["cathode", "neg", "right", "pin2", "2"],
"source_component_id": "source_component_0"
},
{
"type": "source_component",
"source_component_id": "source_component_0",
"ftype": "simple_resistor",
"name": "R1",
"supplier_part_numbers": {
"jlcpcb": ["C22859", "C25077", "C17415"]
},
"resistance": 10
},
{
"type": "schematic_component",
"schematic_component_id": "schematic_component_0",
"center": {
"x": 0,
"y": 0
},
"rotation": 0,
"size": {
"width": 1.1238982820000005,
"height": 0.24999600000000122
},
"source_component_id": "source_component_0",
"symbol_name": "boxresistor_horz",
"symbol_display_value": "10Ω"
},
{
"type": "schematic_port",
"schematic_port_id": "schematic_port_0",
"schematic_component_id": "schematic_component_0",
"center": {
"x": -0.5337907000000003,
"y": 0.004194800000000665
},
"source_port_id": "source_port_0",
"facing_direction": "left",
"distance_from_component_edge": 0.4,
"pin_number": 1,
"display_pin_label": "left"
},
{
"type": "schematic_port",
"schematic_port_id": "schematic_port_1",
"schematic_component_id": "schematic_component_0",
"center": {
"x": 0.5337907000000003,
"y": 0.004741299999999338
},
"source_port_id": "source_port_1",
"facing_direction": "right",
"distance_from_component_edge": 0.4,
"pin_number": 2,
"display_pin_label": "right"
},
{
"type": "pcb_component",
"pcb_component_id": "pcb_component_0",
"center": {
"x": 1.7499999999999998,
"y": 0
},
"width": 4.699999999999999,
"height": 2.2,
"layer": "top",
"rotation": 0,
"source_component_id": "source_component_0"
},
{
"type": "pcb_board",
"pcb_board_id": "pcb_board_0",
"center": {
"x": 0,
"y": 0
},
"thickness": 1.4,
"num_layers": 4,
"width": 10,
"height": 10
},
{
"type": "pcb_plated_hole",
"pcb_plated_hole_id": "pcb_plated_hole_0",
"pcb_component_id": "pcb_component_0",
"pcb_port_id": "pcb_port_0",
"outer_diameter": 1.2,
"hole_diameter": 1,
"shape": "circle",
"port_hints": ["pin1"],
"x": 0,
"y": 0,
"layers": ["top", "bottom"]
},
{
"type": "pcb_plated_hole",
"pcb_plated_hole_id": "pcb_plated_hole_1",
"pcb_component_id": "pcb_component_0",
"pcb_port_id": "pcb_port_1",
"outer_diameter": 2.2,
"hole_diameter": 2,
"shape": "circle",
"port_hints": ["pin2"],
"x": 3,
"y": 0,
"layers": ["top", "bottom"]
},
{
"type": "pcb_port",
"pcb_port_id": "pcb_port_0",
"pcb_component_id": "pcb_component_0",
"layers": ["top", "inner1", "inner2", "bottom"],
"x": 0,
"y": 0,
"source_port_id": "source_port_0"
},
{
"type": "pcb_port",
"pcb_port_id": "pcb_port_1",
"pcb_component_id": "pcb_component_0",
"layers": ["top", "inner1", "inner2", "bottom"],
"x": 3,
"y": 0,
"source_port_id": "source_port_1"
},
{
"type": "cad_component",
"cad_component_id": "cad_component_0",
"position": {
"x": 1.7499999999999998,
"y": 0,
"z": 0.7
},
"rotation": {
"x": 0,
"y": 0,
"z": 0
},
"pcb_component_id": "pcb_component_0",
"source_component_id": "source_component_0"
}
]
Loading

0 comments on commit aab7a55

Please sign in to comment.