'/
    lcl_wireTool -- A work in progress wire generation rig.
    
    Created 19 November 2009
    
    Leong Chee Loong -- www.leongcl.com
    
    Creates a nParticle system that is controlled by VolumeAxisFields.
    
    nCloth RigidBody have to be used to make collidable objects. 
    
    On-line Tutor:
    
    http://gaki.mayapython.com/
    
    
    USAGE:
    
    1.User will have to draw or plot curves to act as paths for the wires to generate on.
    2.VolumeAxisFields are created along the curves created by user to control nParticle movement. 
    3.nParticle Positions are recorded to generate the wires along those positions. 
    4.Goal can be set to attract nParticles to a desired location.
    5.Imported mesh can be snapped to ends of each curve to act as jacks or plughead.
  
    PROBLEMS:
    
    1.Currently unable to set keys for goalweight in nParticle attributes.
    2.Imported Mesh not able to snap to ends of curve properly. 
    3.Not able to follow through if user plots or draws another curve/path after executing 
      VolumeAxisFields.  
    
    Current Best Work Flow:
    
    1. Generate Wires one path at a time. 
    2. Delete all Curves after extrusion. 
    3. Then only starting on new wire path. 
    
    EXAMPLE:
    
    execfile('/filepath/lcl_wireTool.py') # creates the GUI with default values
    Maya test file : 
    
    /'
  
#execfile('/filepath/lcl_wireTool.py')
import maya.cmds as mc
  
##__LISTINGS___########
  
def selectCurve():
    curveSelect = mc.select('curve1', add=True)
    return curveSelect
  
def listCurve():
    curveList = mc.ls(type='curveShape')
    curveTrans = [mc.listRelatives(x, parent=True, type='transform')[0] for x in curveList]
    return curveTrans
    #print curveTrans
  
def listObj():
    objList = mc.ls(type='mesh')
    objTrans = [mc.listRelatives(x, parent=True, type='transform')[0] for x in objList]
    return objTrans
    #print objTrans
  
def getPList():
    nParticleShapes = mc.ls(type='nParticle')
    nParticleTrans = [mc.listRelatives(x, parent=True, type='transform')[0] for x in nParticleShapes]
    return nParticleTrans
  
#-----------------------------------------------------------#
#Capturing Positions of each Id into Dictionary, 
#and Creating Curves
#------------------------------------------------------------#
  
    
def pPosListDict(nParticleName, startFrm, endFrm):
    #this is a dictionary#
    #in dictionary there are keys and value#
        #eg: {key1: value1, key2: value2}
    pPosDict = {}
    #-------
    for eachFrm in range(startFrm, (endFrm + 1)):
        mc.currentTime(eachFrm)
        getPshape = mc.ls (type = 'nParticle')
        pCount = mc.particle( nParticleName, query=True, count =True)
        checkpid = mc.getAttr( getPshape[0] + '.particleId')
        
        n = 0 
        for pId in range(pCount):
        
            #----only[x,y,z]----#
            eachPartPos = mc.nParticle(nParticleName, query=True, id = checkpid[n] , attribute='position')
        
            #trying something, if "anything" happens do something else.
            #This is to catagorize of each nParticle Id positions.
            try:
                pPosDict[pId].append(eachPartPos)
            #keyError can be other stuff#
            except KeyError:
                pPosDict[pId] = [eachPartPos]
            n = n + 1
        
    return pPosDict
    
####___command to create just one wire___####
  
def createCurve(singParPosList):
    #checking length of list
    faultlist = 4
    if len(singParPosList) >= faultlist:
        gCurve = mc.curve(d=3, p=singParPosList)
        
  
####___Command to read each and everynParticle and create a wire from each___######         
  
def gWire(pLastFrm):
    pList = getPList()
    startFrm = 0
    endFrm = mc.intFieldGrp(pLastFrm, query=True, value1=True)    
    for pName in pList:
        pPosDict = pPosListDict(pName, startFrm, endFrm)
        for each in pPosDict.values():
             gCurve = createCurve(each)
  
    
####___Emitters To Curve___###############################################################
  
