import math
from mathutils import Vector
from geometry import box,cyl,prism
OAK=2;IRON=10
def beam(g,a,b,w,d,m=OAK,bevel=.008):
 a=Vector(a);b=Vector(b);v=b-a;g.grain=v.normalized()
 box(g,(a+b)/2,(w,d,v.length),m,bevel,v.to_track_quat('Z','Y').to_matrix());g.grain=Vector((1,0,0))

def ribbon(g,points,width,depth,m=OAK,n=8):
 # Rectangular chamfered sweep in facade XY, closed end caps, shared rings.
 pts=[Vector(p) for p in points];vs=[]
 for j,p in enumerate(pts):
  t=(pts[min(j+1,len(pts)-1)]-pts[max(j-1,0)]).normalized();side=Vector((-t.y,t.x,0));z=Vector((0,0,1));w=width/2;d=depth/2;b=min(.008,w*.25)
  for u,v in [(-w+b,-d),(w-b,-d),(w,-d+b),(w,d-b),(w-b,d),(-w+b,d),(-w,d-b),(-w,-d+b)]:vs.append(p+side*u+z*v)
 fs=[tuple(range(n-1,-1,-1)),tuple(range((len(pts)-1)*n,len(pts)*n))]
 for j in range(len(pts)-1):
  for k in range(n):fs.append((j*n+k,j*n+(k+1)%n,(j+1)*n+(k+1)%n,(j+1)*n+k))
 g.grain=(pts[-1]-pts[0]).normalized();g.add(vs,fs,m);g.grain=Vector((1,0,0))

def sweep(g,pts,r,m=IRON,n=5):
 pts=[Vector(p) for p in pts];vs=[]
 for j,p in enumerate(pts):
  t=pts[min(j+1,len(pts)-1)]-pts[max(j-1,0)];q=t.to_track_quat('Z','Y')
  vs += [p+q@Vector((r*math.cos(k*math.tau/n),r*math.sin(k*math.tau/n),0)) for k in range(n)]
 fs=[tuple(range(n-1,-1,-1)),tuple(range((len(pts)-1)*n,len(pts)*n))]
 fs += [(j*n+k,j*n+(k+1)%n,(j+1)*n+(k+1)%n,(j+1)*n+k) for j in range(len(pts)-1) for k in range(n)]
 g.add(vs,fs,m,True)

def peg(g,x,y,z=.007,r=.018,n=6):cyl(g,(x,y,z-.015),(x,y,z+.013),r,OAK,n)
def ring(g,c,r,small=.009,m=IRON,n=12,axis='z'):
 pts=[(c[0]+r*math.cos(i*math.tau/n),c[1]+r*math.sin(i*math.tau/n),c[2]) for i in range(n+1)]
 if axis=='x':pts=[(c[0],c[1]+r*math.sin(i*math.tau/n),c[2]+r*math.cos(i*math.tau/n)) for i in range(n+1)]
 sweep(g,pts,small,m,4)
