[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