# Turn an object according the normal of a selected face from second mesh

I'm trying to find a way to place an object on the selected face from another object according the normal face.

I'd like the local orientation of my first object correspond to the normals of the selected face from my second object.

This is my code.

import bpy
import bmesh
from mathutils import Vector

class TestPanel(bpy.types.Panel):
bl_idname = "object.test_panel"
bl_label = "Test Panel"
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'

def draw(self, context):
layout = self.layout

bl_idname = "object.clone_object"
bl_label = "Clone object"

def execute(self, context):

if context.object.mode == 'EDIT':
bpy.ops.object.mode_set(mode='OBJECT')
obj = bpy.context.active_object

bm = bmesh.new()
bm.from_mesh(obj.data)

selected_faces = [f for f in bm.faces if f.select]

for face in selected_faces:

face_location = face.calc_center_median()
loc_world_space = obj.matrix_world * Vector(face_location)
z = Vector((0,0,1))

angle = face.normal.angle(z)
axis = z.cross(face.normal)
bpy.context.scene.cursor_location = loc_world_space

bpy.ops.transform.rotate(value=angle, axis=axis)

print("face location = ", loc_world_space)
print("angle = ", angle)
print("axis = ", axis)
print("Suzanne = ", context.active_object.matrix_world)

bm.to_mesh(obj.data)
bm.free()

return {'FINISHED'}

else:
self.report({'INFO'}, "Need to be in edit_mode")

return {'FINISHED'}

def register():
bpy.utils.register_module(__name__)

def unregister():
bpy.utils.unregister_module(__name__)

if __name__ == "__main__":
register()


The X and Y axis are good, but the Z axis seems not to undergo rotation.

Made a couple of changes to this script, the main one is using the Vector.rotation_difference method instead of the angle method. This one calculates rotation in all 3 axes.

import bpy
import bmesh
from mathutils import Vector
from math import degrees # Added for more readable printing of rotation angles

class TestPanel(bpy.types.Panel):
bl_idname = "object.test_panel"
bl_label = "Test Panel"
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'

def draw(self, context):
layout = self.layout

bl_idname = "object.clone_object"
bl_label = "Clone object"

def execute(self, context):

if context.object.mode == 'EDIT':
bpy.ops.object.mode_set(mode='OBJECT')
obj = bpy.context.active_object

bm = bmesh.new()
bm.from_mesh(obj.data)

selected_faces = [f for f in bm.faces if f.select]

for face in selected_faces:

face_location = face.calc_center_median()
loc_world_space = obj.matrix_world * Vector(face_location)
z = Vector((0,0,1))

# Changes start here
rot = z.rotation_difference( face.normal ).to_euler()
bpy.context.scene.cursor_location = loc_world_space

bpy.context.object.rotatation_euler = rot

print("face location = ", loc_world_space)
print("rotation = ", [degrees(a) for a in rot] )
print("Suzanne = ", context.active_object.matrix_world)
# And End here

bm.to_mesh(obj.data)
bm.free()

return {'FINISHED'}

else:
self.report({'INFO'}, "Need to be in edit_mode")

return {'FINISHED'}

def register():
bpy.utils.register_module(__name__)

def unregister():
bpy.utils.unregister_module(__name__)

if __name__ == "__main__":
register()

• Thanks for your answer, but the probleme stay the same. The Z axis got the good direction but his rotation value is not the same as the Z axis of the normal face :( – pistiwique Dec 12 '15 at 12:31
• I see, shame. Will have another look when I can. – TLousky Dec 12 '15 at 15:29
• Thanks, but i finally find the solution in the answer of CoDEmanX from this question : blender.stackexchange.com/questions/7150/… – pistiwique Dec 12 '15 at 18:20