utils.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  1. # coding:utf-8
  2. #!/usr/bin/python
  3. #
  4. # Copyright (c) Contributors to the Open 3D Engine Project.
  5. # For complete copyright and license terms please see the LICENSE at the root of this distribution.
  6. #
  7. # SPDX-License-Identifier: Apache-2.0 OR MIT
  8. #
  9. #
  10. # -------------------------------------------------------------------------
  11. """
  12. azpy.dcc.maya.helpers.utils utility module
  13. """
  14. # -------------------------------------------------------------------------
  15. # built in's
  16. # none
  17. # 3rd Party
  18. # none
  19. # Lumberyard extensions
  20. from azpy import initialize_logger
  21. from azpy.env_bool import env_bool
  22. from azpy.constants import ENVAR_DCCSI_GDEBUG
  23. from azpy.constants import ENVAR_DCCSI_DEV_MODE
  24. # maya imports
  25. import maya.cmds as cmds
  26. # -------------------------------------------------------------------------
  27. # -------------------------------------------------------------------------
  28. # -- Misc Global Space Definitions
  29. _DCCSI_GDEBUG = env_bool(ENVAR_DCCSI_GDEBUG, False)
  30. _DCCSI_DEV_MODE = env_bool(ENVAR_DCCSI_DEV_MODE, False)
  31. _PACKAGENAME = __name__
  32. if _PACKAGENAME == '__main__':
  33. _PACKAGENAME = 'azpy.dcc.maya.helpers.utils'
  34. _LOGGER = initialize_logger(_PACKAGENAME, default_log_level=int(20))
  35. _LOGGER.debug('Invoking:: {0}.'.format({_PACKAGENAME}))
  36. # -------------------------------------------------------------------------
  37. # -------------------------------------------------------------------------
  38. # Initiate the Wing IDE debug connection.
  39. if _DCCSI_GDEBUG:
  40. #import azpy.dev.connectDebugger as lyDevConnnect
  41. # lyDevConnnect()
  42. pass
  43. # -------------------------------------------------------------------------
  44. # =========================================================================
  45. # First Class
  46. # =========================================================================
  47. class Selection(object):
  48. '''
  49. Custom Class to handle selection data as well as helper commands
  50. to use/parse the selection data
  51. '''
  52. component_prefixes = {0: 'vtx', 1: 'e', 2: 'f', 3: 'map', 4: 'vtxFace'}
  53. #----------------------------------------------------------------------
  54. def __init__(self):
  55. self.selection = dict()
  56. self._populate_selection_data()
  57. #----------------------------------------------------------------------
  58. #----------------------------------------------------------------------
  59. def _populate_cpv_data(self):
  60. '''
  61. Color per-vertex data
  62. Populates a dictionary:
  63. color/alpha key -> vtxFace list
  64. '''
  65. for obj in self.selection.keys():
  66. rgba_dict = dict()
  67. if not cmds.listRelatives( obj, shapes = True ) :
  68. self.selection[obj].append( rgba_dict )
  69. continue
  70. selection_list = []
  71. selection_list = self.get_vtx_face_list( obj )
  72. if len(selection_list) == 0:
  73. # build attribute fetch
  74. attrTag = '{0}.{1}'.format( obj, "vtxFace[*][*]")
  75. # objects vtxFaceList
  76. obj_vtx_faces = cmds.polyListComponentConversion(attrTag,
  77. toVertexFace=True)
  78. selection_list = cmds.ls( obj_vtx_faces,
  79. long = True,
  80. flatten = True )
  81. for vtx_face in selection_list:
  82. # get color RGB values
  83. try:
  84. # query the color
  85. color_list = cmds.polyColorPerVertex( vtx_face,
  86. query = True,
  87. colorRGB = True)
  88. except:
  89. # if no color, assign balck
  90. cmds.polyColorPerVertex( obj,
  91. colorRGB = [0,0,0],
  92. alpha = True)
  93. color_list = cmds.polyColorPerVertex(vtx_face,
  94. query=True,
  95. colorRGB=True)
  96. # and get alpha values
  97. alpha = cmds.polyColorPerVertex(vtx_face,
  98. query = True,
  99. alpha = True)
  100. # tuple up color and alpha
  101. rgba = ( color_list[0], color_list[1], color_list[2], alpha[0] )
  102. if rgba not in rgba_dict :
  103. rgba_dict[rgba] = []
  104. rgba_dict[rgba].append( vtx_face )
  105. self.selection[obj].append( rgba_dict )
  106. #----------------------------------------------------------------------
  107. #----------------------------------------------------------------------
  108. def _make_component_dict(self, component_list):
  109. '''Populates a dictionary of selected components of the given type'''
  110. component = dict()
  111. if not component_list:
  112. return component
  113. for comp in component_list :
  114. # parent of this dag node
  115. par = cmds.listRelatives( comp, parent = True, fullPath = True)[0]
  116. # get transform
  117. transform = cmds.listRelatives( par, parent = True, fullPath = True)[0]
  118. # To Do: explain what this does
  119. comp_num = comp.split('[')[-1].split(']')[0]
  120. if transform not in component:
  121. component[transform] = []
  122. component[transform].append(comp)
  123. return component
  124. #----------------------------------------------------------------------
  125. #----------------------------------------------------------------------
  126. def _fill_with_component_dict(self, component_type):
  127. '''
  128. Wrapper class for making a component dictionary
  129. Takes in a component type:
  130. http://download.autodesk.com/us/maya/2011help/CommandsPython/filterExpand.html
  131. '''
  132. sel_objs = []
  133. component_dict = dict()
  134. components_from_type = cmds.filterExpand(expand=True,
  135. fullPath=True,
  136. selectionMask=component_type)
  137. # pack component dict
  138. component_dict = self._make_component_dict( components_from_type )
  139. try:
  140. sel_objs += self.selection.keys()
  141. except:
  142. pass
  143. try:
  144. sel_objs += component_dict.keys()
  145. except:
  146. pass
  147. sel_objs = set(sel_objs)
  148. for obj in sel_objs:
  149. if obj not in self.selection.keys() :
  150. self.selection[obj] = []
  151. if obj in component_dict:
  152. self.selection[obj].append( component_dict[obj] )
  153. else:
  154. self.selection[obj].append( None )
  155. #----------------------------------------------------------------------
  156. #----------------------------------------------------------------------
  157. def _populate_selection_data(self):
  158. '''Main population method for filling the class with all the selection data'''
  159. #Vertices - Edges - Faces - UVs - VtxFace - Color To VtxFace
  160. #Final Selection Dictionary Map
  161. sel_objs = []
  162. try:
  163. sel_objs += cmds.ls( selection = True, transforms = True, long = True )
  164. except:
  165. pass
  166. try:
  167. sel_objs += cmds.ls( hilite = True, long = True )
  168. except:
  169. pass
  170. sel_objs = set( sel_objs )
  171. for obj in sel_objs :
  172. self.selection[obj] = []
  173. self._fill_with_component_dict(31) # Polygon Vertices
  174. self._fill_with_component_dict(32) # Polygon Edges
  175. self._fill_with_component_dict(34) # Polygon Face
  176. self._fill_with_component_dict(35) # Polygon UVs
  177. self._fill_with_component_dict(70) # Polygon Vertex Face
  178. self._populate_cpv_data()
  179. #----------------------------------------------------------------------
  180. #----------------------------------------------------------------------
  181. def store_selection(self):
  182. '''Takes current selection and populates the class with the selection data'''
  183. self.selection = dict()
  184. self._populate_selection_data()
  185. #----------------------------------------------------------------------
  186. #----------------------------------------------------------------------
  187. def prettyprint(self):
  188. '''Pretty Print method to inspect the selection data'''
  189. crossbar_str = '{0}'.format('*' * 75)
  190. print ( crossbar_str )
  191. print ( '~ Begin Selection Data Output...' )
  192. for key, value in self.selection.items() :
  193. print(key)
  194. #This is less explict but allows for expansion easier, lets test it out for a while
  195. for itemSet in value:
  196. print(' ', itemSet)
  197. #print ' vtx - ', value[0]
  198. #print ' edg - ', value[1]
  199. #print ' face - ', value[2]
  200. #print ' UV - ', value[3]
  201. #print ' vtx-face - ', value[4]
  202. #print ' colorDict - ', value[5]
  203. print ( crossbar_str )
  204. #----------------------------------------------------------------------
  205. #----------------------------------------------------------------------
  206. def select(self, obj, component_type, clear_selection=True, add_value=False):
  207. '''Allow easy reselection of specific selection data'''
  208. cmds.select( clear = clear_selection )
  209. if self.selection[obj][component_type] != None :
  210. cmds.hilite( obj )
  211. cmds.select(self.selection[obj][component_type], add=add_value)
  212. #----------------------------------------------------------------------
  213. #----------------------------------------------------------------------
  214. def restore_selection(self):
  215. '''Restores the selection back to how it was when the class populated its selection data'''
  216. cmds.select( clear = True)
  217. for obj in self.selection.keys() :
  218. cmds.select( obj, add = True )
  219. self.select( obj, 0, 0, add_value = True )
  220. self.select( obj, 1, 0, add_value = True )
  221. self.select( obj, 2, 0, add_value = True )
  222. self.select( obj, 3, 0, add_value = True )
  223. #----------------------------------------------------------------------
  224. #----------------------------------------------------------------------
  225. def get_vtx_face_list(self, obj):
  226. '''Turns all current selection data into a vtxFace selection list'''
  227. selection_list = set()
  228. # To Do: explain what this does
  229. for index in range(0, 2):
  230. sel_part = self.selection[obj][index]
  231. try:
  232. sel = cmds.polyListComponentConversion( sel_part, toVertexFace = True)
  233. selection_list.update( cmds.ls( sel, long = True, flatten = True) )
  234. except:
  235. pass
  236. # To Do: explain what this does
  237. try:
  238. selection_list.update( self.selection[obj][4] )
  239. except:
  240. pass
  241. return list(selection_list)
  242. #----------------------------------------------------------------------
  243. #----------------------------------------------------------------------
  244. def get_first_mesh(self):
  245. '''Returns the first mesh it finds in the selection list'''
  246. for item in self.selection.keys() :
  247. if cmds.listRelatives( item, shanpes = True ) :
  248. return item
  249. #----------------------------------------------------------------------
  250. #----------------------------------------------------------------------
  251. def get_component_list(self, obj, component_index=0):
  252. if self.selection[obj][component_index] == None : # Return all
  253. component_tag = '{0}.{1}[*]'.format(obj, self.component_prefixes[component_index])
  254. return cmds.ls( component_tag, long = True, flatten = True )
  255. else:
  256. return self.selection[obj][component_index]
  257. #----------------------------------------------------------------------
  258. #----------------------------------------------------------------------
  259. def get_component_index(self, obj, component_index=0):
  260. index_list = []
  261. if self.selection[obj][component_index] :
  262. for comp in self.selection[obj][component_index] :
  263. component_number = comp.split('[')[-1].split(']')[0]
  264. index_list.append(component_number)
  265. return index_list
  266. #----------------------------------------------------------------------
  267. #----------------------------------------------------------------------
  268. def get_inverse_component_index(self, obj, component_index=0):
  269. ''''''
  270. index_list = []
  271. full_component_list = []
  272. if self.selection[obj][component_index] :
  273. working = self.selection[obj][component_index]
  274. sel_component_list = cmds.ls(working, long=True, flatten=True)
  275. component_tag = '{0}.{1}[*]'.format(obj, self.component_prefixes[component_index])
  276. full_component_list = cmds.ls( component_tag, long = True, flatten = True)
  277. for comp in [comp for comp in full_component_list if comp not in sel_component_list ] :
  278. component_number = comp.split('[')[-1].split(']')[0]
  279. index_list.append(component_number)
  280. return index_list
  281. #----------------------------------------------------------------------
  282. # ----------------------------------------------------------------------
  283. def get_object_attributes(self, obj):
  284. attribute_list = {}
  285. for attr in cmds.listAttr(obj):
  286. target_string = f'{obj}.{attr}'
  287. try:
  288. attr_value = cmds.getAttr(target_string)
  289. if attr_value:
  290. attribute_list[attr] = attr_value
  291. else:
  292. attribute_list[attr] = ''
  293. except RuntimeError:
  294. pass
  295. except ValueError:
  296. pass
  297. for key, value in attribute_list.items():
  298. print(f'AttributeName: {key} : Value: {value}')
  299. # ----------------------------------------------------------------------
  300. # -------------------------------------------------------------------------
  301. #==========================================================================
  302. # Class Test
  303. #==========================================================================
  304. if __name__ == '__main__':
  305. # get a selection object
  306. sel = Selection()
  307. # to do: this needs some tests?