Previous Thread  Next Thread

chat icon Rotate object coordinate system

dom107

Posted: Mon Nov 05, 2012 2:33 pm
Joined: 18 Apr 2012
Posts: 35
Hello,

I started a script to rotate an object coordinate system so that a chosen axis (from the object coordinate system) is normal to an object face.

The following scripts works (children objects are not processed) but:
1) It seems to remember a previous selection when execting several times without an explicit new selection.
2) It allows execute for the x axis (default).

Thanks for your help.

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()   
Reply with quote


dom107

Posted: Mon Nov 05, 2012 2:36 pm
Joined: 18 Apr 2012
Posts: 35
2) It only executes for the x axis (default).

(not "2) It allows execute for the x axis (default). ")
Reply with quote


dom107

Posted: Tue Mar 26, 2013 12:52 pm
Joined: 18 Apr 2012
Posts: 35
Hello,

I've rewritten the script. It works well provided the object is evenly scaled along its axes.


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()
Reply with quote


 
Jump to:  
Powered by phpBB © 2001, 2005 phpBB Group