Merge branch 'blender-v3.3-release'
[blender-addons.git] / mesh_tools / vertex_align.py
blobec1c812b245e8c0de23c9341c5db1f8dd4af1237
1 # SPDX-License-Identifier: GPL-2.0-or-later
3 # Note: Property group was moved to __init__
5 bl_info = {
6 "name": "Vertex Align",
7 "author": "",
8 "version": (0, 1, 7),
9 "blender": (2, 61, 0),
10 "location": "View3D > Tool Shelf",
11 "description": "",
12 "warning": "",
13 "doc_url": "",
14 "category": "Mesh",
18 import bpy
19 from bpy.props import (
20 BoolVectorProperty,
21 FloatVectorProperty,
23 from mathutils import Vector
24 from bpy.types import Operator
27 # Edit Mode Toggle
28 def edit_mode_out():
29 bpy.ops.object.mode_set(mode='OBJECT')
32 def edit_mode_in():
33 bpy.ops.object.mode_set(mode='EDIT')
36 def get_mesh_data_():
37 edit_mode_out()
38 ob_act = bpy.context.active_object
39 me = ob_act.data
40 edit_mode_in()
41 return me
44 def list_clear_(l):
45 l[:] = []
46 return l
49 class va_buf():
50 list_v = []
51 list_0 = []
54 # Store The Vertex coordinates
55 class Vertex_align_store(Operator):
56 bl_idname = "vertex_align.store_id"
57 bl_label = "Active Vertex"
58 bl_description = ("Store Selected Vertex coordinates as an align point\n"
59 "Single Selected Vertex only")
61 @classmethod
62 def poll(cls, context):
63 obj = context.active_object
64 return (obj and obj.type == 'MESH' and context.mode == 'EDIT_MESH')
66 def execute(self, context):
67 try:
68 me = get_mesh_data_()
69 list_0 = [v.index for v in me.vertices if v.select]
71 if len(list_0) == 1:
72 list_clear_(va_buf.list_v)
73 for v in me.vertices:
74 if v.select:
75 va_buf.list_v.append(v.index)
76 bpy.ops.mesh.select_all(action='DESELECT')
77 else:
78 self.report({'WARNING'}, "Please select just One Vertex")
79 return {'CANCELLED'}
80 except:
81 self.report({'WARNING'}, "Storing selection could not be completed")
82 return {'CANCELLED'}
84 self.report({'INFO'}, "Selected Vertex coordinates are stored")
86 return {'FINISHED'}
89 # Align to original
90 class Vertex_align_original(Operator):
91 bl_idname = "vertex_align.align_original"
92 bl_label = "Align to original"
93 bl_description = "Align selection to stored single vertex coordinates"
94 bl_options = {'REGISTER', 'UNDO'}
96 @classmethod
97 def poll(cls, context):
98 obj = context.active_object
99 return (obj and obj.type == 'MESH' and context.mode == 'EDIT_MESH')
101 def draw(self, context):
102 layout = self.layout
103 layout.label(text="Axis:")
105 row = layout.row(align=True)
106 row.prop(context.scene.mesh_extra_tools, "vert_align_axis",
107 text="X", index=0, toggle=True)
108 row.prop(context.scene.mesh_extra_tools, "vert_align_axis",
109 text="Y", index=1, toggle=True)
110 row.prop(context.scene.mesh_extra_tools, "vert_align_axis",
111 text="Z", index=2, toggle=True)
113 def execute(self, context):
114 edit_mode_out()
115 ob_act = context.active_object
116 me = ob_act.data
117 cen1 = context.scene.mesh_extra_tools.vert_align_axis
118 list_0 = [v.index for v in me.vertices if v.select]
120 if len(va_buf.list_v) == 0:
121 self.report({'INFO'},
122 "Original vertex not stored in memory. Operation Cancelled")
123 edit_mode_in()
124 return {'CANCELLED'}
126 elif len(va_buf.list_v) != 0:
127 if len(list_0) == 0:
128 self.report({'INFO'}, "No vertices selected. Operation Cancelled")
129 edit_mode_in()
130 return {'CANCELLED'}
132 elif len(list_0) != 0:
133 vo = (me.vertices[va_buf.list_v[0]].co).copy()
134 if cen1[0] is True:
135 for i in list_0:
136 v = (me.vertices[i].co).copy()
137 me.vertices[i].co = Vector((vo[0], v[1], v[2]))
138 if cen1[1] is True:
139 for i in list_0:
140 v = (me.vertices[i].co).copy()
141 me.vertices[i].co = Vector((v[0], vo[1], v[2]))
142 if cen1[2] is True:
143 for i in list_0:
144 v = (me.vertices[i].co).copy()
145 me.vertices[i].co = Vector((v[0], v[1], vo[2]))
146 edit_mode_in()
148 return {'FINISHED'}
151 # Align to custom coordinates
152 class Vertex_align_coord_list(Operator):
153 bl_idname = "vertex_align.coord_list_id"
154 bl_label = ""
155 bl_description = "Align to custom coordinates"
157 @classmethod
158 def poll(cls, context):
159 obj = context.active_object
160 return (obj and obj.type == 'MESH' and context.mode == 'EDIT_MESH')
162 def execute(self, context):
163 edit_mode_out()
164 ob_act = context.active_object
165 me = ob_act.data
166 list_clear_(va_buf.list_0)
167 va_buf.list_0 = [v.index for v in me.vertices if v.select][:]
169 if len(va_buf.list_0) == 0:
170 self.report({'INFO'}, "No vertices selected. Operation Cancelled")
171 edit_mode_in()
172 return {'CANCELLED'}
174 elif len(va_buf.list_0) != 0:
175 bpy.ops.vertex_align.coord_menu_id('INVOKE_DEFAULT')
177 edit_mode_in()
179 return {'FINISHED'}
182 # Align to custom coordinates menu
183 class Vertex_align_coord_menu(Operator):
184 bl_idname = "vertex_align.coord_menu_id"
185 bl_label = "Tweak custom coordinates"
186 bl_description = "Change the custom coordinates for aligning"
187 bl_options = {'REGISTER', 'UNDO'}
189 def_axis_coord: FloatVectorProperty(
190 name="",
191 description="Enter the values of coordinates",
192 default=(0.0, 0.0, 0.0),
193 min=-100.0, max=100.0,
194 step=1, size=3,
195 subtype='XYZ',
196 precision=3
198 use_axis_coord = BoolVectorProperty(
199 name="Axis",
200 description="Choose Custom Coordinates axis",
201 default=(False,) * 3,
202 size=3,
204 is_not_undo = False
206 @classmethod
207 def poll(cls, context):
208 obj = context.active_object
209 return (obj and obj.type == 'MESH')
211 def using_store(self, context):
212 scene = context.scene
213 return scene.mesh_extra_tools.vert_align_use_stored
215 def draw(self, context):
216 layout = self.layout
218 if self.using_store(context) and self.is_not_undo:
219 layout.label(text="Using Stored Coordinates", icon="INFO")
221 row = layout.split(0.25)
222 row.prop(self, "use_axis_coord", index=0, text="X")
223 row.prop(self, "def_axis_coord", index=0)
225 row = layout.split(0.25)
226 row.prop(self, "use_axis_coord", index=1, text="Y")
227 row.prop(self, "def_axis_coord", index=1)
229 row = layout.split(0.25)
230 row.prop(self, "use_axis_coord", index=2, text="Z")
231 row.prop(self, "def_axis_coord", index=2)
233 def invoke(self, context, event):
234 self.is_not_undo = True
235 scene = context.scene
236 if self.using_store(context):
237 self.def_axis_coord = scene.mesh_extra_tools.vert_align_store_axis
239 return context.window_manager.invoke_props_dialog(self, width=200)
241 def execute(self, context):
242 self.is_not_undo = False
243 edit_mode_out()
244 ob_act = context.active_object
245 me = ob_act.data
247 for i in va_buf.list_0:
248 v = (me.vertices[i].co).copy()
249 tmp = Vector((v[0], v[1], v[2]))
251 if self.use_axis_coord[0] is True:
252 tmp[0] = self.def_axis_coord[0]
253 if self.use_axis_coord[1] is True:
254 tmp[1] = self.def_axis_coord[1]
255 if self.use_axis_coord[2] is True:
256 tmp[2] = self.def_axis_coord[2]
257 me.vertices[i].co = tmp
259 edit_mode_in()
261 return {'FINISHED'}
264 # Register
265 classes = (
266 Vertex_align_store,
267 Vertex_align_original,
268 Vertex_align_coord_list,
269 Vertex_align_coord_menu,
273 def register():
274 for cls in classes:
275 bpy.utils.register_class(cls)
278 def unregister():
279 for cls in classes:
280 bpy.utils.unregister_class(cls)
283 if __name__ == "__main__":
284 register()