abse/museair-usb

USB-C–powered ESP32-C3 controller board with AP63203 buck conversion, AP2112K 3.3V regulation, I²C SEN62 sensor interface, status LED, buttons, UART/I²C headers, and extensive decoupling.

Version
0.5.7
License
unset
Stars
0

scripts/add-flat-light-pipe.py

from pathlib import Path
import json,base64,numpy as np,trimesh
from OCP.gp import gp_Pnt,gp_Dir,gp_Ax2
from OCP.BRepPrimAPI import BRepPrimAPI_MakeCylinder,BRepPrimAPI_MakeBox,BRepPrimAPI_MakeCone
from OCP.BRepAlgoAPI import BRepAlgoAPI_Fuse,BRepAlgoAPI_Cut
from OCP.BRepMesh import BRepMesh_IncrementalMesh
from OCP.TopExp import TopExp_Explorer
from OCP.TopAbs import TopAbs_FACE,TopAbs_REVERSED
from OCP.TopoDS import TopoDS
from OCP.TopLoc import TopLoc_Location
from OCP.BRep import BRep_Tool
from OCP.BRepCheck import BRepCheck_Analyzer
r=Path(__file__).resolve().parent.parent;a=r/'assembly-assets';out=r/'mechanical/light-pipe'
x,y,z=-11.5,18.5,38.6;inch=25.4;height=.350*inch;outer=.185*inch;inner=.140*inch;base=.105*inch;recess=.085*inch;pin=.023*inch;pinlen=.060*inch
ax=lambda xx,yy,zz:gp_Ax2(gp_Pnt(xx,yy,zz),gp_Dir(0,0,1))
fuse=lambda aa,bb:BRepAlgoAPI_Fuse(aa,bb).Shape()
s=BRepPrimAPI_MakeBox(gp_Pnt(x-outer/2,y-outer/2,z),outer,outer,base).Shape()
s=BRepAlgoAPI_Cut(s,BRepPrimAPI_MakeBox(gp_Pnt(x-inner/2,y-inner/2,z-.01),inner,inner,recess+.01).Shape()).Shape()
# Transition profile shown but not dimensioned: visual reconstruction, not OEM CAD.
s=fuse(s,BRepPrimAPI_MakeCone(ax(x,y,z+base),outer/2,.118*inch/2,.8).Shape())
s=fuse(s,BRepPrimAPI_MakeCylinder(ax(x,y,z+base+.8),.118*inch/2,height-base-.8).Shape())
pins=[]
for sign in [-1,1]:
 px=x+sign*.136*inch/2;py=y+sign*.080*inch;pins.append([px,py]);s=fuse(s,BRepPrimAPI_MakeCylinder(ax(px,py,z-pinlen),pin/2,pinlen+.01).Shape())
assert BRepCheck_Analyzer(s).IsValid()
BRepMesh_IncrementalMesh(s,.02,False,.08,True).Perform();ex=TopExp_Explorer(s,TopAbs_FACE);tri=[]
while ex.More():
 f=TopoDS.Face_s(ex.Current());loc=TopLoc_Location();t=BRep_Tool.Triangulation_s(f,loc)
 if t:
  for i in range(1,t.NbTriangles()+1):
   ids=list(t.Triangle(i).Get())
   if f.Orientation()==TopAbs_REVERSED:ids[1],ids[2]=ids[2],ids[1]
   tri.append([t.Node(j).Transformed(loc.Transformation()).Coord() for j in ids])
 ex.Next()
v=np.array(tri).reshape(-1,3);m=trimesh.Trimesh(vertices=v,faces=np.arange(len(v)).reshape(-1,3),process=True)
for name,tint in [('bivar-vlp-350-f',[235,248,255,90]),('vlp-section-display',[85,175,205,255])]:
 m.visual=trimesh.visual.TextureVisuals(material=trimesh.visual.material.PBRMaterial(name='Drawing-based clear polycarbonate'+(' — tinted for section' if 'section' in name else ''),baseColorFactor=tint,metallicFactor=0,roughnessFactor=.15,alphaMode='BLEND' if tint[3]<255 else 'OPAQUE',doubleSided=True));raw=trimesh.Scene(m).export(file_type='glb');(a/(name+'.glb')).write_bytes(raw);(a/(name+'.ts')).write_text('export default '+json.dumps('data:model/gltf-binary;base64,'+base64.b64encode(raw).decode())+'\n')
 if 'section' in name:
  (r/'viewer/pipe-mount-display.txt').write_text(base64.b64encode(raw).decode())
  cut=m.slice_plane([x,y,0],[-1,0,0],cap=True);cut.visual=trimesh.visual.TextureVisuals(material=trimesh.visual.material.PBRMaterial(baseColorFactor=[85,175,205,255],metallicFactor=0,roughnessFactor=.2));(r/'viewer/pipe-section-display.txt').write_text(base64.b64encode(trimesh.Scene(cut).export(file_type='glb')).decode())
pcb=trimesh.load(a/'pcb-geometry.gltf',force='scene');cm=trimesh.collision.CollisionManager();cm.add_object('pipe',m);hits=[]
for n in pcb.graph.nodes_geometry:
 tf,g=pcb.graph[n];p=pcb.geometry[g].copy();p.apply_transform(tf)
 if cm.in_collision_single(p):hits.append(n)
report={'part':'VLP-350-F','source':'Bivar VLP-XXX-X rev L drawing; not OEM CAD','status':'PCB holes and routed copper verified; physical fit untested','pcb_top_z_mm':z,'body_height_mm':height,'lens_z_mm':z+height,'lid_z_mm':[45,47],'projection_mm':z+height-47,'led_top_z_mm':39.41,'cavity_roof_z_mm':z+recess,'led_cavity_clearance_mm':z+recess-39.41,'base_width_mm':outer,'pins_world_xy_mm':pins,'pin_diameter_mm':pin,'pin_length_mm':pinlen,'required_drill_mm':.024*inch,'required_drill_limits_mm':[.022*inch,.027*inch],'cad_contact_nodes':hits,'cad_contact_explanation':'PCB top texture plane and via artwork are not physical collision solids; substrate contact at the seating face is expected. Native drill and copper-clearance checks are authoritative.','undimensioned_transition_profile_illustrative':True,'published':False}
(out/'vlp-350-fit-audit.json').write_text(json.dumps(report,indent=2));print(json.dumps(report,indent=2))
p=r/'assembly.circuit.tsx';p.write_text(p.read_text().replace('bivar-plp1-175','bivar-vlp-350-f').replace('PLP1-175','VLP-350-F').replace('BIVAR_PLP1_175_LIGHT_PIPE','BIVAR_VLP_350_F_LIGHT_PIPE'))