Final merge of HEAD (bf-blender) into the orange branch.
[blender.git] / release / scripts / clean_mesh.py
1 #!BPY
2
3 """
4 Name: 'Clean Mesh'
5 Blender: 234
6 Group: 'Mesh'
7 Tooltip: 'Clean unused data from all selected meshes'
8 """
9
10 __author__ = "Campbell Barton"
11 __url__ = ("blender", "elysiun")
12 __version__ = "1.1 04/25/04"
13
14 __bpydoc__ = """\
15 This script cleans specific data from all selected meshes.
16
17 Usage:
18
19 Select the meshes to be cleaned and run this script.  A pop-up will ask
20 you what you want to remove:
21
22 - Free standing vertices;<br>
23 - Edges that are not part of any face;<br>
24 - Edges below a threshold length;<br>
25 - Faces below a threshold area;<br>
26 - All of the above.
27
28 After choosing one of the above alternatives, if your choice requires a
29 threshold value you'll be prompted with a number pop-up to set it.
30 """
31
32
33 # $Id$
34 #
35 # -------------------------------------------------------------------------- 
36 # Mesh Cleaner 1.0 By Campbell Barton (AKA Ideasman)
37 # -------------------------------------------------------------------------- 
38 # ***** BEGIN GPL LICENSE BLOCK ***** 
39
40 # This program is free software; you can redistribute it and/or 
41 # modify it under the terms of the GNU General Public License 
42 # as published by the Free Software Foundation; either version 2 
43 # of the License, or (at your option) any later version. 
44
45 # This program is distributed in the hope that it will be useful, 
46 # but WITHOUT ANY WARRANTY; without even the implied warranty of 
47 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
48 # GNU General Public License for more details. 
49
50 # You should have received a copy of the GNU General Public License 
51 # along with this program; if not, write to the Free Software Foundation, 
52 # Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. 
53
54 # ***** END GPL LICENCE BLOCK ***** 
55 # -------------------------------------------------------------------------- 
56
57
58 # Made by Ideasman/Campbell 2004/04/25 - ideasman@linuxmail.org
59
60 import Blender
61 from Blender import *
62 from math import sqrt
63
64 time1 = Blender.sys.time()
65
66 VRemNum = ERemNum = FRemNum = 0 # Remember for statistics
67
68
69 #================#
70 # Math functions #
71 #================#
72 def compare(f1, f2, limit):
73   if f1 + limit > f2 and f1 - limit < f2:
74     return 1
75   return 0
76
77 def measure(v1, v2):
78   return Mathutils.Vector([v1[0]-v2[0], v1[1] - v2[1], v1[2] - v2[2]]).length
79
80 def triArea2D(v1, v2, v3):
81   e1 = measure(v1, v2)  
82   e2 = measure(v2, v3)  
83   e3 = measure(v3, v1)  
84   p = e1+e2+e3
85   return 0.25 * sqrt(p*(p-2*e1)*(p-2*e2)*(p-2*e3))
86
87
88 #=============================#
89 # Blender functions/shortcuts #
90 #=============================#
91 def error(str):
92         Draw.PupMenu('ERROR%t|'+str)
93
94 def getLimit(text):
95   return Draw.PupFloatInput(text, 0.001, 0.0, 1.0, 0.1, 3)
96
97 def faceArea(f):
98   if len(f.v) == 4:
99     return triArea2D(f.v[0].co, f.v[1].co, f.v[2].co) + triArea2D(f.v[0].co, f.v[2].co, f.v[3].co)
100   elif len(f.v) == 3:
101     return triArea2D(f.v[0].co, f.v[1].co, f.v[2].co)
102
103
104
105 #================#
106 # Mesh functions #
107 #================#
108 def delFreeVert(mesh):
109   global VRemNum
110   usedList = eval('[' + ('False,' * len(mesh.verts) )+ ']')
111   # Now tag verts that areused
112   for f in mesh.faces:
113     for v in f.v:
114       usedList[mesh.verts.index(v)] = True
115   vIdx = 0
116   for bool in usedList:
117     if bool == False:
118       mesh.verts.pop(vIdx)
119       vIdx -= 1
120       VRemNum += 1
121     vIdx += 1
122   mesh.update()
123
124
125 def delEdge(mesh):
126   global ERemNum
127   fIdx = 0
128   while fIdx < len(mesh.faces):
129     if len(mesh.faces[fIdx].v) == 2:
130       mesh.faces.pop(fIdx)
131       ERemNum += 1
132       fIdx -= 1
133     fIdx +=1
134   mesh.update()
135
136 def delEdgeLen(mesh, limit):
137   global ERemNum
138   fIdx = 0
139   while fIdx < len(mesh.faces):
140     if len(mesh.faces[fIdx].v) == 2:
141       if measure(mesh.faces[fIdx].v[0].co, mesh.faces[fIdx].v[1].co) <= limit:
142         mesh.faces(fIdx)
143         ERemNum += 1
144         fIdx -= 1
145     fIdx +=1    
146   mesh.update()
147
148 def delFaceArea(mesh, limit):
149   global FRemNum
150   fIdx = 0
151   while fIdx < len(mesh.faces):
152     if len(mesh.faces[fIdx].v) > 2:
153       if faceArea(mesh.faces[fIdx]) <= limit:
154         mesh.faces.pop(fIdx)
155         FRemNum += 1
156         fIdx -= 1
157     fIdx +=1
158   mesh.update()
159
160
161 #====================#
162 # Make a mesh list   #
163 #====================#
164
165 is_editmode = Window.EditMode()
166 if is_editmode: Window.EditMode(0)
167
168 meshList = []
169 if len(Object.GetSelected()) > 0:
170   for ob in Object.GetSelected():
171     if ob.getType() == 'Mesh':
172       meshList.append(ob.getData())
173
174
175 #====================================#
176 # Popup menu to select the functions #
177 #====================================#
178 if len(meshList) == 0:
179   error('no meshes in selection')
180 else:
181   method = Draw.PupMenu(\
182   'Clean Mesh, Remove...%t|\
183   Verts: free standing|\
184   Edges: not in a face|\
185   Edges: below a length|\
186   Faces: below an area|%l|\
187   All of the above|')
188   
189   if method >= 3:
190     limit = getLimit('threshold: ')
191
192   if method != -1:
193     for mesh in meshList:
194       if method == 1:
195         delFreeVert(mesh)
196       elif method == 2:
197         delEdge(mesh)
198       elif method == 3:
199         delEdgeLen(mesh, limit)
200       elif method == 4:
201         delFaceArea(mesh, limit)
202       elif method == 6: # All of them
203         delFaceArea(mesh, limit)
204         delEdge(mesh)
205         delFreeVert(mesh)
206       
207       mesh.update(0)
208       Redraw()
209 print 'mesh cleanup time',Blender.sys.time() - time1
210 if is_editmode: Window.EditMode(1)
211
212 if method != -1:
213   Draw.PupMenu('Removed from ' + str(len(meshList)) +' Mesh(es)%t|' + 'Verts:' + str(VRemNum) + ' Edges:' + str(ERemNum) + ' Faces:' + str(FRemNum))