0
$\begingroup$

I created a cylinder via python.

I rotated it it 2 times (y and z axis). Then moved it up. Then i changed the origin to be in world center and rotated in on z - axis.

So the result is like this (which is ok)

enter image description here

then i added these line to my code

# expected: rotation "in place" - so same as before, but vertical
setOriginToGeometry(bpy.context.active_object)
bpy.ops.transform.rotate(value = math.pi / 2, orient_axis='Z', orient_type='GLOBAL', orient_matrix=((1, 0, 0), (0, 1, 0), (0, 0, 1)), orient_matrix_type='GLOBAL', constraint_axis=(False, False, True), mirror=True, use_proportional_edit=False, proportional_edit_falloff='SMOOTH', proportional_size=1, use_proportional_connected=False, use_proportional_projected=False)

and as i wrote in the comments i expected the green bar to rotate "just in place", instead i got this:

enter image description here

so obviously i am doing and understanding something wrong, but what? Any help appreciated!

my code:

import bpy
import math

def setOriginToCursor(object):
    bpy.context.view_layer.objects.active = object
    bpy.ops.object.origin_set(type='ORIGIN_CURSOR')

def setOriginToGeometry(object): 
    bpy.context.view_layer.objects.active = object
    bpy.ops.object.origin_set(type='GEOMETRY_ORIGIN')

i = 0
name = "object"
halfPi = math.pi / 2
radius = 3
number_of_objects = 1

angle = 2 * math.pi / number_of_objects

bpy.ops.mesh.primitive_cylinder_add(radius=1, depth=2, enter_editmode=False, align='WORLD', location=(0, 0, 0), scale=(0.1,  0.1, 1))

new_Name = name + '_' + str(i)
bpy.context.active_object.name = new_Name

# rotation 90 y-Axis, so i can see it from top view (result : horizontal)
bpy.ops.transform.rotate(value = halfPi, orient_axis='Y', orient_type='GLOBAL', orient_matrix=((1, 0, 0), (0, 1, 0), (0, 0, 1)), orient_matrix_type='GLOBAL', constraint_axis=(False, True, False), mirror=True, use_proportional_edit=False, proportional_edit_falloff='SMOOTH', proportional_size=1, use_proportional_connected=False, use_proportional_projected=False)
# rotation 90 on z axis, so it is vertical
bpy.ops.transform.rotate(value = math.pi * 2 - angle * i + math.pi / 2, orient_axis='Z', orient_type='GLOBAL', orient_matrix=((1, 0, 0), (0, 1, 0), (0, 0, 1)), orient_matrix_type='GLOBAL', constraint_axis=(False, False, True), mirror=True, use_proportional_edit=False, proportional_edit_falloff='SMOOTH', proportional_size=1, use_proportional_connected=False, use_proportional_projected=False)
# move it up on y-axis
bpy.context.active_object.location[0] = math.sin(angle*i)*radius      
bpy.context.active_object.location[1] = math.cos(angle*i)*radius       
bpy.context.active_object.location[2] = 0



#i = 2


# works as expected  

setOriginToCursor(bpy.context.active_object)
# moved and rotated to the left from origin - horizontal
bpy.ops.transform.rotate(value = math.pi / 2, orient_axis='Z', orient_type='GLOBAL', orient_matrix=((1, 0, 0), (0, 1, 0), (0, 0, 1)), orient_matrix_type='GLOBAL', constraint_axis=(False, False, True), mirror=True, use_proportional_edit=False, proportional_edit_falloff='SMOOTH', proportional_size=1, use_proportional_connected=False, use_proportional_projected=False)

# expected: rotation "in place" - so same as before, but vertical
# but it is: in world origin :(
setOriginToGeometry(bpy.context.active_object)
bpy.ops.transform.rotate(value = math.pi / 2, orient_axis='Z', orient_type='GLOBAL', orient_matrix=((1, 0, 0), (0, 1, 0), (0, 0, 1)), orient_matrix_type='GLOBAL', constraint_axis=(False, False, True), mirror=True, use_proportional_edit=False, proportional_edit_falloff='SMOOTH', proportional_size=1, use_proportional_connected=False, use_proportional_projected=False)
$\endgroup$

1 Answer 1

2
$\begingroup$

Use variable names.

import bpy
context = bpy.context
scene = context.scene
ob = context.object

The context variable step is for when your test code works, and you wish to make an operator, can very easily copy an paste blocks of code. To where context is a usual suspect in operator and panel method arguments.

Reducing a line like

bpy.context.scene.cursor.location = bpy.context.active_object.location

to

