ShiboSoftwareDev/linux-gameboy-advance

Restores PCB assembly metadata by assigning part numbers and 3D CAD models, removing test-point bodies, and validating top-side SMT solder-paste features without altering copper or pads.

Version
1.0.17
License
unset
Stars
0

scripts/search-via-position.mjs

import fs from "node:fs"
import {
  checkViaTraceClearance,
  checkViaPadClearance,
  checkViasInPads,
  checkDifferentNetViaSpacing,
  checkSameNetViaSpacing,
  checkEachPcbTraceNonOverlapping,
} from "@tscircuit/checks"
import { getFullConnectivityMapFromCircuitJson } from "circuit-json-to-connectivity-map"

const circuit = JSON.parse(fs.readFileSync("dist/index/circuit.json", "utf8"))
const traces = JSON.parse(fs.readFileSync("work/optimized-carrier-traces.json", "utf8"))
const cache = JSON.parse(fs.readFileSync("carrier-route-cache.json", "utf8"))
const carrierIds = new Set(cache.traces.map((trace) => trace.pcb_trace_id))
const routeById = new Map(traces.map((trace) => [trace.pcb_trace_id, trace.route]))
for (const trace of circuit.filter((e) => e.type === "pcb_trace" && routeById.has(e.pcb_trace_id)))
  trace.route = routeById.get(trace.pcb_trace_id)
const keyByTrace = new Map(circuit.filter((e)=>e.type==="pcb_via").map((v)=>[v.pcb_trace_id,v.subcircuit_connectivity_map_key]))
for(let i=circuit.length-1;i>=0;i--) if(circuit[i].type==="pcb_via"&&carrierIds.has(circuit[i].pcb_trace_id)) circuit.splice(i,1)
let nextVia=0
for(const trace of circuit.filter((e)=>e.type==="pcb_trace"&&carrierIds.has(e.pcb_trace_id))){
  let occurrence=0
  for(const point of trace.route.filter((p)=>p.route_type==="via")) circuit.push({
    type:"pcb_via",pcb_via_id:`search_via_${nextVia++}`,pcb_trace_id:trace.pcb_trace_id,
    x:point.x,y:point.y,hole_diameter:point.via_hole_diameter,outer_diameter:point.via_diameter,
    layers:["top","inner1","inner2","bottom"],from_layer:point.from_layer,to_layer:point.to_layer,
    subcircuit_id:trace.subcircuit_id,subcircuit_connectivity_map_key:keyByTrace.get(trace.pcb_trace_id),occurrence:occurrence++,
  })
}
const connMap=getFullConnectivityMapFromCircuitJson(circuit)
const cases=[
  {traceId:"source_trace_127_0",routeIndex:31,occurrence:3},
  {traceId:"source_trace_124_0",routeIndex:31,occurrence:2},
]
const hasCandidateError=(via)=>[
  ...checkViaTraceClearance(circuit,{connMap,minClearance:0.1}),
  ...checkViaPadClearance(circuit,{connMap,minClearance:0.1}),
  ...checkViasInPads(circuit),
  ...checkDifferentNetViaSpacing(circuit,{connMap,minClearance:0.2}),
  ...checkSameNetViaSpacing(circuit,{connMap,minClearance:0.2}),
  ...checkEachPcbTraceNonOverlapping(circuit,{connMap,minClearance:0.1}),
].some((e)=>
  e.pcb_via_id===via.pcb_via_id||
  e.pcb_pad_ids?.includes(via.pcb_via_id)||
  e.pcb_trace_error_id?.includes(via.pcb_via_id)||
  e.pcb_trace_error_id?.includes(via.pcb_trace_id)||
  e.message?.includes(via.pcb_via_id))

for(const item of cases){
  const trace=circuit.find((e)=>e.type==="pcb_trace"&&e.pcb_trace_id===item.traceId)
  const via=circuit.find((e)=>e.type==="pcb_via"&&e.pcb_trace_id===item.traceId&&e.occurrence===item.occurrence)
  const point=trace.route[item.routeIndex], origin={x:point.x,y:point.y}
  let found=null, tested=0
  outer: for(let radius=0;radius<=4;radius+=0.05){
    const steps=Math.ceil(radius/0.05)
    for(let ix=-steps;ix<=steps;ix++)for(let iy=-steps;iy<=steps;iy++){
      const dx=ix*0.05,dy=iy*0.05,d=Math.hypot(dx,dy)
      if(d>radius+1e-6||d<radius-0.07)continue
      const x=origin.x+dx,y=origin.y+dy
      for(const index of [item.routeIndex-1,item.routeIndex,item.routeIndex+1]){
        trace.route[index].x=x;trace.route[index].y=y
      }
      via.x=x;via.y=y;tested++
      if(!hasCandidateError(via)){found={x,y,d};break outer}
    }
  }
  console.log(item.traceId,{origin,found,tested})
  if(found){
    for(const index of [item.routeIndex-1,item.routeIndex,item.routeIndex+1]){
      routeById.get(item.traceId)[index].x=found.x;routeById.get(item.traceId)[index].y=found.y
    }
  }
}
fs.writeFileSync("work/searched-carrier-traces.json",JSON.stringify(traces,null,2)+"\n")