#!/usr/bin/env python # -*- coding: utf-8 -*- import maya.cmds as cmds # type: ignore import maya.mel as mel # type: ignore import math # set currentArcCurve and storeEdge as global variables global currentArcCurve global storeEdge currentArcCurve = "" storeEdge = [] def run(): if cmds.window("arcDeformerUI", exists = True): cmds.deleteUI("arcDeformerUI") arcDeformerUI = cmds.window("arcDeformerUI",title = "Arc Deformer", w=320) cmds.frameLayout(labelVisible= False) cmds.rowColumnLayout(nc=4 ,cw=[(1,5),(2,60),(3,20),(4,180)]) cmds.text(l ='') cmds.text(l ='Curve Type') cmds.text(l ='') cmds.radioButtonGrp('curveType', nrb=2, sl=1, labelArray2=['Bezier', 'Nurbs'], cw = [(1,100),(2,100)],cc=lambda x: controlNumberSwitch()) cmds.setParent( '..' ) cmds.rowColumnLayout(nc=10 ,cw=[(1,10),(2,60),(3,20),(4,50),(5,10),(6,50),(7,10),(8,50),(9,10),(10,95)]) cmds.text(l ='') cmds.text(l ='Options') cmds.text(l ='') cmds.checkBox('makeArc', label= "Arc" ,v = 1, cc= lambda x: makeArcSwitch()) cmds.text(l ='') cmds.checkBox('snapCurve', label= "Snap" ,v = 1, cc= lambda x: disableEvenSpaceCheckBox()) cmds.text(l ='') cmds.checkBox('evenSpace', label= "Even" ,v = 1) cmds.text(l ='') cmds.checkBox('cleanCurve', label= "Keep Curve" ,v = 1) cmds.setParent( '..' ) cmds.intSliderGrp('CPSlider', cw3=[80, 30, 180], label = 'Control Point ', field= 1, min= 2, max= 10, fmx = 500, v = 3 ) cmds.floatSliderGrp('dropOffSlider' , label = 'DropOff', v = 0.01, cw3=[80, 30, 180], field=1 ,pre = 2, min= 0.01, max= 10) cmds.rowColumnLayout(nc=4 ,cw=[(1,120),(2,80),(3,10),(4,80)]) cmds.text(l ='') cmds.button( l= 'Run', c = lambda x: arcEdgeLoop()) cmds.text(l ='') cmds.button( l= 'Done', c = lambda x: arcDone()) cmds.text(l ='') cmds.setParent( '..' ) cmds.showWindow(arcDeformerUI) def arcDone(): global storeEdge global currentArcCurve if cmds.objExists('arcCurve*'): arcCurveList = cmds.ls( "arcCurve*", transforms =1 ) a = arcCurveList[0] for a in arcCurveList: if 'BaseWire' not in a: shapeNode = cmds.listRelatives(a, fullPath=True ) hist = cmds.listConnections(cmds.listConnections(shapeNode[0],sh=1, d=1 ) ,d=1 ,sh=1) cmds.delete(hist,ch=1) cmds.delete('arcCurve*') if len(currentArcCurve)>0: if cmds.objExists(currentArcCurve): shapeNode = cmds.listRelatives(currentArcCurve, fullPath=True ) hist = cmds.listConnections(cmds.listConnections(shapeNode[0],sh=1, d=1 ) ,d=1 ,sh=1) cmds.delete(hist,ch=1) if cmds.objExists(currentArcCurve): cmds.select(currentArcCurve) cmds.select(storeEdge,add=1) if cmds.objExists(currentArcCurve + 'BaseWire'): cmds.delete(currentArcCurve + 'BaseWire') def arcEdgeLoop(): global storeEdge global currentArcCurve currentDropOff = cmds.floatSliderGrp('dropOffSlider' ,q=1,v=1) snapCheck = cmds.checkBox('snapCurve',q = 1 ,v = 1) goEven = cmds.checkBox('evenSpace', q=1 ,v = 1) conP = cmds.intSliderGrp('CPSlider',q=1 , v = True ) curveT = cmds.radioButtonGrp('curveType', q=1, sl=1) goArc = cmds.checkBox('makeArc', q=1 ,v = 1) cClean = cmds.checkBox('cleanCurve', q=1 ,v = 1) selEdge = cmds.filterExpand(expand=True ,sm=32) selCurve = cmds.filterExpand(expand=True ,sm=9) if selCurve: if len(selEdge)>0 and len(selCurve)== 1: storeEdge = selEdge cmds.select(selCurve,d=1) selMeshForDeformer = cmds.ls(sl=1,o=1) getCircleState,listVtx = vtxLoopOrderCheck() newCurve = cmds.duplicate(selCurve[0], rr=1) cmds.rename(newCurve[0],'newsnapCurve') currentArcCurve = 'newsnapCurve' cmds.rebuildCurve(currentArcCurve,ch=1, rpo=1, rt=0, end=1, kr=0, kcp=0, kep=1, kt=0, s = 100, d=1, tol=0.01) #check tip order curveTip = cmds.pointOnCurve(currentArcCurve , pr = 0, p=1) tipA = cmds.pointPosition(listVtx[0],w=1) tipB = cmds.pointPosition(listVtx[-1],w=1) distA = math.sqrt( ((tipA[0] - curveTip[0])**2) + ((tipA[1] - curveTip[1])**2) + ((tipA[2] - curveTip[2])**2) ) distB = math.sqrt( ((tipB[0] - curveTip[0])**2) + ((tipB[1] - curveTip[1])**2) + ((tipB[2] - curveTip[2])**2) ) if distA > distB: listVtx.reverse() #snap to curve if goEven == 1: for q in range(len(selEdge)+1): if q == 0: pp = cmds.pointOnCurve(currentArcCurve , pr = 0, p=1) cmds.move( pp[0], pp[1], pp[2],listVtx[q] , a =True, ws=True) else: pp = cmds.pointOnCurve(currentArcCurve , pr = (1.0/len(selEdge)*q), p=1) cmds.move( pp[0], pp[1], pp[2],listVtx[q] , a =True, ws=True) else: sum = 0 totalEdgeLoopLength = 0 Llist = [] uList = [] pList = [] for i in range(len(listVtx)-1): pA = cmds.pointPosition(listVtx[i], w =1) pB = cmds.pointPosition(listVtx[i+1], w =1) checkDistance = math.sqrt( ((pA[0] - pB[0])**2) + ((pA[1] - pB[1])**2) + ((pA[2] - pB[2])**2) ) Llist.append(checkDistance) totalEdgeLoopLength = totalEdgeLoopLength + checkDistance for j in Llist: sum = sum + j uList.append(sum) for k in uList: p = k / totalEdgeLoopLength pList.append(p) for q in range(len(selEdge)+1): if q == 0: pp = cmds.pointOnCurve(currentArcCurve , pr = 0, p=1) cmds.move( pp[0], pp[1], pp[2],listVtx[q] , a =True, ws=True) else: pp = cmds.pointOnCurve(currentArcCurve , pr = pList[q-1], p=1) cmds.move( pp[0], pp[1], pp[2],listVtx[q] , a =True, ws=True) cmds.delete('newsnapCurve') deformerNames = cmds.wire(selMeshForDeformer, gw=0, en = 1, ce = 0, li= 0, dds = [(0,1)], dt=1, w = selCurve[0]) cmds.connectControl("dropOffSlider", (deformerNames[0]+".dropoffDistance[0]")) if snapCheck == 0: cmds.setAttr((deformerNames[0] + '.dropoffDistance[0]'),1) else: cmds.setAttr((deformerNames[0] + '.dropoffDistance[0]'),currentDropOff) currentArcCurve = selCurve[0] cmds.select(selCurve[0]) else: if selEdge: storeEdge = selEdge if cClean == 0: if cmds.objExists('arcCurve*'): arcDone() selMeshForDeformer = cmds.ls(sl=1,o=1) getCircleState,listVtx = vtxLoopOrderCheck() deformerNames = [] #make nurbs curve if getCircleState == 0: #Arc if goArc == 1: midP = int(len(listVtx)/2) cmds.move(0.01, 0, 0,selEdge[midP],r=1, cs=1 ,ls=1, wd =1) p1 = cmds.pointPosition(listVtx[0], w =1) p2 = cmds.pointPosition(listVtx[midP], w =1) p3 = cmds.pointPosition(listVtx[-1], w =1) newNode = cmds.createNode('makeThreePointCircularArc') cmds.setAttr((newNode + '.pt1'), p1[0], p1[1] , p1[2]) cmds.setAttr((newNode + '.pt2'), p2[0], p2[1] , p2[2]) cmds.setAttr((newNode + '.pt3'), p3[0], p3[1] , p3[2]) cmds.setAttr((newNode + '.d'), 3) cmds.setAttr((newNode + '.s'), len(listVtx)) newCurve = cmds.createNode('nurbsCurve') cmds.connectAttr((newNode+'.oc'), (newCurve+'.cr')) cmds.delete(ch=1) transformNode = cmds.listRelatives(newCurve, fullPath=True , parent=True ) cmds.select(transformNode) cmds.rename(transformNode,'arcCurve0') getNewNode = cmds.ls(sl=1) currentArcCurve = getNewNode[0] numberP = 0 if curveT == 2:#nubs curve numberP = int(conP) - 3 if numberP < 1: numberP = 1 else: numberP = int(conP) -1 cmds.rebuildCurve(currentArcCurve,ch=1, rpo=1, rt=0, end=1, kr=0, kcp=0, kep=1, kt=0, s= numberP, d=3, tol=0.01) else: p1 = cmds.pointPosition(listVtx[0], w =1) cmds.curve(d= 1, p=p1) cmds.rename('arcCurve0') getNewNode = cmds.ls(sl=1) currentArcCurve = getNewNode[0] for l in range(1,len(listVtx)): p2 = cmds.pointPosition(listVtx[l], w =1) cmds.curve(currentArcCurve, a= 1, d= 1, p=p2) numberP = int(conP) -1 cmds.rebuildCurve(currentArcCurve,ch=1, rpo=1, rt=0, end=1, kr=0, kcp=0, kep=1, kt=0, s= numberP, d=1, tol=0.01) else: #circle p1 = cmds.pointPosition(listVtx[0], w =1) cmds.curve(d= 1, p=p1) cmds.rename('arcCurve0') getNewNode = cmds.ls(sl=1) currentArcCurve = getNewNode[0] for l in range(1,len(listVtx)): p2 = cmds.pointPosition(listVtx[l], w =1) cmds.curve(currentArcCurve, a= 1, d= 1, p=p2) cmds.curve(currentArcCurve, a= 1, d= 1, p=p1) cmds.closeCurve(currentArcCurve,ch=0, ps=2, rpo=1, bb= 0.5, bki=0, p=0.1) conP = cmds.intSliderGrp('CPSlider',q=1 , v = True ) numberP = int(conP) if numberP < 4: numberP = 4 cmds.intSliderGrp('CPSlider',e=1 , v = 4 ) cmds.rebuildCurve(currentArcCurve,ch=1, rpo=1, rt=0, end=1, kr=0, kcp=0, kep=1, kt=0, s = numberP, d=3, tol=0.01) ########################################################################### cmds.delete(currentArcCurve ,ch=1) totalEdgeLoopLength = 0; sum = 0 Llist = [] uList = [] pList = [] #cmds.select(selEdge) for i in range(len(listVtx)-1): pA = cmds.pointPosition(listVtx[i], w =1) pB = cmds.pointPosition(listVtx[i+1], w =1) checkDistance = math.sqrt( ((pA[0] - pB[0])**2) + ((pA[1] - pB[1])**2) + ((pA[2] - pB[2])**2) ) Llist.append(checkDistance) totalEdgeLoopLength = totalEdgeLoopLength + checkDistance if goEven == 1: avg = totalEdgeLoopLength / (len(selEdge)) for j in range(len(selEdge)): sum = ((j+1)*avg) uList.append(sum) else: for j in Llist: sum = sum + j uList.append(sum) for k in uList: p = k / totalEdgeLoopLength pList.append(p) #snap to curve if snapCheck == 1: for q in range(len(pList)): if q+1 == len(listVtx): pp = cmds.pointOnCurve(currentArcCurve, pr = 0, p=1) cmds.move( pp[0], pp[1], pp[2],listVtx[0] , a =True, ws=True) else: pp = cmds.pointOnCurve(currentArcCurve , pr = pList[q], p=1) cmds.move( pp[0], pp[1], pp[2],listVtx[q+1] , a =True, ws=True) #convert to Bezier Curve cmds.delete(currentArcCurve ,ch=1) cmds.select(currentArcCurve) if curveT == 1: cmds.nurbsCurveToBezier() if getCircleState == 1: #circle need to fix bug cmds.closeCurve(currentArcCurve,ch=0, ps=2, rpo=1, bb= 0.5, bki=0, p=0.1) cmds.closeCurve(currentArcCurve,ch=0, ps=2, rpo=1, bb= 0.5, bki=0, p=0.1) #wireWrap deformerNames = cmds.wire( selMeshForDeformer, gw=0, en = 1, ce = 0, li= 0, dds = [(0,1)], dt=1, w = currentArcCurve) #select controllers if getCircleState == 0: cmds.setToolTo('moveSuperContext') degree = cmds.getAttr(currentArcCurve + '.degree') spans = cmds.getAttr(currentArcCurve + '.spans') numberCVs = degree + spans collect = [] for x in range(int(numberCVs/3)-1): g = currentArcCurve + '.cv[' + str((x+1)*3) + ']' collect.append(g) cmds.select(collect ,r=1) else: cmds.select(currentArcCurve + '.cv[*]') cmd = 'doMenuNURBComponentSelection("' + currentArcCurve + '", "controlVertex");' mel.eval(cmd) cmds.connectControl("dropOffSlider", (deformerNames[0]+".dropoffDistance[0]")) if snapCheck == 0: cmds.setAttr((deformerNames[0] + '.dropoffDistance[0]'),1) else: cmds.setAttr((deformerNames[0] + '.dropoffDistance[0]'),currentDropOff) #add to viewport even in isolate mode for x in range(1,5): cmds.isolateSelect(('modelPanel' + str(x)), ado= currentArcCurve ) def makeArcSwitch():# min point for Nurbs are 4 point goArc = cmds.checkBox('makeArc', q=1 ,v = 1) curveT = cmds.radioButtonGrp('curveType', q=1, sl=1) if goArc == 0: cmds.intSliderGrp('CPSlider', e=1, min= 4, v = 4 , fmx = 500) else: if curveT == 1: cmds.intSliderGrp('CPSlider', e=1, min= 2, v = 3, fmx = 500) else: cmds.intSliderGrp('CPSlider', e=1, min= 4, v = 4, fmx = 500) def disableEvenSpaceCheckBox(): snapCheck = cmds.checkBox('snapCurve',q = 1 ,v = 1) if snapCheck == 0 : cmds.checkBox('evenSpace', e=1 ,en=0) else: cmds.checkBox('evenSpace', e=1 ,en=1) def controlNumberSwitch():# min point for Nurbs are 4 point curveT = cmds.radioButtonGrp('curveType', q=1, sl=1) getCurrentV = cmds.intSliderGrp('CPSlider', q=1 ,v = 1 ) if curveT == 2: cmds.intSliderGrp('CPSlider', e=1, min= 4 ) if getCurrentV < 4: cmds.intSliderGrp('CPSlider', e=1, v= 4 ) else: cmds.intSliderGrp('CPSlider', e=1, min= 2 ) def vtxLoopOrderCheck(): selEdges = cmds.ls(sl=1,fl=1) shapeNode = cmds.listRelatives(selEdges[0], fullPath=True , parent=True ) transformNode = cmds.listRelatives(shapeNode[0], fullPath=True , parent=True ) edgeNumberList = [] for a in selEdges: checkNumber = ((a.split('.')[1]).split('\n')[0]).split(' ') for c in checkNumber: findNumber = ''.join([n for n in c.split('|')[-1] if n.isdigit()]) if findNumber: edgeNumberList.append(findNumber) getNumber = [] for s in selEdges: evlist = cmds.polyInfo(s,ev=True) checkNumber = ((evlist[0].split(':')[1]).split('\n')[0]).split(' ') for c in checkNumber: findNumber = ''.join([n for n in c.split('|')[-1] if n.isdigit()]) if findNumber: getNumber.append(findNumber) dup = set([x for x in getNumber if getNumber.count(x) > 1]) getHeadTail = list(set(getNumber) - dup) checkCircleState = 0 if not getHeadTail: #close curve checkCircleState = 1 getHeadTail.append(getNumber[0]) vftOrder = [] vftOrder.append(getHeadTail[0]) count = 0 while len(dup)> 0 and count < 1000: checkVtx = transformNode[0]+'.vtx['+ vftOrder[-1] + ']' velist = cmds.polyInfo(checkVtx,ve=True) getNumber = [] checkNumber = ((velist[0].split(':')[1]).split('\n')[0]).split(' ') for c in checkNumber: findNumber = ''.join([n for n in c.split('|')[-1] if n.isdigit()]) if findNumber: getNumber.append(findNumber) findNextEdge = [] for g in getNumber: if g in edgeNumberList: findNextEdge = g edgeNumberList.remove(findNextEdge) checkVtx = transformNode[0]+'.e['+ findNextEdge + ']' findVtx = cmds.polyInfo(checkVtx,ev=True) getNumber = [] checkNumber = ((findVtx[0].split(':')[1]).split('\n')[0]).split(' ') for c in checkNumber: findNumber = ''.join([n for n in c.split('|')[-1] if n.isdigit()]) if findNumber: getNumber.append(findNumber) gotNextVtx = [] for g in getNumber: if g in dup: gotNextVtx = g dup.remove(gotNextVtx) vftOrder.append(gotNextVtx) count += 1 if checkCircleState == 0: vftOrder.append(getHeadTail[1]) else:#close curve remove connected vtx if vftOrder[0] == vftOrder[1]: vftOrder = vftOrder[1:] elif vftOrder[0] == vftOrder[-1]: vftOrder = vftOrder[0:-1] finalList = [] for v in vftOrder: finalList.append(transformNode[0]+'.vtx['+ v + ']' ) return checkCircleState, finalList if __name__ == "__main__": run()