How to write a python script in Maya with a condition logic - python

I’m starting as a programmer and currently working on a project but got stuck + have a bit of a brain fart(sorry).
I need to write a tool that will:
1 - set character rig by selecting character in the scene and set script to remember selection.
2 - evaluate whether selected character rig has a namespace or not (depending on that the next step takes different root)
if there is a namespace:
3 - find control in the character rig [namespace] + [side L\R] + [Ctrl]
4 - select target loc and snap one to another then bake animation
if there is no namespace:
3 - find control in the character rig [side L\R] + [Ctrl]
4 - select target loc and snap one to another then bake animation
I wrote parts of the script but don’t know how to put it together because I don’t know how to word this condition in the script.
Can anyone help me to put my brain back in order?
CH = pm.ls(sl=True, fl=True)
for c in CH:
if pm.referenceQuery(c, isNodeReferenced=True):
nameSpace = c.split(':')[0] + ':'
nameS.append(nameSpace)
name = nameSpace + 'L' + '_Weapon_ctrl'
print name
else:
name = 'L' + '_Weapon_ctrl'
print name
def bakeToObj():
Target = pm.ls(sl=True, fl=True)[0]
pm.cutKey(Weapon)
par = pm.parentConstraint([Target] + [Weapon], mo=False)
startTime = pm.playbackOptions(query=True, minTime=True)
endTime = pm.playbackOptions(query=True, maxTime=True)
pm.bakeResults(Weapon, simulation=True, t=(startTime, endTime))
pm.showHidden(above=True)
pm.delete(par)
return bakeToObj

I recommend to continue where you started. The list ist a very good start. Now you can create a script with all functions you need for the list of tasks and one function to call them all, e.g.:
def getSelectedCharacterRig():
sel = pm.ls(sl=True, fl=True)
return sel
def getCtrlName(rig):
....
return ctrlName
def findCtrl(ctrlName):
...
return ctrl
def selectTargetLoc(ctrl):
...
def bake(someObject):
return bakedObject
def doIt():
selection = getSelectedCharacterRig()
ctrlName = getCtrlName(selection)
...
This way you can see what you need an how to do it. And you will see if a function is not needed at all.

Related

Stuck in loop help - Python

The second 'if' statement midway through this code is using an 'or' between two conditions. This is causing the issue I just don't know how to get around it. The code is going through a data file and turning on the given relay number at a specific time, I need it to only do this once per given relay. If I use an 'and' between the conditions, it will only turn on the first relay that matches the current time and wait for the next hour and turn on the next given relay.
Could someone suggest something to fix this issue, thank you!
def schedule():
metadata, sched = dbx.files_download(path=RELAYSCHEDULE)
if not sched.content:
pass # If file is empty then exit routine
else:
relaySchedule = str(sched.content)
commaNum = relaySchedule.count(',')
data1 = relaySchedule.split(',')
for i in range(commaNum):
data2 = data1[i].split('-')
Time1 = data2[1]
currentRN = data2[0]
currentDT = datetime.datetime.now()
currentHR = currentDT.hour
global RN
global T
if str(currentHR) == str(Time1):
if T != currentHR or RN != currentRN:
relaynum = int(data2[0])
relaytime = int(data2[2])
T = currentHR
RN = currentRN
k = threading.Thread(target=SendToRelay(relaynum, relaytime)).start()
else:
print("Pass")
Desired Inputs:
sched.content = '1-19-10,3-9-20,4-9-10,'
T = ' '
RN = ' '
T and RN are global variables because the loop is running indefinitely, they're there to let the loop know whether the specific Time(T) and Relay Number(RN) have already been used.
Desired Outputs:
If the time is 9 AM then,
T = 9
RN should be whatever the given relay number is so RN = 3, but not sure this is the right thing to use.
Sorry if this is confusing. I basically need the program to read a set of scheduled times for specific relays to turn on, I need it to read the current time and if it matches the time in the schedule it will then check which relay is within that time and turn it on for however long. Once it has completed that, I need it to go over that same set of data in case there is another relay within the same time that also needs to turn on, the issue is that if I don't use T and RN variables to check whether a previous relay has been set, it will read the file and turn on the same relay over and over.
Try printing all used variables, check if everything is, what you think it is. On top of that, sometimes whietespaces characters causes problem with comparison.
I fixed it. For anyone wondering this is the new working code:
def schedule():
metadata, sched = dbx.files_download(path=RELAYSCHEDULE)
if not sched.content:
pass # If file is empty then exit routine
else:
relaySchedule = str(sched.content)
commaNum = relaySchedule.count(',')
data1 = relaySchedule.split(',')
for i in range(commaNum):
data2 = data1[i].split('-')
TimeSched = data2[1]
relaySched = data2[0]
currentDT = datetime.datetime.now()
currentHR = currentDT.hour
global RN
global T
if str(currentHR) == str(TimeSched):
if str(T) != str(currentHR):
RN = ''
T = currentHR
if str(relaySched) not in str(RN):
relaynum = int(data2[0])
relaytime = int(data2[2])
k = threading.Thread(target=SendToRelay(relaynum, relaytime)).start()
RN = str(RN) + str(relaySched)

