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:
2006-02-20 05:11:04 +00:00
parent 29a5fbc6b7
commit 23e55acfcb

View File

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