Added a function to BPyMesh - getFaceLoopEdges(faces, seams=[])

returns all face loops as a list of their edge keys

Used this in uvcalc_follow_active_coords to speed it from 5.53sec to 0.098 on a 1000 face mesh.
This commit is contained in:
Campbell Barton 2006-12-27 15:21:34 +00:00
parent 4d74f07043
commit 7b93fff204
2 changed files with 85 additions and 111 deletions

@ -301,19 +301,76 @@ def mesh2linkedFaces(me):
def getEdgeLoopsFromFaces(faces): def getFaceLoopEdges(faces, seams=[]):
''' '''
Takes me.faces or a list of faces and returns the edge loops Takes me.faces or a list of faces and returns the edge loops
These edge loops are the edges that sit between quads, so they dont touch These edge loops are the edges that sit between quads, so they dont touch
1 quad, not not connected will make 2 edge loops, both only containing 2 edges. 1 quad, not not connected will make 2 edge loops, both only containing 2 edges.
return a list of edge key lists
[ [(0,1), (4, 8), (3,8)], ...]
optionaly, seams are edge keys that will be removed
''' '''
OTHER_INDEX = 2,3,0,1 # opposite face index
edges = {} edges = {}
for f in faces: for f in faces:
for i, edkey in enumerate(f.edge_keys): if len(f) == 4:
try: edges[edkey].append((f, i)) edge_keys = f.edge_keys
except: edges[edkey] = [(f, i)] for i, edkey in enumerate(f.edge_keys):
try: edges[edkey].append(edge_keys[OTHER_INDEX[i]])
except: edges[edkey] = [ edge_keys[OTHER_INDEX[i]] ]
for edkey in seams:
edges[edkey] = []
# Collect edge loops here
edge_loops = []
for edkey, ed_adj in edges.iteritems():
if 0 <len(ed_adj) < 3: # 1 or 2
# Seek the first edge
context_loop = [edkey, ed_adj[0]]
edge_loops.append(context_loop)
if len(ed_adj) == 2:
other_dir = ed_adj[1]
else:
other_dir = None
ed_adj[:] = []
flipped = False
while 1:
# from knowing the last 2, look for th next.
ed_adj = edges[context_loop[-1]]
if len(ed_adj) != 2:
if other_dir and flipped==False: # the original edge had 2 other edges
flipped = True # only flip the list once
context_loop.reverse()
ed_adj[:] = []
context_loop.append(other_dir) # save 1 lookiup
ed_adj = edges[context_loop[-1]]
if len(ed_adj) != 2:
ed_adj[:] = []
break
else:
ed_adj[:] = []
break
i = ed_adj.index(context_loop[-2])
context_loop.append( ed_adj[ not i] )
# Dont look at this again
ed_adj[:] = []
return edge_loops