def    emitCubeToCurve(*args):
    getCurve = []
    gnParticle = mc.nParticle(n='mynParticle')
    getCurve = listCurve()
    for eachCurve in getCurve:
        gCube = mc.polyCube(n='myObjEmit1')
        gEmit = mc.emitter(gCube[0], dx=1, dy=0, dz=0, sp=0.33,n='myEmitter')
        mc.connectDynamic(gnParticle[0], em=gEmit[0])
    
    snaptoCurve()    
    fConnect()
  
####___Snap Emitters To Curve___#########################3
  
def snaptoCurve():
    eachObj = listObj()
    getCurve = listCurve()
    #getCurve = emitCubeToCurve()
    a= 0    
    for eachCurve in getCurve:    
        addCname = eachCurve +".cv[0]"
        curveP1 = mc.getAttr(addCname)
        mc.move(curveP1[0][0],curveP1[0][1],curveP1[0][2],eachObj[a],absolute=True)
        a=a+1    
        
    
####__Set Max COunt___#######
  
def setPartMaxCount(*args):
    pCount = mc.intFieldGrp(pmaxCount, query=True, value1=True)
    nParticleShapes = mc.ls(type='nParticle')
    for eachPshape in nParticleShapes:
        cName = eachPshape + '.maxCount'
        mc.setAttr(cName, pCount)
        
##____VolumeAxis duplicate along curve___###
  
def volToCurve(startFrm,endFrm):
    
    lsVol = [] 
    lspath = listCurve()
    #lspath = mc.ls(selection = True)
    #frmBegin = startFrm
    frmEnd = mc.intFieldGrp(endFrm, query=True, value1=True)
  
    for eachpath in lspath:
        volAxis = mc.volumeAxis(pos=(0, 0, 0), afc=0, afx=0, arx=0, alx=0, drs=0.5)
        gPath = mc.pathAnimation( volAxis, stu=startFrm, etu=frmEnd, fa='x', ua='y', worldUpVector=(0,1,0), bank=False, c=eachpath )
        lsVol.append(volAxis)
  
  
    for volumeX in lsVol:
    
        lsSecVol = []    
        for eachFrame in range (startFrm,(frmEnd+1)):
            mc.currentTime(eachFrame)
            duplicated = mc.duplicate(volumeX)
            lsSecVol[len(lsSecVol):] = [duplicated[0]]
    
        mc.group( lsSecVol, name='VolumAxisGrp')
  
####dynamicRelations#################    
def fConnect():
  
    getVol = mc.ls(type='volumeAxisField')
    getPart = getPList()
    
    for eachPart in getPart:
        print eachPart
        for eachVol in getVol:
            mc.connectDynamic(eachPart,f=eachVol)
  
  
  
####Selecting All VolumeFields######
  
def SelVolF(*args):
    lsVol = mc.ls(type='volumeAxisField')
    mc.select(lsVol)
  
##Select nParticles####
def selectnParticles(*args):
    getPart = getPList()
    mc.select(getPart)    
    
##Select nParticles####
def selectEmits(*args):
    getEmits = mc.ls( type = 'pointEmitter') 
    mc.select(getEmits)        
    
  
  
#####extrude########
def extrude(*args):
    control = mc.circle( nr=(0, 1, 0), c=(0, 0, 0),r=0.2,n='myCircle' )
    extrusion = []
    getCurves = listCurve()
    #getCurve = gWire()
    for eachCurve in getCurves:
        extrudeCurve = mc.extrude( 'myCircle',eachCurve, extrudeType = 2, ucp = 1, fpt = True, upn = True, rsp=True)
        extrusion.append(extrudeCurve[0])
        
    mc.group (extrusion, control, name = 'wireGrp')    
####Define Goal Object####
# 2 or more goals, they will average out #
# only one can be activated at a time#
def goalDef(*args):
    
    getParticle = getPList()
    getObj = mc.ls( selection = True)
    for anObj in getObj:
        mc.goal( getParticle[0], g=anObj, w=.75 )
  
