| Code: |
| # ##### BEGIN GPL LICENSE BLOCK #####
# # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation, # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # # ##### END GPL LICENSE BLOCK ##### bl_info = { "name": "rotate_axis_dom", "author": "dom107", "version": (1,0), "blender": (2, 6, 3), "location": "View3D > Tool Shelf > Rotate Axis Panel", "description": "Rotate object local axis system according to a face normal of the object", "warning": "", "wiki_url": "", "tracker_url": "", "category": "Object"} import bpy from bpy.props import EnumProperty, BoolProperty from mathutils import Vector # Container for the rotate axis settings class rotate_axis_settings: def __init__(self, context, axis, invert_axis): print(" >>> rotate_axis_settings ", invert_axis, axis) self.context = context self.axis = axis self.invert_axis = invert_axis def rotate_axis(self, Config): bpy.ops.object.mode_set(mode='OBJECT') # scene = Config.context.scene ob_act = Config.context.active_object if not ob_act or ob_act.type != 'MESH': self.report({'INFO'}, "No mesh selected") return me = ob_act.data print(" 1 invert / axis", Config.invert_axis, Config.axis) faces_list = [face for face in me.polygons if face.select] if len(faces_list) == 1: selected_face = faces_list[0] face_normal = selected_face.normal print(" invert / axis", Config.invert_axis, Config.axis) if Config.axis == 'x': current_vector = Vector((1.0, 0.0, 0.0)) # X axis in local coordinates elif Config.axis == 'y': current_vector = Vector((0.0, 1.0, 0.0)) # Y axis in local coordinates else: current_vector = Vector((0.0, 0.0, 1.0)) # Z axis in local coordinates if Config.invert_axis == True: print(" invert") current_vector = - current_vector rot_mat = current_vector.rotation_difference(face_normal).to_matrix() ob_act.matrix_world *= rot_mat.to_4x4() # Rotate vertices in the other direction for face_num, face in enumerate(me.polygons): for vert_num, vertex in enumerate(face.vertices): me.vertices[face.vertices[vert_num]].co = rot_mat.inverted() * me.vertices[face.vertices[vert_num]].co else: self.report({'INFO'}, "Too many faces or no face selected") print(" Too many faces or no face selected ") def draw_axis_rename_panel(self, context): layout = self.layout sce = context.scene mode = context.mode col = layout.column(align=True) layout.prop(sce, "axis_choice_dropdown_prop") layout.prop(sce, "invert_axis") col = layout.column(align=True) class VIEW3D_PT_RotateAxis(bpy.types.Panel): bl_space_type = 'VIEW_3D' bl_region_type = 'TOOLS' bl_label = "Rotate Axis" bl_options = {'DEFAULT_CLOSED'} @classmethod def poll(cls, context): return (context.object is not None) def draw_header(self, context): layout = self.layout def draw(self, context): layout = self.layout row = layout.row(align=True) # layout.operator("idname_must.be_all_lowercase_and_contain_one_dot") layout.operator("object.rotate_axis_dom") draw_axis_rename_panel(self, context) class VIEW3D_OT_RotateAxis(bpy.types.Operator): bl_idname = "object.rotate_axis_dom" bl_label = "Apply axis rotation" # button label bl_description = "Rotate local axis system so that chosen axis is along a face normal" bl_options = {'REGISTER', 'UNDO'} print(" RotateAxis") axis_list = [ ( 'x', 'X', 'Map to X axis' ), # return value, name, description ( 'y', 'Y', 'Map to Y axis' ), ( 'z', 'Z', 'Map to Z axis' )] axis = EnumProperty( name="Axis", description="Map to an axis", items=axis_list) invert_axis = BoolProperty( name="Invert axis", description="Chosen axis will be in the opposite direction of the face normal.", default=False) def execute(self, context): print(" >>> VIEW3D_OT_RotateAxis ", self.invert_axis, self.axis) Config = rotate_axis_settings(context, axis=self.axis, invert_axis=self.invert_axis) rotate_axis(self, Config) return {'FINISHED'} # http://www.blender.org/documentation/blender_python_api_2_60_6/bpy.props.html def register(): bpy.utils.register_module(__name__) axis_list = [ ( 'x', 'X', 'Map to X axis' ), # return value, name, description ( 'y', 'Y', 'Map to Y axis' ), ( 'z', 'Z', 'Map to Z axis' )] bpy.types.Scene.axis_choice_dropdown_prop = bpy.props.EnumProperty( name="Axis", description="Map to an axis", items=axis_list) bpy.types.Scene.invert_axis = bpy.props.BoolProperty( name="Invert axis", description="If checked, chosen axis will be in the opposite direction of the face normal", default=False) def unregister(): bpy.utils.unregister_module(__name__) # Remove properties del bpy.types.Scene.axis_choice_dropdown_prop del bpy.types.Scene.invert_axis if __name__ == '__main__': register() if __name__ == "__main__": register() |
| Quote: |
|
# ##### BEGIN GPL LICENSE BLOCK ##### # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation, # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # # ##### END GPL LICENSE BLOCK ##### bl_info = { "name": "rotate_axis_dom", "author": "dom107", "version": (1,0), "blender": (2, 66, 0), "location": "View3D > Tool Shelf > Rotate Axis Panel", "description": "Rotate object local axis system along a face normal of a selected object", "warning": "", "wiki_url": "", "tracker_url": "", "category": "Object"} import bpy from mathutils import Vector class RotateAxisUi(bpy.types.Panel): bl_space_type = 'VIEW_3D' bl_region_type = 'TOOLS' bl_label = "Rotate axis" bl_description = "Rotate local axis system so that chosen axis is along a face normal (object scale must be even along each axis)" bl_options = {'DEFAULT_CLOSED'} def draw(self, context): layout = self.layout obj = context.object col = layout.column_flow(columns=5,align=True) col.operator("object.rot_location_x",text="X") col.operator("object.rot_location_y",text="Y") col.operator("object.rot_location_z",text="Z") col = layout.column_flow(columns=5,align=True) col.operator("object.rot_location_xm",text="-X") col.operator("object.rot_location_ym",text="-Y") col.operator("object.rot_location_zm",text="-Z") def process_object_axis_rotation(obj, rot_mat): # Rotate object vertices in opposite direction me = obj.data for vertex in me.vertices: vertex.co = rot_mat.to_quaternion().inverted() * vertex.co # Update object matrix applying rotation obj.matrix_world *= rot_mat.to_4x4() def rotate_axis(self, axis): bpy.ops.object.mode_set(mode='OBJECT') if len(bpy.context.selected_objects) != 1: self.report({'INFO'}, "Please select one mesh") return obj_selected = bpy.context.selected_objects[0] if obj_selected.type != 'MESH': self.report({'INFO'}, "No mesh selected") return me = obj_selected.data faces_list = [face for face in me.polygons if face.select] if len(faces_list) == 1: selected_face = faces_list[0] face_normal = selected_face.normal # face normal in local coordinates if axis == 'x': axis_to_move = Vector((1.0, 0.0, 0.0)) # X axis in local coordinates elif axis == 'y': axis_to_move = Vector((0.0, 1.0, 0.0)) # Y axis in local coordinates elif axis == 'z': axis_to_move = Vector((0.0, 0.0, 1.0)) # Z axis in local coordinates elif axis == '-x': axis_to_move = Vector((-1.0, 0.0, 0.0)) # -X axis in local coordinates elif axis == '-y': axis_to_move = Vector((0.0, -1.0, 0.0)) # -Y axis in local coordinates else: axis_to_move = Vector((0.0, 0.0, -1.0)) # -Z axis in local coordinates #print(" axis_to_move", axis_to_move) # Rotation matrix (3x3) rot_mat = axis_to_move.rotation_difference(face_normal).to_matrix() process_object_axis_rotation(obj_selected, rot_mat) else: self.report({'INFO'}, "Too many faces or no face selected") # Classes class RotateXOperator(bpy.types.Operator): """""" bl_idname = "object.rot_location_x" bl_label = "Apply X axis rotation" bl_description = "Rotate local axis system so that the X axis is along a selected face normal (object scale must be even along each axis)" @classmethod def poll(cls, context): return context.active_object != None def execute(self, context): rotate_axis(self, 'x') return {'FINISHED'} class RotateYOperator(bpy.types.Operator): """""" bl_idname = "object.rot_location_y" bl_label = "Apply Y axis rotation" bl_description = "Rotate local axis system so that the Y axis is along a selected face normal (object scale must be even along each axis)" @classmethod def poll(cls, context): return context.active_object != None def execute(self, context): rotate_axis(self, 'y') return {'FINISHED'} class RotateZOperator(bpy.types.Operator): """""" bl_idname = "object.rot_location_z" bl_label = "Apply Z axis rotation" bl_description = "Rotate local axis system so that the Z axis is along a selected face normal (object scale must be even along each axis)" @classmethod def poll(cls, context): return context.active_object != None def execute(self, context): rotate_axis(self, 'z') return {'FINISHED'} class RotateXmOperator(bpy.types.Operator): """""" bl_idname = "object.rot_location_xm" bl_label = "Apply -X axis rotation" bl_description = "Rotate local axis system so that the X axis is opposite to a selected face normal (object scale must be even along each axis)" @classmethod def poll(cls, context): return context.active_object != None def execute(self, context): rotate_axis(self, '-x') return {'FINISHED'} class RotateYmOperator(bpy.types.Operator): """""" bl_idname = "object.rot_location_ym" bl_label = "Apply -Y axis rotation" bl_description = "Rotate local axis system so that the Y axis is opposite to a selected face normal (object scale must be even along each axis)" @classmethod def poll(cls, context): return context.active_object != None def execute(self, context): rotate_axis(self, '-y') return {'FINISHED'} class RotateZmOperator(bpy.types.Operator): """""" bl_idname = "object.rot_location_zm" bl_label = "Apply -Z axis rotation" bl_description = "Rotate local axis system so that the Z axis is opposite to a selected face normal (object scale must be even along each axis)" @classmethod def poll(cls, context): return context.active_object != None def execute(self, context): rotate_axis(self, '-z') return {'FINISHED'} def register(): bpy.utils.register_module(__name__) pass def unregister(): bpy.utils.unregister_module(__name__) pass if __name__ == "__main__": register() |