@ -39,7 +39,8 @@ http://mediawiki.blender.org/index.php/Scripts/Manual/UV_Calculate/Follow_active
from Blender import * from Blender import *
import BPyMesh
reload(BPyMesh)
def extend(): def extend():
scn = Scene.GetCurrent() scn = Scene.GetCurrent()
@ -54,12 +55,12 @@ def extend():
me_verts = me.verts me_verts = me.verts
# 0:normal extend, 1:edge length # 0:normal extend, 1:edge length
EXTEND_MODE = Draw.PupMenu("Use Face Area%t|Loop Average%x2|Face Average%x1|None%x0") EXTEND_MODE = Draw.PupMenu("Use Face Area%t|Loop Average%x2|None%x0")
if EXTEND_MODE == -1: if EXTEND_MODE == -1:
return return
Window.WaitCursor(1) Window.WaitCursor(1)
t = sys.time()
edge_average_lengths = {} edge_average_lengths = {}
OTHER_INDEX = 2,3,0,1 OTHER_INDEX = 2,3,0,1
@ -118,39 +119,22 @@ def extend():
# Set the 2 UV's on the target face that are not touching # Set the 2 UV's on the target face that are not touching
# for this we need to do basic expaning on the source faces UV's # for this we need to do basic expaning on the source faces UV's
if EXTEND_MODE == 1 or EXTEND_MODE == 2: if EXTEND_MODE == 2:
try: # divide by zero is possible try: # divide by zero is possible
''' '''
measure the length of each face from the middle of each edge to the opposite measure the length of each face from the middle of each edge to the opposite
allong the axis we are copying, use this allong the axis we are copying, use this
''' '''
i1a= edgepair_outer_target[iB]
i2a= edgepair_inner_target[iA]
if i1a>i2a: i1a, i2a = i2a, i1a
if EXTEND_MODE == 1: i1b= edgepair_outer_source[iB]
# Average lengths with edge_average_lengths i2b= edgepair_inner_source[iA]
if i1b>i2b: i1b, i2b = i2b, i1b
factor =\ # print edge_average_lengths
(\ factor = edge_average_lengths[i1a, i2a][0] / edge_average_lengths[i1b, i2b][0]
(me_verts[edgepair_outer_target[iB]].co + me_verts[edgepair_outer_target[iA]].co)-\
(me_verts[edgepair_inner_target[iA]].co + me_verts[edgepair_inner_target[iB]].co)\
).length / (\
(me_verts[edgepair_outer_source[iB]].co + me_verts[edgepair_outer_source[iA]].co)-\
(me_verts[edgepair_inner_source[iA]].co + me_verts[edgepair_inner_source[iB]].co)\
).length
else: # EXTEND_MODE == 2
i1a= edgepair_outer_target[iB]
i2a= edgepair_inner_target[iA]
if i1a>i2a: i1a, i2a = i2a, i1a
i1b= edgepair_outer_source[iB]
i2b= edgepair_inner_source[iA]
if i1b>i2b: i1b, i2b = i2b, i1b
# print edge_average_lengths
factor = edge_average_lengths[i1a, i2a][0] / edge_average_lengths[i1b, i2b][0]
except: except:
# Div By Zero? # Div By Zero?
factor = 1.0 factor = 1.0
@ -158,12 +142,6 @@ def extend():
uvs_vhash_target[edgepair_outer_target[iB]][:] = uvs_vhash_source[edgepair_inner_source[0]] +factor * (uvs_vhash_source[edgepair_inner_source[0]] - uvs_vhash_source[edgepair_outer_source[1]]) uvs_vhash_target[edgepair_outer_target[iB]][:] = uvs_vhash_source[edgepair_inner_source[0]] +factor * (uvs_vhash_source[edgepair_inner_source[0]] - uvs_vhash_source[edgepair_outer_source[1]])
uvs_vhash_target[edgepair_outer_target[iA]][:] = uvs_vhash_source[edgepair_inner_source[1]] +factor * (uvs_vhash_source[edgepair_inner_source[1]] - uvs_vhash_source[edgepair_outer_source[0]]) uvs_vhash_target[edgepair_outer_target[iA]][:] = uvs_vhash_source[edgepair_inner_source[1]] +factor * (uvs_vhash_source[edgepair_inner_source[1]] - uvs_vhash_source[edgepair_outer_source[0]])
else: else:
# same as above but with no factor # same as above but with no factor
uvs_vhash_target[edgepair_outer_target[iB]][:] = uvs_vhash_source[edgepair_inner_source[0]] + (uvs_vhash_source[edgepair_inner_source[0]] - uvs_vhash_source[edgepair_outer_source[1]]) uvs_vhash_target[edgepair_outer_target[iB]][:] = uvs_vhash_source[edgepair_inner_source[0]] + (uvs_vhash_source[edgepair_inner_source[0]] - uvs_vhash_source[edgepair_outer_source[1]])
@ -197,7 +175,7 @@ def extend():
# Modes # Modes
# 0 unsearched # 0 unsearched
# 1:mapped, use search from this face. # 1:mapped, use search from this face. - removed!!
# 2:all siblings have been searched. dont search again. # 2:all siblings have been searched. dont search again.
face_modes = [0] * len(face_sel) face_modes = [0] * len(face_sel)
face_modes[face_act_local_index] = 1 # extend UV's from this face. face_modes[face_act_local_index] = 1 # extend UV's from this face.
@ -213,75 +191,14 @@ def extend():
SEAM = Mesh.EdgeFlags.SEAM SEAM = Mesh.EdgeFlags.SEAM
if EXTEND_MODE == 2: if EXTEND_MODE == 2:
# Generate grid average edge lengths per edgeloop! edge_loops = BPyMesh.getFaceLoopEdges(face_sel, [ed.key for ed in me.edges if ed.flag & SEAM] )
# this means that for each face loop, the edges on it will have new fake, everaged lengths me_verts = me.verts
# WARNING! - This is not that optimal!!!... but neither is it horrid - Campbell for loop in edge_loops:
looplen = [0.0]
seam_keys = {} # should be a set for ed in loop:
for ed in me.edges: edge_average_lengths[ed] = looplen
if ed.flag & SEAM: looplen[0] += (me_verts[ed[0]].co - me_verts[ed[1]].co).length
seam_keys[ed.key] = None looplen[0] = looplen[0] / len(loop)
# edge_average_lengths = {} # ed.key:length
# #edge_average_lengths.fromkeys(edge_faces)
# Why dosnt fromkeys work?
for edkey in edge_faces.keys():
edge_average_lengths[edkey] = None
# EDGROUP is the current edge loop index, assigned to all edges
EDGROUP = [0]
EDGROUPS = [EDGROUP] #
while 1:
start_edge = None
# get the first unused edge
for edkey, value in edge_average_lengths.iteritems():
if value == None:
start_edge = edkey
break
if start_edge == None:
break
edge_average_lengths[start_edge] = EDGROUP
one_more_edge = True
while one_more_edge:
one_more_edge = False
for f in face_sel:
edge_keys = f.edge_keys
for i, edkey in enumerate(edge_keys):
if edge_average_lengths[edkey] == EDGROUP:
# if the opposite edge has not been assigned then assign it
if (not seam_keys.has_key(edge_keys[OTHER_INDEX[i]])) and\
edge_average_lengths[edge_keys[OTHER_INDEX[i]]] == None:
edge_average_lengths[edge_keys[OTHER_INDEX[i]]] = EDGROUP
one_more_edge = True
# new list
EDGROUP = [EDGROUP[0]+1]
EDGROUPS.append(EDGROUP)
edge_average_length_groups = [0.0] * len(EDGROUPS)
edge_average_count = [0] * len(EDGROUPS)
edge_lengths = dict([(ed.key, ed.length) for ed in me.edges])
# Now we have the edge loops, average the lengths.
for edkey, edgroup in edge_average_lengths.iteritems():
edge_average_length_groups[edgroup[0]] += edge_lengths[edkey]
edge_average_count[edgroup[0]] += 1
for i in xrange(len(edge_average_count)):
if edge_average_count[i]:
# so edge_average_lengths now referenced the length rather then the group.
EDGROUPS[i][0] = edge_average_length_groups[i] / edge_average_count[i]
# Finished averaging lengths
# edge_average_lengths can be used.
@ -318,12 +235,12 @@ def extend():
ok= True # keep searching ok= True # keep searching
face_modes[i] = 2 # dont search again face_modes[i] = 2 # dont search again
print sys.time() - t
me.update() me.update()
Window.RedrawAll() Window.RedrawAll()
Window.WaitCursor(0) Window.WaitCursor(0)
if __name__ == '__main__': if __name__ == '__main__':
#t = sys.time()
extend() extend()
#print sys.time() - t