[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [23796] trunk/blender/release/scripts/io/ mesh_skin.py: skin tool from 2.4, am loathed to do this but durian artists want.

Campbell Barton ideasman42 at gmail.com
Mon Oct 12 23:11:31 CEST 2009


Revision: 23796
          http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=23796
Author:   campbellbarton
Date:     2009-10-12 23:11:31 +0200 (Mon, 12 Oct 2009)

Log Message:
-----------
skin tool from 2.4, am loathed to do this but durian artists want.

Added Paths:
-----------
    trunk/blender/release/scripts/io/mesh_skin.py

Copied: trunk/blender/release/scripts/io/mesh_skin.py (from rev 23795, branches/blender2.4/release/scripts/mesh_skin.py)
===================================================================
--- trunk/blender/release/scripts/io/mesh_skin.py	                        (rev 0)
+++ trunk/blender/release/scripts/io/mesh_skin.py	2009-10-12 21:11:31 UTC (rev 23796)
@@ -0,0 +1,639 @@
+#!BPY
+
+"""
+Name: 'Skin Faces/Edge-Loops'
+Blender: 243
+Group: 'MeshFaceKey'
+Tooltip: 'Select 2 vert loops, then run this script.'
+"""
+
+__author__ = "Campbell Barton AKA Ideasman"
+__url__ = ["blenderartists.org", "www.blender.org"]
+__version__ = "1.1 2006/12/26"
+
+__bpydoc__ = """\
+With this script vertex loops can be skinned: faces are created to connect the
+selected loops of vertices.
+
+Usage:
+
+In mesh Edit mode select the vertices of the loops (closed paths / curves of
+vertices: circles, for example) that should be skinned, then run this script.
+A pop-up will provide further options, if the results of a method are not adequate try one of the others.
+"""
+
+
+# $Id$
+#
+# -------------------------------------------------------------------------- 
+# Skin Selected edges 1.0 By Campbell Barton (AKA Ideasman)
+# -------------------------------------------------------------------------- 
+# ***** BEGIN GPL LICENSE BLOCK ***** 
+# 
+# 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 ***** 
+# -------------------------------------------------------------------------- 
+
+# Made by Ideasman/Campbell 2005/06/15 - cbarton at metavr.com
+
+import Blender
+import bpy
+from Blender import Window
+from Blender.Mathutils import MidpointVecs, Vector
+from Blender.Mathutils import AngleBetweenVecs as _AngleBetweenVecs_
+import BPyMessages
+
+from Blender.Draw import PupMenu
+
+BIG_NUM = 1<<30
+
+global CULL_METHOD
+CULL_METHOD = 0
+
+def AngleBetweenVecs(a1,a2):
+	try:
+		return _AngleBetweenVecs_(a1,a2)
+	except:
+		return 180.0
+
+class edge(object):
+	__slots__ = 'v1', 'v2', 'co1', 'co2', 'length', 'removed', 'match', 'cent', 'angle', 'next', 'prev', 'normal', 'fake'
+	def __init__(self, v1,v2):
+		self.v1 = v1
+		self.v2 = v2
+		co1, co2= v1.co, v2.co
+		self.co1= co1
+		self.co2= co2
+		
+		# uv1 uv2 vcol1 vcol2 # Add later
+		self.length = (co1 - co2).length
+		self.removed = 0	# Have we been culled from the eloop
+		self.match = None	# The other edge were making a face with
+		
+		self.cent= MidpointVecs(co1, co2)
+		self.angle= 0.0
+		self.fake= False
+
+class edgeLoop(object):
+	__slots__ = 'centre', 'edges', 'normal', 'closed', 'backup_edges'
+	def __init__(self, loop, me, closed): # Vert loop
+		# Use next and prev, nextDist, prevDist
+		
+		# Get Loops centre.
+		fac= len(loop)
+		verts = me.verts
+		self.centre= reduce(lambda a,b: a+verts[b].co/fac, loop, Vector())
+		
+		# Convert Vert loop to Edges.
+		self.edges = [edge(verts[loop[vIdx-1]], verts[loop[vIdx]]) for vIdx in xrange(len(loop))]
+		
+		if not closed:
+			self.edges[0].fake = True # fake edge option
+			
+		self.closed = closed
+			
+		
+		# Assign linked list
+		for eIdx in xrange(len(self.edges)-1):
+			self.edges[eIdx].next = self.edges[eIdx+1]
+			self.edges[eIdx].prev = self.edges[eIdx-1]
+		# Now last
+		self.edges[-1].next = self.edges[0]
+		self.edges[-1].prev = self.edges[-2]
+		
+		
+		
+		# GENERATE AN AVERAGE NORMAL FOR THE WHOLE LOOP.
+		self.normal = Vector()
+		for e in self.edges:
+			n = (self.centre-e.co1).cross(self.centre-e.co2)
+			# Do we realy need tot normalize?
+			n.normalize()
+			self.normal += n
+			
+			# Generate the angle
+			va= e.cent - e.prev.cent
+			vb= e.next.cent - e.cent
+			
+			e.angle= AngleBetweenVecs(va, vb)
+		
+		# Blur the angles
+		#for e in self.edges:
+		#	e.angle= (e.angle+e.next.angle)/2
+		
+		# Blur the angles
+		#for e in self.edges:
+		#	e.angle= (e.angle+e.prev.angle)/2
+			
+		self.normal.normalize()
+		
+		# Generate a normal for each edge.
+		for e in self.edges:
+			
+			n1 = e.co1
+			n2 = e.co2
+			n3 = e.prev.co1
+			
+			a = n1-n2
+			b = n1-n3
+			normal1 = a.cross(b)
+			normal1.normalize()
+			
+			n1 = e.co2
+			n3 = e.next.co2
+			n2 = e.co1
+			
+			a = n1-n2
+			b = n1-n3
+			
+			normal2 = a.cross(b)
+			normal2.normalize()
+			
+			# Reuse normal1 var
+			normal1 += normal1 + normal2
+			normal1.normalize()
+			
+			e.normal = normal1
+			#print e.normal
+
+
+		
+	def backup(self):
+		# Keep a backup of the edges
+		self.backup_edges = self.edges[:]
+			
+	def restore(self):
+		self.edges = self.backup_edges[:]
+		for e in self.edges:
+			e.removed = 0
+		
+	def reverse(self):
+		self.edges.reverse()
+		self.normal.negate()
+		
+		for e in self.edges:
+			e.normal.negate()
+			e.v1, e.v2 = e.v2, e.v1
+			e.co1, e.co2 = e.co2, e.co1
+			e.next, e.prev = e.prev, e.next
+		
+	
+	def removeSmallest(self, cullNum, otherLoopLen):
+		'''
+		Removes N Smallest edges and backs up the loop,
+		this is so we can loop between 2 loops as if they are the same length,
+		backing up and restoring incase the loop needs to be skinned with another loop of a different length.
+		'''
+		global CULL_METHOD
+		if CULL_METHOD == 1: # Shortest edge
+			eloopCopy = self.edges[:]
+			
+			# Length sort, smallest first
+			try:	eloopCopy.sort(key = lambda e1: e1.length)
+			except:	eloopCopy.sort(lambda e1, e2: cmp(e1.length, e2.length ))
+			
+			# Dont use atm
+			#eloopCopy.sort(lambda e1, e2: cmp(e1.angle*e1.length, e2.angle*e2.length)) # Length sort, smallest first
+			#eloopCopy.sort(lambda e1, e2: cmp(e1.angle, e2.angle)) # Length sort, smallest first
+			
+			remNum = 0
+			for i, e in enumerate(eloopCopy):
+				if not e.fake:
+					e.removed = 1
+					self.edges.remove( e ) # Remove from own list, still in linked list.
+					remNum += 1
+				
+					if not remNum < cullNum:
+						break
+			
+		else: # CULL METHOD is even
+				
+			culled = 0
+			
+			step = int(otherLoopLen / float(cullNum)) * 2
+			
+			currentEdge = self.edges[0]
+			while culled < cullNum:
+				
+				# Get the shortest face in the next STEP
+				step_count= 0
+				bestAng= 360.0
+				smallestEdge= None
+				while step_count<=step or smallestEdge==None:
+					step_count+=1
+					if not currentEdge.removed: # 0 or -1 will not be accepted
+						if currentEdge.angle<bestAng and not currentEdge.fake:
+							smallestEdge= currentEdge
+							bestAng= currentEdge.angle
+					
+					currentEdge = currentEdge.next
+				
+				# In that stepping length we have the smallest edge.remove it
+				smallestEdge.removed = 1
+				self.edges.remove(smallestEdge)
+				
+				# Start scanning from the edge we found? - result is over fanning- no good.
+				#currentEdge= smallestEdge.next
+				
+				culled+=1
+	
+
+# Returns face edges.
+# face must have edge data.
+
+def getSelectedEdges(me, ob):	
+	MESH_MODE= Blender.Mesh.Mode()
+	
+	if MESH_MODE & Blender.Mesh.SelectModes.EDGE or MESH_MODE & Blender.Mesh.SelectModes.VERTEX:
+		Blender.Mesh.Mode(Blender.Mesh.SelectModes.EDGE)
+		edges= [ ed for ed in me.edges if ed.sel ]
+		# print len(edges), len(me.edges)
+		Blender.Mesh.Mode(MESH_MODE)
+		return edges
+	
+	elif MESH_MODE & Blender.Mesh.SelectModes.FACE:
+		Blender.Mesh.Mode(Blender.Mesh.SelectModes.EDGE)
+		
+		# value is [edge, face_sel_user_in]
+		'''
+		try: # Python 2.4 only
+			edge_dict=  dict((ed.key, [ed, 0]) for ed in me.edges)
+		except:
+		'''
+		# Cant try 2.4 syntax because python 2.3 will complain still
+		edge_dict=  dict([(ed.key, [ed, 0]) for ed in me.edges])
+		
+		for f in me.faces:
+			if f.sel:
+				for edkey in f.edge_keys:
+					edge_dict[edkey][1] += 1
+		
+		Blender.Mesh.Mode(MESH_MODE)
+		return [ ed_data[0] for ed_data in edge_dict.itervalues() if ed_data[1] == 1 ]
+	
+	
+
+def getVertLoops(selEdges, me):
+	'''
+	return a list of vert loops, closed and open [(loop, closed)...]
+	'''
+	
+	mainVertLoops = []
+	# second method
+	tot = len(me.verts)
+	vert_siblings = [[] for i in xrange(tot)]
+	vert_used = [False] * tot
+	
+	for ed in selEdges:
+		i1, i2 = ed.key
+		vert_siblings[i1].append(i2)
+		vert_siblings[i2].append(i1)
+	
+	# find the first used vert and keep looping.
+	for i in xrange(tot):
+		if vert_siblings[i] and not vert_used[i]:
+			sbl = vert_siblings[i] # siblings
+			
+			if len(sbl) > 2:
+				return None
+			
+			vert_used[i] = True
+			
+			# do an edgeloop seek
+			if len(sbl) == 2:
+				contextVertLoop= [sbl[0], i, sbl[1]] # start the vert loop
+				vert_used[contextVertLoop[ 0]] = True
+				vert_used[contextVertLoop[-1]] = True
+			else:
+				contextVertLoop= [i, sbl[0]]
+				vert_used[contextVertLoop[ 1]] = True
+			
+			# Always seek up
+			ok = True
+			while ok:
+				ok = False
+				closed = False
+				sbl = vert_siblings[contextVertLoop[-1]]
+				if len(sbl) == 2:
+					next = sbl[not sbl.index( contextVertLoop[-2] )]
+					if vert_used[next]:
+						closed = True
+						# break
+					else:
+						contextVertLoop.append( next ) # get the vert that isnt the second last
+						vert_used[next] = True
+						ok = True
+			
+			# Seek down as long as the starting vert was not at the edge.
+			if not closed and len(vert_siblings[i]) == 2:
+				
+				ok = True
+				while ok:
+					ok = False
+					sbl = vert_siblings[contextVertLoop[0]]
+					if len(sbl) == 2:
+						next = sbl[not sbl.index( contextVertLoop[1] )]
+						if vert_used[next]:
+							closed = True
+						else:
+							contextVertLoop.insert(0, next) # get the vert that isnt the second last
+							vert_used[next] = True
+							ok = True
+			
+			mainVertLoops.append((contextVertLoop, closed))
+	
+	
+	verts = me.verts
+	# convert from indicies to verts
+	# mainVertLoops = [([verts[i] for i in contextVertLoop], closed) for contextVertLoop, closed in  mainVertLoops]
+	# print len(mainVertLoops)
+	return mainVertLoops
+	
+
+
+def skin2EdgeLoops(eloop1, eloop2, me, ob, MODE):
+	
+	new_faces= [] # 
+	
+	# Make sure e1 loops is bigger then e2

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list