blender/release/scripts/bevel_center.py

463 lines
10 KiB
Python
Raw Normal View History

New scripts: - hotkeys, obdatacopier and renameobjectbyblock, all from Jean-Michel Soler (jms); - bevel_center by Loic Berthe, suggested for inclusion by jms; - doc_browser, by Daniel Dunbar (Zr) Thanks to them for the new contributions! (I included doc_browser at 'Misc' because only users interested in script writing would actually use it, but it could also be under 'Help'. Opinions?) BPython related: - Added scriptlink methods to object, lamp, camera and world. - Object: added object.makeTrack and object.clearTrack (old track method). - sys: made sys.exists(path) return 0 for not found; 1 for file, 2 for dir and -1 for neither. - doc updates and fixes. - made ONLOAD event work. G.f's SCENESCRIPT bit was being zeroed in set_app_data. - Blender: updated functions Load and Save to support the builtin importers and exporters besides .blend (dxf, videoscape, vrml 1.0, stl, ...) - Draw: added mouse wheel events. - Scene: added scene.play to play back animations (like ALT+A and SHIFT+ALT+A). Makes a good counter, too, when the 'win' attribute is set to a space that doesn't "animate". The scene.play() addition and the fix to ONLOAD scriptlinks is part of the work for a Blender demo mode. It already works, but I'll still add support for Radiosity calculations and fix a thing in main(): it executes onload scripts too early (BIF_Init), giving funny results in alt+a animations and renderings when firing up Blender. Loading after the program is up has no such problems. When I finish I'll post examples of demo mode scripts.
2004-07-03 05:17:04 +00:00
#!BPY
""" Registration info for Blender menus
Name: 'Bevel Center'
Blender: 232
Group: 'Mesh'
Tip: 'Bevel selected vertices.'
"""
######################################################################
# Bevel Center v1 for Blender
#
# This script lets you bevel the selected vertices and control the
# thickness of the bevel
#
# (c) 2004 Lo<4C>c Berthe (loic.berthe@lilotux.net)
# released under Blender Artistic License
#
######################################################################
import Blender
from Blender import NMesh
from Blender.Draw import *
from Blender.BGL import *
from math import pi, sin, sqrt
######################################################################
# Functions to handle the global structures of the script NV, NE and NC
# which contain informations about the vertices, faces and corners to be
# created
class Dir:
def __init__(self, co):
self.co = co
def add_to_NV(old,co,new):
dir = Dir(co)
#
if old in NV.keys():
NV[old][dir] = new
else:
NV[old] = {dir:new}
def is_in_NV(old,co):
if old in NV.keys():
for dir in NV[old]:
if dir.co == co : return NV[old][dir]
#
return False
def add_to_NE(old, new):
ind1 = old[0].index
ind2 = old[1].index
if ind1 > ind2:
new.reverse()
ind1,ind2 = ind2,ind1
id = str(ind1)+"_"+str(ind2)
if id in NE.keys():
[NE[id].append(v) for v in new]
else:
NE[id] = new
def add_to_NC(old,edge):
if old in NC.keys():
NC[old].append(edge)
else:
NC[old] = [edge]
######################################################################
# Geometric functions
def norm(vec):
n = sqrt(vec[0]**2+vec[1]**2+vec[2]**2)
return [vec[0]/n,vec[1]/n,vec[2]/n]
def parall_coord(old, dir):
co = old.co
vec = [0.0,0.0,0.0]
nco = [0.0,0.0,0.0]
#
if len(dir) == 1:
for i in range(3): vec[i] = dir[0].co[i] - co[i]
vec = norm(vec)
#
elif len(dir) == 2:
vec1 = [0.0,0.0,0.0]
vec2 = [0.0,0.0,0.0]
for i in range(3):
vec1[i] = dir[0].co[i] - co[i]
vec2[i] = dir[1].co[i] - co[i]
vec1 = norm(vec1)
vec2 = norm(vec2)
for i in range(3) : vec[i] = vec1[i]+vec2[i]
#
for i in range(3): nco[i] = co[i] + dist.val*vec[i]
return (nco,vec)
def get_vert(old, dir):
""" Look in NV if a vertice corresponding to the vertex old and the
direction dir already exists, and create one otherwise"""
(nco, vec) = parall_coord(old, dir)
v = is_in_NV(old,vec)
if v: return v
#
v = NMesh.Vert(nco[0],nco[1],nco[2])
v.sel = 1
me.verts.append(v)
add_to_NV(old,vec,v)
return v
######################################################################
# Functions to create the differents faces
def make_NF():
""" Analyse the mesh, sort the faces containing selected vertices and
create a liste NF : NF = [[flag, vertlist, old_face]]. Flag describes the
topology of the face."""
#
for f in me.faces:
V = f.v
v_sel = [x.sel for x in V]
nb_sel = sum(v_sel)
if nb_sel == 0 :
pass
else:
nb_v = len(V)
#
if nb_v == 4:
#
if nb_sel == 4:
NF.append([1,V,f])
#
elif nb_sel == 3:
if v_sel == [0,1,1,1]: V = [V[1],V[2],V[3],V[0]]
elif v_sel == [1,0,1,1]: V = [V[2],V[3],V[0],V[1]]
elif v_sel == [1,1,0,1]: V = [V[3],V[0],V[1],V[2]]
NF.append([2,V,f])
#
elif nb_sel == 2:
if v_sel == [1,0,1,0] or v_sel == [0,1,0,1]:
if v_sel == [0,1,0,1]: V = [V[1],V[2],V[3],V[0]]
NF.append([5,[V[0],V[1],V[3]],f])
NF.append([5,[V[2],V[1],V[3]]])
else:
if v_sel == [0,1,1,0]: V = [V[1],V[2],V[3],V[0]]
elif v_sel == [0,0,1,1]: V = [V[2],V[3],V[0],V[1]]
elif v_sel == [1,0,0,1]: V = [V[3],V[0],V[1],V[2]]
NF.append([3,V,f])
#
else:
if v_sel == [0,1,0,0]: V = [V[1],V[2],V[3],V[0]]
elif v_sel == [0,0,1,0]: V = [V[2],V[3],V[0],V[1]]
elif v_sel == [0,0,0,1]: V = [V[3],V[0],V[1],V[2]]
NF.append([4,V,f])
#
elif nb_v == 3:
#
if nb_sel == 3:
NF.append([6,V,f])
#
elif nb_sel == 2:
if v_sel == [0,1,1]: V = [V[1],V[2],V[0]]
elif v_sel == [1,0,1]: V = [V[2],V[0],V[1]]
NF.append([7,V,f])
#
else:
if v_sel == [0,1,0]: V = [V[1],V[2],V[0]]
elif v_sel == [0,0,1]: V = [V[2],V[0],V[1]]
NF.append([5,V,f])
def make_faces():
""" Make the new faces according to NF """
#
for N in NF:
cas = N[0]
V = N[1]
#
if cas < 6:
new_v = [0,0,0,0]
if cas == 1: # v_sel = [1,1,1,1]
for i in range(-1,3):
new_v[i] = get_vert(V[i],[V[i-1],V[i+1]])
new_f = NMesh.Face(new_v)
me.faces.append(new_f)
for i in range(-1,3):
add_to_NE([V[i],V[i+1]],[new_v[i],new_v[i+1]])
#
elif cas == 2: # v_sel = [1,1,1,0]
new_v[0] = get_vert(V[0],[V[3]])
new_v[1] = get_vert(V[1],[V[0],V[2]])
new_v[2] = get_vert(V[2],[V[3]])
new_v[3] = V[3]
#
new_f = NMesh.Face(new_v)
me.faces.append(new_f)
#
add_to_NE([V[0],V[1]],[new_v[0],new_v[1]])
add_to_NE([V[1],V[2]],[new_v[1],new_v[2]])
#
elif cas == 3: # v_sel = [1,1,0,0]
new_v[0] = get_vert(V[0],[V[3]])
new_v[1] = get_vert(V[1],[V[2]])
new_v[2] = V[2]
new_v[3] = V[3]
#
new_f = NMesh.Face(new_v)
me.faces.append(new_f)
#
add_to_NE([V[0],V[1]],[new_v[0],new_v[1]])
#
elif cas == 4: # v_sel = [1,0,0,0]
new_v[0] = get_vert(V[0],[V[3]])
new_v[1] = get_vert(V[0],[V[1]])
new_v[2] = V[1]
new_v[3] = V[3]
#
new_f = NMesh.Face(new_v)
me.faces.append(new_f)
#
add_to_NC(V[0], new_v[0:2])
#
new_v[0] = V[1]
new_v[1] = V[2]
new_v[2] = V[3]
#
new_f = NMesh.Face(new_v[:3])
me.faces.append(new_f)
#
else: # v_sel = [1,0,0]
new_v[0] = get_vert(V[0],[V[2]])
new_v[1] = get_vert(V[0],[V[1]])
new_v[2] = V[1]
new_v[3] = V[2]
#
new_f = NMesh.Face(new_v)
me.faces.append(new_f)
#
add_to_NC(V[0], new_v[0:2])
#
else:
new_v = [0,0,0]
#
if cas == 6: # v_sel = [1,1,1]
for i in range(-1,2):
new_v[i] = get_vert(V[i],[V[i-1],V[i+1]])
new_f = NMesh.Face(new_v)
me.faces.append(new_f)
for i in range(-1,2):
add_to_NE([V[i],V[i+1]],[new_v[i],new_v[i+1]])
#
elif cas == 7: # v_sel = [1,1,0]
new_v[0] = get_vert(V[0],[V[2]])
new_v[1] = get_vert(V[1],[V[2]])
new_v[2] = V[2]
#
new_f = NMesh.Face(new_v)
me.faces.append(new_f)
add_to_NE([V[0],V[1]],[new_v[0],new_v[1]])
def make_edges():
""" Make the faces corresponding to selected edges """
#
for l in NE.values():
if len(l) == 4:
f = NMesh.Face([l[0],l[1],l[3],l[2]])
me.faces.append(f)
def make_corners():
""" Make the faces corresponding to selected corners """
#
for v in NV.keys():
V = NV[v].values()
nb_v = len(V)
#
if nb_v < 3:
pass
#
elif nb_v == 3:
new_f = NMesh.Face(V)
me.faces.append(new_f)
#
else:
# We need to know which are the edges around the corner.
# First, we look for the quads surrounding the corner.
q = [NE[id] for id in NE.keys() if str(v.index) in id.split('_')]
#
# We will put the associated edges in the list eed
is_in_v = lambda x:x in V
eed = [filter(is_in_v, l) for l in q]
#
# We will add the edges coming from faces where only one vertice is selected.
# They are stocked in NC.
if v in NC.keys():
eed = eed+NC[v]
b = eed.pop()
# b will contain the sorted list of vertices
#
while eed:
for l in eed:
if l[0] == b[-1]:
b.append(l[1])
eed.remove(l)
break
elif l[1] == b[-1]:
b.append(l[0])
eed.remove(l)
break
# Now we can create the faces
if nb_v == 4:
new_f = NMesh.Face(b[:4])
me.faces.append(new_f)
#
else:
co = [0.0, 0.0,0.0]
vec = [0.0, 0.0,0.0]
for x in V:
co[0] += x[0]
co[1] += x[1]
co[2] += x[2]
#
for dir in NV[v]:
vec[0] += dir.co[0]
vec[1] += dir.co[1]
vec[2] += dir.co[2]
#
co = [x/nb_v for x in co]
vec = [x/nb_v for x in vec]
center = NMesh.Vert(co[0],co[1],co[2])
center.sel = 1
me.verts.append(center)
add_to_NV(v,vec,center)
#
for k in range(nb_v):
new_f = NMesh.Face([center, b[k], b[k+1]])
me.faces.append(new_f)
#
def clear_old():
""" Erase old faces and vertices """
for F in NF:
if len(F) == 3:
me.faces.remove(F[2])
#
for v in NV.keys():
me.verts.remove(v)
######################################################################
# Interface
#
global dist
dist = Create(0.2)
left = Create(0.0)
right = Create(1.0)
num = Create(2)
# Events
EVENT_NOEVENT = 1
EVENT_BEVEL = 2
EVENT_UPDATE = 3
EVENT_RECURS = 4
EVENT_EXIT = 5
def draw():
global dist, left, right, num
global EVENT_NOEVENT, EVENT_BEVEL, EVENT_UPDATE, EVENT_RECURS, EVENT_EXIT
glClear(GL_COLOR_BUFFER_BIT)
Button("Bevel",EVENT_BEVEL,10,100,280,25)
left=Number('', EVENT_NOEVENT,10,70,45, 20,left.val,0,right.val,'Set the minimum of the slider')
right = Number("",EVENT_NOEVENT,245,70,45,20,right.val,left.val,200,"Set the maximum of the slider")
dist=Slider("Thickness ",EVENT_UPDATE,60,70,180,20,dist.val,left.val,right.val,0,"Thickness of the bevel")
glRasterPos2d(8,40)
Text('To finish, you can use recursive bevel to smooth it')
num=Number('', EVENT_NOEVENT,10,10,40, 16,num.val,1,100,'Recursion level')
Button("Recursive",EVENT_RECURS,55,10,100,16)
Button("Exit",EVENT_EXIT,210,10,80,20)
def event(evt, val):
if (evt == QKEY and not val):
Exit()
def bevent(evt):
if evt == EVENT_EXIT :
Exit()
#
elif evt == EVENT_BEVEL:
bevel()
#
elif evt == EVENT_UPDATE:
try:
bevel_update()
except NameError:
pass
#
elif evt == EVENT_RECURS:
recursive()
Register(draw, event, bevent)
######################################################################
def bevel():
""" The main function, which creates the bevel """
global me,NF,NV,NE,NC, old_dist
#
objects = Blender.Object.GetSelected()
me = NMesh.GetRaw(objects[0].data.name)
#
NF = []
NV = {}
NE = {}
NC = {}
#
make_NF()
make_faces()
make_edges()
make_corners()
clear_old()
#
old_dist = dist.val
#
me.update(1)
Blender.Redraw()
def bevel_update():
""" Use NV to update the bevel """
global dist, old_dist
fac = dist.val - old_dist
old_dist = dist.val
#
for old_v in NV.keys():
for dir in NV[old_v].keys():
for i in range(3):
NV[old_v][dir].co[i] += fac*dir.co[i]
#
me.update(1)
Blender.Redraw()
def recursive():
""" Make a recursive bevel... still experimental """
global dist
#
if num.val > 1:
a = pi/4
ang = []
for k in range(num.val):
ang.append(a)
a = (pi+2*a)/4
#
l = [2*(1-sin(x))/sin(2*x) for x in ang]
R = dist.val/sum(l)
l = [x*R for x in l]
#
dist.val = l[0]
bevel_update()
#
for x in l[1:]:
dist.val = x
bevel()
# vim:set ts=4 sw=4: