Mathutils API Update
Recently a patch was submitted [#25747], which highlights some problems with the mathutils API which I have also noticed from my use of mathutils for testing tools and import/exporters.
I ran these changes by Uncle_Entity, dougal2 & z0r on IRC before writing up the proposal for initial feedback and have now written down the proposed changes in detail.
--Ideasman42 10:51, 3 February 2011 (UTC)
Coerce Method Arguments
At the moment passing fixed values to a function is annoying because you must use mathutils constructors, or assign a value beforehand for reuse.
>>> myvec.cross(Vector((0, 0, 1)))
... but we could also accept
>>> myvec.cross((0, 0, 1))
Same with vec.angle(other), quat.difference((...))
This will NOT extend to operators
>>> Vector(...) + (1,2,3) >>> Vector(...) + Euler(...)
Seems convenient but introduces ambiguity as to what is the return type, and confuses which operators have special behavior such as Vector() * Matrix().
It also means the first value:
>>> (x, y, z, x) * Matrix()
Could be treated as a 4d vector or a quaternion.
Separate Modify In-Place Methods
Clear separation between methods which modify in-place and ones which return new values.
At the moment this backfires in common cases when modifying wrapped data is not intended:
>>> imat = obj.matrix_world.invert() * othermat # edits object. >>> imat = obj.matrix_world.copy().invert() * othermat # ok.
mathutils wrapped types are used in the GameEngine and for many RNA types so I think its worth avoiding confusion here.
I propose to have 2 methods in cases such as this.
>>> matrix.invert() # Inverts in-place, returns None >>> matrix.inverted() # Returns a new, inverted matrix.
Same with normalize / normalized, transpose / transposed... etc.
- matrix/euler.to_quat() --> to_quaternion()
This abbreviation isnt used anywhere else in mathutils.
- matrix.rotation_part() --> matrix.to_3x3()
rotation_part() also contains scale which is misleading.
- matrix.translation_part() --> to_translation()
- scale_part() --> to_scale()
At the moment we have matrix methods rotation_part() / scale_part() / translation_part().
The method naming implies that together they will decompose the matrix, but as noted above this is not the case.
Since these methods were written I have added...
>>> loc, rot, scale = matrix.decompose()
So I'm proposing to drop the *_part() suffix and have this in keeping with: matrix.to_euler(), to_quat(), to_3x3()
- matrix.resize3x3 --> resize_3x3(), better matches to_3x3().
Consistent Matrix Constructor Argument order
At the moment Matrix constructor order is mixed.
>>> mathutils.Matrix.Rotation(angle, matrix_size, axis) >>> mathutils.Matrix.Scale(factor, matrix_size, axis) >>> mathutils.Matrix.Shear(plane, factor, matrix_size) # <-- Odd one out >>> mathutils.Matrix.OrthoProjection(plane, matrix_size, axis) >>> mathutils.Matrix.Translation(vector)