[Bf-committers] python mathutils api update proposal

Campbell Barton ideasman42 at gmail.com
Fri Feb 4 00:18:57 CET 2011


Points taken:
inverse() vs inverted(), I don't have a strong opinion on this one,
both are acceptable (AFAIK), its just easier to remember to add 'ed'
suffix to get a copy: normalized(). conjugated(), inverted(),
transposed()


The second is not so easy:

Disagree regarding: matix.to_euler() & matrix.to_quaternion()

In a very general context I see your point:
For eg, pretend api call: 'nurbs.to_mesh()'
... would convert a mesh to a curve (in place), but in python context
converting between types is almost unheard of, I don't think its so
confusing.

You say it implies the matrix its self is being changed but to me this
implies that the return value is converted into a different
representation.

But this point is valid for matrix.to_translation() since no
conversion happens, its just convenient access to matrix[3][0:3].
So translation_part() is correct naming (where scale_part() and
rotation_part() are incorrect IMHO).
In this case I'm not convinced its worth to have an exception, to me
matrix.to_translation() is not _incorrect_ "to_translation()" can be
short for "to translation vector", but I see your point about the
ambiguity.
Perhaps matrix.translation_component() but that gets annoyingly verbose :S

On Thu, Feb 3, 2011 at 10:23 PM, Bassam Kurdali
<bkurdali at freefactory.org> wrote:
> +1 on the changes, with some qualifications:
>
> -for qualifying in place vs. returning new, whatabout verb/noun instead
> of present/past tense of verb:
> matrix.invert() inverts the matrix, returns none
> matrix.inverse() returns the new inverse matrix.
>
> in the rename methods we go from translation_part() to to_translation()
> however, (nit picking) the 'to' implies that the matrix is being
> changed, we are getting into the same region of ambiguity that you were
> attempting to solve in the earlier example.
> a suggustion is to use the verb 'derive'
> as in :
> matrix.derive_quaternion()
> matrix.derive_translation()
> or some other similar verb.
> cheers
> Bassam
> On Thu, 2011-02-03 at 21:54 +0000, Campbell Barton wrote:
>> On Thu, Feb 3, 2011 at 11:25 AM, Alex Fraser <alex at phatcore.com> wrote:
>> > On Thu, Feb 3, 2011 at 10:08 PM, Campbell Barton <ideasman42 at gmail.com> wrote:
>> >> Here are some proposed changes to the mathutils API I'd like to make
>> >
>> > As discussed on IRC, these changes look fine to me. One more
>> > suggestion: can we allow vector components to be specified without the
>> > use of a tuple, i.e. Vector(x,y,z) instead of Vector((x,y,z))?
>> >
>> > Cheers,
>> > Alex (z0r)
>>
>> Short answer is it doesn't make sense for Vectors to have one triple
>> arg, so - we could.
>>
>> Longer answer:
>>
>> The reason I made this change is that Quaternions and Eulers have
>> optional arguments which are more cumbersome to parse in C (see
>> example below)
>>
>> Since if we support both we would want to allow the same for other types: eg.
>> Quaternion(w, x, y, z) # 2.4x, NOT SUPPORTED IN 2.5x
>> Quaternion((w, x, y, z))
>> Quaternion((x, y, z), angle)
>> Quaternion(someOtherQuat)
>>
>> Euler(x, y, z) # 2.4x, NOT SUPPORTED IN 2.5x
>> Euler((x, y, z))
>> Euler((x, y, z), 'ZXY')
>> Euler(x, y, z, 'ZXY') # 2.4x didnt have order argument but perhaps
>> this would be expected to work too?
>> Euler(someOtherEuler)
>>
>> Since quats have axis/angle and eulers have optional order argument
>> there needs to be checks for argument lengths '0, 1, 2, 4' for quats,
>> and '0, 1, 2, 3, (possibly) 4' for eulers.
>>
>> The likelyhood we add new arguments to , Vector(x,y,z,w) is low so it
>> could be an exception, but then its confusing as to why Vector(x,y,z)
>> and Euler(x,y,z) doesn't.
>>
>> My preference is to have consistency between types rather then have
>> Vector() as the exception, even though I can see its a bit annoying.
>>
>> To see what I mean about sloppy argument parsing, see comparison of
>> 2.4x and 2.5x code below - both the same function though 2.5x uses
>> mathutils_array_parse() utility function.
>> The 2.4x code even had a memory leak for some time (refcount error).
>>
>> # --- 2.5x Code
>> static PyObject *Quaternion_new(PyTypeObject *type, PyObject *args,
>> PyObject *kwds)
>> {
>>       PyObject *seq= NULL;
>>       double angle = 0.0f;
>>       float quat[QUAT_SIZE]= {0.0f, 0.0f, 0.0f, 0.0f};
>>
>>       if(kwds && PyDict_Size(kwds)) {
>>               PyErr_SetString(PyExc_TypeError, "mathutils.Quaternion(): takes no
>> keyword args");
>>               return NULL;
>>       }
>>
>>       if(!PyArg_ParseTuple(args, "|Od:mathutils.Quaternion", &seq, &angle))
>>               return NULL;
>>
>>       switch(PyTuple_GET_SIZE(args)) {
>>       case 0:
>>               break;
>>       case 1:
>>               if (mathutils_array_parse(quat, QUAT_SIZE, QUAT_SIZE, seq,
>> "mathutils.Quaternion()") == -1)
>>                       return NULL;
>>               break;
>>       case 2:
>>               if (mathutils_array_parse(quat, 3, 3, seq, "mathutils.Quaternion()") == -1)
>>                       return NULL;
>>               angle= fmod(angle + M_PI*2, M_PI*4) - M_PI*2; /* clamp because of
>> precision issues */
>>               axis_angle_to_quat(quat, quat, angle);
>>               break;
>>       /* PyArg_ParseTuple assures no more then 2 */
>>       }
>>       return newQuaternionObject(quat, Py_NEW, type);
>> }
>>
>>
>>
>>
>> # --- 2.4x Code:
>> PyObject *M_Mathutils_Quaternion(PyObject * self, PyObject * args)
>> {
>>       PyObject *listObject = NULL, *n, *q, *f;
>>       int size, i;
>>       float quat[4];
>>       double norm = 0.0f, angle = 0.0f;
>>
>>       size = PySequence_Length(args);
>>       if (size == 1 || size == 2) { //seq?
>>               listObject = PySequence_GetItem(args, 0);
>>               if (PySequence_Check(listObject)) {
>>                       size = PySequence_Length(listObject);
>>                       if ((size == 4 && PySequence_Length(args) !=1) ||
>>                               (size == 3 && PySequence_Length(args) !=2) || (size >4 || size < 3)) {
>>                               // invalid args/size
>>                               Py_DECREF(listObject);
>>                               PyErr_SetString(PyExc_AttributeError, "Mathutils.Quaternion(): 4d
>> numeric sequence expected or 3d vector and number\n");
>>                               return NULL;
>>                       }
>>                       if(size == 3){ //get angle in axis/angle
>>                               n = PySequence_GetItem(args, 1);
>>                               if(n == NULL) { // parsed item not a number or getItem fail
>>                                       Py_DECREF(listObject);
>>                                       PyErr_SetString(PyExc_TypeError, "Mathutils.Quaternion(): 4d
>> numeric sequence expected or 3d vector and number\n");
>>                                       return NULL;
>>                               }
>>
>>                               angle = PyFloat_AsDouble(n);
>>                               Py_DECREF(n);
>>
>>                               if (angle==-1 && PyErr_Occurred()) {
>>                                       Py_DECREF(listObject);
>>                                       PyErr_SetString(PyExc_TypeError, "Mathutils.Quaternion(): 4d
>> numeric sequence expected or 3d vector and number\n");
>>                                       return NULL;
>>                               }
>>                       }
>>               }else{
>>                       Py_DECREF(listObject); /* assume the list is teh second arg */
>>                       listObject = PySequence_GetItem(args, 1);
>>                       if (size>1 && PySequence_Check(listObject)) {
>>                               size = PySequence_Length(listObject);
>>                               if (size != 3) {
>>                                       // invalid args/size
>>                                       Py_DECREF(listObject);
>>                                       PyErr_SetString(PyExc_AttributeError, "Mathutils.Quaternion(): 4d
>> numeric sequence expected or 3d vector and number\n");
>>                                       return NULL;
>>                               }
>>                               n = PySequence_GetItem(args, 0);
>>                               if(n == NULL) { // parsed item not a number or getItem fail
>>                                       Py_DECREF(listObject);
>>                                       PyErr_SetString(PyExc_TypeError, "Mathutils.Quaternion(): 4d
>> numeric sequence expected or 3d vector and number\n");
>>                                       return NULL;
>>                               }
>>                               angle = PyFloat_AsDouble(n);
>>                               Py_DECREF(n);
>>
>>                               if (angle==-1 && PyErr_Occurred()) {
>>                                       Py_DECREF(listObject);
>>                                       PyErr_SetString(PyExc_TypeError, "Mathutils.Quaternion(): 4d
>> numeric sequence expected or 3d vector and number\n");
>>                                       return NULL;
>>                               }
>>                       } else { // argument was not a sequence
>>                               Py_XDECREF(listObject);
>>                               PyErr_SetString(PyExc_TypeError, "Mathutils.Quaternion(): 4d
>> numeric sequence expected or 3d vector and number\n");
>>                               return NULL;
>>                       }
>>               }
>>       } else if (size == 0) { //returns a new empty quat
>>               return newQuaternionObject(NULL, Py_NEW);
>>       } else {
>>               Py_INCREF(args);
>>               listObject = args;
>>       }
>>
>>       if (size == 3) { // invalid quat size
>>               if(PySequence_Length(args) != 2){
>>                       Py_DECREF(listObject);
>>                       PyErr_SetString(PyExc_AttributeError, "Mathutils.Quaternion(): 4d
>> numeric sequence expected or 3d vector and number\n");
>>                       return NULL;
>>               }
>>       }else{
>>               if(size != 4){
>>                       Py_DECREF(listObject);
>>                       PyErr_SetString(PyExc_AttributeError, "Mathutils.Quaternion(): 4d
>> numeric sequence expected or 3d vector and number\n");
>>                       return NULL;
>>               }
>>       }
>>
>>       for (i=0; i<size; i++) { //parse
>>               q = PySequence_GetItem(listObject, i);
>>               if (q == NULL) { // Failed to read sequence
>>                       Py_DECREF(listObject);
>>                       PyErr_SetString(PyExc_RuntimeError, "Mathutils.Quaternion(): 4d
>> numeric sequence expected or 3d vector and number\n");
>>                       return NULL;
>>               }
>>
>>               f = PyNumber_Float(q);
>>               if(f == NULL) { // parsed item not a number
>>                       Py_DECREF(q);
>>                       Py_DECREF(listObject);
>>                       PyErr_SetString(PyExc_TypeError, "Mathutils.Quaternion(): 4d
>> numeric sequence expected or 3d vector and number\n");
>>                       return NULL;
>>               }
>>
>>               quat[i] = (float)PyFloat_AS_DOUBLE(f);
>>               Py_DECREF(f);
>>               Py_DECREF(q);
>>       }
>>       if(size == 3){ //calculate the quat based on axis/angle
>>               norm = sqrt(quat[0] * quat[0] + quat[1] * quat[1] + quat[2] * quat[2]);
>>               quat[0] /= (float)norm;
>>               quat[1] /= (float)norm;
>>               quat[2] /= (float)norm;
>>
>>               angle = angle * (Py_PI / 180);
>>               quat[3] =(float) (sin(angle/ 2.0f)) * quat[2];
>>               quat[2] =(float) (sin(angle/ 2.0f)) * quat[1];
>>               quat[1] =(float) (sin(angle/ 2.0f)) * quat[0];
>>               quat[0] =(float) (cos(angle/ 2.0f));
>>       }
>>
>>       Py_DECREF(listObject);
>>       return newQuaternionObject(quat, Py_NEW);
>> }
>>
>
>
> _______________________________________________
> Bf-committers mailing list
> Bf-committers at blender.org
> http://lists.blender.org/mailman/listinfo/bf-committers
>



-- 
- Campbell


More information about the Bf-committers mailing list