[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [12516] trunk/blender/release/scripts/ wizard_curve2tree.py: (work in progress commit) - tree wizard, makes a subsurfed skin from curves.

Campbell Barton cbarton at metavr.com
Wed Nov 7 22:39:23 CET 2007


Revision: 12516
          http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=12516
Author:   campbellbarton
Date:     2007-11-07 22:39:23 +0100 (Wed, 07 Nov 2007)

Log Message:
-----------
(work in progress commit) - tree wizard, makes a subsurfed skin from curves. also adds UV's (and soon bones)
needs a user interface.

Added Paths:
-----------
    trunk/blender/release/scripts/wizard_curve2tree.py

Added: trunk/blender/release/scripts/wizard_curve2tree.py
===================================================================
--- trunk/blender/release/scripts/wizard_curve2tree.py	                        (rev 0)
+++ trunk/blender/release/scripts/wizard_curve2tree.py	2007-11-07 21:39:23 UTC (rev 12516)
@@ -0,0 +1,1121 @@
+import bpy
+import Blender
+from Blender.Mathutils import Vector, CrossVecs, AngleBetweenVecs, LineIntersect, TranslationMatrix, ScaleMatrix
+from Blender.Geometry import ClosestPointOnLine
+
+def debug_pt(co):
+	Blender.Window.SetCursorPos(tuple(co))
+	Blender.Window.RedrawAll()
+	print 'debugging', co
+
+
+def closestVecIndex(vec, vecls):
+	best= -1
+	best_dist = 100000000
+	for i, vec_test in enumerate(vecls):
+		dist = (vec-vec_test).length
+		if dist < best_dist:
+			best = i
+			best_dist = dist
+	
+	return best
+
+eul = 0.00001
+
+class tree:
+	def __init__(self):
+		self.branches_all =		[]
+		self.branches_root =	[]
+		self.mesh = None
+		self.object = None
+		self.limbScale = 1.0
+		
+		self.debug_objects = []
+		
+	def fromCurve(self, object):
+		
+		curve = object.data
+		
+		# Set the curve object scale
+		if curve.bevob:
+			# A bit of a hack to guess the size of the curve object if you have one.
+			bb = curve.bevob.boundingBox
+			# self.limbScale = (bb[0] - bb[7]).length / 2.825 # THIS IS GOOD WHEN NON SUBSURRFED
+			self.limbScale = (bb[0] - bb[7]).length / 1.8
+		# end
+		
+		
+		# Get the curve points as bpoints
+		for spline in curve:
+			brch = branch()
+			self.branches_all.append(brch)
+			
+			for bez in spline:
+				# calc normal vector later
+				pt = bpoint(brch, Vector(bez.vec[1]), Vector(), bez.radius * self.limbScale)
+				brch.bpoints.append( pt )
+		
+		
+		# Get the curve as a mesh. - for inbetween points
+		tmpme = bpy.data.meshes.new()	
+		
+		# remove/backup bevel ob
+		bev_back = curve.bevob
+		if bev_back: curve.bevob = None
+		
+		# get the curve mesh data
+		tmpob = bpy.data.scenes.active.objects.new( curve )
+		tmpme.getFromObject(object)
+		bpy.data.scenes.active.objects.unlink(tmpob)
+		
+		# restore bevel ob
+		if bev_back:
+			curve.bevob = bev_back
+			
+			# Guess the size of the curve object if you have one. This is not perfect but good enough
+			bb = bev_back.boundingBox
+			self.limbScale = (bb[0] - bb[7]).length / 2.825
+			
+			
+		
+		# TEMP FOR TESTING
+		# bpy.data.scenes.active.objects.new(tmpme)
+		
+		vecs = [ v.co for v in tmpme.verts ]
+		del tmpme
+		
+		# for branch
+		#used_points = set()
+		for brch in self.branches_all:
+			offset = 0
+			for i in xrange(1, len(brch.bpoints)):
+				# find the start/end points
+				start_pt =	brch.bpoints[offset+i-1]
+				end_pt =	brch.bpoints[offset+i]
+				
+				start = end = None
+				for j, co in enumerate(vecs):
+					if start == None:
+						if (co-start_pt.co).length < eul:
+							start = j
+					if end == None:
+						if (co-end_pt.co).length < eul:
+							end = j
+					if start != None and end != None:
+						break
+				
+				# for now we assuem the start is always a lower index.
+				#if start > end:
+				#	raise "error index is not one we like"
+				
+				#used_points.add(start)
+				#used_points.add(end)
+				radius = start_pt.radius
+				
+				#print 'coords', start_co, end_co
+				#### print "starting", start, end
+				if start > end:
+					j = start-1
+					raise "some bug!"
+				else:
+					j = start+1
+				
+				step = 1
+				step_tot = abs(start-end)
+				while j!=end:
+					#radius = (start_pt.radius*(step_tot-step) - end_pt.radius*step ) / step_tot
+					w1 = step_tot-step
+					w2 = step
+					
+					radius = ((start_pt.radius*w1) + (end_pt.radius*w2)) / step_tot
+					
+					#### print i,j, radius
+					pt = bpoint(brch, Vector(vecs[j]), Vector(), radius)
+					brch.bpoints.insert(offset+i, pt)
+					offset+=1
+					
+					if start > end:
+						j-=1
+					else:
+						j+=1
+					
+					step +=1
+		
+		# Now calculate the normals
+		for brch in self.branches_all:
+			for i in xrange(1, len(brch.bpoints)-1):
+				brch.bpoints[i].next = brch.bpoints[i+1]
+				brch.bpoints[i].prev = brch.bpoints[i-1]
+			
+			brch.bpoints[0].next = brch.bpoints[1]	
+			brch.bpoints[-1].prev = brch.bpoints[-2]
+			
+			
+			for pt in brch.bpoints:
+				pt.calcNormal()
+				pt.calcNextMidCo()
+		
+		# remove segments
+		# We may want to remove segments for 2 reasons
+		# 1) - too high resolution
+		# 2) - too close together (makes yucky geometry)
+		
+	def resetTags(self, value):
+		for brch in self.branches_all:
+			brch.tag = value
+	
+	def buildConnections(self, sloppy=1.0, stem_trim = 1.0):
+		'''
+		build tree data - fromCurve must run first
+		
+		'''
+		
+		# Connect branches
+		for i in xrange(len(self.branches_all)):
+			
+			brch_i = self.branches_all[i]
+			brch_i_head_pt = brch_i.bpoints[0]
+			
+			for j in xrange(len(self.branches_all)):
+				if i != j:
+					# See if any of the points match this branch
+					# see if Branch 'i' is the child of branch 'j'
+					
+					brch_j = self.branches_all[j]
+					
+					best_j, dist = brch_j.findClosest(brch_i_head_pt.co)
+					
+					# Check its in range, allow for a bit out - hense the 1.5
+					if dist < best_j.radius * sloppy:
+						
+						# Remove points that are within the radius, so as to not get ugly joins
+						# TODO - dont remove the whole branch
+						while len(brch_i.bpoints)>2 and (brch_i.bpoints[0].co - best_j.nextMidCo).length < best_j.radius * stem_trim:
+							del brch_i.bpoints[0]
+							brch_i.bpoints[0].prev = None
+						
+						brch_i.parent_pt = best_j
+						
+						# addas a member of best_j.children later when we have the geometry info available.
+						
+						#### print "Found Connection!!!", i, j
+						break # go onto the next branch
+		
+		"""
+			children = [brch_child for brch_child in pt.children]
+			if children:
+				# This pt is one side of the segment, pt.next joins this segment.
+				# calculate the median point the 2 segments would span
+				# Once this is done we need to adjust 2 things
+				# 1) move both segments up/down so they match the branches best.
+				# 2) set the spacing of the segments around the point.
+				
+		
+		# First try to get the ideal some space around each joint
+		# the spacing shoule be an average of 
+		for brch.bpoints:
+		"""	
+		
+		
+		# Calc points with dependancies
+		# detect circular loops!!! - TODO
+		done_nothing = False
+		self.resetTags(False)
+		while done_nothing == False:
+			done_nothing = True
+			for brch in self.branches_all:
+					
+				if brch.tag == False and (brch.parent_pt == None or brch.parent_pt.branch.tag == True):
+					
+					# Assign this to a spesific side of the parents point
+					# we know this is a child but not which side it should be attached to.
+					if brch.parent_pt:
+						child_locs = [\
+						brch.parent_pt.childPoint(0),\
+						brch.parent_pt.childPoint(1),\
+						brch.parent_pt.childPoint(2),\
+						brch.parent_pt.childPoint(3)]
+						
+						best_idx = closestVecIndex(brch.bpoints[0].co, child_locs)
+						brch.parent_pt.children[best_idx] = brch
+					# DONE
+					
+					done_nothing = False
+					
+					for pt in brch.bpoints:
+						# for temp debugging
+						## self.mesh.faces.extend([pt.verts])
+						pt.calcVerts()
+						# pt.toMesh(self.mesh) # Cant do here because our children arnt calculated yet!
+					
+					brch.tag = True
+	
+	def optimizeSpacing(self, density=1.0, joint_compression=1.0):
+		'''
+		Optimize spacing, taking branch hierarchy children into account,
+		can add or subdivide segments so branch joins dont look horrible.
+		'''
+		for brch in self.branches_all:
+			brch.evenJointDistrobution(joint_compression)
+		
+		# Correct points that were messed up from sliding
+		# This happens when one point is pushed past another and the branch gets an overlaping line
+		for brch in self.branches_all:
+			brch.fixOverlapError()
+		
+		# Collapsing
+		for brch in self.branches_all:
+			brch.collapsePoints(density)
+		
+		for brch in self.branches_all:
+			brch.branchReJoin()
+	
+	
+	def toDebugDisplay(self):
+		'''
+		Should be able to call this at any time to see whats going on
+		'''
+		sce = bpy.data.scenes.active
+		
+		for ob in self.debug_objects:
+			for ob in sce.objects:
+				sce.objects.unlink(ob)
+		
+		for branch_index, brch in enumerate(self.branches_all):
+			pt_index = 0
+			for pt_index, pt in enumerate(brch.bpoints):
+				name = '%.3d_%.3d' % (branch_index, pt_index) 
+				if pt.next==None:
+					name += '_end'
+				if pt.prev==None:
+					name += '_start'
+					
+				ob = sce.objects.new('Empty', name)
+				self.debug_objects.append(ob)
+				mat = ScaleMatrix(pt.radius, 4) * TranslationMatrix(pt.co)
+				ob.setMatrix(mat)
+				ob.setDrawMode(8) # drawname
+		Blender.Window.RedrawAll()
+		
+		
+	
+	def toMesh(self, mesh=None, do_uvmap=True, do_uv_scalewidth=True, uv_image = None):
+		# Simple points
+		'''
+		self.mesh = bpy.data.meshes.new()
+		self.object = bpy.data.scenes.active.objects.new(self.mesh)
+		self.mesh.verts.extend([ pt.co for brch in self.branches_all for pt in brch.bpoints ])
+		'''
+		if mesh:
+			self.mesh = mesh
+			mesh.verts = None
+		else:
+			self.mesh = bpy.data.meshes.new()
+		
+		totverts = 0
+		
+		for brch in self.branches_all:
+			totverts += len(brch.bpoints)
+		
+		self.mesh.verts.extend( [ (0.0,0.0,0.0) ] * ((totverts * 4)+1) ) # +1 is a dummy vert
+		verts = self.mesh.verts
+		
+		# Assign verts to points, 4 verts for each point.
+		i = 1 # dummy vert, should be 0
+		for brch in self.branches_all:			
+			for pt in brch.bpoints:
+				pt.verts[0] = verts[i]
+				pt.verts[1] = verts[i+1]
+				pt.verts[2] = verts[i+2]
+				pt.verts[3] = verts[i+3]
+				i+=4
+				
+			# Do this again because of collapsing
+			# pt.calcVerts(brch)
+		
+		# roll the tube so quads best meet up to their branches.
+		for brch in self.branches_all:
+			#for pt in brch.bpoints:
+			if brch.parent_pt:
+				
+				# Use temp lists for gathering an average
+				if brch.parent_pt.roll_angle == None:
+					brch.parent_pt.roll_angle = [brch.getParentQuadAngle()]
+				# More then 2 branches use this point, add to the list
+				else:
+					brch.parent_pt.roll_angle.append( brch.getParentQuadAngle() )
+		
+		# average the temp lists into floats
+		for brch in self.branches_all:
+			#for pt in brch.bpoints:
+			if brch.parent_pt and type(brch.parent_pt.roll_angle) == list:
+				# print brch.parent_pt.roll_angle
+				f = 0.0
+				for val in brch.parent_pt.roll_angle:
+					f += val
+				brch.parent_pt.roll_angle = f/len(brch.parent_pt.roll_angle)
+		

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list