Maya Python Script - Problem with Functions and Radio Button


#1

Hi guys, I’m new in programming. I would like to generate a parametric dome to calculate some kind of stresses and to visualize these stresses on the dome with different colors.
Now I defined a function ( called ‘S()’ ) that generates a dome by some parameters controlled by sliders. but I don’t find a way to execute two others different functions ( ‘T()’ , V() ) to control the color of the surface. These two functions have to be executed by radiobuttons.
Thanks to all for the help!

import maya.cmds as cmds
import numpy as np
#if cmds.window(ram, exists=True): #ogni volta che lancio il programma si cancella la finestra creata in precedenza
    #cmds.deleteUI(ram)
angolo= range(10,360,10)
#Definisco una cupola fittizia per poter generare le altre
cmds.circle(nr=(1, 0, 0), c=(0, 0, 0), sw=-90, r=0, n="S1")
cmds.rotate(0,0,0) 
cupola1=[]
for i in range (35):
    cmds.duplicate()
    cmds.rotate(0,angolo[i],0)
    cupola1=cupola1+["S"+str(i+1)]
cmds.loft(cupola1, ['S36','S1'])
cmds.delete(cupola1, ['S36','S1'])

cmds.nurbsToPoly('loftedSurface1', name='pippo', mnd=1,  ch=1, f=0, pt=0, pc=500, chr=0.9, ft=0.01, mel=0.001, d=0.1, ut=1, un=3, vt=1, vn=3, uch=0, ucr=0, cht=0.2,es=0,ntr=0,mrt=0,uss=1)
cmds.delete('loftedSurface1')


#Definisco la finestra di output
ram = cmds.window('Volte Sottili', t='Volte Sottili', w=300, h=300, sizeable = False) #definisco una finestra con il nome e le dimensioni
cmds.columnLayout(adj=True)
#imagePath = cmds.internalVar(upd = True)+'icons/img1.jpg'
#cmds.image(w=200, h=100, image = imagePath)
cmds.separator(h=20)
cmds.text('Parametri')
cmds.separator(h=20)

#Slider dei Parametri
radius2 = cmds.intSliderGrp(l = 'Radius [m]', min = 0.1, max = 50, field = True, dc='S()')
gamma2 = cmds.intSliderGrp(l = 'Peso specifico [KN/mc]', min = 0, max = 50, field = True, dc='S()')
spess2 = cmds.intSliderGrp(l = 'Spessore [m]', min = 0.1, max = 1, field = True, dc='S()')
sweep2 = cmds.intSliderGrp(l = 'Angolo [gradi]', min = 10, max = 90, value=90, field = True, dc='S()')
cmds.separator(h=20)
cmds.text('Solution Plot2')
cmds.separator(h=20)

cmds.showWindow(ram)


