Permalink
Cannot retrieve contributors at this time
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Blender_add-ons/AutoMirror/AutoMirror_V2-4.py /
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
203 lines (159 sloc)
9.4 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| ###################################################################################################### | |
| # An simple add-on to auto cut in two and mirror an object # | |
| # Actualy partialy uncommented (see further version) # | |
| # Author: Lapineige # | |
| # License: GPL v3 # | |
| ###################################################################################################### | |
| ############# Add-on description (used by Blender) | |
| bl_info = { | |
| "name": "Auto Mirror", | |
| "description": "Super fast cutting and mirroring for mesh", | |
| "author": "Lapineige", | |
| "version": (2, 4), | |
| "blender": (2, 7, 1), | |
| "location": "View 3D > Toolbar > Tools tab > AutoMirror (panel)", | |
| "warning": "", | |
| "wiki_url": "http://www.le-terrier-de-lapineige.over-blog.com", | |
| "tracker_url": "http://blenderlounge.fr/forum/viewtopic.php?f=18&p=7103#p7103", | |
| "category": "Mesh"} | |
| ############# | |
| import bpy | |
| from mathutils import Vector | |
| bpy.types.Scene.AutoMirror_axis = bpy.props.EnumProperty(items = [("x", "X", "", 1),("y", "Y", "", 2),("z", "Z", "", 3)], description="Axis used by the mirror modifier") | |
| bpy.types.Scene.AutoMirror_orientation = bpy.props.EnumProperty(items = [("positive", "Positive", "", 1),("negative", "Negative", "", 2)], description="Choose the side along the axis of the editable part (+/- coordinates)") | |
| bpy.types.Scene.AutoMirror_threshold = bpy.props.FloatProperty(default= 0.001, min= 0.001, description="Vertices closer than this distance are merged on the loopcut") | |
| bpy.types.Scene.AutoMirror_toggle_edit = bpy.props.BoolProperty(default= True, description="If not in edit mode, change mode to edit") | |
| bpy.types.Scene.AutoMirror_cut = bpy.props.BoolProperty(default= True, description="If enabeled, cut the mesh in two parts and mirror it. If not, just make a loopcut") | |
| bpy.types.Scene.AutoMirror_clipping = bpy.props.BoolProperty(default=True) | |
| bpy.types.Scene.AutoMirror_use_clip = bpy.props.BoolProperty(default=True, description="Use clipping for the mirror modifier") | |
| bpy.types.Scene.AutoMirror_show_on_cage = bpy.props.BoolProperty(default=True, description="Enable to edit the cage (it's the classical modifier's option)") | |
| bpy.types.Scene.AutoMirror_apply_mirror = bpy.props.BoolProperty(description="Apply the mirror modifier (useful to symmetrise the mesh)") | |
| ############### Operator | |
| class AlignVertices(bpy.types.Operator): | |
| """ """ | |
| bl_idname = "object.align_vertices" | |
| bl_label = "Align Vertices on 1 Axis" | |
| @classmethod | |
| def poll(cls, context): | |
| return True | |
| def execute(self, context): | |
| bpy.ops.object.mode_set(mode = 'OBJECT') | |
| x1,y1,z1 = bpy.context.scene.cursor_location | |
| bpy.ops.view3d.snap_cursor_to_selected() | |
| x2,y2,z2 = bpy.context.scene.cursor_location | |
| bpy.context.scene.cursor_location[0],bpy.context.scene.cursor_location[1],bpy.context.scene.cursor_location[2] = 0,0,0 | |
| #Vertices coordinate to 0 (local coordinate, so on the origin) | |
| for vert in bpy.context.object.data.vertices: | |
| if vert.select: | |
| if bpy.context.scene.AutoMirror_axis == 'x': | |
| axis = 0 | |
| elif bpy.context.scene.AutoMirror_axis == 'y': | |
| axis = 1 | |
| elif bpy.context.scene.AutoMirror_axis == 'z': | |
| axis = 2 | |
| vert.co[axis] = 0 | |
| # | |
| bpy.context.scene.cursor_location = x2,y2,z2 | |
| bpy.ops.object.origin_set(type='ORIGIN_CURSOR') | |
| bpy.context.scene.cursor_location = x1,y1,z1 | |
| bpy.ops.object.mode_set(mode = 'EDIT') | |
| return {'FINISHED'} | |
| class AutoMirror(bpy.types.Operator): | |
| """ Automatically cut an object along an axis """ | |
| bl_idname = "object.automirror" | |
| bl_label = "AutoMirror" | |
| bl_options = {'REGISTER'} # 'UNDO' ? | |
| @classmethod | |
| def poll(cls, context): | |
| return True | |
| def draw(self, context): | |
| layout = self.layout | |
| if bpy.context.object and bpy.context.object.type == 'MESH': | |
| layout.prop(context.scene, "AutoMirror_axis", text="Mirror axis") | |
| layout.prop(context.scene, "AutoMirror_orientation", text="Orientation") | |
| layout.prop(context.scene, "AutoMirror_threshold", text="Threshold") | |
| layout.prop(context.scene, "AutoMirror_toggle_edit", text="Toggle edit") | |
| layout.prop(context.scene, "AutoMirror_cut", text="Cut and mirror") | |
| if bpy.context.scene.AutoMirror_cut: | |
| layout.prop(context.scene, "AutoMirror_clipping", text="Clipping") | |
| layout.prop(context.scene, "AutoMirror_apply_mirror", text="Apply mirror") | |
| else: | |
| layout.label(icon="ERROR", text="No mesh selected") | |
| def get_local_axis_vector(self, context, X, Y, Z, orientation): | |
| loc = context.object.location | |
| bpy.ops.object.mode_set(mode="OBJECT") # Needed to avoid to translate vertices | |
| v1 = Vector((loc[0],loc[1],loc[2])) | |
| bpy.ops.transform.translate(value=(X*orientation, Y*orientation, Z*orientation), constraint_axis=((X==1), (Y==1), (Z==1)), constraint_orientation='LOCAL') | |
| v2 = Vector((loc[0],loc[1],loc[2])) | |
| bpy.ops.transform.translate(value=(-X*orientation, -Y*orientation, -Z*orientation), constraint_axis=((X==1), (Y==1), (Z==1)), constraint_orientation='LOCAL') | |
| bpy.ops.object.mode_set(mode="EDIT") | |
| return v2-v1 | |
| def execute(self, context): | |
| X,Y,Z = 0,0,0 | |
| if bpy.context.scene.AutoMirror_axis == 'x': | |
| X = 1 | |
| elif bpy.context.scene.AutoMirror_axis == 'y': | |
| Y = 1 | |
| elif bpy.context.scene.AutoMirror_axis == 'z': | |
| Z = 1 | |
| current_mode = bpy.context.object.mode # Save the current mode | |
| if bpy.context.object.mode != "EDIT": | |
| bpy.ops.object.mode_set(mode="EDIT") # Go to edit mode | |
| bpy.ops.mesh.select_all(action='SELECT') # Select all the vertices | |
| if bpy.context.scene.AutoMirror_orientation == 'positive': | |
| orientation = 1 | |
| else: | |
| orientation = -1 | |
| cut_normal = self.get_local_axis_vector(context, X, Y, Z, orientation) | |
| bpy.ops.mesh.bisect(plane_co=(bpy.context.object.location[0], bpy.context.object.location[1], bpy.context.object.location[2]), plane_no=cut_normal, use_fill= False, clear_inner= bpy.context.scene.AutoMirror_cut, clear_outer= 0, threshold= bpy.context.scene.AutoMirror_threshold) # Cut the mesh | |
| bpy.ops.object.align_vertices() # Use to align the vertices on the origin, needed by the "threshold" | |
| if not bpy.context.scene.AutoMirror_toggle_edit: | |
| bpy.ops.object.mode_set(mode=current_mode) # Reload previous mode | |
| if bpy.context.scene.AutoMirror_cut: | |
| bpy.ops.object.modifier_add(type='MIRROR') # Add a mirror modifier | |
| bpy.context.object.modifiers[-1].use_x = X # Choose the axis to use, based on the cut's axis | |
| bpy.context.object.modifiers[-1].use_y = Y | |
| bpy.context.object.modifiers[-1].use_z = Z | |
| bpy.context.object.modifiers[-1].use_clip = context.scene.AutoMirror_use_clip | |
| bpy.context.object.modifiers[-1].show_on_cage = context.scene.AutoMirror_show_on_cage | |
| if bpy.context.scene.AutoMirror_apply_mirror: | |
| bpy.ops.object.mode_set(mode='OBJECT') | |
| bpy.ops.object.modifier_apply(apply_as= 'DATA', modifier= bpy.context.object.modifiers[-1].name) | |
| if bpy.context.scene.AutoMirror_toggle_edit: | |
| bpy.ops.object.mode_set(mode='EDIT') | |
| else: | |
| bpy.ops.object.mode_set(mode=current_mode) | |
| return {'FINISHED'} | |
| #################### Panel | |
| class BisectMirror(bpy.types.Panel): | |
| """ The AutoMirror panel on the toolbar tab 'Tools' """ | |
| bl_label = "Auto Mirror" | |
| bl_space_type = 'VIEW_3D' | |
| bl_region_type = 'TOOLS' | |
| bl_category = "Tools" | |
| def draw(self, context): | |
| layout = self.layout | |
| if bpy.context.object and bpy.context.object.type == 'MESH': | |
| layout.operator("object.automirror") | |
| layout.prop(context.scene, "AutoMirror_axis", text="Mirror Axis", expand=True) | |
| layout.prop(context.scene, "AutoMirror_orientation", text="Orientation") | |
| layout.prop(context.scene, "AutoMirror_threshold", text="Threshold") | |
| layout.prop(context.scene, "AutoMirror_toggle_edit", text="Toggle Edit") | |
| layout.prop(context.scene, "AutoMirror_cut", text="Cut and Mirror") | |
| if bpy.context.scene.AutoMirror_cut: | |
| row = layout.row() | |
| row.prop(context.scene, "AutoMirror_use_clip", text="Use Clip") | |
| row.prop(context.scene, "AutoMirror_show_on_cage", text="Editable") | |
| layout.prop(context.scene, "AutoMirror_apply_mirror", text="Apply Mirror") | |
| else: | |
| layout.label(icon="ERROR", text="No mesh selected") | |
| def register(): | |
| bpy.utils.register_class(BisectMirror) | |
| bpy.utils.register_class(AutoMirror) | |
| bpy.utils.register_class(AlignVertices) | |
| def unregister(): | |
| bpy.utils.unregister_class(BisectMirror) | |
| bpy.utils.unregister_class(AutoMirror) | |
| bpy.utils.unregister_class(AlignVertices) | |
| if __name__ == "__main__": | |
| register() | |