0hmX/am3352
This code suite comprises TypeScript scripts that analyze, verify, and assemble complex DDR memory interface hardware, focusing on physical routing, via and pad placement, electrical clearance, and physical constraints, often involving precise geometric calculations and consistent provenance tracking.
- Version
- 1.0.5
- License
- unset
- Stars
- 0
scripts/ddr-ground-plane-antipads.ts
/** Append explicit conventional-through-via antipads without cutting the outer
* reference-plane boundary or merging existing voids. Reject a placement that
* needs more general repouring. Positive inner-ring orientation matches the
* captured tscircuit BREP convention. Caller must provide correct GND aliases.
*/
type Point={x:number;y:number}
function inside(p:Point,vs:Point[]){let yes=false;for(let i=0,j=vs.length-1;i<vs.length;j=i++){const a=vs[i]!,b=vs[j]!;if((a.y>p.y)!==(b.y>p.y)&&p.x<(b.x-a.x)*(p.y-a.y)/(b.y-a.y)+a.x)yes=!yes}return yes}
function ringDistance(p:Point,vs:Point[]){return Math.min(...vs.map((a,i)=>{const b=vs[(i+1)%vs.length]!,dx=b.x-a.x,dy=b.y-a.y,t=Math.max(0,Math.min(1,((p.x-a.x)*dx+(p.y-a.y)*dy)/(dx*dx+dy*dy)||0));return Math.hypot(p.x-a.x-t*dx,p.y-a.y-t*dy)}))}
export function planDdrGroundAntipads(originalPlanes:any[],vias:Array<Point&{net:string;diameter?:number}>,options:{clearanceMm?:number;minimumCopperWebMm?:number}={}){
const planes=structuredClone(originalPlanes),added:any[]=[],clearance=options.clearanceMm??.1016,web=options.minimumCopperWebMm??.1524
if(!Number.isFinite(clearance)||clearance<.1016||!Number.isFinite(web)||web<.1016)throw Error('Clearance and plane web must be at least 0.1016 mm')
for(const via of vias)if(!Number.isFinite(via.x)||!Number.isFinite(via.y)||!via.net||!Number.isFinite(via.diameter??.4572)||(via.diameter??.4572)<.4572)throw Error('Invalid or undersize via')
for(const [planeIndex,plane]of planes.entries()){
if(plane.type!=='pcb_copper_pour'||plane.shape!=='brep')throw Error('Expected GND BREP plane')
const shape=plane.brep_shape
for(const via of vias){if(via.net==='GND')continue
const radius=((via.diameter??.4572)/2+clearance)/Math.cos(Math.PI/64),outer=shape.outer_ring.vertices,holes=shape.inner_rings??=[],inOuter=inside(via,outer),distOuter=ringDistance(via,outer),hole=holes.find((h:any)=>inside(via,h.vertices))
if(!inOuter){if(distOuter<radius)throw Error(`Via antipad crosses outer boundary on ${plane.pcb_copper_pour_id}`);continue}
if(hole){if(ringDistance(via,hole.vertices)<radius)throw Error(`Existing hole too small on ${plane.pcb_copper_pour_id}`);continue}
if(distOuter<radius+web||holes.some((h:any)=>ringDistance(via,h.vertices)<radius+web))throw Error(`Antipad violates required reference-plane web on ${plane.pcb_copper_pour_id}`)
const vertices=Array.from({length:64},(_,i)=>({x:via.x+radius*Math.cos(i*Math.PI/32),y:via.y+radius*Math.sin(i*Math.PI/32)}))
shape.inner_rings.push({vertices});added.push({planeIndex,planeId:plane.pcb_copper_pour_id,center:{x:via.x,y:via.y},radiusMm:radius})
}
}
return {planes,added,clearanceMm:clearance,minimumCopperWebMm:web,outerRingsUnchanged:true,originalHolesUnchanged:true}
}