Revision: 14246
          
http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=14246
Author:   briggs
Date:     2008-03-26 16:59:56 +0100 (Wed, 26 Mar 2008)

Log Message:
-----------
-> New face weld code for FLT importer

Replaced the use of remove doubles with some new custom 'face welding'
code that wil clean up meshes on import.This will not remove any faces
or do any edge collapse and so is a more suitable method of cleaning
up imported meshes. This same code could potentially be of use when
importing other formats as well (such as DXF...)

Modified Paths:
--------------
    trunk/blender/release/scripts/flt_import.py

Modified: trunk/blender/release/scripts/flt_import.py
===================================================================
--- trunk/blender/release/scripts/flt_import.py 2008-03-26 15:25:56 UTC (rev 
14245)
+++ trunk/blender/release/scripts/flt_import.py 2008-03-26 15:59:56 UTC (rev 
14246)
@@ -620,10 +620,12 @@
        def parse(self): # Run once per import
                Node.parse(self)
 
+
 class InterNode(Node):
        def __init__(self):
                self.object = None
                self.mesh = None
+               self.swapmesh = None
                self.hasMesh = False
                self.faceLs= []
                self.matrix = None
@@ -638,7 +640,281 @@
                        self.uvlayers[mask] = False
                        mask = mask / 2
                
+       #######################################################
+       ##              Begin Remove Doubles Replacement     ##
+       #######################################################
+       def __xvertsort(self,__a,__b):
+               (__vert, __x1) = __a
+               (__vert2,__x2) = __b
+               
+               if __x1 > __x2:
+                       return 1
+               elif __x1 < __x2:
+                       return -1
+               return 0        
+       def __calcFaceNorm(self,__face):
+               if len(__face) == 3:
+                       return Blender.Mathutils.TriangleNormal(__face[0].co, 
__face[1].co, __face[2].co)
+               elif len(__face) == 4:
+                       return Blender.Mathutils.QuadNormal(__face[0].co, 
__face[1].co, __face[2].co, __face[3].co)
+                       
+       def __replaceFaceVert(self,__weldface, __oldvert, __newvert):
+               __index = None
+               for __i, __v in enumerate(__weldface):
+                       if __v == __oldvert:
+                               __index = __i
+                               break
+               __weldface[__index] = __newvert
+       
+       def __matchEdge(self,__weldmesh, __edge1, __edge2):
+               if __edge1[0] in __weldmesh['Vertex Disk'][__edge2[1]] and 
__edge1[1] in __weldmesh['Vertex Disk'][__edge2[0]]:
+                       return True
+               return False
+       #have to compare original faces!
+       def __faceWinding(self, __weldmesh, __face1, __face2):
+               
+               __f1edges = list()
+               __f2edges = list()
+               
+               __f1edges.append((__face1.verts[0], __face1.verts[1]))
+               __f1edges.append((__face1.verts[1], __face1.verts[2]))
+               if len(__face1.verts) == 3:
+                       __f1edges.append((__face1.verts[2], __face1.verts[0]))
+               else:
+                       __f1edges.append((__face1.verts[2], __face1.verts[3]))
+                       __f1edges.append((__face1.verts[3], __face1.verts[0]))
 
