~ubuntu-branches/ubuntu/gutsy/blender/gutsy-security

« back to all changes in this revision

Viewing changes to release/scripts/mesh_cleanup.py

  • Committer: Bazaar Package Importer
  • Author(s): Lukas Fittl
  • Date: 2006-09-20 01:57:27 UTC
  • mfrom: (1.2.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20060920015727-gmoqlxwstx9wwqs3
Tags: 2.42a-1ubuntu1
* Merge from Debian unstable (Closes: Malone #55903). Remaining changes:
  - debian/genpot: Add python scripts from Lee June <blender@eyou.com> to
    generate a reasonable PO template from the sources. Since gettext is used
    in a highly nonstandard way, xgettext does not work for this job.
  - debian/rules: Call the scripts, generate po/blender.pot, and clean it up
    in the clean target.
  - Add a proper header to the generated PO template.
* debian/control: Build depend on libavformat-dev >= 3:0.cvs20060823-3.1,
  otherwise this package will FTBFS

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
#!BPY
2
2
"""
3
 
Name: 'Clean meshes'
4
 
Blender: 228
 
3
Name: 'Clean Meshes'
 
4
Blender: 242
5
5
Group: 'Mesh'
6
6
Tooltip: 'Clean unused data from all selected mesh objects.'
7
7
"""
 
8
 
 
9
__author__ = ["Campbell Barton"]
 
10
__url__ = ("blender", "elysiun", "http://members.iinet.net.au/~cpbarton/ideasman/")
 
11
__version__ = "0.1"
 
12
__bpydoc__ = """\
 
13
Clean Meshes
 
14
 
 
15
Cleans unused data from selected meshes
 
16
"""
 
17
 
 
18
# ***** BEGIN GPL LICENSE BLOCK *****
 
19
#
 
20
# Script copyright (C) Campbell J Barton
 
21
#
 
22
# This program is free software; you can redistribute it and/or
 
23
# modify it under the terms of the GNU General Public License
 
24
# as published by the Free Software Foundation; either version 2
 
25
# of the License, or (at your option) any later version.
 
26
#
 
27
# This program is distributed in the hope that it will be useful,
 
28
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
29
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
30
# GNU General Public License for more details.
 
31
#
 
32
# You should have received a copy of the GNU General Public License
 
33
# along with this program; if not, write to the Free Software Foundation,
 
34
# Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
35
#
 
36
# ***** END GPL LICENCE BLOCK *****
 
37
# --------------------------------------------------------------------------
 
38
 
 
39
 
8
40
from Blender import *
9
41
from Blender.Mathutils import TriangleArea
10
42
 
 
43
import Blender
 
44
import BPyMesh
 
45
dict2MeshWeight= BPyMesh.dict2MeshWeight
 
46
meshWeight2Dict= BPyMesh.meshWeight2Dict
 
47
 
11
48
def rem_free_verts(me):
12
 
        vert_users = [0] * len(me.verts)
 
49
        vert_users= [0] * len(me.verts)
13
50
        for f in me.faces:
14
51
                for v in f.v:
15
52
                        vert_users[v.index]+=1
18
55
                for v in e: # loop on edge verts
19
56
                        vert_users[v.index]+=1
20
57
        
21
 
        verts_free = []
22
 
        for i, users in enumerate(vert_users):
23
 
                if not users:
24
 
                        verts_free.append(i)
 
58
        verts_free= [i for i, users in enumerate(vert_users) if not users]
25
59
        
26
60
        if verts_free:
27
61
                pass
31
65
def rem_free_edges(me, limit=None):
32
66
        ''' Only remove based on limit if a limit is set, else remove all '''
33
67
        def sortPair(a,b):
34
 
                return min(a,b), max(a,b)
 
68
                if a>b:
 
69
                        return b,a
 
70
                else:
 
71
                        return a,b
35
72
        
36
 
        edgeDict = {} # will use a set when python 2.4 is standard.
 
73
        edgeDict= {} # will use a set when python 2.4 is standard.
37
74
        
38
75
        for f in me.faces:
39
 
                for i in xrange(len(f.v)):
40
 
                        edgeDict[sortPair(f.v[i].index, f.v[i-1].index)] = None
 
76
                fidxs= [v.index for v in f.v]
 
77
                for i in xrange(len(fidxs)):
 
78
                        edgeDict[sortPair(fidxs[i], fidxs[i-1])]= None
41
79
        
42
 
        edges_free = []
 
80
        edges_free= []
43
81
        for e in me.edges:
44
82
                if not edgeDict.has_key(sortPair(e.v1.index, e.v2.index)):
45
83
                        edges_free.append(e)
46
84
        
47
85
        if limit != None:
48
 
                edges_free = [e for e in edges_free if (e.v1.co-e.v2.co).length <= limit]
 
86
                edges_free= [e for e in edges_free if (e.v1.co-e.v2.co).length <= limit]
49
87
        
50
88
        me.edges.delete(edges_free)
51
89
        return len(edges_free)
52
90
 
53
91
def rem_area_faces(me, limit=0.001):
54
92
        ''' Faces that have an area below the limit '''
55
 
        def faceArea(f):
56
 
                if len(f.v) == 3:
57
 
                        return TriangleArea(f.v[0].co, f.v[1].co, f.v[2].co)
58
 
                elif len(f.v) == 4:
59
 
                        return\
60
 
                         TriangleArea(f.v[0].co, f.v[1].co, f.v[2].co) +\
61
 
                         TriangleArea(f.v[0].co, f.v[2].co, f.v[3].co)
62
 
        rem_faces = [f for f in me.faces if faceArea(f) <= limit]
 
93
        rem_faces= [f for f in me.faces if f.area <= limit]
63
94
        if rem_faces:
64
95
                me.faces.delete( 0, rem_faces )
65
96
        return len(rem_faces)
67
98
def rem_perimeter_faces(me, limit=0.001):
68
99
        ''' Faces whos combine edge length is below the limit '''
69
100
        def faceEdLen(f):
70
 
                if len(f.v) == 3:
71
 
                        return\
72
 
                        (f.v[0].co-f.v[1].co).length +\
73
 
                        (f.v[1].co-f.v[2].co).length +\
74
 
                        (f.v[2].co-f.v[0].co).length
75
 
                elif len(f.v) == 4:
76
 
                        return\
77
 
                        (f.v[0].co-f.v[1].co).length +\
78
 
                        (f.v[1].co-f.v[2].co).length +\
79
 
                        (f.v[2].co-f.v[3].co).length +\
80
 
                        (f.v[3].co-f.v[0].co).length
81
 
        rem_faces = [f for f in me.faces if faceEdLen(f) <= limit]
 
101
                v= f.v
 
102
                if len(v) == 3:
 
103
                        return\
 
104
                        (v[0].co-v[1].co).length +\
 
105
                        (v[1].co-v[2].co).length +\
 
106
                        (v[2].co-v[0].co).length
 
107
                else: # 4
 
108
                        return\
 
109
                        (v[0].co-v[1].co).length +\
 
110
                        (v[1].co-v[2].co).length +\
 
111
                        (v[2].co-v[3].co).length +\
 
112
                        (v[3].co-v[0].co).length
 
113
        rem_faces= [f for f in me.faces if faceEdLen(f) <= limit]
82
114
        if rem_faces:
83
115
                me.faces.delete( 0, rem_faces )
84
116
        return len(rem_faces)
85
117
 
86
 
def main():
87
 
        
88
 
        def getLimit(text):
89
 
                return Draw.PupFloatInput(text, 0.001, 0.0, 1.0, 0.1, 4)
90
 
        
91
 
        
92
 
        scn = Scene.GetCurrent()
93
 
        obsel = Object.GetSelected()
94
 
        actob = scn.getActiveObject()
95
 
        
96
 
        is_editmode = Window.EditMode()
 
118
def rem_unused_materials(me):
 
119
        materials= me.materials
 
120
        len_materials= len(materials)
 
121
        if len_materials < 2:
 
122
                return 0
 
123
                
 
124
        rem_materials= 0
 
125
        
 
126
        material_users= dict( [(i,0) for i in xrange(len_materials)] )
 
127
        
 
128
        for f in me.faces:
 
129
                # Make sure the face index isnt too big. this happens sometimes.
 
130
                if f.mat >= len_materials:
 
131
                        f.mat=0
 
132
                material_users[f.mat] += 1
 
133
        
 
134
        mat_idx_subtract= 0
 
135
        reindex_mapping= dict( [(i,0) for i in xrange(len_materials)] )
 
136
        i= len_materials
 
137
        while i:
 
138
                i-=1
 
139
                
 
140
                if material_users[i] == 0:
 
141
                        mat_idx_subtract+=1
 
142
                        reindex_mapping[i]= mat_idx_subtract
 
143
                        materials.pop(i)
 
144
                        rem_materials+=1
 
145
        
 
146
        for f in me.faces:
 
147
                f.mat= f.mat - reindex_mapping[f.mat]
 
148
        
 
149
        me.materials= materials
 
150
        return rem_materials
 
151
 
 
152
 
 
153
def rem_free_groups(me, groupNames, vWeightDict):
 
154
        ''' cound how many vert users a group has and remove unsued groups '''
 
155
        rem_groups              = 0
 
156
        groupUserDict= dict([(group,0) for group in groupNames])
 
157
        
 
158
        for vertexWeight in vWeightDict:
 
159
                for group, weight in vertexWeight.iteritems():
 
160
                        groupUserDict[group] += 1
 
161
        
 
162
        i=len(groupNames)
 
163
        while i:
 
164
                i-=1
 
165
                group= groupNames[i]
 
166
                if groupUserDict[group] == 0:
 
167
                        del groupNames[i]
 
168
                        print '\tremoving, vgroup', group
 
169
                        rem_groups+=1
 
170
        return rem_groups
 
171
 
 
172
def rem_zero_weights(me, limit, groupNames, vWeightDict):
 
173
        ''' remove verts from a group when their weight is zero.'''
 
174
        rem_vweight_count= 0
 
175
        for vertexWeight in vWeightDict:
 
176
                items= vertexWeight.items()
 
177
                for group, weight in items:
 
178
                        if weight < limit:
 
179
                                del vertexWeight[group]
 
180
                                rem_vweight_count+= 1
 
181
 
 
182
        return rem_vweight_count
 
183
 
 
184
        
 
185
def normalize_vweight(me, groupNames, vWeightDict):
 
186
        for vertexWeight in vWeightDict:
 
187
                unit= 0.0
 
188
                for group, weight in vertexWeight.iteritems():
 
189
                        unit+= weight
 
190
                
 
191
                if unit != 1.0 and unit != 0.0:
 
192
                        for group, weight in vertexWeight.iteritems():
 
193
                                vertexWeight[group]= weight/unit
 
194
 
 
195
 
 
196
 
 
197
def main():     
 
198
        scn= Scene.GetCurrent()
 
199
        obsel= Object.GetSelected()
 
200
        actob= scn.getActiveObject()
 
201
        
 
202
        is_editmode= Window.EditMode()
97
203
        
98
204
        # Edit mode object is not active, add it to the list.
99
205
        if is_editmode and (not actob.sel):
100
206
                obsel.append(actob)
101
207
        
102
 
        meshes = [ob.getData(mesh=1) for ob in obsel if ob.getType() == 'Mesh']
103
 
        
104
208
        
105
209
        #====================================#
106
210
        # Popup menu to select the functions #
107
211
        #====================================#
108
 
        '''
109
 
        if not meshes:
110
 
                Draw.PupMenu('ERROR%t|no meshes in selection')
111
 
                return
112
 
        method = Draw.PupMenu("""
113
 
Clean Mesh, Remove...%t|
114
 
Verts: free standing|
115
 
Edges: not in a face|
116
 
Edges: below a length|
117
 
Faces: below an area|%l|
118
 
All of the above|""")
119
 
        if method == -1:
120
 
                return
121
 
        
122
 
        if method >= 3:
123
 
                limit = getLimit('threshold: ')
124
 
        
125
 
        print 'method', method
126
 
        '''
127
 
        
128
 
        
129
 
        CLEAN_VERTS_FREE = Draw.Create(1)
130
 
        CLEAN_EDGE_NOFACE = Draw.Create(0)
131
 
        CLEAN_EDGE_SMALL = Draw.Create(0)
132
 
        CLEAN_FACE_PERIMETER = Draw.Create(0)
133
 
        CLEAN_FACE_SMALL = Draw.Create(0)
134
 
        limit = Draw.Create(0.01)
135
 
        
 
212
        
 
213
        CLEAN_ALL_DATA= Draw.Create(0)
 
214
        CLEAN_VERTS_FREE= Draw.Create(1)
 
215
        CLEAN_EDGE_NOFACE= Draw.Create(0)
 
216
        CLEAN_EDGE_SMALL= Draw.Create(0)
 
217
        CLEAN_FACE_PERIMETER= Draw.Create(0)
 
218
        CLEAN_FACE_SMALL= Draw.Create(0)
 
219
        
 
220
        CLEAN_MATERIALS= Draw.Create(0)
 
221
        CLEAN_GROUP= Draw.Create(0)
 
222
        CLEAN_VWEIGHT= Draw.Create(0)
 
223
        CLEAN_WEIGHT_NORMALIZE= Draw.Create(0)
 
224
        limit= Draw.Create(0.01)
136
225
        # Get USER Options
137
226
        
138
 
        pup_block = [\
 
227
        pup_block= [\
139
228
        ('Verts: free', CLEAN_VERTS_FREE, 'Remove verts that are not used by an edge or a face.'),\
140
229
        ('Edges: free', CLEAN_EDGE_NOFACE, 'Remove edges that are not in a face.'),\
141
230
        ('Edges: short', CLEAN_EDGE_SMALL, 'Remove edges that are below the length limit.'),\
142
231
        ('Faces: small perimeter', CLEAN_FACE_PERIMETER, 'Remove faces below the perimeter limit.'),\
143
232
        ('Faces: small area', CLEAN_FACE_SMALL, 'Remove faces below the area limit (may remove faces stopping T-face artifacts).'),\
 
233
        'Materials',\
 
234
        ('Material Clean', CLEAN_MATERIALS, 'Remove unused materials.'),\
 
235
        'VGroups',\
 
236
        ('Group Clean', CLEAN_GROUP, 'Remove vertex groups that have no verts using them.'),\
 
237
        ('Weight Clean', CLEAN_VWEIGHT, 'Remove zero weighted verts from groups (limit is zero threshold).'),\
 
238
        ('Weight Normalize', CLEAN_WEIGHT_NORMALIZE, 'Make the sum total of vertex weights accross vgroups 1.0 for each vertex.'),\
 
239
        '',\
144
240
        ('limit: ', limit, 0.001, 1.0, 'Limit used for the area and length tests above (a higher limit will remove more data).'),\
 
241
        '',\
 
242
        ('All Mesh Data', CLEAN_ALL_DATA, 'Warning! Operate on ALL mesh objects in your Blend file. Use with care'),\
145
243
        ]
146
244
        
147
 
        
148
245
        if not Draw.PupBlock('Clean Selected Meshes...', pup_block):
149
246
                return
150
247
        
151
 
        
152
 
        CLEAN_VERTS_FREE = CLEAN_VERTS_FREE.val
153
 
        CLEAN_EDGE_NOFACE = CLEAN_EDGE_NOFACE.val
154
 
        CLEAN_EDGE_SMALL = CLEAN_EDGE_SMALL.val
155
 
        CLEAN_FACE_PERIMETER = CLEAN_FACE_PERIMETER.val
156
 
        CLEAN_FACE_SMALL = CLEAN_FACE_SMALL.val
157
 
        limit = limit.val
 
248
        CLEAN_VERTS_FREE= CLEAN_VERTS_FREE.val
 
249
        CLEAN_EDGE_NOFACE= CLEAN_EDGE_NOFACE.val
 
250
        CLEAN_EDGE_SMALL= CLEAN_EDGE_SMALL.val
 
251
        CLEAN_FACE_PERIMETER= CLEAN_FACE_PERIMETER.val
 
252
        CLEAN_FACE_SMALL= CLEAN_FACE_SMALL.val
 
253
        CLEAN_MATERIALS= CLEAN_MATERIALS.val
 
254
        CLEAN_GROUP= CLEAN_GROUP.val
 
255
        CLEAN_VWEIGHT= CLEAN_VWEIGHT.val
 
256
        CLEAN_WEIGHT_NORMALIZE= CLEAN_WEIGHT_NORMALIZE.val
 
257
        limit= limit.val
 
258
        CLEAN_ALL_DATA= CLEAN_ALL_DATA.val
158
259
        
159
260
        if is_editmode: Window.EditMode(0)
160
261
        
161
 
        rem_face_count = rem_edge_count = rem_vert_count = 0
 
262
        if CLEAN_ALL_DATA:
 
263
                if CLEAN_GROUP or CLEAN_VWEIGHT or CLEAN_WEIGHT_NORMALIZE:
 
264
                        # For groups we need the objects linked to the mesh
 
265
                        meshes= [ob.getData(mesh=1) for ob in Object.Get() if ob.getType() == 'Mesh']
 
266
                else:
 
267
                        meshes= Mesh.Get()
 
268
        else:
 
269
                meshes= [ob.getData(mesh=1) for ob in obsel if ob.getType() == 'Mesh']
 
270
        
 
271
        rem_face_count= rem_edge_count= rem_vert_count= rem_material_count= rem_group_count= rem_vweight_count= 0
162
272
        
163
273
        for me in meshes:
164
274
                if CLEAN_FACE_SMALL:
175
285
                
176
286
                if CLEAN_VERTS_FREE:
177
287
                        rem_vert_count += rem_free_verts(me)
178
 
        
 
288
                
 
289
                if CLEAN_MATERIALS:
 
290
                        rem_material_count += rem_unused_materials(me)
 
291
                
 
292
                if CLEAN_VWEIGHT or CLEAN_GROUP or CLEAN_WEIGHT_NORMALIZE:
 
293
                        groupNames, vWeightDict= meshWeight2Dict(me)
 
294
                        
 
295
                        if CLEAN_VWEIGHT:
 
296
                                rem_vweight_count += rem_zero_weights(me, limit, groupNames, vWeightDict)
 
297
                        
 
298
                        if CLEAN_GROUP:
 
299
                                rem_group_count += rem_free_groups(me, groupNames, vWeightDict)
 
300
                                pass
 
301
                        
 
302
                        if CLEAN_WEIGHT_NORMALIZE:
 
303
                                normalize_vweight(me, groupNames, vWeightDict)
 
304
                        
 
305
                        # Copy back to mesh vertex groups.
 
306
                        dict2MeshWeight(me, groupNames, vWeightDict)
 
307
                        
 
308
                
179
309
        if is_editmode: Window.EditMode(0)
180
 
        Draw.PupMenu('Removed from ' + str(len(meshes)) +' Mesh(es)%t|' + 'Verts:' + str(rem_vert_count) + ' Edges:' + str(rem_edge_count) + ' Faces:' + str(rem_face_count))
 
310
        stat_string= 'Removed from ' + str(len(meshes)) + ' Mesh(es)%t|'
 
311
        
 
312
        if CLEAN_VERTS_FREE:                                                    stat_string+= 'Verts: %i|' % rem_edge_count
 
313
        if CLEAN_EDGE_SMALL or CLEAN_EDGE_NOFACE:               stat_string+= 'Edges: %i|' % rem_edge_count
 
314
        if CLEAN_FACE_SMALL or CLEAN_FACE_PERIMETER:    stat_string+= 'Faces: %i|' % rem_face_count
 
315
        if CLEAN_MATERIALS:                                                             stat_string+= 'Materials: %i|' % rem_material_count
 
316
        if CLEAN_VWEIGHT:                                                               stat_string+= 'VWeights: %i|' % rem_vweight_count
 
317
        if CLEAN_GROUP:                                                                 stat_string+= 'VGroups: %i|' % rem_group_count
 
318
        
 
319
        Draw.PupMenu(stat_string)
 
320
        
181
321
        
182
322
if __name__ == '__main__':
183
323
        main()
184