Python in Maya: main function calls other function while passing variables?

I am an animator who is a beginner at coding...I appreciate your help!
I am writing a Python script to automatically duplicate controller objects in Maya. It creates controllers for each bone in the character's hand.
It worked fine as a single long function, but I want to have a Main Function, "handCtrls()", call functions within it for the various tasks. I also need to pass variables to the sub-functions, because I am iterating on the variable "i".
I get an error on the line which calls the function "nullGrouper(side, boney, i, ctrl)", and the error says that "global variable 'ctrl' is undefined". But it is defined in the "ctrlDup" function, and I used "return ctrl", which I though would send that variable back to 'handCtrls()'.
here is the code:
import maya.cmds as c
def ctrlDup(side, boney, i, ctrlOrig):
#Select and duplicate the original Control, and place it at the appropiate boney
c.select(ctrlOrig)
ctrl = c.duplicate(ctrlOrig, n=side + boney + str(i) + '_CTRL')
print(ctrl)
print('ctrlDup passed')
return ctrl
def nullGrouper(side, boney, i, ctrl):
#Create null group at same position as Control
print(ctrl)
print(ctrl[0])
nullGrp = c.group(n=side + boney + str(i) + '_GRP', empty=1, world=1)
print(nullGrp)
c.parentConstraint(ctrl, nullGrp, n='nullGrp_parentConstr_temp')
c.delete('nullGrp_parentConstr_temp')
print('nullGrouper passed')
return ctrl, nullGrp
def handCtrls():
#First select the Controller to be duplicated
sel = c.ls(sl=1)
ctrlOrig = sel[0]
#List sides
sideList = ['L_', 'R_']
#List bones of part
boneyList = ['thumb', 'index', 'middle', 'ring', 'pinky']
#Now, iterate across finger joints, up to 3, group controls, and parent them
for side in sideList:
for boney in boneyList:
for i in range(1, 4, 1):
#Check if boney is thumb, and joint number is 3
if (boney!='thumb') or (i!=3):
ctrlDup(side, boney, i, ctrlOrig)
nullGrouper(side, boney, i, ctrl)
else:
pass
print("It's done.")
handCtrls()
There are several 'print' commands just to check if the variable is getting passed. Thank you!
It is because you are not storing the return
...
ctrl = ctrlDup(side, boney, i, ctrlOrig)
nullGrouper(side, boney, i, ctrl)

python worm how to make it more complex?

Please be kind this is my second post and i hope you all like.
Here I have made a program that makes directories inside directories,
but the problem is I would like a way to make it self replicate.
Any ideas and help is greatly appreciated.
Before:
user/scripts
After:
user/scripts/worm1/worm2/worm3
The script is as follows:
import os, sys, string, random
worms_made = 0
stop = 20
patha = ''
pathb = '/'
pathc = ''
def fileworm(worms_made, stop, patha, pathb, pathc):
filename = (''.join(random.choice(string.ascii_lowercase
+string.ascii_uppercase + string.digits) for i in range(8)))
pathc = patha + filename + pathb
worms_made = worms_made + 1
os.system("mkdir %s" % filename)
os.chdir(pathc)
print "Worms made: %r" % worms_made
if worms_made == stop:
print "*Done"
exit(0)
elif worms_made != stop:
pass
fileworm(worms_made, stop, patha, pathb, pathc)
fileworm(worms_made, stop, patha, pathb, pathc)
To create a variable depth, you could do something like this:
import os
depth = 3
worms = ['worm{}'.format(x) for x in range(1, depth+1)]
path = os.path.join(r'/user/scripts', *worms)
os.path.makedirs(path)
As mentioned, os.path.makedirs() will create all the required folders in one call. You just need to build the full path.
Python has a function to help with creating paths called os.path.join(). This makes sure the correct / or \ is automatically added for the current operating system between each part.
worms is a list containing ["worm1", "worm2", "worm3"], it is created using a Python feature called a list comprehension. This is passed to the os.path.join() function using * meaning the each element of the list is passed as a separate parameter.
I suggest you try adding print worms or print path to see how it works.
The result is that a string looking something like as follows is passed to the function to create your folder structure:
/user/scripts/worm1/worm2/worm3

Python (Pywin32) Referencing Own Cell/Horizontal Movement

