It’s a fabulously day in Toronto, crisp and sunny, I am loving it! J
Today I will do my second posting to this posting “Overriding __str__() for Maya Python Objects” from September 14th, 2009.
I will talk about how we know in the MMatrix documentation where to read that the operators we need to use are formatted like this (row, column):
self(0,0), self(0,1), self(0,2), self(0,3), self(1,0), self(1,1), self(1,2), self(1,3), self(2,0), self(2,1), self(2,2), self(2,3), self(3,0), self(3,1), self(3,2), self(3,3)
For this part of the code:
#New __str__ function for Making the matrix readable....
def myMatrix_str(self):
return "[[%g,%g,%g,%g][%g,%g,%g,%g][%g,%g,%g,%g][%g,%g,%g,%g]]" % (self(0,0), self(0,1), self(0,2), self(0,3), self(1,0), self(1,1), self(1,2), self(1,3), self(2,0), self(2,1), self(2,2), self(2,3), self(3,0), self(3,1), self(3,2), self(3,3))
In this case the API method is defined as follows:
double operator() (unsigned int row, unsigned int col) const
Which is the '()' operator.
With operators the syntax for each one is different so you just have to know them. In just about all cases 'self' goes to the left of the operator but the positioning of the other arguments depends upon the operator. For example, the '+' operator takes a single argument on the right, while the '()' operator takes any number of arguments as a comma-separated list between the parentheses.
For another example we can take MVector:
We know that MVector consists of three values: x, y and z. You decide that you'd like your method to return them as the string '[ x y z ]' which means that you need to get those three individual values. In general, there are three possible ways:
1) See if they are stored in public member variables. MVector has public variables 'x', 'y' and 'z', so you can just do this:
return '[ %g %g %g ]' % (this.x, this.y, this.z)
2) See if there is an operator which will return the values. In this case that would mean looking at all of the operators which return a float or a double and then reading their descriptions to see which ones are returning the individual component values. It's generally safe to eliminate operators such as +, -, *, / since those usually try to have meanings similar to add, subtract, multiply and divide, where possible. In practice, indexing operators will almost always be either [] or (). In this case we have both operator[] and operator(), either of which will work:
return '[ %g %g %g ]' % (this(0), this(1), this(2))
or:
return '[ %g %g %g ]' % (this[0], this[1], this[2])
3) See if there is a normal method (i.e. not an operator) which will return the values in a useful format. MVector has the get(double[3]) method to do this.
However, since it uses a modifiable array, which Python does not directly support, we have to use MScriptUtil to retrieve the values, which gets pretty ugly:
d3 = om.MScriptUtil()
d3.createFromDouble(0, 0, 0)
d3Ptr = om.asDoublePtr()
this.get(d3Ptr)
return '[ %g %g %g ]' % (om.MScriptUtil.getDoubleArrayItem(d3Ptr, 0), om.MScriptUtil.getDoubleArrayItem(d3Ptr, 1), om.MScriptUtil.getDoubleArrayItem(d3Ptr, 2) ]
In the case of MVector, #1 is the clearest and simplest approach.
Now let's try the same thing with MMatrix:
1) MMatrix has a 'matrix' public attribute which contains the values we need. It requires a double index operator, which Python does not support. However, if you try to print out the 'matrix' member you'll get something like this:
<Swig Object of type 'double (*)[4]' at 0x13926f0>
In other words, Python sees the 'matrix' member as a pointer to an array of four doubles. If you look at MScriptUtil.getDouble4ArrayItem() you'll see that it takes two indices, named 'r' and 'c', which sound suspiciously like 'row' and 'column'. And indeed, it works!
str = ''
for row in range(4):
str += '| '
for col in range(4)
str += '%g ' % om.MScriptUtil.getDouble4ArrayItem(this.matrix, row, col)
str += '|\n'
return str
2) operator[](int row) returns a pointer to a row of values. If you try to print out m[0], for example, you'll see something like this:
<Swig Object of type 'double *' at 0x13926f0>
which means that Python sees each row as an array of doubles of no specific length. That means we can use MScriptUtil.getDoubleArrayItem() to retrieve the values:
str = ''
for row in range(4):
str += '| '
rowPtr = this[row]
for col in range(4):
str += '%g ' % om.MScriptUtil.getDoubleArrayItem(rowPtr, col)
str += '|\n'
return str
There's also operator()(int row, int col) which returns a single value at a time. That's nicer because we don't have to fiddle with pointers:
str = ''
for row in range(4):
str += '| %g %g %g %g |\n' % (this(row, 0), this(row, 1), this(row, 2), this(row, 3))
return str
3) MMatrix has a get() method which takes a 'float[4][4]'. I can't think of any way of working with that, even using MScriptUtil.
Big Thanks to Dean Edmonds for breaking it down and his explanation!
~Kristine





Subscribe
Comments