diff options
author | Campbell Barton <ideasman42@gmail.com> | 2006-10-20 04:17:34 +0400 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2006-10-20 04:17:34 +0400 |
commit | a43bfad9e58682c4bf3bcd08ec828de65e763ac2 (patch) | |
tree | 5f2cee288372eaf32b59b9f05a82a7d92913d30b | |
parent | 6fcae7b5d456c84916f774bc0336523f41a00a12 (diff) |
removed this script since Briggs ported it to C
-rw-r--r-- | release/scripts/mesh_tri2quad.py | 493 |
1 files changed, 0 insertions, 493 deletions
diff --git a/release/scripts/mesh_tri2quad.py b/release/scripts/mesh_tri2quad.py deleted file mode 100644 index e3b45970db5..00000000000 --- a/release/scripts/mesh_tri2quad.py +++ /dev/null @@ -1,493 +0,0 @@ -#!BPY - -""" -Name: 'Triangles to Quads' -Blender: 240 -Group: 'Mesh' -Tooltip: 'Triangles to Quads for all selected mesh objects.' -""" - -__author__ = "Campbell Barton AKA Ideasman" -__url__ = ["http://members.iinet.net.au/~cpbarton/ideasman/", "blender", "elysiun"] - -__bpydoc__ = """\ -This script joins any triangles into quads for all selected mesh objects. - -Usage: - -Select the mesh(es) and run this script. Mesh data will be edited in place. -so make a backup copy first if your not sure of the results - -The limit value allows you to choose how pedantic the algorithum is when detecting errors between 2 triangles. -Over 50 could result in quads that are not correct. - -The joining of quads takes into account UV mapping, UV Images and Vertex colours -and will not join faces that have mis-matching data. -""" - -# ***** BEGIN GPL LICENSE BLOCK ***** -# -# Script copyright (C) Campbell J Barton -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software Foundation, -# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# -# ***** END GPL LICENCE BLOCK ***** -# -------------------------------------------------------------------------- - - - -from Blender import Scene, Object, Mathutils, Draw, Window, sys - -TRI_LIST = (0,1,2) - -vecAngle = Mathutils.AngleBetweenVecs -TriangleNormal = Mathutils.TriangleNormal - -#=============================================================================# -# All measurement algorithums for face compatibility when joining into quads # -# every function returns a value between 0.0 and 1.0 # -#=============================================================================# -# total diff is 1.0, no diff is 0.0 -# measure accross 2 possible triangles in the imagined quad. -def isfaceNoDiff(imagQuag): - # Divide the quad one way and measure normals - noA1 = TriangleNormal(imagQuag[0].co, imagQuag[1].co, imagQuag[2].co) - noA2 = TriangleNormal(imagQuag[0].co, imagQuag[2].co, imagQuag[3].co) - - if noA1 == noA2: - normalADiff = 0.0 - else: - try: - normalADiff = vecAngle(noA1, noA2) - except: - #print noA1, noA2 - normalADiff = 179 - - #print normalADiff, noA1, noA2 - - # Alternade division of the quad - noB1 = TriangleNormal(imagQuag[1].co, imagQuag[2].co, imagQuag[3].co) - noB2 = TriangleNormal(imagQuag[3].co, imagQuag[0].co, imagQuag[1].co) - if noB1 == noB2: - normalBDiff = 0.0 - else: - try: - normalBDiff = vecAngle(noB1, noB2) - except: - # print noB1, noB2 - normalBDiff = 179 - - # Should never be NAN anymore. - ''' - if normalBDiff != normalBDiff or normalADiff != normalADiff: - raise "NAN" - ''' - # The greatest possible difference is 180 for each - return (normalADiff/360) + (normalBDiff/360) - - -# 4 90d angles == 0, each corner diff from 90 is added together. -# 360 is total possible difference, -def isfaceCoLin(imagQuag): - - edgeVec1 = imagQuag[0].co - imagQuag[1].co - edgeVec2 = imagQuag[1].co - imagQuag[2].co - edgeVec3 = imagQuag[2].co - imagQuag[3].co - edgeVec4 = imagQuag[3].co - imagQuag[0].co - - # Work out how different from 90 each edge is. - diff = 0 - try: - diff = (\ - abs(vecAngle(edgeVec1, edgeVec2) - 90)+\ - abs(vecAngle(edgeVec2, edgeVec3) - 90)+\ - abs(vecAngle(edgeVec3, edgeVec4) - 90)+\ - abs(vecAngle(edgeVec4, edgeVec1) - 90)) / 360 - except: - return 1.0 - - # Avoid devide by 0 - if not diff: - return 0.0 - - return diff - - -# Meause the areas of the 2 possible ways of subdividing the imagined quad. -# if 1 is very different then the quad is concave. -# We should probably throw out any pairs that are at all concave, -# since even a slightly concacve paor will definetly be co linear. -# though even virging on this can be a recipe for a bad join. -def isfaceConcave(imagQuag): - # Add the 2 areas the deviding one way - areaA =\ - Mathutils.TriangleArea(imagQuag[0].co, imagQuag[1].co, imagQuag[2].co) +\ - Mathutils.TriangleArea(imagQuag[0].co, imagQuag[2].co, imagQuag[3].co) - - # Add the tri's triangulated the alternate way. - areaB =\ - Mathutils.TriangleArea(imagQuag[1].co, imagQuag[2].co, imagQuag[3].co) +\ - Mathutils.TriangleArea(imagQuag[3].co, imagQuag[0].co, imagQuag[1].co) - - # Make a ratio of difference so they are between 1 and 0 - # Need to invert the value so 1.0 is 0 - minarea = min(areaA, areaB) - maxarea = max(areaA, areaB) - - # Aviod devide by 0 - if maxarea == 0.0: - return 1 - else: - return 1 - (minarea / maxarea) - - - -# This returns a list of verts, to test -# dosent modify the actual faces. -def meshJoinFacesTest(f1, f2, V1FREE, V2FREE): - # pretend face - dummyFace = f1.v[:] - - # We know the 2 free verts. insert the f2 free vert in - if V1FREE is 0: - dummyFace.insert(2, f2.v[V2FREE]) - elif V1FREE is 1: - dummyFace.append(f2.v[V2FREE]) - elif V1FREE is 2: - dummyFace.insert(1, f2.v[V2FREE]) - - return dummyFace - - -# Measure how good a quad the 2 tris will make, -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: - return False - - measure = 0 # start at 0, a lower value is better. - - # Do a series of tests, - # each value will add to the measure value - # and be between 0 and 1.0 - - 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. - - a1= isfaceNoDiff(imagFace) - a2= isfaceCoLin(imagFace) - a3= isfaceConcave(imagFace) - - #print 'a1 NODIFF %f' % a1 - #print 'a2 COLIN %f' % a2 - #print 'a3 CONCAVE %f' % a3 - - measure = (a1+a2+a3)/3 - if measure > limit: return False - ''' - - return [f1,f2, measure, f1free, f2free] - - -# We know the faces are good to join, simply execute the join -# by making f1 into a quad and f2 inde an edge (2 vert face.) -INSERT_LOOKUP = (2,3,1) -OTHER_LOOKUP = ((1,2),(0,2),(0,1)) -def meshJoinFaces(f1, f2, V1FREE, V2FREE, mesh): - - # Only used if we have edges. - # DEBUG - edgeVert1, edgeVert2 = OTHER_LOOKUP[V1FREE] - edgeVert1, edgeVert2 = f1[edgeVert1], f1[edgeVert2] - - - fverts = f1.v[:] - if mesh.hasFaceUV(): - fuvs = f1.uv[:] - if f1.col: - fcols = f1.col[:] - - - # We know the 2 free verts. insert the f2 free vert in - # Work out which vert to insert - i = INSERT_LOOKUP[V1FREE] - - # Insert the vert in the desired location. - fverts.insert(i, f2.v[V2FREE]) - if mesh.hasFaceUV(): - fuvs.insert(i, f2.uv[V2FREE]) - if f1.col: - fcols.insert(i, f2.col[V2FREE]) - - # Assign the data to the faces. - f1.v = fverts - if mesh.hasFaceUV(): - f1.uv = fuvs - if f1.col: - f1.col = fcols - - # Make an edge from the 2nd vert. - # removing anything other then the free vert will - # remove the edge from accress the new quad - f2.v.pop(not V2FREE) - - mesh.removeEdge(edgeVert1, edgeVert2) - #return f2 - - - -def compare2(v1, v2, limit): - if v1[0] + limit > v2[0] and v1[0] - limit < v2[0] and\ - v1[1] + limit > v2[1] and v1[1] - limit < v2[1]: - return True - return False - - -def compare3(v1, v2, limit): - if v1[0] + limit > v2[0] and v1[0] - limit < v2[0] and\ - v1[1] + limit > v2[1] and v1[1] - limit < v2[1] and\ - v1[2] + limit > v2[2] and v1[2] - limit < v2[2]: - return True - return False - - -UV_LIMIT = 0.005 # 0.0 to 1.0, can be greater then these bounds tho -def compareFaceUV(f1, f2): - if f1.image == None and f1.image == None: - # No Image, ignore uv's - return True - elif f1.image != f2.image: - # Images differ, dont join faces. - return False - - # We know 2 of these will match. - for v1i in TRI_LIST: - for v2i in TRI_LIST: - if f1[v1i] is f2[v2i]: - # We have a vertex index match. - # now match the UV's - if not compare2(f1.uv[v1i], f2.uv[v2i], UV_LIMIT): - # UV's are different - return False - - return True - - -COL_LIMIT = 3 # 0 to 255 -def compareFaceCol(f1, f2): - # We know 2 of these will match. - for v1i in TRI_LIST: - for v2i in TRI_LIST: - if f1[v1i] is f2[v2i]: - # We have a vertex index match. - # now match the UV's - if not compare3(f1.col[v1i], f2.col[v2i], COL_LIMIT): - # UV's are different - return False - - return True - -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 - pairCount = 0 - - # each item in this list will be a list - # [face1, face2, measureFacePairValue] - facePairLs = [] - - if selectedFacesOnly: - faceList = [f for f in mesh.faces if f.sel if len(f) is 3 if not f.hide] - else: - 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() - 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: - - 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[edkey1a, edkey1b].append((f, 2)) - except: edgeFaceUsers[edkey1a, edkey1b] = [(f, 2)] - - try: edgeFaceUsers[edkey2a, edkey2b].append((f, 0)) - except: edgeFaceUsers[edkey2a, edkey2b] = [(f, 0)] - - try: edgeFaceUsers[edkey3a, edkey3b].append((f, 1)) - except: edgeFaceUsers[edkey3a, edkey3b] = [(f, 1)] - - - edgeDoneCount = 0 - for faceListEdgeShared in edgeFaceUsers.itervalues(): - if len(faceListEdgeShared) == 2: - f1, f1free = faceListEdgeShared[0] - f2, f2free = faceListEdgeShared[1] - - if f1.mat != f2.mat: - pass # faces have different materials. - elif has_face_uv and (not compareFaceUV(f1, f2)): - pass # UV's are there but dont match. - elif has_vert_col and not compareFaceCol(f1, f2): - pass # Colours are there but dont match. - else: - # We can now store the qpair and measure - # there eligability for becoming 1 quad. - 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 - - edgeDoneCount += 1 - if not edgeDoneCount % 20: - p = float(edgeDoneCount) / len(edgeFaceUsers) - Window.DrawProgressBar(p*0.5, 'Found pairs: %i' % pairCount) - - - # Sort, best options first :) - facePairLs.sort(lambda a,b: cmp(a[2], b[2])) - draws = 0 - print '\t...joining pairs' - joinCount = 0 - len_facePairLs = len(facePairLs) - - #faces_to_remove = [] - - for pIdx, pair in enumerate(facePairLs): - # We know the last item is the best option, and no other face pairs will get in the way. - # now join the faces. - - # If any of the faces have alredy been used then they will not have a lengh of 3 verts - if len(pair[0]) is 3 and len(pair[1]) is 3: - joinCount +=1 - # print 'joining faces', joinCount, 'Limit:', facePairLs[-1][2] - #faces_to_remove.append( meshJoinFaces(pair[0], pair[1], mesh) ) - meshJoinFaces(pair[0], pair[1], pair[3], pair[4], mesh) - - 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 of %i' % (joinCount, len_facePairLs)) - draws +=1 - - # print 'Draws', draws - - # Remove faces, due to a bug in ZR's new BF-Blender CVS - - fIdx = len(mesh.faces) - while fIdx: - fIdx -=1 - if len(mesh.faces[fIdx]) < 3: - mesh.faces.pop(fIdx) - - if joinCount: - print "tri2quad time for %s: %s joined %s tri's into quads" % (mesh.name, sys.time()-time1, joinCount) - - #mesh.update(0, (mesh.edges != []), 0) - mesh.update(0, 0, 0) - - else: - print "tri2quad nothing done %s: %s joined none" % (mesh.name, sys.time()-time1) - - - -#====================================# -# Sanity checks # -#====================================# -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 - - # GET UNIQUE MESHES. - meshDict = {} - # Mesh names - for ob in selection: - if ob.getType() == 'Mesh': - meshDict[ob.getData(1)] = ob # dont do doubles. - - # 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.'),\ - ] - - if not Draw.PupBlock('Tri2Quad for %i mesh object(s)' % len(meshDict), pup_block): - return - - selectedFacesOnly = selectedFacesOnly.val - respectUVs = respectUVs.val - respectVCols = respectVCols.val - limit = limit.val - - # We now know we can execute - is_editmode = Window.EditMode() - if is_editmode: Window.EditMode(0) - - limit = limit/100.0 # Make between 1 and 0 - - for ob in meshDict.itervalues(): - mesh = ob.getData() - tri2quad(mesh, limit, selectedFacesOnly, respectUVs, respectVCols) - if is_editmode: Window.EditMode(1) - -# Dont run when importing -if __name__ == '__main__': - Window.DrawProgressBar(0.0, 'Triangles to Quads 1.1 ') - main() - Window.DrawProgressBar(1.0, '')
\ No newline at end of file |