####Define_plugsHead####
def plugToWire(*args):
    
    ptonCurveLs = mc.ls(type = 'pointOnCurveInfo')
    
    if (len(ptonCurvesLs)> 0):
        mc.delete(ptonCurveLs)
    
    getObj = []
    theObj = mc.ls(selection = True)
    getCurves = mc.ls(type = 'curveShape')
    fcurve = len(getCurves) * 2
  
    
    #creating instance objects#
    for eachC in range (fcurve):
        getObj.append(mc.instance(theObj))
  
    #snaping to each curve ends#
    a= 0    
    for eachCurve in getCurves:    
        
        addCname = eachCurve +".cv[0]" #building the string#
        curveP1 = mc.getAttr(addCname)#returns the Cv position
        curvename = eachCurve + ".maxValue" 
        maxCurvePt = mc.getAttr(curvename)#find number of spans on each curve
        number = str(maxCurvePt)
        addCname2 = eachCurve + '.cv['+ number + ']' #building the string#
        curveP2 = mc.getAttr(addCname2) #returns the Cv position#
    
        #average normals#
        infoNode1 = mc.pointOnCurve(eachCurve, constructionHistory=True, parameter = -0.1)
        tangentInfo1 = mc.getAttr(infoNode1 + ".tangent")  # returns the tangent Info
        rotA = mc.angleBetween(euler=True, v2=(curveP1[0][0], curveP1[0][1], curveP1[0][2]), v1=(tangentInfo1[0][0],tangentInfo1[0][1],tangentInfo1[0][2]))
        mc.move( curveP1[0][0],curveP1[0][1],curveP1[0][2],getObj[a], relative=True, absolute=True)
        mc.move( curveP2[0][0],curveP2[0][1],curveP2[0][2],getObj[(a+1)], relative=True, absolute=True)
        mc.rotate ( (-180 + rotA[0]),  rotA[1], (-180 + rotA[2]), getObj[a], absolute=True)
        
        #tangent Constraint#
        mc.tangentConstraint( addCname2, getObj[(a+1)])
        a=a+2    
     
####Setting Attributes#####
  
###EmiterAttributes####
def emitOnSurf(*args):
    getEmits = mc.ls(type='pointEmitter')  
    
    for eachEmit in getEmits:
        eachString = (eachEmit + '.emitterType')
        mc.setAttr(eachString,2)
  
def emitOnOmni(*args):    
    getEmits = mc.ls(type='pointEmitter')  
    
    for eachEmit in getEmits:
        eachString = (eachEmit + '.emitterType')
        mc.setAttr(eachString,1)
        
###Set_Particle_Attributes###
  
def setPartAttr(*args):
    conserveAttrs = mc.floatFieldGrp(conserveAttr, query = True , value1 = True)
    goalWAttrs = mc.floatFieldGrp( goalWAttr, query = True , value1 = True)
    collisionAttrs = mc.intFieldGrp( collisionAttr, query = True ,value1 = True)
    particleRadiuss = mc.floatFieldGrp( particleRadius, query = True , value1 =True)
    
    getPart = mc.ls(type = 'nParticle')
    for eachPart in getPart:
        mc.setAttr(eachPart + ".conserve" , conserveAttrs)
        mc.setAttr(eachPart + ".goalWeight[0]" , goalWAttrs)
        mc.setAttr(eachPart + ".selfCollide" , collisionAttrs)
        mc.setAttr(eachPart + ".radius" , particleRadiuss)
    
  
###Set_VolumeAxisField_Attributes####
  
def setVolFieldAttr(*args):
    tFreqs = []
    magnitudes = mc.floatFieldGrp(magnitude, query = True ,  value1 = True)
    dSpeeds = mc.floatFieldGrp(dSpeed, query = True , value1 = True)
    tbss = mc.floatFieldGrp(tbs, query = True , value1 = True)
    tFreqs = mc.floatFieldGrp( tFreq, query = True , value = True)
    
    getVolField = mc.ls(type='volumeAxisField')
    for eachVol in getVolField:
        mc.setAttr (eachVol + ".magnitude" , magnitudes)
        mc.setAttr (eachVol + ".directionalSpeed" , dSpeeds)
        mc.setAttr (eachVol + ".turbulence" , tbss)
        mc.setAttr (eachVol + ".turbulenceFrequencyX" , tFreqs[0])
        mc.setAttr (eachVol + ".turbulenceFrequencyY" , tFreqs[1])
        mc.setAttr (eachVol + ".turbulenceFrequencyZ" , tFreqs[2])