def S():
    cmds.delete('pippo') 
       
    #Parametri della superficie
    radius = cmds.intSliderGrp(radius2, q = True, value = True) #metri      
    gamma = cmds.intSliderGrp(gamma2, q = True, value = True) #KN/mc
    spess = cmds.intSliderGrp(spess2, q = True, value = True) #metri   
    sweep = cmds.intSliderGrp(sweep2, q = True, value = True)
    
    C = 1 #Ampiezza (dipende dal vincolo, consideriamo un carrello, C=1)
    delta = 0 #Sfasamento (dipende dal vincolo, consideriamo un carrello, delta=0)
    poisson = 0.15 #coeff. di poisson (dipende dal materiale)
           
    #Definisco la cupola
    angolo = range(10,360,10)  #angolo di rotazione dei semiarchi
    cmds.circle(nr = (1, 0, 0), c = (0, 0, 0), sw = -sweep, r = radius, n="S1")
    cmds.rotate(0,0,0)
    cmds.move(0,0,0) 
    cupola1 = []
    for i in range (35):
        cmds.duplicate()
        cmds.rotate(0,angolo[i],0)
        cupola1 = cupola1 + ["S"+str(i+1)]
    cmds.loft(cupola1, ['S36','S1'])
    cmds.delete(cupola1, ['S36','S1'])
    
    #Trasformo il loft(NURBS) in una polisuperficie
    cmds.nurbsToPoly('loftedSurface1', name='pippo', mnd=1,  ch=1, f=0, pt=0, pc=500, chr=0.9, ft=0.01, mel=0.001, d=0.1, ut=1, un=3, vt=1, vn=3, uch=0, ucr=0, cht=0.2,es=0,ntr=0,mrt=0,uss=1)
    
    cmds.delete('loftedSurface1')

    #Analizzo il numero di punti della superficie
    n = cmds.polyEvaluate('pippo', v=True, f=False)
    
    #Definisco un vettore vertex lungo quanto il numero dei punti della superficie
    vertex = np.zeros((n,3))
    angolo = np.zeros(n) #parte dalla base
    angolo_complementare = np.zeros(n) #parte dall'asse
    stress = np.zeros(n)
    stress_adm = np.zeros(n)
    vertex_adm = np.zeros((n,3))
     
    #Mi tiro fuori le coordinate xyz dei punti appartenenti alla superficie  
    for i in range(n):
        vertex[i,:]=(cmds.pointPosition('pippo.pt[%d]' %i))           
    
    #Calcolo lo sforzo normale di meridiano   
    for i in range(n):
        lato = np.sqrt(vertex[i,0]**2+vertex[i,2]**2) #trovo il lato in pianta
        diagonale = np.sqrt(lato**2+vertex[i,1]**2) #trovo la diagonale
        angolo[i] = abs(np.arcsin(vertex[i,1]/diagonale)*180/np.pi) #trovo l'angolo (omega), in gradi
        angolo_complementare[i] = (90-angolo[i])*np.pi/180 
        stress[i] = abs(-gamma*spess*radius*(1-np.cos(angolo_complementare[i]))/(np.sin(angolo_complementare[i]**2)))
        
    #Calcolo lo sforzo normale adimensionale   
    where_are_NaNs = np.isnan(stress)
    stress[where_are_NaNs] = 12 #quando ho valori non validi li sostituisco
    
    stress_max = np.amax(stress)
    for i in range(n):
        stress_adm[i] = stress[i]/stress_max
    
    vertex_max = np.amax(vertex[i][1])    
    for i in range(n):
        vertex_adm[i][1] = vertex[i][1]/vertex_max
        
    cmds.delete('loftedSurface1')
    
    #for i in range(n):
            #cmds.polyColorPerVertex('pippo.vtx[%d]'%i, rgb=(stress_adm[i], 0.5, 0.5))

    cmds.setAttr("pippo.displayColors",  1)
    cmds.refresh()
    cmds.select('pippo', d=True)
    
def T():
    for i in range(n):
            cmds.polyColorPerVertex('pippo.vtx[%d]'%i, rgb=(stress_adm[i], 0.5, 0.5))
            
    
    cmds.setAttr("pippo.displayColors",  1)
    cmds.refresh()
    cmds.select('pippo', d=True)
    
    
def V():
    for i in range(n):
            cmds.polyColorPerVertex('pippo.vtx[%d]'%i, rgb=(vertex_adm[i][1], 0.5, 0.5))
            
    
    cmds.setAttr("pippo.displayColors",  1)
    cmds.refresh()
    cmds.select('pippo', d=True)
    
        
         
cmds.rowColumnLayout(numberOfColumns=4, columnWidth=[(1,75), (2,25), (3,75), (4,25), (5,200)], columnOffset=[(1,'both', 3)])
cmds.radioCollection()     
StressColore2 = cmds.radioButton(label = 'StressColore', editable = True, onCommand = T)
cmds.separator(h=10, style='none')
VerticeColore = cmds.radioButton(label = 'VerticeColore', editable = True, onCommand = V)
cmds.separator(h=10, style='none')

#2

Hey, if I’m understanding correctly, you want radio buttons that fire off different functions? You’ll need a radio collection layout to hold the 2 buttons. Each of the radio buttons should have an onCommand parameter that triggers when that button is selected. You can also use the offCommand parameter if you need to do any sort of cleanup when the other is selected. This code is a basic radio button setup. It’s up to you to change things to fit your own needs. All of this can be found on Autodesk’s command help pages.

https://download.autodesk.com/us/maya/2011help/CommandsPython/radioButton.html

from maya import cmds

def T(*args):
    print 'T function runs'

def V(*args):
    print 'V function runs'

if cmds.window('testUI', exists=1):
    cmds.deleteUI('testUI')
