# ##### 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": "Hotkey: 'Alt X'", "description": "V/E/F Align tools", # "author": "pitiwazou, meta-androcto", # "version": (0, 1, 0), "blender": (2, 77, 0), "location": "Mesh Edit Mode", "warning": "", "wiki_url": "", "category": "Edit Align Pie" } import bpy from bpy.types import ( Menu, Operator, ) # Pie Align - Alt + X class PieAlign(Menu): bl_idname = "pie.align" bl_label = "Pie Align" def draw(self, context): layout = self.layout pie = layout.menu_pie() # 4 - LEFT pie.operator("align.x", text="Align X", icon='TRIA_LEFT') # 6 - RIGHT pie.operator("align.z", text="Align Z", icon='TRIA_DOWN') # 2 - BOTTOM pie.operator("align.y", text="Align Y", icon='PLUS') # 8 - TOP pie.operator("align.2y0", text="Align To Y-0") # 7 - TOP - LEFT pie.operator("align.2x0", text="Align To X-0") # 9 - TOP - RIGHT pie.operator("align.2z0", text="Align To Z-0") # 1 - BOTTOM - LEFT pie.separator() # 3 - BOTTOM - RIGHT # pie.menu("align.xyz") box = pie.split().box().column() row = box.row(align=True) row.label("X") row.operator("alignx.left", text="Neg") row.operator("alignx.right", text="Pos") row = box.row(align=True) row.label("Y") row.operator("aligny.front", text="Neg") row.operator("aligny.back", text="Pos") row = box.row(align=True) row.label("Z") row.operator("alignz.bottom", text="Neg") row.operator("alignz.top", text="Pos") # Align X class AlignX(Operator): bl_idname = "align.x" bl_label = "Align X" bl_description = "Align Selected Along X" bl_options = {'REGISTER', 'UNDO'} def execute(self, context): for vert in bpy.context.object.data.vertices: bpy.ops.transform.resize(value=(0, 1, 1), constraint_axis=(True, False, False), constraint_orientation='GLOBAL', mirror=False, proportional='DISABLED', proportional_edit_falloff='SMOOTH', proportional_size=1) return {'FINISHED'} # Align Y class AlignY(Operator): bl_idname = "align.y" bl_label = "Align Y" bl_description = "Align Selected Along Y" bl_options = {'REGISTER', 'UNDO'} def execute(self, context): for vert in bpy.context.object.data.vertices: bpy.ops.transform.resize(value=(1, 0, 1), constraint_axis=(False, True, False), constraint_orientation='GLOBAL', mirror=False, proportional='DISABLED', proportional_edit_falloff='SMOOTH', proportional_size=1) return {'FINISHED'} # Align Z class AlignZ(Operator): bl_idname = "align.z" bl_label = "Align Z" bl_description = "Align Selected Along Z" bl_options = {'REGISTER', 'UNDO'} def execute(self, context): for vert in bpy.context.object.data.vertices: bpy.ops.transform.resize(value=(1, 1, 0), constraint_axis=(False, False, True), constraint_orientation='GLOBAL', mirror=False, proportional='DISABLED', proportional_edit_falloff='SMOOTH', proportional_size=1) return {'FINISHED'} ##################### # Align To 0 # ##################### # Align to X - 0 class AlignToX0(Operator): bl_idname = "align.2x0" bl_label = "Align To X = 0" bl_description = "Align Selected To Location X = 0" bl_options = {'REGISTER', 'UNDO'} def execute(self, context): bpy.ops.object.mode_set(mode='OBJECT') for vert in bpy.context.object.data.vertices: if vert.select: vert.co[0] = 0 bpy.ops.object.editmode_toggle() return {'FINISHED'} # Align to Z - 0 class AlignToY0(Operator): bl_idname = "align.2y0" bl_label = "Align To Y = 0" bl_description = "Align Selected To Location Y = 0" bl_options = {'REGISTER', 'UNDO'} def execute(self, context): bpy.ops.object.mode_set(mode='OBJECT') for vert in bpy.context.object.data.vertices: if vert.select: vert.co[1] = 0 bpy.ops.object.editmode_toggle() return {'FINISHED'} # Align to Z - 0 class AlignToZ0(Operator): bl_idname = "align.2z0" bl_label = "Align To Z = 0" bl_description = "Align Selected To Location Z = 0" bl_options = {'REGISTER', 'UNDO'} def execute(self, context): bpy.ops.object.mode_set(mode='OBJECT') for vert in bpy.context.object.data.vertices: if vert.select: vert.co[2] = 0 bpy.ops.object.editmode_toggle() return {'FINISHED'} # Align X Left class AlignXLeft(Operator): bl_idname = "alignx.left" bl_label = "Align X Left" bl_options = {'REGISTER', 'UNDO'} def execute(self, context): bpy.ops.object.mode_set(mode='OBJECT') count = 0 axe = 0 for vert in bpy.context.object.data.vertices: if vert.select: if count == 0: max = vert.co[axe] count += 1 continue count += 1 if vert.co[axe] < max: max = vert.co[axe] bpy.ops.object.mode_set(mode='OBJECT') for vert in bpy.context.object.data.vertices: if vert.select: vert.co[axe] = max bpy.ops.object.mode_set(mode='EDIT') return {'FINISHED'} # Align X Right class AlignXRight(Operator): bl_idname = "alignx.right" bl_label = "Align X Right" def execute(self, context): bpy.ops.object.mode_set(mode='OBJECT') count = 0 axe = 0 for vert in bpy.context.object.data.vertices: if vert.select: if count == 0: max = vert.co[axe] count += 1 continue count += 1 if vert.co[axe] > max: max = vert.co[axe] bpy.ops.object.mode_set(mode='OBJECT') for vert in bpy.context.object.data.vertices: if vert.select: vert.co[axe] = max bpy.ops.object.mode_set(mode='EDIT') return {'FINISHED'} # Align Y Back class AlignYBack(Operator): bl_idname = "aligny.back" bl_label = "Align Y back" bl_options = {'REGISTER', 'UNDO'} def execute(self, context): bpy.ops.object.mode_set(mode='OBJECT') count = 0 axe = 1 for vert in bpy.context.object.data.vertices: if vert.select: if count == 0: max = vert.co[axe] count += 1 continue count += 1 if vert.co[axe] > max: max = vert.co[axe] bpy.ops.object.mode_set(mode='OBJECT') for vert in bpy.context.object.data.vertices: if vert.select: vert.co[axe] = max bpy.ops.object.mode_set(mode='EDIT') return {'FINISHED'} # Align Y Front class AlignYFront(Operator): bl_idname = "aligny.front" bl_label = "Align Y Front" bl_options = {'REGISTER', 'UNDO'} def execute(self, context): bpy.ops.object.mode_set(mode='OBJECT') count = 0 axe = 1 for vert in bpy.context.object.data.vertices: if vert.select: if count == 0: max = vert.co[axe] count += 1 continue count += 1 if vert.co[axe] < max: max = vert.co[axe] bpy.ops.object.mode_set(mode='OBJECT') for vert in bpy.context.object.data.vertices: if vert.select: vert.co[axe] = max bpy.ops.object.mode_set(mode='EDIT') return {'FINISHED'} # Align Z Top class AlignZTop(Operator): bl_idname = "alignz.top" bl_label = "Align Z Top" bl_options = {'REGISTER', 'UNDO'} def execute(self, context): bpy.ops.object.mode_set(mode='OBJECT') count = 0 axe = 2 for vert in bpy.context.object.data.vertices: if vert.select: if count == 0: max = vert.co[axe] count += 1 continue count += 1 if vert.co[axe] > max: max = vert.co[axe] bpy.ops.object.mode_set(mode='OBJECT') for vert in bpy.context.object.data.vertices: if vert.select: vert.co[axe] = max bpy.ops.object.mode_set(mode='EDIT') return {'FINISHED'} # Align Z Bottom class AlignZBottom(Operator): bl_idname = "alignz.bottom" bl_label = "Align Z Bottom" bl_options = {'REGISTER', 'UNDO'} def execute(self, context): bpy.ops.object.mode_set(mode='OBJECT') count = 0 axe = 2 for vert in bpy.context.object.data.vertices: if vert.select: if count == 0: max = vert.co[axe] count += 1 continue count += 1 if vert.co[axe] < max: max = vert.co[axe] bpy.ops.object.mode_set(mode='OBJECT') for vert in bpy.context.object.data.vertices: if vert.select: vert.co[axe] = max bpy.ops.object.mode_set(mode='EDIT') return {'FINISHED'} classes = ( PieAlign, AlignX, AlignY, AlignZ, AlignToX0, AlignToY0, AlignToZ0, AlignXLeft, AlignXRight, AlignYBack, AlignYFront, AlignZTop, AlignZBottom, ) addon_keymaps = [] def register(): for cls in classes: bpy.utils.register_class(cls) wm = bpy.context.window_manager if wm.keyconfigs.addon: # Align km = wm.keyconfigs.addon.keymaps.new(name='Mesh') kmi = km.keymap_items.new('wm.call_menu_pie', 'X', 'PRESS', alt=True) kmi.properties.name = "pie.align" # kmi.active = True addon_keymaps.append((km, kmi)) def unregister(): for cls in classes: bpy.utils.unregister_class(cls) wm = bpy.context.window_manager kc = wm.keyconfigs.addon if kc: km = kc.keymaps['Mesh'] for kmi in km.keymap_items: if kmi.idname == 'wm.call_menu_pie': if kmi.properties.name == "pie.align": km.keymap_items.remove(kmi) if __name__ == "__main__": register()