# Python function behaves differently in a loop?

I rather hastily wrote a short python script which orients the local rotation of an object so the Y goes along the longest axis, without affecting the apparent global orientation.

import bpy
import math

def set_orientation(ob, target_rotation):
bpy.context.scene.objects.active = ob
#ob: object to operate on

#this assumes you are starting at 0 rotaton, so you pobably want to apply rotation before doing anything:
bpy.ops.object.transform_apply(location=False, rotation=True, scale=False) #apply rotation
#get inverse of rotation we want:
#we need to apply the rotations in reverse order, so unsure that we are in zyx:
ob.rotation_mode = 'ZYX'
ob.rotation_euler = (t_rot) #set rotation to inverse
bpy.ops.object.transform_apply(location=False, rotation=True, scale=False) #apply rotation

ob.rotation_mode = 'XYZ' #set rotation mode back (was zyx, so we want xyz)
ob.rotation_euler = (t_rot) #set rotation

def fix_orientation(ob):
if ob.type != 'MESH':
return

d = ob.dimensions
correction = (0,0,0)

if d > d and d > d:
correction = (0,0,90)

if d > d and d > d:
correction = (0,0,0)

if d > d and d > d:
correction = (90,0,0)

# hack for fixing rotation on boards at 45 degree angles:
if abs(d - d) < .1:
correction = (0,0,45)

if abs(d - d) < .1:
correction = (0,45,0)

if abs(d - d) < .1:
correction = (45,0,0)

set_orientation(ob, correction)

for ob in bpy.data.objects:
# doesn't work as expected
fix_orientation(ob)

# works as expected:
#fix_orientation(bpy.context.object)


However when I run the function fix_orientation() from within the loop, it changes the actual object rotation in global space. This doesn't happen if I just call it once on the active object.

Why is it only working as intended when called once?
What am I doing wrong (aside from the rather uncleanly implementation)? • Interesting. Another way would be to manipulate the mesh vertex coords v.co = v.co.yxz would swap x and y for instance, would probably naff some of the normals tho. Nov 18, 2015 at 15:26

The loop is not the problem. The dimensions are based on the selection, which is why running the loop did not work.

All you need is to add in selection and deselection to your script.

Notice on line 6 ob.select = True and on line 25 ob.select = False. That selects the object the loop is working on, then deselects it when that iteration of the loop is done.
The reason you need to select and deselect each object is because ob.dimensions is the bounding box of the selection, not just one object.
Which is why it seamed to work for only one object at a time.

Entire script:

import bpy
import math

def set_orientation(ob, target_rotation):
bpy.context.scene.objects.active = ob
ob.select = True
#ob: object to operate on

#this assumes you are starting at 0 rotaton, so you pobably want to apply rotation before doing anything:
bpy.ops.object.transform_apply(location=False, rotation=True, scale=False) #apply rotation
#get inverse of rotation we want:
#we need to apply the rotations in reverse order, so unsure that we are in zyx:
ob.rotation_mode = 'ZYX'
ob.rotation_euler = (t_rot) #set rotation to inverse
bpy.ops.object.transform_apply(location=False, rotation=True, scale=False) #apply rotation

ob.rotation_mode = 'XYZ' #set rotation mode back (was zyx, so we want xyz)
ob.rotation_euler = (t_rot) #set rotation
ob.select = False

def fix_orientation(ob):
if ob.type != 'MESH':
return

d = ob.dimensions
correction = (0,0,0)

if d > d and d > d:
correction = (0,0,90)

if d > d and d > d:
correction = (0,0,0)

if d > d and d > d:
correction = (90,0,0)

# hack for fixing rotation on boards at 45 degree angles:
if abs(d - d) < .1:
correction = (0,0,45)

if abs(d - d) < .1:
correction = (0,45,0)

if abs(d - d) < .1:
correction = (45,0,0)

set_orientation(ob, correction)

for ob in bpy.data.objects:
fix_orientation(ob)