[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