On Thu, Feb 3, 2011 at 11:25 AM, Alex Fraser <[email protected]> wrote:
> On Thu, Feb 3, 2011 at 10:08 PM, Campbell Barton <[email protected]> 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);
}

-- 
- Campbell
_______________________________________________
Bf-committers mailing list
[email protected]
http://lists.blender.org/mailman/listinfo/bf-committers

Reply via email to