* stopped bpy from importing automaticaly as decieded in the meeting. * removed Blender.Main, since we agree it will be called bpy, renamed files also. * updated epydocs from this and last commit. * updated scripts to use bpy.*, and bugfix's for widgetwizard
		
			
				
	
	
		
			635 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			635 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
#!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@metavr.com
 | 
						|
 | 
						|
import Blender
 | 
						|
import bpy
 | 
						|
from Blender import Window
 | 
						|
from Blender.Mathutils import MidpointVecs, Vector, CrossVecs
 | 
						|
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 = CrossVecs(self.centre-e.co1, 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 = CrossVecs(a,b)
 | 
						|
			normal1.normalize()
 | 
						|
			
 | 
						|
			n1 = e.co2
 | 
						|
			n3 = e.next.co2
 | 
						|
			n2 = e.co1
 | 
						|
			
 | 
						|
			a = n1-n2
 | 
						|
			b = n1-n3
 | 
						|
			
 | 
						|
			normal2 = CrossVecs(a,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
 | 
						|
	if len(eloop1.edges) != len(eloop2.edges):
 | 
						|
		if len(eloop1.edges) < len(eloop2.edges):
 | 
						|
			eloop1, eloop2 = eloop2, eloop1
 | 
						|
		
 | 
						|
		eloop1.backup() # were about to cull faces
 | 
						|
		CULL_FACES = len(eloop1.edges) - len(eloop2.edges)
 | 
						|
		eloop1.removeSmallest(CULL_FACES, len(eloop1.edges))
 | 
						|
	else:
 | 
						|
		CULL_FACES = 0
 | 
						|
	# First make sure poly vert loops are in sync with eachother.
 | 
						|
	
 | 
						|
	# The vector allong which we are skinning.
 | 
						|
	skinVector = eloop1.centre - eloop2.centre
 | 
						|
	
 | 
						|
	loopDist = skinVector.length
 | 
						|
	
 | 
						|
	# IS THE LOOP FLIPPED, IF SO FLIP BACK. we keep it flipped, its ok,
 | 
						|
	if eloop1.closed or eloop2.closed:
 | 
						|
		angleBetweenLoopNormals = AngleBetweenVecs(eloop1.normal, eloop2.normal)
 | 
						|
		if angleBetweenLoopNormals > 90:
 | 
						|
			eloop2.reverse()
 | 
						|
			
 | 
						|
 | 
						|
		DIR= eloop1.centre - eloop2.centre
 | 
						|
		
 | 
						|
		# if eloop2.closed:
 | 
						|
		bestEloopDist = BIG_NUM
 | 
						|
		bestOffset = 0
 | 
						|
		# Loop rotation offset to test.1
 | 
						|
		eLoopIdxs = range(len(eloop1.edges))
 | 
						|
		for offset in xrange(len(eloop1.edges)):
 | 
						|
			totEloopDist = 0 # Measure this total distance for thsi loop.
 | 
						|
			
 | 
						|
			offsetIndexLs = eLoopIdxs[offset:] + eLoopIdxs[:offset] # Make offset index list
 | 
						|
			
 | 
						|
			
 | 
						|
			# e1Idx is always from 0uu to N, e2Idx is offset.
 | 
						|
			for e1Idx, e2Idx in enumerate(offsetIndexLs):
 | 
						|
				e1= eloop1.edges[e1Idx]
 | 
						|
				e2= eloop2.edges[e2Idx]
 | 
						|
				
 | 
						|
				
 | 
						|
				# Include fan connections in the measurement.
 | 
						|
				OK= True
 | 
						|
				while OK or e1.removed:
 | 
						|
					OK= False
 | 
						|
					
 | 
						|
					# Measure the vloop distance ===============
 | 
						|
					diff= ((e1.cent - e2.cent).length) #/ nangle1
 | 
						|
					
 | 
						|
					ed_dir= e1.cent-e2.cent
 | 
						|
					a_diff= AngleBetweenVecs(DIR, ed_dir)/18 # 0 t0 18
 | 
						|
					
 | 
						|
					totEloopDist += (diff * (1+a_diff)) / (1+loopDist)
 | 
						|
					
 | 
						|
					# Premeture break if where no better off
 | 
						|
					if totEloopDist > bestEloopDist:
 | 
						|
						break
 | 
						|
					
 | 
						|
					e1=e1.next
 | 
						|
					
 | 
						|
			if totEloopDist < bestEloopDist:
 | 
						|
				bestOffset = offset
 | 
						|
				bestEloopDist = totEloopDist
 | 
						|
		
 | 
						|
		# Modify V2 LS for Best offset
 | 
						|
		eloop2.edges = eloop2.edges[bestOffset:] + eloop2.edges[:bestOffset]
 | 
						|
			
 | 
						|
	else:
 | 
						|
		# Both are open loops, easier to calculate.
 | 
						|
		
 | 
						|
		
 | 
						|
		# Make sure the fake edges are at the start.
 | 
						|
		for i, edloop in enumerate((eloop1, eloop2)):
 | 
						|
			# print "LOOPO"
 | 
						|
			if edloop.edges[0].fake:
 | 
						|
				# alredy at the start
 | 
						|
				#print "A"
 | 
						|
				pass
 | 
						|
			elif edloop.edges[-1].fake:
 | 
						|
				# put the end at the start
 | 
						|
				edloop.edges.insert(0, edloop.edges.pop())
 | 
						|
				#print "B"
 | 
						|
				
 | 
						|
			else:
 | 
						|
				for j, ed in enumerate(edloop.edges):
 | 
						|
					if ed.fake:
 | 
						|
						#print "C"
 | 
						|
						edloop.edges = edloop.edges = edloop.edges[j:] + edloop.edges[:j]
 | 
						|
						break
 | 
						|
		# print "DONE"
 | 
						|
		ed1, ed2 = eloop1.edges[0], eloop2.edges[0]
 | 
						|
		
 | 
						|
		if not ed1.fake or not ed2.fake:
 | 
						|
			raise "Error"
 | 
						|
		
 | 
						|
		# Find the join that isnt flipped (juts like detecting a bow-tie face)
 | 
						|
		a1 = (ed1.co1 - ed2.co1).length + (ed1.co2 - ed2.co2).length
 | 
						|
		a2 = (ed1.co1 - ed2.co2).length + (ed1.co2 - ed2.co1).length
 | 
						|
		
 | 
						|
		if a1 > a2:
 | 
						|
			eloop2.reverse()
 | 
						|
			# make the first edge the start edge still
 | 
						|
			eloop2.edges.insert(0, eloop2.edges.pop())
 | 
						|
	
 | 
						|
	
 | 
						|
	
 | 
						|
	
 | 
						|
	for loopIdx in xrange(len(eloop2.edges)):
 | 
						|
		e1 = eloop1.edges[loopIdx]
 | 
						|
		e2 = eloop2.edges[loopIdx]
 | 
						|
		
 | 
						|
		# Remember the pairs for fan filling culled edges.
 | 
						|
		e1.match = e2; e2.match = e1
 | 
						|
		
 | 
						|
		if not (e1.fake or e2.fake):
 | 
						|
			new_faces.append([e1.v1, e1.v2, e2.v2, e2.v1])
 | 
						|
	
 | 
						|
	# FAN FILL MISSING FACES.
 | 
						|
	if CULL_FACES:
 | 
						|
		# Culled edges will be in eloop1.
 | 
						|
		FAN_FILLED_FACES = 0
 | 
						|
		
 | 
						|
		contextEdge = eloop1.edges[0] # The larger of teh 2
 | 
						|
		while FAN_FILLED_FACES < CULL_FACES:
 | 
						|
			while contextEdge.next.removed == 0:
 | 
						|
				contextEdge = contextEdge.next
 | 
						|
			
 | 
						|
			vertFanPivot = contextEdge.match.v2
 | 
						|
			
 | 
						|
			while contextEdge.next.removed == 1:
 | 
						|
				#if not contextEdge.next.fake:
 | 
						|
				new_faces.append([contextEdge.next.v1, contextEdge.next.v2, vertFanPivot])
 | 
						|
				
 | 
						|
				# Should we use another var?, this will work for now.
 | 
						|
				contextEdge.next.removed = 1
 | 
						|
				
 | 
						|
				contextEdge = contextEdge.next
 | 
						|
				FAN_FILLED_FACES += 1
 | 
						|
		
 | 
						|
		# may need to fan fill backwards 1 for non closed loops.
 | 
						|
		
 | 
						|
		eloop1.restore() # Add culled back into the list.
 | 
						|
	
 | 
						|
	me.faces.extend(new_faces)
 | 
						|
 | 
						|
 | 
						|
def main():
 | 
						|
	global CULL_METHOD
 | 
						|
	
 | 
						|
	is_editmode = Window.EditMode()
 | 
						|
	if is_editmode: Window.EditMode(0)
 | 
						|
	ob = bpy.scenes.active.objects.active
 | 
						|
	if ob == None or ob.type != 'Mesh':
 | 
						|
		BPyMessages.Error_NoMeshActive()
 | 
						|
		return
 | 
						|
	
 | 
						|
	me = ob.getData(mesh=1)
 | 
						|
	
 | 
						|
	if me.multires:
 | 
						|
		BPyMessages.Error_NoMeshMultiresEdit()
 | 
						|
		return
 | 
						|
	
 | 
						|
	time1 = Blender.sys.time()
 | 
						|
	selEdges = getSelectedEdges(me, ob)
 | 
						|
	vertLoops = getVertLoops(selEdges, me) # list of lists of edges.
 | 
						|
	if vertLoops == None:
 | 
						|
		PupMenu('Error%t|Selection includes verts that are a part of more then 1 loop')
 | 
						|
		if is_editmode: Window.EditMode(1)
 | 
						|
		return
 | 
						|
	# print len(vertLoops)
 | 
						|
	
 | 
						|
	
 | 
						|
	if len(vertLoops) > 2:
 | 
						|
		choice = PupMenu('Loft '+str(len(vertLoops))+' edge loops%t|loop|segment')
 | 
						|
		if choice == -1:
 | 
						|
			if is_editmode: Window.EditMode(1)
 | 
						|
			return
 | 
						|
	elif len(vertLoops) < 2:
 | 
						|
		PupMenu('Error%t|No Vertloops found!')
 | 
						|
		if is_editmode: Window.EditMode(1)	
 | 
						|
		return
 | 
						|
	else:
 | 
						|
		choice = 2
 | 
						|
	
 | 
						|
	
 | 
						|
	# The line below checks if any of the vert loops are differenyt in length.
 | 
						|
	if False in [len(v[0]) == len(vertLoops[0][0]) for v in vertLoops]:
 | 
						|
		CULL_METHOD = PupMenu('Small to large edge loop distrobution method%t|remove edges evenly|remove smallest edges')
 | 
						|
		if CULL_METHOD == -1:
 | 
						|
			if is_editmode: Window.EditMode(1)
 | 
						|
			return
 | 
						|
		
 | 
						|
		if CULL_METHOD ==1: # RESET CULL_METHOD
 | 
						|
			CULL_METHOD = 0 # shortest
 | 
						|
		else:
 | 
						|
			CULL_METHOD = 1 # even
 | 
						|
	
 | 
						|
	
 | 
						|
	time1 = Blender.sys.time()
 | 
						|
	# Convert to special edge data.
 | 
						|
	edgeLoops = []
 | 
						|
	for vloop, closed in vertLoops:
 | 
						|
		edgeLoops.append(edgeLoop(vloop, me, closed))
 | 
						|
		
 | 
						|
	
 | 
						|
	# VERT LOOP ORDERING CODE
 | 
						|
	# "Build a worm" list - grow from Both ends
 | 
						|
	edgeOrderedList = [edgeLoops.pop()]
 | 
						|
	
 | 
						|
	# Find the closest.
 | 
						|
	bestSoFar = BIG_NUM
 | 
						|
	bestIdxSoFar = None
 | 
						|
	for edLoopIdx, edLoop in enumerate(edgeLoops):
 | 
						|
		l =(edgeOrderedList[-1].centre - edLoop.centre).length 
 | 
						|
		if l < bestSoFar:
 | 
						|
			bestIdxSoFar = edLoopIdx
 | 
						|
			bestSoFar = l
 | 
						|
			
 | 
						|
	edgeOrderedList.append( edgeLoops.pop(bestIdxSoFar) )
 | 
						|
	
 | 
						|
	# Now we have the 2 closest, append to either end-
 | 
						|
	# Find the closest.
 | 
						|
	while edgeLoops:
 | 
						|
		bestSoFar = BIG_NUM
 | 
						|
		bestIdxSoFar = None
 | 
						|
		first_or_last = 0 # Zero is first
 | 
						|
		for edLoopIdx, edLoop in enumerate(edgeLoops):
 | 
						|
			l1 =(edgeOrderedList[-1].centre - edLoop.centre).length 
 | 
						|
			
 | 
						|
			if l1 < bestSoFar:
 | 
						|
				bestIdxSoFar = edLoopIdx
 | 
						|
				bestSoFar = l1
 | 
						|
				first_or_last = 1 # last
 | 
						|
			
 | 
						|
			l2 =(edgeOrderedList[0].centre - edLoop.centre).length 
 | 
						|
			if l2 < bestSoFar:
 | 
						|
				bestIdxSoFar = edLoopIdx
 | 
						|
				bestSoFar = l2
 | 
						|
				first_or_last = 0 # last
 | 
						|
		
 | 
						|
		if first_or_last: # add closest Last
 | 
						|
			edgeOrderedList.append( edgeLoops.pop(bestIdxSoFar) )	
 | 
						|
		else: # Add closest First
 | 
						|
			edgeOrderedList.insert(0, edgeLoops.pop(bestIdxSoFar) )	 # First
 | 
						|
	
 | 
						|
	for i in xrange(len(edgeOrderedList)-1):
 | 
						|
		skin2EdgeLoops(edgeOrderedList[i], edgeOrderedList[i+1], me, ob, 0)	
 | 
						|
	if choice == 1 and len(edgeOrderedList) > 2: # Loop
 | 
						|
		skin2EdgeLoops(edgeOrderedList[0], edgeOrderedList[-1], me, ob, 0)	
 | 
						|
	
 | 
						|
	# REMOVE SELECTED FACES.
 | 
						|
	faces= [ f for f in me.faces if f.sel ]
 | 
						|
	
 | 
						|
	if faces:
 | 
						|
		me.faces.delete(1, faces)
 | 
						|
	
 | 
						|
	print '\nSkin done in %.4f sec.' % (Blender.sys.time()-time1)
 | 
						|
	
 | 
						|
	if is_editmode: Window.EditMode(1)
 | 
						|
 | 
						|
if __name__ == '__main__':
 | 
						|
	main()
 |