+               __f2edges.append((__face2.verts[0], __face2.verts[1]))
+               __f2edges.append((__face2.verts[1], __face2.verts[2]))
+               if len(__face2.verts) == 3:
+                       __f2edges.append((__face2.verts[2], __face2.verts[0]))
+               else:
+                       __f2edges.append((__face2.verts[2], __face2.verts[3]))
+                       __f2edges.append((__face2.verts[3], __face2.verts[0]))
+
+                       
+               #find a matching edge
+               for __edge1 in __f1edges:
+                       for __edge2 in __f2edges:
+                               if self.__matchEdge(__weldmesh, __edge1, 
__edge2): #no more tests nessecary
+                                       return True
+               
+               return False
+               
+       def __floatcompare(self, __f1, __f2):
+               epsilon = 0.01
+               if ((__f1 + epsilon) > __f2) and ((__f1 - epsilon) < __f2):
+                       return True
+               return False
+       def __testFace(self,__weldmesh,__v1face, __v2face, __v1bface, 
__v2bface):
+               limit = 0.01
+               __matchvert = None
+               #frst test (for real this time!). Are the faces the same face?
+               if __v1face == __v2face:
+                       return False
+               
+               #first test: Do the faces possibly geometrically share more 
than two vertices? we should be comparing original faces for this? - Yes.....
+               __match = 0
+               for __vert in __v1bface.verts:
+                       for __vert2 in __v2bface.verts:
+                               if (abs(__vert.co[0] - __vert2.co[0]) <= limit) 
and (abs(__vert.co[1] - __vert2.co[1]) <= limit) and (abs(__vert.co[2] - 
__vert2.co[2]) <= limit): #this needs to be fixed!
+                               #if __vert2 in __weldmesh['Vertex 
Disk'][__vert] or __vert == __vert2:
+                                       __match += 1
+                                       __matchvert = __vert2
+               #avoid faces sharing more than two verts
+               if __match > 2:
+                       return False
+       
+
+               #consistent winding for face normals
+               if not self.__faceWinding(__weldmesh, __v1bface, __v2bface):
+                       return False
+
+               #second test: Compatible normals.Anything beyond almost exact 
opposite is 'ok'
+               __v1facenorm = self.__calcFaceNorm(__v1face)
+               __v2facenorm = self.__calcFaceNorm(__v2face)
+
+               #dont even mess with zero length faces
+               if __v1facenorm.length < limit:
+                       return False
+               if __v2facenorm.length < limit:
+                       return False
+
+               __v1facenorm.normalize()
+               __v2facenorm.normalize()
+               __v2facenorm = __v2facenorm.negate()
+
+               if self.__floatcompare(__v1facenorm[0], __v2facenorm[0]) and 
self.__floatcompare(__v1facenorm[1], __v2facenorm[1]) and 
self.__floatcompare(__v1facenorm[2], __v2facenorm[2]):
+                       return False
+
+               #next test: dont weld a subface to a non-subface!
+               if __v1bface.getProperty("FLT_SFLEVEL") != 
__v2bface.getProperty("FLT_SFLEVEL"):
+                       return False    
+                       
+               #final test: edge test - We dont want to create a non-manifold 
edge through our weld operation  
+       
+               return True
+
+       def __copyFaceData(self, __source, __target):
+               #copy vcolor layers.
+               __actColLayer = self.mesh.activeColorLayer
+               for __colorlayer in self.mesh.getColorLayerNames():
+                       self.mesh.activeColorLayer = __colorlayer
+                       for __i, __col in enumerate(__source.col):
+                               __target.col[__i].r = __col.r
+                               __target.col[__i].g = __col.g
+                               __target.col[__i].b = __col.b                   
+                       
+               self.mesh.activeColorLayer = __actColLayer
+               #copy uv layers.
+               __actUVLayer = self.mesh.activeUVLayer
+               for __uvlayer in self.mesh.getUVLayerNames():
+                       self.mesh.activeUVLayer = __uvlayer
+                       __target.image = __source.image
+                       __target.mode = __source.mode
+                       __target.smooth = __source.smooth
+                       __target.transp = __source.transp
+                       for __i, __uv in enumerate(__source.uv):
+                               __target.uv[__i][0] = __uv[0]
+                               __target.uv[__i][1] = __uv[1]
+                       
+               self.mesh.activeUVLayer = __actUVLayer
+               #copy property layers
+               for __property in self.mesh.faces.properties:
+                       __target.setProperty(__property, 
__source.getProperty(__property))      
+
+       def findDoubles(self):
+               limit = 0.01
+               sortblock = list()
+               double = dict()
+               for vert in self.mesh.verts:
+                       double[vert] = None
+                       sortblock.append((vert, vert.co[0] + vert.co[1] + 
vert.co[2]))
+               sortblock.sort(self.__xvertsort)
+               
+               a = 0
+               while a < len(self.mesh.verts):
+                       (vert,xsort) = sortblock[a]
+                       b = a+1
+                       if not double[vert]:
+                               while b < len(self.mesh.verts):
+                                       (vert2, xsort2) = sortblock[b]
+                                       if not double[vert2]:
+                                               #first test, simple distance
+                                               if (xsort2 - xsort) > limit: 
+                                                       break
+                                               #second test, more expensive
+                                               if (abs(vert.co[0] - 
vert2.co[0]) <= limit) and (abs(vert.co[1] - vert2.co[1]) <= limit) and 
(abs(vert.co[2] - vert2.co[2]) <= limit):
+                                                       double[vert2] = vert
+                                       b+=1                            
+                       a+=1
+       
+               return double
+
+       def buildWeldMesh(self):
+               
+               weldmesh = dict()
+               weldmesh['Vertex Disk'] = dict() #this is geometric adjacency
+               weldmesh['Vertex Faces'] = dict() #topological adjacency
+               
+               #find the doubles for this mesh
+               double = self.findDoubles()
+               
+               for vert in self.mesh.verts:
+                       weldmesh['Vertex Faces'][vert] = list()
+       
+               #create weld faces      
+               weldfaces = list()
+               originalfaces = list()
+               for face in self.mesh.faces:
+                       weldface = list()
+                       for vert in face.verts:
+                               weldface.append(vert)
+                       weldfaces.append(weldface)
+                       originalfaces.append(face)
+               for i, weldface in enumerate(weldfaces):
+                       for vert in weldface:
+                               weldmesh['Vertex Faces'][vert].append(i)
+               weldmesh['Weld Faces'] = weldfaces
+               weldmesh['Original Faces'] = originalfaces
+               
+               #Now we need to build the vertex disk data. first we do just 
the 'target' vertices
+               for vert in self.mesh.verts:
+                       if not double[vert]: #its a target
+                               weldmesh['Vertex Disk'][vert] = list()
+               for vert in self.mesh.verts:
+                       if double[vert]: #its a double
+                               weldmesh['Vertex 
Disk'][double[vert]].append(vert)
+                               
+               #Now we need to create the disk information for the remaining 
vertices
+               targets = weldmesh['Vertex Disk'].keys()
+               for target in targets:
+                       for doublevert in weldmesh['Vertex Disk'][target]:
+                               weldmesh['Vertex Disk'][doublevert] = [target]
+                               for othervert in weldmesh['Vertex 
Disk'][target]:
+                                       if othervert != doublevert:
+                                               weldmesh['Vertex 
Disk'][doublevert].append(othervert)           
+               
+               return weldmesh                 
+
+       def weldFuseFaces(self,weldmesh):
+               #slight modification here: we need to walk around the mesh as 
many times as it takes to have no more matches
+               done = 0
+               while not done:
+                       done = 1
+                       for windex, weldface in enumerate(weldmesh['Weld 
Faces']):
+                               for vertex in weldface:
+                                       #we walk around the faces of the 
doubles of this vertex and if possible, we weld them.
+                                       for doublevert in weldmesh['Vertex 
Disk'][vertex]:
+                                               removeFaces = list() #list of 
faces to remove from doubleverts face list
+                                               for doublefaceindex in 
weldmesh['Vertex Faces'][doublevert]:
+                                                       doubleface = 
weldmesh['Weld Faces'][doublefaceindex]
+                                                       oface1 = 
self.mesh.faces[windex]
+                                                       oface2 = 
self.mesh.faces[doublefaceindex]
+                                                       ok = 
self.__testFace(weldmesh, weldface, doubleface, oface1, oface2)
+                                                       if ok:
+                                                               done = 0
+                                                               
removeFaces.append(doublefaceindex)
+                                                               
self.__replaceFaceVert(doubleface, doublevert, vertex)
+                                               for doublefaceindex in 
removeFaces:
+                                                       weldmesh['Vertex 
Faces'][doublevert].remove(doublefaceindex)
+                               
+               #old faces first
+               oldindices = list()
+               for face in self.mesh.faces:
+                       oldindices.append(face.index)
+               #make our new faces.
+               newfaces = list()
+               for weldface in weldmesh['Weld Faces']:
+                       newfaces.append(weldface)
+               newindices = self.mesh.faces.extend(newfaces, indexList=True, 
ignoreDups=True)
+               #copy custom data over
+               for i, newindex in enumerate(newindices):
+                       try:
+                               
self.__copyFaceData(self.mesh.faces[oldindices[i]], self.mesh.faces[newindex])
+                       except:
+                               print "warning, could not copy face data!"
+               #delete the old faces
+               self.mesh.faces.delete(1, oldindices)
+               
+               #Clean up stray vertices
+               vertuse = dict()
+               for vert in self.mesh.verts:
+                       vertuse[vert] = 0
+               for face in self.mesh.faces:
+                       for vert in face.verts:
+                               vertuse[vert] += 1
+               delverts = list()
+               for vert in self.mesh.verts:
+                       if not vertuse[vert] and vert.index != 0:
+                               delverts.append(vert)
+               
+               self.mesh.verts.delete(delverts)        
+
+       #######################################################
+       ##             End Remove Doubles Replacement        ##
+       #######################################################
+
        def blender_import_my_faces(self):
 
                # Add the verts onto the mesh
@@ -848,10 +1124,12 @@
                                
                        #Finally, go through, remove dummy vertex, remove 
doubles and add edgesplit modifier.
                        Blender.Mesh.Mode(Blender.Mesh.SelectModes['VERTEX'])

@@ Diff output truncated at 10240 characters. @@

_______________________________________________
Bf-blender-cvs mailing list
Bf-blender-cvs@blender.org
http://lists.blender.org/mailman/listinfo/bf-blender-cvs

Reply via email to