import rhinoscriptsyntax as rs
import math
import Rhino

def PolarArray(idc,pcs,n,axis):
   """
   idc= identificativo oggetto
   pcs= centro rotazione
   n= numero oggetti su 360 gradi
   axis= vettore  asse rotazione
   """
   ang=(360.0/n)
   #rs.MessageBox(str(ang))
   arrsfere=[]
   n=int(n)
   for i in range (n):
     sfe=rs.RotateObject(idc,pcs,ang*i,axis,copy=True)
     Rhino.RhinoApp.Wait()
     arrsfere.append(sfe)
   return  arrsfere

def smusso_r(m,z,spes,smusso):  #crea superfici per smussi    
        
        l=m*z/2
        pi=(l,0,0)
        h=m*math.tan(15*math.pi/180)
        pe=(l+m,0,h)
        lsm=rs.AddLine(pe,pi)
        pm=rs.CurveMidPoint(lsm)
        rs.ScaleObject(lsm,pm,(2,2,2))
        sm1=rs.AddRevSrf(lsm,((0,0,0),(0,0,1)))        
        if smusso=="1s":
            rs.DeleteObject(lsm)
            return [sm1]        
        sm2=rs.RotateObject(sm1,(0,0,spes/2),180,(0,1,0),True)
        if smusso=="1d":
            rs.DeleteObject(sm1)
            rs.DeleteObject(lsm)
            return [sm2] 
        rs.DeleteObject(lsm)        
        return sm1,sm2        
    
def profilo(m,z,spessore,diametro,smusso): # crea profilo e ruota dentata
    rs.EnableRedraw(False)    
    rm=z*m/2 #raggio primitivo
    re=rm+m  #raggio esterno
    ri=rm-m*5/4
    alfa=20/180*math.pi
    rc=rm*math.cos(alfa)  # raggio convoluta
    cir_m=rs.AddCircle((0,0,0),rm)  # cerchio primitivo      
    l_arco=(re**2-rc**2)**0.5 #lunghezza arco per generare l'evolvente
                              # calcolato col metodo della corda di un cerchio
    nd=4 # numero divisioni per generare il profilo
    if z>40:nd=3
    if z>100: nd=2  
    #if z>300:nd=1
    angolo=l_arco/(2*math.pi*rc)*2*math.pi #angolo per generare evolvente
    d_arco=l_arco/nd  # delta arco
    d_angolo=angolo/nd #delta angolo
    lp=[]
    for i in range (nd+1): #punti per generare l'evolvente
        px=rc*math.cos(d_angolo*i)
        py=rc*math.sin(d_angolo*i)
        dx=d_arco*i*math.sin(d_angolo*i)
        dy=-d_arco*i*math.cos(d_angolo*i)
        p=(px+dx,py+dy,0)
        lp.append(p)
    if z<=800:
        fianco=rs.AddInterpCurve(lp,3) # fianco del dente
    else:
        fianco=rs.AddLine(lp[0],lp[1])
    if rc>ri: #se raggio convoluta maggiore del raggio interno
              # devo aggiungere un tratto di linea
        li=rs.AddLine((rc,0,0),(ri,0,0))
        fianco=rs.JoinCurves((fianco,li),True)        
        rs.RebuildCurve(fianco[0],3,nd)             
        p2i=rs.CurveStartPoint(fianco)
    else:# devo tagliare una parte del fianco        
        cir_i=rs.AddCircle((0,0,0),ri)
        lp=rs.CurveCurveIntersection(fianco,cir_i)
        pi=lp[0][1]
        param=rs.CurveClosestPoint(fianco,pi)
        lista_split=rs.SplitCurve(fianco,param)
        fianco=lista_split[1]
        
        rs.RebuildCurve(fianco,3,nd+1)
        p2i=rs.CurveStartPoint(fianco)
        rs.DeleteObject(lista_split[0])
        rs.DeleteObject(cir_i)
    da_dente=360/z  # angolo tra due denti in gradi
    d_alfa_dente=da_dente*math.pi/180  # angolo in radianti
    # ruoto il fianco di un passo e faccio il mirror per fianco sinistro
    fianco_sinistro=rs.RotateObject(fianco,(0,0,0),da_dente/2,None,True)     
    listap=rs.CurveCurveIntersection(cir_m,fianco_sinistro)
    p2=listap[0][1] # punto intersezione tra fianco e circonferenza primitiva  
    rs.DeleteObject(cir_m)
    # Mirror del fianco
    rs.MirrorObject(fianco_sinistro,(0,0,0),p2)
    ### Punti per disegnare arco di testa e arco di base  del dente
    p1e=rs.CurveEndPoint(fianco)
    p2e=rs.CurveEndPoint(fianco_sinistro) 
    ar=m*30/z
    #if z>80:ar=0.5
    #if z>150: ar=0.2
    #if z> 400:ar=0.05
    mat_rot=rs.XformRotation2(ar,(0,0,1),(0,0,0))
    pm=rs.PointTransform(p1e,mat_rot)
    if z<=800:
        arco_e=rs.AddArc3Pt(p1e,p2e,pm) # arco esterno
    else:
        arco_e=rs.AddLine(p1e,p2e)
    p1i=rs.CurveStartPoint(fianco_sinistro)
    pmi=rs.PointTransform(p1i,mat_rot)
    mat_rot2=rs.XformRotation2(da_dente,(0,0,1),(0,0,0))    
    p2i=rs.PointTransform(p2i,mat_rot2)
    if z<=300:
        arco_i=rs.AddArc3Pt(p1i,p2i,pmi)  # arco interno
    else:
        arco_i=rs.AddLine(p1i,p2i)
    rs.Command("_ClearUndo")
    dente=rs.JoinCurves((fianco,fianco_sinistro,arco_e,arco_i),True)
    dente_estruso=rs.ExtrudeCurveStraight(dente,(0,0,0),(0,0,spessore))
    #la=mf.PolarArray(dente_estruso,(0,0,0),z,(0,0,1))
    la=PolarArray(dente_estruso,(0,0,0),z,(0,0,1))
    ruota=rs.JoinSurfaces(la,True)
    rs.DeleteObject(dente)
    rs.DeleteObject(dente_estruso)
    print "ciao"
    #profilo=profilo(modulo,num_denti)
    #ruota=rs.ExtrudeCurveStraight(profilo,(0,0,0),(0,0,spessore))
    #rs.DeleteObject(profilo)
    rs.CapPlanarHoles(ruota)
    print "fine"
    cil=rs.AddCylinder((0,0,0),spessore,diametro/2)
    l_ruota=rs.BooleanDifference((ruota),(cil))
    if smusso=="1s":
        sm=smusso_r(m,z,spessore,smusso)
        l_ruota=rs.BooleanDifference(l_ruota,sm)
    if smusso=="1d":
        sm=smusso_r(m,z,spessore,smusso)
        l_ruota=rs.BooleanDifference(l_ruota,sm)
    if smusso=="2":
        sm=smusso_r(m,z,spessore,smusso)
        l_ruota=rs.BooleanDifference(l_ruota,sm)
    return l_ruota[0]
    rs.EnableRedraw(True)    
    
