MetaBox/Scripts/Modeling/UV/UVDeluxe/uvdeluxe.py
2025-01-14 02:12:52 +08:00

1403 lines
51 KiB
Python

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#from distutils import command
#import subprocess
import maya.cmds as mc
import maya.mel as mel
import pymel.core as pm
import math
import os
#Define globals
version = '1.1.2'
mult = 1
#################
###UI SETTINGS###
#vvvvvvvvvvvvvvv#
from .uistates import UiStates
uis = UiStates.pickleLoad()
red = [0.807843,0.364706,0.305882] #[0.8, 0.3, 0.3]
green = [0.454902,0.752941,0.294118] #[0.3, 0.8, 0.3]
blue = [0.239216,0.615686,0.819608]
yellow = [0.819608,0.670588,0.239216]
#################
#*****************#
# MAKE WINDOW #
#*****************#
def createUI(*args):
if mc.window('UVDeluxe', exists=True):
#remove when not in dev mode
mc.deleteUI('UVDeluxe')
mc.window('UVDeluxe',s=True,width=440,title='UV Deluxe %s' % version, toolbox=False)
#Create Scriptjobs
jobNumber1 = mc.scriptJob(parent='UVDeluxe',event=['linearUnitChanged',lambda *args:updateUI('units_text')])
jobNumber2 = mc.scriptJob(parent='UVDeluxe',event=['SelectionChanged',lambda *args:updateUI_TexResAutomatic()])
### Define texture panel ###
# Figure out percentage
pnSize = (220/float(uis.widthHeight[0]))*100
try:
#swp flag only available in 2011 and beyond
pane = mc.paneLayout('textureEditorPanel', paneSize=[1,pnSize,1], cn='vertical2', swp=1)
except:
pane = mc.paneLayout('textureEditorPanel', paneSize=[1,pnSize,1], cn='vertical2')
uvTextureViews = mc.getPanel(scriptType='polyTexturePlacementPanel')
if len(uvTextureViews):
mc.scriptedPanel(uvTextureViews[0], e=True, unParent=True)
#Load main ui elements#
mc.columnLayout ('MainColumn', columnWidth=220)
ui_Settings(0)
ui_Mover()
ui_Scaler()
ui_Ratio()
ui_MatchUV()
ui_Straighten()
ui_Align()
ui_SelectionSet()
ui_QuickSnap()
#Add texture panel to window
mc.scriptedPanel(uvTextureViews[0], e=True, parent=pane)
# SHOW WINDOW #
mc.showWindow('UVDeluxe')
mc.window('UVDeluxe',edit=True,mnb=True,widthHeight=uis.widthHeight)
updateUI_TexResAutomatic()
#-----------------#
# UPDATE UI #
#-----------------#
def updateUI(command,*args):
if command=='units_text':
#'Maya Units' text in settings.
mc.text('unitText',edit=True,label='Working Units: %s' % mc.currentUnit(q=True,f=True))
mc.text('ratio_unit',edit=True,label='Pixels per %s:' % mc.currentUnit(q=True))
command = 'texture_res'
elif 'angle' in command:
# Straighten Edges Angle dials
if command.split(':')[1] == 'field':
aValue = mc.floatField('angleField',q=True,value=True)
mc.floatSlider('angleSlider',edit=True,value=aValue)
if command.split(':')[1] == 'slider':
aValue = mc.floatSlider('angleSlider',q=True,value=True)
mc.floatField('angleField',edit=True,value=aValue)
elif command == 'scale_pivot':
#Check if scaling pivot is based on selection
if mc.radioButton('PivSel',q=True,sl = True):
mc.floatField('scalePivotFieldU',edit=True,enable=False)
mc.floatField('scalePivotFieldV',edit=True,enable=False)
mc.text('spu',edit=True,enable=False)
mc.text('spv',edit=True,enable=False)
mc.button('samplePivotButton',edit=True,enable=False)
else:
mc.floatField('scalePivotFieldU',edit=True,enable=True)
mc.floatField('scalePivotFieldV',edit=True,enable=True)
mc.text('spu',edit=True,enable=True)
mc.text('spv',edit=True,enable=True)
mc.button('samplePivotButton',edit=True,enable=True)
return
## Relevant for Texture Resolution ##
def updateUI_SetRatio():
#Updates the floatField containing the value that gets queried by unfold.
mult = setRatioMultiplier()
unfold=0.0009765625*(mc.intField('densityField',q=True,value=True))
mc.floatField('ratioField',edit=True,v=unfold*mult)
return
def isPowerOfTwo(x):
return (x != 0) and ((x & (x - 1)) == 0)
def updateUI_TexResAutomatic():
checkbox = mc.checkBox('DTR',q=True,v=True)
if checkbox:
res = getFileResolution()
if res:
mc.text('resTextW', edit=True, label=res[0])
mc.text('resTextH', edit=True, label=res[1])
# Update the resolution text of the manual controls.
# if isPowerOfTwo(res[0]) and res[0] >= 32 and res[0] <= 8192:
# mc.text('resTextManW', edit=True, label=res[0])
# mc.text('resTextManH', edit=True, label=res[1])
updateUI_SetRatio()
return
#----------------#
# Settings #
#----------------#
def ui_Settings(flag,*args):
def retainCompSpace():
if mc.checkBox ('SCR',q=True,value=True):
mc.texMoveContext('texMoveContext',e=True,scr=True)
else: mc.texMoveContext('texMoveContext',e=True,scr=False)
uis.setUiState()
def openPrefs(*args):
#Open preference window
mel.eval('preferencesWnd "general";')
#Change tab
mel.eval('textScrollList -edit -selectItem (uiRes("m_preferencesWnd.kSettingsTab")) prefIndex;')
mel.eval('switchPrefTabs 0;')
return
def setResolution(*args):
# IMPORTANT! SetRatio: multiplier = ((multiplier*(8192/textureResW))/8)
iterations = 8
resMin = 32
#maxRes = 32*(2**iterations)
#mel. Create a local var "sliderValue" to whatever textureSliderW is set to.
sliderValueW = mc.intSlider('textureSliderW', query=True, value=True)
sliderValueH = mc.intSlider('textureSliderH', query=True, value=True)
#Width
p2 = resMin
for i in range(0,iterations+1,1):
if sliderValueW == i:
mc.text('resTextManW',edit=True,label=str(p2))
p2*=2
#Height
p2 = resMin
for i in range(0,iterations+1,1):
if sliderValueH == i:
mc.text('resTextManH',edit=True,label=str(p2))
p2*=2
return
def callSetResAndUpdateUI():
"""
Called when moving either resolution slider
"""
setResolution()
updateUI_SetRatio()
uis.setUiState()
return
def checkDetectTextureResolution():
"""
Called when checkbox value is changed for Detect Resolution
"""
if mc.checkBox('DTR',q=True,v=True):
mc.intSlider('textureSliderW', e=True, enable=False)
mc.intSlider('textureSliderH', e=True, enable=False)
mc.text('resTextManW', e=True, enable=False)
mc.text('resTextManH', e=True, enable=False)
else:
mc.intSlider('textureSliderW', e=True, enable=True)
mc.intSlider('textureSliderH', e=True, enable=True)
mc.text('resTextManW', e=True, enable=True)
mc.text('resTextManH', e=True, enable=True)
uis.setUiState()
return
mc.frameLayout('layout_Settings',label='Settings',width=220,
cll=True,
cl=uis.collapseFrame0,
cc=lambda *args:uis.setUiState(),
ec=lambda *args:uis.setUiState())
## Units and Preferences button
mc.columnLayout()
mc.rowLayout(numberOfColumns=2,cw2=(146,60))
mc.text('unitText',label='Working Units: %s' % mc.currentUnit(q=True,f=True))
mc.button(label='Maya Prefs',w=68,c=openPrefs)
mc.setParent('..')
## DeTect Resolution
s = [110,40,40]
mc.rowLayout(numberOfColumns=3,cw3=s)
mc.checkBox ('DTR',label="Detect Resolution:",h=20,
value = uis.detectTextureSize, cc=lambda *args:checkDetectTextureResolution())
mc.text('resTextW',label='0')
mc.text('resTextH',label='0')
mc.setParent('..')
## Width controller
MAN = not uis.detectTextureSize
mc.rowLayout(numberOfColumns=3,cw3=(40,30,140))
mc.text(label='Size W:')
mc.text('resTextManW', label='', enable = MAN)
mc.intSlider('textureSliderW' ,w=140, min=0, max=8, step=1,
enable= not uis.detectTextureSize,
value = 4,
cc=lambda *args:callSetResAndUpdateUI())
mc.setParent('..')
## Height controller
mc.rowLayout(numberOfColumns=3,cw3=(40,30,140))
mc.text(label='Size H:')
mc.text('resTextManH', label='', enable = MAN)
mc.intSlider('textureSliderH', w=140, min=0, max=8, step=1,
enable= not uis.detectTextureSize%(1+1),
value = 4,
cc=lambda *args:callSetResAndUpdateUI())
mc.setParent('..')
## Create Checkboxes
mc.checkBox ('SCR',label='Retain component spacing (Move tool)',h=20,
value=uis.retainCS,cc=lambda *args:retainCompSpace())
## Set parent for frameLayout & columnLayout
mc.setParent('..')
mc.setParent('..')
setResolution()
#--------------#
# MOVER #
#--------------#
def ui_Mover():
def move(dTuple,*args):
if not mc.polyListComponentConversion(fuv=True):
mel.eval('warning "Please select some UVs"')
else:
steps = mc.floatField('steps',q=True,v=True)
sel = mc.ls(sl = True)
mel.eval('polySelectBorderShell 0')
mc.polyEditUV(u=(steps*dTuple[0]),v=(steps*dTuple[1]))
#Refocus selection
mc.select(sel,r=True)
return
mc.frameLayout('layout_Mover',label='Mover',width=220,cll=True,cl=uis.collapseFrame1,
cc=lambda *args:uis.setUiState(),
ec=lambda *args:uis.setUiState())
mc.columnLayout()
##
mc.rowLayout(numberOfColumns=2,cw2=(107,107))
mc.text(label='Move by steps of:')
mc.floatField('steps',precision=2,width=107,value=1.0)
mc.setParent('..')
##
mc.rowLayout(numberOfColumns=4,cw4=(52,52,52,52))
mc.button(label='Up',w=52, c=lambda *args:move((0,1)))
mc.button(label='Down',w=52, c=lambda *args:move((0,-1)))
mc.button(label='Left',w=52, c=lambda *args:move((-1,0)))
mc.button(label='Right',w=52, c=lambda *args:move((1,0)))
mc.setParent('..')
mc.setParent('..')
mc.setParent('..')
#-----------------------#
# SCALE AND ROTATE #
#-----------------------#
def ui_Scaler():
def getPivot(method):
## Methods
## 1 = Updates UI with sampled position
## 2 = Return Custom UV
## None = return selection center
try:
pivot = mc.polyEvaluate(mc.ls(sl = True), bc2=True)
pivotU=((pivot[0][0] + pivot[0][1]) * 0.5)
pivotV=((pivot[1][0] + pivot[1][1]) * 0.5)
except:
mel.eval("warning (\"You do not have any UVs selected!\")")
if method == 1:
mc.floatField('scalePivotFieldU', edit=True, value=pivotU)
mc.floatField('scalePivotFieldV', edit=True, value=pivotV)
return
elif method == 2:
pivotU = mc.floatField('scalePivotFieldU', query=True, value=True)
pivotV = mc.floatField('scalePivotFieldV', query=True, value=True)
return (pivotU, pivotV)
def scale(button_info, *args):
button_data = button_info.split(':')
if button_data[0] == 'custom':
if button_data[1] == 'u':
button_data[0] = float(mc.floatField('scaleCustomU', query=True, v=True))
else:
button_data[0] = float(mc.floatField('scaleCustomV', query=True, v=True))
else:
button_data[0] = float(button_data[0])
#Get pivot from preset or selection
if mc.radioButton('CustomPivot', query=True, sl = True): pivotUV = getPivot(2)
else: pivotUV = getPivot(None)
if button_data[1] == 'u':
mc.polyEditUV(pu=pivotUV[0], pv=pivotUV[1], su=button_data[0], sv=0)
if button_data[1] == 'v':
mc.polyEditUV(pu=pivotUV[0], pv=pivotUV[1], su=0, sv=button_data[0])
return
def smartRotate(dir):
if not mc.ls(sl = True):
mel.eval("print 'Could not rotate UVs: Nothing selected'")
return
resolution = getWorkingResolution()
resW = resolution[0]
resH = resolution[1]
selCenter = getPivot(None)
#Get pivot from preset or selection
if mc.radioButton('CustomPivot', query=True, sl = True): pivotUV = getPivot(2)
else: pivotUV = selCenter
#Correct texture/scaling ratio before rotating.
scaleV = resH/resW
mc.polyEditUV(pu=selCenter[0], pv=selCenter[1], su=0, sv=scaleV)
#Perform rotate
mc.polyEditUV(pu=pivotUV[0], pv=pivotUV[1], angle=mc.intField('rot_deg', query=True, v=True)*dir)
#Reverse correction
selCenter = getPivot(None) #Update position after potential move
scaleV = resW/resH
mc.polyEditUV(pu=selCenter[0], pv=selCenter[1], su=0, sv=scaleV)
return
mc.frameLayout('layout_Scaler',label='Scaling and Rotation',width=220,cll=True,cl=uis.collapseFrame2,
cc=lambda *args:uis.setUiState(),
ec=lambda *args:uis.setUiState())
mc.columnLayout()
#mc.text(label='Set scaling pivot to selection or custom cords',height=20)
mc.text(label='Pivot for scaling and roation:',height=20)
mc.radioCollection('SP_RC')
##
mc.rowLayout(numberOfColumns=4,cw4=(65,75,34,34))
mc.radioButton('PivSel',w=65,label='Selection',cl='SP_RC',onc=lambda *args:updateUI('scale_pivot'),h=14)
mc.setParent('..')
##
mc.rowLayout(numberOfColumns=3,cw3=(115,33,110))
mc.radioButton('CustomPivot', h=18, w=80,label='Custom UV',cl='SP_RC',onc=lambda *args:updateUI('scale_pivot'))
mc.text('spu',l='Pos U:',align="left",w=33,enable=False)
mc.floatField('scalePivotFieldU',pre=7,w=60,v=0.0,h=18)
mc.setParent('..')
##
mc.rowLayout(numberOfColumns=3,cw3=(115,33,110))
mc.button('samplePivotButton',l='Sample selection', c=lambda *args:getPivot(1),h=18,w=108)
mc.text('spv',l='Pos V:',align="left",w=33,enable=False)
mc.floatField('scalePivotFieldV',pre=7,w=60,v=0.0,h=18)
mc.setParent('..')
##
##
mc.radioCollection('SP_RC',edit=True,select='PivSel') #Set default selection pivot mode
mc.text(label='Scale by:',height=20)
##
mc.rowLayout(numberOfColumns=6,cw6=(35,25,25,30,42,47))
mc.text(l='Width:',h=18)
mc.button(l='0.5',w=25, c=lambda *args:scale('0.5:u'),h=20, bgc=red)
mc.button(l='2.0',w=25, c=lambda *args:scale('2.0:u'),h=20, bgc=red)
mc.button(l='-1.0',w=27, c=lambda *args:scale('-1.0:u'),h=20, bgc=red)
mc.floatField('scaleCustomU',pre=3, v=0.001 ,w=42,h=20)
mc.button(l='Custom',w=47, c=lambda *args:scale('custom:u'),h=20, bgc=red)
mc.setParent('..')
###
mc.rowLayout(numberOfColumns=6,cw6=(35,25,25,30,42,47))
mc.text(l='Height:',h=18)
mc.button(l='0.5',w=25, c=lambda *args:scale('0.5:v'),h=20,bgc=green)
mc.button(l='2.0',w=25, c=lambda *args:scale('2.0:v'),h=20,bgc=green)
mc.button(l='-1.0',w=27, c=lambda *args:scale('-1.0:v'),h=20,bgc=green)
mc.floatField('scaleCustomV',pre=3, v=0.001, w=42,h=20)
mc.button(l='Custom',w=47, c=lambda *args:scale('custom:v'),h=20,bgc=green)
mc.setParent('..')
##
mc.text('')
mc.text(label='Smart Rotate: Maintain width/height ratio')
mc.rowLayout(numberOfColumns=3,cw3=(34,89,89))
mc.intField('rot_deg',min=0,max=360,v=90,w=34)
mc.button('CW_BTN', label='Rotate CW',w=87, c=lambda *args:(smartRotate(-1)))
mc.button('CCW_BTN',label='Rotate CCW',w=89, c=lambda *args:(smartRotate(1)))
mc.setParent('..')
#mc.text(align='left',label=' (Rotates with width/height ratio correction)')
##
mc.setParent('..')
mc.setParent('..')
return
#----------------#
# RATIO UI #
#----------------#
def ui_Ratio():
global mult
RS = RatioSampler()
def ratioHelp(*args):
help =['This tool will scale your selected shells as close as possible to \nthe desired pixel density. Accuracy will vary depending on the \namount of distortion to your UVs. A new or unmodifed polyCube \nwill have no distortion and be scaled correctly.',
"Shells are scaled using the Unfold tool's -scale flag. \nThe output value is simply the number parsed to the \nUnfold tool, and all other options turned off"]
mc.confirmDialog(title='Set Ratio',button='Ok, whatever',message=str(help[0])+'\n\n'+str(help[1]));
return
def sampleRatio(*args):
RS.getSource()
mc.button('SMR_BTN', e=True, enable=True)
return
def setManRatio(*args):
RS.setRatio()
return
def updateSourceRatio(*args):
RS.sourceRatio = mc.floatField('sampledRatioField', q=True, v=True)
print(RS.sourceRatio)
return
def setRatio(*args):
if mc.checkBox('DTR',q=True,v=True):
resW = float(mc.text('resTextW',q=True,l=True))
resH = float(mc.text('resTextH',q=True,l=True))
else:
resW = float(mc.text('resTextManW',q=True,l=True))
resH = float(mc.text('resTextManH',q=True,l=True))
#mult
#mult = setRatioMultiplier()
#Define selection and convert it to uvs
selection = mc.ls(sl = True)
selection = mc.polyListComponentConversion(selection, tuv=True)
#Find center of selection
pivot = mc.polyEvaluate(selection,bc2=True)
pu=((pivot[0][0] + pivot[0][1]) * 0.5)
pv=((pivot[1][0] + pivot[1][1]) * 0.5)
#Correct texture/scaling ratio before rotating.
if resH != resW:
scaleV = resH/resW
mc.polyEditUV(pu=pu,pv=pv,su=0,sv=scaleV)
mc.unfold(i=0,us=True,s=mc.floatField('ratioField',q=True,v=True))
#Reverse correction
scaleV = resW/resH
mc.polyEditUV(pu=pu,pv=pv,su=0,sv=scaleV)
else:
mc.unfold(i=0,us=True,s=mc.floatField('ratioField',q=True,v=True))
mc.select(selection,replace=True)
return
mc.frameLayout('layout_Ratio',label='Ratio (Pixel density)',width=220,cll=True,cl=uis.collapseFrame3,
cc=lambda *args:uis.setUiState(),
ec=lambda *args:uis.setUiState())
mc.columnLayout()
##
mc.rowLayout(numberOfColumns=2,cw2=(170,42))
mc.text(label='Scale shells to desired pixel density',w=170)
mc.button(w=42,label='Help', align='right', command=ratioHelp)
mc.setParent('..')
##//Sampled Density Controls//
##
s = 109,103
mc.rowLayout(numberOfColumns=2,cw2=s)
mc.button(label='Copy Ratio', w=s[0], command=sampleRatio)
mc.button('SMR_BTN', w=s[1],label='Paste Ratio',command=setManRatio, enable=True)
mc.setParent('..')
##
mc.rowLayout(numberOfColumns=2,cw2=(108,106))
mc.text(label='Custom Ratio:',w=108)
mc.floatField('sampledRatioField', pre=5, enable=True, w=106, v=0, cc=updateSourceRatio)
mc.setParent('..')
##//Pixel Density Controls//
##
mc.text(label='')
s = [72,35,103]
mc.rowLayout(numberOfColumns=3,cw3=s)
mc.text('ratio_unit', w=s[0], label='Pixels per %s:' % mc.currentUnit(q=True))
mc.intField('densityField',v=256,min=0,max=8192,w=s[1],cc=lambda *args:updateUI_SetRatio())
mc.button(label='Set Pixel Density', w=s[2],command=setRatio)
mc.setParent('..')
##
mc.rowLayout(numberOfColumns=2,cw2=(108,106))
mc.text(label='Pixel Density:',w=108)
#(ignore)
mc.floatField('ratioField',pre=5,enable=False,w=106, v=0.0009765625*(mc.intField('densityField',q=True,v=True)))
mc.setParent('..')
##
mc.setParent('..')
mc.setParent('..')
updateUI_SetRatio()
#-------------------#
# MatchUV UI #
#-------------------#
def ui_MatchUV():
def matchUVS(*args):
maxDist = uis.matchDist
def sortDist(tuple):
return tuple[1]
def getOtherUVS(allSelected,suvs):
objects = [i.split('.')[0] for i in allSelected]
objects = [i for i in set(objects)]
uvs = mc.ls(mc.polyListComponentConversion(objects,tuv=True),fl=True)
return sorted(set.difference(set(uvs)-set(suvs)))
### SETUP ###
allSelected = mc.ls(sl = True)
# Create list of uvs
suvs = mc.ls(mc.polyListComponentConversion(tuv=True),sl = True,fl=True)
ouvs= getOtherUVS(allSelected,suvs)
# Create list of positions
spos = [mc.polyEditUV(i,query=True) for i in suvs]
opos = [mc.polyEditUV(i,query=True) for i in ouvs]
### PERFORM ###
for i in range(len(suvs)):
withinRange = []
for j in range(len(ouvs)):
x = spos[i][0]-opos[j][0]
y = spos[i][1]-opos[j][1]
dist = math.sqrt((x**2) + (y**2))
if dist < maxDist:
withinRange.append((opos[j],dist))
withinRange = sorted(withinRange,key=sortDist)
if len(withinRange):
mc.polyEditUV(suvs[i],u=withinRange[0][0][0],v=withinRange[0][0][1],relative=False)
uis.setUiState()
return
def matchUVS_refresh_ui(*args):
mc.floatField(matchField, edit=True, value=mc.floatSlider(matchSlider, q=True, v=True))
uis.matchDist = mc.floatField(matchField, query=True, value=True)
mc.frameLayout('layout_MatchUV',label='Match UVs',width=220,cll=True,cl=uis.collapseFrame7,
cc=lambda *args:uis.setUiState(),
ec=lambda *args:uis.setUiState())
mc.columnLayout()
##
mc.text(label='Snap selected UVs to closest unselected UVs')
mc.rowLayout(numberOfColumns=3,cw3=(70,60,80))
mc.text(label="Max distance:")
matchField = mc.floatField(pre=5,v=uis.matchDist,w=50)
matchSlider = mc.floatSlider(min=0.0,max=1.0,value=uis.matchDist,w=82,dc=matchUVS_refresh_ui)
mc.setParent('..')
mc.button(width=80,label='Match UVs', command=matchUVS)
mc.setParent('..')
mc.setParent('..')
return
#-------------------#
# Straighten UI #
#-------------------#
def ui_Straighten():
def help(*args):
help =['This script will flatten edges based on the initial angle of each edge.\nWhat that means is, if an edge is closer to being more vertical than \nhorizontal it can only be flattened vertically, or vice versa.',
'So before the script flattens anything, it sorts all edges into two lists\nof horizontal and vertical before it decides which lists to flatten.']
mc.confirmDialog(title='Straighten Edges',button='Got it!',message=help[0]+'\n\n'+help[1])
return
## UI ##
mc.frameLayout('layout_Straighten',label='Straighten Edges',width=220,cll=True,cl=uis.collapseFrame4,
cc=lambda *args:uis.setUiState(),
ec=lambda *args:uis.setUiState())
mc.columnLayout()
##
mc.rowLayout(numberOfColumns=2,cw2=(170,33))
mc.text(label='Straighten based on UV selection')
mc.button(w=33,label='Info',align='right',c=help)
mc.setParent('..')
##
mc.rowLayout(numberOfColumns=3,cw3=(82,35,100))
mc.text(label='Angle tolerance:',align='left',w=82)
mc.floatField('angleField',min=0,max=45,value=30,pre=1,w=35,cc=lambda *args:updateUI('angle:field'))
mc.floatSlider('angleSlider',min=0,max=45,value=30,w=82,dc=lambda *args:updateUI('angle:slider'))
mc.setParent('..')
##
mc.rowLayout(numberOfColumns=3,cw3=(71,71,71))
mc.button(label='Horizontal',w=71, h=20, c=lambda *args:(straightenEdges('hori')), bgc=green)
mc.button(label='Vertical',w=71, h=20, c=lambda *args:(straightenEdges('vert')), bgc=red)
mc.button(label='Both',w=71, h=20, c=lambda *args:(straightenEdges('both')), bgc=yellow)
mc.setParent('..')
##
mc.setParent('..')
mc.setParent('..')
#-------------------#
# Align Tools UI #
#-------------------#
def ui_Align():
mc.frameLayout('layout_Align',label='Align Tools',width=220,cll=True,cl=uis.collapseFrame5,
cc=lambda *args:uis.setUiState(),
ec=lambda *args:uis.setUiState())
mc.columnLayout()
##
mc.rowLayout(numberOfColumns=2,cw2=(137,77))
mc.text(align='left',label='Straighten shells by rotation:',w=137)
mc.button(label='Rotate Align',w=77, c=lambda *args:(align('--shell')))
mc.setParent('..')
##
##
mc.text(label='Align Selected Shells:')
mc.rowLayout(numberOfColumns=4,cw4=(52,52,52,52))
mc.button(label='Top', w=52, c=lambda *args:alignShells("up"), h=20, bgc=green)
mc.button(label='Bottom', w=52, c=lambda *args:alignShells("down"), h=20, bgc=green)
mc.button(label='Left', w=52, c=lambda *args:alignShells("left"), h=20, bgc=red)
mc.button(label='Right', w=52, c=lambda *args:alignShells("right"), h=20, bgc=red)
mc.setParent('..')
##
mc.rowLayout(numberOfColumns=2,cw2=(106,106))
mc.button(label='Center Vertical', w=106, c=lambda *args:alignShells("centerV"), h=20, bgc=green)
mc.button(label='Center Horizontal', w=106, c=lambda *args:alignShells("centerH"), h=20, bgc=red)
mc.setParent('..')
##
mc.rowLayout(numberOfColumns=1, w=212)
mc.button(label='Move Shells to 0-1 Space', w=212, c= gatherShells, h=20, bgc=yellow)
mc.setParent('..')
##
mc.setParent('..')
mc.setParent('..')
return
#-----------------------#
# SELECTION SETS #
#-----------------------#
def ui_SelectionSet():
selectionSlots = ['none','none','none','none','none','none']
colorBlank = [0.3,0.3,0.3]
uColor = [0.584314,0.772549,0.0]
vColor = [0.913725,0.878431,0.0]
eColor = [0.870588,0.643137,0.117647]
oColor = [0.152941,0.729412,0.447059]
fColor = [0.478431,0.227451,0.227451]
def storeLoadSelection(slot):
#Store selection if button is blank..
slotLabel = mc.button("slotButton%i" % slot,q=True,label=True)
if slotLabel == '':
sel = mc.ls(sl = True)
if len(sel):
selectionSlots[slot-1] = sel
#fluff
try:
type = mc.ls(sl = True,fl=True)[0].split('.')[1]
type = type.split('[')[0]
except:
type = ''
if type == 'map':
color = uColor
elif type == 'e':
color = eColor
elif type == 'vtx' or type == 'vtxFace':
color = vColor
elif type == 'f':
color = fColor
else:
color = oColor
mc.button("slotButton%i" % slot,edit=True,label='%i' % len(mc.ls(sl = True,fl=True)),bgc=color)
#..load selection if not
else:
mc.select(selectionSlots[slot-1],replace=True)
def clearSlot(slot):
mc.button("slotButton%i" % slot,edit=True,label='',bgc=colorBlank)
mc.frameLayout('layout_SelectionSets',label='Selections',width=220,cll=True,cl=uis.collapseFrame8,
cc=lambda *args:uis.setUiState(),
ec=lambda *args:uis.setUiState())
mc.columnLayout()
mc.button("selectBorderEdges", label='Select Shell Border Edges', w=214, c=lambda *args: selectShellBorderEdges())
mc.text(l=' Store selections')
mc.rowLayout(numberOfColumns=6)
mc.button("slotButton1", label='', w=49, c=lambda *args: storeLoadSelection(1), bgc=colorBlank)
mc.iconTextButton("slotTrash1",style="iconOnly", ann="Clear Slot 1", image="SP_TrashIcon.png", c=lambda *args: clearSlot(1))
mc.button("slotButton2", label='', w=49, c=lambda *args: storeLoadSelection(2), bgc=colorBlank)
mc.iconTextButton("slotTrash2",style="iconOnly", ann="Clear Slot 2", image="SP_TrashIcon.png", c=lambda *args: clearSlot(2))
mc.button("slotButton3", label='', w=49, c=lambda *args: storeLoadSelection(3), bgc=colorBlank)
mc.iconTextButton("slotTrash3",style="iconOnly", ann="Clear Slot 3", image="SP_TrashIcon.png", c=lambda *args: clearSlot(3))
mc.setParent('..')
mc.rowLayout(numberOfColumns=6)
mc.button("slotButton4", label='', w=49, c=lambda *args: storeLoadSelection(4), bgc=colorBlank)
mc.iconTextButton("slotTrash4",style="iconOnly", ann="Clear Slot 4", image="SP_TrashIcon.png", c=lambda *args: clearSlot(4))
mc.button("slotButton5" ,label='', w=49, c=lambda *args: storeLoadSelection(5), bgc=colorBlank)
mc.iconTextButton("slotTrash5",style="iconOnly", ann="Clear Slot 5", image="SP_TrashIcon.png", c=lambda *args: clearSlot(5))
mc.button("slotButton6",label='', w=49, c=lambda *args: storeLoadSelection(6), bgc=colorBlank)
mc.iconTextButton("slotTrash6",style="iconOnly", ann="Clear Slot 6", image="SP_TrashIcon.png", c=lambda *args: clearSlot(6))
mc.setParent('..')
mc.setParent('..')
mc.setParent('..')
#--------------------#
# Quck UvSnapshot UI #
#--------------------#
def ui_QuickSnap():
#path = os.path.expanduser('~')
#path = os.getenv('USERPROFILE') or os.getenv('HOME')
path = uis.snapPath
def performQuicksnap():
# options #
resolution = getWorkingResolution()
width = resolution[0]
height = resolution[1]
if mc.checkBox ('doubleRes', query=True, value=True):
width *= 2
height *= 2
autoLoad = mc.checkBox ('autoLoad', query=True, value=True)
antiAlias = mc.checkBox ('antiAliasing', query=True, value=True)
fileName = 'outUV'
format = mc.optionMenuGrp('fileFormat', query=True, value=True)
filePath = mc.textField('pathField',query=True,text=True) + '/' + fileName + '.' + format
uis.setUiState()
# # # Perform # # #
mc.uvSnapshot(name=filePath,xr=width,yr=height,o=True,aa=antiAlias,ff=format)
if autoLoad:
os.startfile(filePath)
mc.frameLayout('layout_QuickSnap',label='Quick UV Snapshot',width=220,cll=True,cl=uis.collapseFrame6,
cc=lambda *args:uis.setUiState(),
ec=lambda *args:uis.setUiState())
mc.columnLayout()
##
mc.text(align='left',label='Create UV Snapshot for selected objects')
##
mc.rowLayout(numberOfColumns=3,cw3=(65,65,70))
mc.checkBox ('autoLoad',label='Open file',value=True)
mc.checkBox ('antiAliasing',label='Anti Alias',value=True)
mc.checkBox ('doubleRes',label='Double Size',value=False)
mc.setParent('..')
##
#mc.text(label="Output directory:")
mc.textField("pathField",text=path,width=214)
##
mc.rowLayout(numberOfColumns=2,cw2=(89,122))
mc.optionMenuGrp('fileFormat',label="Format:",cat=[1,'left',0],cw2=[40,48])
mc.button(label='Save snapshot',w=119, c=lambda *args:performQuicksnap())
mc.menuItem(label='tga')
mc.menuItem(label='tif')
mc.menuItem(label='png')
mc.setParent('..')
##
mc.setParent('..')
mc.setParent('..')
#####////////////////////////////////#####
##### #####
##### CLASSES #####
##### #####
#####////////////////////////////////#####
class RatioSampler:
def __init__(self):
self.sourceArea = None
self.sourceUVArea = None
self.sourceRatio = None
def getSource(self):
if not len(pm.ls(sl=True)): return
self.sourceArea = self.__getAreaAverage()
self.sourceUVArea = self.__getUVAreaAverage()
self.sourceRatio = self.sourceArea/self.sourceUVArea
mc.floatField('sampledRatioField', edit=True, v=self.sourceRatio)
return
def setRatio(self):
selected = UVClass()
selected.getShells()
for shell in selected.shells:
pm.select(shell.uvs)
targetArea = self.__getAreaAverage()
targetUVArea = self.__getUVAreaAverage()
targetRatio = targetArea/targetUVArea
ratio = (targetRatio/self.sourceRatio)**0.5
pivot = shell.getPivot()
pm.polyMoveUV(s=[ratio, ratio], pvt=[pivot[0], pivot[1]], ch=False)
return
def __getAreaAverage(self):
"""
Returns the average area of the selected faces (or corresponding faces).
The script pretends that the user is working in cm, or else the math doesn't work:
A 1x1cm plane will return an area of 1, and a 1x1m plane will return an area of 10000,
so the area of objects in meter will be multiplied by 0.0001
"""
sel = pm.ls(sl=True)
faces = pm.ls(pm.polyListComponentConversion(sel, tf=True), fl=True)
# Get multiplier
unit = pm.currentUnit(q=True, f=True)
mult = 1.0
if not unit == 'centimeter':
if unit == 'meter':
mult = 0.0001
elif unit == 'millimeter':
mult = 1000
# Get area of faces
areas = [f.getArea(space='world') for f in faces]
sum = 0
for a in areas:
sum += a * mult
print("Face Area: ", sum/len(areas))
return sum/len(areas)
def __getUVAreaAverage(self):
"""
Returns the average area of the selected UVs.
"""
sel = pm.ls(sl=True)
faces = pm.ls(pm.polyListComponentConversion(sel, tf=True), fl=True)
#Get area of UV Faces
UVAreas = [f.getUVArea() for f in faces]
sum = 0
for a in UVAreas:
sum += a
print("UV Area: ", sum/len(UVAreas))
return sum/len(UVAreas)
class UVClass:
def __init__(self, uvs = "selection"):
#Set self.uvs from a list of uvs or automatically
if uvs == "selection": #No list was sent
self.uvs = mc.ls(mc.polyListComponentConversion(tuv=True),fl=True)
else: self.uvs = uvs
self.type = "standard"
self.shells = []
self.borderEdges = []
def setMinMax(self):
xPositions = sorted([mc.polyEditUV(i, query=True)[0] for i in self.uvs])
yPositions = sorted([mc.polyEditUV(i, query=True)[1] for i in self.uvs])
self.minMax = (xPositions[0],xPositions[-1]),(yPositions[0],yPositions[-1])
self.xMin = self.minMax[0][0]
self.xMax = self.minMax[0][1]
self.yMin = self.minMax[1][0]
self.yMax = self.minMax[1][1]
def getPivot(self):
pivot = mc.polyEvaluate(self.uvs,bc2=True)
pivU = ((pivot[0][0] + pivot[0][1]) * 0.5)
pivV = ((pivot[1][0] + pivot[1][1]) * 0.5)
return pivU,pivV
def getShells(self):
""" This creates a list object (shells) within the class containing a UVClass per shell found"""
if len(self.shells): #No need to do this twice
if self.type == "shell":
print("Class is already of shell type. This function call is redundant")
return
currentSelection = mc.ls(sl = True)
self.shells = []
for uv in self.uvs:
found = False
for shell in self.shells:
if uv in shell.uvs:
found = True
if not found:
mc.select(uv)
mel.eval('polySelectBorderShell 0;')
thisShell = UVClass()
thisShell.type = "shell"
thisShell.setMinMax()
self.shells.append(thisShell)
mc.select(currentSelection)
#####///////////////////////////////////////#####
##### #####
##### SHARED PROCEDURES #####
##### #####
#####///////////////////////////////////////#####
"""
def selectShellBorderEdges():
from borders import BorderEdges
selected = UVClass()
selected.getShells()
edges = BorderEdges(selected.shells)
mc.select(edges)
return
"""
def selectShellBorderEdges():
selected = UVClass()
selected.getShells()
finalEdges = []
for shell in selected.shells:
#Get border UVs for first uv in shell
mc.select(shell.uvs[0])
mel.eval('polySelectBorderShell 1;')
#Get this shell's BORDER UVS
buvs = mc.ls(sl=True,fl=True)
#List edges that are connected to uv border
relatedEdges = pm.ls(pm.polyListComponentConversion(te=True),fl=True)
print(relatedEdges)
for edge in relatedEdges:
# UVClass uses cmds and not pymel, so we need to use it here as well when comparing names
# mc.ls > pCube1.map[0]...
# pm.ls > pCube1Shape1[0]
#Get CONNECTED UVS
cuvs = mc.ls(pm.polyListComponentConversion(edge, tuv=True),fl=True)
matches = 0
for uv in cuvs:
if uv in buvs: matches +=1
if matches > 1:
#Converting to string because of weird error: Problem with the API object returned by __apiobject__ method
matchEdgeFaces = pm.ls(edge.connectedFaces(),fl=True)
if edge.isOnBoundary():
#Border edge is auto accept
finalEdges.append(str(edge))
else:
if len(matchEdgeFaces) > 1:
#A triangulated face may have an edge that's not the shell border but both uvs are.
#Here we look to see if both faces connected to that edge are within the uv shell.
#if they are, we discard that edge.
""" Working on it
facesInShell = 0
for f in matchEdgeFaces:
fuvs = mc.ls(pm.polyListComponentConversion(matchEdgeFaces, tuv=True),fl=True)
if fuvs[0] in shell.uvs:
print f, "is in shell."
facesInShell +=1
else: print f, "NOT in shell"
if facesInShell == 2:
finalEdges.append(str(edge))
"""
# Partial sollution
mefUVS = mc.ls(pm.polyListComponentConversion(matchEdgeFaces, tuv=True),fl=True)
blab = 0
for uv in mefUVS:
if uv in buvs: blab += 1
if blab < len(mefUVS):
finalEdges.append(str(edge))
#SELECT!
mc.select(finalEdges)
def gatherShells(*args):
selected = UVClass()
selected.getShells()
for shell in selected.shells:
x_center = (shell.xMin + shell.xMax)/2.0
y_center = (shell.yMin + shell.yMax)/2.0
if x_center > 1:
mc.polyEditUV(shell.uvs, u= -int(x_center),v=0)
if x_center < 0:
mc.polyEditUV(shell.uvs, u= -int(x_center) + 1,v=0)
if y_center > 1:
mc.polyEditUV(shell.uvs, u= 0, v= -int(y_center))
if y_center < 0:
mc.polyEditUV(shell.uvs, u= 0, v= -int(y_center) + 1)
return
def alignShells(dir):
selected = UVClass()
selected.getShells()
shellsUVs = []
for shell in selected.shells:
for uv in shell.uvs:
shellsUVs.append(uv)
allUVs = UVClass(shellsUVs)
allUVs.setMinMax()
#Move shells
for shell in selected.shells:
if dir == "right":
mc.polyEditUV(shell.uvs, u= allUVs.xMax - shell.xMax)
elif dir == "left":
mc.polyEditUV(shell.uvs, u= allUVs.xMin - shell.xMin)
elif dir == "centerH":
mc.polyEditUV(shell.uvs, u = (allUVs.xMin+allUVs.xMax)/2 - (shell.xMax + shell.xMin)/2)
elif dir == "up":
mc.polyEditUV(shell.uvs, v= allUVs.yMax - shell.yMax)
elif dir == "down":
mc.polyEditUV(shell.uvs, v= allUVs.yMin - shell.yMin)
elif dir == "centerV":
mc.polyEditUV(shell.uvs, v = (allUVs.yMin+allUVs.yMax)/2 - (shell.yMax + shell.yMin)/2)
return
def align(flag,*args): #Rotate align shell(s)
orgSel = UVClass()
orgSel.getShells()
alignPoints = []
if len(orgSel.uvs) < 2:
mel.eval('warning("Select at least two uvs!")')
return
for shell in orgSel.shells:
#Rotations can be unexpected if more than two uvs per shell were selected
#This is often because orgSel is not in the same order as uvs were selected
uvPositions = {}
for uv in orgSel.uvs:
if uv in shell.uvs and uv not in uvPositions.keys():
uvPositions[len(uvPositions.items())] = uv
if len(uvPositions) >= 2:
angle = findAngle(( uvPositions.get(0), uvPositions.get(1) ))
pivot = shell.getPivot()
pu = pivot[0]
pv = pivot[1]
#Align to hoizontal
if angle >-45 and angle < 45:
mc.polyEditUV (shell.uvs, pu=pu,pv=pv,angle=(0 - angle))
elif angle >135 and angle < 180:
mc.polyEditUV (shell.uvs, pu=pu,pv=pv,angle=(180 - angle))
elif angle >-180 and angle <-135:
mc.polyEditUV (shell.uvs, pu=pu,pv=pv,angle=(180 - angle))
#Align to vertical
if angle >45 and angle <135:
mc.polyEditUV (shell.uvs, pu=pu,pv=pv,angle=(90 - angle))
elif angle <-45 and angle >-135:
mc.polyEditUV (shell.uvs, pu=pu,pv=pv,angle=(270 - angle))
return
def findAngle(tuple):
#Returns angle of two UV points
uv0 = tuple[0]
uv1 = tuple[1]
p1 = mc.polyEditUV(uv0,q=True)
p2 = mc.polyEditUV(uv1,q=True)
X = (p2[0] - p1[0])
Y = (p2[1] - p1[1])
radians = math.atan2(Y,X)
angle = radians*57.2957795
return angle
def findBox2D(uvs):
xMin = mc.polyEditUV(uvs[0],query=True)[0]
xMax = mc.polyEditUV(uvs[0],query=True)[0]
yMin = mc.polyEditUV(uvs[0],query=True)[1]
yMax = mc.polyEditUV(uvs[0],query=True)[1]
for u in uvs:
posX = mc.polyEditUV(u,query=True)[0]
posY = mc.polyEditUV(u,query=True)[1]
if posX > xMax: xMax = posX
elif posX < xMin: xMin = posX
if posY > yMax: yMax = posY
elif posY < yMin: yMin = posY
return (xMin,xMax), (yMin,yMax)
def getFileResolution():
texWinName = mc.getPanel(sty='polyTexturePlacementPanel')
availableImages = mc.textureWindow(texWinName[0], q=True, imn=True)
if availableImages:
currentImage = availableImages[mc.textureWindow(texWinName[0], q=True, imageNumber=True)]
currentImage = currentImage.split()[-1]
#Find currently used image
if 'outSizeX' in mc.listAttr(currentImage):
x = mc.getAttr(currentImage + '.outSizeX')
y = mc.getAttr(currentImage + '.outSizeY')
return int(x), int(y)
else: return None
def getWorkingResolution():
"""
Returns the active "working" resolution, based on whether or not the user
has set UVDeluxe to to manual or automatic texture resolution detection.
"""
checkbox = mc.checkBox('DTR',q=True,v=True)
if checkbox:
resW = float(mc.text('resTextW',q=True,l=True))
resH = float(mc.text('resTextH',q=True,l=True))
else:
resW = float(mc.text('resTextManW',q=True,l=True))
resH = float(mc.text('resTextManH',q=True,l=True))
return resW, resH
def setRatioMultiplier():
"""
Get the correct multiplier for the pixel ratio calculation.
"""
resolution = getWorkingResolution()
resW = resolution[0]
resH = resolution[1]
# resH = float(mc.text('resTextH',q=True,l=True))
if resW > 0:
unit = mc.currentUnit(query=True,f=True)
global mult
mult = 1
if not unit == 'centimeter':
if unit == 'meter':
mult = 0.01
elif unit == 'millimeter':
mult = 10
else:
mc.confirmDialog(title='Sorry!',button='ok',message='UVDeluxe\'s Set Ratio does work with unit type: %s\nPlease work in meters, centimeters or millimeters' % unit);
#mc.error('Script not configured for unit %s' % unit)
mult = (mult*(8192/resW))/8
return mult
else:
return 0
def straightenEdges(flag):
def findAdjacentEdges(gotEdges):
## Accepts list of tuples size 2 ##
adjacentEdges = {}
##STEP ONE##
#Create list of all UVs in gotEdges
everyUV = []
for e in range(0,len(gotEdges),1):
for u in range(0,len(gotEdges[e]),1):
if not gotEdges[e][u] in everyUV:
everyUV.append(gotEdges[e][u])
#Check which uvs are in more than one edge, and store those edge connections.
pairs = []
loneEdges = []
for u in range(0,len(everyUV),1):
#Clear list of found edges for this uv
foundE = []
for e in range(0,len(gotEdges),1):
if everyUV[u] in gotEdges[e]:
foundE.append(gotEdges[e])
#Put edges into appropriate list, right before the loop iteration ends.
if e==len(gotEdges)-1:
if len(foundE) == 2 and not foundE in pairs: pairs.append(foundE)
elif len(foundE) == 1 and not foundE in loneEdges:
loneEdges.append(foundE)
#Remove pair-ends that got put into loneEdges
for l in range(len(loneEdges)-1,-1,-1):
found = []
for p in range(0,len(pairs),1):
if loneEdges[l][0] in pairs[p]:
found.append(l)
for f in range(0,len(found),1):
loneEdges.pop(found[f])
## STEP TWO ##
incomplete = True
addNewPair = False
unsortedPairs = pairs[:]
keysComplete = []
if len(pairs):
while incomplete:
keysSkipped = 0
if len(unsortedPairs):
### print "\nAdding new key!"
adjacentEdges[len(adjacentEdges)] = unsortedPairs[0]
for key in adjacentEdges.keys():
### print "\nNow checking Key %d" % key
if key not in keysComplete:
#Pop first pair key from unsortet.
popPairs = []
deletePair = []
for p in unsortedPairs:
if p == adjacentEdges[key]:
deletePair.append(p)
for p in deletePair:
unsortedPairs.remove(p)
addingToKey = True
while addingToKey:
uvs_inKey = []
for pair in adjacentEdges.get(key):
for uv in pair:
uvs_inKey.append(uv)
popPairs = []
pairsToAdd = []
for p in range(0,len(unsortedPairs),1):
for uv in uvs_inKey:
#Check if either edge of pair contains key-uv
if uv in unsortedPairs[p][0] or uv in unsortedPairs[p][1]:
pairsToAdd.append(unsortedPairs[p])
#Add pairs to key and remove from list of unsorted pairs
for pair in pairsToAdd:
adjacentEdges[key] += pair
adjacentEdges[key] = sorted(list(set(adjacentEdges[key])))
if pair in unsortedPairs:
unsortedPairs.remove(pair)
#Break loop when nothing more to add
if not len(pairsToAdd):
addingToKey = False
keysComplete.append(key)
else:
#Break loop when all keys are complete
keysSkipped += 1
if keysSkipped == len(adjacentEdges):
incomplete = False
#Assign key to every single edge left
for e in loneEdges:
adjacentEdges[len(adjacentEdges)] = e
#Restructure keys from list of tuples to list of uvs
for key in adjacentEdges.keys():
uvs_inKey = []
for tuple in adjacentEdges[key]:
uvs_inKey.append(tuple[0])
uvs_inKey.append(tuple[1])
#Replace list with new list
adjacentEdges[key] = sorted(list(set(uvs_inKey)))
return adjacentEdges
max_angle = mc.floatField('angleField', query=True, value=True)
orgSel = mc.ls(sl = True)
edges = createEdgeList()
#Sort edges by horizontal and vertical
sortedEdges = sortEdges(edges,max_angle)
#Determin method of straightening
## Horizontal
if not flag == 'vert':
hz_edges = findAdjacentEdges(sortedEdges[0])
for key in hz_edges.keys():
box = findBox2D(hz_edges[key])
centerV=((box[1][0] + box [1][1]) * 0.5)
mc.polyEditUV(hz_edges[key],v=centerV,relative=False)
## Vertical
if not flag == 'hori':
vt_edges = findAdjacentEdges(sortedEdges[1])
for key in vt_edges.keys():
box = findBox2D(vt_edges[key])
centerU=((box[0][0] + box[0][1]) * 0.5)
mc.polyEditUV(vt_edges[key],u=centerU,relative=False)
return
def createEdgeList():
def addToEdges(uv0, uv1):
uvTup1 = (uv0,uv1)
uvTup2 = (uv1,uv0)
if not uvTup1 in edges.values() and not uvTup2 in edges.values():
edges[len(edges)] = uvTup1
return
edges = { }
orgSel = mc.ls(sl = True, fl=True)
#####################
#Build list of edges
if len(orgSel):
for u in range(0,len(orgSel),1):
uv1 = orgSel[u]
uvToEdge = mc.ls(mc.polyListComponentConversion(orgSel[u], fuv=True, te=True), fl=True)
#Get uvs in convertToFace selection
faces = mc.ls(mc.polyListComponentConversion(orgSel[u], fuv=True, tf=True), fl=True)
uvGrowSel = []
for f in faces:
uv = mc.ls(mc.polyListComponentConversion(f, ff=True, tuv=True), fl=True)
for point in uv:
if not point in uvGrowSel:
uvGrowSel.append(point)
#Check if there is a connection between point 1 and points in grow selection.
for g in uvGrowSel:
e1 = mc.ls(mc.polyListComponentConversion(uv1, fuv=True, te=True), fl=True)
e2 = mc.ls(mc.polyListComponentConversion(g, fuv=True, te=True), fl=True)
se = list(set(e1) & set(e2))
if len(se):
#There is
ed = mc.ls(mc.polyListComponentConversion(se[0], fe=True, tuv=True), fl=True)
keepUVs = []
for e in range(len(ed)):
if ed[e] in uvGrowSel and ed[e] in orgSel:
keepUVs.append(ed[e])
if len(keepUVs) == 2:
addToEdges(keepUVs[0], keepUVs[1])
return edges
def sortEdges(edges, max_angle):
hz_edges = {}
vt_edges = {}
for e in edges:
if not e in hz_edges.values() and not e in vt_edges.values():
angle = findAngle(edges[e])
#if not uvTup1 in edges.values() and not uvTup2 in edges.values(): edges[len(edges)] = uvTup1
if angle < 0:
angle = angle*-1
#hoizontal
if angle < 45 and angle >= 0:
if angle < max_angle:
hz_edges[len(hz_edges)] = edges[e]
elif angle >= 135 and angle < 180:
if angle > 180-max_angle:
hz_edges[len(hz_edges)] = edges[e]
#vertical
elif angle < 135 and angle >= 45:
if angle < 90 and angle > 90-max_angle:
vt_edges[len(vt_edges)] = edges[e]
elif angle > 90 and angle < 90+max_angle:
vt_edges[len(vt_edges)] = edges[e]
return hz_edges,vt_edges