def stop(*args):
    mc.play(state = False)
def play(*args):
    mc.playbackOptions( loop='continuous' )
    mc.playbackOptions( minTime='0sec', maxTime='10sec' )
    mc.play(forward = True)
  
#####----UI Window----#####
#####----avoid duplicate window
  
windowG = 'WireGenerationTool'
 
if (mc.window(windowG, query=True, ex=True)):
    mc.deleteUI(windowG)
  
windowG = mc.window('WireGenerationTool', title='WireGenerationTool', iconName='WGT', widthHeight=(400,400), rtf=True )
mc.columnLayout( adjustableColumn=True )
  
mc.text( label= 'STEP 1 : Please DRAW THE CURVE FIRST ')
mc.text( label= '=============================================================')
etFrm = mc.intFieldGrp(label='VolumeAxisFields copies',value1=50)
  
pLastFrm = mc.intFieldGrp(label ='nParticle Cache Frames', value1=20)
  
mc.button( label= 'Generate Fields', actOnPress=True, command=lambda x: volToCurve( 1, etFrm))
  
mc.button( label= 'Make Emitter Cubes', actOnPress=True, command=emitCubeToCurve)
#maxCOunt#
pmaxCount = mc.intFieldGrp(label ='Each nParticle Max Count', value1=50, changeCommand = setPartMaxCount)
  
mc.text( label = '============================================================')
#Defininf Emitters Attributes
mc.button( label= 'Set General Attr in Emitters', actOnPress=True, recomputeSize = True, command=selectEmits)
mc.checkBox( label='omni', align = 'left', editable = True, onCommand =  emitOnOmni)
mc.checkBox( label='surface', align='left', editable = True, onCommand = emitOnSurf)
  
  
  
#Define Particle Attributes#    
mc.button( label= 'Set General Attr in nParticles', actOnPress=True, recomputeSize = True, command=selectnParticles)
conserveAttr = mc.floatFieldGrp(  label = 'Conserve', value1 = 0.3, changeCommand = setPartAttr)
goalWAttr = mc.floatFieldGrp( label = 'GoalWeight', value1 = 0.5,  changeCommand = setPartAttr)
collisionAttr = mc.intFieldGrp(  label = 'collision between', value1= 1,  changeCommand = setPartAttr)
particleRadius = mc.floatFieldGrp( label = 'Particle Radius', value1 = 0.1,  changeCommand = setPartAttr)
  
  
  
#Define VolumeAxisField Attributes#    
mc.button( label= 'Set General Attr in VolumeFields', actOnPress=True, recomputeSize = True, command=SelVolF)
magnitude = mc.floatFieldGrp(label = 'Magnitude', value1 = 1,  changeCommand = setVolFieldAttr )
dSpeed = mc.floatFieldGrp(label = 'DirectionSpeed', value1 = 10,  changeCommand = setVolFieldAttr)
tbs = mc.floatFieldGrp(label = 'Terbulence', value1 = 0,  changeCommand = setVolFieldAttr)
tFreq = mc.floatFieldGrp( numberOfFields=3, label= 'TerbulenceFreq',  value1 = 0, value2 = 0, value3 = 0)
  
  
  
mc.text( label = '============================================================')
mc.text( label = 'For object collision select desired objects and use collider tab in nDynamics')
mc.text( label = '============================================================')
mc.text( label = 'If more than one Goal, goal weight will be average out between them.')
mc.text( label = '============================================================')
mc.text( label = 'Please Select Desired Goal Objects')
mc.button( label= 'Set Goals', actOnPress=True, command=goalDef)
mc.button(label = 'Test', actOnPress = True, command = play)
mc.button(label = 'StopTest', actOnPress = True, command = stop)
mc.text( label = '============================================================')
mc.button( label= 'Create Curves From nParticles', actOnPress=True, command=lambda x:gWire(pLastFrm))
mc.button( label= 'Extrude Surface', actOnPress=True, command=extrude)
mc.button( label= 'Objects To Wire Tips', actOnPress=True, command = plugToWire)
mc.showWindow( windowG )