def ingranaggio(): # crea finestra per dati ingranaggio e li passa a profilo
    num_denti=rs.GetDocumentData("DatiIngranaggio","num_denti")
    if num_denti=="" or num_denti==None:num_denti="30"
    modulo=rs.GetDocumentData("DatiIngranaggio","modulo")
    if modulo=="" or modulo==None:modulo="2"
    spessore=rs.GetDocumentData("DatiIngranaggio","spessore")
    if spessore=="" or spessore==None:spessore="20"
    diametro=rs.GetDocumentData("DatiIngranaggio","diametro")
    if diametro=="" or diametro==None:diametro="20"
    smusso=rs.GetDocumentData("DatiIngranaggio","smusso")
    if smusso=="" or smusso==None:smusso="0"
    item=[" Number gear teeth","Module ","Wheel thickness","Hole diameter","Chamfer  0=no , 1s , 1d , 2"]
    value=[num_denti,modulo,spessore,diametro,smusso]
    dati=rs.PropertyListBox(item,value,"Dati Ingranaggio","Introduci i dati")
    if dati!=None:
        num_denti=float(dati[0])
        modulo=float(dati[1])
        spessore=float(dati[2])
        diametro=float(dati[3])
        smusso=dati[4]
        rs.SetDocumentData("DatiIngranaggio","num_denti",str(num_denti))
        rs.SetDocumentData("DatiIngranaggio","modulo",str(modulo))
        rs.SetDocumentData("DatiIngranaggio","spessore",str(spessore))
        rs.SetDocumentData("DatiIngranaggio","diametro",str(diametro))
        rs.SetDocumentData("DatiIngranaggio","smusso",smusso)
    else:
        return
    if diametro>= num_denti*modulo-2*modulo*2.5:
        rs.MessageBox("Diametro foro troppo grande reintrodurre i dati")
        return
    
    id_ruota=profilo(modulo,num_denti,spessore,diametro,smusso)# chiamo la def
    rs.SelectObject(id_ruota)
    rs.EnableRedraw(True)
    rs.Command("_Orient W0 W0,0,10 _Copy=_Yes",False)
    rs.DeleteObject(id_ruota)    
ingranaggio()