I'm trying to create a hexagonal array of spheres around a center sphere in the XY plane using a python loop function (couldn't figure out how to do it using duplicate special). It should end up looking something like this:
0 0
0 0 0
0 0
Here's my code. I' getting a syntax error
# Error: line 1: invalid syntax #
when I call it, though I'm pretty sure there's nothing wrong with line one.
import maya.cmds as cmds
class Sphere(radius, tx=0, ty=0, tz=0, sx=0, sy=0, sz=0):
self.diameter = 2*radius
def createSphere(radius, tx, ty):
newSphere = Sphere(radius=radius, tx=tx, ty=ty)
return newSphere
def duplicateSphere(wholeSphere):
for i in range(6, 1, -1):
createSphere(tx=wholeSphere.diameter*math.cos(2*math.pi/i), ty=wholeSphere.diameter*math.sin(2*math.pi/i))
# create spheres with projections onto x and y axes as translation params
duplicateSphere(createSphere(1.03))
Any ideas as to what's going on?
Ok, first off to answer your question, the SyntaxError
is caused by improper class instantiation. class declaration must be separated from the constructor method in python, like so:
class Sphere(object):
def __init__(self, radius, tx=0, ty=0, tz=0, sx=0, sy=0, sz=0):
self.diameter = 2 * radius
Tip: In the maya script editor panel, if you enable History->Show Stack Trace it will give you a better idea of where the actual error is occurring.
However, there are a couple other issues at play. For one, you are never storing the parameters you pass into the sphere class (except radius, which you are storing implicitly by storing the diameter). You probably wanted:
class Sphere(object):
def __init__(self, radius, tx=0, ty=0, tz=0, sx=1, sy=1, sz=1):
self.radius = radius
self.tx = tx
self.ty = ty
self.tz = tz
self.sx = sx
self.sy = sy
self.sz = sz
self.diameter = 2 * radius
I changed the scale defaults to 1 instead of 0 so that the default sphere is not invisibly small.
Also, as theodox pointed out, you have a TypeError
in your createSphere
method, which takes 3 params (none of them are keyword arguments currently and therefore not optional) and you are only passing in 1.
However, the main issue is that currently you are not actually creating any spheres in maya. If the intention is that your sphere object is an object-oriented wrapper around maya.cmds, you will need it to call cmds.sphere
somewhere, and you will probably want to cmds.move()
and cmds.scale()
it to by your t* and s* values. If you do all this in the constructor, you could actually then avoid setting instance variables for all the sphere properties if you wanted.
This would look something like this:
cmds.sphere(radius=self.radius)
cmds.move(self.tx,self.ty,self.tz)
cmds.scale(self.sx,self.sy,self.sz)
Finally, I think your trig is a bit off (you want each iteration to vary by exactly 60° or π/3 radians). To get the proper angles, I think you want something more along the lines of:
import math
for i in range(6,0,-1):
angle = math.pi * i / 3.0
distance = wholeSphere.diameter
tx = distance * math.cos(angle)
ty = distance * math.sin(angle)
# ...
As a last note, consider looking at an object-oriented solution like pymel to avoid needing to reinvent the wheel in terms of wrapping maya.cmds commands in objects.
Anyways, applying all these corrections produces something like:
import maya.cmds as cmds
import math
class Sphere(object):
def __init__(self, radius, tx=0, ty=0, tz=0, sx=1, sy=1, sz=1):
self.diameter = 2*radius
self.radius = radius
self.tx = tx
self.ty = ty
self.tz = tz
self.sx = sx
self.sy = sy
self.sz = sz
cmds.sphere(radius=self.radius)
cmds.move(self.tx,self.ty,self.tz)
cmds.scale(self.sx,self.sy,self.sz)
def createSphere(radius, tx=0, ty=0):
newSphere = Sphere(radius, tx=tx, ty=ty)
return newSphere
def duplicateSphere(wholeSphere):
for i in range(6, 0, -1):
angle = math.pi * i / 3.0
distance = wholeSphere.diameter
tx = distance * math.cos(angle)
ty = distance * math.sin(angle)
createSphere(wholeSphere.radius, tx=tx, ty=ty)
duplicateSphere(createSphere(1.03))