cmds.window ('testUI')
cmds.rowLayout(nc=5)
cmds.radioCollection()
r1 = cmds.radioButton( label='T function', onCommand=T)
r2 = cmds.radioButton( label='V function', onCommand=V)
cmds.showWindow('testUI')

#3

Tank you al_ka for the answer!
I tried to do like this but the problem is that the argument in the functions T and V depending by S argument, and so the radiobuttons don’t work.
This is how i difined T and that pippo is generated by the other function S.

def T():
    for i in range(n):
            cmds.polyColorPerVertex('pippo.vtx[%d]'%i, rgb=(stress_adm[i], 0.5, 0.5))       
    cmds.setAttr("pippo.displayColors",  1)
    cmds.refresh()
    cmds.select('pippo', d=True)

This is S:

def S():
    cmds.delete('pippo') 
       
    #Parametri della superficie
    radius = cmds.intSliderGrp(radius2, q = True, value = True) #metri      
    gamma = cmds.intSliderGrp(gamma2, q = True, value = True) #KN/mc
    spess = cmds.intSliderGrp(spess2, q = True, value = True) #metri   
    sweep = cmds.intSliderGrp(sweep2, q = True, value = True)
    
    C = 1 #Ampiezza (dipende dal vincolo, consideriamo un carrello, C=1)
    delta = 0 #Sfasamento (dipende dal vincolo, consideriamo un carrello, delta=0)
    poisson = 0.15 #coeff. di poisson (dipende dal materiale)
           
    #Definisco la cupola
    angolo = range(10,360,10)  #angolo di rotazione dei semiarchi
    cmds.circle(nr = (1, 0, 0), c = (0, 0, 0), sw = -sweep, r = radius, n="S1")
    cmds.rotate(0,0,0)
    cmds.move(0,0,0) 
    cupola1 = []
    for i in range (35):
        cmds.duplicate()
        cmds.rotate(0,angolo[i],0)
        cupola1 = cupola1 + ["S"+str(i+1)]
    cmds.loft(cupola1, ['S36','S1'])
    cmds.delete(cupola1, ['S36','S1'])
    
    #Trasformo il loft(NURBS) in una polisuperficie
    cmds.nurbsToPoly('loftedSurface1', name='pippo', mnd=1,  ch=1, f=0, pt=0, pc=500, chr=0.9, ft=0.01, mel=0.001, d=0.1, ut=1, un=3, vt=1, vn=3, uch=0, ucr=0, cht=0.2,es=0,ntr=0,mrt=0,uss=1)
    
    cmds.delete('loftedSurface1')

    #Analizzo il numero di punti della superficie
    n = cmds.polyEvaluate('pippo', v=True, f=False)
    
    #Definisco un vettore vertex lungo quanto il numero dei punti della superficie
    vertex = np.zeros((n,3))
    angolo = np.zeros(n) #parte dalla base
    angolo_complementare = np.zeros(n) #parte dall'asse
    stress = np.zeros(n)
    stress_adm = np.zeros(n)
    vertex_adm = np.zeros((n,3))
     
    #Mi tiro fuori le coordinate xyz dei punti appartenenti alla superficie  
    for i in range(n):
        vertex[i,:]=(cmds.pointPosition('pippo.pt[%d]' %i))           
    
    #Calcolo lo sforzo normale di meridiano   
    for i in range(n):
        lato = np.sqrt(vertex[i,0]**2+vertex[i,2]**2) #trovo il lato in pianta
        diagonale = np.sqrt(lato**2+vertex[i,1]**2) #trovo la diagonale
        angolo[i] = abs(np.arcsin(vertex[i,1]/diagonale)*180/np.pi) #trovo l'angolo (omega), in gradi
        angolo_complementare[i] = (90-angolo[i])*np.pi/180 
        stress[i] = abs(-gamma*spess*radius*(1-np.cos(angolo_complementare[i]))/(np.sin(angolo_complementare[i]**2)))
        
    #Calcolo lo sforzo normale adimensionale   
    where_are_NaNs = np.isnan(stress)
    stress[where_are_NaNs] = 12 #quando ho valori non validi li sostituisco
    
    stress_max = np.amax(stress)
    for i in range(n):
        stress_adm[i] = stress[i]/stress_max
    
    vertex_max = np.amax(vertex[i][1])    
    for i in range(n):
        vertex_adm[i][1] = vertex[i][1]/vertex_max
        
    cmds.delete('loftedSurface1')
    
    #for i in range(n):
            #cmds.polyColorPerVertex('pippo.vtx[%d]'%i, rgb=(stress_adm[i], 0.5, 0.5))

    cmds.setAttr("pippo.displayColors",  1)
    cmds.refresh()
    cmds.select('pippo', d=True)

