Updated
This commit is contained in:
435
Scripts/Modeling/Select/EdgeLoopSmartSelect.py
Normal file
435
Scripts/Modeling/Select/EdgeLoopSmartSelect.py
Normal file
@ -0,0 +1,435 @@
|
||||
#!/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)
|
||||
|
||||
# Check if checkCurrentSelPoly is None or an empty list
|
||||
if not checkCurrentSelPoly:
|
||||
# If no polygon is selected, display a warning and return
|
||||
MGlobal.displayWarning("No polygon object selected.")
|
||||
return
|
||||
|
||||
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()
|
Reference in New Issue
Block a user