Rewrote the part that converted blenders curves into branches,
authorCampbell Barton <ideasman42@gmail.com>
Sat, 10 Nov 2007 20:00:15 +0000 (20:00 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Sat, 10 Nov 2007 20:00:15 +0000 (20:00 +0000)
Was converting into a mesh and then doing location checks, to figure out what the radius should be and then interpolating. this was the slowest part of the script and it made a mesh every time.

Now use blenders bezier interpolation function and calculate points like blender does.

fixed a driver syntax error for the Z axis (typo)

release/scripts/wizard_curve2tree.py

index 4c20a869e0069ab2a2b3c8d7d2c2b24821027449..9e34b4f82c98e7d0781591692421d99347cff1ee 100644 (file)
@@ -19,6 +19,36 @@ import Blender
 from Blender.Mathutils import Vector, CrossVecs, AngleBetweenVecs, LineIntersect, TranslationMatrix, ScaleMatrix
 from Blender.Geometry import ClosestPointOnLine
 
+# Copied from blender, we could wrap this! - BKE_curve.c
+# But probably not toooo bad in python
+def forward_diff_bezier(q0, q1, q2, q3, pointlist, steps, axis):
+       f= float(steps)
+       rt0= q0
+       rt1= 3.0*(q1-q0)/f
+       f*= f
+       rt2= 3.0*(q0-2.0*q1+q2)/f
+       f*= steps
+       rt3= (q3-q0+3.0*(q1-q2))/f
+       
+       q0= rt0
+       q1= rt1+rt2+rt3
+       q2= 2*rt2+6*rt3
+       q3= 6*rt3
+       if axis == None:
+               for a in xrange(steps+1):
+                       pointlist[a] = q0
+                       q0+= q1
+                       q1+= q2
+                       q2+= q3;
+               
+       else:
+               for a in xrange(steps+1):
+                       pointlist[a][axis] = q0
+                       q0+= q1
+                       q1+= q2
+                       q2+= q3;
+
+
 def debug_pt(co):
        Blender.Window.SetCursorPos(tuple(co))
        Blender.Window.RedrawAll()
@@ -28,6 +58,8 @@ def closestVecIndex(vec, vecls):
        best= -1
        best_dist = 100000000
        for i, vec_test in enumerate(vecls):
+               # Dont use yet, we may want to tho
+               #if vec_test: # Seems odd, but use this so we can disable some verts in the list.
                dist = (vec-vec_test).length
                if dist < best_dist:
                        best = i
@@ -60,8 +92,10 @@ class tree:
        
        
        def fromCurve(self, object):
+               # Now calculate the normals
                self.object = object
                curve = object.data
+               steps = curve.resolu # curve resolution
                
                # Set the curve object scale
                if curve.bevob:
@@ -69,118 +103,46 @@ class tree:
                        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
+               # forward_diff_bezier will fill in the blanks
+               pointlist = [[None, None, None] for i in xrange(steps+1)]
+               radlist = [ [None] for i in xrange(steps+1) ]
+
+
                for spline in curve:
                        brch = branch()
                        self.branches_all.append(brch)
-                       brch.bpoints = [ bpoint(brch, Vector(bez.vec[1]), Vector(), bez.radius * self.limbScale) for bez in spline ]
-               
-               # 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 = [ tuple(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]
+                       bez_list = list(spline)
+                       for i in xrange(1, len(bez_list)):
+                               bez1 = bez_list[i-1]
+                               bez2 = bez_list[i]
+                               bez1_vec = bez1.vec
+                               bez2_vec = bez2.vec
                                
-                               start = end = None
-                               for j, co in enumerate(vecs):
-                                       if start == None:
-                                               if abs(co[0]-start_pt.co[0]) < eul and abs(co[1]-start_pt.co[1]) < eul and abs(co[2]-start_pt.co[2]) < eul:
-                                                       start = j
-                                       if end == None:
-                                               if abs(co[0]-end_pt.co[0]) < eul and abs(co[1]-end_pt.co[1]) < eul and abs(co[2]-end_pt.co[2]) < eul:
-                                                       end = j
-                                       if start != None and end != None:
-                                               break
+                               roll1 = bez1.radius
+                               roll2 = bez2.radius
                                
-                               # for now we assuem the start is always a lower index.
-                               #if start > end:
-                               #       raise "error index is not one we like"
+                               # x,y,z,axis
+                               for ii in (0,1,2):
+                                       forward_diff_bezier(bez1_vec[1][ii], bez1_vec[2][ii],  bez2_vec[0][ii], bez2_vec[1][ii], pointlist, steps, ii)
                                
-                               #used_points.add(start)
-                               #used_points.add(end)
-                               radius = start_pt.radius
+                               # radius - no axis
+                               forward_diff_bezier(roll1, roll1 + 0.390464*(roll2-roll1), roll2 - 0.390464*(roll2-roll1),      roll2,  radlist, steps, None)
                                
-                               #print 'coords', start_co, end_co
-                               #### print "starting", start, end
-                               if start > end:
-                                       j = start-1
-                                       raise "some bug!"
-                               else:
-                                       j = start+1
+                               bpoints = [ bpoint(brch, Vector(pointlist[ii]), Vector(), radlist[ii] * self.limbScale) for ii in xrange(len(pointlist)) ]
                                
-                               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
+                               # remove endpoint for all but the last
+                               if i != len(bez_list)-1:
+                                       bpoints.pop()
+                               
+                               brch.bpoints.extend(bpoints)
                
-               # 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)
+               for brch in self.branches_all:
+                       brch.calcPointLinkedList()
+                       brch.calcPointExtras()
                
        def resetTags(self, value):
                for brch in self.branches_all:
@@ -203,24 +165,26 @@ class tree:
                                        
                                        brch_j = self.branches_all[j]
                                        
-                                       best_j, dist = brch_j.findClosest(brch_i.bpoints[0].co)
+                                       pt_best_j, dist = brch_j.findClosest(brch_i.bpoints[0].co)
                                        
-                                       # Check its in range, allow for a bit out - hense the 1.5
-                                       if dist < best_j.radius * sloppy:
+                                       # Check its in range, allow for a bit out - hense the sloppy
+                                       if dist < pt_best_j.radius * sloppy:
                                                
-                                               # if 1) dont remove the whole branch, maybe an option but later
-                                               # if 2) we are alredy a parent, cant remove me now.... darn :/ not nice... could do this properly but it would be slower and its a corner case.
-                                               # if 3) this point is within the branch, remove it.
+                                               # if 1) dont remove the whole branch, maybe an option but later
+                                               # if 2) we are alredy a parent, cant remove me now.... darn :/ not nice...
+                                               #               could do this properly but it would be slower and its a corner case.
+                                               #
+                                               # if 3) this point is within the branch, remove it.
                                                while   len(brch_i.bpoints)>2 and\
                                                                brch_i.bpoints[0].isParent == False and\
-                                                               (brch_i.bpoints[0].co - best_j.nextMidCo).length < best_j.radius * base_trim:
+                                                               (brch_i.bpoints[0].co - pt_best_j.nextMidCo).length < pt_best_j.radius * base_trim:
                                                        
                                                        # brch_i.bpoints[0].next = 101 # testing.
                                                        del brch_i.bpoints[0]
                                                        brch_i.bpoints[0].prev = None
                                                
-                                               brch_i.parent_pt = best_j
-                                               best_j.isParent = True # dont remove me
+                                               brch_i.parent_pt = pt_best_j
+                                               pt_best_j.isParent = True # dont remove me
                                                
                                                # addas a member of best_j.children later when we have the geometry info available.
                                                
@@ -260,6 +224,7 @@ class tree:
                                        # 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),\
@@ -267,8 +232,17 @@ class tree:
                                                brch.parent_pt.childPoint(3)]
                                                
                                                best_idx = closestVecIndex(brch.bpoints[0].co, child_locs)
