11
$\begingroup$

In order to optimize my script, I would need some help to perform a rotation around the cursor
(see Rotate object around cursor with Python)

With low-level python, that means, without bpy.ops.* operations.

I have to admit that I didn't find a good overview on how to make rotation with python without bpy.ops. Do I have to perform matrix operations for a simple rotation around an axis Z located at the cursor position?

$\endgroup$
2
  • $\begingroup$ I think you are better of using the bpy.ops. The functions in the module call on compiled C commands. This is a lot faster than doing it with python. Also optimizing a script by not using the built-ins blender provides is rather silly. This is just my opinion though $\endgroup$
    – Vader
    Mar 7, 2014 at 13:18
  • 3
    $\begingroup$ The low level python api will call c-functions as well. See this post and this post for reasons to not use operators. $\endgroup$ Mar 7, 2014 at 15:25

2 Answers 2

18
$\begingroup$

Rotate a vector

import bpy
from math import pi
from mathutils import Vector, Euler, Matrix, Quaternion

v = Vector((1.0, 1.0, 1.0))
#point which will be rotated around the cursor

cursor_loc = bpy.context.scene.cursor_location

rot_mat = Matrix.Rotation(pi / 2.0, 3, 'Z')
v_new = rot_mat * (v - cursor_loc) + cursor_loc

There are further options available (see api docs):

You can construct a matrix, this is most efficient if you want to apply the same transformation on many points.

mat = (Matrix.Translation(cursor_loc) *
       Matrix.Rotation(pi / 2.0, 4, 'Z') *
       Matrix.Translation(-cursor_loc))
v_new = mat * v

You can use quaternions:

# using (axis, angle) constructor
q = Quaternion((0.0, 0.0, 1.0), pi / 2.0)
v_new = q * (v - cursor_loc) + cursor_loc

or eulers:

eu = Euler((0.0, 0.0, pi / 2.0), 'XYZ')
v_new = v - cursor_loc
v_new.rotate(eu)  # works for quat's and matrix types too
v_new += cursor_loc

Rotate an object

mat = (Matrix.Translation(cursor_loc) *
       Matrix.Rotation(pi / 2.0, 4, 'Z') *
       Matrix.Translation(-cursor_loc))

obj.matrix_world = mat * obj.matrix_world

Euler and Quaternion both offer a method to convert them to a matrix:

q  = Quaternion()
eu = Euler()

mat =  q.to_matrix().to_4x4()
mat = eu.to_matrix().to_4x4()
$\endgroup$
4
  • 1
    $\begingroup$ You can also do from math import radians and specify the rotation in degrees like radians(90) (equal to pi/2) $\endgroup$
    – CodeManX
    Mar 7, 2014 at 18:47
  • $\begingroup$ Thanks pink vertex for the answer. I have difficulties to adapt your proposal for a single point (the vector v) to a whole object obj; could you adapt your script to make it run for an object obj that is a plan or a cube? Thanks. $\endgroup$
    – Salvatore
    Mar 7, 2014 at 23:26
  • $\begingroup$ Added a section. $\endgroup$ Mar 8, 2014 at 1:46
  • $\begingroup$ great, it helped me a lot! I used the matrix_basis and not matrix_world but your answer provided me the information I needed to move ahead. Thanks! $\endgroup$
    – Salvatore
    Mar 8, 2014 at 23:51
0
$\begingroup$

Rotate object(s) around cursor with cursor rotation

I did a function. you can run it on selected objects in a loop.

for ob in context.selected.objects
    rot_around_curs(context, ob)

I convert cursor rotation to a matrix, then modify obj matrix to get a rotation around the cursor with the cursor rotation value

    def rot_around_curs(self, context, obj):
        curs = context.scene.cursor
        mat = curs.matrix
        loc = curs.location
        R = mat.to_quaternion().to_matrix().to_4x4() #cursor rotation
        T = Matrix.Translation(loc) #cursor location
        M = T @ R @ T.inverted() #we just involve the rotation
        obj.matrix_world = M @ obj.matrix_world #update obj matrix

the advantage of converting matrix in quaternion is to not use for instance curs.rotation_euler depending in what rotation mode you are

$\endgroup$
1
  • $\begingroup$ Hi, thanks for the post. This site is not a regular forum, answers should be substantial and thoroughly explain the solution and required workflow. One liners and short tips rarely make for a good answer. If you can edit your post and provide some more details about the code. Perhaps add a few images illustrating the workflow and final results. See How do I write a good answer? $\endgroup$ Nov 3, 2021 at 11:36

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .