Files
Nexus/2025/scripts/modeling_tools/ModIt/Modeling/Section_SELECTIONS.py
2026-01-22 00:06:13 +08:00

434 lines
16 KiB
Python

##--------------------------------------------------------------------------
# Import Qt from project's unified Qt.py module
import sys as _sys
import os as _os
# Add parent scripts directory to sys.path
_modit_dir = _os.path.dirname(_os.path.abspath(__file__))
_scripts_dir = _modit_dir
while _os.path.basename(_scripts_dir) != 'scripts' and _scripts_dir != _os.path.dirname(_scripts_dir):
_scripts_dir = _os.path.dirname(_scripts_dir)
if _scripts_dir not in _sys.path:
_sys.path.insert(0, _scripts_dir)
from Qt import QtWidgets, QtCore, QtGui, QtCompat
# Use QtCompat for cross-version compatibility
wrapInstance = QtCompat.wrapInstance
QIcon = QtGui.QIcon
QWidget = QtWidgets.QWidget
from maya import cmds as mc
import maya.mel as mel
import json
import os
import maya.cmds as cmds
from functools import partial
import importlib
from .. import ModIt_Global
importlib.reload(ModIt_Global)
from .. import ModIt_CSS
importlib.reload(ModIt_CSS)
##______________________GLOBAL VAR
##PATH_SET
IconPath = ModIt_Global.IconsPathThemeClassic
PreferencePath = ModIt_Global.PreferencePath
ToolsPath = ModIt_Global.ToolPath
# ******************************************
# BUTTONS PARAMS
# ******************************************
iconFixeSize = 32
iconButtonSize = 30
separatorWidth = ModIt_Global.separatorWidth
##JSON PREF DATA
PRIM_MODE =(json.load(open(PreferencePath + 'Setting_Primitives_Placement.json',"r"))['PRIM_MODE'])
PRIM_SIZE =(json.load(open(PreferencePath + 'Setting_Primitives_Size.json',"r"))['PRIM_SIZE'])
class MyCustomBtn_Widget_forIcon(QtWidgets.QPushButton):
def __init__(self, iconPath):
super().__init__()
#FOR ICON HOVER EFFECT
pix_normal = QtGui.QPixmap(iconPath)
pix_over = pix_normal.copy()
painter = QtGui.QPainter(pix_over)
painter.fillRect(pix_over.rect(), QtGui.QColor(250, 250, 250, 40))
painter.setCompositionMode(QtGui.QPainter.CompositionMode_Plus)
painter.end()
self._icon_normal = QIcon(pix_normal)
self._icon_over = QIcon(pix_over)
self.setIcon(self._icon_normal)
#FOR CONTEXT MENU
self.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
def enterEvent(self, event): #ICON
self.setIcon(self._icon_over)
return super(MyCustomBtn_Widget, self).enterEvent(event)
def leaveEvent(self, event): #ICON
self.setIcon(self._icon_normal)
return super(MyCustomBtn_Widget, self).leaveEvent(event)
def mousePressEvent(self, event): #CONTEXT MENUE
super().mousePressEvent(event)
if event.button() == QtCore.Qt.RightButton:
# emit the signal, we can grab the pos directly from the event, no need to get cursor position anymore
self.customContextMenuRequested.emit(event.pos())
# make a call to mouseRelease event to restore button back to its original state
self.mouseReleaseEvent(event)
class MyCustomBtn_Widget(QtWidgets.QPushButton):
def __init__(self):
super().__init__()
self.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
def mousePressEvent(self, event):
super().mousePressEvent(event)
if event.button() == QtCore.Qt.RightButton:
# emit the signal, we can grab the pos directly from the event, no need to get cursor position anymore
self.customContextMenuRequested.emit(event.pos())
# make a call to mouseRelease event to restore button back to its original state
self.mouseReleaseEvent(event)
class SELECTIONS_LAYOUT(QtWidgets.QWidget):
def __init__(self, parent=None):
super().__init__(parent=parent)
SECTION_SELECTIONS_LAYOUT = QtWidgets.QHBoxLayout() # MAIN
SECTION_SELECTIONS_LAYOUT.setContentsMargins(0,0,0,0)
SECTION_SELECTIONS_LAYOUT.setSpacing(0)
self.setLayout(SECTION_SELECTIONS_LAYOUT)
##---------------------------------------------------- ALIGN PIVOT
self.AlignPivotFace_btn = MyCustomBtn_Widget()
self.AlignPivotFace_btn.setFixedSize(iconFixeSize, iconFixeSize)
self.AlignPivotFace_btn.setIconSize(QtCore.QSize(iconButtonSize, iconButtonSize))
self.AlignPivotFace_btn.setIcon(QtGui.QIcon(IconPath + "AlignFace.png"))
self.AlignPivotFace_btn.setToolTip(" Align and Bake Object Pivot based on Face Normals ")
self.AlignPivotFace_btn.clicked.connect(self.alignPivotFace)
##---------------------------------------------------- CONTINUS EDGE
self.ContinusEdge_btn = MyCustomBtn_Widget()
self.ContinusEdge_btn.setFixedSize(iconFixeSize, iconFixeSize)
self.ContinusEdge_btn.setIconSize(QtCore.QSize(iconButtonSize, iconButtonSize))
self.ContinusEdge_btn.setIcon(QtGui.QIcon(IconPath + "ContinusEdge.png"))
self.ContinusEdge_btn.setToolTip(" Select All Perimeter Contiguous Edge Until +45° angle ")
self.ContinusEdge_btn.clicked.connect(self.continusEdges)
##---------------------------------------------------- SELECT INNER
self.SelIn_btn = QtWidgets.QPushButton()
self.SelIn_btn.setFixedSize(iconFixeSize, iconFixeSize)
self.SelIn_btn.setIconSize(QtCore.QSize(iconButtonSize, iconButtonSize))
self.SelIn_btn.setIcon(QtGui.QIcon(IconPath + "SelIco1b.png"))
self.SelIn_btn.setToolTip(" Select Inner Faces ")
self.SelIn_btn.clicked.connect(self.selInner)
##---------------------------------------------------- SELECT INNER + SELECTION
self.SelInAndSel_btn = QtWidgets.QPushButton()
self.SelInAndSel_btn.setFixedSize(iconFixeSize, iconFixeSize)
self.SelInAndSel_btn.setIconSize(QtCore.QSize(iconButtonSize, iconButtonSize))
self.SelInAndSel_btn.setIcon(QtGui.QIcon(IconPath + "SelIco1.png"))
self.SelInAndSel_btn.setToolTip(" Select Inner Faces and Keep Selection ")
self.SelInAndSel_btn.clicked.connect(self.selInnerPlus)
##---------------------------------------------------- NX Edge
self.EdgeNx_btn = MyCustomBtn_Widget()
self.EdgeNx_btn.setFixedSize(iconFixeSize, iconFixeSize)
self.EdgeNx_btn.setIconSize(QtCore.QSize(iconButtonSize, iconButtonSize))
self.EdgeNx_btn.setIcon(QtGui.QIcon(IconPath + "SelIco3.png"))
self.EdgeNx_btn.setToolTip(" Select Every X Edges ")
self.EdgeNx_btn.clicked.connect(partial(self.selEdgeNX, "edgeLoop", 2))
# C O N N E C T P O P U P M E N U T O O U R B U T T O N
self.EdgeNx_btn.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.EdgeNx_btn.customContextMenuRequested.connect(self.showPopupNedge)
# CUBE M E N U I T E M S
self.popupMenuNedge = QtWidgets.QMenu()
Loop_2 = self.popupMenuNedge.addAction(" > Loop : Select 1 Edge each 2 Edges")
Loop_3 = self.popupMenuNedge.addAction(" > Loop : Select 1 Edge each 3 Edges")
Loop_4 = self.popupMenuNedge.addAction(" > Loop : Select 1 Edge each 4 Edges")
Loop_2.triggered.connect(partial(self.selEdgeNX, "edgeLoop", 2))
Loop_3.triggered.connect(partial(self.selEdgeNX, "edgeLoop", 3))
Loop_4.triggered.connect(partial(self.selEdgeNX, "edgeLoop", 4))
Ring_2 = self.popupMenuNedge.addAction(" > Ring : Select 1 Edge each 2 Edges")
Ring_3 = self.popupMenuNedge.addAction(" > Ring : Select 1 Edge each 3 Edges")
Ring_4 = self.popupMenuNedge.addAction(" > Ring : Select 1 Edge each 4 Edges")
Ring_2.triggered.connect(partial(self.selEdgeNX, "edgeRing", 2))
Ring_3.triggered.connect(partial(self.selEdgeNX, "edgeRing", 3))
Ring_4.triggered.connect(partial(self.selEdgeNX, "edgeRing", 4))
##---------------------------------------------------- CHECK FACES
self.CheckFace_btn = MyCustomBtn_Widget()
self.CheckFace_btn.setFixedSize(iconFixeSize, iconFixeSize)
self.CheckFace_btn.setIconSize(QtCore.QSize(iconButtonSize, iconButtonSize))
self.CheckFace_btn.setIcon(QtGui.QIcon(IconPath + "SelIco2.png"))
self.CheckFace_btn.setToolTip(" Select Object Faces By Type ")
self.CheckFace_btn.clicked.connect(self.checkNGon)
# C O N N E C T P O P U P M E N U T O O U R B U T T O N
self.CheckFace_btn.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.CheckFace_btn.customContextMenuRequested.connect(self.showPopupCheck)
# CUBE M E N U I T E M S
self.popupMenuCube = QtWidgets.QMenu()
Ngons = self.popupMenuCube.addAction(" Select all NGons faces on the selected mesh")
Quad = self.popupMenuCube.addAction(" Select all Quadrangles faces on the selected mesh")
Tri = self.popupMenuCube.addAction(" Select all Triangles faces on the selected mesh")
Concave = self.popupMenuCube.addAction(" Select all Concaves faces on the selected mesh")
Ngons.triggered.connect(self.checkNGon)
Quad.triggered.connect(self.checkQuad)
Tri.triggered.connect(self.checkTri)
Concave.triggered.connect(self.checkNConcave)
##---------------------------------------------------- Add to Layout
SECTION_SELECTIONS_LAYOUT.addWidget(self.AlignPivotFace_btn)
SECTION_SELECTIONS_LAYOUT.addWidget(self.ContinusEdge_btn)
SECTION_SELECTIONS_LAYOUT.addWidget(self.SelIn_btn)
SECTION_SELECTIONS_LAYOUT.addWidget(self.SelInAndSel_btn)
SECTION_SELECTIONS_LAYOUT.addWidget(self.EdgeNx_btn)
SECTION_SELECTIONS_LAYOUT.addWidget(self.CheckFace_btn)
#------------------------------------------------
##---------------------------------------------------- D E F I N I T I O N
#------------------------------------------------
def BAM(self):
print("BAMMM")
def showPopupNedge(self, position):
self.popupMenuNedge.exec_(self.EdgeNx_btn.mapToGlobal(position))
self.EdgeNx_btn.update()
def showPopupCheck(self, position):
self.popupMenuCube.exec_(self.CheckFace_btn.mapToGlobal(position))
self.CheckFace_btn.update()
def Clean(self):
mc.sets(n="selInnerPlusSet1")
mc.sets(add="selInnerPlusSet1")
mc.SelectFacetMask()
mc.polyUVSet(d=True, uvSet="ModIt_UvLayout")
mc.select(clear=True)
mc.select("selInnerPlusSet1")
mc.delete("selInnerPlusSet1")
def CleanPluss(self):
mc.sets(n="selInnerPlusSet1")
mc.sets(add="selInnerPlusSet1")
mc.SelectFacetMask()
mc.polyUVSet(d=True, uvSet="ModIt_UvLayout")
mc.select(clear=True)
mc.select("selInnerPlusSet1")
mc.delete("selInnerPlusSet1")
mc.GrowPolygonSelectionRegion()
def selInner(self):
#Verif Selection is Face
checkSelectedComponent = mc.filterExpand(sm=34)
if checkSelectedComponent == None:
ModIt_Global.WarningWindow(" You should select Faces.", 300)
return
mc.undoInfo(openChunk=True, infinity=True)
selFace= mc.ls(sl=True)
selObj = cmds.ls(sl=1, fl=1, o=1)
mc.polyProjection (selObj, ch=1, type= "Planar", ibd = False, cm= True, uvSetName = "ModIt_UvLayout", kir = True, md= "c")
mc.polyUVSet(cuv= True, uvSet = "ModIt_UvLayout")
selEdgePeri = mc.ConvertSelectionToEdgePerimeter()
mc.polyMapCut()
mc.SelectMeshUVShell()
mc.scriptJob( runOnce=True, e = ["SelectionChanged", self.Clean])
mc.undoInfo(closeChunk=True)
def selInnerPlus(self):
#Verif Selection is Face
checkSelectedComponent = mc.filterExpand(sm=34)
if checkSelectedComponent == None:
ModIt_Global.WarningWindow(" You should select Faces.", 300)
return
mc.undoInfo(openChunk=True, infinity=True)
selFace=mc.ls(sl=True)
selObj = cmds.ls(sl=1, fl=1, o=1)
mc.polyProjection (selObj, ch=1, type= "Planar", ibd = False, cm= True, uvSetName = "ModIt_UvLayout", kir = True, md= "c")
mc.polyUVSet(cuv= True, uvSet = "ModIt_UvLayout")
selEdgePeri = mc.ConvertSelectionToEdgePerimeter()
mc.polyMapCut()
mc.SelectMeshUVShell()
mc.scriptJob( runOnce=True, e = ["SelectionChanged", self.CleanPluss])
mc.undoInfo(closeChunk=True)
def selEdgeNX(self, type, nbr):
mel.eval('polySelectEdgesEveryN "%s" %s;' % (type, nbr))
def checkNGon(self):
mc.selectMode(q=True, co=True)
mc.polySelectConstraint(m=3 ,t = 0x0008, sz=3)
mc.polySelectConstraint(dis=True)
def checkTri(self):
mc.selectMode(q=True, co=True)
mc.polySelectConstraint(m=3 ,t = 0x0008, sz=1)
mc.polySelectConstraint(dis=True)
def checkQuad(self):
mc.selectMode(q=True, co=True)
mc.polySelectConstraint(m=3 ,t = 0x0008, sz=2)
mc.polySelectConstraint(dis=True)
def checkNConcave(self):
mc.selectMode(q=True, co=True)
mc.polySelectConstraint(m=3 ,t = 0x0008, c=1)
mc.polySelectConstraint(dis=True)
def alignPivotFace(self):
#Verif Selection is Face
checkSelectedComponent = mc.filterExpand(sm=34)
if checkSelectedComponent == None:
ModIt_Global.WarningWindow(" Works on Face mode only.", 300)
return
else:
mc.undoInfo(openChunk=True, infinity=True)
mc.setToolTo('Move')
getPivotPos = mel.eval("float $getPivotPos[] = `manipMoveContext -q -p Move`;")
mel.eval("ConvertSelectionToVertices;")
vtxSel = mc.ls(fl=1, sl=1)
selectedObjectStore = mc.ls(o=1, sl=1)
objectSelectionStore = mc.listRelatives(selectedObjectStore[0], p=1)
if len(vtxSel) < 3:
mc.warning("ModIt : Please select at least 3 Vertices, 2 Edges or 1 Face")
plane = mc.polyPlane(cuv=2, sy=1, sx=1, h=1, n='rotationPlane', ch=1, w=1, ax=(0, 1, 0))
mc.select((plane[0] + ".vtx[0:2]"), vtxSel[0], vtxSel[1], vtxSel[2])
mel.eval("snap3PointsTo3Points(0)")
mc.parent(objectSelectionStore, plane[0])
mc.makeIdentity(objectSelectionStore, apply=True, s=0, r=1, t=0, n=0)
mc.xform(ws=1, piv=(getPivotPos[0], getPivotPos[1], getPivotPos[2]))
mc.parent(objectSelectionStore, world=1)
mc.delete(plane)
mc.undoInfo(closeChunk=True)
def continusEdges(self):
#Verif Selection is Edge
checkSelectedComponent = mc.filterExpand(sm=32)
if checkSelectedComponent == None:
ModIt_Global.WarningWindow(" You should select a border edge.", 300)
return
else:
mc.undoInfo(openChunk=True, infinity=True)
# 1 - Continus Edge
mc.SelectContiguousEdges()
# 2 - Store Continus Set
mc.sets(n="ModIt_SelContinus_tempSet")
# Need to get select objectq
mc.SelectVertexMask()
mc.SelectToggleMode()
objSel = mc.ls(sl=True)
# GET ALL FACE
list = mc.ls(sl=True)
for item in list:
fCount = mc.polyEvaluate(v=True)
mc.select(cl=True)
mc.select(item + '.f[0:' + str(fCount) + ']', add=True)
# CONVERT IN EDGE
mc.ConvertSelectionToContainedEdges()
mc.sets(n="ModIt_IntEdges_tempSet")
mc.select(mc.sets('ModIt_IntEdges_tempSet', sub="ModIt_SelContinus_tempSet"))
mc.sets(n="ModIt_GoodSel")
mc.select(d=True)
obSelName = str(objSel[0])
mel.eval('doMenuComponentSelectionExt(" ' + obSelName + '", "edge", 0);')
mc.select("ModIt_GoodSel")
mc.delete("ModIt_IntEdges_tempSet")
mc.delete("ModIt_SelContinus_tempSet")
mc.delete("ModIt_GoodSel")