#!/usr/bin/env python # -*- coding: utf-8 -*- import maya.cmds as cmds import maya.OpenMaya as om import maya.OpenMayaUI as omui from maya.OpenMaya import MGlobal import math import re import maya.mel as mel def run(): global selInitialGeo global storeAllEdges selInitialGeo = [] storeAllEdges = [] testAnySel = cmds.ls(sl=1) if testAnySel: checkCurrentSelEdge = cmds.filterExpand(sm=32) checkCurrentSelPoly = cmds.filterExpand(sm=12) checkCurrentSelOther =cmds.filterExpand(sm=(31,34,35) ) if checkCurrentSelEdge: checkEdgeLoopGrp = getEdgeRingGroup(checkCurrentSelEdge) if len(checkEdgeLoopGrp) == 1: listAAA = '' try: listAAA = vtxLoopOrder(checkCurrentSelEdge) except: pass if listAAA: storeAllEdges = checkCurrentSelEdge checkCurrentSelPoly = cmds.ls(hl=1) selInitialGeo.append(checkCurrentSelPoly[0]) if not cmds.attributeQuery('start', node = selInitialGeo[0], ex=True ): cmds.addAttr(selInitialGeo[0], at = 'long', ln='start') if not cmds.attributeQuery('end', node = selInitialGeo[0], ex=True ): cmds.addAttr(selInitialGeo[0], at = 'long',ln='end') if not cmds.attributeQuery('nearest', node = selInitialGeo[0], ex=True ): cmds.addAttr(selInitialGeo[0], at = 'long',ln='nearest') if not cmds.attributeQuery('closeTo', node = selInitialGeo[0], ex=True ): cmds.addAttr(selInitialGeo[0], at = 'long',ln='closeTo') if not cmds.attributeQuery('firstRun', node = selInitialGeo[0], ex=True ): cmds.addAttr(selInitialGeo[0], at = 'long',ln='firstRun') cmds.setAttr((selInitialGeo[0]+'.firstRun'),0) selShortestLoop() else: cmds.select(checkCurrentSelEdge) else: cmds.select(checkCurrentSelEdge) else: if checkCurrentSelOther: checkCurrentSelPoly = cmds.ls(hl=1) selInitialGeo.append(checkCurrentSelPoly[0]) CMD = 'doMenuComponentSelectionExt("' + str(checkCurrentSelPoly[0])+ '", "edge", 0);' mel.eval(CMD) cmds.select(cl=1) cmds.polyCrease((checkCurrentSelPoly[0]+'.e[*]'), value=0) if not cmds.attributeQuery('start', node = selInitialGeo[0], ex=True ): cmds.addAttr(selInitialGeo[0], at = 'long', ln='start') if not cmds.attributeQuery('end', node = selInitialGeo[0], ex=True ): cmds.addAttr(selInitialGeo[0], at = 'long',ln='end') if not cmds.attributeQuery('nearest', node = selInitialGeo[0], ex=True ): cmds.addAttr(selInitialGeo[0], at = 'long',ln='nearest') if not cmds.attributeQuery('closeTo', node = selInitialGeo[0], ex=True ): cmds.addAttr(selInitialGeo[0], at = 'long',ln='closeTo') if not cmds.attributeQuery('firstRun', node = selInitialGeo[0], ex=True ): cmds.addAttr(selInitialGeo[0], at = 'long',ln='firstRun') cmds.setAttr((selInitialGeo[0]+'.firstRun'),0) cmds.scriptJob ( runOnce=True, event = ["SelectionChanged", selShortestLoop]) else: print('no selection') def selShortestLoop(): global ctx global storeAllEdges global selInitialGeo global storeCameraPosition global initialList initialList = [] storeAllEdges = cmds.ls(sl=1,fl=1) listVtx = vtxLoopOrder(storeAllEdges) initialList = listVtx startID = listVtx[0].split('[')[-1].split(']')[0] endID = listVtx[-1].split('[')[-1].split(']')[0] cmds.setAttr((selInitialGeo[0]+'.start'),int(startID)) cmds.setAttr((selInitialGeo[0]+'.end'),int(endID)) view = omui.M3dView.active3dView() cam = om.MDagPath() view.getCamera(cam) camPath = cam.fullPathName() cameraTrans = cmds.listRelatives(camPath,type='transform',p=True) storeCameraPosition = cmds.xform(cameraTrans,q=1,ws=1,rp=1) if cmds.objExists('preSelDisp')==0: cmds.createNode("creaseSet") cmds.rename("preSelDisp") cmds.sets((selInitialGeo[0]+".e[*]"),remove="preSelDisp") cmds.sets(storeAllEdges,forceElement="preSelDisp") cmds.setAttr("preSelDisp.creaseLevel", 1) cmds.polyOptions(dce=1) ctx = 'Click2dTo3dCtx' if cmds.draggerContext(ctx, exists=True): cmds.deleteUI(ctx) cmds.draggerContext(ctx, ppc= liveShortPause ,rc = liveShortPause, dragCommand = liveShortMove, fnz = liveShortStop ,name=ctx, cursor='crossHair',undoMode='step') cmds.setToolTo(ctx) def liveShortMove(): global selInitialGeo global ctx global screenX,screenY global storeCameraPosition global storeAllEdges modifiers = cmds.getModifiers() if selInitialGeo: vpX, vpY, _ = cmds.draggerContext(ctx, query=True, dragPoint=True) pos = om.MPoint() dir = om.MVector() hitpoint = om.MFloatPoint() omui.M3dView().active3dView().viewToWorld(int(vpX), int(vpY), pos, dir) pos2 = om.MFloatPoint(pos.x, pos.y, pos.z) checkHit = 0 finalMesh = [] finalX = 0 finalY = 0 finalZ = 0 shortDistance = 10000000000 distanceBetween = 1000000000 hitFacePtr = om.MScriptUtil().asIntPtr() hitFace = [] for mesh in selInitialGeo: selectionList = om.MSelectionList() selectionList.add(mesh) dagPath = om.MDagPath() selectionList.getDagPath(0, dagPath) fnMesh = om.MFnMesh(dagPath) intersection = fnMesh.closestIntersection( om.MFloatPoint(pos2), om.MFloatVector(dir), None, None, False, om.MSpace.kWorld, 99999, False, None, hitpoint, None, hitFacePtr, None, None, None) if intersection: x = hitpoint.x y = hitpoint.y z = hitpoint.z finalX = x finalY = y finalZ = z hitFace = om.MScriptUtil(hitFacePtr).asInt() hitFaceName = (selInitialGeo[0] + '.f[' + str(hitFace) +']') cpX,cpY,cpZ = getPolyFaceCenter(hitFaceName) shortDistanceCheck = 10000 checkCVDistance = 10000 cvList = (cmds.polyInfo(hitFaceName , fv=True )[0]).split(':')[-1].split(' ') cvListX = [x for x in cvList if x.strip()] for v in cvListX: checkNumber = ''.join([n for n in v.split('|')[-1] if n.isdigit()]) if len(checkNumber) > 0: cvPoint = (selInitialGeo[0] + '.vtx[' + str(checkNumber) +']') cvPosition = cmds.pointPosition(cvPoint) checkCVDistance = math.sqrt( ((float(cvPosition[0]) - finalX)**2) + ((float(cvPosition[1]) - finalY)**2) + ((float(cvPosition[2]) - finalZ)**2)) if checkCVDistance < shortDistanceCheck: shortDistanceCheck = checkCVDistance mostCloseCVPoint = cvPoint mostCloseCVPointPos = cvPosition newID = mostCloseCVPoint.split('[')[-1].split(']')[0] cmds.setAttr((selInitialGeo[0]+'.nearest'),int(newID)) checkRun = cmds.getAttr(selInitialGeo[0]+'.firstRun') if checkRun == 1: checkCloseTo = cmds.getAttr(selInitialGeo[0]+'.nearest') checkStart = cmds.getAttr(selInitialGeo[0]+'.start') checkEnd = cmds.getAttr(selInitialGeo[0]+'.end') startPosition = cmds.pointPosition( (selInitialGeo[0] + '.vtx[' + str(checkStart) +']')) endPosition = cmds.pointPosition( (selInitialGeo[0] + '.vtx[' + str(checkEnd) +']')) nearPosition = cmds.pointPosition( (selInitialGeo[0] + '.vtx[' + str(checkCloseTo) +']')) distA = math.sqrt( ((float(nearPosition[0]) - startPosition[0])**2) + ((float(nearPosition[1]) - startPosition[1])**2) + ((float(nearPosition[2]) - startPosition[2])**2)) distB = math.sqrt( ((float(nearPosition[0]) - endPosition[0])**2) + ((float(nearPosition[1]) - endPosition[1])**2) + ((float(nearPosition[2]) - endPosition[2])**2)) if distA > distB: cmds.setAttr((selInitialGeo[0]+'.end'),checkEnd) cmds.setAttr((selInitialGeo[0]+'.start'),checkStart) else: cmds.setAttr((selInitialGeo[0]+'.end'),checkStart) cmds.setAttr((selInitialGeo[0]+'.start'),checkEnd) checkStart = cmds.getAttr(selInitialGeo[0]+'.start') checkEnd = cmds.getAttr(selInitialGeo[0]+'.end') checkNearest = cmds.getAttr(selInitialGeo[0]+'.nearest') #get shortest cmds.select(cl=1) cmds.sets((selInitialGeo[0]+".e[*]"),remove="preSelDisp") sortList = [] if modifiers == 4: # "press Ctrl" PA = (selInitialGeo[0] + '.vtx[' + str(checkEnd) +']') PB = (selInitialGeo[0] + '.vtx[' + str(checkNearest) +']') UVA = cmds.polyListComponentConversion(PA,fv =1 ,tuv=1) UVB = cmds.polyListComponentConversion(PB,fv =1 ,tuv=1) startUVID = UVA[0].split('[')[-1].split(']')[0] endUVID = UVB[0].split('[')[-1].split(']')[0] #cmds.polySelect(selInitialGeo[0] , shortestEdgePathUV=(int(startUVID), int(endUVID))) listShort = cmds.polySelect(selInitialGeo[0] ,q=1, shortestEdgePathUV=(int(startUVID), int(endUVID))) if listShort: for l in listShort: sortList.append(selInitialGeo[0]+'.e['+ str(l) +']' ) else: #cmds.polySelect(selInitialGeo[0] , shortestEdgePath=(int(checkEnd), int(checkNearest))) #maya run faster without select listShort = cmds.polySelect(selInitialGeo[0] ,q=1, shortestEdgePath=(int(checkEnd), int(checkNearest))) if listShort: for l in listShort: sortList.append(selInitialGeo[0]+'.e['+ str(l) +']' ) getC = storeAllEdges + sortList cmds.select(getC) cmds.sets(getC,forceElement="preSelDisp") if modifiers == 1: # "press Shelf" liveList = cmds.sets("preSelDisp",q=1) liveList = cmds.ls(liveList,fl=1) listVtx = vtxLoopOrder(liveList) checkEndID = listVtx[-1].split('[')[-1].split(']')[0] extEdgeA = [] extEdgeB = [] if int(checkEndID) == checkNearest: extEdgeA = cmds.polyListComponentConversion(listVtx[-1],fv =1 ,te=1) extEdgeB = cmds.polyListComponentConversion(listVtx[-2],fv =1 ,te=1) else: extEdgeA = cmds.polyListComponentConversion(listVtx[0],fv =1 ,te=1) extEdgeB = cmds.polyListComponentConversion(listVtx[1],fv =1 ,te=1) extEdgeA = cmds.ls(extEdgeA,fl=1) extEdgeB = cmds.ls(extEdgeB,fl=1) extEdge = list(set(extEdgeA) - (set(extEdgeA)-set(extEdgeB))) checkExtLoop = cmds.polySelectSp(extEdge,q=1, loop=1) checkExtLoop = cmds.ls(checkExtLoop,fl=1) otherList = list(set(checkExtLoop) - set(liveList)) checkEdgeLoopGrp = getEdgeRingGroup(otherList) if checkEdgeLoopGrp: if len(checkEdgeLoopGrp) > 0: if len(checkEdgeLoopGrp) == 1: cmds.sets(otherList,forceElement="preSelDisp") elif len(checkEdgeLoopGrp)> 1: for c in checkEdgeLoopGrp: cvList = cmds.polyListComponentConversion (c,fe=1,tv=1) cvList = cmds.ls(cvList,fl=1) if (selInitialGeo[0]+'.vtx['+ str(checkNearest) +']' ) in cvList: cmds.sets(c,forceElement="preSelDisp") cmds.select("preSelDisp", add=1) cmds.refresh(cv=True,f=True) def liveShortPause(): global storeAllEdges global selInitialGeo global initialList checkRun = cmds.getAttr(selInitialGeo[0]+'.firstRun') if checkRun == 0: cmds.setAttr((selInitialGeo[0]+'.firstRun'),1) else: cmds.setAttr((selInitialGeo[0]+'.firstRun'),2) getEdgeList = cmds.ls(sl=1,fl=1) storeAllEdges = getEdgeList listVtx = vtxLoopOrder(getEdgeList) if len(listVtx)>0: listHead = listVtx[0] listEnd = listVtx[-1] if listHead in initialList: cmds.setAttr((selInitialGeo[0]+'.start'),int(listVtx[0].split('[')[-1].split(']')[0])) cmds.setAttr((selInitialGeo[0]+'.end'),int(listVtx[-1].split('[')[-1].split(']')[0])) else: cmds.setAttr((selInitialGeo[0]+'.start'),int(listVtx[-1].split('[')[-1].split(']')[0])) cmds.setAttr((selInitialGeo[0]+'.end'),int(listVtx[0].split('[')[-1].split(']')[0])) else: liveShortStop() def liveShortStop(): cmds.setToolTo("moveSuperContext") cmds.polyOptions(dce=0) if cmds.objExists('preSelDisp'): cmds.setAttr("preSelDisp.creaseLevel", 0) cmds.delete('preSelDisp') def getPolyFaceCenter(faceName): meshFaceName = faceName.split('.')[0] findVtx = cmds.polyInfo(faceName, fv=1) 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) centerX = 0 centerY = 0 centerZ = 0 for g in getNumber: x,y,z = cmds.pointPosition((meshFaceName + '.vtx['+g + ']'),w=1) centerX = centerX + x centerY = centerY + y centerZ = centerZ + z centerX = centerX/len(getNumber) centerY = centerY/len(getNumber) centerZ = centerZ/len(getNumber) return centerX,centerY,centerZ def vtxLoopOrder(edgelist): if edgelist: selEdges = edgelist 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) vftOrder = [] finalList = [] if len(getHeadTail)>0: vftOrder.append(getHeadTail[0]) count = 0 while len(dup)> 0 and count < 100: 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 if len(gotNextVtx)> 0: dup.remove(gotNextVtx) vftOrder.append(gotNextVtx) count += 1 if len(getHeadTail)>1: vftOrder.append(getHeadTail[1]) for v in vftOrder: finalList.append(transformNode[0]+'.vtx['+ v + ']' ) return finalList def getEdgeRingGroup(selEdges): if selEdges: trans = selEdges[0].split(".")[0] e2vInfos = cmds.polyInfo(selEdges, ev=True) e2vDict = {} fEdges = [] for info in e2vInfos: evList = [ int(i) for i in re.findall('\\d+', info) ] e2vDict.update(dict([(evList[0], evList[1:])])) while True: try: startEdge, startVtxs = e2vDict.popitem() except: break edgesGrp = [startEdge] num = 0 for vtx in startVtxs: curVtx = vtx while True: nextEdges = [] for k in e2vDict: if curVtx in e2vDict[k]: nextEdges.append(k) if nextEdges: if len(nextEdges) == 1: if num == 0: edgesGrp.append(nextEdges[0]) else: edgesGrp.insert(0, nextEdges[0]) nextVtxs = e2vDict[nextEdges[0]] curVtx = [ vtx for vtx in nextVtxs if vtx != curVtx ][0] e2vDict.pop(nextEdges[0]) else: break else: break num += 1 fEdges.append(edgesGrp) retEdges =[] for f in fEdges: collectList=[] for x in f: getCom= (trans +".e["+ str(x) +"]") collectList.append(getCom) retEdges.append(collectList) return retEdges run()