use f.area where possible over python function and use len(mface) over len(mface.v)
[blender.git] / release / scripts / unweld.py
1 #!BPY
2 """ Registration info for Blender menus: <- these words are ignored
3 Name: 'Unweld'
4 Blender: 234
5 Group: 'Mesh'
6 Tip: 'Unweld all faces from a (or several) selected and common vertex. Made vertex bevelling'
7 """
8
9 __author__ = "Jean-Michel Soler (jms)"
10 __url__ = ("blender", "elysiun",
11 "Script's homepage, http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_faces2vertex.htm#exemple",
12 "Communicate problems and errors, http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender")
13 __version__ = "0.4.5 beta"
14
15 __bpydoc__ = """\
16 This script unwelds faces from a selected vertex.
17
18 There's also experimental support for static or dynamic (move mouse in the
19 Scripts window) vertex bevel.
20
21 Usage:
22
23 Select a vertex, then run this script.  Its options are:
24
25 - unbind points;<br>
26 - with noise;<br>
27 - middle face;<br>
28 - static bevel vertex;<br>
29 - moving bevel vertex;
30 """
31
32 # ------------------------------------------
33 # Un-Weld script 0.4.5 beta
34 name="UnWeld"
35 Tip= 'Unweld all faces from a selected and common vertex. Made vertex bevelling'
36 #
37 # split all faces from one selected vertex
38 # (c) 2004 J-M Soler released under Blender Artistic License
39 #----------------------------------------------
40 # Official Page :
41 website = 'http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_faces2vertex.htm#exemple'
42 # Communicate problems and errors on:
43 community = 'http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender'
44 #----------------------------------------------
45 # Blender Artistic License
46 # http://download.blender.org/documentation/html/x21254.html
47 #---------------------------------------------
48 # Changelog
49 #----------------------------------------------
50 # 25/05 :
51 # -- separate choise, normal (same place) or spread at random, middle of the face
52 # -- works on several vertices too
53 # -- Quite vertex bevelling on <<lone>> vertex : create hole in faces around this
54 # vertex
55 # 03/06 :
56 # -- a sort of "bevelled vertex" extrusion controled by horizontal mouse
57 # displacement. just a beta test to the mouse control.
58 # 08/08 :
59 # -- minor correction to completely disconnect face.
60 #----------------------------------------------
61 # Page officielle :
62 #   http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_faces2vertex.htm#exemple
63 # Communiquer les problemes et erreurs sur:
64 #   http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender
65 # Blender Artistic License
66 #    http://download.blender.org/documentation/html/x21254.html
67 #--------------------------------------------- 
68 # Changelog
69 #----------------------------------------------
70 #      25/05 :
71 #           -- separation du choix, normal ou dispersion hasardeuse, 
72 #              milieu de face
73 #           -- sommets multiples / 
74 #           -- presque  unvertex bevelling sur un vertex solitaire : cree
75 #              un trou dans la facette autour du sommet
76 #     03/06 :
77 #           -- une sorte de vertex extruder en biseau, controle par
78 #              deplacement horizontal de la souris 
79 #     08/08 :
80 #           -- correction mineure pour s'assurer que les faces soient 
81 #              entierment deconnectees
82 #----------------------------------------------
83
84 import Blender
85 from Blender import Noise
86 from Blender.Draw import *
87 from Blender.BGL import *
88
89 # $Id$
90 Blender.Window.EditMode(0)
91
92
93 def autoDocHelp_script(name,Tip,website):
94     try:
95        dir = Blender.Get('datadir')
96        scriptdir=dir[:dir.find(dir.split(Blender.sys.sep)[-2])]+'scripts'+Blender.sys.sep
97        ttt="""#!BPY\n\"\"\"\nName: '%s'\nBlender: 234
98 Group: 'HelpWebsites'\nTooltip: '%s'\n\"\"\"
99 import Blender, webbrowser\nwebbrowser.open('%s')\n"""%(name,Tip,website)
100        fil=open(scriptdir+'Help_%s.py'%name.replace(' ','_'),'w')
101        fil.write(ttt)
102        fil.close()
103        ttt="""#!BPY\n\"\"\"\nName: 'A french speaking users community'\nBlender: 234\nGroup: 'HelpWebsites'\nTooltip:  'aA french community News Portal, zoo-Blender.'\n\"\"\"
104 import Blender,webbrowser
105 webbrowser.open('http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender')\n"""
106        fil=open(scriptdir+'Help_frenchusers.py','w')
107        fil.write(ttt)
108        fil.close()
109     except:
110        pass
111
112 autoDocHelp_script(name,Tip,website)
113
114 Nr=Noise.random
115 decal=0.03
116 t=[0.0,0.0,0.0]
117 pl=[]
118 orig=[]
119
120 DEBUG = 0
121 SUBSURF=0
122 DIM=Create(1.0)
123
124 def  Tampon(v,t):
125       for n in range(len(v)): t[n]=t[n]+v[n]
126       return t
127    
128 def  freeTampon(t):
129       for n in range(3): t[n]=0.0
130       return t
131
132 def  TamponMoyen(t,f):      
133       for n in range(3): t[n]/=len(f)
134       return t
135
136 def  appliqueMoyenne(v,t):
137       for n in range(len(v)): v[n]=t[n]
138       return v
139
140 def docF(f0,f):
141       try:
142           f0.mat=f.mat
143           f0.uv=f.uv 
144           f0.col=f.col
145           f0.image=f.image
146           f0.smooth=f.smooth
147           f0.mode=f.mode
148           f0.flag=f.flag
149           return f0
150       except:
151           pass    
152
153 def listConnecterFace(me,lebon):
154                listf2v={}
155                #tri des faces connectees aux sommets selectionnes                           
156                for f in me.faces:
157                  for v in f.v:
158                    if v==lebon:
159                       if v.index not in listf2v.keys():
160                           listf2v[me.verts.index(v)]=[f]
161                       elif f not in listf2v[me.verts.index(v)]:
162                          listf2v[me.verts.index(v)].append(f)
163                return listf2v
164
165
166 def creerFaceSupplementaire(me,lebon,listf2v):
167                global t
168                for f in listf2v[lebon.index]:
169
170                   f0=Blender.NMesh.Face()
171                   if result==3: t=freeTampon(t)
172
173                   for v in f.v:
174                      if result==3: t=Tampon(v,t)
175
176                      if v!=lebon:
177                         f0.append(v)
178                      else:
179                         if result==2:                           
180                            nv=Blender.NMesh.Vert(lebon.co[0]+Nr()*decal,
181                                                  lebon.co[1]+Nr()*decal,
182                                                  lebon.co[2]+Nr()*decal)
183                         else:
184                            nv=Blender.NMesh.Vert(lebon.co[0],
185                                                  lebon.co[1],
186                                                  lebon.co[2])
187                         nv.sel=1
188                         me.verts.append(nv)
189
190                         f0.append(me.verts[me.verts.index(nv)])
191                         localise=me.verts.index(nv)                          
192                      docF(f0,f)   
193                      
194                   if result==3:
195                          t=TamponMoyen(t,f0.v)
196                          me.verts[localise]=appliqueMoyenne(me.verts[localise],t)
197                   me.faces.append(f0)                  
198
199                del me.verts[me.verts.index(lebon)]
200
201                for f in listf2v[lebon.index]:
202                   del me.faces[me.faces.index(f)]
203                return me
204
205 def collecte_edge(listf2v,me,lebon):
206       back=0
207       edgelist = []
208       vertlist = []
209       if DEBUG : print listf2v    
210       for face in listf2v[lebon.index]:
211           if len(face.v) == 4:
212               vlist = [0,1,2,3,0]
213           elif len(face.v) == 3:
214               vlist = [0,1,2,0]
215           else:
216               vlist = [0,1]
217           for i in range(len(vlist)-1):              
218               vert0 = min(face.v[vlist[i]].index,face.v[vlist[i+1]].index)
219               vert1 = max(face.v[vlist[i]].index,face.v[vlist[i+1]].index)              
220               edgeinlist = 0
221               if vert0==lebon.index or vert1==lebon.index:                 
222                  for edge in edgelist:
223                     if ((edge[0]==vert0) and (edge[1]==vert1)):
224                         edgeinlist = 1
225                         edge[2] = edge[2]+1
226                         edge.append(me.faces.index(face))
227                         break                  
228                  if edgeinlist==0:
229                     edge = [vert0,vert1,1,me.faces.index(face)]
230                     edgelist.append(edge)
231                     
232       for  edge in edgelist:
233         #print edge
234         if len(edge)==4:
235                    del edgelist[edgelist.index(edge)]
236                            
237       edges=len(edgelist)
238       if DEBUG : print 'number of edges : ',edges," Edge list : " ,edgelist    
239       return edges, edgelist     
240
241 MouseClickG= Blender.Draw.LEFTMOUSE
242 MouseClickD= Blender.Draw.RIGHTMOUSE
243 MouseClickM= Blender.Draw.MIDDLEMOUSE
244
245 mouse_x=1
246 mouse_y=1
247
248 x=1
249 y=1
250
251 debut=0
252
253 def D():
254   size=Buffer(GL_FLOAT, 4)
255   glGetFloatv(GL_SCISSOR_BOX, size)
256   size= size.list 
257   glColor3f(0.1, 0.1, 0.15)
258   glRasterPos2f(10, size[3]-16)
259   Text("Quit = Q Key")
260   glRasterPos2f(10, size[3]-36)
261   Text("Mouse to the Right = Increase")
262   glRasterPos2f(10, size[3]-56)
263   Text("Mouse to the Left = Decrease")
264
265 def E(evt,val):
266  global mouse_x,x,pl,orig,me,debut
267  global mouse_y,y, MouseClickG,MouseClickD,MouseClickM
268  if (evt== QKEY): Exit()
269  
270  if (evt == MOUSEX): 
271        mouse_x = val
272        pos=x-mouse_x
273        x=mouse_x
274        if pos==0:
275           pos=1
276        deplace(pl,orig,abs(pos)/pos)
277  
278  if (evt == MOUSEY): mouse_y = val
279
280 def BE(evt):
281  pass
282
283
284 def deplace(pl,orig,n):
285     global me, OBJECT
286     for p in pl:
287        #print p, orig,len(me.verts) 
288        me.verts[p].co[0]+=n*orig[0]
289        me.verts[p].co[1]+=n*orig[1]
290        me.verts[p].co[2]+=n*orig[2]
291     me.update()
292     Blender.Redraw()
293
294
295 def VertexBevel(result):
296               global t,pl, orig,me,  SUBSURF
297               unique=0
298               for v in me.verts:
299                   if v.sel==1:
300                      lebon=v   
301                      unique+=1
302
303               if  unique==1:
304                     edges=0
305                     edgelist=[]
306                     vertlist=[]
307                     orig=lebon.no[:]
308                     listf2v=listConnecterFace(me,lebon)
309                     edges, edgelist = collecte_edge(listf2v,me,lebon)
310                     for f in listf2v[lebon.index]:
311                        f0=Blender.NMesh.Face()
312                        for v in f.v:
313                           if v!=lebon:
314                              f0.append(v)
315                           else:
316                               nv=Blender.NMesh.Vert(lebon.co[0],lebon.co[1],lebon.co[2])                           
317                               nv.sel=1 
318                               me.verts.append(nv)
319                               f0.append(me.verts[me.verts.index(nv)])
320                               for e in edgelist:
321                                  if e[-1]==me.faces.index(f) or e[-2]==me.faces.index(f):
322                                      if me.verts.index(nv) not in e:
323                                         e.insert(0,me.verts.index(nv))
324                        docF(f0,f)               
325                        me.faces.append(f0)                       
326                        vertlist.append([me.verts.index(nv),me.faces.index(f)])
327                     for e in  edgelist :
328                         del e[e.index(lebon.index)]
329                         f0=Blender.NMesh.Face()
330                         for n in range(3): 
331                            f0.v.append(me.verts[e[n]])
332                         me.faces.append(f0);
333                      
334                     for ve in vertlist:
335                          t=freeTampon(t)
336                          for v in me.faces[ve[1]].v:
337                               t=Tampon(v,t)                     
338                          t=TamponMoyen(t,me.faces[ve[1]].v)
339                          ve.append(t[:])        
340                          me.verts[ve[0]]=appliqueMoyenne(me.verts[ve[0]],t)
341
342                     def swap(x,y):
343                         return y,x
344
345                     p=[[edgelist[0][0],edgelist[0][1]]] 
346                     while len(p)!=len(edgelist): 
347                       for n in range(1,len(edgelist)) :
348                            if p[-1][1]== edgelist[n][0]:
349                               p.append([edgelist[n][0],edgelist[n][1]])
350                               n+=1
351                            elif p[-1][1]== edgelist[n][1]:
352                               edgelist[n][0],edgelist[n][1]=swap(edgelist[n][0],edgelist[n][1])
353                               p.append([edgelist[n][0],edgelist[n][1]])
354                               n+=1
355                     if len(p)%2==0:
356                           P0=p[:(len(p))/2] ; P1=p[len(p)/2:]; P1.reverse()
357                           for s in range(len(P0)-1):
358                              f0=Blender.NMesh.Face()
359                              table=[P0[s][0],P0[s][1],P1[s+1][0],P1[s+1][1]]
360                              for t in table:f0.v.append(me.verts[t])
361                              me.faces.append(f0) 
362                     elif len(p) >3 :   
363                           P0=p[:(len(p)-1)/2];P1=p[(len(p)-1)/2:-1]; P1.reverse()
364                           for s in range(len(P0)-1):
365                              f0=Blender.NMesh.Face()
366                              table=[P0[s][0],P0[s][1],P1[s+1][0],P1[s+1][1]]
367                              for t in table:f0.v.append(me.verts[t])
368                              me.faces.append(f0) 
369                           f0=Blender.NMesh.Face()
370                           table=[p[-1][0],P0[0][0],P1[-1][1]]
371                           for t in table:f0.v.append(me.verts[t])
372                           me.faces.append(f0) 
373
374                     elif len(p) ==3 :   
375                           if DEBUG :print P0,P1      
376                           f0=Blender.NMesh.Face()
377                           table=[p[0][0],p[0][1],p[1][1]]
378                           for t in table:f0.v.append(me.verts[t])
379                           me.faces.append(f0) 
380
381                     for f in listf2v[lebon.index]:
382                        del me.faces[me.faces.index(f)]  
383                     del me.verts[me.verts.index(lebon)]
384                     me.update()
385
386                     if me.mode&Blender.NMesh.Modes['SUBSURF']:
387                        me.mode-=Blender.NMesh.Modes['SUBSURF']
388                        SUBSURF=1 
389                        me.update()
390                        OBJECT[0].makeDisplayList() 
391
392                     if result==5:
393                        pl=[]
394                        for s in me.verts:
395                            if s.sel==1:
396                               pl.append(s.index)
397                        Blender.Draw.Register(D,E,BE)
398
399                     """
400                     if SUBSURF==1 :
401                        me.mode+=Blender.NMesh.Modes['SUBSURF']
402                        me.update()
403                        OBJECT[0].makeDisplayList() 
404                     """  
405               else:
406                   name = " It could leave only one selected vertex %t | ok %x1 ?"
407                   result = Blender.Draw.PupMenu(name)
408
409 OBJECT=Blender.Object.GetSelected()
410
411 if len(OBJECT)!=0:
412    if  OBJECT[0].getType()=='Mesh':
413        name = "Unweld %t|Unbind Points %x1|With Noise %x2|Middle Face %x3|Static Bevel Vertex %x4|Moving Bevel Vertex %x5|"
414        result = Blender.Draw.PupMenu(name)
415        if result:
416            me=OBJECT[0].getData()
417            unique=0
418            if result<4:
419               vSelection=[]
420               for v in me.verts:
421                 if v.sel==1:
422                     vSelection.append(v)
423               for v in  vSelection:
424                     lebon=v    
425                     if DEBUG : print lebon
426                     listf2v=listConnecterFace(me,lebon)
427                     me=creerFaceSupplementaire(me,lebon,listf2v)
428                     #OBJECT[0].link(me)
429                     me.update()
430                     OBJECT[0].makeDisplayList()
431            else:
432                VertexBevel(result)
433                OBJECT[0].makeDisplayList()
434                     
435    else:
436        name = "Nothing to do! Are you sure ?"
437        result = Blender.Draw.PupMenu(name)
438
439