home *** CD-ROM | disk | FTP | other *** search
/ Windows News 2005 November / WNnov2005.iso / Windows / Equipement / Blender / blender-2.37a-windows.exe / $_5_ / .blender / scripts / bevel_center.py < prev    next >
Text File  |  2005-04-17  |  13KB  |  501 lines

  1. #!BPY
  2.  
  3. """ Registration info for Blender menus
  4. Name: 'Bevel Center'
  5. Blender: 236
  6. Group: 'Mesh'
  7. Tip: 'Bevel selected vertices'
  8. """
  9.  
  10. __author__ = "Loic Berthe"
  11. __url__ = ("blender", "elysiun")
  12. __version__ = "1.0"
  13.  
  14. __bpydoc__ = """\
  15. This script implements vertex bevelling in Blender.
  16.  
  17. Usage:
  18.  
  19. Select the mesh you want to work on, enter Edit Mode and select the vertices
  20. to bevel.  Then run this script from the 3d View's Mesh->Scripts menu.
  21.  
  22. You can control the thickness of the bevel with the slider -- redefine the
  23. end points for bigger or smaller ranges.  The thickness can be changed even
  24. after applying the bevel, as many times as needed.
  25.  
  26. For an extra smoothing after or instead of direct bevel, set the level of
  27. recursiveness and use the "Recursive" button.
  28.  
  29. Notes:<br>
  30.     You can undo and redo your steps just like with normal mesh operations in
  31. Blender.
  32. """
  33.  
  34. # $Id: bevel_center.py,v 1.6 2005/04/16 05:25:41 ianwill Exp $
  35. #
  36. ######################################################################
  37. # Bevel Center v1 for Blender
  38. #
  39. # This script lets you bevel the selected vertices and control the
  40. # thickness of the bevel
  41. #
  42. # (c) 2004 Lo∩c Berthe (loic.berthe@lilotux.net)
  43. # released under Blender Artistic License
  44. #
  45. ######################################################################
  46.  
  47. import Blender
  48. from Blender import NMesh, Window
  49. from Blender.Draw import *
  50. from Blender.BGL import *
  51.  
  52. from math import pi, sin, sqrt
  53.  
  54. ######################################################################
  55. # Functions to handle the global structures of the script NV, NE and NC
  56. # which contain informations about the vertices, faces and corners to be
  57. # created
  58.  
  59. class Dir:
  60.     def __init__(self, co):
  61.         self.co = co
  62.  
  63. def add_to_NV(old,co,new):
  64.     dir = Dir(co)
  65.     #
  66.     if old in NV.keys():
  67.         NV[old][dir] = new
  68.     else:
  69.         NV[old] = {dir:new}
  70.  
  71. def is_in_NV(old,co):
  72.     if old in NV.keys():
  73.         for dir in NV[old]:
  74.             if dir.co == co : return NV[old][dir]
  75.     #
  76.     return False
  77.  
  78. def add_to_NE(old, new):
  79.     ind1 = old[0].index
  80.     ind2 = old[1].index
  81.     if ind1 > ind2:
  82.         new.reverse()
  83.         ind1,ind2 = ind2,ind1
  84.     id = str(ind1)+"_"+str(ind2)
  85.     if id in NE.keys():
  86.         [NE[id].append(v) for v in new]
  87.     else:
  88.         NE[id] = new
  89.  
  90. def add_to_NC(old,edge):
  91.     if old in NC.keys():
  92.         NC[old].append(edge)
  93.     else:
  94.         NC[old] = [edge]
  95.         
  96. ######################################################################
  97. # Geometric functions
  98.         
  99. def norm(vec):
  100.     n = sqrt(vec[0]**2+vec[1]**2+vec[2]**2)
  101.     return [vec[0]/n,vec[1]/n,vec[2]/n]
  102.  
  103. def parall_coord(old, dir):
  104.     co = old.co
  105.     vec = [0.0,0.0,0.0]
  106.     nco = [0.0,0.0,0.0]
  107.     #
  108.     if len(dir) == 1:
  109.         for i in range(3): vec[i] = dir[0].co[i] - co[i] 
  110.         vec = norm(vec)
  111.     #
  112.     elif len(dir) == 2:
  113.         vec1 = [0.0,0.0,0.0]
  114.         vec2 = [0.0,0.0,0.0]
  115.         for i in range(3):
  116.             vec1[i] = dir[0].co[i] - co[i] 
  117.             vec2[i] = dir[1].co[i] - co[i] 
  118.         vec1 = norm(vec1)
  119.         vec2 = norm(vec2)
  120.         for i in range(3) : vec[i] = vec1[i]+vec2[i]
  121.     #
  122.     for i in range(3): nco[i] = co[i] + dist.val*vec[i]
  123.     return (nco,vec)
  124.  
  125. def get_vert(old, dir):
  126.     """ Look in NV if a vertice corresponding to the vertex old and the
  127.     direction dir already exists, and create one otherwise""" 
  128.     (nco, vec) = parall_coord(old, dir)
  129.     v = is_in_NV(old,vec)
  130.     if v: return v
  131.     #
  132.     v = NMesh.Vert(nco[0],nco[1],nco[2])
  133.     v.sel = 1
  134.     me.verts.append(v)
  135.     add_to_NV(old,vec,v)
  136.     return v
  137.             
  138. ######################################################################
  139. # Functions to create the differents faces
  140.     
  141. def make_NF():
  142.     """ Analyse the mesh, sort the faces containing selected vertices and
  143.     create a liste NF : NF = [[flag, vertlist, old_face]]. Flag describes the
  144.     topology of the face.""" 
  145.     #
  146.     for f in me.faces:
  147.         V = f.v
  148.         v_sel = [x.sel for x in V]
  149.         nb_sel = sum(v_sel)
  150.         if nb_sel == 0 :
  151.             pass
  152.         else:
  153.             nb_v = len(V)
  154.             #
  155.             if nb_v == 4:
  156.                 #
  157.                 if nb_sel == 4:
  158.                     NF.append([1,V,f])
  159.                 #
  160.                 elif nb_sel == 3:
  161.                     if v_sel == [0,1,1,1]: V = [V[1],V[2],V[3],V[0]]
  162.                     elif v_sel == [1,0,1,1]: V = [V[2],V[3],V[0],V[1]]
  163.                     elif v_sel == [1,1,0,1]: V = [V[3],V[0],V[1],V[2]]
  164.                     NF.append([2,V,f])
  165.                 #        
  166.                 elif nb_sel == 2:
  167.                     if v_sel == [1,0,1,0] or v_sel == [0,1,0,1]:
  168.                         if    v_sel == [0,1,0,1]: V = [V[1],V[2],V[3],V[0]]
  169.                         NF.append([5,[V[0],V[1],V[3]],f])
  170.                         NF.append([5,[V[2],V[1],V[3]]])
  171.                     else:
  172.                         if v_sel == [0,1,1,0]: V = [V[1],V[2],V[3],V[0]]
  173.                         elif v_sel == [0,0,1,1]: V = [V[2],V[3],V[0],V[1]]
  174.                         elif v_sel == [1,0,0,1]: V = [V[3],V[0],V[1],V[2]]
  175.                         NF.append([3,V,f])
  176.                 #
  177.                 else:
  178.                     if v_sel == [0,1,0,0]: V = [V[1],V[2],V[3],V[0]]
  179.                     elif v_sel == [0,0,1,0]: V = [V[2],V[3],V[0],V[1]]
  180.                     elif v_sel == [0,0,0,1]: V = [V[3],V[0],V[1],V[2]]
  181.                     NF.append([4,V,f])
  182.             #
  183.             elif nb_v == 3:
  184.                 #
  185.                 if nb_sel == 3:
  186.                     NF.append([6,V,f])
  187.                 #
  188.                 elif nb_sel == 2:
  189.                     if v_sel == [0,1,1]: V = [V[1],V[2],V[0]]
  190.                     elif v_sel == [1,0,1]: V = [V[2],V[0],V[1]]
  191.                     NF.append([7,V,f])
  192.                 #
  193.                 else:
  194.                     if v_sel == [0,1,0]: V = [V[1],V[2],V[0]]
  195.                     elif v_sel == [0,0,1]: V = [V[2],V[0],V[1]]
  196.                     NF.append([5,V,f])
  197.  
  198. def make_faces():
  199.     """ Make the new faces according to NF """
  200.     #
  201.     for N in NF:
  202.         cas = N[0]
  203.         V = N[1]
  204.         #
  205.         if cas < 6:
  206.             new_v = [0,0,0,0]
  207.             if cas == 1:                # v_sel = [1,1,1,1]
  208.                 for i in range(-1,3):
  209.                     new_v[i] = get_vert(V[i],[V[i-1],V[i+1]])
  210.                 new_f = NMesh.Face(new_v)
  211.                 me.faces.append(new_f)
  212.                 for i in range(-1,3):
  213.                     add_to_NE([V[i],V[i+1]],[new_v[i],new_v[i+1]])
  214.             #
  215.             elif cas == 2:                # v_sel = [1,1,1,0]
  216.                 new_v[0] = get_vert(V[0],[V[3]])
  217.                 new_v[1] = get_vert(V[1],[V[0],V[2]])
  218.                 new_v[2] = get_vert(V[2],[V[3]])
  219.                 new_v[3] = V[3]
  220.                 #
  221.                 new_f = NMesh.Face(new_v)
  222.                 me.faces.append(new_f)
  223.                 #
  224.                 add_to_NE([V[0],V[1]],[new_v[0],new_v[1]])
  225.                 add_to_NE([V[1],V[2]],[new_v[1],new_v[2]])
  226.             #        
  227.             elif cas == 3:                # v_sel = [1,1,0,0]
  228.                 new_v[0] = get_vert(V[0],[V[3]])
  229.                 new_v[1] = get_vert(V[1],[V[2]])
  230.                 new_v[2] = V[2]
  231.                 new_v[3] = V[3]
  232.                 #
  233.                 new_f = NMesh.Face(new_v)
  234.                 me.faces.append(new_f)
  235.                 #
  236.                 add_to_NE([V[0],V[1]],[new_v[0],new_v[1]])
  237.             #
  238.             elif cas == 4:                # v_sel = [1,0,0,0]
  239.                 new_v[0] = get_vert(V[0],[V[3]])
  240.                 new_v[1] = get_vert(V[0],[V[1]])
  241.                 new_v[2] = V[1]
  242.                 new_v[3] = V[3]
  243.                 #
  244.                 new_f = NMesh.Face(new_v)
  245.                 me.faces.append(new_f)
  246.                 #
  247.                 add_to_NC(V[0], new_v[0:2])
  248.                 #
  249.                 new_v[0] = V[1]
  250.                 new_v[1] = V[2]
  251.                 new_v[2] = V[3]
  252.                 #
  253.                 new_f = NMesh.Face(new_v[:3])
  254.                 me.faces.append(new_f)
  255.             #
  256.             else:                # v_sel = [1,0,0]
  257.                 new_v[0] = get_vert(V[0],[V[2]])
  258.                 new_v[1] = get_vert(V[0],[V[1]])
  259.                 new_v[2] = V[1]
  260.                 new_v[3] = V[2]
  261.                 #
  262.                 new_f = NMesh.Face(new_v)
  263.                 me.faces.append(new_f)
  264.                 #
  265.                 add_to_NC(V[0], new_v[0:2])
  266.         #
  267.         else:
  268.             new_v = [0,0,0]
  269.             #
  270.             if cas == 6:                # v_sel = [1,1,1]
  271.                 for i in range(-1,2):
  272.                     new_v[i] = get_vert(V[i],[V[i-1],V[i+1]])
  273.                 new_f = NMesh.Face(new_v)
  274.                 me.faces.append(new_f)
  275.                 for i in range(-1,2):
  276.                     add_to_NE([V[i],V[i+1]],[new_v[i],new_v[i+1]])
  277.             #
  278.             elif cas == 7:                # v_sel = [1,1,0]
  279.                 new_v[0] = get_vert(V[0],[V[2]])
  280.                 new_v[1] = get_vert(V[1],[V[2]])
  281.                 new_v[2] = V[2]
  282.                 #
  283.                 new_f = NMesh.Face(new_v)
  284.                 me.faces.append(new_f)
  285.                 add_to_NE([V[0],V[1]],[new_v[0],new_v[1]])
  286.  
  287. def make_edges():
  288.     """ Make the faces corresponding to selected edges """
  289.     #
  290.     for l in NE.values():
  291.         if len(l) == 4:
  292.             f = NMesh.Face([l[0],l[1],l[3],l[2]])
  293.             me.faces.append(f)
  294.  
  295. def make_corners():
  296.     """ Make the faces corresponding to selected corners """
  297.     #
  298.     for v in NV.keys():
  299.         V = NV[v].values()
  300.         nb_v = len(V)
  301.         #
  302.         if nb_v < 3:
  303.             pass
  304.         #
  305.         elif nb_v == 3:
  306.             new_f = NMesh.Face(V)
  307.             me.faces.append(new_f)
  308.         #
  309.         else:
  310.             # We need to know which are the edges around the corner.
  311.             # First, we look for the quads surrounding the corner.
  312.             q = [NE[id] for id in NE.keys() if str(v.index) in id.split('_')]
  313.             #
  314.             # We will put the associated edges in the list eed
  315.             is_in_v = lambda x:x in V
  316.             eed =  [filter(is_in_v, l) for l in q]
  317.             #
  318.             # We will add the edges coming from faces where only one vertice is selected.
  319.             # They are stocked in NC.
  320.             if v in NC.keys():
  321.                 eed = eed+NC[v]
  322.             b = eed.pop()
  323.             # b will contain the sorted list of vertices
  324.             #
  325.             while  eed:
  326.                 for l in eed:
  327.                     if l[0] == b[-1]:
  328.                         b.append(l[1])
  329.                         eed.remove(l)
  330.                         break
  331.                     elif l[1] == b[-1]:
  332.                         b.append(l[0])
  333.                         eed.remove(l)
  334.                         break
  335.             # Now we can create the faces
  336.             if nb_v == 4:
  337.                 new_f = NMesh.Face(b[:4])
  338.                 me.faces.append(new_f)
  339.             #
  340.             else:
  341.                 co = [0.0, 0.0,0.0]
  342.                 vec = [0.0, 0.0,0.0]
  343.                 for x in V:
  344.                     co[0] += x[0]
  345.                     co[1] += x[1]
  346.                     co[2] += x[2]
  347.                 #
  348.                 for dir in NV[v]:
  349.                     vec[0] += dir.co[0]
  350.                     vec[1] += dir.co[1]
  351.                     vec[2] += dir.co[2]
  352.                 #
  353.                 co = [x/nb_v for x in co]
  354.                 vec = [x/nb_v for x in vec]
  355.                 center = NMesh.Vert(co[0],co[1],co[2])
  356.                 center.sel = 1
  357.                 me.verts.append(center)
  358.                 add_to_NV(v,vec,center)
  359.                 #
  360.                 for k in range(nb_v):
  361.                     new_f = NMesh.Face([center, b[k], b[k+1]])
  362.                     me.faces.append(new_f)
  363.         #
  364.  
  365. def clear_old():
  366.     """ Erase old faces and vertices """
  367.     for F in NF:
  368.         if len(F) == 3:
  369.             me.faces.remove(F[2])
  370.     #
  371.     for v in NV.keys():
  372.         me.verts.remove(v)
  373.  
  374. ######################################################################
  375. # Interface
  376. #
  377. global dist
  378. NV = {}
  379. dist = Create(0.2)
  380. left = Create(0.0)
  381. right = Create(1.0)
  382. num = Create(2)
  383.  
  384. # Events
  385. EVENT_NOEVENT = 1
  386. EVENT_BEVEL = 2
  387. EVENT_UPDATE = 3
  388. EVENT_RECURS = 4
  389. EVENT_EXIT = 5
  390.  
  391. def draw():
  392.     global dist, left, right, num
  393.     global EVENT_NOEVENT, EVENT_BEVEL, EVENT_UPDATE, EVENT_RECURS, EVENT_EXIT
  394.  
  395.     glClear(GL_COLOR_BUFFER_BIT)
  396.     Button("Bevel",EVENT_BEVEL,10,100,300,25)
  397.     left=Number('',  EVENT_NOEVENT,10,70,50, 20,left.val,0,right.val,'Set the minimum of the slider')
  398.     right = Number("",EVENT_NOEVENT,260,70,50,20,right.val,left.val,200,"Set the maximum of the slider")
  399.     dist=Slider("Thickness ",EVENT_UPDATE,65,70,190,20,dist.val,left.val,right.val,0,"Thickness of the bevel, can be changed even after bevelling")
  400.     glRasterPos2d(10,40)
  401.     Text('To finish, you can use recursive bevel to smooth it')
  402.     num=Number('',    EVENT_NOEVENT,10,10,50, 16,num.val,1,100,'Recursion level')
  403.     Button("Recursive",EVENT_RECURS,65,10,100,16)
  404.     Button("Exit",EVENT_EXIT,230,10,80,20)
  405.  
  406. def event(evt, val):
  407.     if ((evt == QKEY or evt == ESCKEY) and not val):
  408.         Exit()
  409.  
  410. def bevent(evt):
  411.     if evt == EVENT_EXIT :
  412.         Exit()
  413.     #
  414.     elif evt == EVENT_BEVEL:
  415.         bevel()
  416.     #
  417.     elif evt == EVENT_UPDATE:
  418.         try:
  419.             bevel_update()
  420.         except NameError:
  421.             pass
  422.     #
  423.     elif evt == EVENT_RECURS:
  424.         recursive()
  425.  
  426. Register(draw, event, bevent)
  427.  
  428. ######################################################################
  429. def bevel():
  430.     """ The main function, which creates the bevel """
  431.     global me,NF,NV,NE,NC, old_dist
  432.     #
  433.     is_editmode = Window.EditMode()
  434.     if is_editmode: Window.EditMode(0)
  435.     objects = Blender.Object.GetSelected() 
  436.     bev_obj = objects[0]
  437.     if bev_obj.getType() != "Mesh":
  438.         PupMenu("ERROR: active object must be a mesh")
  439.         return
  440.     me = NMesh.GetRaw(bev_obj.getData(name_only = True))
  441.     #
  442.     NF = []
  443.     NV = {}
  444.     NE = {}
  445.     NC = {}
  446.     #
  447.     make_NF()
  448.     make_faces()
  449.     make_edges()
  450.     make_corners()
  451.     clear_old()
  452.     #
  453.     old_dist = dist.val
  454.     #
  455.     me.update(1)
  456.     if is_editmode: Window.EditMode(1)
  457.     Blender.Redraw()
  458.  
  459. def bevel_update():
  460.     """ Use NV to update the bevel """
  461.     global dist, old_dist, NV
  462.     if not NV: return
  463.     is_editmode = Window.EditMode()
  464.     if is_editmode: Window.EditMode(0)
  465.     fac = dist.val - old_dist
  466.     old_dist = dist.val
  467.     #
  468.     for old_v in NV.keys():
  469.         for dir in NV[old_v].keys():
  470.             for i in range(3):
  471.                 NV[old_v][dir].co[i] += fac*dir.co[i]
  472.     #
  473.     me.update(1)
  474.     if is_editmode: Window.EditMode(1)
  475.     Blender.Redraw()
  476.  
  477. def recursive():
  478.     """ Make a recursive bevel... still experimental """
  479.     global dist
  480.     #
  481.     if num.val > 1:
  482.         a = pi/4
  483.         ang = []
  484.         for k in range(num.val):
  485.             ang.append(a)
  486.             a = (pi+2*a)/4
  487.         #
  488.         l = [2*(1-sin(x))/sin(2*x) for x in ang]
  489.         R = dist.val/sum(l)
  490.         l = [x*R for x in l]
  491.         #
  492.         dist.val = l[0]
  493.         bevel_update()
  494.         #
  495.         for x in l[1:]:
  496.             dist.val = x
  497.             bevel()
  498.     
  499. # vim:set ts=4 sw=4:
  500.  
  501.