scene.cursor.location = ob.location

Remove default settings from operators.

Sure can copy the complete operator call from the info window, but what of these settings do you need to set? Consult the docs, if it's default it's not required, reducing

bpy.ops.transform.rotate(
    value = math.pi * 2 - angle * i + math.pi / 2, 
    orient_axis='Z', 
    orient_type='GLOBAL', 
    orient_matrix=((1, 0, 0), (0, 1, 0), (0, 0, 1)), 
    orient_matrix_type='GLOBAL', 
    constraint_axis=(False, False, True), 
    mirror=True, 
    use_proportional_edit=False, 
    proportional_edit_falloff='SMOOTH', 
    proportional_size=1, 
    use_proportional_connected=False, 
    use_proportional_projected=False
    )

to.

bpy.ops.transform.rotate(
    value = math.pi * 2 - angle * i + math.pi / 2, 
    orient_axis='Z'
    )

to rotate globally (the default) about 'Z'.

What I think the issue is.

If using set origin to cursor, pays to know where that cursor is, and unless it is a script where this is used and set by the user first, make sure its location is a known entity.

scene.cursor.location = (0, 0, 0) # so we know where it is
setOriginToGeometry(ob)
bpy.ops.transform.rotate(value = math.pi / 2, orient_axis='Z')

IMO better still, make it an argument and pass it to your origin set method, and set it (and reset it) there

Or better still, just don't do it with operators, most of time they are not required & IMO it will drive you nuts, so instead I'm....

Revisiting this answer.

Thank you very much for your answer batFinger. Unfortunately i do not understand it. But that is my fault because i have just a few days experience with Blender python and i am pretty proud i made it that far (from my - i have no idea what i am doing - point of view ;). Hopefully i do understand your answer in a few weeks when i am diving deeper into that very amazing topic

This begs the question.. hows it going with operators?, am aware how we can become attached to getting a script to work...(guilty myself on many an occasion) IMO once we "See the light" will never return to using code designed basically as a UI interface to do simple tasks like transforms (translate, rotate, scale).

enter image description here

In this example add the scaled cylinder at (0, 0, 0)

Emulate the edit mode rotation of 90 about X axis, and translation of 1 (radius) units in Y direction with a translation and rotation matrix. The objects origin will remain at (0, 0, 0) and the mesh will be at 12 o'clock (top view) and can be simply rotated around the clock with its Z rotation property.

The Mesh.transform(matrix) uses the matrix supplied to transform all the vertices of the mesh in one fell swoop. A 4x4 (rowsxcolumns) transform matrix, like the matrix world is made up of its translation, rotation, scale parts

M = T @ R @ S 

Here we have use T and R

import bpy
from mathutils import Matrix
from math import pi

context = bpy.context
scene = context.scene
radius = 1
# create our object to array       
bpy.ops.mesh.primitive_cylinder_add(
        location=(0, 0, 0),
        scale=(0.1, 0.1, 1),
        )

ob = context.active_object
        
T = Matrix.Translation((0, radius, 0))
R = Matrix.Rotation(pi / 2, 4, 'X')
ob.data.transform(T @ R)

Effectively this has made our object lie in the XY plane, point up (+Y) and shifted its origin 1 down from its orginal location.

$\endgroup$
4
  • $\begingroup$ Thank you very much again batFINGER for your help. I appreciate it very very much that you answer that quick and so detailed!! although...again...i do understand just a half of your answer...but i will now learn about Matrix and translation and rotation...and then i will understand your answer completely! ;) at least i made it work ;) $\endgroup$
    – Chris
    Mar 11, 2021 at 11:37
  • $\begingroup$ after watching and reading several tutorials, i think i got it now - nearly. Just one question: why does R = Matrix.Rotation(pi / 2, 4, 'X') rotate around z-axis? I would have expected 'Z' to rotate around z-Axis. $\endgroup$
    – Chris
    Mar 13, 2021 at 14:50
  • 1
    $\begingroup$ The example above is the equivalent of adding a cylinder, go into edit mode, rotate 90 degrees about X (the matrix) making it lie in XY plane and then translate it +1 in Y. Then exit edit mode. The object has zero rotation, zero location and unit scale. And can be rotated about Z to emulate a clock hand for example using one rotation. Mesh.transform is == edit mode select all transfrom, without the need for any operators to mode switch or select etc. $\endgroup$
    – batFINGER
    Mar 13, 2021 at 15:21
  • $\begingroup$ Thank you very much!!! That helped me a lot! $\endgroup$
    – Chris
    Mar 14, 2021 at 5:56

You must log in to answer this question.

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