[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [14246] trunk/blender/release/scripts/ flt_import.py: -> New face weld code for FLT importer

Geoffrey Bantle hairbat at yahoo.com
Wed Mar 26 17:00:14 CET 2008


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. @@




More information about the Bf-blender-cvs mailing list