I tried also to define T and V inside S.


#4

My mistake, I misunderstood what you were asking. Instead, you need to query the radioCollection to figure out which radio button is currently selected when you run the S() function. I’ve adjusted the code. I gave the radio collection a name so I can query it later on. I also set the first button to default to being selected (that way S() doesn’t fail if none of them are selected. I’m still not entirely sure if this is what you’re after, but hopefully with this logic of querying the radio buttons you can work through it.

from maya import cmds

def S(*args):
    selRadio = cmds.radioCollection('radioButtons', q=1, sl=1)
    if selRadio == r1:
        print 'Do the thing with the first radio button'
    else:
        print 'Do the thing with the second radio button'        

if cmds.window('testUI', exists=1):
    cmds.deleteUI('testUI')
cmds.window ('testUI')
cmds.rowLayout(nc=5)
cmds.radioCollection('radioButtons')
r1 = cmds.radioButton(label='Radio One', sl=1)
r2 = cmds.radioButton(label='Radio Two')
cmds.button (label='S function', c=S)
cmds.showWindow('testUI')

#5

Thanks al_ka, I tried to correct the script but the radiobuttons don’t work. Maybe they enter in conflict with the sliders that control the geometry of the dome. The surface now it is not colored the right way, appear always black, but in the inner side it is colored just a small piece.
This the part of code about the output window, sliders and radiobutton:

#OUTPUT WINDOW
ram = cmds.window('Volte Sottili', t='Volte Sottili', w=300, h=300, sizeable = False)
cmds.columnLayout(adj=True)
imagePath = cmds.internalVar(upd = True)+'icons/img1.jpg'
cmds.image(w=200, h=100, image = imagePath)
cmds.separator(h=20)
cmds.text('Parametri')
cmds.separator(h=20)

#SLIDER AND RADIOBUTTONS
radius2 = cmds.intSliderGrp(l = 'Raggio [m]', min = 0.1, max = 50, value=5, field = True, dc='S()')
gamma2 = cmds.intSliderGrp(l = 'Peso Specifico [KN/mc]', min = 0, max = 50, value=25, field = True, dc='S()')
spess2 = cmds.floatSliderGrp(l = 'Spessore [m]', min = 0.010, max = 1, value=0.1, s=0.005, field = True, dc='S()')
sweep2 = cmds.intSliderGrp(l = 'Angolo [°]', min = 10, max = 90, value=90, field = True, dc='S()')
cmds.separator(h=20)
cmds.text('Solution Plot2')
cmds.separator(h=20)
cmds.rowLayout(nc=5)
cmds.radioCollection('radioButtons')
r1 = cmds.radioButton(label='Radio One', sl=1)
r2 = cmds.radioButton(label='Radio Two')
cmds.button (label='S function', c=S)
cmds.showWindow(ram)

This is a part of S() where I say how to color the surface, I don’t know if I’m doing something wrong here:

def S():
     selRadio = cmds.radioCollection('radioButtons', q=1, sl=1)
          if selRadio == r1:
              cmds.polyColorPerVertex('pippo.vtx[%d]'%i, rgb=(stress_adm[i], 0.5, 0.5))
         else:
              cmds.polyColorPerVertex('pippo.vtx[%d]'%i, rgb=(1, 0.5, 0.5))   
    
      cmds.setAttr("pippo.displayColors",  1)
      cmds.refresh()
      cmds.select('pippo', d=True)

I think the sliders and radiobuttons have to work together, but I do not know how I can do it.
This is how appear when i run the script:

When I push the S function button Maya says that an argument is not given (as shown in the picture), but slider still work in real time.
I tried also to give an argument S(rgb), I don’t know if is correct, but the script still doesn’t work.

Sorry for the long and unclear post :slight_smile:


#6

Most things seem to be in working order. The issue isn’t with the radio button setup. You just need to change your S function with *args in the arguments. All button UI elements pass some sort of data when they call a function, so you need something there to collect it. I’m also not sure why the if statement in the S function is indented. Might have just been a pasting error.

def S(*args):