updates to bl_info
[blender-addons-contrib.git] / mesh_select_vertex_groups.py
1 # ##### BEGIN GPL LICENSE BLOCK #####
2 #
3 #  This program is free software; you can redistribute it and/or
4 #  modify it under the terms of the GNU General Public License
5 #  as published by the Free Software Foundation; either version 2
6 #  of the License, or (at your option) any later version.
7 #
8 #  This program is distributed in the hope that it will be useful,
9 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
10 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 #  GNU General Public License for more details.
12 #
13 #  You should have received a copy of the GNU General Public License
14 #  along with this program; if not, write to the Free Software Foundation,
15 #  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 #
17 # ##### END GPL LICENSE BLOCK #####
18
19 bl_info = {
20     'name': 'Select Vertex Groups',
21     'author': 'Martin Ellison',
22     'version': (1, 0),
23     'blender': (2, 5, 9),
24     'api': 39685,
25     'location': 'Toolbox',
26     'description': 'Finds all the vertex groups that chosen verts are in, & any verts that are not in any group',
27     'warning': '', # used for warning icon and text in addons panel
28     "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.5/Py/"\
29         "Scripts/Modeling/Select_Vertex_Groups",
30     'tracker_url': 'https://projects.blender.org/tracker/index.php?'\
31         'func=detail&aid=22025',
32     'category': 'Mesh'}
33
34 """
35 This script finds all the vertex groups that chosen vertexes are in, and any vertexes that are not in any vertex group.
36
37 This is useful for cleaning up a mesh if vertex groups under animation go off to the wrong place (because they are in a vertex group that they should not be in, or not in the vertex group that they should be in).
38
39 How to use:
40 1. select a mesh and get into edit mode.
41 2. by default it will use all vertexes; alternatively, select vertexes of interest and click on 'use selected vertexes'. Note that subsequent selections and deselections of vertexes will not change the set of vertexes to be used, you need to click on these buttons again to do that.
42 3. click on 'select' and 'deselect' buttons for listed vertex groups, and for no vertex group, to select and deselect vertexes.
43
44 This only lists vertex groups that have used vertexes.
45
46 You may want to use the mesh select/deselect all (keyboard A) operator to start.
47
48 Once you have the right vertexes selected, you can use the standard vertex groups property editor to add them to or remove them from the desired vertex groups.
49 """
50
51
52 import bpy
53 from bpy.props import *
54
55 global use_selected_only, used_vertexes, the_mesh, vertex_usage
56 use_selected_only = False
57 used_vertexes = set()
58 the_mesh = None
59 vertex_usage = ''
60
61 class UseAll(bpy.types.Operator):
62     bl_idname = "mesh.primitive_fvg_useall"
63     bl_label = "Use all Vertexes"
64     bl_register = True
65     bl_undo = True
66     #limit = FloatProperty(name="limit", description="Ignore weights under this limit.", default= 0.01, min = 0.0, max = 1.0, soft_min=0.0, soft_max=1.0)
67
68     def execute(self, context):
69         global use_selected_only
70         use_selected_only = False
71         bpy.ops.object.editmode_toggle()
72         set_used()
73         bpy.ops.object.editmode_toggle()
74         return {'FINISHED'}
75
76 class UseSelected(bpy.types.Operator):
77     bl_idname = "mesh.primitive_fvg_useselected"
78     bl_label = "Use Selected Vertexes"
79     bl_register = True
80     bl_undo = True
81
82     def execute(self, context):
83         global use_selected_only
84         use_selected_only = True
85         bpy.ops.object.editmode_toggle()
86         set_used()
87         bpy.ops.object.editmode_toggle()
88         return {'FINISHED'}
89
90 class SelectFound(bpy.types.Operator):
91     bl_idname = "mesh.primitive_fvg_selfound"
92     bl_label = "Select"
93     bl_register = True
94     bl_undo = True
95     vertexgroup = bpy.props.StringProperty(name = 'vertexgroup', description = 'vertexgroup', default = '', options = set())
96
97     def execute(self, context):
98         global the_mesh
99         bpy.ops.object.editmode_toggle()
100         vertexgroup = self.properties.vertexgroup
101         fv = found_verts(vertexgroup)
102         for v in fv: v.select = True
103         bpy.ops.object.editmode_toggle()
104         return {'FINISHED'}
105
106 class DeselectFound(bpy.types.Operator):
107     bl_idname = "mesh.primitive_fvg_deselfound"
108     bl_label = "Deselect"
109     bl_register = True
110     bl_undo = True
111     vertexgroup = bpy.props.StringProperty(name = 'vertexgroup', description = 'vertexgroup', default = '', options = set())
112
113     def execute(self, context):
114         global the_mesh
115         bpy.ops.object.editmode_toggle()
116         vertexgroup = self.properties.vertexgroup
117         fv = found_verts(vertexgroup)
118         for v in fv: v.select = False
119         bpy.ops.object.editmode_toggle()
120         return {'FINISHED'}
121
122 def set_used():
123         global use_selected_only, used_vertexes, the_mesh, vertex_usage
124         obj = bpy.context.active_object
125         used_vertexes = set()
126         if use_selected_only:
127                 for v in obj.data.vertices:
128                         if v.select: used_vertexes.add(v.index)
129         else:
130                 for v in obj.data.vertices: used_vertexes.add(v.index)
131         the_mesh = obj
132         vertex_usage = '%d vertexes used' % (len(used_vertexes))
133
134
135 def make_groups(limit):
136         global used_vertexes
137         vgp = []
138         vgdict = {}
139         vgused = {}
140         obj = bpy.context.active_object
141         all_in_group = True
142         for vg in obj.vertex_groups:
143                 vgdict[vg.index] = vg.name
144         for v in obj.data.vertices:
145                 in_group = False
146                 if v.index in used_vertexes:
147                         for g in v.groups:
148                                 gr = g.group
149                                 w = g.weight
150                                 if w > limit:
151                                         if not gr in vgused: vgused[gr] = 0
152                                         vgused[gr] += 1
153                                         in_group = True
154                 if not in_group: all_in_group = False
155         if not all_in_group:
156                 vgp.append(("no group", "(No group)"))
157         for gn in vgused.keys():
158                 name = vgdict[gn]
159                 vgp.append((name, '%s has %d vertexes' % (name, vgused[gn]) ))
160         print("%d groups found\n" % len(vgp))
161         return vgp
162
163 def found_verts(vertex_group):
164         global used_vertexes
165         vgfound = []
166         obj = bpy.context.active_object
167         if vertex_group == 'no group':
168                 for v in obj.data.vertices:
169                         if v.index in used_vertexes and len(v.groups) == 0:
170                                 vgfound.append(v)
171         else:
172                 vgnum = -1
173                 for vg in obj.vertex_groups:
174                         if vg.name == vertex_group: vgnum = vg.index
175                 for v in obj.data.vertices:
176                         if v.index in used_vertexes:
177                                 found = False
178                                 for g in v.groups:
179                                         if g.group == vgnum: found = True
180                                 if found: vgfound.append(v)
181         print('%d vertexes found for %s' % (len(vgfound), vertex_group))
182         return vgfound
183
184
185 class VIEW3D_PT_FixVertexGroups(bpy.types.Panel):
186     bl_space_type = "VIEW_3D"
187     bl_region_type = "TOOLS"
188     bl_label = "Select Vertex Groups"
189
190     @classmethod
191     def poll(self, context):
192         if bpy.context.active_object:
193            obj = bpy.context.active_object
194            if obj.type == 'MESH' and obj.mode == 'EDIT': return True
195         return False
196
197     def draw(self, context):
198         global use_selected_only, used_vertexes, the_mesh, vertex_usage
199
200         if bpy.context.active_object:
201            obj = bpy.context.active_object
202            if obj.type == 'MESH' and obj.mode == 'EDIT':
203                 layout = self.layout
204                 use_all = layout.operator("mesh.primitive_fvg_useall", "Use all vertexes")
205                 layout.operator("mesh.primitive_fvg_useselected", "Use selected vertexes")
206                 if use_selected_only:
207                     layout.label(text = 'Using selected vertexes.')
208                 else:
209                     layout.label(text = 'Using all vertexes.')
210                 layout.label(vertex_usage)
211                 if len(used_vertexes) == 0 or obj is not the_mesh: set_used()
212                 #layout.prop(use_all, 'limit', slider = True)
213                 #groups = make_groups(use_all.limitval)
214                 groups = make_groups(0.01)
215                 for gp in groups:
216                         layout.label(text = gp[1])
217                         row = layout.row()
218                         sel_op = row.operator("mesh.primitive_fvg_selfound", "Select")
219                         sel_op.vertexgroup = gp[0]
220                         desel_op = row.operator("mesh.primitive_fvg_deselfound", "Deselect")
221                         desel_op.vertexgroup = gp[0]
222
223 classes = [UseAll, UseSelected, SelectFound, DeselectFound]
224
225 def register():
226     bpy.utils.register_module(__name__)
227     pass
228
229 def unregister():
230     bpy.utils.unregister_module(__name__)
231     pass
232
233 if __name__ == "__main__":
234     print('------ executing --------')
235     register()