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

17
$\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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.