Small update...

Bugfix, Wrongly waited colinear test that caused quads with co-linear edges to be made.
 Bugfix, Use active object even if unselected.
 Optimize, Skip further tests if face pair is above the quad error limit.
 Optimize, Faster edge/Face user dict creation ~10%
 Feature: Options to ignore VCols and UV's as delimetres.
This commit is contained in:
Campbell Barton 2006-02-20 05:11:04 +00:00
parent 29a5fbc6b7
commit 23e55acfcb

@ -26,8 +26,7 @@ and will not join faces that have mis-matching data.
"""
from Blender import Object, Mathutils, Draw, Window, sys
import math
from Blender import Scene, Object, Mathutils, Draw, Window, sys
TRI_LIST = (0,1,2)
@ -89,11 +88,10 @@ def isfaceCoLin(imagQuag):
# Work out how different from 90 each edge is.
diff = 0
try:
diff += abs(vecAngle(edgeVec1, edgeVec2) - 90)
diff += abs(vecAngle(edgeVec2, edgeVec3) - 90)
diff += abs(vecAngle(edgeVec3, edgeVec4) - 90)
diff += abs(vecAngle(edgeVec4, edgeVec1) - 90)
diff = abs(vecAngle(edgeVec1, edgeVec2) - 90)
diff = max(diff, abs(vecAngle(edgeVec2, edgeVec3) - 90))
diff = max(diff, abs(vecAngle(edgeVec3, edgeVec4) - 90))
diff = max(diff, abs(vecAngle(edgeVec4, edgeVec1) - 90))
except:
return 1.0
@ -101,7 +99,7 @@ def isfaceCoLin(imagQuag):
if not diff:
return 0.0
return diff/360
return min(diff/180, 1.0)
# Meause the areas of the 2 possible ways of subdividing the imagined quad.
@ -151,7 +149,7 @@ def meshJoinFacesTest(f1, f2, V1FREE, V2FREE):
# Measure how good a quad the 2 tris will make,
def measureFacePair(f1, f2, f1free, f2free):
def measureFacePair(f1, f2, f1free, f2free, limit):
# Make a imaginary quad. from 2 tris into 4 verts
imagFace = meshJoinFacesTest(f1, f2, f1free, f2free)
if imagFace is False:
@ -163,24 +161,29 @@ def measureFacePair(f1, f2, f1free, f2free):
# each value will add to the measure value
# and be between 0 and 1.0
measure+= isfaceNoDiff(imagFace)
measure+= isfaceCoLin(imagFace)
measure+= isfaceConcave(imagFace)
measure+= isfaceNoDiff(imagFace)/3
if measure > limit: return False
measure+= isfaceCoLin(imagFace)/3
if measure > limit: return False
measure+= isfaceConcave(imagFace)/3
if measure > limit: return False
# For debugging.
'''
# For debugging.
a1= isfaceNoDiff(imagFace)
a2= isfaceCoLin(imagFace)
a3= isfaceConcave(imagFace)
print 'a1 %f' % a1
print 'a2 %f' % a2
print 'a3 %f' % a3
#print 'a1 NODIFF %f' % a1
#print 'a2 COLIN %f' % a2
#print 'a3 CONCAVE %f' % a3
measure = a1+a2+a3
measure = (a1+a2+a3)/3
if measure > limit: return False
'''
return [f1,f2, measure/3, f1free, f2free]
return [f1,f2, measure, f1free, f2free]
# We know the faces are good to join, simply execute the join
@ -225,11 +228,7 @@ def meshJoinFaces(f1, f2, V1FREE, V2FREE, mesh):
# remove the edge from accress the new quad
f2.v.pop(not V2FREE)
# DEBUG
if mesh.edges:
mesh.removeEdge(edgeVert1, edgeVert2)
mesh.removeEdge(edgeVert1, edgeVert2)
#return f2
@ -285,10 +284,8 @@ def compareFaceCol(f1, f2):
return True
def sortPair(a,b):
return min(a,b), max(a,b)
def tri2quad(mesh, limit, selectedFacesOnly):
def tri2quad(mesh, limit, selectedFacesOnly, respectUVs, respectVCols):
print '\nStarting tri2quad for mesh: %s' % mesh.name
print '\t...finding pairs'
time1 = sys.time() # Time the function
@ -303,25 +300,36 @@ def tri2quad(mesh, limit, selectedFacesOnly):
else:
faceList = [f for f in mesh.faces if len(f) == 3]
has_face_uv = mesh.hasFaceUV()
has_vert_col = mesh.hasVertexColours()
# Set if applicable for this mesh.
has_face_uv= has_vert_col = False
if respectUVs:
has_face_uv = mesh.hasFaceUV()
if respectVCols:
has_vert_col = mesh.hasVertexColours()
# Build a list of edges and tris that use those edges.
# This is so its faster to find tri pairs.
edgeFaceUsers = {}
for f in faceList:
i1,i2,i3 = f.v[0].index, f.v[1].index, f.v[2].index
ed1, ed2, ed3 = sortPair(i1, i2), sortPair(i2, i3), sortPair(i3, i1)
edkey1a= edkey3b= f.v[0].index
edkey1b= edkey2a= f.v[1].index
edkey2b= edkey3a= f.v[2].index
if edkey1a > edkey1b: edkey1a, edkey1b = edkey1b, edkey1a
if edkey2a > edkey2b: edkey2a, edkey2b = edkey2b, edkey2a
if edkey3a > edkey3b: edkey3a, edkey3b = edkey3b, edkey3a
# The second int in the tuple is the free vert, its easier to store then to work it out again.
try: edgeFaceUsers[ed1].append((f, 2))
except: edgeFaceUsers[ed1] = [(f, 2)]
try: edgeFaceUsers[edkey1a, edkey1b].append((f, 2))
except: edgeFaceUsers[edkey1a, edkey1b] = [(f, 2)]
try: edgeFaceUsers[ed2].append((f, 0))
except: edgeFaceUsers[ed2] = [(f, 0)]
try: edgeFaceUsers[edkey2a, edkey2b].append((f, 0))
except: edgeFaceUsers[edkey2a, edkey2b] = [(f, 0)]
try: edgeFaceUsers[ed3].append((f, 1))
except: edgeFaceUsers[ed3] = [(f, 1)]
try: edgeFaceUsers[edkey3a, edkey3b].append((f, 1))
except: edgeFaceUsers[edkey3a, edkey3b] = [(f, 1)]
edgeDoneCount = 0
@ -339,8 +347,9 @@ def tri2quad(mesh, limit, selectedFacesOnly):
else:
# We can now store the qpair and measure
# there eligability for becoming 1 quad.
pair = measureFacePair(f1, f2, f1free, f2free)
if pair is not False and pair[2] < limit: # Some terraible error
pair = measureFacePair(f1, f2, f1free, f2free, limit)
#if pair is not False and pair[2] < limit: # Some terraible error
if pair is not False: # False means its above the limit.
facePairLs.append(pair)
pairCount += 1
@ -372,7 +381,7 @@ def tri2quad(mesh, limit, selectedFacesOnly):
if not pIdx % 20:
p = (0.5 + ((float((len_facePairLs - (len_facePairLs - pIdx))))/len_facePairLs*0.5)) * 0.99
Window.DrawProgressBar(p, 'Joining Face count: %i' % joinCount)
Window.DrawProgressBar(p, 'Joining Face count: %i of %i' % (joinCount, len_facePairLs))
draws +=1
# print 'Draws', draws
@ -383,11 +392,7 @@ def tri2quad(mesh, limit, selectedFacesOnly):
while fIdx:
fIdx -=1
if len(mesh.faces[fIdx]) < 3:
mesh.faces.pop(fIdx)
# Was buggy in 2.4.alpha fixed now I think
#mesh.faces[0].sel = 0
mesh.faces.pop(fIdx)
if joinCount:
print "tri2quad time for %s: %s joined %s tri's into quads" % (mesh.name, sys.time()-time1, joinCount)
@ -407,8 +412,14 @@ def error(str):
Draw.PupMenu('ERROR%t|'+str)
def main():
scn= Scene.GetCurrent()
#selection = Object.Get()
selection = Object.GetSelected()
actob = scn.getActiveObject()
if not actob.sel:
selection.append(actob)
if len(selection) is 0:
error('No object selected')
return
@ -422,14 +433,20 @@ def main():
# Create the variables.
selectedFacesOnly = Draw.Create(1)
respectUVs = Draw.Create(1)
respectVCols = Draw.Create(1)
limit = Draw.Create(25)
pup_block = [\
('Selected Faces Only', selectedFacesOnly, 'Use only selected faces from all selected meshes.'),\
('UV Delimit', respectUVs, 'Only join pairs that have matching UVs on the joining edge.'),\
('VCol Delimit', respectVCols, 'Only join pairs that have matching Vert Colors on the joining edge.'),\
('Limit: ', limit, 1, 100, 'A higher value will join more tris to quads, even if the quads are not perfect.'),\
]
selectedFacesOnly = selectedFacesOnly.val
respectUVs = respectUVs.val
respectVCols = respectVCols.val
limit = limit.val
if not Draw.PupBlock('Tri2Quad for %i mesh object(s)' % len(meshDict), pup_block):
@ -443,7 +460,7 @@ def main():
for ob in meshDict.itervalues():
mesh = ob.getData()
tri2quad(mesh, limit, selectedFacesOnly)
tri2quad(mesh, limit, selectedFacesOnly, respectUVs, respectVCols)
if is_editmode: Window.EditMode(1)
# Dont run when importing