astra/pd-power-supply
USB-PD Power Supply with RP2040 controller
- Version
- 1.1.6
- License
- unset
- Stars
- 0
scripts/export-enclosure.mjs
import {readFileSync,writeFileSync,mkdirSync} from 'node:fs'
import jscad from '@jscad/modeling'
const {primitives:p,transforms:t,booleans:b,geometries:g}=jscad
const data=JSON.parse(readFileSync('dist/index/circuit.json','utf8'))
const id=data.find(x=>x.type==='source_component'&&x.name==='CASE').source_component_id
const parts=data.filter(x=>x.type==='cad_component'&&x.source_component_id===id)
function evaluate(n){
switch(n.type){
case 'cuboid':return p.cuboid({size:n.size})
case 'cylinder':return p.cylinder({radius:n.radius,height:n.height,segments:n.resolution??48})
case 'translate':return t.translate(n.vector,evaluate(n.shape))
case 'rotate':return t.rotate(n.angles,evaluate(n.shape))
case 'subtract':return b.subtract(...n.shapes.map(evaluate))
case 'union':return b.union(...n.shapes.map(evaluate))
default:throw new Error(`Unexpected enclosure plan: ${n.type}`)
}
}
function stl(shape){
const polys=g.geom3.toPolygons(shape)
const triangles=polys.flatMap(poly=>{const v=poly.vertices;return Array.from({length:v.length-2},(_,i)=>[v[0],v[i+1],v[i+2]])})
const output=Buffer.alloc(84+triangles.length*50)
output.write('tscircuit-generated PD supply enclosure');output.writeUInt32LE(triangles.length,80)
triangles.forEach((tri,i)=>{let off=84+i*50;const a=tri[0],u=tri[1].map((v,k)=>v-a[k]),v=tri[2].map((v,k)=>v-a[k]);const n=[u[1]*v[2]-u[2]*v[1],u[2]*v[0]-u[0]*v[2],u[0]*v[1]-u[1]*v[0]];const len=Math.hypot(...n)||1;[...n.map(x=>x/len),...tri.flat()].forEach(x=>{output.writeFloatLE(x,off);off+=4})})
return output
}
mkdirSync('dist/enclosure',{recursive:true})
let base=evaluate(parts[0].model_jscad)
// Native enclosure API does not yet create bosses. Union the same four preview
// bosses into its generated base, at floor Z=2..6 in enclosure-local coordinates.
for(const hole of data.filter(x=>x.type==='pcb_hole' && (x.hole_diameter===3.2||x.diameter===3.2))){
const {x,y}=hole
const boss=t.translate([x,y,4],b.subtract(p.cylinder({radius:3.4,height:4,segments:48}),p.cylinder({radius:1.6,height:6,segments:48})))
base=b.union(base,boss)
}
writeFileSync('dist/enclosure/base.stl',stl(base))
let lid=evaluate(parts[1].model_jscad)
// Bring printed lid lowest Z to zero for slicers.
const bounds=jscad.measurements.measureBoundingBox(lid)
lid=t.translate([0,0,-bounds[0][2]],lid)
writeFileSync('dist/enclosure/lid.stl',stl(lid))
console.log('Exported generated enclosure base (with M3 bosses) and lid.')