import os import math from ldmt_function.ldmt_loadUIFile import get_maya_window, load_ui_file import maya.OpenMayaUI as omui from ldmt_core import ldmt_cmds as ld from functools import partial import maya.cmds as cmds import maya.mel as mel try: from Qt.QtCore import * from Qt.QtGui import * from Qt.QtWidgets import * # from Qt.QtUiTools import * from Qt import __version__ from Qt.QtCompat import loadUi, wrapInstance except ImportError: from Qt.QtCore import * from Qt.QtGui import * # from Qt.QtUiTools import * from Qt import __version__ from Qt.QtCompat import wrapInstance import maya.OpenMaya as om import maya.api.OpenMaya as om2 import random import ast LDMTPATH = ld.getPath('LDMT') ldmt_uifile = LDMTPATH + '/ldmt_ui/ldmt_checkUVBleed.ui' ldmt_window_name = 'ldmt_checkUVBleed' ldmt_button_name = 'btn_'+ldmt_window_name.split('_')[1] ''' Function ''' def changeSelectionType(sel,selType): #selType vertex face edge puv mel.eval('if( !`exists doMenuComponentSelection` ) eval( "source dagMenuProc" );') mel.eval('doMenuComponentSelection("'+sel+'","'+selType+'")' ) def getUVEdgeDic(sel): selList = om2.MSelectionList() selList.add(sel) selPath = selList.getDagPath(0) selMesh = om2.MFnMesh(selPath) selVtxIter = om2.MItMeshVertex(selPath) selEdgeIter = om2.MItMeshEdge(selPath) selFaceIter = om2.MItMeshPolygon(selPath) uvid_uv = [] # generate {uvid:[u,v],} from MFnMesh.getUVs() vtxid_uvid = [] edgeid_vtxid = [] edgeid_uvid = [] #edgeid_vtxid + vtxid_uvid faceid_edgeid = [] faceid_uvid = [] edgeid_faceid = [] #faceid_edgeid reverse uvedgeid_uvid = [] # get { uvedgeid: [uvid1, uvid2]} On border uvid_usi = selMesh.getUvShellsIds() # [usi1,usi2,...] uvid_usi = uvid_usi[1] uvArray = selMesh.getUVs() for i in range(len(uvArray[0])): uvid_uv.append([uvArray[0][i],uvArray[1][i]]) while not selVtxIter.isDone(): #get {[[uvid1,uvid2],...]} vtxid_uvid.append(list(set(selVtxIter.getUVIndices()))) selVtxIter.next() while not selEdgeIter.isDone(): #get edge to vtx edgeid_vtxid.append([selEdgeIter.vertexId(0),selEdgeIter.vertexId(1)]) edgeid_faceid.append(selEdgeIter.getConnectedFaces()) selEdgeIter.next() for edgeid in range(len(edgeid_vtxid)): # get {[[uvid1,uvid2,uvid3],...]} vtx0 = edgeid_vtxid[edgeid][0] vtx1 = edgeid_vtxid[edgeid][1] edgeid_uvid.append(vtxid_uvid[vtx0] + vtxid_uvid[vtx1]) while not selFaceIter.isDone(): # get {[[uvid1,uvid2,uvid3,uvid4], ...] } verts = selFaceIter.getVertices() faceid_edgeid.append(selFaceIter.getEdges()) uvids=[] for index in range(len(verts)): uvids.append(selFaceIter.getUVIndex(index)) #necessary for uvedgeid faceid_uvid.append(uvids) selFaceIter.next() for edgeid in range(len(edgeid_faceid)): faceids = edgeid_faceid[edgeid] edgeuvids = set(edgeid_uvid[edgeid]) numface = len(faceids) if numface == 1: #OnBorder uvids = faceid_uvid[faceids[0]] uvedgeid_uvid.append(list(edgeuvids.intersection(uvids))) continue elif numface == 2: uvidsA = faceid_uvid[faceids[0]] uvidsB = faceid_uvid[faceids[1]] intersectUV = list(set(uvidsA).intersection(uvidsB)) intersectUV_len = len(intersectUV) if intersectUV_len<2: if intersectUV_len == 1: for uv in edgeuvids: if uv == intersectUV[0]: continue elif uv in uvidsA or uv in uvidsB: uvedgeid_uvid.append([intersectUV[0],uv]) else: uvedgeid_uvid.append(list(edgeuvids.intersection(uvidsA))) uvedgeid_uvid.append(list(edgeuvids.intersection(uvidsB))) else: print("Cleanup mesh first!!!!") usi_uvid = {} usi_uvidOnBord = {} usi_uvedgeidOnBord = {} usi_bb = {} for uvid in range(len(uvid_usi)): usi = uvid_usi[uvid] if usi in usi_uvid: usi_uvid[usi].append(uvid) else: usi_uvid[usi] = [uvid] for uvedgeid in range(len(uvedgeid_uvid)): usi = uvid_usi[uvedgeid_uvid[uvedgeid][0]] if usi in usi_uvedgeidOnBord: usi_uvedgeidOnBord[usi].append(uvedgeid) else: usi_uvedgeidOnBord[usi] = [uvedgeid] for usi in usi_uvedgeidOnBord: edgeids = usi_uvedgeidOnBord[usi] uvsOnBord = [] for edgeid in edgeids: uvsOnBord = uvsOnBord + uvedgeid_uvid[edgeid] usi_uvidOnBord[usi] = list(set(uvsOnBord)) for usi in usi_uvidOnBord: umin = 1 umax = 0 vmin = 1 vmax = 0 for uvid in usi_uvidOnBord[usi]: u = uvid_uv[uvid][0] v = uvid_uv[uvid][1] if u < umin: umin = u if u > umax: umax = u if v < vmin: vmin = v if v > vmax: vmax = v usi_bb[usi] = [[umin,umax],[vmin,vmax]] usi_bbarea = {} for i in range(len(usi_uvid)): #get {usi:area,} from usi_bb usi_bbarea[i] = abs(usi_bb[i][0][1]-usi_bb[i][0][0])*abs(usi_bb[i][1][1]-usi_bb[i][1][0]) bbarea_usi = sorted(zip(usi_bbarea.values(), usi_bbarea.keys())) # get [(minarea, usi0),...,( maxarea, usi99)] bbarea_usi.reverse() uvedgeid_uv = [] for uvedgeid in range(len(uvedgeid_uvid)): uvidA = uvedgeid_uvid[uvedgeid][0] uvidB = uvedgeid_uvid[uvedgeid][1] uA = uvid_uv[uvidA][0] vA = uvid_uv[uvidA][1] uB = uvid_uv[uvidB][0] vB = uvid_uv[uvidB][1] if vB >= vA: uvedgeid_uv.append([[uA,vA],[uB,vB]]) else: uvedgeid_uv.append([[uB,vB],[uA,vA]]) return usi_uvid, uvid_uv, uvedgeid_uvid, usi_uvidOnBord, usi_uvedgeidOnBord, usi_bb, bbarea_usi, uvedgeid_uv def LD_CheckUVBleed(uvScale,pixelDistance,borderDistance): uvDistance = float(pixelDistance)/uvScale borderDistance = float(borderDistance)/uvScale TOLERANCE = 4 p = 10**TOLERANCE sel = cmds.ls(sl=1,o=1) sel = sel[0] faceWithNoUV = getFacesHaveNoUV(sel) if faceWithNoUV !=[]: cmds.select(faceWithNoUV,r=1) cmds.warning("Some Faces Have no UVs!") return uvDic = getUVEdgeDic(sel) #uvDic[6] usi_uvid = uvDic[0] uvid_uv = uvDic[1] uvedgeid_uvid = uvDic[2] usi_uvidOnBord = uvDic[3] usi_uvedgeidOnBord = uvDic[4] usi_bb = uvDic[5] bbarea_usi = uvDic[6] uvedgeid_uv = uvDic[7] uvNotPass = set() # len(uvNotPass) Filter out stacking uvs skipList = set() skipListTemp = set() intersectList = {} usi_uvidOnBord_final = {} usi_uvedgeidOnBord_final = {} # prepare for tupleA in range(len(bbarea_usi)): usiA = bbarea_usi[tupleA][1] skipListTemp.add(usiA) # fast detect bb_uminA = usi_bb[usiA][0][0] bb_umaxA = usi_bb[usiA][0][1] bb_vminA = usi_bb[usiA][1][0] bb_vmaxA = usi_bb[usiA][1][1] for tupleB in range(len(bbarea_usi)): usiB = bbarea_usi[tupleB][1] #faset detect bb_uminB = usi_bb[usiB][0][0] bb_umaxB = usi_bb[usiB][0][1] bb_vminB = usi_bb[usiB][1][0] bb_vmaxB = usi_bb[usiB][1][1] if bb_uminA - uvDistance > bb_umaxB or\ bb_umaxA + uvDistance < bb_uminB or\ bb_vminA - uvDistance > bb_vmaxB or\ bb_vmaxA + uvDistance < bb_vminB : continue if usiB in skipListTemp: continue if ifUVShellStack(usiA,usiB,usi_bb, p): skipList.add(usiB) skipListTemp.add(usiB) elif ifUVShellIntersect(usiA,usiB,usi_uvedgeidOnBord, uvedgeid_uv, usi_bb): if usiA in intersectList: intersectList[usiA].append(usiB) else: intersectList[usiA]=[usiB] skipListTemp.add(usiB) skipList.add(usiB) elif ifUVShellContain(usiA,usiB,usi_uvedgeidOnBord,usi_uvidOnBord,uvedgeid_uv,uvid_uv): skipList.add(usiB) skipListTemp.add(usiB) # calculate final list for usiA in usi_uvidOnBord: if usiA in skipList: continue if usiA in intersectList: tempUVidList = [] tempUVedgeidList = [] for usiB in intersectList[usiA]: tempUVidList += usi_uvidOnBord[usiB] tempUVedgeidList += usi_uvedgeidOnBord[usiB] usi_uvidOnBord_final[usiA] = tempUVidList + usi_uvidOnBord[usiA] usi_uvedgeidOnBord_final[usiA] = tempUVedgeidList + usi_uvedgeidOnBord[usiA] else: usi_uvidOnBord_final[usiA] = usi_uvidOnBord[usiA] usi_uvedgeidOnBord_final[usiA] = usi_uvedgeidOnBord[usiA] usi_bb_final = {} for usi in usi_uvidOnBord_final: umin = 1 umax = 0 vmin = 1 vmax = 0 for uvid in usi_uvidOnBord_final[usi]: u = uvid_uv[uvid][0] v = uvid_uv[uvid][1] if u < umin: umin = u if u > umax: umax = u if v < vmin: vmin = v if v > vmax: vmax = v usi_bb_final[usi] = [[umin,umax],[vmin,vmax]] # calculate final result for usiA in usi_uvidOnBord_final: if usi_bb_final[usiA][0][0] - borderDistance < 0 or\ usi_bb_final[usiA][0][1] + borderDistance > 1 or\ usi_bb_final[usiA][1][0] - borderDistance < 0 or\ usi_bb_final[usiA][1][1] + borderDistance > 1: for uvid in usi_uvidOnBord_final[usiA]: x = uvid_uv[uvid][0] y = uvid_uv[uvid][1] if x - borderDistance < 0 or\ x + borderDistance > 1 or\ y - borderDistance < 0 or\ y + borderDistance > 1: uvNotPass.add(uvid) for usiB in usi_uvidOnBord_final: if usiB == usiA or\ usi_bb_final[usiA][0][0] - uvDistance > usi_bb_final[usiB][0][1] or\ usi_bb_final[usiA][0][1] + uvDistance < usi_bb_final[usiB][0][0] or\ usi_bb_final[usiA][1][0] - uvDistance > usi_bb_final[usiB][1][1] or\ usi_bb_final[usiA][1][1] + uvDistance < usi_bb_final[usiB][1][0]: continue for uvid in usi_uvidOnBord_final[usiA]: if uvid in uvNotPass: continue x = uvid_uv[uvid][0] y = uvid_uv[uvid][1] if x - uvDistance > usi_bb_final[usiB][0][1] or\ x + uvDistance < usi_bb_final[usiB][0][0] or\ y - uvDistance > usi_bb_final[usiB][1][1] or\ y + uvDistance < usi_bb_final[usiB][1][0]: continue for edge in usi_uvedgeidOnBord_final[usiB]: uvedgeid = uvedgeid_uvid[edge] x1 = uvid_uv[uvedgeid[0]][0] y1 = uvid_uv[uvedgeid[0]][1] x2 = uvid_uv[uvedgeid[1]][0] y2 = uvid_uv[uvedgeid[1]][1] cross = (x2 - x1) * (x - x1) + (y2 - y1) * (y - y1) if cross <= 0: closest = ((x - x1)**2 + (y - y1)**2)**(0.5) if closest < uvDistance: uvNotPass.add(uvid) continue d2 = (x2 - x1)**2 + (y2 - y1)**2 if cross >= d2: closest = ((x - x2)**2 + (y - y2)**2)**(0.5) if closest < uvDistance: uvNotPass.add(uvid) continue r = cross / d2 px = x1 + (x2 - x1) * r py = y1 + (y2 - y1) * r closest = ((x - px)**2 + (py - y)**2)**(0.5) if closest < uvDistance: uvNotPass.add(uvid) uvNamesNotPass = [] for uv in uvNotPass: uvNamesNotPass.append(sel+'.map['+str(uv)+']') cmds.select(uvNamesNotPass,r=1) changeSelectionType(sel,"puv") def ifUVShellStack(usiA, usiB, usi_bb, p): # fast filter usiA_umin = float(int(usi_bb[usiA][0][0] * p))/p usiB_umin = float(int(usi_bb[usiB][0][0] * p))/p if not usiA_umin == usiB_umin: return 0 usiA_umax = float(int(usi_bb[usiA][0][1] * p))/p usiA_vmin = float(int(usi_bb[usiA][1][0] * p))/p usiA_vmax = float(int(usi_bb[usiA][1][1] * p))/p usiB_umax = float(int(usi_bb[usiB][0][1] * p))/p usiB_vmin = float(int(usi_bb[usiB][1][0] * p))/p usiB_vmax = float(int(usi_bb[usiB][1][1] * p))/p if usiA_umax == usiB_umax and usiA_vmin == usiB_vmin and usiA_vmax == usiB_vmax: return 1 return 0 def ifUVShellIntersect(usiA, usiB, usi_uvedgeidOnBord, uvedgeid_uv, usi_bb): for edgeA in usi_uvedgeidOnBord[usiA]: ax = uvedgeid_uv[edgeA][0][0] ay = uvedgeid_uv[edgeA][0][1] bx = uvedgeid_uv[edgeA][1][0] by = uvedgeid_uv[edgeA][1][1] # fast filter abx = [ax,bx] aby = [ay,by] if bx bb_umaxB or\ abx[1] < bb_uminB or\ aby[0] > bb_vmaxB or\ aby[1] < bb_vminB: continue for edgeB in usi_uvedgeidOnBord[usiB]: cx = uvedgeid_uv[edgeB][0][0] cy = uvedgeid_uv[edgeB][0][1] dx = uvedgeid_uv[edgeB][1][0] dy = uvedgeid_uv[edgeB][1][1] # fast filter cdx = [cx,dx] cdy = [cy,dy] if dx cdx[1] or\ abx[1] < cdx[0] or\ aby[0] > cdy[1] or\ aby[1] < cdy[0]: continue x1 = bx - ax y1 = by - ay x2 = cx - ax y2 = cy - ay cross1 = x1*y2-x2*y1 x2 = dx - ax y2 = dy - ay cross2 = x1*y2-x2*y1 x1 = dx - cx y1 = dy - cy x2 = ax - cx y2 = ay - cy cross3 = x1*y2-x2*y1 x2 = bx - cx y2 = by - cy cross4 = x1*y2-x2*y1 if (cross1*cross2 <= 0 and cross3*cross4<=0): return 1 return 0 def ifUVShellContain(usiA,usiB,usi_uvedgeidOnBord,usi_uvidOnBord,uvedgeid_uv,uvid_uv): uvid = usi_uvidOnBord[usiB][0] intersects = 0 ray_u = uvid_uv[uvid][0] ray_v = uvid_uv[uvid][1] for edge in usi_uvedgeidOnBord[usiA]: u0 = uvedgeid_uv[edge][0][0] v0 = uvedgeid_uv[edge][0][1] u1 = uvedgeid_uv[edge][1][0] v1 = uvedgeid_uv[edge][1][1] if (v1 >= ray_v and v0 < ray_v): if ((u0-ray_u)*(v1-ray_v)-(v0-ray_v)*(u1-ray_u)) < 0: intersects += 1 if intersects%2 == 1: return 1 return 0 def getFacesHaveNoUV(sel): selList = om2.MSelectionList() selList.add(sel) selPath = selList.getDagPath(0) selVtxIter= om2.MItMeshVertex(selPath) faceidWithNoUV = [] faceWithNoUV = [] while not selVtxIter.isDone(): if selVtxIter.numUVs()==0: faceidWithNoUV += selVtxIter.getConnectedFaces() selVtxIter.next() faceidWithNoUV = list(set(faceidWithNoUV)) for faceid in faceidWithNoUV: faceWithNoUV+=[sel+'.f['+str(faceid)+']'] return faceWithNoUV # checkUVBleed_0() # cProfile.run('checkUVBleed_0()') ''' #UI ''' class ldmt_cls(QDialog): def __init__(self, parent = get_maya_window()): super(ldmt_cls, self).__init__(parent) self.window_name = ldmt_window_name self.setWindowTitle(ldmt_window_name) self.setWindowFlags(Qt.Window) self.move(QCursor.pos() + QPoint(20,20)) # update status bar so it's not only show in help line window. self.set_ui() self.setupBtn() # self.statusbar.showMessage(ld.tag()) # self.installStartBar() def set_ui(self): main_layout = QVBoxLayout(self) self.ui = load_ui_file(ldmt_uifile) if self.ui is None: cmds.warning("UI file not found: {}".format(ldmt_uifile)) return main_layout.addWidget(self.ui) def setupBtn(self): self.ui.btn_check.clicked.connect(self.checkUVBleed) def checkUVBleed(self): cmds.undoInfo(ock = 1) try: minShellBleed = int(self.ui.text_borderBleed.text()) minBorderBleed = int(self.ui.text_borderBleed.text()) uvSize = int(self.ui.box_textureSize.currentText()) except: ld.msg("Input value is not valid!") LD_CheckUVBleed(uvSize,minShellBleed,minBorderBleed) cmds.undoInfo(cck = 1) def installStartBar(self): allQWidgets = self.findChildren(QWidget) for i in allQWidgets: i.installEventFilter(self) def eventFilter(self, obj, event ): '''Connect signals on mouse over''' if event.type() == QEvent.Enter: self.oldMessage = ld.tag() self.statusbar.showMessage(' '+obj.statusTip(),0) elif event.type() == QEvent.Leave: self.statusbar.showMessage(' '+self.oldMessage, 0) pass event.accept() return False # def closeEvent(self,event): # ld.turnToolBtnOff(self,ldmt_button_name) # cmds.deleteUI(ldmt_window_name) def ldmt_show(): if cmds.window(ldmt_window_name, exists=True): cmds.deleteUI(ldmt_window_name) app = QApplication.instance() dialog = ldmt_cls(parent=app.activeWindow()) dialog.show() app.exec_() if __name__ == '__main__': ldmt_show()