mohan-bee/stm32-midi-keys
Clips rectangular ground-region geometry to fit within the board’s scaled rounded-edge outline using polygon intersection.
- Version
- 1.0.2
- License
- unset
- Stars
- 0
scripts/silkscreen.ts
import { readFileSync, writeFileSync } from 'node:fs'
const g=JSON.parse(readFileSync('source/geometry.json','utf8'))
const rectangles:any[]=[]
// ponytail: Circuit JSON has no filled silk polygon. Approximate with 0.025mm strips
// until the platform supports filled silkscreen polygons directly.
const step=0.025
for(const poly of g.silkscreenPolygons.filter((p:any)=>p.filled)) {
const points=poly.points
const minY=Math.min(...points.map((p:any)=>p.y)), maxY=Math.max(...points.map((p:any)=>p.y))
let previous:any[]=[]
for(let y=minY; y<maxY-1e-8; y+=step) {
const height=Math.min(step,maxY-y), cy=y+height/2
const xs:number[]=[]
for(let i=0;i<points.length;i++) {
const a=points[i],b=points[(i+1)%points.length]
if((a.y<=cy && b.y>cy)||(b.y<=cy && a.y>cy)) xs.push(a.x+(cy-a.y)*(b.x-a.x)/(b.y-a.y))
}
xs.sort((a,b)=>a-b)
if(xs.length%2) throw new Error('Unpaired silk polygon intersections')
const current=[]
for(let i=0;i<xs.length;i+=2) {
const left=xs[i],right=xs[i+1]
const prev=previous.find(r=>Math.abs(r.center.x-(left+right)/2)<1e-7 && Math.abs(r.width-(right-left))<1e-7)
if(prev) {prev.center.y+=height/2;prev.height+=height;current.push(prev)}
else {
const rect={type:'pcb_silkscreen_rect',pcb_silkscreen_rect_id:`key_silk_${rectangles.length}`,pcb_component_id:'',layer:poly.layer==='F.SilkS'?'top':'bottom',center:{x:(left+right)/2,y:cy},width:right-left,height,stroke_width:0,is_filled:true,has_stroke:false}
rectangles.push(rect);current.push(rect)
}
}
previous=current
}
}
writeFileSync('silkscreen.json',JSON.stringify(rectangles,null,2))
console.log(`Generated ${rectangles.length} silk rectangles from ${g.silkscreenPolygons.length} polygons`)