abse/smartwatch-flex-top-only
Three-panel flex smartwatch with two parallel R3.9 bends, all components flat-top, low-profile JST connector harnesses, split heartbeat optical windows and screw-retained PCB mounting. Modeled 39 × 50.5 × 14.5mm prototype; 100% routing, zero native DRC and shorts. Hardware qualification pending.
- Version
- 0.2.20
- License
- unset
- Stars
- 0
scripts/audit-board-edge.mjs
import fs from 'node:fs'
import {createHash} from 'node:crypto'
import {copperModel} from './copper-model.mjs'
import {gap,inside} from './copper-geometry.mjs'
const [cacheFile,sourceFile,out='reports/board-edge-audit.json']=process.argv.slice(2),cache=JSON.parse(fs.readFileSync(cacheFile)),source=JSON.parse(fs.readFileSync(sourceFile))
const board=source.find(e=>e.type==='pcb_board'),cutouts=source.filter(e=>e.type==='pcb_cutout').map(c=>{if(c.shape==='polygon')return {kind:'polygon',points:c.points};if(c.shape!=='rect')throw Error('Unsupported cutout');return {kind:'polygon',points:[{x:c.center.x-c.width/2,y:c.center.y-c.height/2},{x:c.center.x+c.width/2,y:c.center.y-c.height/2},{x:c.center.x+c.width/2,y:c.center.y+c.height/2},{x:c.center.x-c.width/2,y:c.center.y+c.height/2}]}})
const edges=board.outline.map((a,i)=>({kind:'segment',a,b:board.outline[(i+1)%board.outline.length],r:0})),failures=[];let minimum=Infinity
for(const s of copperModel(cache,source)){
const points=s.kind==='polygon'?s.points:s.kind==='segment'?[s.a,s.b]:[s]
let d=Math.min(...edges.map(e=>gap(s,e)),...cutouts.map(e=>gap(s,e)))
if(points.some(p=>!inside(p,board.outline)))d=-1
if(!Number.isFinite(d))throw Error('Non-finite copper shape distance: '+s.id)
minimum=Math.min(d,minimum);if(d<.3-1e-6)failures.push({id:s.id,net:s.net,gapMM:d})
}
const report={cacheFile,sourceFile,cacheSha256:createHash('sha256').update(fs.readFileSync(cacheFile)).digest('hex'),sourceSha256:createHash('sha256').update(fs.readFileSync(sourceFile)).digest('hex'),requiredMM:.3,minimumMM:minimum,failures,scope:'Actual pad, routed trace, printed winding and through-via copper against board outline and cutouts; copper pours handled by generated BREP audit.'};fs.writeFileSync(out,JSON.stringify(report,null,2)+'\n');console.log('Board edge/cutout clearance:',failures.length,'failures; minimum',minimum);if(failures.length)process.exitCode=1