I have script (operator) which should align align all selected objects somewhat.
import bpy
from mathutils import Vector
class VCUTILS_OT_alignToLongest(bpy.types.Operator):
bl_idname = "object.align_to_longest"
bl_label = "Align Objects along their Longest Axis"
bl_description = "Create average vector from the longest edges and align object to have x axis along this vector"
bl_options = {'UNDO'}
shortestEdgeEvaluated = 0.8
def execute(self, context):
for obj in bpy.context.selected_objects:
if getattr(obj, 'type') in ['MESH']:
self.alignObject(obj)
return {'FINISHED'}
def alignObject(self, obj):
mesh = obj.data
# Apply object rotation
bpy.context.view_layer.objects.active = obj
bpy.ops.object.transform_apply(location=False, rotation=True, scale=False)
# Find longest edge length
longestD = 0.0
for edge in mesh.edges:
v1 = Vector(mesh.vertices[edge.vertices[0]].co)
v2 = Vector(mesh.vertices[edge.vertices[1]].co)
longestD = max(longestD, (v2 - v1).length)
# Find direction as an average of longest edges
axis = None
for edge in mesh.edges:
v1 = Vector(mesh.vertices[edge.vertices[0]].co)
v2 = Vector(mesh.vertices[edge.vertices[1]].co)
eVect = v2 - v1
if eVect.length >= longestD * VCUTILS_OT_alignToLongest.shortestEdgeEvaluated:
eVect.normalize()
if axis is None:
axis = eVect
else:
if axis.dot(eVect) > 0:
axis += eVect
else:
axis -= eVect
axis.normalize()
# Align the object according to major axis found
rotQuat = axis.to_track_quat('X', 'Z')
rotEuler = rotQuat.to_euler()
# rotEuler = ( 0, 0, 0.785 )
print("Euler: " + str(rotEuler))
obj.rotation_euler = rotEuler
# Rotate the mesh back
for v in mesh.vertices:
v.co = Vector(v.co) @ rotQuat.to_matrix()
print("Obj " + str(obj) + " done")
If I try it with that "proper rotation" it rotates the first selected object and ignores all others. It prints correct rotations for all objects to stdout, however. If I uncomment that line with "Rotation for debug" it rotates all selected objects to that fixed rotation.
I'am screwed now, I cannot imagine, where may be the problem ...
EDIT> Images before and after
. The leftmost selected is properly aligned. Other two selected not.
EDIT2> Added full script, python init and testfile
bl_info = {
"name": "VCUtils",
"author": "Vaclav Cermak <disnel@disnel.com>",
"description": "Various my utilities",
"version": (0, 9),
"blender": (2, 80, 0),
"location": "View3D",
"warning": "",
"category": "Generic"
}
import bpy
from . alignToLongest_op import VCUTILS_OT_alignToLongest
classes = (
VCUTILS_OT_alignToLongest,
)
def register():
for cls in classes:
bpy.utils.register_class(cls)
def unregister():
for cls in classes:
bpy.utils.unregister_class(cls)
bpy.ops.object.apply...
works on all selected objects, wheras you are calling it in a loop whilst changing active object, quite likely only the last set active object appears to "have worked" the others will be zeroed because of the op call. Kudos for putting the time into the script. However I would strongly recommend you please check out how I have done this in my answer. It is using no operators. Looping over hundreds of objects and calling operators blender will slow down considerably. $\endgroup$