-                                               brch.parent_pt.children[best_idx] = brch
-                                       # DONE
+                                               
+                                               # Crap! we alredy have a branch here, this is hard to solve nicely :/
+                                               # Probably the best thing to do here is attach this branch to the base of the one thats alredy there
+                                               # For even 
+                                               
+                                               if brch.parent_pt.children[best_idx]:
+                                                       # Todo - some fun trick! to get the join working.
+                                                       pass
+                                               else:
+                                                       brch.parent_pt.children[best_idx] = brch
+                                               #~ # DONE
                                        
                                        done_nothing = False
                                        
@@ -713,7 +687,7 @@ class tree:
                        try:    cu.delBezier(0) 
                        except: pass
                        cu.driver = 2 # Python expression
-                       cu.driverExpression = '%.3f*(%s.evaluate(%.3f,%.3f,(b.Get("curframe")*%.3f)+%.3f).w-0.5)' % (anim_magnitude, tex_str,  anim_offset.x, anim_offset.y, anim_speed_final, anim_offset.z)
+                       cu.driverExpression = '%.3f*(%s.evaluate((%.3f,%.3f,(b.Get("curframe")*%.3f)+%.3f)).w-0.5)' % (anim_magnitude, tex_str,  anim_offset.x, anim_offset.y, anim_speed_final, anim_offset.z)
                        
                        
                        #(%s.evaluate((b.Get("curframe")*%.3f,0,0)).w-0.5)*%.3f
@@ -1093,8 +1067,19 @@ class branch:
                s += '\tbpoints:', len(self.bpoints)
                for pt in brch.bpoints:
                        s += str(self.pt)
+       
+       def calcPointLinkedList(self):
+               for i in xrange(1, len(self.bpoints)-1):
+                       self.bpoints[i].next = self.bpoints[i+1]
+                       self.bpoints[i].prev = self.bpoints[i-1]
                
+               self.bpoints[0].next = self.bpoints[1]  
+               self.bpoints[-1].prev = self.bpoints[-2]
                
+       def calcPointExtras(self):
+               for pt in self.bpoints:
+                       pt.calcNormal()
+                       pt.calcNextMidCo()              
        
        def getParentQuadAngle(self):
                '''
@@ -1472,6 +1457,7 @@ def buildTree(ob, single=False):
                joint_smooth = PREFS['seg_joint_smooth'].val\
        )
        
+       
        ob_mesh = getCurveChild('Mesh')
        if not ob_mesh:
                # New object