Skip to content
Snippets Groups Projects
vertex_align.py 8.06 KiB
Newer Older
  • Learn to ignore specific revisions
  • # SPDX-License-Identifier: GPL-2.0-or-later
    
    
    # Note: Property group was moved to __init__
    
    bl_info = {
        "name": "Vertex Align",
        "author": "",
        "version": (0, 1, 7),
        "blender": (2, 61, 0),
        "location": "View3D > Tool Shelf",
        "description": "",
        "warning": "",
    
        "doc_url": "",
        "category": "Mesh",
    }
    
    
    
    import bpy
    from bpy.props import (
            BoolVectorProperty,
            FloatVectorProperty,
            )
    from mathutils import Vector
    from bpy.types import Operator
    
    
    # Edit Mode Toggle
    def edit_mode_out():
        bpy.ops.object.mode_set(mode='OBJECT')
    
    
    def edit_mode_in():
        bpy.ops.object.mode_set(mode='EDIT')
    
    
    def get_mesh_data_():
        edit_mode_out()
        ob_act = bpy.context.active_object
        me = ob_act.data
        edit_mode_in()
        return me
    
    
    def list_clear_(l):
        l[:] = []
        return l
    
    
    class va_buf():
        list_v = []
        list_0 = []
    
    
    # Store The Vertex coordinates
    class Vertex_align_store(Operator):
        bl_idname = "vertex_align.store_id"
        bl_label = "Active Vertex"
        bl_description = ("Store Selected Vertex coordinates as an align point\n"
                          "Single Selected Vertex only")
    
        @classmethod
        def poll(cls, context):
            obj = context.active_object
            return (obj and obj.type == 'MESH' and context.mode == 'EDIT_MESH')
    
        def execute(self, context):
            try:
                me = get_mesh_data_()
                list_0 = [v.index for v in me.vertices if v.select]
    
                if len(list_0) == 1:
                    list_clear_(va_buf.list_v)
                    for v in me.vertices:
                        if v.select:
                            va_buf.list_v.append(v.index)
                            bpy.ops.mesh.select_all(action='DESELECT')
                else:
                    self.report({'WARNING'}, "Please select just One Vertex")
                    return {'CANCELLED'}
            except:
                self.report({'WARNING'}, "Storing selection could not be completed")
                return {'CANCELLED'}
    
            self.report({'INFO'}, "Selected Vertex coordinates are stored")
    
            return {'FINISHED'}
    
    
    # Align to original
    class Vertex_align_original(Operator):
        bl_idname = "vertex_align.align_original"
        bl_label = "Align to original"
        bl_description = "Align selection to stored single vertex coordinates"
        bl_options = {'REGISTER', 'UNDO'}
    
        @classmethod
        def poll(cls, context):
            obj = context.active_object
            return (obj and obj.type == 'MESH' and context.mode == 'EDIT_MESH')
    
        def draw(self, context):
            layout = self.layout
            layout.label(text="Axis:")
    
            row = layout.row(align=True)
            row.prop(context.scene.mesh_extra_tools, "vert_align_axis",
                     text="X", index=0, toggle=True)
            row.prop(context.scene.mesh_extra_tools, "vert_align_axis",
                     text="Y", index=1, toggle=True)
            row.prop(context.scene.mesh_extra_tools, "vert_align_axis",
                     text="Z", index=2, toggle=True)
    
        def execute(self, context):
            edit_mode_out()
            ob_act = context.active_object
            me = ob_act.data
            cen1 = context.scene.mesh_extra_tools.vert_align_axis
            list_0 = [v.index for v in me.vertices if v.select]
    
            if len(va_buf.list_v) == 0:
                self.report({'INFO'},
                            "Original vertex not stored in memory. Operation Cancelled")
                edit_mode_in()
                return {'CANCELLED'}
    
            elif len(va_buf.list_v) != 0:
                if len(list_0) == 0:
                    self.report({'INFO'}, "No vertices selected. Operation Cancelled")
                    edit_mode_in()
                    return {'CANCELLED'}
    
                elif len(list_0) != 0:
                    vo = (me.vertices[va_buf.list_v[0]].co).copy()
                    if cen1[0] is True:
                        for i in list_0:
                            v = (me.vertices[i].co).copy()
                            me.vertices[i].co = Vector((vo[0], v[1], v[2]))
                    if cen1[1] is True:
                        for i in list_0:
                            v = (me.vertices[i].co).copy()
                            me.vertices[i].co = Vector((v[0], vo[1], v[2]))
                    if cen1[2] is True:
                        for i in list_0:
                            v = (me.vertices[i].co).copy()
                            me.vertices[i].co = Vector((v[0], v[1], vo[2]))
            edit_mode_in()
    
            return {'FINISHED'}
    
    
    # Align to custom coordinates
    class Vertex_align_coord_list(Operator):
        bl_idname = "vertex_align.coord_list_id"
        bl_label = ""
        bl_description = "Align to custom coordinates"
    
        @classmethod
        def poll(cls, context):
            obj = context.active_object
            return (obj and obj.type == 'MESH' and context.mode == 'EDIT_MESH')
    
        def execute(self, context):
            edit_mode_out()
            ob_act = context.active_object
            me = ob_act.data
            list_clear_(va_buf.list_0)
            va_buf.list_0 = [v.index for v in me.vertices if v.select][:]
    
            if len(va_buf.list_0) == 0:
                self.report({'INFO'}, "No vertices selected. Operation Cancelled")
                edit_mode_in()
                return {'CANCELLED'}
    
            elif len(va_buf.list_0) != 0:
                bpy.ops.vertex_align.coord_menu_id('INVOKE_DEFAULT')
    
            edit_mode_in()
    
            return {'FINISHED'}
    
    
    # Align to custom coordinates menu
    class Vertex_align_coord_menu(Operator):
        bl_idname = "vertex_align.coord_menu_id"
        bl_label = "Tweak custom coordinates"
        bl_description = "Change the custom coordinates for aligning"
        bl_options = {'REGISTER', 'UNDO'}
    
        def_axis_coord: FloatVectorProperty(
                name="",
                description="Enter the values of coordinates",
                default=(0.0, 0.0, 0.0),
                min=-100.0, max=100.0,
                step=1, size=3,
                subtype='XYZ',
                precision=3
                )
        use_axis_coord = BoolVectorProperty(
                name="Axis",
                description="Choose Custom Coordinates axis",
                default=(False,) * 3,
                size=3,
                )
        is_not_undo = False
    
        @classmethod
        def poll(cls, context):
            obj = context.active_object
            return (obj and obj.type == 'MESH')
    
        def using_store(self, context):
            scene = context.scene
            return scene.mesh_extra_tools.vert_align_use_stored
    
        def draw(self, context):
            layout = self.layout
    
            if self.using_store(context) and self.is_not_undo:
                layout.label(text="Using Stored Coordinates", icon="INFO")
    
            row = layout.split(0.25)
            row.prop(self, "use_axis_coord", index=0, text="X")
            row.prop(self, "def_axis_coord", index=0)
    
            row = layout.split(0.25)
            row.prop(self, "use_axis_coord", index=1, text="Y")
            row.prop(self, "def_axis_coord", index=1)
    
            row = layout.split(0.25)
            row.prop(self, "use_axis_coord", index=2, text="Z")
            row.prop(self, "def_axis_coord", index=2)
    
        def invoke(self, context, event):
            self.is_not_undo = True
            scene = context.scene
            if self.using_store(context):
                self.def_axis_coord = scene.mesh_extra_tools.vert_align_store_axis
    
            return context.window_manager.invoke_props_dialog(self, width=200)
    
        def execute(self, context):
            self.is_not_undo = False
            edit_mode_out()
            ob_act = context.active_object
            me = ob_act.data
    
            for i in va_buf.list_0:
                v = (me.vertices[i].co).copy()
                tmp = Vector((v[0], v[1], v[2]))
    
                if self.use_axis_coord[0] is True:
                    tmp[0] = self.def_axis_coord[0]
                if self.use_axis_coord[1] is True:
                    tmp[1] = self.def_axis_coord[1]
                if self.use_axis_coord[2] is True:
                    tmp[2] = self.def_axis_coord[2]
                me.vertices[i].co = tmp
    
            edit_mode_in()
    
            return {'FINISHED'}
    
    
    #  Register
    classes = (
        Vertex_align_store,
        Vertex_align_original,
        Vertex_align_coord_list,
        Vertex_align_coord_menu,
        )
    
    
    def register():
        for cls in classes:
            bpy.utils.register_class(cls)
    
    
    def unregister():
        for cls in classes:
            bpy.utils.unregister_class(cls)
    
    
    if __name__ == "__main__":
        register()