"""Blender-authored schematic of an original IceCube DOM, not a CAD replica."""
import bpy, math
from pathlib import Path
P=Path(__file__).resolve().parent; O=P/'assets/models'; O.mkdir(exist_ok=True)
bpy.ops.object.select_all(action='SELECT');bpy.ops.object.delete(use_global=False)
def material(name,color,metal=0,rough=.4,alpha=1):
 m=bpy.data.materials.new(name);m.diffuse_color=(*color,alpha);m.use_nodes=True
 n=m.node_tree.nodes.get('Principled BSDF');n.inputs['Base Color'].default_value=(*color,alpha);n.inputs['Metallic'].default_value=metal;n.inputs['Roughness'].default_value=rough;n.inputs['Alpha'].default_value=alpha
 return m
glass=material('Glass housing cutaway',(0.48,.78,.88),.08,.15,.15)
metal=material('Steel support band',(.25,.34,.41),.8,.25)
dark=material('Photomultiplier body',(.06,.09,.12),.3,.27)
gold=material('Photocathode schematic',(.65,.48,.22),.58,.22)
pcb=material('Digitization board',(.04,.28,.19),.2,.42)
copper=material('Copper traces',(.73,.5,.24),.7,.3)
white=material('Connector insulator',(.75,.86,.88),0,.3)
def objfinish(name,m):
 o=bpy.context.object;o.name=name;o.data.materials.append(m)
 for p in o.data.polygons:p.use_smooth=True
 return o
def sphere(name,r,z,m,theta=math.pi,phi=2*math.pi):
 vs=[];fs=[];u=80;v=40
 for j in range(v+1):
  a=theta*j/v
  for i in range(u+1):
   b=phi*i/u+.15;vs.append((r*math.sin(a)*math.cos(b),r*math.sin(a)*math.sin(b),z+r*math.cos(a)))
 for j in range(v):
  for i in range(u):
   k=j*(u+1)+i;fs.append((k,k+1,k+u+2,k+u+1))
 mesh=bpy.data.meshes.new(name);mesh.from_pydata(vs,[],fs);mesh.update();o=bpy.data.objects.new(name,mesh);bpy.context.collection.objects.link(o);o.data.materials.append(m)
 for p in mesh.polygons:p.use_smooth=True
 return o
def cyl(name,r,depth,z,m,x=0,y=0):
 bpy.ops.mesh.primitive_cylinder_add(vertices=64,radius=r,depth=depth,location=(x,y,z));return objfinish(name,m)
def box(name,loc,scale,m):
 bpy.ops.mesh.primitive_cube_add(size=1,location=loc);o=objfinish(name,m);o.scale=scale;bpy.ops.object.transform_apply(location=False,rotation=False,scale=True)
 bevel=o.modifiers.new('Soft manufactured edges','BEVEL');bevel.width=.007;bevel.segments=3
 return o
def torus(name,r,t,z,m):
 bpy.ops.mesh.primitive_torus_add(major_radius=r,minor_radius=t,major_segments=96,minor_segments=12,location=(0,0,z));return objfinish(name,m)
sphere('Partial pressure sphere: removed front sector',1,0,glass,phi=math.pi*1.28)
torus('Equatorial seal',1,.036,0,metal)
# The PMT window faces downward in the original DOM. Exaggerated for readability.
o=sphere('Downward facing photocathode window',.70,-.12,gold,theta=math.pi/2);o.rotation_euler.x=math.pi;o.location.z=-.24
torus('Photomultiplier rim',.70,.045,-.12,dark)
cyl('PMT neck',.19,.5,.08,dark)
cyl('Digitizing electronics board',.68,.038,.39,pcb)
torus('Board support',.66,.021,.37,metal)
for i in range(8):
 a=i*math.pi/4;x=.43*math.cos(a);y=.43*math.sin(a)
 box('Electronics component '+str(i),(x,y,.44),(.15,.10,.065),dark)
 box('Circuit trace '+str(i),(x*.63,y*.63,.414),(.18,.012,.004),copper)
for i in range(4):
 a=i*math.pi/2;cyl('Mechanical support '+str(i),.016,.42,.17,metal,.60*math.cos(a),.60*math.sin(a))
box('Mainboard processor',(.06,0,.45),(.24,.24,.06),dark)
cyl('Cable connector',.075,.19,.86,metal)
cyl('Readout cable',.023,.8,1.30,dark)
for i in range(3):
 box('Cable wiring '+str(i),(-.10+i*.075,.08,.60),(.028,.028,.28),copper)
bpy.ops.wm.save_as_mainfile(filepath=str(O/'icecube_dom_schematic.blend'))
bpy.ops.export_scene.gltf(filepath=str(O/'icecube_dom_schematic.glb'),export_format='GLB',export_apply=True,export_yup=True)
print('Saved Blender source and glTF DOM schematic',flush=True)
