So, pymel's Quaternion class currently has some serious unit issues...
before I get into exactly what they were, and what I'd like to do to fix
them, I was wondering if many people actually used them - and if so, how -
because fixing them may break existing code.

Basically, I'm wondering: if you DO use the Quaternion class, do you
generally rely on the output of the Quaternion's component access operations
(ie, indexing, iteration, or accessing by component name: myQuat[2], for x
in myQuat, myQuat.x) being in degrees by default (assuming you have your ui
angle setting set to degrees, the default)?  Do you use them, but weren't
even aware this was the case?

If you're wondering why I'm asking, here's the problem in detail, and how
I'm proposing to fix it:

Right now, all assignments are done in units of radians, regardless of what
the internal unit setting for the Quaternion is.  Internally, all the data
is stored as radians as well, since it is based on MQuaternion.
However, item retrieval will convert to the Quaternion's unit; which means
that, if the internal unit is not radians, what you set will be different
than what you get... and this will often be the case, since the default
unit is generally degrees.

For instance, in this scenario:

q1 = Quaternion(1,2,3,4)
q2 = Quaterion(*q1)

...q1 and q2 will NOT be equal (as q1 will set it's value in radians, but
spit them back out - for the initialization of q2 - in degrees.

Even more confusing, if we do:

q3 = Quaterion(q1)

...then q1 and q3 WILL be equal.

Also confusing is that even if you explicitly specify a unit, inputs are
ALWAYS interpreted as being in radians... so if you do this:

q4 = Quaternion([30,60,90,120], unit='degrees')

then

list(q4) == [30,60,90,120]

will be False, because 30,60, etc will be interpreted as radians, then
converted to degrees on iteration.

I suspect that most people have simply assumed (as I did) that Quaternions
simply always work in radians - or at least have that unit by default -
since when setting them, the value is always interpreted as being in
radians,
and if you then pass the Quaternion object 'whole' into api methods, which
always expect radians, things work as expected.  You only get burned if you
then try to extract individual members of the quaternion - either by
iteration
or component (ie, x,y,z,w) access - which will then be in degrees.

Unfortunately, this means that if we convert assignment values to be
interpreted in the Quaternion's unit setting, I imagine most people's code
will break.

So, we are left with 3 choices, none of which are attractive:

1) Leave things as is: assignment always in radians, extraction in the set
unit

   Advantages:
   If you don't change anything, you can't break existing code...

   Disadvantages:
   Assignment and extraction will be in different units, which is pretty
       confusing for the reasons I gave above.

2) Make assignments and retrieval always be in the set unit, and leave the
   default unit as the current UI unit (ie, generally degrees).

   Advantages:
   Assignment / extraction is consistent
   Default unit behavior is similar to how it's handled with EulerRotation

   Disadvantages:
   Likely to break people's code, since I imagine most people just always
       worked in radians with it.

3) Make assignments and retrieval always be in the set unit, but change the
   default unit to always be radians (regardless of UI setting)

   Advantages:
   Less likely to break people's existing code than 2)
   Assignment / extraction now consistent

   Disadvantages:
   May still break people's code, if they were relying on the default
       extraction to be in degrees
   Now have inconsistent default unit behavior between EulerRotation and
       Quaternion

Unless there's outcry, I'll be implementing option 3...

- Paul

-- 
http://groups.google.com/group/python_inside_maya

Reply via email to