So please don't tell me to google or research or read anything, I've been doing that for the past couple of days and will get annoyed if I see someone say that again.
My problem: I am using pywin32 and python 2.7.8 to communicate with (an already existing) excel sheet. I use it to log my hours worked and money earned, etc. I have it functioning to the point that I can open the workbook, find the next empty cell under my existing entries and write the date in that cell. My problem lies in the fact that I need to navigate horizontally. I want the program to run automatically so I will not always know the number of the cell. For example, my current cell is 18,1. I need to move to 18,2 18,3 18,4 and 18,5. But next time I run the script I may need 19,2... etc.
How can I do this? Is there a way to return the current cell or something?
code:
import win32com.client as win32
import os, time
xl = win32.Dispatch('Excel.Application')
xl.visible = True
xl.Workbooks.Open(os.path.join('C:\\Users\\[REDACTED]\\Desktop', '[REDACTED].xls'))
xlSheet = xl.Sheets(1)
activecell = xlSheet.Cells(1,1)
def GetEmptyCell():
global activecell
activecell = xlSheet.Cells(1,1)
for c in range(1,99,1):
if activecell.Value == None:
print 'Empty cell'
activecell = xlSheet.Cells(c,1)
print '(' + str(c) + ',1)'
return activecell
elif activecell.Value != None:
c += 1
activecell = xlSheet.Cells(c,1)
print 'Full cell, next'
GetEmptyCell()
def WriteToEmpty():
global activecell
global HoursWorked
global GrossIncome
global NetIncome
HoursWorked = raw_input('Input amount of hours worked: ')
GrossIncome = float(HoursWorked) * 9.15
NetIncome = float(GrossIncome) * 0.86233
print 'Money Made: ' + str(GrossIncome) + ' Take Home: ' + str(NetIncome)
activecell.Value = time.strftime('%a') + ' ' + time.strftime('%m') + '/' + time.strftime('%d')
#HELP FROM HERE
WriteToEmpty()``
There are dozens of ways to acheive what you want. If you have contiguous data in column A you could use something like xl.range("A1").end(xldown).offset(1,0).address to get the address of the first cell in the next empty row. Or you could use xl.range("A1").currentregion and offset from there.
Personally i'd probably just put the current region into an array and work from there, then dump the array back to the sheet, but thats always my preference, most people seem to prefer to work on the sheet.

Cannot print alt and az using pyephem in function

I'm working on building a simple python program for a class which will run on a Raspberry Pi and an Arduino to direct a telescope. I had started to learn python some time ago, and I'm having trouble getting my functions to work properly. Right now, I have this:
import ephem
def const(p, d): # find the constellation #
def loc():
sbend = ephem.Observer()
sbend.lat = '41.67'
sbend.lon = '86.26'
p = getattr(ephem, p)
p.compute(sbend)
print p.alt, p.az
o = getattr(ephem, p)
print ephem.constellation(o(d))
return loc()
const(raw_input('Planet: '), raw_input('yyyy/mm/dd: '))
From what I remember, a function inside another can call a variable from the parent. Can it also work the other way round like I have at the end? I'd like to be able to print the constellation (which is working) as well as the alt and az of the planet based on the hardcoded location. For some reason, it isn't calculating the altitude and azimuth though. Thoughts?
EDIT
I added return loc() on line 14.
I was doing more reading and some other threads said that to get to an inner function, it needs to be returned at the end of the parent. But, it's still not working for me.
I am not clear on why you have one function inside of another, so I might be missing part of the problem that you are trying to solve; but if I wanted to determine in what constellation a planet lies, where the planet's name and the date are provided as inputs, then I would simply perform those steps all in a row, without any complicated functions-inside-of-functions:
import ephem
def const(planet_name, date_string):
planet_class = getattr(ephem, planet_name)
planet = planet_class()
south_bend = ephem.Observer()
south_bend.lat = '41.67'
south_bend.lon = '-86.26' # west is negative
south_bend.date = date_string
planet.compute(south_bend)
return ephem.constellation((planet.ra, planet.dec))
print const(raw_input('Planet: '), raw_input('yyyy/mm/dd: '))
Taking #Brandon's example, here is my final code:
import ephem
def const(planet_name, date_string):
planet_class = getattr(ephem, planet_name)
planet = planet_class()
south_bend = ephem.Observer()
south_bend.lat = '41.67'
south_bend.lon = '-86.26'
south_bend.date = date_string
planet.compute(south_bend)
print ephem.constellation((planet.ra, planet.dec))
return planet.alt, planet.az
print const(raw_input('Planet: '), raw_input('yyyy/mm/dd: '))
I realized after looking at it that he was using planet.ra and planet.dec to locate the background constellation, not to print it's coordinates in the sky. All I did was add the return call at the end to print the altitude and azimuth data.

Categories